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,125 @@
1
+ /**
2
+ * @file Shared useIntersectionObserver hook with cached observer instances.
3
+ */
4
+ import * as React from "react";
5
+
6
+ const createIdGenerator = () => {
7
+ const map = new Map<object, number>();
8
+ return (ref: object | null | undefined) => {
9
+ if (!ref) {
10
+ return undefined;
11
+ }
12
+ const existing = map.get(ref);
13
+ if (existing !== undefined) {
14
+ return existing;
15
+ }
16
+ const nextId = map.size;
17
+ map.set(ref, nextId);
18
+ return nextId;
19
+ };
20
+ };
21
+
22
+ const getId = createIdGenerator();
23
+ type Unobserve = () => void;
24
+ type Callback = (entry: IntersectionObserverEntry) => void;
25
+ type SharedObserver = {
26
+ observe: (target: Element, callback: Callback) => Unobserve;
27
+ };
28
+ const observerCache = new Map<string, SharedObserver>();
29
+ const getSharedObserver = (options: IntersectionObserverInit) => {
30
+ const observerKey = `ovs-threshold:${options.threshold}-rootMargin:${options.rootMargin}-root:${getId(options.root)}`;
31
+
32
+ if (observerCache.has(observerKey)) {
33
+ return observerCache.get(observerKey)!;
34
+ }
35
+ const observer = new (class {
36
+ #callbackMap = new Map<Element, Callback>();
37
+ #intersectionObserver = new IntersectionObserver((entries) => {
38
+ entries.forEach((entry) => {
39
+ const callback = this.#callbackMap.get(entry.target);
40
+ if (callback) {
41
+ callback(entry);
42
+ }
43
+ });
44
+ }, options);
45
+ observe(target: Element, callback: Callback) {
46
+ this.#callbackMap.set(target, callback);
47
+ this.#intersectionObserver.observe(target);
48
+ return () => {
49
+ this.#callbackMap.delete(target);
50
+ this.#intersectionObserver.unobserve(target);
51
+ };
52
+ }
53
+ })();
54
+ observerCache.set(observerKey, observer);
55
+
56
+ return observer;
57
+ };
58
+ const voidClientRect = Object.freeze({
59
+ x: 0,
60
+ y: 0,
61
+ width: 0,
62
+ height: 0,
63
+ top: 0,
64
+ right: 0,
65
+ bottom: 0,
66
+ left: 0,
67
+ }) as DOMRectReadOnly;
68
+ /**
69
+ * Observe intersection changes for a given element reference using shared observers.
70
+ *
71
+ * @param ref - Ref holding the element to observe.
72
+ * @param options - Intersection observer configuration.
73
+ * @returns Latest intersection entry snapshot with sensible defaults.
74
+ */
75
+ export function useIntersectionObserver<T extends HTMLElement>(
76
+ ref: React.RefObject<T | null>,
77
+ { threshold = 0, rootMargin = "0px", root = null }: IntersectionObserverInit,
78
+ ): {
79
+ readonly boundingClientRect: DOMRectReadOnly;
80
+ readonly intersectionRatio: number;
81
+ readonly intersectionRect: DOMRectReadOnly;
82
+ readonly isIntersecting: boolean;
83
+ readonly rootBounds: DOMRectReadOnly | null;
84
+ readonly target: Element | null;
85
+ readonly time: DOMHighResTimeStamp;
86
+ } {
87
+ const [intersection, setIntersection] = React.useState<IntersectionObserverEntry | null>(null);
88
+
89
+ React.useEffect(() => {
90
+ const target = ref.current;
91
+ if (!target) {
92
+ return;
93
+ }
94
+
95
+ const observer = getSharedObserver({
96
+ threshold,
97
+ rootMargin,
98
+ root,
99
+ });
100
+
101
+ return observer.observe(target, (entry) => {
102
+ setIntersection({
103
+ isIntersecting: entry.isIntersecting,
104
+ boundingClientRect: entry.boundingClientRect,
105
+ intersectionRatio: entry.intersectionRatio,
106
+ intersectionRect: entry.intersectionRect,
107
+ rootBounds: entry.rootBounds,
108
+ target: entry.target,
109
+ time: entry.time,
110
+ });
111
+ });
112
+ }, [ref, threshold, rootMargin, root]);
113
+
114
+ return React.useMemo(() => {
115
+ return {
116
+ isIntersecting: intersection?.isIntersecting ?? false,
117
+ boundingClientRect: intersection?.boundingClientRect ?? voidClientRect,
118
+ intersectionRatio: intersection?.intersectionRatio ?? 0,
119
+ intersectionRect: intersection?.intersectionRect ?? voidClientRect,
120
+ rootBounds: intersection?.rootBounds ?? null,
121
+ target: intersection?.target ?? ref.current,
122
+ time: intersection?.time ?? 0,
123
+ };
124
+ }, [intersection, ref]);
125
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @file useIsomorphicLayoutEffect - SSR-safe version of useLayoutEffect
3
+ *
4
+ * Uses useLayoutEffect on the client and useEffect on the server to avoid warnings
5
+ * during server-side rendering (e.g., with Next.js)
6
+ */
7
+ import * as React from "react";
8
+
9
+ /**
10
+ * Check if we're running in a browser environment
11
+ */
12
+ const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
13
+
14
+ /**
15
+ * SSR-safe version of useLayoutEffect
16
+ *
17
+ * - Client: Uses useLayoutEffect for synchronous layout updates
18
+ * - Server: Uses useEffect to avoid SSR warnings
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * useIsomorphicLayoutEffect(() => {
23
+ * // This runs synchronously after DOM mutations on the client
24
+ * // but safely falls back to useEffect on the server
25
+ * measureElement();
26
+ * }, [deps]);
27
+ * ```
28
+ */
29
+ export const useIsomorphicLayoutEffect = isBrowser ? React.useLayoutEffect : React.useEffect;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @file Shared useResizeObserver hook with cached observer instances.
3
+ */
4
+ import * as React from "react";
5
+
6
+ type Unobserve = () => void;
7
+ type Callback = (entry: ResizeObserverEntry, observer: ResizeObserver) => void;
8
+ type SharedObserver = {
9
+ observe: (target: Element, callback: Callback) => Unobserve;
10
+ };
11
+ const observerCache = new Map<string, SharedObserver>();
12
+ const getSharedObserver = (options: ResizeObserverOptions) => {
13
+ const { box = "content-box" } = options;
14
+ const observerKey = `resize-box:${box}`;
15
+ const cached = observerCache.get(observerKey);
16
+ if (cached) {
17
+ return cached;
18
+ }
19
+ const observer = new (class {
20
+ #callbackMap = new Map<Element, Callback>();
21
+ #resizeObserver = new ResizeObserver((entries, observer) => {
22
+ entries.forEach((entry) => {
23
+ const callback = this.#callbackMap.get(entry.target);
24
+ if (callback) {
25
+ callback(entry, observer);
26
+ }
27
+ });
28
+ });
29
+ observe(target: Element, callback: Callback) {
30
+ this.#callbackMap.set(target, callback);
31
+ this.#resizeObserver.observe(target, options);
32
+ return () => {
33
+ this.#callbackMap.delete(target);
34
+ this.#resizeObserver.unobserve(target);
35
+ };
36
+ }
37
+ })();
38
+ observerCache.set(observerKey, observer);
39
+
40
+ return observer;
41
+ };
42
+ /**
43
+ * Observe size changes for a given element reference using shared resize observers.
44
+ *
45
+ * @param ref - Ref holding the element whose size to monitor.
46
+ * @param options - Resize observer configuration.
47
+ * @returns Latest resize entry and a derived DOMRect snapshot.
48
+ */
49
+ export function useResizeObserver<T extends HTMLElement>(
50
+ ref: React.RefObject<T | null>,
51
+ { box }: ResizeObserverOptions,
52
+ ) {
53
+ const [entry, setEntry] = React.useState<ResizeObserverEntry | null>(null);
54
+ const target = ref.current;
55
+
56
+ React.useEffect(() => {
57
+ if (!target) {
58
+ return;
59
+ }
60
+
61
+ const observer = getSharedObserver({ box });
62
+ return observer.observe(target, (nextEntry) => {
63
+ setEntry(nextEntry);
64
+ });
65
+ }, [box, target]);
66
+
67
+ const rect = React.useMemo(() => {
68
+ if (!entry) {
69
+ return null;
70
+ }
71
+
72
+ if (entry.borderBoxSize?.length > 0) {
73
+ const size = entry.borderBoxSize[0];
74
+ return new DOMRect(0, 0, size.inlineSize, size.blockSize);
75
+ }
76
+
77
+ return entry.contentRect;
78
+ }, [entry]);
79
+
80
+ return { entry, rect };
81
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * @file useScrollContainer - Detect the nearest scrollable ancestor
3
+ *
4
+ * Traverses the DOM tree to find the nearest ancestor with overflow: scroll/auto.
5
+ * Returns null if the document is the scroll container.
6
+ */
7
+ import * as React from "react";
8
+
9
+ /**
10
+ * Check if an element is a scroll container.
11
+ */
12
+ function isScrollContainer(element: Element): boolean {
13
+ const style = getComputedStyle(element);
14
+ const overflowY = style.overflowY;
15
+ const overflowX = style.overflowX;
16
+
17
+ return (
18
+ overflowY === "scroll" ||
19
+ overflowY === "auto" ||
20
+ overflowX === "scroll" ||
21
+ overflowX === "auto"
22
+ );
23
+ }
24
+
25
+ /**
26
+ * Find the nearest scrollable ancestor of an element.
27
+ *
28
+ * @param element - Starting element to search from
29
+ * @returns The nearest scrollable ancestor, or null if document is the container
30
+ */
31
+ function findScrollContainer(element: Element | null): HTMLElement | null {
32
+ if (!element) {
33
+ return null;
34
+ }
35
+
36
+ // eslint-disable-next-line no-restricted-syntax -- DOM traversal requires let
37
+ let current = element.parentElement;
38
+
39
+ while (current) {
40
+ if (isScrollContainer(current)) {
41
+ return current;
42
+ }
43
+ current = current.parentElement;
44
+ }
45
+
46
+ return null;
47
+ }
48
+
49
+ /**
50
+ * Hook to detect the nearest scrollable ancestor of a ref element.
51
+ *
52
+ * @param ref - Ref to the element to find scroll container for
53
+ * @returns The nearest scrollable ancestor element, or null if document is the container
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * const elementRef = useRef<HTMLDivElement>(null);
58
+ * const scrollContainer = useScrollContainer(elementRef);
59
+ * // scrollContainer is HTMLElement if in nested scroll, null if document scroll
60
+ * ```
61
+ */
62
+ export function useScrollContainer<T extends HTMLElement>(
63
+ ref: React.RefObject<T | null>,
64
+ ): HTMLElement | null {
65
+ const [container, setContainer] = React.useState<HTMLElement | null>(null);
66
+
67
+ React.useEffect(() => {
68
+ const element = ref.current;
69
+ if (!element) {
70
+ setContainer(null);
71
+ return;
72
+ }
73
+
74
+ const scrollContainer = findScrollContainer(element);
75
+ setContainer(scrollContainer);
76
+ }, [ref]);
77
+
78
+ return container;
79
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @file Hook for snapping element transform animation.
3
+ *
4
+ * Built on top of useAnimationFrame, provides a convenient API
5
+ * for animating element transforms from one position to another.
6
+ */
7
+ import * as React from "react";
8
+ import { useAnimationFrame, interpolate, easings } from "./useAnimationFrame.js";
9
+ import type { EasingFunction } from "./useAnimationFrame.js";
10
+
11
+ // Re-export easings for convenience
12
+ export { easings } from "./useAnimationFrame.js";
13
+ export type { EasingFunction } from "./useAnimationFrame.js";
14
+
15
+ /**
16
+ * Options for useSnapAnimation hook.
17
+ */
18
+ export type UseSnapAnimationOptions = {
19
+ /** Reference to the element to animate */
20
+ elementRef: React.RefObject<HTMLElement | null>;
21
+ /** Duration of animation in milliseconds */
22
+ duration?: number;
23
+ /** Easing function for the animation */
24
+ easing?: EasingFunction;
25
+ /** Callback when animation completes */
26
+ onComplete?: () => void;
27
+ };
28
+
29
+ /**
30
+ * Result from useSnapAnimation hook.
31
+ */
32
+ export type UseSnapAnimationResult = {
33
+ /** Whether animation is currently running */
34
+ isAnimating: boolean;
35
+ /** Start a new animation from current value to target */
36
+ animate: (from: number, to: number, axis: "x" | "y") => void;
37
+ /** Cancel any running animation */
38
+ cancel: () => void;
39
+ };
40
+
41
+ /** Default animation duration in ms */
42
+ const DEFAULT_DURATION = 300;
43
+
44
+ /**
45
+ * Hook for snapping element transform animation.
46
+ *
47
+ * Animates an element's transform from one position to another
48
+ * using requestAnimationFrame for smooth animation.
49
+ *
50
+ * @example
51
+ * ```tsx
52
+ * const elementRef = useRef<HTMLDivElement>(null);
53
+ * const { animate, isAnimating } = useSnapAnimation({
54
+ * elementRef,
55
+ * duration: 300,
56
+ * easing: easings.easeOutExpo,
57
+ * });
58
+ *
59
+ * // Start animation
60
+ * animate(currentX, targetX, "x");
61
+ * ```
62
+ */
63
+ export function useSnapAnimation(options: UseSnapAnimationOptions): UseSnapAnimationResult {
64
+ const {
65
+ elementRef,
66
+ duration = DEFAULT_DURATION,
67
+ easing = easings.easeOutExpo,
68
+ onComplete,
69
+ } = options;
70
+
71
+ // Store animation parameters in refs for use in onFrame callback
72
+ const animParamsRef = React.useRef<{
73
+ from: number;
74
+ to: number;
75
+ axis: "x" | "y";
76
+ } | null>(null);
77
+
78
+ const handleFrame = React.useCallback(
79
+ ({ easedProgress }: { easedProgress: number }) => {
80
+ const element = elementRef.current;
81
+ const params = animParamsRef.current;
82
+ if (!element || !params) {
83
+ return;
84
+ }
85
+
86
+ const currentValue = interpolate(params.from, params.to, easedProgress);
87
+ const translateFn = params.axis === "x" ? "translateX" : "translateY";
88
+ element.style.transform = `${translateFn}(${currentValue}px)`;
89
+ },
90
+ [elementRef],
91
+ );
92
+
93
+ const { isAnimating, start, cancel } = useAnimationFrame({
94
+ duration,
95
+ easing,
96
+ onFrame: handleFrame,
97
+ onComplete,
98
+ });
99
+
100
+ const animate = React.useCallback(
101
+ (from: number, to: number, axis: "x" | "y") => {
102
+ const element = elementRef.current;
103
+ if (!element) {
104
+ return;
105
+ }
106
+
107
+ // If from and to are the same, no animation needed
108
+ if (Math.abs(from - to) < 0.5) {
109
+ const translateFn = axis === "x" ? "translateX" : "translateY";
110
+ element.style.transform = `${translateFn}(${to}px)`;
111
+ return;
112
+ }
113
+
114
+ // Store animation parameters
115
+ animParamsRef.current = { from, to, axis };
116
+
117
+ // Start animation
118
+ start();
119
+ },
120
+ [elementRef, start],
121
+ );
122
+
123
+ return {
124
+ isAnimating,
125
+ animate,
126
+ cancel,
127
+ };
128
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * @file Tests for useSwipeContentTransform hook.
3
+ */
4
+ import { renderHook } from "@testing-library/react";
5
+ import { useSwipeContentTransform } from "./useSwipeContentTransform.js";
6
+
7
+ describe("useSwipeContentTransform", () => {
8
+ const createMockElementRef = (): { element: HTMLDivElement; ref: React.RefObject<HTMLDivElement> } => {
9
+ const element = document.createElement("div");
10
+ return { element, ref: { current: element } };
11
+ };
12
+
13
+ it("returns initial state correctly", () => {
14
+ const { ref } = createMockElementRef();
15
+ const { result } = renderHook(() =>
16
+ useSwipeContentTransform({
17
+ elementRef: ref,
18
+ targetPx: 0,
19
+ displacement: 0,
20
+ isSwiping: false,
21
+ }),
22
+ );
23
+
24
+ expect(result.current.isAnimating).toBe(false);
25
+ expect(result.current.currentPx).toBe(0);
26
+ });
27
+
28
+ it("updates element transform during swipe", () => {
29
+ const { element, ref } = createMockElementRef();
30
+ const { rerender } = renderHook(
31
+ ({ displacement, isSwiping }) =>
32
+ useSwipeContentTransform({
33
+ elementRef: ref,
34
+ targetPx: 0,
35
+ displacement,
36
+ isSwiping,
37
+ }),
38
+ {
39
+ initialProps: { displacement: 0, isSwiping: true },
40
+ },
41
+ );
42
+
43
+ // Simulate swipe movement
44
+ rerender({ displacement: 100, isSwiping: true });
45
+
46
+ expect(element.style.transform).toBe("translateX(100px)");
47
+ });
48
+
49
+ it("uses correct transform function for vertical axis", () => {
50
+ const { element, ref } = createMockElementRef();
51
+ const { rerender } = renderHook(
52
+ ({ displacement, isSwiping }) =>
53
+ useSwipeContentTransform({
54
+ elementRef: ref,
55
+ targetPx: 0,
56
+ displacement,
57
+ isSwiping,
58
+ axis: "vertical",
59
+ }),
60
+ {
61
+ initialProps: { displacement: 0, isSwiping: true },
62
+ },
63
+ );
64
+
65
+ rerender({ displacement: 50, isSwiping: true });
66
+
67
+ expect(element.style.transform).toBe("translateY(50px)");
68
+ });
69
+
70
+ it("applies target position with displacement", () => {
71
+ const { element, ref } = createMockElementRef();
72
+ const { rerender } = renderHook(
73
+ ({ displacement, isSwiping }) =>
74
+ useSwipeContentTransform({
75
+ elementRef: ref,
76
+ targetPx: -300, // target is off-screen left
77
+ displacement,
78
+ isSwiping,
79
+ }),
80
+ {
81
+ initialProps: { displacement: 0, isSwiping: true },
82
+ },
83
+ );
84
+
85
+ // During swipe, position = targetPx + displacement
86
+ rerender({ displacement: 100, isSwiping: true });
87
+
88
+ expect(element.style.transform).toBe("translateX(-200px)");
89
+ });
90
+
91
+ it("does not update transform when element ref is null", () => {
92
+ const nullRef: React.RefObject<HTMLElement | null> = { current: null };
93
+
94
+ const { rerender } = renderHook(
95
+ ({ displacement, isSwiping }) =>
96
+ useSwipeContentTransform({
97
+ elementRef: nullRef,
98
+ targetPx: 0,
99
+ displacement,
100
+ isSwiping,
101
+ }),
102
+ {
103
+ initialProps: { displacement: 0, isSwiping: true },
104
+ },
105
+ );
106
+
107
+ // Should not throw
108
+ expect(() => {
109
+ rerender({ displacement: 100, isSwiping: true });
110
+ }).not.toThrow();
111
+ });
112
+
113
+ it("snaps to target when target changes and not swiping", () => {
114
+ const { element, ref } = createMockElementRef();
115
+ const { rerender } = renderHook(
116
+ ({ targetPx }) =>
117
+ useSwipeContentTransform({
118
+ elementRef: ref,
119
+ targetPx,
120
+ displacement: 0,
121
+ isSwiping: false,
122
+ }),
123
+ {
124
+ initialProps: { targetPx: 0 },
125
+ },
126
+ );
127
+
128
+ // Change target without swiping - should snap
129
+ rerender({ targetPx: 300 });
130
+
131
+ expect(element.style.transform).toBe("translateX(300px)");
132
+ });
133
+ });