react-panel-layout 0.5.2 → 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.
Files changed (463) hide show
  1. package/dist/{FloatingPanelFrame-D9Cp2al1.cjs → FloatingPanelFrame-CEmXDvUA.cjs} +2 -2
  2. package/dist/{FloatingPanelFrame-D9Cp2al1.cjs.map → FloatingPanelFrame-CEmXDvUA.cjs.map} +1 -1
  3. package/dist/{FloatingPanelFrame-lLg-Lpg7.js → FloatingPanelFrame-SgYLc6Ud.js} +11 -11
  4. package/dist/{FloatingPanelFrame-lLg-Lpg7.js.map → FloatingPanelFrame-SgYLc6Ud.js.map} +1 -1
  5. package/dist/FloatingWindow-BpdOpg_L.js +400 -0
  6. package/dist/FloatingWindow-BpdOpg_L.js.map +1 -0
  7. package/dist/FloatingWindow-TCDNY5gE.cjs +2 -0
  8. package/dist/FloatingWindow-TCDNY5gE.cjs.map +1 -0
  9. package/dist/GridLayout-B4VRsC0r.cjs +2 -0
  10. package/dist/GridLayout-B4VRsC0r.cjs.map +1 -0
  11. package/dist/GridLayout-BltqeCPK.js +927 -0
  12. package/dist/GridLayout-BltqeCPK.js.map +1 -0
  13. package/dist/HorizontalDivider-B5Z-KZLk.cjs +2 -0
  14. package/dist/HorizontalDivider-B5Z-KZLk.cjs.map +1 -0
  15. package/dist/HorizontalDivider-WF1k_qND.js +30 -0
  16. package/dist/HorizontalDivider-WF1k_qND.js.map +1 -0
  17. package/dist/PanelSystem-Bs8bQwQF.cjs +3 -0
  18. package/dist/PanelSystem-Bs8bQwQF.cjs.map +1 -0
  19. package/dist/PanelSystem-Dr1TBhxM.js +1946 -0
  20. package/dist/PanelSystem-Dr1TBhxM.js.map +1 -0
  21. package/dist/ResizeHandle-CScipO5l.cjs +2 -0
  22. package/dist/ResizeHandle-CScipO5l.cjs.map +1 -0
  23. package/dist/ResizeHandle-CdA_JYfN.js +120 -0
  24. package/dist/ResizeHandle-CdA_JYfN.js.map +1 -0
  25. package/dist/SwipePivotTabBar-BGO9X94m.js +407 -0
  26. package/dist/SwipePivotTabBar-BGO9X94m.js.map +1 -0
  27. package/dist/SwipePivotTabBar-BrQismcZ.cjs +2 -0
  28. package/dist/SwipePivotTabBar-BrQismcZ.cjs.map +1 -0
  29. package/dist/config.cjs +1 -1
  30. package/dist/config.cjs.map +1 -1
  31. package/dist/config.js +11 -9
  32. package/dist/config.js.map +1 -1
  33. package/dist/constants/styles.d.ts +18 -4
  34. package/dist/floating.cjs +1 -1
  35. package/dist/floating.js +1 -1
  36. package/dist/grid/index.d.ts +58 -0
  37. package/dist/grid.cjs +2 -0
  38. package/dist/grid.cjs.map +1 -0
  39. package/dist/grid.js +13 -0
  40. package/dist/grid.js.map +1 -0
  41. package/dist/hooks/gesture/presets.d.ts +33 -0
  42. package/dist/hooks/gesture/testing/createGestureSimulator.d.ts +110 -0
  43. package/dist/hooks/gesture/thresholdValue.d.ts +44 -0
  44. package/dist/hooks/gesture/types.d.ts +254 -0
  45. package/dist/hooks/gesture/useDirectionalLock.d.ts +20 -0
  46. package/dist/hooks/gesture/useEdgeSwipeInput.d.ts +23 -0
  47. package/dist/hooks/gesture/useNativeGestureGuard.d.ts +23 -0
  48. package/dist/hooks/gesture/usePointerTracking.d.ts +22 -0
  49. package/dist/hooks/gesture/useScrollBoundary.d.ts +23 -0
  50. package/dist/hooks/gesture/useSwipeInput.d.ts +5 -0
  51. package/dist/hooks/gesture/utils.d.ts +40 -0
  52. package/dist/hooks/useAnimatedVisibility.d.ts +58 -0
  53. package/dist/hooks/useAnimationFrame.d.ts +84 -0
  54. package/dist/hooks/useSnapAnimation.d.ts +54 -0
  55. package/dist/hooks/useSwipeContentTransform.d.ts +79 -0
  56. package/dist/index.cjs +1 -2
  57. package/dist/index.cjs.map +1 -1
  58. package/dist/index.d.ts +0 -1
  59. package/dist/index.js +25 -2006
  60. package/dist/index.js.map +1 -1
  61. package/dist/modules/pivot/PivotContent.d.ts +1 -1
  62. package/dist/modules/pivot/SwipePivotContent.d.ts +39 -0
  63. package/dist/modules/pivot/SwipePivotContent.debug.tmp.d.ts +25 -0
  64. package/dist/modules/pivot/SwipePivotContent.test.d.ts +1 -0
  65. package/dist/modules/pivot/SwipePivotTabBar.d.ts +89 -0
  66. package/dist/modules/pivot/index.d.ts +3 -0
  67. package/dist/modules/pivot/scaleInputState.d.ts +37 -0
  68. package/dist/modules/pivot/types.d.ts +67 -2
  69. package/dist/modules/pivot/usePivotSwipeInput.d.ts +68 -0
  70. package/dist/modules/stack/StackContent.d.ts +15 -0
  71. package/dist/modules/stack/SwipeStackContent.d.ts +63 -0
  72. package/dist/modules/stack/SwipeStackOutlet.d.ts +80 -0
  73. package/dist/modules/stack/computeStackContentState.d.ts +99 -0
  74. package/dist/modules/stack/computeSwipeStackTransform.d.ts +76 -0
  75. package/dist/modules/stack/types.d.ts +194 -0
  76. package/dist/modules/stack/useStackAnimationState.d.ts +32 -0
  77. package/dist/modules/stack/useStackNavigation.d.ts +23 -0
  78. package/dist/modules/stack/useStackSwipeInput.d.ts +27 -0
  79. package/dist/panels/index.d.ts +67 -0
  80. package/dist/panels.cjs +2 -0
  81. package/dist/panels.cjs.map +1 -0
  82. package/dist/panels.js +28 -0
  83. package/dist/panels.js.map +1 -0
  84. package/dist/pivot/index.d.ts +3 -0
  85. package/dist/pivot.cjs +1 -1
  86. package/dist/pivot.cjs.map +1 -1
  87. package/dist/pivot.js +20 -2
  88. package/dist/pivot.js.map +1 -1
  89. package/dist/resizer/index.d.ts +57 -0
  90. package/dist/resizer.cjs +2 -0
  91. package/dist/resizer.cjs.map +1 -0
  92. package/dist/resizer.js +8 -0
  93. package/dist/resizer.js.map +1 -0
  94. package/dist/stack/index.d.ts +72 -0
  95. package/dist/stack.cjs +2 -0
  96. package/dist/stack.cjs.map +1 -0
  97. package/dist/stack.js +980 -0
  98. package/dist/stack.js.map +1 -0
  99. package/dist/sticky-header/StickyArea.d.ts +38 -0
  100. package/dist/sticky-header/index.d.ts +4 -4
  101. package/dist/sticky-header/types.d.ts +35 -22
  102. package/dist/sticky-header.cjs +1 -1
  103. package/dist/sticky-header.cjs.map +1 -1
  104. package/dist/sticky-header.js +65 -174
  105. package/dist/sticky-header.js.map +1 -1
  106. package/dist/styles-DPPuJ0sf.js +57 -0
  107. package/dist/styles-DPPuJ0sf.js.map +1 -0
  108. package/dist/styles-qf6ptVLD.cjs +2 -0
  109. package/dist/styles-qf6ptVLD.cjs.map +1 -0
  110. package/dist/useContentCache-CO3LYNmz.js +24 -0
  111. package/dist/useContentCache-CO3LYNmz.js.map +1 -0
  112. package/dist/useContentCache-DqXtLrLs.cjs +2 -0
  113. package/dist/useContentCache-DqXtLrLs.cjs.map +1 -0
  114. package/dist/useDocumentPointerEvents-CKdhGXd0.js +46 -0
  115. package/dist/useDocumentPointerEvents-CKdhGXd0.js.map +1 -0
  116. package/dist/useDocumentPointerEvents-ChqrKXDk.cjs +2 -0
  117. package/dist/useDocumentPointerEvents-ChqrKXDk.cjs.map +1 -0
  118. package/dist/useEffectEvent-Dp7HLCf0.js +13 -0
  119. package/dist/useEffectEvent-Dp7HLCf0.js.map +1 -0
  120. package/dist/useEffectEvent-huSsGUnl.cjs +2 -0
  121. package/dist/useEffectEvent-huSsGUnl.cjs.map +1 -0
  122. package/dist/useFloatingState-C4kRaW_R.cjs +2 -0
  123. package/dist/useFloatingState-C4kRaW_R.cjs.map +1 -0
  124. package/dist/useFloatingState-tEfA_wbc.js +74 -0
  125. package/dist/useFloatingState-tEfA_wbc.js.map +1 -0
  126. package/dist/window/index.d.ts +61 -0
  127. package/dist/window.cjs +2 -0
  128. package/dist/window.cjs.map +1 -0
  129. package/dist/window.js +149 -0
  130. package/dist/window.js.map +1 -0
  131. package/docs/design-tokens.md +405 -0
  132. package/package.json +29 -4
  133. package/src/PanelSystemContext.tsx +88 -0
  134. package/src/components/grid/GridLayerList.tsx +172 -0
  135. package/src/components/grid/GridLayerResizeHandles.tsx +145 -0
  136. package/src/components/grid/GridLayout.spec.tsx +743 -0
  137. package/src/components/grid/GridLayout.tsx +130 -0
  138. package/src/components/grid/GridTrackResizeHandle.tsx +87 -0
  139. package/src/components/paneling/FloatingPanelFrame.tsx +203 -0
  140. package/src/components/panels/DropSuggestOverlay.tsx +131 -0
  141. package/src/components/panels/PanelGroupView.tsx +112 -0
  142. package/src/components/pivot/PivotLayer.tsx +27 -0
  143. package/src/components/resizer/HorizontalDivider.tsx +52 -0
  144. package/src/components/resizer/ResizeHandle.tsx +118 -0
  145. package/src/components/tabs/TabBar.tsx +223 -0
  146. package/src/components/tabs/TabBarTab.tsx +133 -0
  147. package/src/components/tabs/TabDragOverlay.tsx +92 -0
  148. package/src/components/window/DialogOverlay.tsx +180 -0
  149. package/src/components/window/Drawer.tsx +282 -0
  150. package/src/components/window/DrawerLayers.tsx +58 -0
  151. package/src/components/window/FloatingWindow.tsx +95 -0
  152. package/src/components/window/PopupLayerPortal.tsx +218 -0
  153. package/src/config/PanelContentDeclaration.tsx +427 -0
  154. package/src/config/index.tsx +52 -0
  155. package/src/config/panelJsx.spec.tsx +54 -0
  156. package/src/config/panelJsxConfig.spec.tsx +54 -0
  157. package/src/config/panelJsxDrawer.spec.tsx +33 -0
  158. package/src/config/panelRouter.spec.ts +68 -0
  159. package/src/config/panelRouter.tsx +155 -0
  160. package/src/constants/styles.ts +261 -0
  161. package/src/demo/Layout.module.css +258 -0
  162. package/src/demo/Layout.tsx +176 -0
  163. package/src/demo/components/CodeBlock.module.css +54 -0
  164. package/src/demo/components/CodeBlock.tsx +34 -0
  165. package/src/demo/components/CodePreview.module.css +37 -0
  166. package/src/demo/components/CodePreview.tsx +31 -0
  167. package/src/demo/components/DataPreview.module.css +177 -0
  168. package/src/demo/components/DataPreview.tsx +115 -0
  169. package/src/demo/components/Story.module.css +68 -0
  170. package/src/demo/components/Story.tsx +54 -0
  171. package/src/demo/components/layout/CodePanel.module.css +183 -0
  172. package/src/demo/components/layout/CodePanel.tsx +149 -0
  173. package/src/demo/components/layout/DemoPage.module.css +60 -0
  174. package/src/demo/components/layout/DemoPage.tsx +56 -0
  175. package/src/demo/components/layout/SingleSamplePage.module.css +11 -0
  176. package/src/demo/components/layout/SingleSamplePage.tsx +35 -0
  177. package/src/demo/components/layout/SplitDemoLayout.module.css +107 -0
  178. package/src/demo/components/layout/SplitDemoLayout.tsx +218 -0
  179. package/src/demo/components/layout/index.ts +11 -0
  180. package/src/demo/components/tab-styles/ChromeTabBar.module.css +75 -0
  181. package/src/demo/components/tab-styles/ChromeTabBar.tsx +111 -0
  182. package/src/demo/components/tab-styles/GitHubTabBar.module.css +81 -0
  183. package/src/demo/components/tab-styles/GitHubTabBar.tsx +109 -0
  184. package/src/demo/components/tab-styles/VSCodeTabBar.module.css +78 -0
  185. package/src/demo/components/tab-styles/VSCodeTabBar.tsx +109 -0
  186. package/src/demo/components/tab-styles/index.ts +6 -0
  187. package/src/demo/components/ui/DemoButton.module.css +63 -0
  188. package/src/demo/components/ui/DemoButton.tsx +32 -0
  189. package/src/demo/components/ui/DemoCard.module.css +15 -0
  190. package/src/demo/components/ui/DemoCard.tsx +30 -0
  191. package/src/demo/components/ui/DemoContainer.module.css +17 -0
  192. package/src/demo/components/ui/DemoContainer.tsx +30 -0
  193. package/src/demo/components/ui/DemoPanel.module.css +23 -0
  194. package/src/demo/components/ui/DemoPanel.tsx +33 -0
  195. package/src/demo/components/ui/PanelText.module.css +18 -0
  196. package/src/demo/components/ui/PanelText.tsx +29 -0
  197. package/src/demo/components/ui/PanelTitle.module.css +18 -0
  198. package/src/demo/components/ui/PanelTitle.tsx +31 -0
  199. package/src/demo/contexts/TabbarDemoConfig.tsx +218 -0
  200. package/src/demo/demo.css +172 -0
  201. package/src/demo/hooks/useMedia.ts +41 -0
  202. package/src/demo/hooks/useShikiHighlight.ts +55 -0
  203. package/src/demo/index.tsx +293 -0
  204. package/src/demo/pages/Drawer/animations/index.tsx +22 -0
  205. package/src/demo/pages/Drawer/basics/index.tsx +17 -0
  206. package/src/demo/pages/Drawer/components/DrawerAnimations.module.css +125 -0
  207. package/src/demo/pages/Drawer/components/DrawerAnimations.tsx +118 -0
  208. package/src/demo/pages/Drawer/components/DrawerBasics.module.css +55 -0
  209. package/src/demo/pages/Drawer/components/DrawerBasics.tsx +76 -0
  210. package/src/demo/pages/Drawer/components/DrawerMenuLayout.module.css +332 -0
  211. package/src/demo/pages/Drawer/components/DrawerMenuLayout.tsx +199 -0
  212. package/src/demo/pages/Drawer/menu/index.tsx +17 -0
  213. package/src/demo/pages/FloatingPanelFrame/ResizableFloatingPanelsPreview.module.css +163 -0
  214. package/src/demo/pages/FloatingPanelFrame/ResizableFloatingPanelsPreview.tsx +234 -0
  215. package/src/demo/pages/FloatingPanelFrame/basic/index.tsx +17 -0
  216. package/src/demo/pages/FloatingPanelFrame/complex/index.tsx +26 -0
  217. package/src/demo/pages/FloatingPanelFrame/components/BasicPanel.module.css +16 -0
  218. package/src/demo/pages/FloatingPanelFrame/components/BasicPanel.tsx +24 -0
  219. package/src/demo/pages/FloatingPanelFrame/components/ComplexPanel.module.css +54 -0
  220. package/src/demo/pages/FloatingPanelFrame/components/ComplexPanel.tsx +67 -0
  221. package/src/demo/pages/FloatingPanelFrame/components/PanelWithControls.module.css +21 -0
  222. package/src/demo/pages/FloatingPanelFrame/components/PanelWithControls.tsx +41 -0
  223. package/src/demo/pages/FloatingPanelFrame/components/PanelWithMeta.module.css +5 -0
  224. package/src/demo/pages/FloatingPanelFrame/components/PanelWithMeta.tsx +43 -0
  225. package/src/demo/pages/FloatingPanelFrame/components/ScrollablePanel.module.css +11 -0
  226. package/src/demo/pages/FloatingPanelFrame/components/ScrollablePanel.tsx +42 -0
  227. package/src/demo/pages/FloatingPanelFrame/index.tsx +80 -0
  228. package/src/demo/pages/FloatingPanelFrame/scrollable/index.tsx +30 -0
  229. package/src/demo/pages/FloatingPanelFrame/with-controls/index.tsx +30 -0
  230. package/src/demo/pages/FloatingPanelFrame/with-meta/index.tsx +17 -0
  231. package/src/demo/pages/HorizontalDivider/components/PanelsWithRichContent.module.css +112 -0
  232. package/src/demo/pages/HorizontalDivider/components/PanelsWithRichContent.tsx +56 -0
  233. package/src/demo/pages/HorizontalDivider/components/SimpleResizablePanels.module.css +46 -0
  234. package/src/demo/pages/HorizontalDivider/components/SimpleResizablePanels.tsx +29 -0
  235. package/src/demo/pages/HorizontalDivider/components/ThreePanelLayout.module.css +54 -0
  236. package/src/demo/pages/HorizontalDivider/components/ThreePanelLayout.tsx +30 -0
  237. package/src/demo/pages/HorizontalDivider/index.module.css +14 -0
  238. package/src/demo/pages/HorizontalDivider/index.tsx +64 -0
  239. package/src/demo/pages/HorizontalDivider/panels-with-rich-content/index.tsx +21 -0
  240. package/src/demo/pages/HorizontalDivider/simple-resizable-panels/index.tsx +21 -0
  241. package/src/demo/pages/HorizontalDivider/three-panel-layout/index.tsx +21 -0
  242. package/src/demo/pages/PanelLayout/PanelLayoutDemo.module.css +174 -0
  243. package/src/demo/pages/PanelLayout/PanelLayoutDemo.tsx +248 -0
  244. package/src/demo/pages/PanelLayout/components/DashboardLayout.module.css +115 -0
  245. package/src/demo/pages/PanelLayout/components/DashboardLayout.tsx +124 -0
  246. package/src/demo/pages/PanelLayout/components/DraggableOverlays.module.css +101 -0
  247. package/src/demo/pages/PanelLayout/components/DraggableOverlays.tsx +122 -0
  248. package/src/demo/pages/PanelLayout/components/IDELayout.module.css +104 -0
  249. package/src/demo/pages/PanelLayout/components/IDELayout.tsx +143 -0
  250. package/src/demo/pages/PanelLayout/components/SimpleGrid.module.css +19 -0
  251. package/src/demo/pages/PanelLayout/components/SimpleGrid.tsx +62 -0
  252. package/src/demo/pages/PanelLayout/dashboard/index.tsx +22 -0
  253. package/src/demo/pages/PanelLayout/draggable-overlays/index.tsx +22 -0
  254. package/src/demo/pages/PanelLayout/ide-layout/index.tsx +22 -0
  255. package/src/demo/pages/PanelLayout/index.tsx +94 -0
  256. package/src/demo/pages/PanelLayout/simple-grid/index.tsx +22 -0
  257. package/src/demo/pages/PanelSystem/PanelSystemPreview.module.css +20 -0
  258. package/src/demo/pages/PanelSystem/PanelSystemPreview.tsx +101 -0
  259. package/src/demo/pages/PanelSystem/preview/index.tsx +18 -0
  260. package/src/demo/pages/PanelSystem/tabbar/index.tsx +129 -0
  261. package/src/demo/pages/Pivot/basics/index.tsx +17 -0
  262. package/src/demo/pages/Pivot/components/Pivot.module.css +278 -0
  263. package/src/demo/pages/Pivot/components/PivotBasics.tsx +103 -0
  264. package/src/demo/pages/Pivot/components/PivotSidebar.tsx +168 -0
  265. package/src/demo/pages/Pivot/components/PivotTabs.tsx +129 -0
  266. package/src/demo/pages/Pivot/components/PivotTransitions.tsx +120 -0
  267. package/src/demo/pages/Pivot/components/SwipePivot.module.css +114 -0
  268. package/src/demo/pages/Pivot/components/SwipePivot.tsx +193 -0
  269. package/src/demo/pages/Pivot/components/SwipeTabsPivot.module.css +203 -0
  270. package/src/demo/pages/Pivot/components/SwipeTabsPivot.tsx +289 -0
  271. package/src/demo/pages/Pivot/sidebar/index.tsx +17 -0
  272. package/src/demo/pages/Pivot/swipe/index.tsx +16 -0
  273. package/src/demo/pages/Pivot/swipe-debug/index.tsx +287 -0
  274. package/src/demo/pages/Pivot/swipe-tabs/index.tsx +15 -0
  275. package/src/demo/pages/Pivot/tabs/index.tsx +17 -0
  276. package/src/demo/pages/Pivot/transitions/index.tsx +17 -0
  277. package/src/demo/pages/ResizeHandle/both-directions/index.tsx +17 -0
  278. package/src/demo/pages/ResizeHandle/components/BothDirectionsDemo.module.css +72 -0
  279. package/src/demo/pages/ResizeHandle/components/BothDirectionsDemo.tsx +41 -0
  280. package/src/demo/pages/ResizeHandle/components/HorizontalResizeDemo.module.css +61 -0
  281. package/src/demo/pages/ResizeHandle/components/HorizontalResizeDemo.tsx +33 -0
  282. package/src/demo/pages/ResizeHandle/components/NestedPanelsDemo.module.css +83 -0
  283. package/src/demo/pages/ResizeHandle/components/NestedPanelsDemo.tsx +53 -0
  284. package/src/demo/pages/ResizeHandle/components/VerticalResizeDemo.module.css +68 -0
  285. package/src/demo/pages/ResizeHandle/components/VerticalResizeDemo.tsx +33 -0
  286. package/src/demo/pages/ResizeHandle/horizontal/index.tsx +17 -0
  287. package/src/demo/pages/ResizeHandle/index.module.css +11 -0
  288. package/src/demo/pages/ResizeHandle/index.tsx +71 -0
  289. package/src/demo/pages/ResizeHandle/nested-panels/index.tsx +17 -0
  290. package/src/demo/pages/ResizeHandle/vertical/index.tsx +17 -0
  291. package/src/demo/pages/ResponsiveLayout/adaptive-workspace/index.tsx +22 -0
  292. package/src/demo/pages/ResponsiveLayout/components/ResponsiveWorkspace.module.css +423 -0
  293. package/src/demo/pages/ResponsiveLayout/components/ResponsiveWorkspace.tsx +398 -0
  294. package/src/demo/pages/Stack/basics/index.tsx +22 -0
  295. package/src/demo/pages/Stack/components/Stack.module.css +234 -0
  296. package/src/demo/pages/Stack/components/StackBasics.tsx +217 -0
  297. package/src/demo/pages/Stack/components/StackTablet.module.css +299 -0
  298. package/src/demo/pages/Stack/components/StackTablet.tsx +401 -0
  299. package/src/demo/pages/Stack/tablet/index.tsx +22 -0
  300. package/src/demo/pages/StickyHeader/basics/index.tsx +17 -0
  301. package/src/demo/pages/StickyHeader/components/StickyHeader.module.css +219 -0
  302. package/src/demo/pages/StickyHeader/components/StickyHeaderBasics.tsx +103 -0
  303. package/src/demo/routes.tsx +193 -0
  304. package/src/demo/styles/animations.css +68 -0
  305. package/src/demo/styles/stack-themes.css +35 -0
  306. package/src/demo/utils/createPanelView.tsx +58 -0
  307. package/src/floating/index.ts +24 -0
  308. package/src/grid/index.ts +75 -0
  309. package/src/hooks/ContentCacheContext.tsx +87 -0
  310. package/src/hooks/gesture/presets.spec.ts +86 -0
  311. package/src/hooks/gesture/presets.ts +95 -0
  312. package/src/hooks/gesture/testing/createGestureSimulator.spec.ts +237 -0
  313. package/src/hooks/gesture/testing/createGestureSimulator.ts +310 -0
  314. package/src/hooks/gesture/thresholdValue.spec.ts +103 -0
  315. package/src/hooks/gesture/thresholdValue.ts +77 -0
  316. package/src/hooks/gesture/types.ts +290 -0
  317. package/src/hooks/gesture/useDirectionalLock.spec.ts +271 -0
  318. package/src/hooks/gesture/useDirectionalLock.ts +115 -0
  319. package/src/hooks/gesture/useEdgeSwipeInput.spec.ts +454 -0
  320. package/src/hooks/gesture/useEdgeSwipeInput.ts +131 -0
  321. package/src/hooks/gesture/useNativeGestureGuard.spec.ts +413 -0
  322. package/src/hooks/gesture/useNativeGestureGuard.ts +133 -0
  323. package/src/hooks/gesture/usePointerTracking.spec.ts +364 -0
  324. package/src/hooks/gesture/usePointerTracking.ts +134 -0
  325. package/src/hooks/gesture/useScrollBoundary.spec.ts +249 -0
  326. package/src/hooks/gesture/useScrollBoundary.ts +113 -0
  327. package/src/hooks/gesture/useSwipeInput.spec.ts +592 -0
  328. package/src/hooks/gesture/useSwipeInput.ts +310 -0
  329. package/src/hooks/gesture/utils.spec.ts +152 -0
  330. package/src/hooks/gesture/utils.ts +87 -0
  331. package/src/hooks/useAnimatedVisibility.spec.ts +257 -0
  332. package/src/hooks/useAnimatedVisibility.ts +146 -0
  333. package/src/hooks/useAnimationFrame.ts +200 -0
  334. package/src/hooks/useCSSMatrix.spec.ts +214 -0
  335. package/src/hooks/useCSSMatrix.ts +262 -0
  336. package/src/hooks/useClonedElementPreview.ts +28 -0
  337. package/src/hooks/useContainerScroll.ts +78 -0
  338. package/src/hooks/useContentCache.spec.tsx +232 -0
  339. package/src/hooks/useContentCache.tsx +127 -0
  340. package/src/hooks/useDocumentPointerEvents.ts +137 -0
  341. package/src/hooks/useDocumentScroll.ts +41 -0
  342. package/src/hooks/useEffectEvent.ts +40 -0
  343. package/src/hooks/useElementComponentWrapper.tsx +63 -0
  344. package/src/hooks/useIntersectionObserver.tsx +125 -0
  345. package/src/hooks/useIsomorphicLayoutEffect.ts +29 -0
  346. package/src/hooks/useResizeObserver.tsx +81 -0
  347. package/src/hooks/useScrollContainer.ts +79 -0
  348. package/src/hooks/useSnapAnimation.ts +128 -0
  349. package/src/hooks/useSwipeContentTransform.spec.ts +133 -0
  350. package/src/hooks/useSwipeContentTransform.ts +235 -0
  351. package/src/hooks/useTransitionState.ts +95 -0
  352. package/src/index.tsx +88 -0
  353. package/src/modules/grid/GridLayoutContext.tsx +57 -0
  354. package/src/modules/grid/LayerInstanceContext.tsx +56 -0
  355. package/src/modules/grid/resizeHandles.ts +157 -0
  356. package/src/modules/grid/trackUtils.ts +146 -0
  357. package/src/modules/grid/useGridPlacements.ts +143 -0
  358. package/src/modules/grid/useGridTracks.ts +156 -0
  359. package/src/modules/grid/useLayerDragHandle.ts +16 -0
  360. package/src/modules/grid/useLayerInteractions.tsx +850 -0
  361. package/src/modules/keybindings/KeybindingsProvider.tsx +111 -0
  362. package/src/modules/panels/dom/DomRegistry.tsx +94 -0
  363. package/src/modules/panels/index.ts +45 -0
  364. package/src/modules/panels/interactions/InteractionsContext.test.tsx +330 -0
  365. package/src/modules/panels/interactions/InteractionsContext.tsx +394 -0
  366. package/src/modules/panels/interactions/dnd.ts +28 -0
  367. package/src/modules/panels/keybindings/KeybindingsInstaller.tsx +15 -0
  368. package/src/modules/panels/layout/adapter.ts +124 -0
  369. package/src/modules/panels/rendering/ContentRegistry.spec.tsx +304 -0
  370. package/src/modules/panels/rendering/ContentRegistry.tsx +205 -0
  371. package/src/modules/panels/rendering/GroupContainer.tsx +65 -0
  372. package/src/modules/panels/rendering/RenderBridge.tsx +115 -0
  373. package/src/modules/panels/rendering/RenderContext.tsx +31 -0
  374. package/src/modules/panels/state/PanelSplitHandles.tsx +147 -0
  375. package/src/modules/panels/state/PanelSystemContext.splitLimits.spec.tsx +50 -0
  376. package/src/modules/panels/state/PanelSystemContext.tsx +289 -0
  377. package/src/modules/panels/state/StateContext.tsx +12 -0
  378. package/src/modules/panels/state/cleanup.ts +37 -0
  379. package/src/modules/panels/state/commands.ts +53 -0
  380. package/src/modules/panels/state/focus/Context.tsx +25 -0
  381. package/src/modules/panels/state/focus/logic.ts +57 -0
  382. package/src/modules/panels/state/groups/Context.tsx +25 -0
  383. package/src/modules/panels/state/groups/logic.ts +105 -0
  384. package/src/modules/panels/state/splitLimits.spec.ts +46 -0
  385. package/src/modules/panels/state/splitLimits.ts +90 -0
  386. package/src/modules/panels/state/state.spec.ts +49 -0
  387. package/src/modules/panels/state/tree/Context.tsx +24 -0
  388. package/src/modules/panels/state/tree/logic.spec.ts +34 -0
  389. package/src/modules/panels/state/tree/logic.ts +138 -0
  390. package/src/modules/panels/state/types.ts +142 -0
  391. package/src/modules/panels/system/PanelSystem.empty-tabbar.spec.tsx +53 -0
  392. package/src/modules/panels/system/PanelSystem.tab-click-activates.spec.tsx +44 -0
  393. package/src/modules/panels/system/PanelSystem.tab-reorder.spec.tsx +64 -0
  394. package/src/modules/panels/system/PanelSystem.tabs-no-dup.spec.tsx +57 -0
  395. package/src/modules/panels/system/PanelSystem.tsx +206 -0
  396. package/src/modules/pivot/PivotContent.spec.tsx +179 -0
  397. package/src/modules/pivot/PivotContent.tsx +77 -0
  398. package/src/modules/pivot/SwipePivotContent.debug.tmp.tsx +237 -0
  399. package/src/modules/pivot/SwipePivotContent.position.spec.tsx +167 -0
  400. package/src/modules/pivot/SwipePivotContent.spec.tsx +464 -0
  401. package/src/modules/pivot/SwipePivotContent.test.tsx +502 -0
  402. package/src/modules/pivot/SwipePivotContent.tsx +197 -0
  403. package/src/modules/pivot/SwipePivotTabBar.spec.tsx +865 -0
  404. package/src/modules/pivot/SwipePivotTabBar.tsx +523 -0
  405. package/src/modules/pivot/index.ts +8 -0
  406. package/src/modules/pivot/scaleInputState.spec.ts +210 -0
  407. package/src/modules/pivot/scaleInputState.ts +66 -0
  408. package/src/modules/pivot/types.ts +139 -0
  409. package/src/modules/pivot/usePivot.spec.ts +621 -0
  410. package/src/modules/pivot/usePivot.spec.tsx +186 -0
  411. package/src/modules/pivot/usePivot.tsx +345 -0
  412. package/src/modules/pivot/usePivotSwipeInput.spec.ts +649 -0
  413. package/src/modules/pivot/usePivotSwipeInput.ts +136 -0
  414. package/src/modules/resizer/useResizeDrag.ts +94 -0
  415. package/src/modules/stack/StackContent.spec.tsx +264 -0
  416. package/src/modules/stack/StackContent.tsx +111 -0
  417. package/src/modules/stack/SwipeStackContent.spec.tsx +1277 -0
  418. package/src/modules/stack/SwipeStackContent.tsx +356 -0
  419. package/src/modules/stack/SwipeStackOutlet.spec.tsx +252 -0
  420. package/src/modules/stack/SwipeStackOutlet.tsx +221 -0
  421. package/src/modules/stack/computeStackContentState.spec.ts +281 -0
  422. package/src/modules/stack/computeStackContentState.ts +304 -0
  423. package/src/modules/stack/computeSwipeStackTransform.spec.ts +186 -0
  424. package/src/modules/stack/computeSwipeStackTransform.ts +145 -0
  425. package/src/modules/stack/types.ts +226 -0
  426. package/src/modules/stack/useStackAnimationState.spec.ts +186 -0
  427. package/src/modules/stack/useStackAnimationState.ts +138 -0
  428. package/src/modules/stack/useStackNavigation.spec.ts +477 -0
  429. package/src/modules/stack/useStackNavigation.tsx +336 -0
  430. package/src/modules/stack/useStackSwipeInput.spec.ts +276 -0
  431. package/src/modules/stack/useStackSwipeInput.ts +139 -0
  432. package/src/modules/window/useDrawerState.ts +81 -0
  433. package/src/modules/window/useFloatingState.spec.ts +252 -0
  434. package/src/modules/window/useFloatingState.ts +141 -0
  435. package/src/panels/index.ts +119 -0
  436. package/src/pivot/index.ts +19 -0
  437. package/src/resizer/index.ts +68 -0
  438. package/src/stack/index.ts +91 -0
  439. package/src/sticky-header/StickyArea.tsx +221 -0
  440. package/src/sticky-header/index.ts +18 -0
  441. package/src/sticky-header/types.ts +68 -0
  442. package/src/types.ts +323 -0
  443. package/src/utils/CSSMatrix.ts +321 -0
  444. package/src/utils/css.ts +65 -0
  445. package/src/utils/dialogUtils.ts +43 -0
  446. package/src/utils/math.ts +18 -0
  447. package/src/utils/polyfills/createDialogPolyfill.ts +18 -0
  448. package/src/utils/typedActions.ts +103 -0
  449. package/src/vite-env.d.ts +6 -0
  450. package/src/window/index.ts +67 -0
  451. package/dist/GridLayout-BQQ63eA1.cjs +0 -2
  452. package/dist/GridLayout-BQQ63eA1.cjs.map +0 -1
  453. package/dist/GridLayout-CJTKq7Mp.js +0 -1465
  454. package/dist/GridLayout-CJTKq7Mp.js.map +0 -1
  455. package/dist/sticky-header/StickyHeader.d.ts +0 -53
  456. package/dist/styles-CA2_zLZt.js +0 -52
  457. package/dist/styles-CA2_zLZt.js.map +0 -1
  458. package/dist/styles-PsqGOEJP.cjs +0 -2
  459. package/dist/styles-PsqGOEJP.cjs.map +0 -1
  460. package/dist/usePivot-7ctin_P_.cjs +0 -2
  461. package/dist/usePivot-7ctin_P_.cjs.map +0 -1
  462. package/dist/usePivot-CgQxB8rc.js +0 -124
  463. package/dist/usePivot-CgQxB8rc.js.map +0 -1
@@ -0,0 +1,136 @@
1
+ /**
2
+ * @file Hook for binding swipe input to Pivot navigation.
3
+ *
4
+ * This hook connects swipe gesture detection to Pivot's navigation API,
5
+ * translating swipe gestures into go(-1) and go(1) calls.
6
+ *
7
+ * Supports both:
8
+ * - Touch/pointer swipe gestures
9
+ * - Trackpad two-finger swipe (wheel events)
10
+ */
11
+ import * as React from "react";
12
+ import { useSwipeInput } from "../../hooks/gesture/useSwipeInput.js";
13
+ import { useNativeGestureGuard } from "../../hooks/gesture/useNativeGestureGuard.js";
14
+ import { mergeGestureContainerProps } from "../../hooks/gesture/utils.js";
15
+ import type { SwipeInputState, SwipeInputThresholds, GestureAxis } from "../../hooks/gesture/types.js";
16
+ import type { UsePivotResult } from "./types.js";
17
+
18
+ /**
19
+ * Options for usePivotSwipeInput hook.
20
+ */
21
+ export type UsePivotSwipeInputOptions = {
22
+ /** Reference to the swipe container element */
23
+ containerRef: React.RefObject<HTMLElement | null>;
24
+ /** Pivot navigation result from usePivot */
25
+ pivot: Pick<UsePivotResult, "go" | "canGo">;
26
+ /** Axis for swipe detection. @default "horizontal" */
27
+ axis?: GestureAxis;
28
+ /** Whether swipe input is enabled. @default true */
29
+ enabled?: boolean;
30
+ /** Custom swipe thresholds */
31
+ thresholds?: Partial<SwipeInputThresholds>;
32
+ /** Whether to enable trackpad wheel swipe. @default true */
33
+ enableWheelSwipe?: boolean;
34
+ };
35
+
36
+ /**
37
+ * Result from usePivotSwipeInput hook.
38
+ */
39
+ export type UsePivotSwipeInputResult = {
40
+ /** Current swipe input state */
41
+ inputState: SwipeInputState;
42
+ /** Props to spread on the container element */
43
+ containerProps: React.HTMLAttributes<HTMLElement> & {
44
+ style: React.CSSProperties;
45
+ };
46
+ };
47
+
48
+ /**
49
+ * Hook for binding swipe input to Pivot navigation.
50
+ *
51
+ * Detects horizontal swipe gestures and triggers navigation:
52
+ * - Swipe left (direction -1) → go(1) (next)
53
+ * - Swipe right (direction 1) → go(-1) (prev)
54
+ *
55
+ * Note: The direction mapping is inverted because swiping left reveals the next item,
56
+ * similar to how carousel/swipe navigation works in iOS.
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * const containerRef = useRef<HTMLDivElement>(null);
61
+ * const pivot = usePivot({ items });
62
+ * const { inputState, containerProps } = usePivotSwipeInput({
63
+ * containerRef,
64
+ * pivot,
65
+ * });
66
+ *
67
+ * return (
68
+ * <div ref={containerRef} {...containerProps}>
69
+ * <pivot.Outlet />
70
+ * </div>
71
+ * );
72
+ * ```
73
+ */
74
+ export function usePivotSwipeInput(options: UsePivotSwipeInputOptions): UsePivotSwipeInputResult {
75
+ const {
76
+ containerRef,
77
+ pivot,
78
+ axis = "horizontal",
79
+ enabled = true,
80
+ thresholds,
81
+ enableWheelSwipe = true,
82
+ } = options;
83
+
84
+ // Track if swiping is active for native gesture guard
85
+ const [isSwipeActive, setIsSwipeActive] = React.useState(false);
86
+
87
+ // Handle swipe completion
88
+ const handleSwipeEnd = React.useCallback(
89
+ (state: SwipeInputState) => {
90
+ setIsSwipeActive(false);
91
+
92
+ // Invert direction: swipe left (-1) → next (go(1)), swipe right (1) → prev (go(-1))
93
+ const navigationDirection = -state.direction;
94
+
95
+ if (navigationDirection !== 0 && pivot.canGo(navigationDirection)) {
96
+ pivot.go(navigationDirection);
97
+ }
98
+ },
99
+ [pivot],
100
+ );
101
+
102
+ // Use swipe input detection (handles both pointer and wheel)
103
+ const { state: inputState, containerProps: swipeProps } = useSwipeInput({
104
+ containerRef,
105
+ axis,
106
+ enabled,
107
+ thresholds,
108
+ onSwipeEnd: handleSwipeEnd,
109
+ enableWheel: enableWheelSwipe,
110
+ });
111
+
112
+ // Update swipe active state
113
+ React.useEffect(() => {
114
+ const isActive = inputState.phase === "swiping" || inputState.phase === "tracking";
115
+ setIsSwipeActive(isActive);
116
+ }, [inputState.phase]);
117
+
118
+ // Use native gesture guard when swiping
119
+ const { containerProps: guardProps } = useNativeGestureGuard({
120
+ containerRef,
121
+ active: isSwipeActive,
122
+ preventEdgeBack: true,
123
+ preventOverscroll: true,
124
+ });
125
+
126
+ // Merge container props
127
+ const containerProps = React.useMemo(
128
+ () => mergeGestureContainerProps(swipeProps, guardProps),
129
+ [swipeProps, guardProps],
130
+ );
131
+
132
+ return {
133
+ inputState,
134
+ containerProps,
135
+ };
136
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * @file Shared logic for draggable resize handles.
3
+ */
4
+ import * as React from "react";
5
+ import { useDragPointerEvents } from "../../hooks/useDocumentPointerEvents";
6
+ import { useEffectEvent } from "../../hooks/useEffectEvent";
7
+
8
+ export type ResizeDragAxis = "x" | "y";
9
+
10
+ export type UseResizeDragOptions = {
11
+ /** Axis along which the drag should compute deltas */
12
+ axis: ResizeDragAxis;
13
+ /** Callback invoked with the delta value when dragging */
14
+ onResize?: (delta: number) => void;
15
+ };
16
+
17
+ export type UseResizeDragResult<TElement extends HTMLElement> = {
18
+ /** Ref to attach to the draggable element */
19
+ ref: React.RefObject<TElement | null>;
20
+ /** Pointer down handler to initiate dragging */
21
+ onPointerDown: (event: React.PointerEvent<TElement>) => void;
22
+ /** Whether a drag interaction is currently active */
23
+ isDragging: boolean;
24
+ };
25
+
26
+ /**
27
+ * Provides unified pointer handling for resize-capable UI elements.
28
+ *
29
+ * @param options - Configuration for the drag interaction.
30
+ * @returns Handlers and state for wiring into a draggable element.
31
+ */
32
+ export const useResizeDrag = <TElement extends HTMLElement = HTMLElement>(
33
+ options: UseResizeDragOptions,
34
+ ): UseResizeDragResult<TElement> => {
35
+ const elementRef = React.useRef<TElement | null>(null);
36
+ const pointerIdRef = React.useRef<number | null>(null);
37
+ const previousCoordinateRef = React.useRef<number>(0);
38
+ const [isDragging, setIsDragging] = React.useState(false);
39
+
40
+ const emitResize = useEffectEvent((delta: number) => {
41
+ options.onResize?.(delta);
42
+ });
43
+
44
+ const getCoordinate = React.useCallback(
45
+ (event: PointerEvent | React.PointerEvent) => {
46
+ return options.axis === "x" ? event.clientX : event.clientY;
47
+ },
48
+ [options.axis],
49
+ );
50
+
51
+ const handlePointerDown = React.useCallback(
52
+ (event: React.PointerEvent<TElement>) => {
53
+ event.preventDefault();
54
+ elementRef.current = event.currentTarget;
55
+ pointerIdRef.current = event.pointerId;
56
+ previousCoordinateRef.current = getCoordinate(event);
57
+ setIsDragging(true);
58
+ },
59
+ [getCoordinate],
60
+ );
61
+
62
+ const handlePointerMove = React.useCallback(
63
+ (event: PointerEvent) => {
64
+ const coordinate = getCoordinate(event);
65
+ const delta = coordinate - previousCoordinateRef.current;
66
+ if (delta === 0) {
67
+ return;
68
+ }
69
+ previousCoordinateRef.current = coordinate;
70
+ emitResize(delta);
71
+ },
72
+ [getCoordinate, emitResize],
73
+ );
74
+
75
+ const handlePointerUp = React.useCallback(() => {
76
+ setIsDragging(false);
77
+ pointerIdRef.current = null;
78
+ }, []);
79
+
80
+ useDragPointerEvents(elementRef as React.RefObject<HTMLElement | null>, isDragging, {
81
+ onMove: handlePointerMove,
82
+ onUp: handlePointerUp,
83
+ pointerId: pointerIdRef.current ?? undefined,
84
+ capturePointer: true,
85
+ preventDefaults: false,
86
+ });
87
+
88
+ return {
89
+ ref: elementRef,
90
+ onPointerDown: handlePointerDown,
91
+ isDragging,
92
+ };
93
+ };
94
+
@@ -0,0 +1,264 @@
1
+ /**
2
+ * @file Tests for StackContent component - animation behavior.
3
+ *
4
+ * TDD: Tests to reproduce and prevent animation restart issues in production builds.
5
+ */
6
+ import { render, screen } from "@testing-library/react";
7
+ import * as React from "react";
8
+ import { StackContent } from "./StackContent.js";
9
+ import { STACK_ANIMATION_PUSH, STACK_ANIMATION_POP } from "../../constants/styles.js";
10
+ import type { StackNavigationState } from "./types.js";
11
+
12
+ describe("StackContent", () => {
13
+ const createNavigationState = (depth: number): StackNavigationState => ({
14
+ stack: depth === 0 ? ["root"] : depth === 1 ? ["root", "detail"] : ["root", "detail", "edit"],
15
+ depth,
16
+ isRevealing: false,
17
+ revealDepth: null,
18
+ });
19
+
20
+ describe("push animation (becoming active)", () => {
21
+ it("applies push animation when becoming active", () => {
22
+ const { rerender } = render(
23
+ <StackContent
24
+ id="panel"
25
+ depth={1}
26
+ isActive={false}
27
+ displayMode="overlay"
28
+ transitionMode="css"
29
+ navigationState={createNavigationState(0)}
30
+ >
31
+ <div data-testid="content">Content</div>
32
+ </StackContent>,
33
+ );
34
+
35
+ // Panel becomes active (pushed onto stack)
36
+ rerender(
37
+ <StackContent
38
+ id="panel"
39
+ depth={1}
40
+ isActive={true}
41
+ displayMode="overlay"
42
+ transitionMode="css"
43
+ navigationState={createNavigationState(1)}
44
+ >
45
+ <div data-testid="content">Content</div>
46
+ </StackContent>,
47
+ );
48
+
49
+ const wrapper = screen.getByTestId("content").parentElement;
50
+ expect(wrapper?.style?.animation).toBe(STACK_ANIMATION_PUSH);
51
+ });
52
+ });
53
+
54
+ describe("pop animation (becoming inactive)", () => {
55
+ it("applies pop animation when becoming inactive", () => {
56
+ const { rerender } = render(
57
+ <StackContent
58
+ id="panel"
59
+ depth={1}
60
+ isActive={true}
61
+ displayMode="overlay"
62
+ transitionMode="css"
63
+ navigationState={createNavigationState(1)}
64
+ >
65
+ <div data-testid="content">Content</div>
66
+ </StackContent>,
67
+ );
68
+
69
+ // Panel becomes inactive (popped from stack)
70
+ rerender(
71
+ <StackContent
72
+ id="panel"
73
+ depth={1}
74
+ isActive={false}
75
+ displayMode="overlay"
76
+ transitionMode="css"
77
+ navigationState={createNavigationState(0)}
78
+ >
79
+ <div data-testid="content">Content</div>
80
+ </StackContent>,
81
+ );
82
+
83
+ const wrapper = screen.getByTestId("content").parentElement;
84
+ expect(wrapper?.style?.animation).toBe(STACK_ANIMATION_POP);
85
+ });
86
+
87
+ it("keeps panel visible during pop animation", () => {
88
+ // Panel must remain visible during pop animation, otherwise animation won't be seen
89
+ const { rerender } = render(
90
+ <StackContent
91
+ id="panel"
92
+ depth={1}
93
+ isActive={true}
94
+ displayMode="overlay"
95
+ transitionMode="css"
96
+ navigationState={createNavigationState(1)}
97
+ >
98
+ <div data-testid="content">Content</div>
99
+ </StackContent>,
100
+ );
101
+
102
+ // Panel becomes inactive (pop)
103
+ rerender(
104
+ <StackContent
105
+ id="panel"
106
+ depth={1}
107
+ isActive={false}
108
+ displayMode="overlay"
109
+ transitionMode="css"
110
+ navigationState={createNavigationState(0)}
111
+ >
112
+ <div data-testid="content">Content</div>
113
+ </StackContent>,
114
+ );
115
+
116
+ const wrapper = screen.getByTestId("content").parentElement;
117
+ expect(wrapper?.style?.visibility).toBe("visible");
118
+ });
119
+ });
120
+
121
+ describe("no animation when transitionMode=none", () => {
122
+ it("does not apply animation property", () => {
123
+ render(
124
+ <StackContent
125
+ id="panel"
126
+ depth={0}
127
+ isActive={true}
128
+ displayMode="overlay"
129
+ transitionMode="none"
130
+ navigationState={createNavigationState(0)}
131
+ >
132
+ <div data-testid="content">Content</div>
133
+ </StackContent>,
134
+ );
135
+
136
+ const wrapper = screen.getByTestId("content").parentElement;
137
+ expect(wrapper?.style?.animation).toBeFalsy();
138
+ });
139
+ });
140
+
141
+ describe("initial mount behavior (production animation issue)", () => {
142
+ it("does NOT apply push animation on initial mount when isActive=true", () => {
143
+ // No animation should be applied on initial mount
144
+ render(
145
+ <StackContent
146
+ id="panel"
147
+ depth={0}
148
+ isActive={true}
149
+ displayMode="overlay"
150
+ transitionMode="css"
151
+ navigationState={createNavigationState(0)}
152
+ >
153
+ <div data-testid="content">Content</div>
154
+ </StackContent>,
155
+ );
156
+
157
+ const wrapper = screen.getByTestId("content").parentElement;
158
+ expect(wrapper?.style?.animation).toBeFalsy();
159
+ });
160
+
161
+ it("does NOT re-trigger animation when parent re-renders without isActive change", () => {
162
+ // Animation should not be re-triggered when isActive remains unchanged
163
+ const { rerender } = render(
164
+ <StackContent
165
+ id="panel"
166
+ depth={0}
167
+ isActive={true}
168
+ displayMode="overlay"
169
+ transitionMode="css"
170
+ navigationState={createNavigationState(0)}
171
+ >
172
+ <div data-testid="content">Content</div>
173
+ </StackContent>,
174
+ );
175
+
176
+ const wrapper = screen.getByTestId("content").parentElement;
177
+ expect(wrapper?.style?.animation).toBeFalsy();
178
+
179
+ // Parent re-renders (e.g., containerWidth update), isActive unchanged
180
+ rerender(
181
+ <StackContent
182
+ id="panel"
183
+ depth={0}
184
+ isActive={true}
185
+ displayMode="overlay"
186
+ transitionMode="css"
187
+ navigationState={createNavigationState(0)}
188
+ >
189
+ <div data-testid="content">Updated Content</div>
190
+ </StackContent>,
191
+ );
192
+
193
+ expect(wrapper?.style?.animation).toBeFalsy();
194
+ });
195
+
196
+ it("does NOT apply animation for inactive panel on initial mount", () => {
197
+ render(
198
+ <StackContent
199
+ id="panel"
200
+ depth={1}
201
+ isActive={false}
202
+ displayMode="overlay"
203
+ transitionMode="css"
204
+ navigationState={createNavigationState(0)}
205
+ >
206
+ <div data-testid="content">Content</div>
207
+ </StackContent>,
208
+ );
209
+
210
+ const wrapper = screen.getByTestId("content").parentElement;
211
+ expect(wrapper?.style?.animation).toBeFalsy();
212
+ });
213
+ });
214
+
215
+ describe("animation stability during re-renders", () => {
216
+ it("should maintain animation value during re-renders when animating", () => {
217
+ const { rerender } = render(
218
+ <StackContent
219
+ id="panel"
220
+ depth={1}
221
+ isActive={false}
222
+ displayMode="overlay"
223
+ transitionMode="css"
224
+ navigationState={createNavigationState(0)}
225
+ >
226
+ <div data-testid="content">Content</div>
227
+ </StackContent>,
228
+ );
229
+
230
+ // pushでアクティブになる
231
+ rerender(
232
+ <StackContent
233
+ id="panel"
234
+ depth={1}
235
+ isActive={true}
236
+ displayMode="overlay"
237
+ transitionMode="css"
238
+ navigationState={createNavigationState(1)}
239
+ >
240
+ <div data-testid="content">Content</div>
241
+ </StackContent>,
242
+ );
243
+
244
+ const wrapper = screen.getByTestId("content").parentElement;
245
+ expect(wrapper?.style?.animation).toBe(STACK_ANIMATION_PUSH);
246
+
247
+ // Animation value should be maintained after re-render
248
+ rerender(
249
+ <StackContent
250
+ id="panel"
251
+ depth={1}
252
+ isActive={true}
253
+ displayMode="overlay"
254
+ transitionMode="css"
255
+ navigationState={createNavigationState(1)}
256
+ >
257
+ <div data-testid="content">Updated</div>
258
+ </StackContent>,
259
+ );
260
+
261
+ expect(wrapper?.style?.animation).toBe(STACK_ANIMATION_PUSH);
262
+ });
263
+ });
264
+ });
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @file StackContent component for rendering stack panels with animations.
3
+ *
4
+ * Override via CSS custom properties:
5
+ * - --rpl-stack-animation-push: Animation when panel is pushed
6
+ * - --rpl-stack-animation-pop: Animation when panel is popped
7
+ * - --rpl-stack-transition-duration: Duration of transitions
8
+ * - --rpl-stack-transition-easing: Easing for transitions
9
+ */
10
+ import * as React from "react";
11
+ import type { StackContentProps } from "./types.js";
12
+ import { computeStackContentState } from "./computeStackContentState.js";
13
+ import type { StackAnimationType } from "./computeStackContentState.js";
14
+ import { useIsomorphicLayoutEffect } from "../../hooks/useIsomorphicLayoutEffect.js";
15
+
16
+ const baseStyle: React.CSSProperties = {
17
+ position: "absolute",
18
+ inset: 0,
19
+ width: "100%",
20
+ height: "100%",
21
+ };
22
+
23
+ /**
24
+ * Renders a stack panel with appropriate animation based on display mode.
25
+ */
26
+ export const StackContent: React.FC<StackContentProps> = React.memo(
27
+ ({ id, depth, isActive, displayMode, transitionMode, navigationState, swipeProgress, children }) => {
28
+ const ref = React.useRef<HTMLDivElement>(null);
29
+ const prevActiveRef = React.useRef(isActive);
30
+
31
+ // Track current animation type
32
+ const [animationType, setAnimationType] = React.useState<StackAnimationType>(null);
33
+
34
+ // Compute state using pure function
35
+ const computedState = computeStackContentState({
36
+ depth,
37
+ isActive,
38
+ wasActive: prevActiveRef.current,
39
+ currentAnimationType: animationType,
40
+ displayMode,
41
+ transitionMode,
42
+ navigationState,
43
+ swipeProgress,
44
+ });
45
+
46
+ // Update animation type synchronously before paint
47
+ useIsomorphicLayoutEffect(() => {
48
+ const wasActive = prevActiveRef.current;
49
+ prevActiveRef.current = isActive;
50
+
51
+ if (wasActive !== isActive) {
52
+ setAnimationType(computedState.nextAnimationType);
53
+ }
54
+ }, [isActive, computedState.nextAnimationType]);
55
+
56
+ // Clear animation type after animation ends
57
+ // Only handle animation end for this element (not bubbled from children)
58
+ const handleAnimationEnd = React.useCallback((e: React.AnimationEvent) => {
59
+ if (e.target === e.currentTarget) {
60
+ setAnimationType(null);
61
+ }
62
+ }, []);
63
+
64
+ // Build style from computed state
65
+ const style = React.useMemo<React.CSSProperties>(() => {
66
+ const s: React.CSSProperties = {
67
+ ...baseStyle,
68
+ transform: computedState.transform,
69
+ pointerEvents: computedState.pointerEvents,
70
+ zIndex: computedState.zIndex,
71
+ visibility: computedState.visibility,
72
+ };
73
+
74
+ if (computedState.animation !== undefined) {
75
+ s.animation = computedState.animation;
76
+ }
77
+
78
+ if (computedState.transition !== undefined) {
79
+ s.transition = computedState.transition;
80
+ }
81
+
82
+ return s;
83
+ }, [
84
+ computedState.transform,
85
+ computedState.pointerEvents,
86
+ computedState.zIndex,
87
+ computedState.visibility,
88
+ computedState.animation,
89
+ computedState.transition,
90
+ ]);
91
+
92
+ const content = (
93
+ <div
94
+ ref={ref}
95
+ data-stack-content={id}
96
+ data-depth={depth}
97
+ data-active={isActive ? "true" : "false"}
98
+ style={style}
99
+ onAnimationEnd={handleAnimationEnd}
100
+ >
101
+ {children}
102
+ </div>
103
+ );
104
+
105
+ if (transitionMode === "none") {
106
+ return <React.Activity mode={isActive ? "visible" : "hidden"}>{content}</React.Activity>;
107
+ }
108
+
109
+ return content;
110
+ },
111
+ );