react-panel-layout 0.5.1 → 0.6.0
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-D9Cp2al1.cjs → FloatingPanelFrame-CEmXDvUA.cjs} +2 -2
- package/dist/FloatingPanelFrame-CEmXDvUA.cjs.map +1 -0
- package/dist/{FloatingPanelFrame-6W5OexYe.js → FloatingPanelFrame-SgYLc6Ud.js} +12 -15
- package/dist/FloatingPanelFrame-SgYLc6Ud.js.map +1 -0
- package/dist/FloatingWindow-BpdOpg_L.js +400 -0
- package/dist/FloatingWindow-BpdOpg_L.js.map +1 -0
- package/dist/FloatingWindow-TCDNY5gE.cjs +2 -0
- package/dist/FloatingWindow-TCDNY5gE.cjs.map +1 -0
- package/dist/GridLayout-B4VRsC0r.cjs +2 -0
- package/dist/GridLayout-B4VRsC0r.cjs.map +1 -0
- package/dist/GridLayout-BltqeCPK.js +927 -0
- package/dist/GridLayout-BltqeCPK.js.map +1 -0
- package/dist/HorizontalDivider-B5Z-KZLk.cjs +2 -0
- package/dist/HorizontalDivider-B5Z-KZLk.cjs.map +1 -0
- package/dist/HorizontalDivider-WF1k_qND.js +30 -0
- package/dist/HorizontalDivider-WF1k_qND.js.map +1 -0
- package/dist/PanelSystem-Bs8bQwQF.cjs +3 -0
- package/dist/PanelSystem-Bs8bQwQF.cjs.map +1 -0
- package/dist/PanelSystem-Dr1TBhxM.js +1946 -0
- package/dist/PanelSystem-Dr1TBhxM.js.map +1 -0
- package/dist/ResizeHandle-CScipO5l.cjs +2 -0
- package/dist/ResizeHandle-CScipO5l.cjs.map +1 -0
- package/dist/ResizeHandle-CdA_JYfN.js +120 -0
- package/dist/ResizeHandle-CdA_JYfN.js.map +1 -0
- package/dist/SwipePivotTabBar-BGO9X94m.js +407 -0
- package/dist/SwipePivotTabBar-BGO9X94m.js.map +1 -0
- package/dist/SwipePivotTabBar-BrQismcZ.cjs +2 -0
- package/dist/SwipePivotTabBar-BrQismcZ.cjs.map +1 -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 +18 -4
- 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 +110 -0
- package/dist/hooks/gesture/thresholdValue.d.ts +44 -0
- package/dist/hooks/gesture/types.d.ts +254 -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 +40 -0
- package/dist/hooks/useAnimatedVisibility.d.ts +58 -0
- package/dist/hooks/useAnimationFrame.d.ts +84 -0
- package/dist/hooks/useSnapAnimation.d.ts +54 -0
- package/dist/hooks/useSwipeContentTransform.d.ts +79 -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/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 +89 -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 +73 -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 +63 -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 +980 -0
- package/dist/stack.js.map +1 -0
- package/dist/sticky-header/StickyArea.d.ts +38 -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 +65 -174
- package/dist/sticky-header.js.map +1 -1
- package/dist/styles-DPPuJ0sf.js +57 -0
- package/dist/styles-DPPuJ0sf.js.map +1 -0
- package/dist/styles-qf6ptVLD.cjs +2 -0
- package/dist/styles-qf6ptVLD.cjs.map +1 -0
- package/dist/types.d.ts +12 -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-CKdhGXd0.js +46 -0
- package/dist/useDocumentPointerEvents-CKdhGXd0.js.map +1 -0
- package/dist/useDocumentPointerEvents-ChqrKXDk.cjs +2 -0
- package/dist/useDocumentPointerEvents-ChqrKXDk.cjs.map +1 -0
- package/dist/useEffectEvent-Dp7HLCf0.js +13 -0
- package/dist/useEffectEvent-Dp7HLCf0.js.map +1 -0
- package/dist/useEffectEvent-huSsGUnl.cjs +2 -0
- package/dist/useEffectEvent-huSsGUnl.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/window/index.d.ts +61 -0
- package/dist/window.cjs +2 -0
- package/dist/window.cjs.map +1 -0
- package/dist/window.js +149 -0
- package/dist/window.js.map +1 -0
- package/docs/design-tokens.md +405 -0
- package/package.json +29 -4
- package/src/PanelSystemContext.tsx +88 -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 +282 -0
- package/src/components/window/DrawerLayers.tsx +58 -0
- package/src/components/window/FloatingWindow.tsx +95 -0
- package/src/components/window/PopupLayerPortal.tsx +218 -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 +261 -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/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/menu/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 +289 -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.tsx +217 -0
- package/src/demo/pages/Stack/components/StackTablet.module.css +299 -0
- package/src/demo/pages/Stack/components/StackTablet.tsx +401 -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 +193 -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/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 +237 -0
- package/src/hooks/gesture/testing/createGestureSimulator.ts +310 -0
- package/src/hooks/gesture/thresholdValue.spec.ts +103 -0
- package/src/hooks/gesture/thresholdValue.ts +77 -0
- package/src/hooks/gesture/types.ts +290 -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 +454 -0
- package/src/hooks/gesture/useEdgeSwipeInput.ts +131 -0
- package/src/hooks/gesture/useNativeGestureGuard.spec.ts +413 -0
- package/src/hooks/gesture/useNativeGestureGuard.ts +133 -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 +87 -0
- package/src/hooks/useAnimatedVisibility.spec.ts +257 -0
- package/src/hooks/useAnimatedVisibility.ts +146 -0
- package/src/hooks/useAnimationFrame.ts +200 -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/useResizeObserver.tsx +81 -0
- package/src/hooks/useScrollContainer.ts +79 -0
- package/src/hooks/useSnapAnimation.ts +128 -0
- package/src/hooks/useSwipeContentTransform.spec.ts +133 -0
- package/src/hooks/useSwipeContentTransform.ts +235 -0
- package/src/hooks/useTransitionState.ts +95 -0
- package/src/index.tsx +88 -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 +304 -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 +167 -0
- package/src/modules/pivot/SwipePivotContent.spec.tsx +464 -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 +865 -0
- package/src/modules/pivot/SwipePivotTabBar.tsx +523 -0
- package/src/modules/pivot/index.ts +8 -0
- package/src/modules/pivot/scaleInputState.spec.ts +210 -0
- package/src/modules/pivot/scaleInputState.ts +66 -0
- package/src/modules/pivot/types.ts +139 -0
- package/src/modules/pivot/usePivot.spec.ts +621 -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 +649 -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 +1277 -0
- package/src/modules/stack/SwipeStackContent.tsx +356 -0
- package/src/modules/stack/SwipeStackOutlet.spec.tsx +252 -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/types.ts +226 -0
- package/src/modules/stack/useStackAnimationState.spec.ts +186 -0
- package/src/modules/stack/useStackAnimationState.ts +138 -0
- package/src/modules/stack/useStackNavigation.spec.ts +477 -0
- package/src/modules/stack/useStackNavigation.tsx +336 -0
- package/src/modules/stack/useStackSwipeInput.spec.ts +276 -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 +221 -0
- package/src/sticky-header/index.ts +18 -0
- package/src/sticky-header/types.ts +68 -0
- package/src/types.ts +323 -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 +67 -0
- package/dist/FloatingPanelFrame-6W5OexYe.js.map +0 -1
- package/dist/FloatingPanelFrame-D9Cp2al1.cjs.map +0 -1
- package/dist/GridLayout-BzrIDrC9.js +0 -1465
- package/dist/GridLayout-BzrIDrC9.js.map +0 -1
- package/dist/GridLayout-ZrOhoLLB.cjs +0 -2
- package/dist/GridLayout-ZrOhoLLB.cjs.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-BS-DGfwd.cjs +0 -2
- package/dist/usePivot-BS-DGfwd.cjs.map +0 -1
- package/dist/usePivot-BvOGxLQQ.js +0 -124
- package/dist/usePivot-BvOGxLQQ.js.map +0 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Panels entry point - VSCode-like panel system
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*
|
|
5
|
+
* This is a subpath export entry point for `react-panel-layout/panels`.
|
|
6
|
+
*
|
|
7
|
+
* ## Overview
|
|
8
|
+
* Panels provides a VSCode-like panel system with tabbed groups, drag-and-drop
|
|
9
|
+
* tab reordering, split views, and keyboard navigation. Supports both controlled
|
|
10
|
+
* and uncontrolled state management.
|
|
11
|
+
*
|
|
12
|
+
* ## Installation
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { PanelSystem, buildInitialState, usePanelSystem } from "react-panel-layout/panels";
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ## Basic Usage
|
|
18
|
+
* ```tsx
|
|
19
|
+
* const tabs = [
|
|
20
|
+
* { id: 'file1', title: 'index.ts', render: () => <Editor file="index.ts" /> },
|
|
21
|
+
* { id: 'file2', title: 'app.tsx', render: () => <Editor file="app.tsx" /> },
|
|
22
|
+
* ];
|
|
23
|
+
*
|
|
24
|
+
* function App() {
|
|
25
|
+
* const initialState = buildInitialState(tabs);
|
|
26
|
+
* let groupCounter = 1;
|
|
27
|
+
*
|
|
28
|
+
* return (
|
|
29
|
+
* <PanelSystem
|
|
30
|
+
* initialState={initialState}
|
|
31
|
+
* createGroupId={() => `g_${++groupCounter}`}
|
|
32
|
+
* layoutMode="grid"
|
|
33
|
+
* gridTracksInteractive={true}
|
|
34
|
+
* dragThresholdPx={5}
|
|
35
|
+
* />
|
|
36
|
+
* );
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* ## Controlled State
|
|
41
|
+
* ```tsx
|
|
42
|
+
* const [state, setState] = useState(() => buildInitialState(tabs));
|
|
43
|
+
*
|
|
44
|
+
* <PanelSystem
|
|
45
|
+
* initialState={state}
|
|
46
|
+
* state={state}
|
|
47
|
+
* onStateChange={setState}
|
|
48
|
+
* // ...
|
|
49
|
+
* />
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* ## Using Context
|
|
53
|
+
* ```tsx
|
|
54
|
+
* function TabActions() {
|
|
55
|
+
* const { actions } = usePanelSystem();
|
|
56
|
+
* return <button onClick={() => actions.splitFocused('vertical')}>Split</button>;
|
|
57
|
+
* }
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
// Components
|
|
62
|
+
export { PanelSystem } from "../modules/panels/system/PanelSystem.js";
|
|
63
|
+
export { PanelGroupView } from "../components/panels/PanelGroupView.js";
|
|
64
|
+
export { DropSuggestOverlay } from "../components/panels/DropSuggestOverlay.js";
|
|
65
|
+
|
|
66
|
+
// Context
|
|
67
|
+
export {
|
|
68
|
+
PanelSystemProvider,
|
|
69
|
+
usePanelSystem,
|
|
70
|
+
} from "../modules/panels/state/PanelSystemContext.js";
|
|
71
|
+
|
|
72
|
+
// State operations
|
|
73
|
+
export {
|
|
74
|
+
collectGroupsInOrder,
|
|
75
|
+
splitLeaf,
|
|
76
|
+
closeLeaf,
|
|
77
|
+
isGroup,
|
|
78
|
+
setSplitRatio,
|
|
79
|
+
createEmptyGroup,
|
|
80
|
+
addTabToGroup,
|
|
81
|
+
removeTabFromGroup,
|
|
82
|
+
moveTab,
|
|
83
|
+
setActiveTab,
|
|
84
|
+
reorderTabWithinGroup,
|
|
85
|
+
addTabToGroupAtIndex,
|
|
86
|
+
setFocusedGroup,
|
|
87
|
+
focusGroupIndex,
|
|
88
|
+
nextGroup,
|
|
89
|
+
prevGroup,
|
|
90
|
+
refreshGroupOrder,
|
|
91
|
+
splitGroup,
|
|
92
|
+
buildInitialState,
|
|
93
|
+
} from "../modules/panels/index.js";
|
|
94
|
+
|
|
95
|
+
// Types
|
|
96
|
+
export type {
|
|
97
|
+
PanelId,
|
|
98
|
+
GroupId,
|
|
99
|
+
SplitDirection,
|
|
100
|
+
TabDefinition,
|
|
101
|
+
GroupModel,
|
|
102
|
+
PanelTree,
|
|
103
|
+
PanelSystemState,
|
|
104
|
+
DropZone,
|
|
105
|
+
DraggingTab,
|
|
106
|
+
PanelCommands,
|
|
107
|
+
PanelSystemProps,
|
|
108
|
+
PanelSplitLimits,
|
|
109
|
+
IdFactory,
|
|
110
|
+
} from "../modules/panels/index.js";
|
|
111
|
+
|
|
112
|
+
export type {
|
|
113
|
+
PanelSystemContextValue,
|
|
114
|
+
PanelSystemProviderProps,
|
|
115
|
+
PanelStateAction,
|
|
116
|
+
PanelStateActions,
|
|
117
|
+
} from "../modules/panels/state/PanelSystemContext.js";
|
|
118
|
+
|
|
119
|
+
export type { PanelGroupViewProps } from "../components/panels/PanelGroupView.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Pivot entry point - Headless content switching
|
|
3
|
+
*
|
|
4
|
+
* Import via: import { usePivot } from "react-panel-layout/pivot";
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Hook
|
|
8
|
+
export { usePivot } from "../modules/pivot";
|
|
9
|
+
|
|
10
|
+
// Components
|
|
11
|
+
export { SwipePivotTabBar } from "../modules/pivot";
|
|
12
|
+
|
|
13
|
+
// Utilities
|
|
14
|
+
export { scaleInputState } from "../modules/pivot";
|
|
15
|
+
|
|
16
|
+
// Types
|
|
17
|
+
export type { PivotItem, UsePivotOptions, UsePivotResult, PivotItemProps } from "../modules/pivot";
|
|
18
|
+
export type { SwipePivotTabBarProps, IndicatorRenderProps } from "../modules/pivot";
|
|
19
|
+
export type { PivotBehavior, PivotBehaviorItem } from "../types";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Resizer entry point - Resize handle components and hooks
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*
|
|
5
|
+
* This is a subpath export entry point for `react-panel-layout/resizer`.
|
|
6
|
+
*
|
|
7
|
+
* ## Overview
|
|
8
|
+
* Resizer provides draggable resize handles for creating resizable layouts.
|
|
9
|
+
* Includes both ready-to-use components and a low-level hook for custom implementations.
|
|
10
|
+
*
|
|
11
|
+
* ## Installation
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { ResizeHandle, useResizeDrag } from "react-panel-layout/resizer";
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* ## Basic Usage with ResizeHandle
|
|
17
|
+
* ```tsx
|
|
18
|
+
* function ResizableLayout() {
|
|
19
|
+
* const [width, setWidth] = useState(300);
|
|
20
|
+
*
|
|
21
|
+
* return (
|
|
22
|
+
* <div style={{ display: 'flex' }}>
|
|
23
|
+
* <div style={{ width }}>Left Panel</div>
|
|
24
|
+
* <ResizeHandle
|
|
25
|
+
* direction="vertical"
|
|
26
|
+
* onResize={(delta) => setWidth((w) => w + delta)}
|
|
27
|
+
* />
|
|
28
|
+
* <div style={{ flex: 1 }}>Right Panel</div>
|
|
29
|
+
* </div>
|
|
30
|
+
* );
|
|
31
|
+
* }
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* ## Custom Handle with useResizeDrag
|
|
35
|
+
* ```tsx
|
|
36
|
+
* function CustomHandle({ onResize }) {
|
|
37
|
+
* const { ref, isDragging, onPointerDown } = useResizeDrag({
|
|
38
|
+
* axis: 'x',
|
|
39
|
+
* onResize,
|
|
40
|
+
* });
|
|
41
|
+
*
|
|
42
|
+
* return (
|
|
43
|
+
* <div
|
|
44
|
+
* ref={ref}
|
|
45
|
+
* onPointerDown={onPointerDown}
|
|
46
|
+
* style={{ cursor: 'col-resize', background: isDragging ? 'blue' : 'gray' }}
|
|
47
|
+
* />
|
|
48
|
+
* );
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
// Hooks
|
|
54
|
+
export { useResizeDrag } from "../modules/resizer/useResizeDrag.js";
|
|
55
|
+
|
|
56
|
+
// Components
|
|
57
|
+
export { ResizeHandle } from "../components/resizer/ResizeHandle.js";
|
|
58
|
+
export { HorizontalDivider } from "../components/resizer/HorizontalDivider.js";
|
|
59
|
+
|
|
60
|
+
// Types
|
|
61
|
+
export type {
|
|
62
|
+
ResizeDragAxis,
|
|
63
|
+
UseResizeDragOptions,
|
|
64
|
+
UseResizeDragResult,
|
|
65
|
+
} from "../modules/resizer/useResizeDrag.js";
|
|
66
|
+
|
|
67
|
+
export type { ResizeHandleProps } from "../components/resizer/ResizeHandle.js";
|
|
68
|
+
export type { HorizontalDividerProps } from "../components/resizer/HorizontalDivider.js";
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Stack entry point - Hierarchical navigation with swipe support
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*
|
|
5
|
+
* This is a subpath export entry point for `react-panel-layout/stack`.
|
|
6
|
+
*
|
|
7
|
+
* ## Overview
|
|
8
|
+
* Stack provides iOS/iPadOS-style hierarchical navigation where panels stack
|
|
9
|
+
* as users drill down into content. Supports swipe-to-go-back gestures.
|
|
10
|
+
*
|
|
11
|
+
* ## Installation
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { useStackNavigation, SwipeStackOutlet } from "react-panel-layout/stack";
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* ## Basic Usage
|
|
17
|
+
* ```tsx
|
|
18
|
+
* const panels = [
|
|
19
|
+
* { id: 'list', title: 'Items', content: <ListPage /> },
|
|
20
|
+
* { id: 'detail', title: 'Detail', content: <DetailPage /> },
|
|
21
|
+
* ];
|
|
22
|
+
*
|
|
23
|
+
* function App() {
|
|
24
|
+
* const { push, go, Outlet } = useStackNavigation({
|
|
25
|
+
* panels,
|
|
26
|
+
* displayMode: 'overlay',
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* return (
|
|
30
|
+
* <div>
|
|
31
|
+
* <button onClick={() => push('detail')}>View Detail</button>
|
|
32
|
+
* <button onClick={() => go(-1)}>Back</button>
|
|
33
|
+
* <Outlet />
|
|
34
|
+
* </div>
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* ## With Swipe Gestures (SwipeStackContent)
|
|
40
|
+
* ```tsx
|
|
41
|
+
* const containerRef = useRef<HTMLDivElement>(null);
|
|
42
|
+
* const navigation = useStackNavigation({ panels, displayMode: 'overlay' });
|
|
43
|
+
* const swipeInput = useStackSwipeInput({ containerRef, navigation });
|
|
44
|
+
* const { rect } = useResizeObserver(containerRef);
|
|
45
|
+
*
|
|
46
|
+
* return (
|
|
47
|
+
* <div ref={containerRef} {...swipeInput.containerProps}>
|
|
48
|
+
* {panels.map((panel, index) => (
|
|
49
|
+
* <SwipeStackContent
|
|
50
|
+
* key={panel.id}
|
|
51
|
+
* id={panel.id}
|
|
52
|
+
* depth={index}
|
|
53
|
+
* navigationDepth={navigation.state.depth}
|
|
54
|
+
* isActive={navigation.currentPanelId === panel.id}
|
|
55
|
+
* inputState={swipeInput.inputState}
|
|
56
|
+
* containerSize={rect?.width ?? 0}
|
|
57
|
+
* >
|
|
58
|
+
* {panel.content}
|
|
59
|
+
* </SwipeStackContent>
|
|
60
|
+
* ))}
|
|
61
|
+
* </div>
|
|
62
|
+
* );
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
// Hooks
|
|
67
|
+
export { useStackNavigation } from "../modules/stack/useStackNavigation.js";
|
|
68
|
+
export { useStackSwipeInput } from "../modules/stack/useStackSwipeInput.js";
|
|
69
|
+
|
|
70
|
+
// Components
|
|
71
|
+
export { StackContent } from "../modules/stack/StackContent.js";
|
|
72
|
+
export { SwipeStackContent } from "../modules/stack/SwipeStackContent.js";
|
|
73
|
+
export { SwipeStackOutlet } from "../modules/stack/SwipeStackOutlet.js";
|
|
74
|
+
|
|
75
|
+
// Types
|
|
76
|
+
export type {
|
|
77
|
+
StackDisplayMode,
|
|
78
|
+
StackTransitionMode,
|
|
79
|
+
StackPanel,
|
|
80
|
+
StackNavigationState,
|
|
81
|
+
StackPanelProps,
|
|
82
|
+
StackBackButtonProps,
|
|
83
|
+
UseStackNavigationOptions,
|
|
84
|
+
UseStackNavigationResult,
|
|
85
|
+
UseStackSwipeInputOptions,
|
|
86
|
+
UseStackSwipeInputResult,
|
|
87
|
+
StackContentProps,
|
|
88
|
+
} from "../modules/stack/types.js";
|
|
89
|
+
|
|
90
|
+
export type { SwipeStackContentProps } from "../modules/stack/SwipeStackContent.js";
|
|
91
|
+
export type { SwipeStackOutletProps } from "../modules/stack/SwipeStackOutlet.js";
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file StickyArea component for native app-like overscroll experience.
|
|
3
|
+
*
|
|
4
|
+
* Displays cover content that expands during overscroll/bounce,
|
|
5
|
+
* providing a native app-like pull effect commonly seen in iOS apps.
|
|
6
|
+
*
|
|
7
|
+
* Supports both top (header) and bottom (footer) positions.
|
|
8
|
+
* Works with document-level scroll only.
|
|
9
|
+
*/
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
import { useIsomorphicLayoutEffect } from "../hooks/useIsomorphicLayoutEffect";
|
|
12
|
+
import type { StickyAreaProps, StickyAreaState } from "./types";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get area styles based on position.
|
|
16
|
+
*/
|
|
17
|
+
function getAreaStyle(position: "top" | "bottom"): React.CSSProperties {
|
|
18
|
+
return {
|
|
19
|
+
position: "relative",
|
|
20
|
+
paddingTop: position === "top" ? "env(safe-area-inset-top)" : undefined,
|
|
21
|
+
paddingBottom: position === "bottom" ? "env(safe-area-inset-bottom)" : undefined,
|
|
22
|
+
boxSizing: "border-box",
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const bodyStyle: React.CSSProperties = {
|
|
27
|
+
zIndex: 1,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Get cover styles based on position.
|
|
32
|
+
* Explicitly disables transitions to prevent jank from inherited CSS.
|
|
33
|
+
*/
|
|
34
|
+
function getCoverStyle(position: "top" | "bottom"): React.CSSProperties {
|
|
35
|
+
return {
|
|
36
|
+
opacity: 0,
|
|
37
|
+
zIndex: 0,
|
|
38
|
+
userSelect: "none",
|
|
39
|
+
pointerEvents: "none",
|
|
40
|
+
// Disable transitions to prevent jank - styles are updated via RAF
|
|
41
|
+
transition: "none",
|
|
42
|
+
// Enable GPU acceleration for smoother animations
|
|
43
|
+
willChange: "height, opacity",
|
|
44
|
+
transform: "translateZ(0)",
|
|
45
|
+
position: "fixed",
|
|
46
|
+
top: position === "top" ? 0 : undefined,
|
|
47
|
+
bottom: position === "bottom" ? 0 : undefined,
|
|
48
|
+
left: 0,
|
|
49
|
+
right: 0,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const wrapperStyle: React.CSSProperties = {
|
|
54
|
+
position: "relative",
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* StickyArea provides a native app-like overscroll experience.
|
|
59
|
+
*
|
|
60
|
+
* When the user overscrolls (pulls beyond the edge), the cover content
|
|
61
|
+
* expands to fill the visible area, similar to native iOS/Android app behavior.
|
|
62
|
+
*
|
|
63
|
+
* Supports both top (header) and bottom (footer) positions.
|
|
64
|
+
* Works with document-level scroll only.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```tsx
|
|
68
|
+
* // Header (top) - expands on pull-down
|
|
69
|
+
* <StickyArea position="top" cover={<img src="/hero.jpg" />}>
|
|
70
|
+
* <header><h1>My App</h1></header>
|
|
71
|
+
* </StickyArea>
|
|
72
|
+
*
|
|
73
|
+
* // Footer (bottom) - expands on pull-up
|
|
74
|
+
* <StickyArea position="bottom" cover={<div className="footer-bg" />}>
|
|
75
|
+
* <footer>Footer content</footer>
|
|
76
|
+
* </StickyArea>
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export const StickyArea: React.FC<StickyAreaProps> = ({
|
|
80
|
+
position = "top",
|
|
81
|
+
cover,
|
|
82
|
+
children,
|
|
83
|
+
onStateChange,
|
|
84
|
+
}) => {
|
|
85
|
+
const areaRef = React.useRef<HTMLDivElement>(null);
|
|
86
|
+
const coverAreaRef = React.useRef<HTMLDivElement>(null);
|
|
87
|
+
|
|
88
|
+
// State for render function and callback
|
|
89
|
+
const [state, setState] = React.useState<StickyAreaState>({
|
|
90
|
+
isStuck: false,
|
|
91
|
+
scrollOffset: 0,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Update state when values change
|
|
95
|
+
const stateRef = React.useRef(state);
|
|
96
|
+
const updateState = React.useCallback(
|
|
97
|
+
(newState: StickyAreaState) => {
|
|
98
|
+
const prev = stateRef.current;
|
|
99
|
+
if (prev.isStuck !== newState.isStuck || prev.scrollOffset !== newState.scrollOffset) {
|
|
100
|
+
stateRef.current = newState;
|
|
101
|
+
setState(newState);
|
|
102
|
+
onStateChange?.(newState);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
[onStateChange],
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
useIsomorphicLayoutEffect(() => {
|
|
109
|
+
const area = areaRef.current;
|
|
110
|
+
const coverArea = coverAreaRef.current;
|
|
111
|
+
if (!coverArea || !area) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// eslint-disable-next-line no-restricted-syntax -- Performance: mutable state for RAF loop
|
|
116
|
+
let prevHeight = Number.NaN;
|
|
117
|
+
// eslint-disable-next-line no-restricted-syntax -- Performance: mutable state for RAF loop
|
|
118
|
+
let prevLeft = Number.NaN;
|
|
119
|
+
// eslint-disable-next-line no-restricted-syntax -- Performance: mutable state for RAF loop
|
|
120
|
+
let prevWidth = Number.NaN;
|
|
121
|
+
// eslint-disable-next-line no-restricted-syntax -- Performance: mutable state for RAF loop
|
|
122
|
+
let prevIsStuck = false;
|
|
123
|
+
// eslint-disable-next-line no-restricted-syntax -- Performance: mutable state for RAF loop
|
|
124
|
+
let isFirstRun = true;
|
|
125
|
+
|
|
126
|
+
const loop = () => {
|
|
127
|
+
const liveRect = area.getBoundingClientRect();
|
|
128
|
+
const viewportHeight = window.innerHeight;
|
|
129
|
+
|
|
130
|
+
if (position === "top") {
|
|
131
|
+
// TOP: Cover expands upward during pull-down overscroll
|
|
132
|
+
// liveRect.top > 0 means element moved down (overscroll)
|
|
133
|
+
// liveRect.top < 0 means element scrolled up
|
|
134
|
+
const coverAreaHeight = Math.max(0, liveRect.height + liveRect.top);
|
|
135
|
+
|
|
136
|
+
if (coverAreaHeight !== prevHeight) {
|
|
137
|
+
coverArea.style.opacity = coverAreaHeight > 0 ? "1" : "0";
|
|
138
|
+
coverArea.style.height = `${coverAreaHeight}px`;
|
|
139
|
+
prevHeight = coverAreaHeight;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (liveRect.left !== prevLeft || liveRect.width !== prevWidth) {
|
|
143
|
+
coverArea.style.left = `${liveRect.left}px`;
|
|
144
|
+
coverArea.style.width = `${liveRect.width}px`;
|
|
145
|
+
prevLeft = liveRect.left;
|
|
146
|
+
prevWidth = liveRect.width;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const isStuck = liveRect.top < 0;
|
|
150
|
+
const scrollOffset = Math.max(0, -liveRect.top);
|
|
151
|
+
|
|
152
|
+
const shouldUpdateState = isFirstRun ? true : isStuck !== prevIsStuck;
|
|
153
|
+
if (shouldUpdateState) {
|
|
154
|
+
isFirstRun = false;
|
|
155
|
+
prevIsStuck = isStuck;
|
|
156
|
+
updateState({ isStuck, scrollOffset });
|
|
157
|
+
}
|
|
158
|
+
} else {
|
|
159
|
+
// BOTTOM: Cover expands downward during pull-up overscroll
|
|
160
|
+
// liveRect.bottom < viewportHeight means element moved up (overscroll at bottom)
|
|
161
|
+
// liveRect.bottom > viewportHeight means element is below viewport
|
|
162
|
+
const distanceFromBottom = viewportHeight - liveRect.bottom;
|
|
163
|
+
const coverAreaHeight = Math.max(0, liveRect.height + distanceFromBottom);
|
|
164
|
+
|
|
165
|
+
if (coverAreaHeight !== prevHeight) {
|
|
166
|
+
coverArea.style.opacity = coverAreaHeight > 0 ? "1" : "0";
|
|
167
|
+
coverArea.style.height = `${coverAreaHeight}px`;
|
|
168
|
+
prevHeight = coverAreaHeight;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (liveRect.left !== prevLeft || liveRect.width !== prevWidth) {
|
|
172
|
+
coverArea.style.left = `${liveRect.left}px`;
|
|
173
|
+
coverArea.style.width = `${liveRect.width}px`;
|
|
174
|
+
prevLeft = liveRect.left;
|
|
175
|
+
prevWidth = liveRect.width;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const isStuck = liveRect.bottom > viewportHeight;
|
|
179
|
+
const scrollOffset = Math.max(0, liveRect.bottom - viewportHeight);
|
|
180
|
+
|
|
181
|
+
const shouldUpdateState = isFirstRun ? true : isStuck !== prevIsStuck;
|
|
182
|
+
if (shouldUpdateState) {
|
|
183
|
+
isFirstRun = false;
|
|
184
|
+
prevIsStuck = isStuck;
|
|
185
|
+
updateState({ isStuck, scrollOffset });
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// eslint-disable-next-line no-restricted-syntax -- Performance: RAF id needs reassignment
|
|
191
|
+
let id = requestAnimationFrame(function animate() {
|
|
192
|
+
loop();
|
|
193
|
+
id = requestAnimationFrame(animate);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
return () => {
|
|
197
|
+
cancelAnimationFrame(id);
|
|
198
|
+
};
|
|
199
|
+
}, [position, updateState]);
|
|
200
|
+
|
|
201
|
+
// Render children
|
|
202
|
+
const renderedChildren = typeof children === "function" ? children(state) : children;
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<div style={wrapperStyle}>
|
|
206
|
+
<div ref={coverAreaRef} style={getCoverStyle(position)}>
|
|
207
|
+
{cover}
|
|
208
|
+
</div>
|
|
209
|
+
<div ref={areaRef} style={getAreaStyle(position)}>
|
|
210
|
+
<div style={bodyStyle}>{renderedChildren}</div>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
StickyArea.displayName = "StickyArea";
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @deprecated Use StickyArea with position="top" instead
|
|
220
|
+
*/
|
|
221
|
+
export const StickyHeader = StickyArea;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file StickyArea entry point - Native app-like overscroll experience
|
|
3
|
+
*
|
|
4
|
+
* Import via: import { StickyArea } from "react-panel-layout/sticky-header";
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Components
|
|
8
|
+
export { StickyArea, StickyHeader } from "./StickyArea";
|
|
9
|
+
|
|
10
|
+
// Types
|
|
11
|
+
export type {
|
|
12
|
+
StickyAreaPosition,
|
|
13
|
+
StickyAreaProps,
|
|
14
|
+
StickyAreaState,
|
|
15
|
+
// Backwards compatibility
|
|
16
|
+
StickyHeaderProps,
|
|
17
|
+
StickyHeaderState,
|
|
18
|
+
} from "./types";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Type definitions for the StickyArea component.
|
|
3
|
+
*
|
|
4
|
+
* StickyArea provides a native app-like experience for SPAs/PWAs
|
|
5
|
+
* by displaying cover content during overscroll/bounce.
|
|
6
|
+
* Supports both top (header) and bottom (footer) positions.
|
|
7
|
+
* Works with document-level scroll only.
|
|
8
|
+
*/
|
|
9
|
+
import type * as React from "react";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Position of the sticky area.
|
|
13
|
+
* - "top": Header behavior - sticks to top, expands on pull-down overscroll
|
|
14
|
+
* - "bottom": Footer behavior - sticks to bottom, expands on pull-up overscroll
|
|
15
|
+
*/
|
|
16
|
+
export type StickyAreaPosition = "top" | "bottom";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* State information exposed by StickyArea.
|
|
20
|
+
*/
|
|
21
|
+
export type StickyAreaState = {
|
|
22
|
+
/**
|
|
23
|
+
* Whether the area is stuck at its edge of the viewport.
|
|
24
|
+
* - For "top": True when scrolled past the top edge
|
|
25
|
+
* - For "bottom": True when scrolled past the bottom edge
|
|
26
|
+
*/
|
|
27
|
+
isStuck: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* The current scroll offset relative to the area.
|
|
30
|
+
* Positive when the area has scrolled past its edge.
|
|
31
|
+
*/
|
|
32
|
+
scrollOffset: number;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Props for the StickyArea component.
|
|
37
|
+
*/
|
|
38
|
+
export type StickyAreaProps = {
|
|
39
|
+
/**
|
|
40
|
+
* Position of the sticky area.
|
|
41
|
+
* - "top": Header behavior (default)
|
|
42
|
+
* - "bottom": Footer behavior
|
|
43
|
+
*
|
|
44
|
+
* @default "top"
|
|
45
|
+
*/
|
|
46
|
+
position?: StickyAreaPosition;
|
|
47
|
+
/**
|
|
48
|
+
* Cover content displayed behind the area.
|
|
49
|
+
* This content expands during overscroll/bounce to create
|
|
50
|
+
* a native app-like pull effect.
|
|
51
|
+
*/
|
|
52
|
+
cover: React.ReactNode;
|
|
53
|
+
/**
|
|
54
|
+
* Main content that scrolls over the cover.
|
|
55
|
+
* Can be a ReactNode or a render function receiving state.
|
|
56
|
+
*/
|
|
57
|
+
children: React.ReactNode | ((state: StickyAreaState) => React.ReactNode);
|
|
58
|
+
/**
|
|
59
|
+
* Callback fired when sticky state changes.
|
|
60
|
+
*/
|
|
61
|
+
onStateChange?: (state: StickyAreaState) => void;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// Backwards compatibility aliases
|
|
65
|
+
/** @deprecated Use StickyAreaState instead */
|
|
66
|
+
export type StickyHeaderState = StickyAreaState;
|
|
67
|
+
/** @deprecated Use StickyAreaProps instead */
|
|
68
|
+
export type StickyHeaderProps = StickyAreaProps;
|