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,232 @@
1
+ /**
2
+ * @file Unit tests for useContentCache hook.
3
+ * Verifies content caching, cache cleanup, and state preservation.
4
+ */
5
+ import { renderHook, act } from "@testing-library/react";
6
+ import * as React from "react";
7
+ import { useContentCache } from "./useContentCache";
8
+
9
+ /**
10
+ * Creates a simple fake function that tracks call count and can return a configured value.
11
+ */
12
+ function createFake<T>(returnValue: T) {
13
+ const state = { callCount: 0 };
14
+ const fn = () => {
15
+ state.callCount++;
16
+ return returnValue;
17
+ };
18
+ return { fn, state };
19
+ }
20
+
21
+ /**
22
+ * Creates a fake function with custom implementation that tracks call count.
23
+ */
24
+ function createFakeWithImpl<T>(impl: (id: string) => T) {
25
+ const state = { callCount: 0 };
26
+ const fn = (id: string) => {
27
+ state.callCount++;
28
+ return impl(id);
29
+ };
30
+ return { fn, state };
31
+ }
32
+
33
+ describe("useContentCache", () => {
34
+ describe("content caching", () => {
35
+ it("returns cached content for the same ID", () => {
36
+ const content = <div>Test Content</div>;
37
+ const { fn: resolveContent, state } = createFake(content);
38
+
39
+ const { result } = renderHook(() =>
40
+ useContentCache({
41
+ resolveContent,
42
+ validIds: ["item-1"],
43
+ }),
44
+ );
45
+
46
+ // First call should invoke resolveContent
47
+ const first = result.current.getCachedContent("item-1");
48
+ expect(state.callCount).toBe(1);
49
+ expect(first).toBe(content);
50
+
51
+ // Second call should return cached value without calling resolveContent
52
+ const second = result.current.getCachedContent("item-1");
53
+ expect(state.callCount).toBe(1);
54
+ expect(second).toBe(first);
55
+ });
56
+
57
+ it("returns the same reference across re-renders", () => {
58
+ const content = <div>Test Content</div>;
59
+ const { fn: resolveContent, state } = createFake(content);
60
+
61
+ const { result, rerender } = renderHook(
62
+ ({ validIds }) =>
63
+ useContentCache({
64
+ resolveContent,
65
+ validIds,
66
+ }),
67
+ { initialProps: { validIds: ["item-1"] as readonly string[] } },
68
+ );
69
+
70
+ const first = result.current.getCachedContent("item-1");
71
+ expect(state.callCount).toBe(1);
72
+
73
+ // Re-render with same validIds
74
+ rerender({ validIds: ["item-1"] });
75
+ const afterRerender = result.current.getCachedContent("item-1");
76
+
77
+ // Should still be the same reference, resolveContent not called again
78
+ expect(state.callCount).toBe(1);
79
+ expect(afterRerender).toBe(first);
80
+ });
81
+
82
+ it("caches content for multiple IDs independently", () => {
83
+ const content1 = <div>Content 1</div>;
84
+ const content2 = <div>Content 2</div>;
85
+ const { fn: resolveContent, state } = createFakeWithImpl((id: string) => {
86
+ if (id === "item-1") {
87
+ return content1;
88
+ }
89
+ if (id === "item-2") {
90
+ return content2;
91
+ }
92
+ return null;
93
+ });
94
+
95
+ const { result } = renderHook(() =>
96
+ useContentCache({
97
+ resolveContent,
98
+ validIds: ["item-1", "item-2"],
99
+ }),
100
+ );
101
+
102
+ const cached1 = result.current.getCachedContent("item-1");
103
+ const cached2 = result.current.getCachedContent("item-2");
104
+
105
+ expect(cached1).toBe(content1);
106
+ expect(cached2).toBe(content2);
107
+ expect(state.callCount).toBe(2);
108
+
109
+ // Accessing again should not call resolveContent
110
+ result.current.getCachedContent("item-1");
111
+ result.current.getCachedContent("item-2");
112
+ expect(state.callCount).toBe(2);
113
+ });
114
+
115
+ it("returns null for non-existent IDs", () => {
116
+ const { fn: resolveContent } = createFake(null);
117
+ const validIds: string[] = ["item-1"];
118
+
119
+ const { result } = renderHook(() =>
120
+ useContentCache({
121
+ resolveContent,
122
+ validIds,
123
+ }),
124
+ );
125
+
126
+ const cached = result.current.getCachedContent("non-existent");
127
+ expect(cached).toBeNull();
128
+ });
129
+ });
130
+
131
+ describe("cache cleanup", () => {
132
+ it("removes stale entries when validIds changes", () => {
133
+ const content1 = <div>Content 1</div>;
134
+ const content2 = <div>Content 2</div>;
135
+ const { fn: resolveContent, state } = createFakeWithImpl((id: string) => {
136
+ if (id === "item-1") {
137
+ return content1;
138
+ }
139
+ if (id === "item-2") {
140
+ return content2;
141
+ }
142
+ return null;
143
+ });
144
+
145
+ const { result, rerender } = renderHook(
146
+ ({ validIds }) =>
147
+ useContentCache({
148
+ resolveContent,
149
+ validIds,
150
+ }),
151
+ { initialProps: { validIds: ["item-1", "item-2"] as readonly string[] } },
152
+ );
153
+
154
+ // Cache both items
155
+ result.current.getCachedContent("item-1");
156
+ result.current.getCachedContent("item-2");
157
+ expect(state.callCount).toBe(2);
158
+
159
+ // Remove item-1 from validIds
160
+ rerender({ validIds: ["item-2"] });
161
+
162
+ // item-2 should still be cached
163
+ result.current.getCachedContent("item-2");
164
+ expect(state.callCount).toBe(2);
165
+
166
+ // item-1 should be removed from cache, so resolveContent will be called again
167
+ result.current.getCachedContent("item-1");
168
+ expect(state.callCount).toBe(3);
169
+ });
170
+ });
171
+
172
+ describe("clearCache", () => {
173
+ it("clears all cached content", () => {
174
+ const content = <div>Test Content</div>;
175
+ const { fn: resolveContent, state } = createFake(content);
176
+
177
+ const { result } = renderHook(() =>
178
+ useContentCache({
179
+ resolveContent,
180
+ validIds: ["item-1"],
181
+ }),
182
+ );
183
+
184
+ // Cache the content
185
+ result.current.getCachedContent("item-1");
186
+ expect(state.callCount).toBe(1);
187
+
188
+ // Clear cache
189
+ act(() => {
190
+ result.current.clearCache();
191
+ });
192
+
193
+ // Accessing again should call resolveContent
194
+ result.current.getCachedContent("item-1");
195
+ expect(state.callCount).toBe(2);
196
+ });
197
+ });
198
+
199
+ describe("resolveContent updates", () => {
200
+ it("uses latest resolveContent function via ref pattern", () => {
201
+ const initialContent = <div>Initial</div>;
202
+ const updatedContent = <div>Updated</div>;
203
+ const { result, rerender } = renderHook(
204
+ ({ content }) =>
205
+ useContentCache({
206
+ resolveContent: () => content,
207
+ validIds: ["item-1"],
208
+ }),
209
+ { initialProps: { content: initialContent } },
210
+ );
211
+
212
+ // Cache with initial content
213
+ const first = result.current.getCachedContent("item-1");
214
+ expect(first).toBe(initialContent);
215
+
216
+ // Update content
217
+ rerender({ content: updatedContent });
218
+
219
+ // getCachedContent should still return cached value
220
+ const cached = result.current.getCachedContent("item-1");
221
+ expect(cached).toBe(first);
222
+
223
+ // Clear cache and get new content
224
+ act(() => {
225
+ result.current.clearCache();
226
+ });
227
+
228
+ const updated = result.current.getCachedContent("item-1");
229
+ expect(updated).toBe(updatedContent);
230
+ });
231
+ });
232
+ });
@@ -0,0 +1,127 @@
1
+ /**
2
+ * @file Shared content caching hook for preserving React component state.
3
+ *
4
+ * This hook provides a common pattern for caching ReactNode content by ID,
5
+ * ensuring the same reference is returned for the same ID across re-renders.
6
+ * This prevents component remounting when parent components re-create content arrays.
7
+ *
8
+ * Used by:
9
+ * - PanelSystemContext (GridLayout layer content)
10
+ * - usePivot (Pivot item content)
11
+ * - ContentRegistry (Panel content)
12
+ */
13
+ import * as React from "react";
14
+
15
+ /**
16
+ * Function type for resolving content by ID.
17
+ * Called only when content is not already cached.
18
+ */
19
+ export type ContentResolver<TId extends string = string> = (id: TId) => React.ReactNode | null;
20
+
21
+ /**
22
+ * Options for useContentCache hook.
23
+ */
24
+ export type UseContentCacheOptions<TId extends string = string> = {
25
+ /**
26
+ * Function to resolve content by ID.
27
+ * Called only when content is not already in cache.
28
+ */
29
+ resolveContent: ContentResolver<TId>;
30
+ /**
31
+ * Current valid IDs. Used to clean up stale cache entries.
32
+ * When an ID is removed from this array, its cached content is deleted.
33
+ */
34
+ validIds: readonly TId[];
35
+ };
36
+
37
+ /**
38
+ * Result from useContentCache hook.
39
+ */
40
+ export type UseContentCacheResult<TId extends string = string> = {
41
+ /**
42
+ * Get cached content for an ID.
43
+ * Returns the same ReactNode reference for the same ID.
44
+ */
45
+ getCachedContent: (id: TId) => React.ReactNode | null;
46
+ /**
47
+ * Clear all cached content.
48
+ * Use when you need to force re-creation of all content.
49
+ */
50
+ clearCache: () => void;
51
+ };
52
+
53
+ /**
54
+ * Hook for caching ReactNode content by ID.
55
+ *
56
+ * Ensures the same ReactNode reference is returned for the same ID,
57
+ * preventing unnecessary component remounting when parent re-renders.
58
+ *
59
+ * @example
60
+ * ```tsx
61
+ * const { getCachedContent } = useContentCache({
62
+ * resolveContent: (id) => items.find(i => i.id === id)?.content ?? null,
63
+ * validIds: items.map(i => i.id),
64
+ * });
65
+ *
66
+ * return items.map(item => (
67
+ * <div key={item.id}>{getCachedContent(item.id)}</div>
68
+ * ));
69
+ * ```
70
+ */
71
+ export function useContentCache<TId extends string = string>(
72
+ options: UseContentCacheOptions<TId>,
73
+ ): UseContentCacheResult<TId> {
74
+ const { resolveContent, validIds } = options;
75
+
76
+ /**
77
+ * Cache storage. Key: ID, Value: cached ReactNode.
78
+ * Uses ref to persist across re-renders without triggering updates.
79
+ */
80
+ const cacheRef = React.useRef<Map<string, React.ReactNode>>(new Map());
81
+
82
+ /**
83
+ * Store resolveContent in a ref for stable getCachedContent function.
84
+ * This allows getCachedContent to always use the latest resolver
85
+ * without needing to be recreated.
86
+ */
87
+ const resolveContentRef = React.useRef(resolveContent);
88
+ resolveContentRef.current = resolveContent;
89
+
90
+ /**
91
+ * Get or create cached content for an ID.
92
+ * On first access, calls resolveContent and caches the result.
93
+ * On subsequent accesses, returns the cached reference.
94
+ */
95
+ const getCachedContent = React.useCallback((id: TId): React.ReactNode | null => {
96
+ const cached = cacheRef.current.get(id);
97
+ if (cached !== undefined) {
98
+ return cached;
99
+ }
100
+
101
+ const content = resolveContentRef.current(id);
102
+ cacheRef.current.set(id, content);
103
+ return content;
104
+ }, []);
105
+
106
+ /**
107
+ * Clear all cached content.
108
+ */
109
+ const clearCache = React.useCallback((): void => {
110
+ cacheRef.current.clear();
111
+ }, []);
112
+
113
+ /**
114
+ * Clean up stale cache entries when validIds changes.
115
+ * Removes entries for IDs that are no longer valid.
116
+ */
117
+ React.useEffect(() => {
118
+ const currentValidIds = new Set<string>(validIds);
119
+ cacheRef.current.forEach((_, id) => {
120
+ if (!currentValidIds.has(id)) {
121
+ cacheRef.current.delete(id);
122
+ }
123
+ });
124
+ }, [validIds]);
125
+
126
+ return { getCachedContent, clearCache };
127
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * @file Hooks for managing document-level pointer events with proper cleanup
3
+ */
4
+ import * as React from "react";
5
+ import { useEffectEvent } from "./useEffectEvent";
6
+
7
+ export type UseDocumentPointerEventsOptions = {
8
+ onMove?: (e: PointerEvent) => void;
9
+ onUp?: (e: PointerEvent) => void;
10
+ onCancel?: (e: PointerEvent) => void;
11
+ };
12
+
13
+ /**
14
+ * Custom hook for managing document-level pointer events with proper cleanup
15
+ * This pattern is commonly used for drag operations that need to continue
16
+ * even when the pointer moves outside the original element
17
+ */
18
+ export function useDocumentPointerEvents(enabled: boolean, handlers: UseDocumentPointerEventsOptions) {
19
+ const handleMoveEvent = useEffectEvent(handlers.onMove);
20
+ const handleUpEvent = useEffectEvent(handlers.onUp);
21
+ const handleCancelEvent = useEffectEvent(handlers.onCancel);
22
+
23
+ React.useEffect(() => {
24
+ if (!enabled) {
25
+ return;
26
+ }
27
+
28
+ if (handlers.onMove) {
29
+ document.addEventListener("pointermove", handleMoveEvent, { passive: false });
30
+ }
31
+ if (handlers.onUp) {
32
+ document.addEventListener("pointerup", handleUpEvent);
33
+ }
34
+ if (handlers.onCancel) {
35
+ document.addEventListener("pointercancel", handleCancelEvent);
36
+ }
37
+
38
+ // Cleanup function
39
+ return () => {
40
+ if (handlers.onMove) {
41
+ document.removeEventListener("pointermove", handleMoveEvent);
42
+ }
43
+ if (handlers.onUp) {
44
+ document.removeEventListener("pointerup", handleUpEvent);
45
+ }
46
+ if (handlers.onCancel) {
47
+ document.removeEventListener("pointercancel", handleCancelEvent);
48
+ }
49
+ };
50
+ }, [enabled, handlers.onMove, handlers.onUp, handlers.onCancel, handleMoveEvent, handleUpEvent, handleCancelEvent]);
51
+ }
52
+
53
+ /**
54
+ * Hook for capturing pointer during drag operations
55
+ * This ensures that pointer events are delivered to the capturing element
56
+ * even when the pointer moves outside its boundaries
57
+ */
58
+ export function usePointerCapture(elementRef: React.RefObject<HTMLElement | null>, enabled: boolean, pointerId?: number) {
59
+ React.useEffect(() => {
60
+ const element = elementRef.current;
61
+ if (!enabled || !element || pointerId === undefined) {
62
+ return;
63
+ }
64
+
65
+ // Capture pointer
66
+ element.setPointerCapture(pointerId);
67
+
68
+ // Release capture on cleanup
69
+ return () => {
70
+ if (element.hasPointerCapture && element.hasPointerCapture(pointerId)) {
71
+ element.releasePointerCapture(pointerId);
72
+ }
73
+ };
74
+ }, [elementRef, enabled, pointerId]);
75
+ }
76
+
77
+ /**
78
+ * Hook for preventing default pointer events during operations
79
+ * Useful for preventing text selection, context menus, etc. during drag operations
80
+ */
81
+ export function usePreventPointerDefaults(
82
+ elementRef: React.RefObject<HTMLElement | null>,
83
+ enabled: boolean,
84
+ events: string[] = ["pointerdown", "pointermove", "pointerup"],
85
+ ) {
86
+ React.useEffect(() => {
87
+ const element = elementRef.current;
88
+ if (!enabled || !element) {
89
+ return;
90
+ }
91
+
92
+ const preventDefault = (e: Event) => {
93
+ e.preventDefault();
94
+ };
95
+
96
+ // Add listeners
97
+ events.forEach((eventType) => {
98
+ element.addEventListener(eventType, preventDefault, { passive: false });
99
+ });
100
+
101
+ // Cleanup
102
+ return () => {
103
+ events.forEach((eventType) => {
104
+ element.removeEventListener(eventType, preventDefault);
105
+ });
106
+ };
107
+ }, [elementRef, enabled, events]);
108
+ }
109
+
110
+ /**
111
+ * Hook that combines multiple pointer event patterns for drag operations
112
+ */
113
+ export function useDragPointerEvents(
114
+ elementRef: React.RefObject<HTMLElement | null>,
115
+ enabled: boolean,
116
+ options: {
117
+ onMove?: (e: PointerEvent) => void;
118
+ onUp?: (e: PointerEvent) => void;
119
+ onCancel?: (e: PointerEvent) => void;
120
+ pointerId?: number;
121
+ capturePointer?: boolean;
122
+ preventDefaults?: boolean;
123
+ },
124
+ ) {
125
+ const { onMove, onUp, onCancel, pointerId, capturePointer = true, preventDefaults = true } = options;
126
+
127
+ // Document-level event handlers
128
+ useDocumentPointerEvents(enabled, { onMove, onUp, onCancel });
129
+
130
+ // Pointer capture
131
+ const shouldCapturePointer = enabled ? capturePointer : false;
132
+ usePointerCapture(elementRef, shouldCapturePointer, pointerId);
133
+
134
+ // Prevent defaults
135
+ const shouldPreventDefaults = enabled ? preventDefaults : false;
136
+ usePreventPointerDefaults(elementRef, shouldPreventDefaults);
137
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * @file useDocumentScroll - Track document scroll position
3
+ *
4
+ * Provides the current vertical scroll position of the document.
5
+ * Returns negative values during overscroll/bounce on iOS Safari and PWAs.
6
+ */
7
+ import * as React from "react";
8
+
9
+ /**
10
+ * Track document scroll position.
11
+ *
12
+ * @returns Current vertical scroll position (scrollY).
13
+ * Returns negative values during overscroll/bounce.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * const scrollY = useDocumentScroll();
18
+ * // scrollY < 0 during overscroll (pull-down bounce)
19
+ * ```
20
+ */
21
+ export function useDocumentScroll(): number {
22
+ const [scrollY, setScrollY] = React.useState(() => {
23
+ if (typeof window === "undefined") {
24
+ return 0;
25
+ }
26
+ return window.scrollY;
27
+ });
28
+
29
+ React.useEffect(() => {
30
+ const handleScroll = () => {
31
+ setScrollY(window.scrollY);
32
+ };
33
+
34
+ window.addEventListener("scroll", handleScroll, { passive: true });
35
+ return () => {
36
+ window.removeEventListener("scroll", handleScroll);
37
+ };
38
+ }, []);
39
+
40
+ return scrollY;
41
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * @file useEffectEvent hook - Stable event handler for Effects
3
+ *
4
+ * This hook allows you to extract event handlers from Effects without causing them to re-run.
5
+ * The returned function is stable and can be safely used in effect dependencies.
6
+ *
7
+ * @see https://react.dev/learn/separating-events-from-effects#declaring-an-effect-event
8
+ */
9
+ import * as React from "react";
10
+
11
+ /**
12
+ * Extract event handlers from Effects to avoid unnecessary re-runs
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * function Component({ onEvent }) {
17
+ * const onEventHandler = useEffectEvent(onEvent);
18
+ *
19
+ * React.useEffect(() => {
20
+ * // onEventHandler is stable, but always calls the latest onEvent
21
+ * const cleanup = subscribe(onEventHandler);
22
+ * return cleanup;
23
+ * }, []); // No need to include onEvent in dependencies
24
+ * }
25
+ * ```
26
+ */
27
+ export function useEffectEvent<Args extends unknown[], Return>(
28
+ fn: ((...args: Args) => Return) | undefined,
29
+ ): (...args: Args) => Return | undefined {
30
+ const ref = React.useRef<typeof fn>(fn);
31
+ ref.current = fn;
32
+
33
+ return React.useCallback((...args: Args): Return | undefined => {
34
+ const currentFn = ref.current;
35
+ if (currentFn) {
36
+ return currentFn(...args);
37
+ }
38
+ return undefined;
39
+ }, []);
40
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * @file Hook for building wrapper components that accept either an element or a component override.
3
+ */
4
+ import * as React from "react";
5
+
6
+ type WrapperProps = React.HTMLAttributes<HTMLDivElement>;
7
+
8
+ type CloneableProps = WrapperProps & {
9
+ ref?: React.Ref<HTMLDivElement>;
10
+ };
11
+
12
+ type UseElementComponentWrapperOptions = {
13
+ element?: React.ReactElement<WrapperProps>;
14
+ component?: React.ComponentType<WrapperProps & { ref?: React.Ref<HTMLDivElement> }>;
15
+ };
16
+
17
+ type WrapperComponent = React.ForwardRefExoticComponent<
18
+ React.PropsWithChildren<WrapperProps> & React.RefAttributes<HTMLDivElement>
19
+ >;
20
+
21
+ const createWrapperComponent = ({
22
+ element,
23
+ component: Component,
24
+ }: UseElementComponentWrapperOptions): WrapperComponent =>
25
+ React.forwardRef<HTMLDivElement, React.PropsWithChildren<WrapperProps>>(({ children, ...rest }, forwardedRef) => {
26
+ if (element) {
27
+ return React.cloneElement(
28
+ element,
29
+ { ...rest, ref: forwardedRef } as CloneableProps,
30
+ children ?? element.props.children
31
+ );
32
+ }
33
+ if (Component) {
34
+ return (
35
+ <Component {...rest} ref={forwardedRef}>
36
+ {children}
37
+ </Component>
38
+ );
39
+ }
40
+ return (
41
+ <div {...rest} ref={forwardedRef}>
42
+ {children}
43
+ </div>
44
+ );
45
+ });
46
+
47
+ /**
48
+ * Memoizes a wrapper component that can render either a provided element, a provided component, or a default tag.
49
+ * @returns Wrapper component honoring the overrides.
50
+ */
51
+ export function useElementComponentWrapper({
52
+ element,
53
+ component,
54
+ }: UseElementComponentWrapperOptions): WrapperComponent {
55
+ return React.useMemo(
56
+ () =>
57
+ createWrapperComponent({
58
+ element,
59
+ component,
60
+ }),
61
+ [component, element]
62
+ );
63
+ }