react-panel-layout 0.5.2 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{FloatingPanelFrame-lLg-Lpg7.js → FloatingPanelFrame-3eU9AwPo.js} +11 -11
- package/dist/{FloatingPanelFrame-lLg-Lpg7.js.map → FloatingPanelFrame-3eU9AwPo.js.map} +1 -1
- package/dist/{FloatingPanelFrame-D9Cp2al1.cjs → FloatingPanelFrame-CEmXDvUA.cjs} +2 -2
- package/dist/{FloatingPanelFrame-D9Cp2al1.cjs.map → FloatingPanelFrame-CEmXDvUA.cjs.map} +1 -1
- package/dist/FloatingWindow-CUXnEtrb.js +827 -0
- package/dist/FloatingWindow-CUXnEtrb.js.map +1 -0
- package/dist/FloatingWindow-DMwyK0eK.cjs +2 -0
- package/dist/FloatingWindow-DMwyK0eK.cjs.map +1 -0
- package/dist/GridLayout-DKTg_N61.cjs +2 -0
- package/dist/GridLayout-DKTg_N61.cjs.map +1 -0
- package/dist/GridLayout-UWNxXw77.js +926 -0
- package/dist/GridLayout-UWNxXw77.js.map +1 -0
- package/dist/HorizontalDivider-DdxzfV0l.js +30 -0
- package/dist/HorizontalDivider-DdxzfV0l.js.map +1 -0
- package/dist/HorizontalDivider-_pgV4Mcv.cjs +2 -0
- package/dist/HorizontalDivider-_pgV4Mcv.cjs.map +1 -0
- package/dist/PanelSystem-BqUzNtf2.js +1946 -0
- package/dist/PanelSystem-BqUzNtf2.js.map +1 -0
- package/dist/PanelSystem-D603LKKv.cjs +3 -0
- package/dist/PanelSystem-D603LKKv.cjs.map +1 -0
- package/dist/ResizeHandle-CBcAS918.cjs +2 -0
- package/dist/ResizeHandle-CBcAS918.cjs.map +1 -0
- package/dist/ResizeHandle-CXjc1meV.js +119 -0
- package/dist/ResizeHandle-CXjc1meV.js.map +1 -0
- package/dist/SwipePivotTabBar-DWrCuwEI.js +411 -0
- package/dist/SwipePivotTabBar-DWrCuwEI.js.map +1 -0
- package/dist/SwipePivotTabBar-fjjXkpj7.cjs +2 -0
- package/dist/SwipePivotTabBar-fjjXkpj7.cjs.map +1 -0
- package/dist/components/gesture/SwipeSafeZone.d.ts +40 -0
- package/dist/components/window/Drawer.d.ts +3 -1
- package/dist/components/window/DrawerLayers.d.ts +1 -1
- package/dist/components/window/drawerStyles.d.ts +69 -0
- package/dist/components/window/drawerSwipeConfig.d.ts +29 -0
- package/dist/components/window/useDrawerSwipeTransform.d.ts +23 -0
- package/dist/config.cjs +1 -1
- package/dist/config.cjs.map +1 -1
- package/dist/config.js +11 -9
- package/dist/config.js.map +1 -1
- package/dist/constants/styles.d.ts +35 -4
- package/dist/dialog/index.d.ts +69 -0
- package/dist/floating.cjs +1 -1
- package/dist/floating.js +1 -1
- package/dist/grid/index.d.ts +58 -0
- package/dist/grid.cjs +2 -0
- package/dist/grid.cjs.map +1 -0
- package/dist/grid.js +13 -0
- package/dist/grid.js.map +1 -0
- package/dist/hooks/gesture/presets.d.ts +33 -0
- package/dist/hooks/gesture/testing/createGestureSimulator.d.ts +117 -0
- package/dist/hooks/gesture/thresholdValue.d.ts +44 -0
- package/dist/hooks/gesture/types.d.ts +297 -0
- package/dist/hooks/gesture/useDirectionalLock.d.ts +20 -0
- package/dist/hooks/gesture/useEdgeSwipeInput.d.ts +23 -0
- package/dist/hooks/gesture/useNativeGestureGuard.d.ts +23 -0
- package/dist/hooks/gesture/usePointerTracking.d.ts +22 -0
- package/dist/hooks/gesture/useScrollBoundary.d.ts +23 -0
- package/dist/hooks/gesture/useSwipeInput.d.ts +5 -0
- package/dist/hooks/gesture/utils.d.ts +59 -0
- package/dist/hooks/useAnimatedVisibility.d.ts +58 -0
- package/dist/hooks/useAnimationFrame.d.ts +86 -0
- package/dist/hooks/useOperationContinuity.d.ts +64 -0
- package/dist/hooks/useResizeObserver.d.ts +33 -1
- package/dist/hooks/useSharedElementTransition.d.ts +112 -0
- package/dist/hooks/useSnapAnimation.d.ts +54 -0
- package/dist/hooks/useSwipeContentTransform.d.ts +86 -0
- package/dist/index.cjs +1 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +25 -2006
- package/dist/index.js.map +1 -1
- package/dist/modules/dialog/AlertDialog.d.ts +9 -0
- package/dist/modules/dialog/DialogContainer.d.ts +37 -0
- package/dist/modules/dialog/Modal.d.ts +26 -0
- package/dist/modules/dialog/SwipeDialogContainer.d.ts +16 -0
- package/dist/modules/dialog/dialogAnimationUtils.d.ts +113 -0
- package/dist/modules/dialog/types.d.ts +183 -0
- package/dist/modules/dialog/useDialog.d.ts +39 -0
- package/dist/modules/dialog/useDialogContainer.d.ts +47 -0
- package/dist/modules/dialog/useDialogSwipeInput.d.ts +70 -0
- package/dist/modules/dialog/useDialogTransform.d.ts +82 -0
- package/dist/modules/drawer/types.d.ts +74 -0
- package/dist/modules/drawer/useDrawerSwipeInput.d.ts +24 -0
- package/dist/modules/pivot/PivotContent.d.ts +1 -1
- package/dist/modules/pivot/SwipePivotContent.d.ts +39 -0
- package/dist/modules/pivot/SwipePivotContent.debug.tmp.d.ts +25 -0
- package/dist/modules/pivot/SwipePivotContent.test.d.ts +1 -0
- package/dist/modules/pivot/SwipePivotTabBar.d.ts +92 -0
- package/dist/modules/pivot/index.d.ts +3 -0
- package/dist/modules/pivot/scaleInputState.d.ts +37 -0
- package/dist/modules/pivot/types.d.ts +67 -2
- package/dist/modules/pivot/usePivotSwipeInput.d.ts +68 -0
- package/dist/modules/stack/StackContent.d.ts +15 -0
- package/dist/modules/stack/SwipeStackContent.d.ts +66 -0
- package/dist/modules/stack/SwipeStackOutlet.d.ts +80 -0
- package/dist/modules/stack/computeStackContentState.d.ts +99 -0
- package/dist/modules/stack/computeSwipeStackTransform.d.ts +76 -0
- package/dist/modules/stack/types.d.ts +194 -0
- package/dist/modules/stack/useStackAnimationState.d.ts +32 -0
- package/dist/modules/stack/useStackNavigation.d.ts +23 -0
- package/dist/modules/stack/useStackSwipeInput.d.ts +27 -0
- package/dist/panels/index.d.ts +67 -0
- package/dist/panels.cjs +2 -0
- package/dist/panels.cjs.map +1 -0
- package/dist/panels.js +28 -0
- package/dist/panels.js.map +1 -0
- package/dist/pivot/index.d.ts +3 -0
- package/dist/pivot.cjs +1 -1
- package/dist/pivot.cjs.map +1 -1
- package/dist/pivot.js +20 -2
- package/dist/pivot.js.map +1 -1
- package/dist/resizer/index.d.ts +57 -0
- package/dist/resizer.cjs +2 -0
- package/dist/resizer.cjs.map +1 -0
- package/dist/resizer.js +8 -0
- package/dist/resizer.js.map +1 -0
- package/dist/stack/index.d.ts +72 -0
- package/dist/stack.cjs +2 -0
- package/dist/stack.cjs.map +1 -0
- package/dist/stack.js +721 -0
- package/dist/stack.js.map +1 -0
- package/dist/sticky-header/StickyArea.d.ts +38 -0
- package/dist/sticky-header/calculateStickyMetrics.d.ts +28 -0
- package/dist/sticky-header/index.d.ts +4 -4
- package/dist/sticky-header/types.d.ts +35 -22
- package/dist/sticky-header.cjs +1 -1
- package/dist/sticky-header.cjs.map +1 -1
- package/dist/sticky-header.js +73 -174
- package/dist/sticky-header.js.map +1 -1
- package/dist/styles-NkjuMOVS.js +57 -0
- package/dist/styles-NkjuMOVS.js.map +1 -0
- package/dist/styles-qf6ptVLD.cjs +2 -0
- package/dist/styles-qf6ptVLD.cjs.map +1 -0
- package/dist/types.d.ts +16 -0
- package/dist/useContentCache-CO3LYNmz.js +24 -0
- package/dist/useContentCache-CO3LYNmz.js.map +1 -0
- package/dist/useContentCache-DqXtLrLs.cjs +2 -0
- package/dist/useContentCache-DqXtLrLs.cjs.map +1 -0
- package/dist/useDocumentPointerEvents-DXxw3qWj.js +54 -0
- package/dist/useDocumentPointerEvents-DXxw3qWj.js.map +1 -0
- package/dist/useDocumentPointerEvents-DxDSOtip.cjs +2 -0
- package/dist/useDocumentPointerEvents-DxDSOtip.cjs.map +1 -0
- package/dist/useFloatingState-C4kRaW_R.cjs +2 -0
- package/dist/useFloatingState-C4kRaW_R.cjs.map +1 -0
- package/dist/useFloatingState-tEfA_wbc.js +74 -0
- package/dist/useFloatingState-tEfA_wbc.js.map +1 -0
- package/dist/useNativeGestureGuard-C7TSqEkr.cjs +2 -0
- package/dist/useNativeGestureGuard-C7TSqEkr.cjs.map +1 -0
- package/dist/useNativeGestureGuard-CGYo6O0r.js +347 -0
- package/dist/useNativeGestureGuard-CGYo6O0r.js.map +1 -0
- package/dist/window/index.d.ts +63 -0
- package/dist/window.cjs +2 -0
- package/dist/window.cjs.map +1 -0
- package/dist/window.js +160 -0
- package/dist/window.js.map +1 -0
- package/docs/design-tokens.md +405 -0
- package/package.json +34 -4
- package/src/PanelSystemContext.tsx +88 -0
- package/src/components/gesture/SwipeSafeZone.tsx +69 -0
- package/src/components/grid/GridLayerList.tsx +172 -0
- package/src/components/grid/GridLayerResizeHandles.tsx +145 -0
- package/src/components/grid/GridLayout.spec.tsx +743 -0
- package/src/components/grid/GridLayout.tsx +130 -0
- package/src/components/grid/GridTrackResizeHandle.tsx +87 -0
- package/src/components/paneling/FloatingPanelFrame.tsx +203 -0
- package/src/components/panels/DropSuggestOverlay.tsx +131 -0
- package/src/components/panels/PanelGroupView.tsx +112 -0
- package/src/components/pivot/PivotLayer.tsx +27 -0
- package/src/components/resizer/HorizontalDivider.tsx +52 -0
- package/src/components/resizer/ResizeHandle.tsx +118 -0
- package/src/components/tabs/TabBar.tsx +223 -0
- package/src/components/tabs/TabBarTab.tsx +133 -0
- package/src/components/tabs/TabDragOverlay.tsx +92 -0
- package/src/components/window/DialogOverlay.tsx +180 -0
- package/src/components/window/Drawer.tsx +369 -0
- package/src/components/window/DrawerLayers.tsx +68 -0
- package/src/components/window/FloatingWindow.tsx +95 -0
- package/src/components/window/PopupLayerPortal.tsx +218 -0
- package/src/components/window/drawerStyles.spec.ts +263 -0
- package/src/components/window/drawerStyles.ts +228 -0
- package/src/components/window/drawerSwipeConfig.spec.ts +131 -0
- package/src/components/window/drawerSwipeConfig.ts +112 -0
- package/src/components/window/useDrawerSwipeTransform.spec.ts +234 -0
- package/src/components/window/useDrawerSwipeTransform.ts +129 -0
- package/src/config/PanelContentDeclaration.tsx +427 -0
- package/src/config/index.tsx +52 -0
- package/src/config/panelJsx.spec.tsx +54 -0
- package/src/config/panelJsxConfig.spec.tsx +54 -0
- package/src/config/panelJsxDrawer.spec.tsx +33 -0
- package/src/config/panelRouter.spec.ts +68 -0
- package/src/config/panelRouter.tsx +155 -0
- package/src/constants/styles.ts +280 -0
- package/src/demo/Layout.module.css +258 -0
- package/src/demo/Layout.tsx +176 -0
- package/src/demo/components/CodeBlock.module.css +54 -0
- package/src/demo/components/CodeBlock.tsx +34 -0
- package/src/demo/components/CodePreview.module.css +37 -0
- package/src/demo/components/CodePreview.tsx +31 -0
- package/src/demo/components/DataPreview.module.css +177 -0
- package/src/demo/components/DataPreview.tsx +115 -0
- package/src/demo/components/Story.module.css +68 -0
- package/src/demo/components/Story.tsx +54 -0
- package/src/demo/components/layout/CodePanel.module.css +183 -0
- package/src/demo/components/layout/CodePanel.tsx +149 -0
- package/src/demo/components/layout/DemoPage.module.css +60 -0
- package/src/demo/components/layout/DemoPage.tsx +56 -0
- package/src/demo/components/layout/SingleSamplePage.module.css +11 -0
- package/src/demo/components/layout/SingleSamplePage.tsx +35 -0
- package/src/demo/components/layout/SplitDemoLayout.module.css +107 -0
- package/src/demo/components/layout/SplitDemoLayout.tsx +218 -0
- package/src/demo/components/layout/index.ts +11 -0
- package/src/demo/components/tab-styles/ChromeTabBar.module.css +75 -0
- package/src/demo/components/tab-styles/ChromeTabBar.tsx +111 -0
- package/src/demo/components/tab-styles/GitHubTabBar.module.css +81 -0
- package/src/demo/components/tab-styles/GitHubTabBar.tsx +109 -0
- package/src/demo/components/tab-styles/VSCodeTabBar.module.css +78 -0
- package/src/demo/components/tab-styles/VSCodeTabBar.tsx +109 -0
- package/src/demo/components/tab-styles/index.ts +6 -0
- package/src/demo/components/ui/DemoButton.module.css +63 -0
- package/src/demo/components/ui/DemoButton.tsx +32 -0
- package/src/demo/components/ui/DemoCard.module.css +15 -0
- package/src/demo/components/ui/DemoCard.tsx +30 -0
- package/src/demo/components/ui/DemoContainer.module.css +17 -0
- package/src/demo/components/ui/DemoContainer.tsx +30 -0
- package/src/demo/components/ui/DemoPanel.module.css +23 -0
- package/src/demo/components/ui/DemoPanel.tsx +33 -0
- package/src/demo/components/ui/PanelText.module.css +18 -0
- package/src/demo/components/ui/PanelText.tsx +29 -0
- package/src/demo/components/ui/PanelTitle.module.css +18 -0
- package/src/demo/components/ui/PanelTitle.tsx +31 -0
- package/src/demo/contexts/TabbarDemoConfig.tsx +218 -0
- package/src/demo/demo.css +172 -0
- package/src/demo/hooks/useMedia.ts +41 -0
- package/src/demo/hooks/useShikiHighlight.ts +55 -0
- package/src/demo/index.tsx +293 -0
- package/src/demo/pages/Dialog/alerts/index.tsx +22 -0
- package/src/demo/pages/Dialog/card/index.tsx +22 -0
- package/src/demo/pages/Dialog/components/AlertDialogDemo.tsx +124 -0
- package/src/demo/pages/Dialog/components/CardExpandDemo.module.css +243 -0
- package/src/demo/pages/Dialog/components/CardExpandDemo.tsx +204 -0
- package/src/demo/pages/Dialog/components/CustomAlertDialogDemo.tsx +219 -0
- package/src/demo/pages/Dialog/components/DialogDemos.module.css +77 -0
- package/src/demo/pages/Dialog/components/ModalBasics.tsx +45 -0
- package/src/demo/pages/Dialog/components/SwipeDialogDemo.module.css +77 -0
- package/src/demo/pages/Dialog/components/SwipeDialogDemo.tsx +181 -0
- package/src/demo/pages/Dialog/custom-alert/index.tsx +22 -0
- package/src/demo/pages/Dialog/modal/index.tsx +17 -0
- package/src/demo/pages/Dialog/swipe/index.tsx +22 -0
- package/src/demo/pages/Drawer/animations/index.tsx +22 -0
- package/src/demo/pages/Drawer/basics/index.tsx +17 -0
- package/src/demo/pages/Drawer/components/DrawerAnimations.module.css +125 -0
- package/src/demo/pages/Drawer/components/DrawerAnimations.tsx +118 -0
- package/src/demo/pages/Drawer/components/DrawerBasics.module.css +55 -0
- package/src/demo/pages/Drawer/components/DrawerBasics.tsx +76 -0
- package/src/demo/pages/Drawer/components/DrawerMenuLayout.module.css +332 -0
- package/src/demo/pages/Drawer/components/DrawerMenuLayout.tsx +199 -0
- package/src/demo/pages/Drawer/components/DrawerSwipe.module.css +316 -0
- package/src/demo/pages/Drawer/components/DrawerSwipe.tsx +178 -0
- package/src/demo/pages/Drawer/menu/index.tsx +17 -0
- package/src/demo/pages/Drawer/swipe/index.tsx +17 -0
- package/src/demo/pages/FloatingPanelFrame/ResizableFloatingPanelsPreview.module.css +163 -0
- package/src/demo/pages/FloatingPanelFrame/ResizableFloatingPanelsPreview.tsx +234 -0
- package/src/demo/pages/FloatingPanelFrame/basic/index.tsx +17 -0
- package/src/demo/pages/FloatingPanelFrame/complex/index.tsx +26 -0
- package/src/demo/pages/FloatingPanelFrame/components/BasicPanel.module.css +16 -0
- package/src/demo/pages/FloatingPanelFrame/components/BasicPanel.tsx +24 -0
- package/src/demo/pages/FloatingPanelFrame/components/ComplexPanel.module.css +54 -0
- package/src/demo/pages/FloatingPanelFrame/components/ComplexPanel.tsx +67 -0
- package/src/demo/pages/FloatingPanelFrame/components/PanelWithControls.module.css +21 -0
- package/src/demo/pages/FloatingPanelFrame/components/PanelWithControls.tsx +41 -0
- package/src/demo/pages/FloatingPanelFrame/components/PanelWithMeta.module.css +5 -0
- package/src/demo/pages/FloatingPanelFrame/components/PanelWithMeta.tsx +43 -0
- package/src/demo/pages/FloatingPanelFrame/components/ScrollablePanel.module.css +11 -0
- package/src/demo/pages/FloatingPanelFrame/components/ScrollablePanel.tsx +42 -0
- package/src/demo/pages/FloatingPanelFrame/index.tsx +80 -0
- package/src/demo/pages/FloatingPanelFrame/scrollable/index.tsx +30 -0
- package/src/demo/pages/FloatingPanelFrame/with-controls/index.tsx +30 -0
- package/src/demo/pages/FloatingPanelFrame/with-meta/index.tsx +17 -0
- package/src/demo/pages/HorizontalDivider/components/PanelsWithRichContent.module.css +112 -0
- package/src/demo/pages/HorizontalDivider/components/PanelsWithRichContent.tsx +56 -0
- package/src/demo/pages/HorizontalDivider/components/SimpleResizablePanels.module.css +46 -0
- package/src/demo/pages/HorizontalDivider/components/SimpleResizablePanels.tsx +29 -0
- package/src/demo/pages/HorizontalDivider/components/ThreePanelLayout.module.css +54 -0
- package/src/demo/pages/HorizontalDivider/components/ThreePanelLayout.tsx +30 -0
- package/src/demo/pages/HorizontalDivider/index.module.css +14 -0
- package/src/demo/pages/HorizontalDivider/index.tsx +64 -0
- package/src/demo/pages/HorizontalDivider/panels-with-rich-content/index.tsx +21 -0
- package/src/demo/pages/HorizontalDivider/simple-resizable-panels/index.tsx +21 -0
- package/src/demo/pages/HorizontalDivider/three-panel-layout/index.tsx +21 -0
- package/src/demo/pages/PanelLayout/PanelLayoutDemo.module.css +174 -0
- package/src/demo/pages/PanelLayout/PanelLayoutDemo.tsx +248 -0
- package/src/demo/pages/PanelLayout/components/DashboardLayout.module.css +115 -0
- package/src/demo/pages/PanelLayout/components/DashboardLayout.tsx +124 -0
- package/src/demo/pages/PanelLayout/components/DraggableOverlays.module.css +101 -0
- package/src/demo/pages/PanelLayout/components/DraggableOverlays.tsx +122 -0
- package/src/demo/pages/PanelLayout/components/IDELayout.module.css +104 -0
- package/src/demo/pages/PanelLayout/components/IDELayout.tsx +143 -0
- package/src/demo/pages/PanelLayout/components/SimpleGrid.module.css +19 -0
- package/src/demo/pages/PanelLayout/components/SimpleGrid.tsx +62 -0
- package/src/demo/pages/PanelLayout/dashboard/index.tsx +22 -0
- package/src/demo/pages/PanelLayout/draggable-overlays/index.tsx +22 -0
- package/src/demo/pages/PanelLayout/ide-layout/index.tsx +22 -0
- package/src/demo/pages/PanelLayout/index.tsx +94 -0
- package/src/demo/pages/PanelLayout/simple-grid/index.tsx +22 -0
- package/src/demo/pages/PanelSystem/PanelSystemPreview.module.css +20 -0
- package/src/demo/pages/PanelSystem/PanelSystemPreview.tsx +101 -0
- package/src/demo/pages/PanelSystem/preview/index.tsx +18 -0
- package/src/demo/pages/PanelSystem/tabbar/index.tsx +129 -0
- package/src/demo/pages/Pivot/basics/index.tsx +17 -0
- package/src/demo/pages/Pivot/components/Pivot.module.css +278 -0
- package/src/demo/pages/Pivot/components/PivotBasics.tsx +103 -0
- package/src/demo/pages/Pivot/components/PivotSidebar.tsx +168 -0
- package/src/demo/pages/Pivot/components/PivotTabs.tsx +129 -0
- package/src/demo/pages/Pivot/components/PivotTransitions.tsx +120 -0
- package/src/demo/pages/Pivot/components/SwipePivot.module.css +114 -0
- package/src/demo/pages/Pivot/components/SwipePivot.tsx +193 -0
- package/src/demo/pages/Pivot/components/SwipeTabsPivot.module.css +203 -0
- package/src/demo/pages/Pivot/components/SwipeTabsPivot.tsx +320 -0
- package/src/demo/pages/Pivot/sidebar/index.tsx +17 -0
- package/src/demo/pages/Pivot/swipe/index.tsx +16 -0
- package/src/demo/pages/Pivot/swipe-debug/index.tsx +287 -0
- package/src/demo/pages/Pivot/swipe-tabs/index.tsx +15 -0
- package/src/demo/pages/Pivot/tabs/index.tsx +17 -0
- package/src/demo/pages/Pivot/transitions/index.tsx +17 -0
- package/src/demo/pages/ResizeHandle/both-directions/index.tsx +17 -0
- package/src/demo/pages/ResizeHandle/components/BothDirectionsDemo.module.css +72 -0
- package/src/demo/pages/ResizeHandle/components/BothDirectionsDemo.tsx +41 -0
- package/src/demo/pages/ResizeHandle/components/HorizontalResizeDemo.module.css +61 -0
- package/src/demo/pages/ResizeHandle/components/HorizontalResizeDemo.tsx +33 -0
- package/src/demo/pages/ResizeHandle/components/NestedPanelsDemo.module.css +83 -0
- package/src/demo/pages/ResizeHandle/components/NestedPanelsDemo.tsx +53 -0
- package/src/demo/pages/ResizeHandle/components/VerticalResizeDemo.module.css +68 -0
- package/src/demo/pages/ResizeHandle/components/VerticalResizeDemo.tsx +33 -0
- package/src/demo/pages/ResizeHandle/horizontal/index.tsx +17 -0
- package/src/demo/pages/ResizeHandle/index.module.css +11 -0
- package/src/demo/pages/ResizeHandle/index.tsx +71 -0
- package/src/demo/pages/ResizeHandle/nested-panels/index.tsx +17 -0
- package/src/demo/pages/ResizeHandle/vertical/index.tsx +17 -0
- package/src/demo/pages/ResponsiveLayout/adaptive-workspace/index.tsx +22 -0
- package/src/demo/pages/ResponsiveLayout/components/ResponsiveWorkspace.module.css +423 -0
- package/src/demo/pages/ResponsiveLayout/components/ResponsiveWorkspace.tsx +398 -0
- package/src/demo/pages/Stack/basics/index.tsx +22 -0
- package/src/demo/pages/Stack/components/Stack.module.css +234 -0
- package/src/demo/pages/Stack/components/StackBasics.spec.tsx +152 -0
- package/src/demo/pages/Stack/components/StackBasics.tsx +301 -0
- package/src/demo/pages/Stack/components/StackTablet.module.css +299 -0
- package/src/demo/pages/Stack/components/StackTablet.spec.tsx +120 -0
- package/src/demo/pages/Stack/components/StackTablet.tsx +422 -0
- package/src/demo/pages/Stack/tablet/index.tsx +22 -0
- package/src/demo/pages/StickyHeader/basics/index.tsx +17 -0
- package/src/demo/pages/StickyHeader/components/StickyHeader.module.css +219 -0
- package/src/demo/pages/StickyHeader/components/StickyHeaderBasics.tsx +103 -0
- package/src/demo/routes.tsx +214 -0
- package/src/demo/styles/animations.css +68 -0
- package/src/demo/styles/stack-themes.css +35 -0
- package/src/demo/utils/createPanelView.tsx +58 -0
- package/src/dialog/index.ts +85 -0
- package/src/floating/index.ts +24 -0
- package/src/grid/index.ts +75 -0
- package/src/hooks/ContentCacheContext.tsx +87 -0
- package/src/hooks/gesture/presets.spec.ts +86 -0
- package/src/hooks/gesture/presets.ts +95 -0
- package/src/hooks/gesture/testing/createGestureSimulator.spec.ts +241 -0
- package/src/hooks/gesture/testing/createGestureSimulator.ts +385 -0
- package/src/hooks/gesture/thresholdValue.spec.ts +103 -0
- package/src/hooks/gesture/thresholdValue.ts +77 -0
- package/src/hooks/gesture/types.ts +367 -0
- package/src/hooks/gesture/useDirectionalLock.spec.ts +271 -0
- package/src/hooks/gesture/useDirectionalLock.ts +115 -0
- package/src/hooks/gesture/useEdgeSwipeInput.spec.ts +462 -0
- package/src/hooks/gesture/useEdgeSwipeInput.ts +131 -0
- package/src/hooks/gesture/useNativeGestureGuard.spec.ts +473 -0
- package/src/hooks/gesture/useNativeGestureGuard.ts +135 -0
- package/src/hooks/gesture/usePointerTracking.spec.ts +364 -0
- package/src/hooks/gesture/usePointerTracking.ts +134 -0
- package/src/hooks/gesture/useScrollBoundary.spec.ts +249 -0
- package/src/hooks/gesture/useScrollBoundary.ts +113 -0
- package/src/hooks/gesture/useSwipeInput.spec.ts +592 -0
- package/src/hooks/gesture/useSwipeInput.ts +310 -0
- package/src/hooks/gesture/utils.spec.ts +152 -0
- package/src/hooks/gesture/utils.ts +178 -0
- package/src/hooks/useAnimatedVisibility.spec.ts +277 -0
- package/src/hooks/useAnimatedVisibility.ts +172 -0
- package/src/hooks/useAnimationFrame.ts +208 -0
- package/src/hooks/useCSSMatrix.spec.ts +214 -0
- package/src/hooks/useCSSMatrix.ts +262 -0
- package/src/hooks/useClonedElementPreview.ts +28 -0
- package/src/hooks/useContainerScroll.ts +78 -0
- package/src/hooks/useContentCache.spec.tsx +232 -0
- package/src/hooks/useContentCache.tsx +127 -0
- package/src/hooks/useDocumentPointerEvents.ts +137 -0
- package/src/hooks/useDocumentScroll.ts +41 -0
- package/src/hooks/useEffectEvent.ts +40 -0
- package/src/hooks/useElementComponentWrapper.tsx +63 -0
- package/src/hooks/useIntersectionObserver.tsx +125 -0
- package/src/hooks/useIsomorphicLayoutEffect.ts +29 -0
- package/src/hooks/useOperationContinuity.spec.ts +387 -0
- package/src/hooks/useOperationContinuity.ts +135 -0
- package/src/hooks/useResizeObserver.spec.tsx +277 -0
- package/src/hooks/useResizeObserver.tsx +150 -0
- package/src/hooks/useScrollContainer.ts +73 -0
- package/src/hooks/useSharedElementTransition.ts +333 -0
- package/src/hooks/useSnapAnimation.ts +128 -0
- package/src/hooks/useSwipeContentTransform.spec.ts +133 -0
- package/src/hooks/useSwipeContentTransform.ts +373 -0
- package/src/hooks/useTransitionState.ts +95 -0
- package/src/index.tsx +88 -0
- package/src/modules/dialog/AlertDialog.spec.tsx +387 -0
- package/src/modules/dialog/AlertDialog.tsx +221 -0
- package/src/modules/dialog/DialogContainer.spec.tsx +228 -0
- package/src/modules/dialog/DialogContainer.tsx +188 -0
- package/src/modules/dialog/Modal.spec.tsx +220 -0
- package/src/modules/dialog/Modal.tsx +182 -0
- package/src/modules/dialog/SwipeDialogContainer.tsx +208 -0
- package/src/modules/dialog/dialogAnimationUtils.spec.ts +253 -0
- package/src/modules/dialog/dialogAnimationUtils.ts +297 -0
- package/src/modules/dialog/types.ts +186 -0
- package/src/modules/dialog/useDialog.spec.tsx +447 -0
- package/src/modules/dialog/useDialog.ts +214 -0
- package/src/modules/dialog/useDialogContainer.spec.ts +331 -0
- package/src/modules/dialog/useDialogContainer.ts +150 -0
- package/src/modules/dialog/useDialogSwipeInput.spec.ts +157 -0
- package/src/modules/dialog/useDialogSwipeInput.ts +319 -0
- package/src/modules/dialog/useDialogTransform.spec.ts +370 -0
- package/src/modules/dialog/useDialogTransform.ts +407 -0
- package/src/modules/drawer/types.ts +102 -0
- package/src/modules/drawer/useDrawerSwipeInput.spec.ts +566 -0
- package/src/modules/drawer/useDrawerSwipeInput.ts +399 -0
- package/src/modules/grid/GridLayoutContext.tsx +57 -0
- package/src/modules/grid/LayerInstanceContext.tsx +56 -0
- package/src/modules/grid/resizeHandles.ts +157 -0
- package/src/modules/grid/trackUtils.ts +146 -0
- package/src/modules/grid/useGridPlacements.ts +143 -0
- package/src/modules/grid/useGridTracks.ts +156 -0
- package/src/modules/grid/useLayerDragHandle.ts +16 -0
- package/src/modules/grid/useLayerInteractions.tsx +850 -0
- package/src/modules/keybindings/KeybindingsProvider.tsx +111 -0
- package/src/modules/panels/dom/DomRegistry.tsx +94 -0
- package/src/modules/panels/index.ts +45 -0
- package/src/modules/panels/interactions/InteractionsContext.test.tsx +330 -0
- package/src/modules/panels/interactions/InteractionsContext.tsx +394 -0
- package/src/modules/panels/interactions/dnd.ts +28 -0
- package/src/modules/panels/keybindings/KeybindingsInstaller.tsx +15 -0
- package/src/modules/panels/layout/adapter.ts +124 -0
- package/src/modules/panels/rendering/ContentRegistry.spec.tsx +311 -0
- package/src/modules/panels/rendering/ContentRegistry.tsx +205 -0
- package/src/modules/panels/rendering/GroupContainer.tsx +65 -0
- package/src/modules/panels/rendering/RenderBridge.tsx +115 -0
- package/src/modules/panels/rendering/RenderContext.tsx +31 -0
- package/src/modules/panels/state/PanelSplitHandles.tsx +147 -0
- package/src/modules/panels/state/PanelSystemContext.splitLimits.spec.tsx +50 -0
- package/src/modules/panels/state/PanelSystemContext.tsx +289 -0
- package/src/modules/panels/state/StateContext.tsx +12 -0
- package/src/modules/panels/state/cleanup.ts +37 -0
- package/src/modules/panels/state/commands.ts +53 -0
- package/src/modules/panels/state/focus/Context.tsx +25 -0
- package/src/modules/panels/state/focus/logic.ts +57 -0
- package/src/modules/panels/state/groups/Context.tsx +25 -0
- package/src/modules/panels/state/groups/logic.ts +105 -0
- package/src/modules/panels/state/splitLimits.spec.ts +46 -0
- package/src/modules/panels/state/splitLimits.ts +90 -0
- package/src/modules/panels/state/state.spec.ts +49 -0
- package/src/modules/panels/state/tree/Context.tsx +24 -0
- package/src/modules/panels/state/tree/logic.spec.ts +34 -0
- package/src/modules/panels/state/tree/logic.ts +138 -0
- package/src/modules/panels/state/types.ts +142 -0
- package/src/modules/panels/system/PanelSystem.empty-tabbar.spec.tsx +53 -0
- package/src/modules/panels/system/PanelSystem.tab-click-activates.spec.tsx +44 -0
- package/src/modules/panels/system/PanelSystem.tab-reorder.spec.tsx +64 -0
- package/src/modules/panels/system/PanelSystem.tabs-no-dup.spec.tsx +57 -0
- package/src/modules/panels/system/PanelSystem.tsx +206 -0
- package/src/modules/pivot/PivotContent.spec.tsx +179 -0
- package/src/modules/pivot/PivotContent.tsx +77 -0
- package/src/modules/pivot/SwipePivotContent.debug.tmp.tsx +237 -0
- package/src/modules/pivot/SwipePivotContent.position.spec.tsx +171 -0
- package/src/modules/pivot/SwipePivotContent.spec.tsx +494 -0
- package/src/modules/pivot/SwipePivotContent.test.tsx +502 -0
- package/src/modules/pivot/SwipePivotContent.tsx +197 -0
- package/src/modules/pivot/SwipePivotTabBar.spec.tsx +882 -0
- package/src/modules/pivot/SwipePivotTabBar.tsx +583 -0
- package/src/modules/pivot/index.ts +8 -0
- package/src/modules/pivot/scaleInputState.spec.ts +219 -0
- package/src/modules/pivot/scaleInputState.ts +66 -0
- package/src/modules/pivot/types.ts +139 -0
- package/src/modules/pivot/usePivot.spec.ts +635 -0
- package/src/modules/pivot/usePivot.spec.tsx +186 -0
- package/src/modules/pivot/usePivot.tsx +345 -0
- package/src/modules/pivot/usePivotSwipeInput.spec.ts +708 -0
- package/src/modules/pivot/usePivotSwipeInput.ts +136 -0
- package/src/modules/resizer/useResizeDrag.ts +94 -0
- package/src/modules/stack/StackContent.spec.tsx +264 -0
- package/src/modules/stack/StackContent.tsx +111 -0
- package/src/modules/stack/SwipeStackContent.spec.tsx +1564 -0
- package/src/modules/stack/SwipeStackContent.tsx +366 -0
- package/src/modules/stack/SwipeStackOutlet.spec.tsx +250 -0
- package/src/modules/stack/SwipeStackOutlet.tsx +221 -0
- package/src/modules/stack/computeStackContentState.spec.ts +281 -0
- package/src/modules/stack/computeStackContentState.ts +304 -0
- package/src/modules/stack/computeSwipeStackTransform.spec.ts +186 -0
- package/src/modules/stack/computeSwipeStackTransform.ts +145 -0
- package/src/modules/stack/swipeTransitionContinuity.spec.tsx +1133 -0
- package/src/modules/stack/types.ts +226 -0
- package/src/modules/stack/useStackAnimationState.spec.ts +188 -0
- package/src/modules/stack/useStackAnimationState.ts +143 -0
- package/src/modules/stack/useStackNavigation.spec.ts +672 -0
- package/src/modules/stack/useStackNavigation.tsx +393 -0
- package/src/modules/stack/useStackSwipeInput.spec.ts +309 -0
- package/src/modules/stack/useStackSwipeInput.ts +139 -0
- package/src/modules/window/useDrawerState.ts +81 -0
- package/src/modules/window/useFloatingState.spec.ts +252 -0
- package/src/modules/window/useFloatingState.ts +141 -0
- package/src/panels/index.ts +119 -0
- package/src/pivot/index.ts +19 -0
- package/src/resizer/index.ts +68 -0
- package/src/stack/index.ts +91 -0
- package/src/sticky-header/StickyArea.tsx +193 -0
- package/src/sticky-header/calculateStickyMetrics.spec.ts +105 -0
- package/src/sticky-header/calculateStickyMetrics.ts +50 -0
- package/src/sticky-header/index.ts +18 -0
- package/src/sticky-header/types.ts +68 -0
- package/src/types.ts +341 -0
- package/src/utils/CSSMatrix.ts +321 -0
- package/src/utils/css.ts +65 -0
- package/src/utils/dialogUtils.ts +43 -0
- package/src/utils/math.ts +18 -0
- package/src/utils/polyfills/createDialogPolyfill.ts +18 -0
- package/src/utils/typedActions.ts +103 -0
- package/src/vite-env.d.ts +6 -0
- package/src/window/index.ts +69 -0
- package/dist/GridLayout-BQQ63eA1.cjs +0 -2
- package/dist/GridLayout-BQQ63eA1.cjs.map +0 -1
- package/dist/GridLayout-CJTKq7Mp.js +0 -1465
- package/dist/GridLayout-CJTKq7Mp.js.map +0 -1
- package/dist/sticky-header/StickyHeader.d.ts +0 -53
- package/dist/styles-CA2_zLZt.js +0 -52
- package/dist/styles-CA2_zLZt.js.map +0 -1
- package/dist/styles-PsqGOEJP.cjs +0 -2
- package/dist/styles-PsqGOEJP.cjs.map +0 -1
- package/dist/usePivot-7ctin_P_.cjs +0 -2
- package/dist/usePivot-7ctin_P_.cjs.map +0 -1
- package/dist/usePivot-CgQxB8rc.js +0 -124
- package/dist/usePivot-CgQxB8rc.js.map +0 -1
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Tests for useResizeObserver hook.
|
|
3
|
+
*
|
|
4
|
+
* These tests define the contract that useResizeObserver must fulfill.
|
|
5
|
+
* The key requirement is that consuming components can rely on containerSize
|
|
6
|
+
* being available when their animation logic runs.
|
|
7
|
+
*/
|
|
8
|
+
/* eslint-disable no-restricted-syntax -- Dynamic imports needed for isolated module testing */
|
|
9
|
+
import { render, act } from "@testing-library/react";
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
|
|
12
|
+
// We'll import the hook after defining what it should do
|
|
13
|
+
// import { useResizeObserver } from "./useResizeObserver.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Mock ResizeObserver
|
|
17
|
+
*/
|
|
18
|
+
class MockResizeObserver implements ResizeObserver {
|
|
19
|
+
private static instances: MockResizeObserver[] = [];
|
|
20
|
+
private callback: ResizeObserverCallback;
|
|
21
|
+
private observed = new Set<Element>();
|
|
22
|
+
|
|
23
|
+
static getInstances(): MockResizeObserver[] {
|
|
24
|
+
return this.instances;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static clearInstances(): void {
|
|
28
|
+
this.instances = [];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
constructor(callback: ResizeObserverCallback) {
|
|
32
|
+
this.callback = callback;
|
|
33
|
+
MockResizeObserver.instances.push(this);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Required for interface compatibility
|
|
37
|
+
observe(target: Element, options?: ResizeObserverOptions): void {
|
|
38
|
+
this.observed.add(target);
|
|
39
|
+
// Real ResizeObserver fires callback asynchronously after observe
|
|
40
|
+
// We simulate immediate callback for testing
|
|
41
|
+
const entry = this.createEntry(target, 400, 300);
|
|
42
|
+
this.callback([entry], this);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
unobserve(target: Element): void {
|
|
46
|
+
this.observed.delete(target);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
disconnect(): void {
|
|
50
|
+
this.observed.clear();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
triggerResize(target: Element, width: number, height: number): void {
|
|
54
|
+
if (this.observed.has(target)) {
|
|
55
|
+
const entry = this.createEntry(target, width, height);
|
|
56
|
+
this.callback([entry], this);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private createEntry(target: Element, width: number, height: number): ResizeObserverEntry {
|
|
61
|
+
return {
|
|
62
|
+
target,
|
|
63
|
+
contentRect: new DOMRect(0, 0, width, height),
|
|
64
|
+
borderBoxSize: [{ inlineSize: width, blockSize: height }],
|
|
65
|
+
contentBoxSize: [{ inlineSize: width, blockSize: height }],
|
|
66
|
+
devicePixelContentBoxSize: [],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const originalResizeObserver = globalThis.ResizeObserver;
|
|
72
|
+
|
|
73
|
+
describe("useResizeObserver contract", () => {
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
MockResizeObserver.clearInstances();
|
|
76
|
+
globalThis.ResizeObserver = MockResizeObserver;
|
|
77
|
+
|
|
78
|
+
// Mock getBoundingClientRect
|
|
79
|
+
Element.prototype.getBoundingClientRect = function () {
|
|
80
|
+
return new DOMRect(0, 0, 400, 300);
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
afterEach(() => {
|
|
85
|
+
globalThis.ResizeObserver = originalResizeObserver;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("timing requirements", () => {
|
|
89
|
+
/**
|
|
90
|
+
* This is the critical test case.
|
|
91
|
+
*
|
|
92
|
+
* In the real use case (StackTablet -> SwipeStackContent):
|
|
93
|
+
* 1. StackTablet renders, calls useResizeObserver
|
|
94
|
+
* 2. StackTablet passes containerSize to SwipeStackContent
|
|
95
|
+
* 3. SwipeStackContent uses containerSize in its first useLayoutEffect
|
|
96
|
+
*
|
|
97
|
+
* The question: Can containerSize be > 0 when SwipeStackContent's
|
|
98
|
+
* useLayoutEffect runs for the first time?
|
|
99
|
+
*
|
|
100
|
+
* Answer: This depends on React's effect execution order.
|
|
101
|
+
* - Effects run in order of hook registration
|
|
102
|
+
* - Parent's effects run before children's effects? NO.
|
|
103
|
+
* - Actually, React runs effects bottom-up (children first, then parents)
|
|
104
|
+
*
|
|
105
|
+
* So when SwipeStackContent's useLayoutEffect runs:
|
|
106
|
+
* - It's the FIRST effect to run (child before parent)
|
|
107
|
+
* - useResizeObserver's useLayoutEffect hasn't run yet
|
|
108
|
+
* - Therefore containerSize is still 0
|
|
109
|
+
*
|
|
110
|
+
* This means we MUST handle containerSize=0 in SwipeStackContent.
|
|
111
|
+
* The question is: how to abstract this properly?
|
|
112
|
+
*/
|
|
113
|
+
it("documents React effect execution order", () => {
|
|
114
|
+
const executionOrder: string[] = [];
|
|
115
|
+
|
|
116
|
+
const Child: React.FC<{ size: number }> = ({ size }) => {
|
|
117
|
+
React.useLayoutEffect(() => {
|
|
118
|
+
executionOrder.push(`child-layout-effect: size=${size}`);
|
|
119
|
+
}, []);
|
|
120
|
+
|
|
121
|
+
return <div>Child: {size}</div>;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const Parent: React.FC = () => {
|
|
125
|
+
const ref = React.useRef<HTMLDivElement>(null);
|
|
126
|
+
const [size, setSize] = React.useState(0);
|
|
127
|
+
|
|
128
|
+
React.useLayoutEffect(() => {
|
|
129
|
+
executionOrder.push("parent-layout-effect: measuring");
|
|
130
|
+
if (ref.current) {
|
|
131
|
+
setSize(ref.current.getBoundingClientRect().width);
|
|
132
|
+
}
|
|
133
|
+
}, []);
|
|
134
|
+
|
|
135
|
+
executionOrder.push(`parent-render: size=${size}`);
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<div ref={ref}>
|
|
139
|
+
<Child size={size} />
|
|
140
|
+
</div>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
render(<Parent />);
|
|
145
|
+
|
|
146
|
+
// This documents the actual execution order
|
|
147
|
+
// Parent renders first with size=0
|
|
148
|
+
// Child renders with size=0
|
|
149
|
+
// Child's useLayoutEffect runs (sees size=0)
|
|
150
|
+
// Parent's useLayoutEffect runs (sets size=400)
|
|
151
|
+
// Re-render with size=400
|
|
152
|
+
expect(executionOrder).toContain("child-layout-effect: size=0");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Given the above, the proper abstraction is:
|
|
157
|
+
*
|
|
158
|
+
* useResizeObserver should provide a way for consumers to know
|
|
159
|
+
* when the size is "ready" (first valid measurement complete).
|
|
160
|
+
*
|
|
161
|
+
* Consumers that depend on size for animation should:
|
|
162
|
+
* - Not start animation until size is ready
|
|
163
|
+
* - OR use a hook that handles this internally
|
|
164
|
+
*/
|
|
165
|
+
it("should indicate when size is ready", async () => {
|
|
166
|
+
// Import dynamically to test the implementation
|
|
167
|
+
const { useResizeObserver } = await import("./useResizeObserver.js");
|
|
168
|
+
|
|
169
|
+
const results: Array<{ width: number; isReady: boolean }> = [];
|
|
170
|
+
|
|
171
|
+
const TestComponent: React.FC = () => {
|
|
172
|
+
const ref = React.useRef<HTMLDivElement>(null);
|
|
173
|
+
const { rect } = useResizeObserver(ref, { box: "border-box" });
|
|
174
|
+
|
|
175
|
+
const width = rect?.width ?? 0;
|
|
176
|
+
const isReady = rect !== null;
|
|
177
|
+
|
|
178
|
+
React.useEffect(() => {
|
|
179
|
+
results.push({ width, isReady });
|
|
180
|
+
}, [width, isReady]);
|
|
181
|
+
|
|
182
|
+
return <div ref={ref} style={{ width: 400, height: 300 }} />;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
render(<TestComponent />);
|
|
186
|
+
|
|
187
|
+
// After effects run, size should be available
|
|
188
|
+
await act(async () => {});
|
|
189
|
+
|
|
190
|
+
const lastResult = results[results.length - 1];
|
|
191
|
+
expect(lastResult.isReady).toBe(true);
|
|
192
|
+
expect(lastResult.width).toBe(400);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("memory efficiency", () => {
|
|
197
|
+
it("shares ResizeObserver instances for same box option", async () => {
|
|
198
|
+
const { useResizeObserver, clearObserverCache } = await import("./useResizeObserver.js");
|
|
199
|
+
clearObserverCache();
|
|
200
|
+
MockResizeObserver.clearInstances();
|
|
201
|
+
|
|
202
|
+
const TestComponent: React.FC = () => {
|
|
203
|
+
const ref1 = React.useRef<HTMLDivElement>(null);
|
|
204
|
+
const ref2 = React.useRef<HTMLDivElement>(null);
|
|
205
|
+
const ref3 = React.useRef<HTMLDivElement>(null);
|
|
206
|
+
|
|
207
|
+
useResizeObserver(ref1, { box: "border-box" });
|
|
208
|
+
useResizeObserver(ref2, { box: "border-box" });
|
|
209
|
+
useResizeObserver(ref3, { box: "border-box" });
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<>
|
|
213
|
+
<div ref={ref1} />
|
|
214
|
+
<div ref={ref2} />
|
|
215
|
+
<div ref={ref3} />
|
|
216
|
+
</>
|
|
217
|
+
);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
render(<TestComponent />);
|
|
221
|
+
|
|
222
|
+
expect(MockResizeObserver.getInstances().length).toBe(1);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
describe("resize updates", () => {
|
|
227
|
+
it("updates when element size changes", async () => {
|
|
228
|
+
const { useResizeObserver, clearObserverCache } = await import("./useResizeObserver.js");
|
|
229
|
+
clearObserverCache();
|
|
230
|
+
MockResizeObserver.clearInstances();
|
|
231
|
+
|
|
232
|
+
const widths: number[] = [];
|
|
233
|
+
|
|
234
|
+
const TestComponent: React.FC = () => {
|
|
235
|
+
const ref = React.useRef<HTMLDivElement>(null);
|
|
236
|
+
const { rect } = useResizeObserver(ref, { box: "border-box" });
|
|
237
|
+
|
|
238
|
+
React.useEffect(() => {
|
|
239
|
+
if (rect) {
|
|
240
|
+
widths.push(rect.width);
|
|
241
|
+
}
|
|
242
|
+
}, [rect]);
|
|
243
|
+
|
|
244
|
+
return <div ref={ref} data-testid="target" />;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
const { getByTestId } = render(<TestComponent />);
|
|
248
|
+
|
|
249
|
+
await act(async () => {});
|
|
250
|
+
|
|
251
|
+
const element = getByTestId("target");
|
|
252
|
+
const observer = MockResizeObserver.getInstances()[0];
|
|
253
|
+
|
|
254
|
+
act(() => {
|
|
255
|
+
observer.triggerResize(element, 800, 600);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
expect(widths).toContain(400); // Initial
|
|
259
|
+
expect(widths).toContain(800); // After resize
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Based on the tests above, the conclusion is:
|
|
266
|
+
*
|
|
267
|
+
* 1. React's effect execution order means child effects run before parent effects
|
|
268
|
+
* 2. Therefore, on first render, child components will see containerSize=0
|
|
269
|
+
* 3. This is a fundamental React constraint, not a bug in useResizeObserver
|
|
270
|
+
*
|
|
271
|
+
* The proper abstraction for SwipeStackContent is:
|
|
272
|
+
* - Check if containerSize > 0 before consuming isFirstMount
|
|
273
|
+
* - This is NOT a workaround, it's the correct pattern for this React constraint
|
|
274
|
+
*
|
|
275
|
+
* Alternatively, create a higher-level hook like useAnimatedStack that
|
|
276
|
+
* encapsulates both the size observation and the "ready" state.
|
|
277
|
+
*/
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Shared useResizeObserver hook with cached observer instances.
|
|
3
|
+
*
|
|
4
|
+
* Provides element size observation with shared observers for memory efficiency.
|
|
5
|
+
* Size becomes available after the first useLayoutEffect cycle completes.
|
|
6
|
+
*
|
|
7
|
+
* Note: Due to React's effect execution order (children before parents),
|
|
8
|
+
* child components may see containerSize=0 on their first effect run.
|
|
9
|
+
* This is a React constraint, not a bug. Consumers should check for
|
|
10
|
+
* valid size before using it for calculations like animation positions.
|
|
11
|
+
*/
|
|
12
|
+
import * as React from "react";
|
|
13
|
+
import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Shared ResizeObserver that can observe multiple elements.
|
|
17
|
+
*/
|
|
18
|
+
type SharedObserver = {
|
|
19
|
+
observe: (target: Element, callback: (entry: ResizeObserverEntry) => void) => () => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/** Cache of shared observers per box option */
|
|
23
|
+
const observerCache = new Map<string, SharedObserver>();
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get or create a shared ResizeObserver for the given box option.
|
|
27
|
+
*/
|
|
28
|
+
const getSharedObserver = (box: ResizeObserverBoxOptions): SharedObserver => {
|
|
29
|
+
const observerKey = `resize-box:${box}`;
|
|
30
|
+
const cached = observerCache.get(observerKey);
|
|
31
|
+
if (cached) {
|
|
32
|
+
return cached;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const callbacks = new Map<Element, (entry: ResizeObserverEntry) => void>();
|
|
36
|
+
|
|
37
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
38
|
+
for (const entry of entries) {
|
|
39
|
+
const callback = callbacks.get(entry.target);
|
|
40
|
+
if (callback) {
|
|
41
|
+
callback(entry);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
const sharedObserver: SharedObserver = {
|
|
47
|
+
observe(target, callback) {
|
|
48
|
+
callbacks.set(target, callback);
|
|
49
|
+
resizeObserver.observe(target, { box });
|
|
50
|
+
|
|
51
|
+
return () => {
|
|
52
|
+
callbacks.delete(target);
|
|
53
|
+
resizeObserver.unobserve(target);
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
observerCache.set(observerKey, sharedObserver);
|
|
59
|
+
return sharedObserver;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Create a ResizeObserverEntry from getBoundingClientRect.
|
|
64
|
+
*/
|
|
65
|
+
const measureElement = (target: Element): ResizeObserverEntry => {
|
|
66
|
+
const rect = target.getBoundingClientRect();
|
|
67
|
+
return {
|
|
68
|
+
target,
|
|
69
|
+
contentRect: rect,
|
|
70
|
+
borderBoxSize: [{ inlineSize: rect.width, blockSize: rect.height }],
|
|
71
|
+
contentBoxSize: [{ inlineSize: rect.width, blockSize: rect.height }],
|
|
72
|
+
devicePixelContentBoxSize: [],
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Extract DOMRect from ResizeObserverEntry.
|
|
78
|
+
*/
|
|
79
|
+
const entryToRect = (entry: ResizeObserverEntry): DOMRect => {
|
|
80
|
+
if (entry.borderBoxSize?.length > 0) {
|
|
81
|
+
const size = entry.borderBoxSize[0];
|
|
82
|
+
return new DOMRect(0, 0, size.inlineSize, size.blockSize);
|
|
83
|
+
}
|
|
84
|
+
return entry.contentRect;
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Clear observer cache. Exported for testing purposes.
|
|
89
|
+
*/
|
|
90
|
+
export function clearObserverCache(): void {
|
|
91
|
+
observerCache.clear();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Observe size changes for a given element reference using shared resize observers.
|
|
96
|
+
*
|
|
97
|
+
* @param ref - Ref holding the element whose size to monitor.
|
|
98
|
+
* @param options - Resize observer configuration.
|
|
99
|
+
* @returns Latest resize entry and a derived DOMRect snapshot.
|
|
100
|
+
*
|
|
101
|
+
* @remarks
|
|
102
|
+
* The `rect` will be `null` on the first render. After the initial
|
|
103
|
+
* useLayoutEffect runs and triggers a re-render, `rect` will contain
|
|
104
|
+
* the measured size.
|
|
105
|
+
*
|
|
106
|
+
* Due to React's effect execution order, child components' effects run
|
|
107
|
+
* before parent effects. If you pass `rect.width` to a child as a prop,
|
|
108
|
+
* the child's first effect will see `0` (or whatever default you use).
|
|
109
|
+
* This is expected React behavior.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```tsx
|
|
113
|
+
* const containerRef = useRef<HTMLDivElement>(null);
|
|
114
|
+
* const { rect } = useResizeObserver(containerRef, { box: "border-box" });
|
|
115
|
+
* const width = rect?.width ?? 0;
|
|
116
|
+
*
|
|
117
|
+
* // Check if size is ready before using for calculations
|
|
118
|
+
* const isReady = rect !== null;
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export function useResizeObserver<T extends HTMLElement>(
|
|
122
|
+
ref: React.RefObject<T | null>,
|
|
123
|
+
{ box = "content-box" }: ResizeObserverOptions,
|
|
124
|
+
) {
|
|
125
|
+
const [entry, setEntry] = React.useState<ResizeObserverEntry | null>(null);
|
|
126
|
+
|
|
127
|
+
useIsomorphicLayoutEffect(() => {
|
|
128
|
+
const target = ref.current;
|
|
129
|
+
if (!target) {
|
|
130
|
+
setEntry(null);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Measure immediately
|
|
135
|
+
setEntry(measureElement(target));
|
|
136
|
+
|
|
137
|
+
// Set up ResizeObserver for subsequent updates
|
|
138
|
+
const observer = getSharedObserver(box);
|
|
139
|
+
return observer.observe(target, setEntry);
|
|
140
|
+
}, [ref, box]);
|
|
141
|
+
|
|
142
|
+
const rect = React.useMemo(() => {
|
|
143
|
+
if (!entry) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
return entryToRect(entry);
|
|
147
|
+
}, [entry]);
|
|
148
|
+
|
|
149
|
+
return { entry, rect };
|
|
150
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file useScrollContainer - Detect the nearest scrollable ancestor
|
|
3
|
+
*
|
|
4
|
+
* Traverses the DOM tree to find the nearest ancestor with overflow: scroll/auto.
|
|
5
|
+
* Returns null if the document is the scroll container.
|
|
6
|
+
*/
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Check if an element is a scroll container.
|
|
12
|
+
*/
|
|
13
|
+
function isScrollContainer(element: Element): boolean {
|
|
14
|
+
const style = getComputedStyle(element);
|
|
15
|
+
const overflowY = style.overflowY;
|
|
16
|
+
const overflowX = style.overflowX;
|
|
17
|
+
|
|
18
|
+
return overflowY === "scroll" || overflowY === "auto" || overflowX === "scroll" || overflowX === "auto";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Find the nearest scrollable ancestor of an element.
|
|
23
|
+
*
|
|
24
|
+
* @param element - Starting element to search from
|
|
25
|
+
* @returns The nearest scrollable ancestor, or null if document is the container
|
|
26
|
+
*/
|
|
27
|
+
function findScrollContainer(element: Element | null): HTMLElement | null {
|
|
28
|
+
if (!element) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// eslint-disable-next-line no-restricted-syntax -- DOM traversal requires let
|
|
33
|
+
let current = element.parentElement;
|
|
34
|
+
|
|
35
|
+
while (current) {
|
|
36
|
+
if (isScrollContainer(current)) {
|
|
37
|
+
return current;
|
|
38
|
+
}
|
|
39
|
+
current = current.parentElement;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Hook to detect the nearest scrollable ancestor of a ref element.
|
|
47
|
+
*
|
|
48
|
+
* @param ref - Ref to the element to find scroll container for
|
|
49
|
+
* @returns The nearest scrollable ancestor element, or null if document is the container
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* const elementRef = useRef<HTMLDivElement>(null);
|
|
54
|
+
* const scrollContainer = useScrollContainer(elementRef);
|
|
55
|
+
* // scrollContainer is HTMLElement if in nested scroll, null if document scroll
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export function useScrollContainer<T extends HTMLElement>(ref: React.RefObject<T | null>): HTMLElement | null {
|
|
59
|
+
const [container, setContainer] = React.useState<HTMLElement | null>(null);
|
|
60
|
+
|
|
61
|
+
useIsomorphicLayoutEffect(() => {
|
|
62
|
+
const element = ref.current;
|
|
63
|
+
if (!element) {
|
|
64
|
+
setContainer(null);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const scrollContainer = findScrollContainer(element);
|
|
69
|
+
setContainer(scrollContainer);
|
|
70
|
+
}, [ref]);
|
|
71
|
+
|
|
72
|
+
return container;
|
|
73
|
+
}
|