react-panel-layout 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (466) hide show
  1. package/dist/{FloatingPanelFrame-D9Cp2al1.cjs → FloatingPanelFrame-CEmXDvUA.cjs} +2 -2
  2. package/dist/FloatingPanelFrame-CEmXDvUA.cjs.map +1 -0
  3. package/dist/{FloatingPanelFrame-6W5OexYe.js → FloatingPanelFrame-SgYLc6Ud.js} +12 -15
  4. package/dist/FloatingPanelFrame-SgYLc6Ud.js.map +1 -0
  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 +73 -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/types.d.ts +12 -0
  111. package/dist/useContentCache-CO3LYNmz.js +24 -0
  112. package/dist/useContentCache-CO3LYNmz.js.map +1 -0
  113. package/dist/useContentCache-DqXtLrLs.cjs +2 -0
  114. package/dist/useContentCache-DqXtLrLs.cjs.map +1 -0
  115. package/dist/useDocumentPointerEvents-CKdhGXd0.js +46 -0
  116. package/dist/useDocumentPointerEvents-CKdhGXd0.js.map +1 -0
  117. package/dist/useDocumentPointerEvents-ChqrKXDk.cjs +2 -0
  118. package/dist/useDocumentPointerEvents-ChqrKXDk.cjs.map +1 -0
  119. package/dist/useEffectEvent-Dp7HLCf0.js +13 -0
  120. package/dist/useEffectEvent-Dp7HLCf0.js.map +1 -0
  121. package/dist/useEffectEvent-huSsGUnl.cjs +2 -0
  122. package/dist/useEffectEvent-huSsGUnl.cjs.map +1 -0
  123. package/dist/useFloatingState-C4kRaW_R.cjs +2 -0
  124. package/dist/useFloatingState-C4kRaW_R.cjs.map +1 -0
  125. package/dist/useFloatingState-tEfA_wbc.js +74 -0
  126. package/dist/useFloatingState-tEfA_wbc.js.map +1 -0
  127. package/dist/window/index.d.ts +61 -0
  128. package/dist/window.cjs +2 -0
  129. package/dist/window.cjs.map +1 -0
  130. package/dist/window.js +149 -0
  131. package/dist/window.js.map +1 -0
  132. package/docs/design-tokens.md +405 -0
  133. package/package.json +29 -4
  134. package/src/PanelSystemContext.tsx +88 -0
  135. package/src/components/grid/GridLayerList.tsx +172 -0
  136. package/src/components/grid/GridLayerResizeHandles.tsx +145 -0
  137. package/src/components/grid/GridLayout.spec.tsx +743 -0
  138. package/src/components/grid/GridLayout.tsx +130 -0
  139. package/src/components/grid/GridTrackResizeHandle.tsx +87 -0
  140. package/src/components/paneling/FloatingPanelFrame.tsx +203 -0
  141. package/src/components/panels/DropSuggestOverlay.tsx +131 -0
  142. package/src/components/panels/PanelGroupView.tsx +112 -0
  143. package/src/components/pivot/PivotLayer.tsx +27 -0
  144. package/src/components/resizer/HorizontalDivider.tsx +52 -0
  145. package/src/components/resizer/ResizeHandle.tsx +118 -0
  146. package/src/components/tabs/TabBar.tsx +223 -0
  147. package/src/components/tabs/TabBarTab.tsx +133 -0
  148. package/src/components/tabs/TabDragOverlay.tsx +92 -0
  149. package/src/components/window/DialogOverlay.tsx +180 -0
  150. package/src/components/window/Drawer.tsx +282 -0
  151. package/src/components/window/DrawerLayers.tsx +58 -0
  152. package/src/components/window/FloatingWindow.tsx +95 -0
  153. package/src/components/window/PopupLayerPortal.tsx +218 -0
  154. package/src/config/PanelContentDeclaration.tsx +427 -0
  155. package/src/config/index.tsx +52 -0
  156. package/src/config/panelJsx.spec.tsx +54 -0
  157. package/src/config/panelJsxConfig.spec.tsx +54 -0
  158. package/src/config/panelJsxDrawer.spec.tsx +33 -0
  159. package/src/config/panelRouter.spec.ts +68 -0
  160. package/src/config/panelRouter.tsx +155 -0
  161. package/src/constants/styles.ts +261 -0
  162. package/src/demo/Layout.module.css +258 -0
  163. package/src/demo/Layout.tsx +176 -0
  164. package/src/demo/components/CodeBlock.module.css +54 -0
  165. package/src/demo/components/CodeBlock.tsx +34 -0
  166. package/src/demo/components/CodePreview.module.css +37 -0
  167. package/src/demo/components/CodePreview.tsx +31 -0
  168. package/src/demo/components/DataPreview.module.css +177 -0
  169. package/src/demo/components/DataPreview.tsx +115 -0
  170. package/src/demo/components/Story.module.css +68 -0
  171. package/src/demo/components/Story.tsx +54 -0
  172. package/src/demo/components/layout/CodePanel.module.css +183 -0
  173. package/src/demo/components/layout/CodePanel.tsx +149 -0
  174. package/src/demo/components/layout/DemoPage.module.css +60 -0
  175. package/src/demo/components/layout/DemoPage.tsx +56 -0
  176. package/src/demo/components/layout/SingleSamplePage.module.css +11 -0
  177. package/src/demo/components/layout/SingleSamplePage.tsx +35 -0
  178. package/src/demo/components/layout/SplitDemoLayout.module.css +107 -0
  179. package/src/demo/components/layout/SplitDemoLayout.tsx +218 -0
  180. package/src/demo/components/layout/index.ts +11 -0
  181. package/src/demo/components/tab-styles/ChromeTabBar.module.css +75 -0
  182. package/src/demo/components/tab-styles/ChromeTabBar.tsx +111 -0
  183. package/src/demo/components/tab-styles/GitHubTabBar.module.css +81 -0
  184. package/src/demo/components/tab-styles/GitHubTabBar.tsx +109 -0
  185. package/src/demo/components/tab-styles/VSCodeTabBar.module.css +78 -0
  186. package/src/demo/components/tab-styles/VSCodeTabBar.tsx +109 -0
  187. package/src/demo/components/tab-styles/index.ts +6 -0
  188. package/src/demo/components/ui/DemoButton.module.css +63 -0
  189. package/src/demo/components/ui/DemoButton.tsx +32 -0
  190. package/src/demo/components/ui/DemoCard.module.css +15 -0
  191. package/src/demo/components/ui/DemoCard.tsx +30 -0
  192. package/src/demo/components/ui/DemoContainer.module.css +17 -0
  193. package/src/demo/components/ui/DemoContainer.tsx +30 -0
  194. package/src/demo/components/ui/DemoPanel.module.css +23 -0
  195. package/src/demo/components/ui/DemoPanel.tsx +33 -0
  196. package/src/demo/components/ui/PanelText.module.css +18 -0
  197. package/src/demo/components/ui/PanelText.tsx +29 -0
  198. package/src/demo/components/ui/PanelTitle.module.css +18 -0
  199. package/src/demo/components/ui/PanelTitle.tsx +31 -0
  200. package/src/demo/contexts/TabbarDemoConfig.tsx +218 -0
  201. package/src/demo/demo.css +172 -0
  202. package/src/demo/hooks/useMedia.ts +41 -0
  203. package/src/demo/hooks/useShikiHighlight.ts +55 -0
  204. package/src/demo/index.tsx +293 -0
  205. package/src/demo/pages/Drawer/animations/index.tsx +22 -0
  206. package/src/demo/pages/Drawer/basics/index.tsx +17 -0
  207. package/src/demo/pages/Drawer/components/DrawerAnimations.module.css +125 -0
  208. package/src/demo/pages/Drawer/components/DrawerAnimations.tsx +118 -0
  209. package/src/demo/pages/Drawer/components/DrawerBasics.module.css +55 -0
  210. package/src/demo/pages/Drawer/components/DrawerBasics.tsx +76 -0
  211. package/src/demo/pages/Drawer/components/DrawerMenuLayout.module.css +332 -0
  212. package/src/demo/pages/Drawer/components/DrawerMenuLayout.tsx +199 -0
  213. package/src/demo/pages/Drawer/menu/index.tsx +17 -0
  214. package/src/demo/pages/FloatingPanelFrame/ResizableFloatingPanelsPreview.module.css +163 -0
  215. package/src/demo/pages/FloatingPanelFrame/ResizableFloatingPanelsPreview.tsx +234 -0
  216. package/src/demo/pages/FloatingPanelFrame/basic/index.tsx +17 -0
  217. package/src/demo/pages/FloatingPanelFrame/complex/index.tsx +26 -0
  218. package/src/demo/pages/FloatingPanelFrame/components/BasicPanel.module.css +16 -0
  219. package/src/demo/pages/FloatingPanelFrame/components/BasicPanel.tsx +24 -0
  220. package/src/demo/pages/FloatingPanelFrame/components/ComplexPanel.module.css +54 -0
  221. package/src/demo/pages/FloatingPanelFrame/components/ComplexPanel.tsx +67 -0
  222. package/src/demo/pages/FloatingPanelFrame/components/PanelWithControls.module.css +21 -0
  223. package/src/demo/pages/FloatingPanelFrame/components/PanelWithControls.tsx +41 -0
  224. package/src/demo/pages/FloatingPanelFrame/components/PanelWithMeta.module.css +5 -0
  225. package/src/demo/pages/FloatingPanelFrame/components/PanelWithMeta.tsx +43 -0
  226. package/src/demo/pages/FloatingPanelFrame/components/ScrollablePanel.module.css +11 -0
  227. package/src/demo/pages/FloatingPanelFrame/components/ScrollablePanel.tsx +42 -0
  228. package/src/demo/pages/FloatingPanelFrame/index.tsx +80 -0
  229. package/src/demo/pages/FloatingPanelFrame/scrollable/index.tsx +30 -0
  230. package/src/demo/pages/FloatingPanelFrame/with-controls/index.tsx +30 -0
  231. package/src/demo/pages/FloatingPanelFrame/with-meta/index.tsx +17 -0
  232. package/src/demo/pages/HorizontalDivider/components/PanelsWithRichContent.module.css +112 -0
  233. package/src/demo/pages/HorizontalDivider/components/PanelsWithRichContent.tsx +56 -0
  234. package/src/demo/pages/HorizontalDivider/components/SimpleResizablePanels.module.css +46 -0
  235. package/src/demo/pages/HorizontalDivider/components/SimpleResizablePanels.tsx +29 -0
  236. package/src/demo/pages/HorizontalDivider/components/ThreePanelLayout.module.css +54 -0
  237. package/src/demo/pages/HorizontalDivider/components/ThreePanelLayout.tsx +30 -0
  238. package/src/demo/pages/HorizontalDivider/index.module.css +14 -0
  239. package/src/demo/pages/HorizontalDivider/index.tsx +64 -0
  240. package/src/demo/pages/HorizontalDivider/panels-with-rich-content/index.tsx +21 -0
  241. package/src/demo/pages/HorizontalDivider/simple-resizable-panels/index.tsx +21 -0
  242. package/src/demo/pages/HorizontalDivider/three-panel-layout/index.tsx +21 -0
  243. package/src/demo/pages/PanelLayout/PanelLayoutDemo.module.css +174 -0
  244. package/src/demo/pages/PanelLayout/PanelLayoutDemo.tsx +248 -0
  245. package/src/demo/pages/PanelLayout/components/DashboardLayout.module.css +115 -0
  246. package/src/demo/pages/PanelLayout/components/DashboardLayout.tsx +124 -0
  247. package/src/demo/pages/PanelLayout/components/DraggableOverlays.module.css +101 -0
  248. package/src/demo/pages/PanelLayout/components/DraggableOverlays.tsx +122 -0
  249. package/src/demo/pages/PanelLayout/components/IDELayout.module.css +104 -0
  250. package/src/demo/pages/PanelLayout/components/IDELayout.tsx +143 -0
  251. package/src/demo/pages/PanelLayout/components/SimpleGrid.module.css +19 -0
  252. package/src/demo/pages/PanelLayout/components/SimpleGrid.tsx +62 -0
  253. package/src/demo/pages/PanelLayout/dashboard/index.tsx +22 -0
  254. package/src/demo/pages/PanelLayout/draggable-overlays/index.tsx +22 -0
  255. package/src/demo/pages/PanelLayout/ide-layout/index.tsx +22 -0
  256. package/src/demo/pages/PanelLayout/index.tsx +94 -0
  257. package/src/demo/pages/PanelLayout/simple-grid/index.tsx +22 -0
  258. package/src/demo/pages/PanelSystem/PanelSystemPreview.module.css +20 -0
  259. package/src/demo/pages/PanelSystem/PanelSystemPreview.tsx +101 -0
  260. package/src/demo/pages/PanelSystem/preview/index.tsx +18 -0
  261. package/src/demo/pages/PanelSystem/tabbar/index.tsx +129 -0
  262. package/src/demo/pages/Pivot/basics/index.tsx +17 -0
  263. package/src/demo/pages/Pivot/components/Pivot.module.css +278 -0
  264. package/src/demo/pages/Pivot/components/PivotBasics.tsx +103 -0
  265. package/src/demo/pages/Pivot/components/PivotSidebar.tsx +168 -0
  266. package/src/demo/pages/Pivot/components/PivotTabs.tsx +129 -0
  267. package/src/demo/pages/Pivot/components/PivotTransitions.tsx +120 -0
  268. package/src/demo/pages/Pivot/components/SwipePivot.module.css +114 -0
  269. package/src/demo/pages/Pivot/components/SwipePivot.tsx +193 -0
  270. package/src/demo/pages/Pivot/components/SwipeTabsPivot.module.css +203 -0
  271. package/src/demo/pages/Pivot/components/SwipeTabsPivot.tsx +289 -0
  272. package/src/demo/pages/Pivot/sidebar/index.tsx +17 -0
  273. package/src/demo/pages/Pivot/swipe/index.tsx +16 -0
  274. package/src/demo/pages/Pivot/swipe-debug/index.tsx +287 -0
  275. package/src/demo/pages/Pivot/swipe-tabs/index.tsx +15 -0
  276. package/src/demo/pages/Pivot/tabs/index.tsx +17 -0
  277. package/src/demo/pages/Pivot/transitions/index.tsx +17 -0
  278. package/src/demo/pages/ResizeHandle/both-directions/index.tsx +17 -0
  279. package/src/demo/pages/ResizeHandle/components/BothDirectionsDemo.module.css +72 -0
  280. package/src/demo/pages/ResizeHandle/components/BothDirectionsDemo.tsx +41 -0
  281. package/src/demo/pages/ResizeHandle/components/HorizontalResizeDemo.module.css +61 -0
  282. package/src/demo/pages/ResizeHandle/components/HorizontalResizeDemo.tsx +33 -0
  283. package/src/demo/pages/ResizeHandle/components/NestedPanelsDemo.module.css +83 -0
  284. package/src/demo/pages/ResizeHandle/components/NestedPanelsDemo.tsx +53 -0
  285. package/src/demo/pages/ResizeHandle/components/VerticalResizeDemo.module.css +68 -0
  286. package/src/demo/pages/ResizeHandle/components/VerticalResizeDemo.tsx +33 -0
  287. package/src/demo/pages/ResizeHandle/horizontal/index.tsx +17 -0
  288. package/src/demo/pages/ResizeHandle/index.module.css +11 -0
  289. package/src/demo/pages/ResizeHandle/index.tsx +71 -0
  290. package/src/demo/pages/ResizeHandle/nested-panels/index.tsx +17 -0
  291. package/src/demo/pages/ResizeHandle/vertical/index.tsx +17 -0
  292. package/src/demo/pages/ResponsiveLayout/adaptive-workspace/index.tsx +22 -0
  293. package/src/demo/pages/ResponsiveLayout/components/ResponsiveWorkspace.module.css +423 -0
  294. package/src/demo/pages/ResponsiveLayout/components/ResponsiveWorkspace.tsx +398 -0
  295. package/src/demo/pages/Stack/basics/index.tsx +22 -0
  296. package/src/demo/pages/Stack/components/Stack.module.css +234 -0
  297. package/src/demo/pages/Stack/components/StackBasics.tsx +217 -0
  298. package/src/demo/pages/Stack/components/StackTablet.module.css +299 -0
  299. package/src/demo/pages/Stack/components/StackTablet.tsx +401 -0
  300. package/src/demo/pages/Stack/tablet/index.tsx +22 -0
  301. package/src/demo/pages/StickyHeader/basics/index.tsx +17 -0
  302. package/src/demo/pages/StickyHeader/components/StickyHeader.module.css +219 -0
  303. package/src/demo/pages/StickyHeader/components/StickyHeaderBasics.tsx +103 -0
  304. package/src/demo/routes.tsx +193 -0
  305. package/src/demo/styles/animations.css +68 -0
  306. package/src/demo/styles/stack-themes.css +35 -0
  307. package/src/demo/utils/createPanelView.tsx +58 -0
  308. package/src/floating/index.ts +24 -0
  309. package/src/grid/index.ts +75 -0
  310. package/src/hooks/ContentCacheContext.tsx +87 -0
  311. package/src/hooks/gesture/presets.spec.ts +86 -0
  312. package/src/hooks/gesture/presets.ts +95 -0
  313. package/src/hooks/gesture/testing/createGestureSimulator.spec.ts +237 -0
  314. package/src/hooks/gesture/testing/createGestureSimulator.ts +310 -0
  315. package/src/hooks/gesture/thresholdValue.spec.ts +103 -0
  316. package/src/hooks/gesture/thresholdValue.ts +77 -0
  317. package/src/hooks/gesture/types.ts +290 -0
  318. package/src/hooks/gesture/useDirectionalLock.spec.ts +271 -0
  319. package/src/hooks/gesture/useDirectionalLock.ts +115 -0
  320. package/src/hooks/gesture/useEdgeSwipeInput.spec.ts +454 -0
  321. package/src/hooks/gesture/useEdgeSwipeInput.ts +131 -0
  322. package/src/hooks/gesture/useNativeGestureGuard.spec.ts +413 -0
  323. package/src/hooks/gesture/useNativeGestureGuard.ts +133 -0
  324. package/src/hooks/gesture/usePointerTracking.spec.ts +364 -0
  325. package/src/hooks/gesture/usePointerTracking.ts +134 -0
  326. package/src/hooks/gesture/useScrollBoundary.spec.ts +249 -0
  327. package/src/hooks/gesture/useScrollBoundary.ts +113 -0
  328. package/src/hooks/gesture/useSwipeInput.spec.ts +592 -0
  329. package/src/hooks/gesture/useSwipeInput.ts +310 -0
  330. package/src/hooks/gesture/utils.spec.ts +152 -0
  331. package/src/hooks/gesture/utils.ts +87 -0
  332. package/src/hooks/useAnimatedVisibility.spec.ts +257 -0
  333. package/src/hooks/useAnimatedVisibility.ts +146 -0
  334. package/src/hooks/useAnimationFrame.ts +200 -0
  335. package/src/hooks/useCSSMatrix.spec.ts +214 -0
  336. package/src/hooks/useCSSMatrix.ts +262 -0
  337. package/src/hooks/useClonedElementPreview.ts +28 -0
  338. package/src/hooks/useContainerScroll.ts +78 -0
  339. package/src/hooks/useContentCache.spec.tsx +232 -0
  340. package/src/hooks/useContentCache.tsx +127 -0
  341. package/src/hooks/useDocumentPointerEvents.ts +137 -0
  342. package/src/hooks/useDocumentScroll.ts +41 -0
  343. package/src/hooks/useEffectEvent.ts +40 -0
  344. package/src/hooks/useElementComponentWrapper.tsx +63 -0
  345. package/src/hooks/useIntersectionObserver.tsx +125 -0
  346. package/src/hooks/useIsomorphicLayoutEffect.ts +29 -0
  347. package/src/hooks/useResizeObserver.tsx +81 -0
  348. package/src/hooks/useScrollContainer.ts +79 -0
  349. package/src/hooks/useSnapAnimation.ts +128 -0
  350. package/src/hooks/useSwipeContentTransform.spec.ts +133 -0
  351. package/src/hooks/useSwipeContentTransform.ts +235 -0
  352. package/src/hooks/useTransitionState.ts +95 -0
  353. package/src/index.tsx +88 -0
  354. package/src/modules/grid/GridLayoutContext.tsx +57 -0
  355. package/src/modules/grid/LayerInstanceContext.tsx +56 -0
  356. package/src/modules/grid/resizeHandles.ts +157 -0
  357. package/src/modules/grid/trackUtils.ts +146 -0
  358. package/src/modules/grid/useGridPlacements.ts +143 -0
  359. package/src/modules/grid/useGridTracks.ts +156 -0
  360. package/src/modules/grid/useLayerDragHandle.ts +16 -0
  361. package/src/modules/grid/useLayerInteractions.tsx +850 -0
  362. package/src/modules/keybindings/KeybindingsProvider.tsx +111 -0
  363. package/src/modules/panels/dom/DomRegistry.tsx +94 -0
  364. package/src/modules/panels/index.ts +45 -0
  365. package/src/modules/panels/interactions/InteractionsContext.test.tsx +330 -0
  366. package/src/modules/panels/interactions/InteractionsContext.tsx +394 -0
  367. package/src/modules/panels/interactions/dnd.ts +28 -0
  368. package/src/modules/panels/keybindings/KeybindingsInstaller.tsx +15 -0
  369. package/src/modules/panels/layout/adapter.ts +124 -0
  370. package/src/modules/panels/rendering/ContentRegistry.spec.tsx +304 -0
  371. package/src/modules/panels/rendering/ContentRegistry.tsx +205 -0
  372. package/src/modules/panels/rendering/GroupContainer.tsx +65 -0
  373. package/src/modules/panels/rendering/RenderBridge.tsx +115 -0
  374. package/src/modules/panels/rendering/RenderContext.tsx +31 -0
  375. package/src/modules/panels/state/PanelSplitHandles.tsx +147 -0
  376. package/src/modules/panels/state/PanelSystemContext.splitLimits.spec.tsx +50 -0
  377. package/src/modules/panels/state/PanelSystemContext.tsx +289 -0
  378. package/src/modules/panels/state/StateContext.tsx +12 -0
  379. package/src/modules/panels/state/cleanup.ts +37 -0
  380. package/src/modules/panels/state/commands.ts +53 -0
  381. package/src/modules/panels/state/focus/Context.tsx +25 -0
  382. package/src/modules/panels/state/focus/logic.ts +57 -0
  383. package/src/modules/panels/state/groups/Context.tsx +25 -0
  384. package/src/modules/panels/state/groups/logic.ts +105 -0
  385. package/src/modules/panels/state/splitLimits.spec.ts +46 -0
  386. package/src/modules/panels/state/splitLimits.ts +90 -0
  387. package/src/modules/panels/state/state.spec.ts +49 -0
  388. package/src/modules/panels/state/tree/Context.tsx +24 -0
  389. package/src/modules/panels/state/tree/logic.spec.ts +34 -0
  390. package/src/modules/panels/state/tree/logic.ts +138 -0
  391. package/src/modules/panels/state/types.ts +142 -0
  392. package/src/modules/panels/system/PanelSystem.empty-tabbar.spec.tsx +53 -0
  393. package/src/modules/panels/system/PanelSystem.tab-click-activates.spec.tsx +44 -0
  394. package/src/modules/panels/system/PanelSystem.tab-reorder.spec.tsx +64 -0
  395. package/src/modules/panels/system/PanelSystem.tabs-no-dup.spec.tsx +57 -0
  396. package/src/modules/panels/system/PanelSystem.tsx +206 -0
  397. package/src/modules/pivot/PivotContent.spec.tsx +179 -0
  398. package/src/modules/pivot/PivotContent.tsx +77 -0
  399. package/src/modules/pivot/SwipePivotContent.debug.tmp.tsx +237 -0
  400. package/src/modules/pivot/SwipePivotContent.position.spec.tsx +167 -0
  401. package/src/modules/pivot/SwipePivotContent.spec.tsx +464 -0
  402. package/src/modules/pivot/SwipePivotContent.test.tsx +502 -0
  403. package/src/modules/pivot/SwipePivotContent.tsx +197 -0
  404. package/src/modules/pivot/SwipePivotTabBar.spec.tsx +865 -0
  405. package/src/modules/pivot/SwipePivotTabBar.tsx +523 -0
  406. package/src/modules/pivot/index.ts +8 -0
  407. package/src/modules/pivot/scaleInputState.spec.ts +210 -0
  408. package/src/modules/pivot/scaleInputState.ts +66 -0
  409. package/src/modules/pivot/types.ts +139 -0
  410. package/src/modules/pivot/usePivot.spec.ts +621 -0
  411. package/src/modules/pivot/usePivot.spec.tsx +186 -0
  412. package/src/modules/pivot/usePivot.tsx +345 -0
  413. package/src/modules/pivot/usePivotSwipeInput.spec.ts +649 -0
  414. package/src/modules/pivot/usePivotSwipeInput.ts +136 -0
  415. package/src/modules/resizer/useResizeDrag.ts +94 -0
  416. package/src/modules/stack/StackContent.spec.tsx +264 -0
  417. package/src/modules/stack/StackContent.tsx +111 -0
  418. package/src/modules/stack/SwipeStackContent.spec.tsx +1277 -0
  419. package/src/modules/stack/SwipeStackContent.tsx +356 -0
  420. package/src/modules/stack/SwipeStackOutlet.spec.tsx +252 -0
  421. package/src/modules/stack/SwipeStackOutlet.tsx +221 -0
  422. package/src/modules/stack/computeStackContentState.spec.ts +281 -0
  423. package/src/modules/stack/computeStackContentState.ts +304 -0
  424. package/src/modules/stack/computeSwipeStackTransform.spec.ts +186 -0
  425. package/src/modules/stack/computeSwipeStackTransform.ts +145 -0
  426. package/src/modules/stack/types.ts +226 -0
  427. package/src/modules/stack/useStackAnimationState.spec.ts +186 -0
  428. package/src/modules/stack/useStackAnimationState.ts +138 -0
  429. package/src/modules/stack/useStackNavigation.spec.ts +477 -0
  430. package/src/modules/stack/useStackNavigation.tsx +336 -0
  431. package/src/modules/stack/useStackSwipeInput.spec.ts +276 -0
  432. package/src/modules/stack/useStackSwipeInput.ts +139 -0
  433. package/src/modules/window/useDrawerState.ts +81 -0
  434. package/src/modules/window/useFloatingState.spec.ts +252 -0
  435. package/src/modules/window/useFloatingState.ts +141 -0
  436. package/src/panels/index.ts +119 -0
  437. package/src/pivot/index.ts +19 -0
  438. package/src/resizer/index.ts +68 -0
  439. package/src/stack/index.ts +91 -0
  440. package/src/sticky-header/StickyArea.tsx +221 -0
  441. package/src/sticky-header/index.ts +18 -0
  442. package/src/sticky-header/types.ts +68 -0
  443. package/src/types.ts +323 -0
  444. package/src/utils/CSSMatrix.ts +321 -0
  445. package/src/utils/css.ts +65 -0
  446. package/src/utils/dialogUtils.ts +43 -0
  447. package/src/utils/math.ts +18 -0
  448. package/src/utils/polyfills/createDialogPolyfill.ts +18 -0
  449. package/src/utils/typedActions.ts +103 -0
  450. package/src/vite-env.d.ts +6 -0
  451. package/src/window/index.ts +67 -0
  452. package/dist/FloatingPanelFrame-6W5OexYe.js.map +0 -1
  453. package/dist/FloatingPanelFrame-D9Cp2al1.cjs.map +0 -1
  454. package/dist/GridLayout-BzrIDrC9.js +0 -1465
  455. package/dist/GridLayout-BzrIDrC9.js.map +0 -1
  456. package/dist/GridLayout-ZrOhoLLB.cjs +0 -2
  457. package/dist/GridLayout-ZrOhoLLB.cjs.map +0 -1
  458. package/dist/sticky-header/StickyHeader.d.ts +0 -53
  459. package/dist/styles-CA2_zLZt.js +0 -52
  460. package/dist/styles-CA2_zLZt.js.map +0 -1
  461. package/dist/styles-PsqGOEJP.cjs +0 -2
  462. package/dist/styles-PsqGOEJP.cjs.map +0 -1
  463. package/dist/usePivot-BS-DGfwd.cjs +0 -2
  464. package/dist/usePivot-BS-DGfwd.cjs.map +0 -1
  465. package/dist/usePivot-BvOGxLQQ.js +0 -124
  466. package/dist/usePivot-BvOGxLQQ.js.map +0 -1
@@ -0,0 +1,413 @@
1
+ /**
2
+ * @file Tests for useNativeGestureGuard hook.
3
+ */
4
+ /* eslint-disable custom/no-as-outside-guard -- test requires overrides */
5
+ import { renderHook, act } from "@testing-library/react";
6
+ import * as React from "react";
7
+ import { useNativeGestureGuard } from "./useNativeGestureGuard.js";
8
+
9
+ describe("useNativeGestureGuard", () => {
10
+ const createRef = (rect: Partial<DOMRect> = {}): React.RefObject<HTMLDivElement> => {
11
+ const element = document.createElement("div");
12
+ const defaultRect: DOMRect = {
13
+ left: 0,
14
+ right: 300,
15
+ top: 0,
16
+ bottom: 500,
17
+ width: 300,
18
+ height: 500,
19
+ x: 0,
20
+ y: 0,
21
+ toJSON: () => ({}),
22
+ };
23
+ // Override getBoundingClientRect directly instead of using vi.spyOn
24
+ element.getBoundingClientRect = () => ({ ...defaultRect, ...rect });
25
+ return { current: element };
26
+ };
27
+
28
+ /**
29
+ * Creates a fake pointer event with preventDefault tracking.
30
+ * Uses an object to track state instead of let variable.
31
+ */
32
+ const createFakePointerEvent = (props: {
33
+ clientX: number;
34
+ clientY: number;
35
+ pointerType: string;
36
+ }) => {
37
+ const state = { preventDefaultCalled: false };
38
+ const event = {
39
+ ...props,
40
+ preventDefault: () => {
41
+ state.preventDefaultCalled = true;
42
+ },
43
+ wasDefaultPrevented: () => state.preventDefaultCalled,
44
+ };
45
+ return event as unknown as React.PointerEvent<HTMLElement> & { wasDefaultPrevented: () => boolean };
46
+ };
47
+
48
+ describe("overscroll behavior", () => {
49
+ it("applies overscroll-behavior: contain when active and preventOverscroll is true", () => {
50
+ const containerRef = createRef();
51
+ const { result } = renderHook(() =>
52
+ useNativeGestureGuard({
53
+ containerRef,
54
+ active: true,
55
+ preventOverscroll: true,
56
+ }),
57
+ );
58
+
59
+ expect(result.current.containerProps.style.overscrollBehavior).toBe("contain");
60
+ });
61
+
62
+ it("applies overscroll-behavior immediately even when not active", () => {
63
+ // Styles are applied immediately (not waiting for active) to prevent browser gestures
64
+ const containerRef = createRef();
65
+ const { result } = renderHook(() =>
66
+ useNativeGestureGuard({
67
+ containerRef,
68
+ active: false,
69
+ preventOverscroll: true,
70
+ }),
71
+ );
72
+
73
+ expect(result.current.containerProps.style.overscrollBehavior).toBe("contain");
74
+ });
75
+
76
+ it("does not apply overscroll-behavior when preventOverscroll is false", () => {
77
+ const containerRef = createRef();
78
+ const { result } = renderHook(() =>
79
+ useNativeGestureGuard({
80
+ containerRef,
81
+ active: true,
82
+ preventOverscroll: false,
83
+ }),
84
+ );
85
+
86
+ expect(result.current.containerProps.style.overscrollBehavior).toBeUndefined();
87
+ });
88
+ });
89
+
90
+ describe("edge back prevention", () => {
91
+ it("calls preventDefault for touch events in left edge zone", () => {
92
+ const containerRef = createRef({ left: 0, right: 300 });
93
+ const { result } = renderHook(() =>
94
+ useNativeGestureGuard({
95
+ containerRef,
96
+ active: true,
97
+ preventEdgeBack: true,
98
+ edgeWidth: 20,
99
+ }),
100
+ );
101
+
102
+ const mockEvent = createFakePointerEvent({
103
+ clientX: 10, // Within 20px edge zone
104
+ clientY: 100,
105
+ pointerType: "touch",
106
+ });
107
+
108
+ act(() => {
109
+ result.current.containerProps.onPointerDown?.(mockEvent);
110
+ });
111
+
112
+ expect(mockEvent.wasDefaultPrevented()).toBe(true);
113
+ });
114
+
115
+ it("does not call preventDefault for touch events outside left edge zone", () => {
116
+ const containerRef = createRef({ left: 0, right: 300 });
117
+ const { result } = renderHook(() =>
118
+ useNativeGestureGuard({
119
+ containerRef,
120
+ active: true,
121
+ preventEdgeBack: true,
122
+ edgeWidth: 20,
123
+ }),
124
+ );
125
+
126
+ const mockEvent = createFakePointerEvent({
127
+ clientX: 50, // Outside 20px edge zone
128
+ clientY: 100,
129
+ pointerType: "touch",
130
+ });
131
+
132
+ act(() => {
133
+ result.current.containerProps.onPointerDown?.(mockEvent);
134
+ });
135
+
136
+ expect(mockEvent.wasDefaultPrevented()).toBe(false);
137
+ });
138
+
139
+ it("does not call preventDefault for mouse events in edge zone", () => {
140
+ const containerRef = createRef({ left: 0, right: 300 });
141
+ const { result } = renderHook(() =>
142
+ useNativeGestureGuard({
143
+ containerRef,
144
+ active: true,
145
+ preventEdgeBack: true,
146
+ edgeWidth: 20,
147
+ }),
148
+ );
149
+
150
+ const mockEvent = createFakePointerEvent({
151
+ clientX: 10, // Within edge zone
152
+ clientY: 100,
153
+ pointerType: "mouse", // Not touch
154
+ });
155
+
156
+ act(() => {
157
+ result.current.containerProps.onPointerDown?.(mockEvent);
158
+ });
159
+
160
+ expect(mockEvent.wasDefaultPrevented()).toBe(false);
161
+ });
162
+
163
+ it("calls preventDefault even when not active (browser gesture starts immediately)", () => {
164
+ // Browser gesture recognition starts immediately on pointerdown,
165
+ // so we must preventDefault before we know if it's "our" gesture
166
+ const containerRef = createRef({ left: 0, right: 300 });
167
+ const { result } = renderHook(() =>
168
+ useNativeGestureGuard({
169
+ containerRef,
170
+ active: false,
171
+ preventEdgeBack: true,
172
+ edgeWidth: 20,
173
+ }),
174
+ );
175
+
176
+ const mockEvent = createFakePointerEvent({
177
+ clientX: 10,
178
+ clientY: 100,
179
+ pointerType: "touch",
180
+ });
181
+
182
+ act(() => {
183
+ result.current.containerProps.onPointerDown?.(mockEvent);
184
+ });
185
+
186
+ expect(mockEvent.wasDefaultPrevented()).toBe(true);
187
+ });
188
+
189
+ it("does not call preventDefault when preventEdgeBack is false", () => {
190
+ const containerRef = createRef({ left: 0, right: 300 });
191
+ const { result } = renderHook(() =>
192
+ useNativeGestureGuard({
193
+ containerRef,
194
+ active: true,
195
+ preventEdgeBack: false,
196
+ edgeWidth: 20,
197
+ }),
198
+ );
199
+
200
+ // onPointerDown should be undefined when preventEdgeBack is false
201
+ expect(result.current.containerProps.onPointerDown).toBeUndefined();
202
+ });
203
+
204
+ it("does not provide onPointerDown when preventEdgeBack is false", () => {
205
+ const containerRef = createRef();
206
+ const { result } = renderHook(() =>
207
+ useNativeGestureGuard({
208
+ containerRef,
209
+ active: true,
210
+ preventEdgeBack: false,
211
+ }),
212
+ );
213
+
214
+ expect(result.current.containerProps.onPointerDown).toBeUndefined();
215
+ });
216
+ });
217
+
218
+ describe("edge width configuration", () => {
219
+ it("respects custom edge width", () => {
220
+ const containerRef = createRef({ left: 0, right: 300 });
221
+ const { result } = renderHook(() =>
222
+ useNativeGestureGuard({
223
+ containerRef,
224
+ active: true,
225
+ preventEdgeBack: true,
226
+ edgeWidth: 50,
227
+ }),
228
+ );
229
+
230
+ const mockEventInCustomEdge = createFakePointerEvent({
231
+ clientX: 40, // Within 50px edge, but outside default 20px
232
+ clientY: 100,
233
+ pointerType: "touch",
234
+ });
235
+
236
+ act(() => {
237
+ result.current.containerProps.onPointerDown?.(mockEventInCustomEdge);
238
+ });
239
+
240
+ expect(mockEventInCustomEdge.wasDefaultPrevented()).toBe(true);
241
+ });
242
+ });
243
+
244
+ describe("iOS smooth scrolling", () => {
245
+ it("always applies WebkitOverflowScrolling: touch", () => {
246
+ const containerRef = createRef();
247
+ const { result } = renderHook(() =>
248
+ useNativeGestureGuard({
249
+ containerRef,
250
+ active: false,
251
+ }),
252
+ );
253
+
254
+ expect(result.current.containerProps.style.WebkitOverflowScrolling).toBe("touch");
255
+ });
256
+ });
257
+
258
+ describe("null container ref", () => {
259
+ it("handles null container ref gracefully", () => {
260
+ const containerRef = { current: null };
261
+ const { result } = renderHook(() =>
262
+ useNativeGestureGuard({
263
+ containerRef,
264
+ active: true,
265
+ preventEdgeBack: true,
266
+ }),
267
+ );
268
+
269
+ const mockEvent = createFakePointerEvent({
270
+ clientX: 10,
271
+ clientY: 100,
272
+ pointerType: "touch",
273
+ });
274
+
275
+ // Should not throw
276
+ act(() => {
277
+ result.current.containerProps.onPointerDown?.(mockEvent);
278
+ });
279
+
280
+ expect(mockEvent.wasDefaultPrevented()).toBe(false);
281
+ });
282
+ });
283
+
284
+ describe("html overscroll-behavior", () => {
285
+ beforeEach(() => {
286
+ // Reset html style before each test
287
+ document.documentElement.style.overscrollBehavior = "";
288
+ });
289
+
290
+ afterEach(() => {
291
+ // Clean up after each test
292
+ document.documentElement.style.overscrollBehavior = "";
293
+ });
294
+
295
+ it("applies overscroll-behavior: none to html synchronously on pointerdown in edge zone", () => {
296
+ const containerRef = createRef({ left: 0, right: 300 });
297
+ const { result } = renderHook(() =>
298
+ useNativeGestureGuard({
299
+ containerRef,
300
+ active: false,
301
+ preventEdgeBack: true,
302
+ preventOverscroll: true,
303
+ edgeWidth: 20,
304
+ }),
305
+ );
306
+
307
+ expect(document.documentElement.style.overscrollBehavior).toBe("");
308
+
309
+ const mockEvent = createFakePointerEvent({
310
+ clientX: 10,
311
+ clientY: 100,
312
+ pointerType: "touch",
313
+ });
314
+
315
+ act(() => {
316
+ result.current.containerProps.onPointerDown?.(mockEvent);
317
+ });
318
+
319
+ // Applied synchronously in onPointerDown, not waiting for useEffect
320
+ expect(document.documentElement.style.overscrollBehavior).toBe("none");
321
+ });
322
+
323
+ it("removes overscroll-behavior from html when deactivated", () => {
324
+ const containerRef = createRef({ left: 0, right: 300 });
325
+ const { result, rerender } = renderHook(
326
+ ({ active }) =>
327
+ useNativeGestureGuard({
328
+ containerRef,
329
+ active,
330
+ preventEdgeBack: true,
331
+ preventOverscroll: true,
332
+ edgeWidth: 20,
333
+ }),
334
+ { initialProps: { active: false } },
335
+ );
336
+
337
+ // Simulate pointerdown to apply style
338
+ const mockEvent = createFakePointerEvent({
339
+ clientX: 10,
340
+ clientY: 100,
341
+ pointerType: "touch",
342
+ });
343
+
344
+ act(() => {
345
+ result.current.containerProps.onPointerDown?.(mockEvent);
346
+ });
347
+
348
+ expect(document.documentElement.style.overscrollBehavior).toBe("none");
349
+
350
+ // Simulate gesture becoming active then inactive
351
+ rerender({ active: true });
352
+ rerender({ active: false });
353
+
354
+ expect(document.documentElement.style.overscrollBehavior).toBe("");
355
+ });
356
+
357
+ it("restores previous overscroll-behavior value on cleanup", () => {
358
+ document.documentElement.style.overscrollBehavior = "contain";
359
+
360
+ const containerRef = createRef({ left: 0, right: 300 });
361
+ const { result, unmount } = renderHook(() =>
362
+ useNativeGestureGuard({
363
+ containerRef,
364
+ active: false,
365
+ preventEdgeBack: true,
366
+ preventOverscroll: true,
367
+ edgeWidth: 20,
368
+ }),
369
+ );
370
+
371
+ // Simulate pointerdown to apply style
372
+ const mockEvent = createFakePointerEvent({
373
+ clientX: 10,
374
+ clientY: 100,
375
+ pointerType: "touch",
376
+ });
377
+
378
+ act(() => {
379
+ result.current.containerProps.onPointerDown?.(mockEvent);
380
+ });
381
+
382
+ expect(document.documentElement.style.overscrollBehavior).toBe("none");
383
+
384
+ unmount();
385
+ expect(document.documentElement.style.overscrollBehavior).toBe("contain");
386
+ });
387
+
388
+ it("does not apply to html when preventOverscroll is false", () => {
389
+ const containerRef = createRef({ left: 0, right: 300 });
390
+ const { result } = renderHook(() =>
391
+ useNativeGestureGuard({
392
+ containerRef,
393
+ active: false,
394
+ preventEdgeBack: true,
395
+ preventOverscroll: false,
396
+ edgeWidth: 20,
397
+ }),
398
+ );
399
+
400
+ const mockEvent = createFakePointerEvent({
401
+ clientX: 10,
402
+ clientY: 100,
403
+ pointerType: "touch",
404
+ });
405
+
406
+ act(() => {
407
+ result.current.containerProps.onPointerDown?.(mockEvent);
408
+ });
409
+
410
+ expect(document.documentElement.style.overscrollBehavior).toBe("");
411
+ });
412
+ });
413
+ });
@@ -0,0 +1,133 @@
1
+ /**
2
+ * @file Hook for preventing conflicts with native OS gestures.
3
+ *
4
+ * This hook helps prevent conflicts with:
5
+ * - iOS/macOS edge swipe back navigation
6
+ * - Overscroll bounce effects
7
+ *
8
+ * It applies appropriate CSS properties and event handlers to the container.
9
+ */
10
+ import * as React from "react";
11
+ import type {
12
+ UseNativeGestureGuardOptions,
13
+ UseNativeGestureGuardResult,
14
+ } from "./types.js";
15
+ import { DEFAULT_EDGE_WIDTH } from "./types.js";
16
+
17
+ /**
18
+ * Check if a pointer event is within the left edge zone.
19
+ */
20
+ const isInLeftEdge = (clientX: number, container: HTMLElement, edgeWidth: number): boolean => {
21
+ const rect = container.getBoundingClientRect();
22
+ return clientX >= rect.left && clientX <= rect.left + edgeWidth;
23
+ };
24
+
25
+ /**
26
+ * Hook for preventing conflicts with native OS gestures.
27
+ *
28
+ * When active, this hook:
29
+ * - Prevents iOS/macOS edge back gesture by capturing pointerdown events in the edge zone
30
+ * - Prevents overscroll bounce effect using CSS overscroll-behavior
31
+ * - Dynamically applies overscroll-behavior: none to html element during gesture
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * const containerRef = useRef<HTMLDivElement>(null);
36
+ * const { containerProps } = useNativeGestureGuard({
37
+ * containerRef,
38
+ * active: isSwipeActive,
39
+ * preventEdgeBack: true,
40
+ * preventOverscroll: true,
41
+ * });
42
+ *
43
+ * return <div ref={containerRef} {...containerProps}>{children}</div>;
44
+ * ```
45
+ */
46
+ export function useNativeGestureGuard(options: UseNativeGestureGuardOptions): UseNativeGestureGuardResult {
47
+ const {
48
+ containerRef,
49
+ active,
50
+ preventEdgeBack = true,
51
+ preventOverscroll = true,
52
+ edgeWidth = DEFAULT_EDGE_WIDTH,
53
+ } = options;
54
+
55
+ // Track previous html overscroll-behavior value for restoration
56
+ const previousHtmlOverscrollRef = React.useRef<string | null>(null);
57
+
58
+ // Apply overscroll-behavior to html synchronously (called from onPointerDown)
59
+ const applyHtmlOverscroll = React.useCallback(() => {
60
+ if (!preventOverscroll) return;
61
+
62
+ const html = document.documentElement;
63
+ if (previousHtmlOverscrollRef.current === null) {
64
+ previousHtmlOverscrollRef.current = html.style.overscrollBehavior;
65
+ }
66
+ html.style.overscrollBehavior = "none";
67
+ }, [preventOverscroll]);
68
+
69
+ // Remove overscroll-behavior from html when gesture ends
70
+ React.useEffect(() => {
71
+ if (active || !preventOverscroll) {
72
+ return;
73
+ }
74
+
75
+ // Cleanup: restore previous value when deactivated
76
+ if (previousHtmlOverscrollRef.current !== null) {
77
+ document.documentElement.style.overscrollBehavior = previousHtmlOverscrollRef.current;
78
+ previousHtmlOverscrollRef.current = null;
79
+ }
80
+ }, [active, preventOverscroll]);
81
+
82
+ // Cleanup on unmount
83
+ React.useEffect(() => {
84
+ return () => {
85
+ if (previousHtmlOverscrollRef.current !== null) {
86
+ document.documentElement.style.overscrollBehavior = previousHtmlOverscrollRef.current;
87
+ previousHtmlOverscrollRef.current = null;
88
+ }
89
+ };
90
+ }, []);
91
+
92
+ // Pointer down handler that prevents edge back gesture
93
+ // Note: This must run on EVERY pointerdown in edge zone, not just when active,
94
+ // because browser gesture recognition starts immediately on first touch.
95
+ const onPointerDown = React.useCallback((event: React.PointerEvent) => {
96
+ if (!preventEdgeBack) {
97
+ return;
98
+ }
99
+
100
+ const container = containerRef.current;
101
+ if (!container) {
102
+ return;
103
+ }
104
+
105
+ // Prevent for touch events in the left edge zone
106
+ // This must happen immediately, before we know if it's "our" gesture
107
+ if (event.pointerType === "touch" && isInLeftEdge(event.clientX, container, edgeWidth)) {
108
+ // Apply html overscroll-behavior synchronously before browser can recognize gesture
109
+ applyHtmlOverscroll();
110
+ // Prevent the browser from handling this as a back gesture
111
+ event.preventDefault();
112
+ }
113
+ }, [preventEdgeBack, containerRef, edgeWidth, applyHtmlOverscroll]);
114
+
115
+ // Build container props
116
+ // Styles are applied immediately (not waiting for active) to prevent browser gestures
117
+ const containerProps = React.useMemo(() => {
118
+ const style: React.CSSProperties = {
119
+ // Always apply to prevent browser navigation gestures
120
+ overscrollBehavior: preventOverscroll ? "contain" : undefined,
121
+ WebkitOverflowScrolling: "touch",
122
+ };
123
+
124
+ return {
125
+ onPointerDown: preventEdgeBack ? onPointerDown : undefined,
126
+ style,
127
+ };
128
+ }, [preventOverscroll, preventEdgeBack, onPointerDown]);
129
+
130
+ return {
131
+ containerProps,
132
+ };
133
+ }