diff --git a/code/addons/a11y/src/components/Report/Rules.tsx b/code/addons/a11y/src/components/Report/Rules.tsx index fa7bb73ea8fe..1e7d72e08278 100644 --- a/code/addons/a11y/src/components/Report/Rules.tsx +++ b/code/addons/a11y/src/components/Report/Rules.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { styled } from '@storybook/theming'; import { Badge } from '@storybook/components'; import type { CheckResult } from 'axe-core'; -import ReactResizeDetector from 'react-resize-detector'; +import { useResizeDetector } from 'react-resize-detector'; const List = styled.div({ display: 'flex', @@ -53,6 +53,11 @@ const formatSeverityText = (severity: string) => { }; const Rule: FC = ({ rule }) => { + const { ref, width } = useResizeDetector({ + refreshMode: 'debounce', + handleHeight: false, + handleWidth: true, + }); let badgeType: any = null; switch (rule.impact) { case ImpactValue.CRITICAL: @@ -71,14 +76,10 @@ const Rule: FC = ({ rule }) => { break; } return ( - - {(size) => ( - - {formatSeverityText(rule.impact)} - {rule.message} - - )} - + + {formatSeverityText(rule.impact)} + {rule.message} + ); }; diff --git a/code/addons/a11y/src/components/Tabs.tsx b/code/addons/a11y/src/components/Tabs.tsx index aef69aafaace..ba4a1fb8689a 100644 --- a/code/addons/a11y/src/components/Tabs.tsx +++ b/code/addons/a11y/src/components/Tabs.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { styled } from '@storybook/theming'; 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 type { RuleType } from './A11YPanel'; @@ -99,6 +99,11 @@ function retrieveAllNodesFromResults(items: Result[]): NodeResult[] { } export const Tabs: React.FC = ({ tabs }) => { + const { ref, width } = useResizeDetector({ + refreshMode: 'debounce', + handleHeight: false, + handleWidth: true, + }); const { tab: activeTab, setTab } = useA11yContext(); const handleToggle = React.useCallback( @@ -111,38 +116,32 @@ export const Tabs: React.FC = ({ tabs }) => { const highlightToggleId = `${tabs[activeTab].type}-global-checkbox`; const highlightLabel = `Highlight results`; return ( - - {(size) => ( - - - - {tabs.map((tab, index) => ( - - {tab.label} - - ))} - - - {tabs[activeTab].items.length > 0 ? ( - - - {highlightLabel} - - - - ) : null} - {tabs[activeTab].panel} - - )} - + + + + {tabs.map((tab, index) => ( + + {tab.label} + + ))} + + + {tabs[activeTab].items.length > 0 ? ( + + {highlightLabel} + + + ) : null} + {tabs[activeTab].panel} + ); }; diff --git a/code/addons/jest/src/components/Panel.tsx b/code/addons/jest/src/components/Panel.tsx index cba956f1ec0a..ce7ee16c70f8 100644 --- a/code/addons/jest/src/components/Panel.tsx +++ b/code/addons/jest/src/components/Panel.tsx @@ -2,7 +2,7 @@ import type { FC } from 'react'; import React, { Fragment } from 'react'; import { styled, themes, convert } from '@storybook/theming'; 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 type { Test } from '../hoc/provideJestResult'; import { provideTests as provideJestResult } from '../hoc/provideJestResult'; @@ -118,150 +118,143 @@ const getColorByType = (type: string) => { } }; -const Content = styled(({ tests, className }: ContentProps) => ( -
- {tests.map(({ name, result }) => { - if (!result || !result.assertionResults) { - return ( - - This story has tests configured, but no file was found - - ); - } +const TestPanel: FC<{ test: Test }> = ({ test }) => { + const { ref, width } = useResizeDetector(); + const { result } = test; + if (!result || !result.assertionResults) { + return This story has tests configured, but no file was found; + } - const testsByType: Map = getTestsByTypeMap(result); - const entries: any = testsByType.entries(); - const sortedTestsByCount = [...entries].sort((a, b) => a[1].length - b[1].length); + const testsByType: Map = getTestsByTypeMap(result); + const entries: any = testsByType.entries(); + const sortedTestsByCount = [...entries].sort((a, b) => a[1].length - b[1].length); - return ( - - {(size) => { - const { width } = size; - return ( -
- - - {width > 240 ? ( - - {sortedTestsByCount.map((entry: any) => { - return ( - - ); - })} - - ) : null} - - -
- - {testsByType.get(StatusTypes.FAILED_TYPE) ? ( - testsByType.get(StatusTypes.FAILED_TYPE).map((res: any) => ( - - - - )) - ) : ( - - This story has no failing tests. - - )} - -
-
- - {testsByType.get(StatusTypes.PASSED_TYPE) ? ( - testsByType.get(StatusTypes.PASSED_TYPE).map((res: any) => ( - - - - )) - ) : ( - - This story has no passing tests. - - )} - -
-
- - {testsByType.get(StatusTypes.PENDING_TYPE) ? ( - testsByType.get(StatusTypes.PENDING_TYPE).map((res: any) => ( - - - - )) - ) : ( - - This story has no pending tests. - - )} - -
-
- - {testsByType.get(StatusTypes.TODO_TYPE) ? ( - testsByType.get(StatusTypes.TODO_TYPE).map((res: any) => ( - - - - )) - ) : ( - - This story has no tests todo. - - )} - -
-
-
- ); - }} -
- ); - })} + return ( +
+ + + {width > 240 ? ( + + {sortedTestsByCount.map((entry: any) => { + return ( + + ); + })} + + ) : null} + + +
+ + {testsByType.get(StatusTypes.FAILED_TYPE) ? ( + testsByType.get(StatusTypes.FAILED_TYPE).map((res: any) => ( + + + + )) + ) : ( + + This story has no failing tests. + + )} + +
+
+ + {testsByType.get(StatusTypes.PASSED_TYPE) ? ( + testsByType.get(StatusTypes.PASSED_TYPE).map((res: any) => ( + + + + )) + ) : ( + + This story has no passing tests. + + )} + +
+
+ + {testsByType.get(StatusTypes.PENDING_TYPE) ? ( + testsByType.get(StatusTypes.PENDING_TYPE).map((res: any) => ( + + + + )) + ) : ( + + This story has no pending tests. + + )} + +
+
+ + {testsByType.get(StatusTypes.TODO_TYPE) ? ( + testsByType.get(StatusTypes.TODO_TYPE).map((res: any) => ( + + + + )) + ) : ( + + This story has no tests todo. + + )} + +
+
+
+ ); +}; + +const Content = styled(({ tests, className }: ContentProps) => ( +
+ {tests.map((test) => ( + + ))}
))({ flex: '1 1 0%', diff --git a/code/ui/manager/src/app.tsx b/code/ui/manager/src/app.tsx index 666c93752b42..3935126f4674 100644 --- a/code/ui/manager/src/app.tsx +++ b/code/ui/manager/src/app.tsx @@ -1,6 +1,6 @@ import type { FC } 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 { Symbols } from '@storybook/components'; @@ -27,92 +27,59 @@ export interface AppProps { viewMode: State['viewMode']; layout: State['layout']; panelCount: number; - width: number; - height: number; } -const App = React.memo( - ({ viewMode, layout, panelCount, width, height }) => { - let content; +const App: React.FC = ({ viewMode, layout, panelCount }) => { + const { width, height, ref } = useResizeDetector(); + let content; - const props = useMemo( - () => ({ - Sidebar, - Preview, - Panel, - Notifications, - pages: [ - { - key: 'settings', - render: () => , - route: (({ children }) => ( - - {children} - - )) as FC, - }, - ], - }), - [] - ); - - if (!width || !height) { - content =
; - } else if (width < 600) { - content = ; - } else { - content = ( - - ); - } + const props = useMemo( + () => ({ + Sidebar, + Preview, + Panel, + Notifications, + pages: [ + { + key: 'settings', + render: () => , + route: (({ children }) => ( + + {children} + + )) as FC, + }, + ], + }), + [] + ); - return ( - - - - {content} - + if (!width || !height) { + content =
; + } else if (width < 600) { + content = ; + } else { + content = ( + ); - }, - // 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) => ( - - {({ width, height }) => } - -); + return ( + + + + {content} + + ); +}; App.displayName = 'App'; -export default SizedApp; +export default App; diff --git a/code/ui/manager/src/components/layout/container.tsx b/code/ui/manager/src/components/layout/container.tsx index e65de7bd71fe..d9e482b162c8 100644 --- a/code/ui/manager/src/components/layout/container.tsx +++ b/code/ui/manager/src/components/layout/container.tsx @@ -349,9 +349,14 @@ class Layout extends Component { viewMode: undefined, }; + navRef: React.RefObject; + + panelRef: React.RefObject; + constructor(props: LayoutProps) { super(props); - + this.navRef = React.createRef(); + this.panelRef = React.createRef(); const { bounds, options } = props; const { resizerNav, resizerPanel } = persistence.get(); @@ -533,8 +538,9 @@ class Layout extends Component { onStart={this.setDragNav} onDrag={this.resizeNav} onStop={this.unsetDrag} + nodeRef={this.navRef} > - + )} @@ -560,8 +566,10 @@ class Layout extends Component { onStart={this.setDragPanel} onDrag={this.resizePanel} onStop={this.unsetDrag} + nodeRef={this.panelRef} >