mirror of
https://github.com/storybookjs/storybook.git
synced 2025-04-05 07:31:19 +08:00
ui: fix deprecated ReactDOM.findDOMNode calls
This commit is contained in:
parent
a97702b243
commit
c91c03caaf
@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
import { styled } from '@storybook/theming';
|
import { styled } from '@storybook/theming';
|
||||||
import { Badge } from '@storybook/components';
|
import { Badge } from '@storybook/components';
|
||||||
import type { CheckResult } from 'axe-core';
|
import type { CheckResult } from 'axe-core';
|
||||||
import ReactResizeDetector from 'react-resize-detector';
|
import { useResizeDetector } from 'react-resize-detector';
|
||||||
|
|
||||||
const List = styled.div({
|
const List = styled.div({
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -53,6 +53,11 @@ const formatSeverityText = (severity: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Rule: FC<RuleProps> = ({ rule }) => {
|
const Rule: FC<RuleProps> = ({ rule }) => {
|
||||||
|
const { ref, width } = useResizeDetector({
|
||||||
|
refreshMode: 'debounce',
|
||||||
|
handleHeight: false,
|
||||||
|
handleWidth: true,
|
||||||
|
});
|
||||||
let badgeType: any = null;
|
let badgeType: any = null;
|
||||||
switch (rule.impact) {
|
switch (rule.impact) {
|
||||||
case ImpactValue.CRITICAL:
|
case ImpactValue.CRITICAL:
|
||||||
@ -71,14 +76,10 @@ const Rule: FC<RuleProps> = ({ rule }) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ReactResizeDetector handleWidth handleHeight refreshMode="debounce">
|
<Item ref={ref} elementWidth={width || 0}>
|
||||||
{(size) => (
|
<StyledBadge status={badgeType}>{formatSeverityText(rule.impact)}</StyledBadge>
|
||||||
<Item elementWidth={size.width || 0}>
|
<Message>{rule.message}</Message>
|
||||||
<StyledBadge status={badgeType}>{formatSeverityText(rule.impact)}</StyledBadge>
|
</Item>
|
||||||
<Message>{rule.message}</Message>
|
|
||||||
</Item>
|
|
||||||
)}
|
|
||||||
</ReactResizeDetector>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import * as React from 'react';
|
|||||||
|
|
||||||
import { styled } from '@storybook/theming';
|
import { styled } from '@storybook/theming';
|
||||||
import type { NodeResult, Result } from 'axe-core';
|
import type { NodeResult, Result } from 'axe-core';
|
||||||
import ReactResizeDetector from 'react-resize-detector';
|
import { useResizeDetector } from 'react-resize-detector';
|
||||||
import HighlightToggle from './Report/HighlightToggle';
|
import HighlightToggle from './Report/HighlightToggle';
|
||||||
|
|
||||||
import type { RuleType } from './A11YPanel';
|
import type { RuleType } from './A11YPanel';
|
||||||
@ -99,6 +99,11 @@ function retrieveAllNodesFromResults(items: Result[]): NodeResult[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Tabs: React.FC<TabsProps> = ({ tabs }) => {
|
export const Tabs: React.FC<TabsProps> = ({ tabs }) => {
|
||||||
|
const { ref, width } = useResizeDetector({
|
||||||
|
refreshMode: 'debounce',
|
||||||
|
handleHeight: false,
|
||||||
|
handleWidth: true,
|
||||||
|
});
|
||||||
const { tab: activeTab, setTab } = useA11yContext();
|
const { tab: activeTab, setTab } = useA11yContext();
|
||||||
|
|
||||||
const handleToggle = React.useCallback(
|
const handleToggle = React.useCallback(
|
||||||
@ -111,38 +116,32 @@ export const Tabs: React.FC<TabsProps> = ({ tabs }) => {
|
|||||||
const highlightToggleId = `${tabs[activeTab].type}-global-checkbox`;
|
const highlightToggleId = `${tabs[activeTab].type}-global-checkbox`;
|
||||||
const highlightLabel = `Highlight results`;
|
const highlightLabel = `Highlight results`;
|
||||||
return (
|
return (
|
||||||
<ReactResizeDetector handleWidth handleHeight refreshMode="debounce">
|
<Container ref={ref}>
|
||||||
{(size) => (
|
<List>
|
||||||
<Container>
|
<TabsWrapper>
|
||||||
<List>
|
{tabs.map((tab, index) => (
|
||||||
<TabsWrapper>
|
<Item
|
||||||
{tabs.map((tab, index) => (
|
/* eslint-disable-next-line react/no-array-index-key */
|
||||||
<Item
|
key={index}
|
||||||
/* eslint-disable-next-line react/no-array-index-key */
|
data-index={index}
|
||||||
key={index}
|
active={activeTab === index}
|
||||||
data-index={index}
|
onClick={handleToggle}
|
||||||
active={activeTab === index}
|
>
|
||||||
onClick={handleToggle}
|
{tab.label}
|
||||||
>
|
</Item>
|
||||||
{tab.label}
|
))}
|
||||||
</Item>
|
</TabsWrapper>
|
||||||
))}
|
</List>
|
||||||
</TabsWrapper>
|
{tabs[activeTab].items.length > 0 ? (
|
||||||
</List>
|
<GlobalToggle elementWidth={width || 0}>
|
||||||
{tabs[activeTab].items.length > 0 ? (
|
<HighlightToggleLabel htmlFor={highlightToggleId}>{highlightLabel}</HighlightToggleLabel>
|
||||||
<GlobalToggle elementWidth={size.width || 0}>
|
<HighlightToggle
|
||||||
<HighlightToggleLabel htmlFor={highlightToggleId}>
|
toggleId={highlightToggleId}
|
||||||
{highlightLabel}
|
elementsToHighlight={retrieveAllNodesFromResults(tabs[activeTab].items)}
|
||||||
</HighlightToggleLabel>
|
/>
|
||||||
<HighlightToggle
|
</GlobalToggle>
|
||||||
toggleId={highlightToggleId}
|
) : null}
|
||||||
elementsToHighlight={retrieveAllNodesFromResults(tabs[activeTab].items)}
|
{tabs[activeTab].panel}
|
||||||
/>
|
</Container>
|
||||||
</GlobalToggle>
|
|
||||||
) : null}
|
|
||||||
{tabs[activeTab].panel}
|
|
||||||
</Container>
|
|
||||||
)}
|
|
||||||
</ReactResizeDetector>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2,7 +2,7 @@ import type { FC } from 'react';
|
|||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import { styled, themes, convert } from '@storybook/theming';
|
import { styled, themes, convert } from '@storybook/theming';
|
||||||
import { ScrollArea, TabsState, Link, Placeholder } from '@storybook/components';
|
import { ScrollArea, TabsState, Link, Placeholder } from '@storybook/components';
|
||||||
import ResizeObserver from 'react-resize-detector';
|
import { useResizeDetector } from 'react-resize-detector';
|
||||||
import { Result } from './Result';
|
import { Result } from './Result';
|
||||||
import type { Test } from '../hoc/provideJestResult';
|
import type { Test } from '../hoc/provideJestResult';
|
||||||
import { provideTests as provideJestResult } from '../hoc/provideJestResult';
|
import { provideTests as provideJestResult } from '../hoc/provideJestResult';
|
||||||
@ -118,150 +118,143 @@ const getColorByType = (type: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TestPanel: FC<{ test: Test }> = ({ test }) => {
|
||||||
|
const { ref, width } = useResizeDetector();
|
||||||
|
const { result } = test;
|
||||||
|
if (!result || !result.assertionResults) {
|
||||||
|
return <Placeholder>This story has tests configured, but no file was found</Placeholder>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const testsByType: Map<string, any> = getTestsByTypeMap(result);
|
||||||
|
const entries: any = testsByType.entries();
|
||||||
|
const sortedTestsByCount = [...entries].sort((a, b) => a[1].length - b[1].length);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section ref={ref}>
|
||||||
|
<SuiteHead>
|
||||||
|
<SuiteTotals {...{ result, width }} />
|
||||||
|
{width > 240 ? (
|
||||||
|
<ProgressWrapper>
|
||||||
|
{sortedTestsByCount.map((entry: any) => {
|
||||||
|
return (
|
||||||
|
<SuiteProgressPortion
|
||||||
|
key={`progress-portion-${entry[0]}`}
|
||||||
|
color={getColorByType(entry[0])}
|
||||||
|
progressPercent={
|
||||||
|
entry[1] ? (entry[1].length / result.assertionResults.length) * 100 : 0
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ProgressWrapper>
|
||||||
|
) : null}
|
||||||
|
</SuiteHead>
|
||||||
|
<TabsState
|
||||||
|
initial="failing-tests"
|
||||||
|
backgroundColor={convert(themes.light).background.hoverable}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
id="failing-tests"
|
||||||
|
title={`${
|
||||||
|
testsByType.get(StatusTypes.FAILED_TYPE)
|
||||||
|
? testsByType.get(StatusTypes.FAILED_TYPE).length
|
||||||
|
: 0
|
||||||
|
} Failed`}
|
||||||
|
color={getColorByType(StatusTypes.FAILED_TYPE)}
|
||||||
|
>
|
||||||
|
<List>
|
||||||
|
{testsByType.get(StatusTypes.FAILED_TYPE) ? (
|
||||||
|
testsByType.get(StatusTypes.FAILED_TYPE).map((res: any) => (
|
||||||
|
<Item key={res.fullName || res.title}>
|
||||||
|
<Result {...res} />
|
||||||
|
</Item>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Placeholder key={`no-tests-${StatusTypes.FAILED_TYPE}`}>
|
||||||
|
This story has no failing tests.
|
||||||
|
</Placeholder>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id="passing-tests"
|
||||||
|
title={`${
|
||||||
|
testsByType.get(StatusTypes.PASSED_TYPE)
|
||||||
|
? testsByType.get(StatusTypes.PASSED_TYPE).length
|
||||||
|
: 0
|
||||||
|
} Passed`}
|
||||||
|
color={getColorByType(StatusTypes.PASSED_TYPE)}
|
||||||
|
>
|
||||||
|
<List>
|
||||||
|
{testsByType.get(StatusTypes.PASSED_TYPE) ? (
|
||||||
|
testsByType.get(StatusTypes.PASSED_TYPE).map((res: any) => (
|
||||||
|
<Item key={res.fullName || res.title}>
|
||||||
|
<Result {...res} />
|
||||||
|
</Item>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Placeholder key={`no-tests-${StatusTypes.PASSED_TYPE}`}>
|
||||||
|
This story has no passing tests.
|
||||||
|
</Placeholder>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id="pending-tests"
|
||||||
|
title={`${
|
||||||
|
testsByType.get(StatusTypes.PENDING_TYPE)
|
||||||
|
? testsByType.get(StatusTypes.PENDING_TYPE).length
|
||||||
|
: 0
|
||||||
|
} Pending`}
|
||||||
|
color={getColorByType(StatusTypes.PENDING_TYPE)}
|
||||||
|
>
|
||||||
|
<List>
|
||||||
|
{testsByType.get(StatusTypes.PENDING_TYPE) ? (
|
||||||
|
testsByType.get(StatusTypes.PENDING_TYPE).map((res: any) => (
|
||||||
|
<Item key={res.fullName || res.title}>
|
||||||
|
<Result {...res} />
|
||||||
|
</Item>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Placeholder key={`no-tests-${StatusTypes.PENDING_TYPE}`}>
|
||||||
|
This story has no pending tests.
|
||||||
|
</Placeholder>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id="todo-tests"
|
||||||
|
title={`${
|
||||||
|
testsByType.get(StatusTypes.TODO_TYPE)
|
||||||
|
? testsByType.get(StatusTypes.TODO_TYPE).length
|
||||||
|
: 0
|
||||||
|
} Todo`}
|
||||||
|
color={getColorByType(StatusTypes.TODO_TYPE)}
|
||||||
|
>
|
||||||
|
<List>
|
||||||
|
{testsByType.get(StatusTypes.TODO_TYPE) ? (
|
||||||
|
testsByType.get(StatusTypes.TODO_TYPE).map((res: any) => (
|
||||||
|
<Item key={res.fullName || res.title}>
|
||||||
|
<Result {...res} />
|
||||||
|
</Item>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Placeholder key={`no-tests-${StatusTypes.TODO_TYPE}`}>
|
||||||
|
This story has no tests todo.
|
||||||
|
</Placeholder>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
</TabsState>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const Content = styled(({ tests, className }: ContentProps) => (
|
const Content = styled(({ tests, className }: ContentProps) => (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
{tests.map(({ name, result }) => {
|
{tests.map((test) => (
|
||||||
if (!result || !result.assertionResults) {
|
<TestPanel key={test.name} test={test} />
|
||||||
return (
|
))}
|
||||||
<Placeholder key={name}>
|
|
||||||
This story has tests configured, but no file was found
|
|
||||||
</Placeholder>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const testsByType: Map<string, any> = getTestsByTypeMap(result);
|
|
||||||
const entries: any = testsByType.entries();
|
|
||||||
const sortedTestsByCount = [...entries].sort((a, b) => a[1].length - b[1].length);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ResizeObserver refreshMode="debounce" key={name}>
|
|
||||||
{(size) => {
|
|
||||||
const { width } = size;
|
|
||||||
return (
|
|
||||||
<section>
|
|
||||||
<SuiteHead>
|
|
||||||
<SuiteTotals {...{ result, width }} />
|
|
||||||
{width > 240 ? (
|
|
||||||
<ProgressWrapper>
|
|
||||||
{sortedTestsByCount.map((entry: any) => {
|
|
||||||
return (
|
|
||||||
<SuiteProgressPortion
|
|
||||||
key={`progress-portion-${entry[0]}`}
|
|
||||||
color={getColorByType(entry[0])}
|
|
||||||
progressPercent={
|
|
||||||
entry[1]
|
|
||||||
? (entry[1].length / result.assertionResults.length) * 100
|
|
||||||
: 0
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ProgressWrapper>
|
|
||||||
) : null}
|
|
||||||
</SuiteHead>
|
|
||||||
<TabsState
|
|
||||||
initial="failing-tests"
|
|
||||||
backgroundColor={convert(themes.light).background.hoverable}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
id="failing-tests"
|
|
||||||
title={`${
|
|
||||||
testsByType.get(StatusTypes.FAILED_TYPE)
|
|
||||||
? testsByType.get(StatusTypes.FAILED_TYPE).length
|
|
||||||
: 0
|
|
||||||
} Failed`}
|
|
||||||
color={getColorByType(StatusTypes.FAILED_TYPE)}
|
|
||||||
>
|
|
||||||
<List>
|
|
||||||
{testsByType.get(StatusTypes.FAILED_TYPE) ? (
|
|
||||||
testsByType.get(StatusTypes.FAILED_TYPE).map((res: any) => (
|
|
||||||
<Item key={res.fullName || res.title}>
|
|
||||||
<Result {...res} />
|
|
||||||
</Item>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<Placeholder key={`no-tests-${StatusTypes.FAILED_TYPE}`}>
|
|
||||||
This story has no failing tests.
|
|
||||||
</Placeholder>
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="passing-tests"
|
|
||||||
title={`${
|
|
||||||
testsByType.get(StatusTypes.PASSED_TYPE)
|
|
||||||
? testsByType.get(StatusTypes.PASSED_TYPE).length
|
|
||||||
: 0
|
|
||||||
} Passed`}
|
|
||||||
color={getColorByType(StatusTypes.PASSED_TYPE)}
|
|
||||||
>
|
|
||||||
<List>
|
|
||||||
{testsByType.get(StatusTypes.PASSED_TYPE) ? (
|
|
||||||
testsByType.get(StatusTypes.PASSED_TYPE).map((res: any) => (
|
|
||||||
<Item key={res.fullName || res.title}>
|
|
||||||
<Result {...res} />
|
|
||||||
</Item>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<Placeholder key={`no-tests-${StatusTypes.PASSED_TYPE}`}>
|
|
||||||
This story has no passing tests.
|
|
||||||
</Placeholder>
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="pending-tests"
|
|
||||||
title={`${
|
|
||||||
testsByType.get(StatusTypes.PENDING_TYPE)
|
|
||||||
? testsByType.get(StatusTypes.PENDING_TYPE).length
|
|
||||||
: 0
|
|
||||||
} Pending`}
|
|
||||||
color={getColorByType(StatusTypes.PENDING_TYPE)}
|
|
||||||
>
|
|
||||||
<List>
|
|
||||||
{testsByType.get(StatusTypes.PENDING_TYPE) ? (
|
|
||||||
testsByType.get(StatusTypes.PENDING_TYPE).map((res: any) => (
|
|
||||||
<Item key={res.fullName || res.title}>
|
|
||||||
<Result {...res} />
|
|
||||||
</Item>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<Placeholder key={`no-tests-${StatusTypes.PENDING_TYPE}`}>
|
|
||||||
This story has no pending tests.
|
|
||||||
</Placeholder>
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
id="todo-tests"
|
|
||||||
title={`${
|
|
||||||
testsByType.get(StatusTypes.TODO_TYPE)
|
|
||||||
? testsByType.get(StatusTypes.TODO_TYPE).length
|
|
||||||
: 0
|
|
||||||
} Todo`}
|
|
||||||
color={getColorByType(StatusTypes.TODO_TYPE)}
|
|
||||||
>
|
|
||||||
<List>
|
|
||||||
{testsByType.get(StatusTypes.TODO_TYPE) ? (
|
|
||||||
testsByType.get(StatusTypes.TODO_TYPE).map((res: any) => (
|
|
||||||
<Item key={res.fullName || res.title}>
|
|
||||||
<Result {...res} />
|
|
||||||
</Item>
|
|
||||||
))
|
|
||||||
) : (
|
|
||||||
<Placeholder key={`no-tests-${StatusTypes.TODO_TYPE}`}>
|
|
||||||
This story has no tests todo.
|
|
||||||
</Placeholder>
|
|
||||||
)}
|
|
||||||
</List>
|
|
||||||
</div>
|
|
||||||
</TabsState>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</ResizeObserver>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
))({
|
))({
|
||||||
flex: '1 1 0%',
|
flex: '1 1 0%',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { FC } from 'react';
|
import type { FC } from 'react';
|
||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import ResizeObserver from 'react-resize-detector';
|
import { useResizeDetector } from 'react-resize-detector';
|
||||||
|
|
||||||
import { type State } from '@storybook/manager-api';
|
import { type State } from '@storybook/manager-api';
|
||||||
import { Symbols } from '@storybook/components';
|
import { Symbols } from '@storybook/components';
|
||||||
@ -27,92 +27,59 @@ export interface AppProps {
|
|||||||
viewMode: State['viewMode'];
|
viewMode: State['viewMode'];
|
||||||
layout: State['layout'];
|
layout: State['layout'];
|
||||||
panelCount: number;
|
panelCount: number;
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const App = React.memo<AppProps>(
|
const App: React.FC<AppProps> = ({ viewMode, layout, panelCount }) => {
|
||||||
({ viewMode, layout, panelCount, width, height }) => {
|
const { width, height, ref } = useResizeDetector();
|
||||||
let content;
|
let content;
|
||||||
|
|
||||||
const props = useMemo(
|
const props = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
Sidebar,
|
Sidebar,
|
||||||
Preview,
|
Preview,
|
||||||
Panel,
|
Panel,
|
||||||
Notifications,
|
Notifications,
|
||||||
pages: [
|
pages: [
|
||||||
{
|
{
|
||||||
key: 'settings',
|
key: 'settings',
|
||||||
render: () => <SettingsPages />,
|
render: () => <SettingsPages />,
|
||||||
route: (({ children }) => (
|
route: (({ children }) => (
|
||||||
<Route path="/settings/" startsWith>
|
<Route path="/settings/" startsWith>
|
||||||
{children}
|
{children}
|
||||||
</Route>
|
</Route>
|
||||||
)) as FC,
|
)) as FC,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!width || !height) {
|
||||||
|
content = <div />;
|
||||||
|
} else if (width < 600) {
|
||||||
|
content = <Mobile {...props} viewMode={viewMode} options={layout} />;
|
||||||
|
} else {
|
||||||
|
content = (
|
||||||
|
<Desktop
|
||||||
|
{...props}
|
||||||
|
viewMode={viewMode}
|
||||||
|
options={layout}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
panelCount={panelCount}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!width || !height) {
|
|
||||||
content = <div />;
|
|
||||||
} else if (width < 600) {
|
|
||||||
content = <Mobile {...props} viewMode={viewMode} options={layout} />;
|
|
||||||
} else {
|
|
||||||
content = (
|
|
||||||
<Desktop
|
|
||||||
{...props}
|
|
||||||
viewMode={viewMode}
|
|
||||||
options={layout}
|
|
||||||
{...{ width, height }}
|
|
||||||
panelCount={panelCount}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<Global styles={createGlobal} />
|
|
||||||
<Symbols icons={['folder', 'component', 'document', 'bookmarkhollow']} />
|
|
||||||
{content}
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
// This is the default shallowEqual implementation, but with custom behavior for the `size` prop.
|
|
||||||
(prevProps: any, nextProps: any) => {
|
|
||||||
if (Object.is(prevProps, nextProps)) return true;
|
|
||||||
if (typeof prevProps !== 'object' || prevProps === null) return false;
|
|
||||||
if (typeof nextProps !== 'object' || nextProps === null) return false;
|
|
||||||
|
|
||||||
const keysA = Object.keys(prevProps);
|
|
||||||
const keysB = Object.keys(nextProps);
|
|
||||||
if (keysA.length !== keysB.length) return false;
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
|
||||||
for (const key of keysA) {
|
|
||||||
if (key === 'size') {
|
|
||||||
// SizeMe injects a new `size` object every time, even if the width/height doesn't change,
|
|
||||||
// so we chech that one manually.
|
|
||||||
if (prevProps[key].width !== nextProps[key].width) return false;
|
|
||||||
if (prevProps[key].height !== nextProps[key].height) return false;
|
|
||||||
} else {
|
|
||||||
if (!Object.prototype.hasOwnProperty.call(nextProps, key)) return false;
|
|
||||||
if (!Object.is(prevProps[key], nextProps[key])) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
const SizedApp = (props: Omit<AppProps, 'width' | 'height'>) => (
|
return (
|
||||||
<ResizeObserver>
|
<View ref={ref}>
|
||||||
{({ width, height }) => <App {...props} {...{ width, height }} />}
|
<Global styles={createGlobal} />
|
||||||
</ResizeObserver>
|
<Symbols icons={['folder', 'component', 'document', 'bookmarkhollow']} />
|
||||||
);
|
{content}
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
App.displayName = 'App';
|
App.displayName = 'App';
|
||||||
|
|
||||||
export default SizedApp;
|
export default App;
|
||||||
|
@ -349,9 +349,11 @@ class Layout extends Component<LayoutProps, LayoutState> {
|
|||||||
viewMode: undefined,
|
viewMode: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleRef: React.RefObject<HTMLDivElement>;
|
||||||
|
|
||||||
constructor(props: LayoutProps) {
|
constructor(props: LayoutProps) {
|
||||||
super(props);
|
super(props);
|
||||||
|
this.handleRef = React.createRef();
|
||||||
const { bounds, options } = props;
|
const { bounds, options } = props;
|
||||||
|
|
||||||
const { resizerNav, resizerPanel } = persistence.get();
|
const { resizerNav, resizerPanel } = persistence.get();
|
||||||
@ -533,8 +535,9 @@ class Layout extends Component<LayoutProps, LayoutState> {
|
|||||||
onStart={this.setDragNav}
|
onStart={this.setDragNav}
|
||||||
onDrag={this.resizeNav}
|
onDrag={this.resizeNav}
|
||||||
onStop={this.unsetDrag}
|
onStop={this.unsetDrag}
|
||||||
|
nodeRef={this.handleRef}
|
||||||
>
|
>
|
||||||
<Handle axis="x" isDragging={isDragging === 'nav'} />
|
<Handle ref={this.handleRef} axis="x" isDragging={isDragging === 'nav'} />
|
||||||
</Draggable>
|
</Draggable>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user