react-panel-layout 0.5.2 → 0.6.1

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 (541) hide show
  1. package/dist/{FloatingPanelFrame-lLg-Lpg7.js → FloatingPanelFrame-3eU9AwPo.js} +11 -11
  2. package/dist/{FloatingPanelFrame-lLg-Lpg7.js.map → FloatingPanelFrame-3eU9AwPo.js.map} +1 -1
  3. package/dist/{FloatingPanelFrame-D9Cp2al1.cjs → FloatingPanelFrame-CEmXDvUA.cjs} +2 -2
  4. package/dist/{FloatingPanelFrame-D9Cp2al1.cjs.map → FloatingPanelFrame-CEmXDvUA.cjs.map} +1 -1
  5. package/dist/FloatingWindow-CUXnEtrb.js +827 -0
  6. package/dist/FloatingWindow-CUXnEtrb.js.map +1 -0
  7. package/dist/FloatingWindow-DMwyK0eK.cjs +2 -0
  8. package/dist/FloatingWindow-DMwyK0eK.cjs.map +1 -0
  9. package/dist/GridLayout-DKTg_N61.cjs +2 -0
  10. package/dist/GridLayout-DKTg_N61.cjs.map +1 -0
  11. package/dist/GridLayout-UWNxXw77.js +926 -0
  12. package/dist/GridLayout-UWNxXw77.js.map +1 -0
  13. package/dist/HorizontalDivider-DdxzfV0l.js +30 -0
  14. package/dist/HorizontalDivider-DdxzfV0l.js.map +1 -0
  15. package/dist/HorizontalDivider-_pgV4Mcv.cjs +2 -0
  16. package/dist/HorizontalDivider-_pgV4Mcv.cjs.map +1 -0
  17. package/dist/PanelSystem-BqUzNtf2.js +1946 -0
  18. package/dist/PanelSystem-BqUzNtf2.js.map +1 -0
  19. package/dist/PanelSystem-D603LKKv.cjs +3 -0
  20. package/dist/PanelSystem-D603LKKv.cjs.map +1 -0
  21. package/dist/ResizeHandle-CBcAS918.cjs +2 -0
  22. package/dist/ResizeHandle-CBcAS918.cjs.map +1 -0
  23. package/dist/ResizeHandle-CXjc1meV.js +119 -0
  24. package/dist/ResizeHandle-CXjc1meV.js.map +1 -0
  25. package/dist/SwipePivotTabBar-DWrCuwEI.js +411 -0
  26. package/dist/SwipePivotTabBar-DWrCuwEI.js.map +1 -0
  27. package/dist/SwipePivotTabBar-fjjXkpj7.cjs +2 -0
  28. package/dist/SwipePivotTabBar-fjjXkpj7.cjs.map +1 -0
  29. package/dist/components/gesture/SwipeSafeZone.d.ts +40 -0
  30. package/dist/components/window/Drawer.d.ts +3 -1
  31. package/dist/components/window/DrawerLayers.d.ts +1 -1
  32. package/dist/components/window/drawerStyles.d.ts +69 -0
  33. package/dist/components/window/drawerSwipeConfig.d.ts +29 -0
  34. package/dist/components/window/useDrawerSwipeTransform.d.ts +23 -0
  35. package/dist/config.cjs +1 -1
  36. package/dist/config.cjs.map +1 -1
  37. package/dist/config.js +11 -9
  38. package/dist/config.js.map +1 -1
  39. package/dist/constants/styles.d.ts +35 -4
  40. package/dist/dialog/index.d.ts +69 -0
  41. package/dist/floating.cjs +1 -1
  42. package/dist/floating.js +1 -1
  43. package/dist/grid/index.d.ts +58 -0
  44. package/dist/grid.cjs +2 -0
  45. package/dist/grid.cjs.map +1 -0
  46. package/dist/grid.js +13 -0
  47. package/dist/grid.js.map +1 -0
  48. package/dist/hooks/gesture/presets.d.ts +33 -0
  49. package/dist/hooks/gesture/testing/createGestureSimulator.d.ts +117 -0
  50. package/dist/hooks/gesture/thresholdValue.d.ts +44 -0
  51. package/dist/hooks/gesture/types.d.ts +297 -0
  52. package/dist/hooks/gesture/useDirectionalLock.d.ts +20 -0
  53. package/dist/hooks/gesture/useEdgeSwipeInput.d.ts +23 -0
  54. package/dist/hooks/gesture/useNativeGestureGuard.d.ts +23 -0
  55. package/dist/hooks/gesture/usePointerTracking.d.ts +22 -0
  56. package/dist/hooks/gesture/useScrollBoundary.d.ts +23 -0
  57. package/dist/hooks/gesture/useSwipeInput.d.ts +5 -0
  58. package/dist/hooks/gesture/utils.d.ts +59 -0
  59. package/dist/hooks/useAnimatedVisibility.d.ts +58 -0
  60. package/dist/hooks/useAnimationFrame.d.ts +86 -0
  61. package/dist/hooks/useOperationContinuity.d.ts +64 -0
  62. package/dist/hooks/useResizeObserver.d.ts +33 -1
  63. package/dist/hooks/useSharedElementTransition.d.ts +112 -0
  64. package/dist/hooks/useSnapAnimation.d.ts +54 -0
  65. package/dist/hooks/useSwipeContentTransform.d.ts +86 -0
  66. package/dist/index.cjs +1 -2
  67. package/dist/index.cjs.map +1 -1
  68. package/dist/index.d.ts +0 -1
  69. package/dist/index.js +25 -2006
  70. package/dist/index.js.map +1 -1
  71. package/dist/modules/dialog/AlertDialog.d.ts +9 -0
  72. package/dist/modules/dialog/DialogContainer.d.ts +37 -0
  73. package/dist/modules/dialog/Modal.d.ts +26 -0
  74. package/dist/modules/dialog/SwipeDialogContainer.d.ts +16 -0
  75. package/dist/modules/dialog/dialogAnimationUtils.d.ts +113 -0
  76. package/dist/modules/dialog/types.d.ts +183 -0
  77. package/dist/modules/dialog/useDialog.d.ts +39 -0
  78. package/dist/modules/dialog/useDialogContainer.d.ts +47 -0
  79. package/dist/modules/dialog/useDialogSwipeInput.d.ts +70 -0
  80. package/dist/modules/dialog/useDialogTransform.d.ts +82 -0
  81. package/dist/modules/drawer/types.d.ts +74 -0
  82. package/dist/modules/drawer/useDrawerSwipeInput.d.ts +24 -0
  83. package/dist/modules/pivot/PivotContent.d.ts +1 -1
  84. package/dist/modules/pivot/SwipePivotContent.d.ts +39 -0
  85. package/dist/modules/pivot/SwipePivotContent.debug.tmp.d.ts +25 -0
  86. package/dist/modules/pivot/SwipePivotContent.test.d.ts +1 -0
  87. package/dist/modules/pivot/SwipePivotTabBar.d.ts +92 -0
  88. package/dist/modules/pivot/index.d.ts +3 -0
  89. package/dist/modules/pivot/scaleInputState.d.ts +37 -0
  90. package/dist/modules/pivot/types.d.ts +67 -2
  91. package/dist/modules/pivot/usePivotSwipeInput.d.ts +68 -0
  92. package/dist/modules/stack/StackContent.d.ts +15 -0
  93. package/dist/modules/stack/SwipeStackContent.d.ts +66 -0
  94. package/dist/modules/stack/SwipeStackOutlet.d.ts +80 -0
  95. package/dist/modules/stack/computeStackContentState.d.ts +99 -0
  96. package/dist/modules/stack/computeSwipeStackTransform.d.ts +76 -0
  97. package/dist/modules/stack/types.d.ts +194 -0
  98. package/dist/modules/stack/useStackAnimationState.d.ts +32 -0
  99. package/dist/modules/stack/useStackNavigation.d.ts +23 -0
  100. package/dist/modules/stack/useStackSwipeInput.d.ts +27 -0
  101. package/dist/panels/index.d.ts +67 -0
  102. package/dist/panels.cjs +2 -0
  103. package/dist/panels.cjs.map +1 -0
  104. package/dist/panels.js +28 -0
  105. package/dist/panels.js.map +1 -0
  106. package/dist/pivot/index.d.ts +3 -0
  107. package/dist/pivot.cjs +1 -1
  108. package/dist/pivot.cjs.map +1 -1
  109. package/dist/pivot.js +20 -2
  110. package/dist/pivot.js.map +1 -1
  111. package/dist/resizer/index.d.ts +57 -0
  112. package/dist/resizer.cjs +2 -0
  113. package/dist/resizer.cjs.map +1 -0
  114. package/dist/resizer.js +8 -0
  115. package/dist/resizer.js.map +1 -0
  116. package/dist/stack/index.d.ts +72 -0
  117. package/dist/stack.cjs +2 -0
  118. package/dist/stack.cjs.map +1 -0
  119. package/dist/stack.js +721 -0
  120. package/dist/stack.js.map +1 -0
  121. package/dist/sticky-header/StickyArea.d.ts +38 -0
  122. package/dist/sticky-header/calculateStickyMetrics.d.ts +28 -0
  123. package/dist/sticky-header/index.d.ts +4 -4
  124. package/dist/sticky-header/types.d.ts +35 -22
  125. package/dist/sticky-header.cjs +1 -1
  126. package/dist/sticky-header.cjs.map +1 -1
  127. package/dist/sticky-header.js +73 -174
  128. package/dist/sticky-header.js.map +1 -1
  129. package/dist/styles-NkjuMOVS.js +57 -0
  130. package/dist/styles-NkjuMOVS.js.map +1 -0
  131. package/dist/styles-qf6ptVLD.cjs +2 -0
  132. package/dist/styles-qf6ptVLD.cjs.map +1 -0
  133. package/dist/types.d.ts +16 -0
  134. package/dist/useContentCache-CO3LYNmz.js +24 -0
  135. package/dist/useContentCache-CO3LYNmz.js.map +1 -0
  136. package/dist/useContentCache-DqXtLrLs.cjs +2 -0
  137. package/dist/useContentCache-DqXtLrLs.cjs.map +1 -0
  138. package/dist/useDocumentPointerEvents-DXxw3qWj.js +54 -0
  139. package/dist/useDocumentPointerEvents-DXxw3qWj.js.map +1 -0
  140. package/dist/useDocumentPointerEvents-DxDSOtip.cjs +2 -0
  141. package/dist/useDocumentPointerEvents-DxDSOtip.cjs.map +1 -0
  142. package/dist/useFloatingState-C4kRaW_R.cjs +2 -0
  143. package/dist/useFloatingState-C4kRaW_R.cjs.map +1 -0
  144. package/dist/useFloatingState-tEfA_wbc.js +74 -0
  145. package/dist/useFloatingState-tEfA_wbc.js.map +1 -0
  146. package/dist/useNativeGestureGuard-C7TSqEkr.cjs +2 -0
  147. package/dist/useNativeGestureGuard-C7TSqEkr.cjs.map +1 -0
  148. package/dist/useNativeGestureGuard-CGYo6O0r.js +347 -0
  149. package/dist/useNativeGestureGuard-CGYo6O0r.js.map +1 -0
  150. package/dist/window/index.d.ts +63 -0
  151. package/dist/window.cjs +2 -0
  152. package/dist/window.cjs.map +1 -0
  153. package/dist/window.js +160 -0
  154. package/dist/window.js.map +1 -0
  155. package/docs/design-tokens.md +405 -0
  156. package/package.json +34 -4
  157. package/src/PanelSystemContext.tsx +88 -0
  158. package/src/components/gesture/SwipeSafeZone.tsx +69 -0
  159. package/src/components/grid/GridLayerList.tsx +172 -0
  160. package/src/components/grid/GridLayerResizeHandles.tsx +145 -0
  161. package/src/components/grid/GridLayout.spec.tsx +743 -0
  162. package/src/components/grid/GridLayout.tsx +130 -0
  163. package/src/components/grid/GridTrackResizeHandle.tsx +87 -0
  164. package/src/components/paneling/FloatingPanelFrame.tsx +203 -0
  165. package/src/components/panels/DropSuggestOverlay.tsx +131 -0
  166. package/src/components/panels/PanelGroupView.tsx +112 -0
  167. package/src/components/pivot/PivotLayer.tsx +27 -0
  168. package/src/components/resizer/HorizontalDivider.tsx +52 -0
  169. package/src/components/resizer/ResizeHandle.tsx +118 -0
  170. package/src/components/tabs/TabBar.tsx +223 -0
  171. package/src/components/tabs/TabBarTab.tsx +133 -0
  172. package/src/components/tabs/TabDragOverlay.tsx +92 -0
  173. package/src/components/window/DialogOverlay.tsx +180 -0
  174. package/src/components/window/Drawer.tsx +369 -0
  175. package/src/components/window/DrawerLayers.tsx +68 -0
  176. package/src/components/window/FloatingWindow.tsx +95 -0
  177. package/src/components/window/PopupLayerPortal.tsx +218 -0
  178. package/src/components/window/drawerStyles.spec.ts +263 -0
  179. package/src/components/window/drawerStyles.ts +228 -0
  180. package/src/components/window/drawerSwipeConfig.spec.ts +131 -0
  181. package/src/components/window/drawerSwipeConfig.ts +112 -0
  182. package/src/components/window/useDrawerSwipeTransform.spec.ts +234 -0
  183. package/src/components/window/useDrawerSwipeTransform.ts +129 -0
  184. package/src/config/PanelContentDeclaration.tsx +427 -0
  185. package/src/config/index.tsx +52 -0
  186. package/src/config/panelJsx.spec.tsx +54 -0
  187. package/src/config/panelJsxConfig.spec.tsx +54 -0
  188. package/src/config/panelJsxDrawer.spec.tsx +33 -0
  189. package/src/config/panelRouter.spec.ts +68 -0
  190. package/src/config/panelRouter.tsx +155 -0
  191. package/src/constants/styles.ts +280 -0
  192. package/src/demo/Layout.module.css +258 -0
  193. package/src/demo/Layout.tsx +176 -0
  194. package/src/demo/components/CodeBlock.module.css +54 -0
  195. package/src/demo/components/CodeBlock.tsx +34 -0
  196. package/src/demo/components/CodePreview.module.css +37 -0
  197. package/src/demo/components/CodePreview.tsx +31 -0
  198. package/src/demo/components/DataPreview.module.css +177 -0
  199. package/src/demo/components/DataPreview.tsx +115 -0
  200. package/src/demo/components/Story.module.css +68 -0
  201. package/src/demo/components/Story.tsx +54 -0
  202. package/src/demo/components/layout/CodePanel.module.css +183 -0
  203. package/src/demo/components/layout/CodePanel.tsx +149 -0
  204. package/src/demo/components/layout/DemoPage.module.css +60 -0
  205. package/src/demo/components/layout/DemoPage.tsx +56 -0
  206. package/src/demo/components/layout/SingleSamplePage.module.css +11 -0
  207. package/src/demo/components/layout/SingleSamplePage.tsx +35 -0
  208. package/src/demo/components/layout/SplitDemoLayout.module.css +107 -0
  209. package/src/demo/components/layout/SplitDemoLayout.tsx +218 -0
  210. package/src/demo/components/layout/index.ts +11 -0
  211. package/src/demo/components/tab-styles/ChromeTabBar.module.css +75 -0
  212. package/src/demo/components/tab-styles/ChromeTabBar.tsx +111 -0
  213. package/src/demo/components/tab-styles/GitHubTabBar.module.css +81 -0
  214. package/src/demo/components/tab-styles/GitHubTabBar.tsx +109 -0
  215. package/src/demo/components/tab-styles/VSCodeTabBar.module.css +78 -0
  216. package/src/demo/components/tab-styles/VSCodeTabBar.tsx +109 -0
  217. package/src/demo/components/tab-styles/index.ts +6 -0
  218. package/src/demo/components/ui/DemoButton.module.css +63 -0
  219. package/src/demo/components/ui/DemoButton.tsx +32 -0
  220. package/src/demo/components/ui/DemoCard.module.css +15 -0
  221. package/src/demo/components/ui/DemoCard.tsx +30 -0
  222. package/src/demo/components/ui/DemoContainer.module.css +17 -0
  223. package/src/demo/components/ui/DemoContainer.tsx +30 -0
  224. package/src/demo/components/ui/DemoPanel.module.css +23 -0
  225. package/src/demo/components/ui/DemoPanel.tsx +33 -0
  226. package/src/demo/components/ui/PanelText.module.css +18 -0
  227. package/src/demo/components/ui/PanelText.tsx +29 -0
  228. package/src/demo/components/ui/PanelTitle.module.css +18 -0
  229. package/src/demo/components/ui/PanelTitle.tsx +31 -0
  230. package/src/demo/contexts/TabbarDemoConfig.tsx +218 -0
  231. package/src/demo/demo.css +172 -0
  232. package/src/demo/hooks/useMedia.ts +41 -0
  233. package/src/demo/hooks/useShikiHighlight.ts +55 -0
  234. package/src/demo/index.tsx +293 -0
  235. package/src/demo/pages/Dialog/alerts/index.tsx +22 -0
  236. package/src/demo/pages/Dialog/card/index.tsx +22 -0
  237. package/src/demo/pages/Dialog/components/AlertDialogDemo.tsx +124 -0
  238. package/src/demo/pages/Dialog/components/CardExpandDemo.module.css +243 -0
  239. package/src/demo/pages/Dialog/components/CardExpandDemo.tsx +204 -0
  240. package/src/demo/pages/Dialog/components/CustomAlertDialogDemo.tsx +219 -0
  241. package/src/demo/pages/Dialog/components/DialogDemos.module.css +77 -0
  242. package/src/demo/pages/Dialog/components/ModalBasics.tsx +45 -0
  243. package/src/demo/pages/Dialog/components/SwipeDialogDemo.module.css +77 -0
  244. package/src/demo/pages/Dialog/components/SwipeDialogDemo.tsx +181 -0
  245. package/src/demo/pages/Dialog/custom-alert/index.tsx +22 -0
  246. package/src/demo/pages/Dialog/modal/index.tsx +17 -0
  247. package/src/demo/pages/Dialog/swipe/index.tsx +22 -0
  248. package/src/demo/pages/Drawer/animations/index.tsx +22 -0
  249. package/src/demo/pages/Drawer/basics/index.tsx +17 -0
  250. package/src/demo/pages/Drawer/components/DrawerAnimations.module.css +125 -0
  251. package/src/demo/pages/Drawer/components/DrawerAnimations.tsx +118 -0
  252. package/src/demo/pages/Drawer/components/DrawerBasics.module.css +55 -0
  253. package/src/demo/pages/Drawer/components/DrawerBasics.tsx +76 -0
  254. package/src/demo/pages/Drawer/components/DrawerMenuLayout.module.css +332 -0
  255. package/src/demo/pages/Drawer/components/DrawerMenuLayout.tsx +199 -0
  256. package/src/demo/pages/Drawer/components/DrawerSwipe.module.css +316 -0
  257. package/src/demo/pages/Drawer/components/DrawerSwipe.tsx +178 -0
  258. package/src/demo/pages/Drawer/menu/index.tsx +17 -0
  259. package/src/demo/pages/Drawer/swipe/index.tsx +17 -0
  260. package/src/demo/pages/FloatingPanelFrame/ResizableFloatingPanelsPreview.module.css +163 -0
  261. package/src/demo/pages/FloatingPanelFrame/ResizableFloatingPanelsPreview.tsx +234 -0
  262. package/src/demo/pages/FloatingPanelFrame/basic/index.tsx +17 -0
  263. package/src/demo/pages/FloatingPanelFrame/complex/index.tsx +26 -0
  264. package/src/demo/pages/FloatingPanelFrame/components/BasicPanel.module.css +16 -0
  265. package/src/demo/pages/FloatingPanelFrame/components/BasicPanel.tsx +24 -0
  266. package/src/demo/pages/FloatingPanelFrame/components/ComplexPanel.module.css +54 -0
  267. package/src/demo/pages/FloatingPanelFrame/components/ComplexPanel.tsx +67 -0
  268. package/src/demo/pages/FloatingPanelFrame/components/PanelWithControls.module.css +21 -0
  269. package/src/demo/pages/FloatingPanelFrame/components/PanelWithControls.tsx +41 -0
  270. package/src/demo/pages/FloatingPanelFrame/components/PanelWithMeta.module.css +5 -0
  271. package/src/demo/pages/FloatingPanelFrame/components/PanelWithMeta.tsx +43 -0
  272. package/src/demo/pages/FloatingPanelFrame/components/ScrollablePanel.module.css +11 -0
  273. package/src/demo/pages/FloatingPanelFrame/components/ScrollablePanel.tsx +42 -0
  274. package/src/demo/pages/FloatingPanelFrame/index.tsx +80 -0
  275. package/src/demo/pages/FloatingPanelFrame/scrollable/index.tsx +30 -0
  276. package/src/demo/pages/FloatingPanelFrame/with-controls/index.tsx +30 -0
  277. package/src/demo/pages/FloatingPanelFrame/with-meta/index.tsx +17 -0
  278. package/src/demo/pages/HorizontalDivider/components/PanelsWithRichContent.module.css +112 -0
  279. package/src/demo/pages/HorizontalDivider/components/PanelsWithRichContent.tsx +56 -0
  280. package/src/demo/pages/HorizontalDivider/components/SimpleResizablePanels.module.css +46 -0
  281. package/src/demo/pages/HorizontalDivider/components/SimpleResizablePanels.tsx +29 -0
  282. package/src/demo/pages/HorizontalDivider/components/ThreePanelLayout.module.css +54 -0
  283. package/src/demo/pages/HorizontalDivider/components/ThreePanelLayout.tsx +30 -0
  284. package/src/demo/pages/HorizontalDivider/index.module.css +14 -0
  285. package/src/demo/pages/HorizontalDivider/index.tsx +64 -0
  286. package/src/demo/pages/HorizontalDivider/panels-with-rich-content/index.tsx +21 -0
  287. package/src/demo/pages/HorizontalDivider/simple-resizable-panels/index.tsx +21 -0
  288. package/src/demo/pages/HorizontalDivider/three-panel-layout/index.tsx +21 -0
  289. package/src/demo/pages/PanelLayout/PanelLayoutDemo.module.css +174 -0
  290. package/src/demo/pages/PanelLayout/PanelLayoutDemo.tsx +248 -0
  291. package/src/demo/pages/PanelLayout/components/DashboardLayout.module.css +115 -0
  292. package/src/demo/pages/PanelLayout/components/DashboardLayout.tsx +124 -0
  293. package/src/demo/pages/PanelLayout/components/DraggableOverlays.module.css +101 -0
  294. package/src/demo/pages/PanelLayout/components/DraggableOverlays.tsx +122 -0
  295. package/src/demo/pages/PanelLayout/components/IDELayout.module.css +104 -0
  296. package/src/demo/pages/PanelLayout/components/IDELayout.tsx +143 -0
  297. package/src/demo/pages/PanelLayout/components/SimpleGrid.module.css +19 -0
  298. package/src/demo/pages/PanelLayout/components/SimpleGrid.tsx +62 -0
  299. package/src/demo/pages/PanelLayout/dashboard/index.tsx +22 -0
  300. package/src/demo/pages/PanelLayout/draggable-overlays/index.tsx +22 -0
  301. package/src/demo/pages/PanelLayout/ide-layout/index.tsx +22 -0
  302. package/src/demo/pages/PanelLayout/index.tsx +94 -0
  303. package/src/demo/pages/PanelLayout/simple-grid/index.tsx +22 -0
  304. package/src/demo/pages/PanelSystem/PanelSystemPreview.module.css +20 -0
  305. package/src/demo/pages/PanelSystem/PanelSystemPreview.tsx +101 -0
  306. package/src/demo/pages/PanelSystem/preview/index.tsx +18 -0
  307. package/src/demo/pages/PanelSystem/tabbar/index.tsx +129 -0
  308. package/src/demo/pages/Pivot/basics/index.tsx +17 -0
  309. package/src/demo/pages/Pivot/components/Pivot.module.css +278 -0
  310. package/src/demo/pages/Pivot/components/PivotBasics.tsx +103 -0
  311. package/src/demo/pages/Pivot/components/PivotSidebar.tsx +168 -0
  312. package/src/demo/pages/Pivot/components/PivotTabs.tsx +129 -0
  313. package/src/demo/pages/Pivot/components/PivotTransitions.tsx +120 -0
  314. package/src/demo/pages/Pivot/components/SwipePivot.module.css +114 -0
  315. package/src/demo/pages/Pivot/components/SwipePivot.tsx +193 -0
  316. package/src/demo/pages/Pivot/components/SwipeTabsPivot.module.css +203 -0
  317. package/src/demo/pages/Pivot/components/SwipeTabsPivot.tsx +320 -0
  318. package/src/demo/pages/Pivot/sidebar/index.tsx +17 -0
  319. package/src/demo/pages/Pivot/swipe/index.tsx +16 -0
  320. package/src/demo/pages/Pivot/swipe-debug/index.tsx +287 -0
  321. package/src/demo/pages/Pivot/swipe-tabs/index.tsx +15 -0
  322. package/src/demo/pages/Pivot/tabs/index.tsx +17 -0
  323. package/src/demo/pages/Pivot/transitions/index.tsx +17 -0
  324. package/src/demo/pages/ResizeHandle/both-directions/index.tsx +17 -0
  325. package/src/demo/pages/ResizeHandle/components/BothDirectionsDemo.module.css +72 -0
  326. package/src/demo/pages/ResizeHandle/components/BothDirectionsDemo.tsx +41 -0
  327. package/src/demo/pages/ResizeHandle/components/HorizontalResizeDemo.module.css +61 -0
  328. package/src/demo/pages/ResizeHandle/components/HorizontalResizeDemo.tsx +33 -0
  329. package/src/demo/pages/ResizeHandle/components/NestedPanelsDemo.module.css +83 -0
  330. package/src/demo/pages/ResizeHandle/components/NestedPanelsDemo.tsx +53 -0
  331. package/src/demo/pages/ResizeHandle/components/VerticalResizeDemo.module.css +68 -0
  332. package/src/demo/pages/ResizeHandle/components/VerticalResizeDemo.tsx +33 -0
  333. package/src/demo/pages/ResizeHandle/horizontal/index.tsx +17 -0
  334. package/src/demo/pages/ResizeHandle/index.module.css +11 -0
  335. package/src/demo/pages/ResizeHandle/index.tsx +71 -0
  336. package/src/demo/pages/ResizeHandle/nested-panels/index.tsx +17 -0
  337. package/src/demo/pages/ResizeHandle/vertical/index.tsx +17 -0
  338. package/src/demo/pages/ResponsiveLayout/adaptive-workspace/index.tsx +22 -0
  339. package/src/demo/pages/ResponsiveLayout/components/ResponsiveWorkspace.module.css +423 -0
  340. package/src/demo/pages/ResponsiveLayout/components/ResponsiveWorkspace.tsx +398 -0
  341. package/src/demo/pages/Stack/basics/index.tsx +22 -0
  342. package/src/demo/pages/Stack/components/Stack.module.css +234 -0
  343. package/src/demo/pages/Stack/components/StackBasics.spec.tsx +152 -0
  344. package/src/demo/pages/Stack/components/StackBasics.tsx +301 -0
  345. package/src/demo/pages/Stack/components/StackTablet.module.css +299 -0
  346. package/src/demo/pages/Stack/components/StackTablet.spec.tsx +120 -0
  347. package/src/demo/pages/Stack/components/StackTablet.tsx +422 -0
  348. package/src/demo/pages/Stack/tablet/index.tsx +22 -0
  349. package/src/demo/pages/StickyHeader/basics/index.tsx +17 -0
  350. package/src/demo/pages/StickyHeader/components/StickyHeader.module.css +219 -0
  351. package/src/demo/pages/StickyHeader/components/StickyHeaderBasics.tsx +103 -0
  352. package/src/demo/routes.tsx +214 -0
  353. package/src/demo/styles/animations.css +68 -0
  354. package/src/demo/styles/stack-themes.css +35 -0
  355. package/src/demo/utils/createPanelView.tsx +58 -0
  356. package/src/dialog/index.ts +85 -0
  357. package/src/floating/index.ts +24 -0
  358. package/src/grid/index.ts +75 -0
  359. package/src/hooks/ContentCacheContext.tsx +87 -0
  360. package/src/hooks/gesture/presets.spec.ts +86 -0
  361. package/src/hooks/gesture/presets.ts +95 -0
  362. package/src/hooks/gesture/testing/createGestureSimulator.spec.ts +241 -0
  363. package/src/hooks/gesture/testing/createGestureSimulator.ts +385 -0
  364. package/src/hooks/gesture/thresholdValue.spec.ts +103 -0
  365. package/src/hooks/gesture/thresholdValue.ts +77 -0
  366. package/src/hooks/gesture/types.ts +367 -0
  367. package/src/hooks/gesture/useDirectionalLock.spec.ts +271 -0
  368. package/src/hooks/gesture/useDirectionalLock.ts +115 -0
  369. package/src/hooks/gesture/useEdgeSwipeInput.spec.ts +462 -0
  370. package/src/hooks/gesture/useEdgeSwipeInput.ts +131 -0
  371. package/src/hooks/gesture/useNativeGestureGuard.spec.ts +473 -0
  372. package/src/hooks/gesture/useNativeGestureGuard.ts +135 -0
  373. package/src/hooks/gesture/usePointerTracking.spec.ts +364 -0
  374. package/src/hooks/gesture/usePointerTracking.ts +134 -0
  375. package/src/hooks/gesture/useScrollBoundary.spec.ts +249 -0
  376. package/src/hooks/gesture/useScrollBoundary.ts +113 -0
  377. package/src/hooks/gesture/useSwipeInput.spec.ts +592 -0
  378. package/src/hooks/gesture/useSwipeInput.ts +310 -0
  379. package/src/hooks/gesture/utils.spec.ts +152 -0
  380. package/src/hooks/gesture/utils.ts +178 -0
  381. package/src/hooks/useAnimatedVisibility.spec.ts +277 -0
  382. package/src/hooks/useAnimatedVisibility.ts +172 -0
  383. package/src/hooks/useAnimationFrame.ts +208 -0
  384. package/src/hooks/useCSSMatrix.spec.ts +214 -0
  385. package/src/hooks/useCSSMatrix.ts +262 -0
  386. package/src/hooks/useClonedElementPreview.ts +28 -0
  387. package/src/hooks/useContainerScroll.ts +78 -0
  388. package/src/hooks/useContentCache.spec.tsx +232 -0
  389. package/src/hooks/useContentCache.tsx +127 -0
  390. package/src/hooks/useDocumentPointerEvents.ts +137 -0
  391. package/src/hooks/useDocumentScroll.ts +41 -0
  392. package/src/hooks/useEffectEvent.ts +40 -0
  393. package/src/hooks/useElementComponentWrapper.tsx +63 -0
  394. package/src/hooks/useIntersectionObserver.tsx +125 -0
  395. package/src/hooks/useIsomorphicLayoutEffect.ts +29 -0
  396. package/src/hooks/useOperationContinuity.spec.ts +387 -0
  397. package/src/hooks/useOperationContinuity.ts +135 -0
  398. package/src/hooks/useResizeObserver.spec.tsx +277 -0
  399. package/src/hooks/useResizeObserver.tsx +150 -0
  400. package/src/hooks/useScrollContainer.ts +73 -0
  401. package/src/hooks/useSharedElementTransition.ts +333 -0
  402. package/src/hooks/useSnapAnimation.ts +128 -0
  403. package/src/hooks/useSwipeContentTransform.spec.ts +133 -0
  404. package/src/hooks/useSwipeContentTransform.ts +373 -0
  405. package/src/hooks/useTransitionState.ts +95 -0
  406. package/src/index.tsx +88 -0
  407. package/src/modules/dialog/AlertDialog.spec.tsx +387 -0
  408. package/src/modules/dialog/AlertDialog.tsx +221 -0
  409. package/src/modules/dialog/DialogContainer.spec.tsx +228 -0
  410. package/src/modules/dialog/DialogContainer.tsx +188 -0
  411. package/src/modules/dialog/Modal.spec.tsx +220 -0
  412. package/src/modules/dialog/Modal.tsx +182 -0
  413. package/src/modules/dialog/SwipeDialogContainer.tsx +208 -0
  414. package/src/modules/dialog/dialogAnimationUtils.spec.ts +253 -0
  415. package/src/modules/dialog/dialogAnimationUtils.ts +297 -0
  416. package/src/modules/dialog/types.ts +186 -0
  417. package/src/modules/dialog/useDialog.spec.tsx +447 -0
  418. package/src/modules/dialog/useDialog.ts +214 -0
  419. package/src/modules/dialog/useDialogContainer.spec.ts +331 -0
  420. package/src/modules/dialog/useDialogContainer.ts +150 -0
  421. package/src/modules/dialog/useDialogSwipeInput.spec.ts +157 -0
  422. package/src/modules/dialog/useDialogSwipeInput.ts +319 -0
  423. package/src/modules/dialog/useDialogTransform.spec.ts +370 -0
  424. package/src/modules/dialog/useDialogTransform.ts +407 -0
  425. package/src/modules/drawer/types.ts +102 -0
  426. package/src/modules/drawer/useDrawerSwipeInput.spec.ts +566 -0
  427. package/src/modules/drawer/useDrawerSwipeInput.ts +399 -0
  428. package/src/modules/grid/GridLayoutContext.tsx +57 -0
  429. package/src/modules/grid/LayerInstanceContext.tsx +56 -0
  430. package/src/modules/grid/resizeHandles.ts +157 -0
  431. package/src/modules/grid/trackUtils.ts +146 -0
  432. package/src/modules/grid/useGridPlacements.ts +143 -0
  433. package/src/modules/grid/useGridTracks.ts +156 -0
  434. package/src/modules/grid/useLayerDragHandle.ts +16 -0
  435. package/src/modules/grid/useLayerInteractions.tsx +850 -0
  436. package/src/modules/keybindings/KeybindingsProvider.tsx +111 -0
  437. package/src/modules/panels/dom/DomRegistry.tsx +94 -0
  438. package/src/modules/panels/index.ts +45 -0
  439. package/src/modules/panels/interactions/InteractionsContext.test.tsx +330 -0
  440. package/src/modules/panels/interactions/InteractionsContext.tsx +394 -0
  441. package/src/modules/panels/interactions/dnd.ts +28 -0
  442. package/src/modules/panels/keybindings/KeybindingsInstaller.tsx +15 -0
  443. package/src/modules/panels/layout/adapter.ts +124 -0
  444. package/src/modules/panels/rendering/ContentRegistry.spec.tsx +311 -0
  445. package/src/modules/panels/rendering/ContentRegistry.tsx +205 -0
  446. package/src/modules/panels/rendering/GroupContainer.tsx +65 -0
  447. package/src/modules/panels/rendering/RenderBridge.tsx +115 -0
  448. package/src/modules/panels/rendering/RenderContext.tsx +31 -0
  449. package/src/modules/panels/state/PanelSplitHandles.tsx +147 -0
  450. package/src/modules/panels/state/PanelSystemContext.splitLimits.spec.tsx +50 -0
  451. package/src/modules/panels/state/PanelSystemContext.tsx +289 -0
  452. package/src/modules/panels/state/StateContext.tsx +12 -0
  453. package/src/modules/panels/state/cleanup.ts +37 -0
  454. package/src/modules/panels/state/commands.ts +53 -0
  455. package/src/modules/panels/state/focus/Context.tsx +25 -0
  456. package/src/modules/panels/state/focus/logic.ts +57 -0
  457. package/src/modules/panels/state/groups/Context.tsx +25 -0
  458. package/src/modules/panels/state/groups/logic.ts +105 -0
  459. package/src/modules/panels/state/splitLimits.spec.ts +46 -0
  460. package/src/modules/panels/state/splitLimits.ts +90 -0
  461. package/src/modules/panels/state/state.spec.ts +49 -0
  462. package/src/modules/panels/state/tree/Context.tsx +24 -0
  463. package/src/modules/panels/state/tree/logic.spec.ts +34 -0
  464. package/src/modules/panels/state/tree/logic.ts +138 -0
  465. package/src/modules/panels/state/types.ts +142 -0
  466. package/src/modules/panels/system/PanelSystem.empty-tabbar.spec.tsx +53 -0
  467. package/src/modules/panels/system/PanelSystem.tab-click-activates.spec.tsx +44 -0
  468. package/src/modules/panels/system/PanelSystem.tab-reorder.spec.tsx +64 -0
  469. package/src/modules/panels/system/PanelSystem.tabs-no-dup.spec.tsx +57 -0
  470. package/src/modules/panels/system/PanelSystem.tsx +206 -0
  471. package/src/modules/pivot/PivotContent.spec.tsx +179 -0
  472. package/src/modules/pivot/PivotContent.tsx +77 -0
  473. package/src/modules/pivot/SwipePivotContent.debug.tmp.tsx +237 -0
  474. package/src/modules/pivot/SwipePivotContent.position.spec.tsx +171 -0
  475. package/src/modules/pivot/SwipePivotContent.spec.tsx +494 -0
  476. package/src/modules/pivot/SwipePivotContent.test.tsx +502 -0
  477. package/src/modules/pivot/SwipePivotContent.tsx +197 -0
  478. package/src/modules/pivot/SwipePivotTabBar.spec.tsx +882 -0
  479. package/src/modules/pivot/SwipePivotTabBar.tsx +583 -0
  480. package/src/modules/pivot/index.ts +8 -0
  481. package/src/modules/pivot/scaleInputState.spec.ts +219 -0
  482. package/src/modules/pivot/scaleInputState.ts +66 -0
  483. package/src/modules/pivot/types.ts +139 -0
  484. package/src/modules/pivot/usePivot.spec.ts +635 -0
  485. package/src/modules/pivot/usePivot.spec.tsx +186 -0
  486. package/src/modules/pivot/usePivot.tsx +345 -0
  487. package/src/modules/pivot/usePivotSwipeInput.spec.ts +708 -0
  488. package/src/modules/pivot/usePivotSwipeInput.ts +136 -0
  489. package/src/modules/resizer/useResizeDrag.ts +94 -0
  490. package/src/modules/stack/StackContent.spec.tsx +264 -0
  491. package/src/modules/stack/StackContent.tsx +111 -0
  492. package/src/modules/stack/SwipeStackContent.spec.tsx +1564 -0
  493. package/src/modules/stack/SwipeStackContent.tsx +366 -0
  494. package/src/modules/stack/SwipeStackOutlet.spec.tsx +250 -0
  495. package/src/modules/stack/SwipeStackOutlet.tsx +221 -0
  496. package/src/modules/stack/computeStackContentState.spec.ts +281 -0
  497. package/src/modules/stack/computeStackContentState.ts +304 -0
  498. package/src/modules/stack/computeSwipeStackTransform.spec.ts +186 -0
  499. package/src/modules/stack/computeSwipeStackTransform.ts +145 -0
  500. package/src/modules/stack/swipeTransitionContinuity.spec.tsx +1133 -0
  501. package/src/modules/stack/types.ts +226 -0
  502. package/src/modules/stack/useStackAnimationState.spec.ts +188 -0
  503. package/src/modules/stack/useStackAnimationState.ts +143 -0
  504. package/src/modules/stack/useStackNavigation.spec.ts +672 -0
  505. package/src/modules/stack/useStackNavigation.tsx +393 -0
  506. package/src/modules/stack/useStackSwipeInput.spec.ts +309 -0
  507. package/src/modules/stack/useStackSwipeInput.ts +139 -0
  508. package/src/modules/window/useDrawerState.ts +81 -0
  509. package/src/modules/window/useFloatingState.spec.ts +252 -0
  510. package/src/modules/window/useFloatingState.ts +141 -0
  511. package/src/panels/index.ts +119 -0
  512. package/src/pivot/index.ts +19 -0
  513. package/src/resizer/index.ts +68 -0
  514. package/src/stack/index.ts +91 -0
  515. package/src/sticky-header/StickyArea.tsx +193 -0
  516. package/src/sticky-header/calculateStickyMetrics.spec.ts +105 -0
  517. package/src/sticky-header/calculateStickyMetrics.ts +50 -0
  518. package/src/sticky-header/index.ts +18 -0
  519. package/src/sticky-header/types.ts +68 -0
  520. package/src/types.ts +341 -0
  521. package/src/utils/CSSMatrix.ts +321 -0
  522. package/src/utils/css.ts +65 -0
  523. package/src/utils/dialogUtils.ts +43 -0
  524. package/src/utils/math.ts +18 -0
  525. package/src/utils/polyfills/createDialogPolyfill.ts +18 -0
  526. package/src/utils/typedActions.ts +103 -0
  527. package/src/vite-env.d.ts +6 -0
  528. package/src/window/index.ts +69 -0
  529. package/dist/GridLayout-BQQ63eA1.cjs +0 -2
  530. package/dist/GridLayout-BQQ63eA1.cjs.map +0 -1
  531. package/dist/GridLayout-CJTKq7Mp.js +0 -1465
  532. package/dist/GridLayout-CJTKq7Mp.js.map +0 -1
  533. package/dist/sticky-header/StickyHeader.d.ts +0 -53
  534. package/dist/styles-CA2_zLZt.js +0 -52
  535. package/dist/styles-CA2_zLZt.js.map +0 -1
  536. package/dist/styles-PsqGOEJP.cjs +0 -2
  537. package/dist/styles-PsqGOEJP.cjs.map +0 -1
  538. package/dist/usePivot-7ctin_P_.cjs +0 -2
  539. package/dist/usePivot-7ctin_P_.cjs.map +0 -1
  540. package/dist/usePivot-CgQxB8rc.js +0 -124
  541. package/dist/usePivot-CgQxB8rc.js.map +0 -1
@@ -0,0 +1,333 @@
1
+ /**
2
+ * @file Hook for View Transitions API shared element animations.
3
+ *
4
+ * Enables smooth morph animations between a source element (e.g., card)
5
+ * and a target element (e.g., expanded view) using CSS view-transition-name.
6
+ * Supports swipe-to-dismiss with the expanded view animating back to source.
7
+ */
8
+ import * as React from "react";
9
+ import { flushSync } from "react-dom";
10
+
11
+ /**
12
+ * Check if View Transitions API is supported.
13
+ */
14
+ export function supportsViewTransitions(): boolean {
15
+ return typeof document !== "undefined" && "startViewTransition" in document;
16
+ }
17
+
18
+ type ViewTransitionHandle = {
19
+ finished: Promise<void>;
20
+ ready: Promise<void>;
21
+ updateCallbackDone: Promise<void>;
22
+ skipTransition: () => void;
23
+ };
24
+
25
+ /**
26
+ * Start a view transition with the given callback.
27
+ */
28
+ export function startViewTransition(callback: () => void): ViewTransitionHandle | null {
29
+ if (supportsViewTransitions()) {
30
+ return (document as Document & { startViewTransition: (cb: () => void) => ViewTransitionHandle }).startViewTransition(callback);
31
+ }
32
+ callback();
33
+ return null;
34
+ }
35
+
36
+ /** Default dismiss threshold (30% of viewport height) */
37
+ const DEFAULT_DISMISS_THRESHOLD = 0.3;
38
+
39
+ /** Velocity threshold for quick flick dismissal (px/ms) */
40
+ const VELOCITY_THRESHOLD = 0.5;
41
+
42
+ /**
43
+ * Options for useSharedElementTransition hook.
44
+ */
45
+ export type UseSharedElementTransitionOptions<T> = {
46
+ /**
47
+ * Function to generate a unique transition name for an item.
48
+ * Multiple names can be returned for nested shared elements.
49
+ */
50
+ getTransitionName: (item: T) => string | string[];
51
+ /**
52
+ * Function to get a unique key for comparison.
53
+ * Defaults to using getTransitionName result.
54
+ */
55
+ getKey?: (item: T) => string;
56
+ /** Enable swipe to dismiss. @default true */
57
+ swipeDismissible?: boolean;
58
+ /** Threshold ratio (0-1) to trigger dismiss. @default 0.3 */
59
+ dismissThreshold?: number;
60
+ };
61
+
62
+ /** 2D vector */
63
+ type Vector2 = { x: number; y: number };
64
+
65
+ /**
66
+ * Result from useSharedElementTransition hook.
67
+ */
68
+ export type UseSharedElementTransitionResult<T> = {
69
+ /** Currently expanded item, or null if none */
70
+ expandedItem: T | null;
71
+ /** Expand an item with view transition */
72
+ expand: (item: T) => void;
73
+ /** Collapse the expanded item with view transition */
74
+ collapse: () => void;
75
+ /**
76
+ * Get style props for a source element (e.g., card).
77
+ */
78
+ getSourceProps: (item: T, nameIndex?: number) => { style: React.CSSProperties };
79
+ /**
80
+ * Get style props for the target element (e.g., expanded view).
81
+ * Includes transform for swipe tracking.
82
+ */
83
+ getTargetProps: (nameIndex?: number) => { style: React.CSSProperties };
84
+ /**
85
+ * Get swipe container props (onPointerDown, style).
86
+ * Apply to the swipeable container element.
87
+ */
88
+ getSwipeContainerProps: () => React.HTMLAttributes<HTMLElement> & { style: React.CSSProperties };
89
+ /** Whether currently being swiped */
90
+ isSwiping: boolean;
91
+ /** Current displacement during swipe */
92
+ displacement: Vector2;
93
+ /** Whether View Transitions API is supported */
94
+ isSupported: boolean;
95
+ };
96
+
97
+ /**
98
+ * Hook for managing shared element transitions using View Transitions API.
99
+ *
100
+ * @example
101
+ * ```tsx
102
+ * const {
103
+ * expandedItem, expand, collapse,
104
+ * getSourceProps, getTargetProps, getSwipeContainerProps
105
+ * } = useSharedElementTransition({
106
+ * getTransitionName: (album) => [`album-${album.id}`, `album-art-${album.id}`],
107
+ * });
108
+ *
109
+ * // Source (card)
110
+ * <div {...getSourceProps(album, 0)}>
111
+ * <img {...getSourceProps(album, 1)} />
112
+ * </div>
113
+ *
114
+ * // Target (expanded view) - apply swipe props to container
115
+ * {expandedItem && (
116
+ * <div {...getSwipeContainerProps()}>
117
+ * <div {...getTargetProps(0)}>
118
+ * <img {...getTargetProps(1)} />
119
+ * </div>
120
+ * </div>
121
+ * )}
122
+ * ```
123
+ */
124
+ export function useSharedElementTransition<T>(
125
+ options: UseSharedElementTransitionOptions<T>,
126
+ ): UseSharedElementTransitionResult<T> {
127
+ const {
128
+ getTransitionName,
129
+ getKey,
130
+ swipeDismissible = true,
131
+ dismissThreshold = DEFAULT_DISMISS_THRESHOLD,
132
+ } = options;
133
+
134
+ const [expandedItem, setExpandedItem] = React.useState<T | null>(null);
135
+ // Track which item is about to be expanded (for view transition name assignment)
136
+ const [pendingExpandItem, setPendingExpandItem] = React.useState<T | null>(null);
137
+ // Track which item is collapsing (for view transition name assignment on the card)
138
+ const [collapsingItem, setCollapsingItem] = React.useState<T | null>(null);
139
+ const isSupported = React.useMemo(() => supportsViewTransitions(), []);
140
+
141
+ // Swipe tracking state
142
+ const [isSwiping, setIsSwiping] = React.useState(false);
143
+ const [displacement, setDisplacement] = React.useState<Vector2>({ x: 0, y: 0 });
144
+ const startPointRef = React.useRef<Vector2 | null>(null);
145
+ const startTimeRef = React.useRef<number>(0);
146
+
147
+ // Get item key for comparison
148
+ const getItemKey = React.useCallback((item: T): string => {
149
+ if (getKey) {
150
+ return getKey(item);
151
+ }
152
+ const names = getTransitionName(item);
153
+ return Array.isArray(names) ? names[0] : names;
154
+ }, [getKey, getTransitionName]);
155
+
156
+ const expand = React.useCallback((item: T) => {
157
+ // First, set pending item so only this card gets view-transition-name
158
+ setPendingExpandItem(item);
159
+
160
+ // Use requestAnimationFrame to ensure React re-renders before view transition
161
+ requestAnimationFrame(() => {
162
+ const transition = startViewTransition(() => {
163
+ flushSync(() => {
164
+ setExpandedItem(item);
165
+ setPendingExpandItem(null);
166
+ });
167
+ });
168
+ // Fallback if viewTransition not supported
169
+ if (!transition) {
170
+ setExpandedItem(item);
171
+ setPendingExpandItem(null);
172
+ }
173
+ });
174
+ }, []);
175
+
176
+ const collapse = React.useCallback(() => {
177
+ if (!expandedItem) return;
178
+
179
+ setIsSwiping(false);
180
+
181
+ // For closing, expanded view already has view-transition-name
182
+ // We just need the card to also have it in the new state
183
+ // Use flushSync immediately since old state (expanded) already has the name
184
+ const itemToCollapse = expandedItem;
185
+ const transition = startViewTransition(() => {
186
+ flushSync(() => {
187
+ setExpandedItem(null);
188
+ setCollapsingItem(itemToCollapse);
189
+ });
190
+ });
191
+
192
+ // Reset states after transition completes (or immediately if not supported)
193
+ if (transition) {
194
+ transition.finished.then(() => {
195
+ setDisplacement({ x: 0, y: 0 });
196
+ setCollapsingItem(null);
197
+ });
198
+ } else {
199
+ setExpandedItem(null);
200
+ setDisplacement({ x: 0, y: 0 });
201
+ setCollapsingItem(null);
202
+ }
203
+ }, [expandedItem]);
204
+
205
+ // Pointer event handlers for swipe
206
+ const handlePointerDown = React.useCallback((event: React.PointerEvent) => {
207
+ if (!swipeDismissible || !expandedItem) {
208
+ return;
209
+ }
210
+ (event.target as HTMLElement).setPointerCapture(event.pointerId);
211
+ startPointRef.current = { x: event.clientX, y: event.clientY };
212
+ startTimeRef.current = Date.now();
213
+ setIsSwiping(true);
214
+ }, [swipeDismissible, expandedItem]);
215
+
216
+ const handlePointerMove = React.useCallback((event: React.PointerEvent) => {
217
+ if (!isSwiping || !startPointRef.current) {
218
+ return;
219
+ }
220
+ const dx = event.clientX - startPointRef.current.x;
221
+ const dy = event.clientY - startPointRef.current.y;
222
+ setDisplacement({ x: dx, y: dy });
223
+ }, [isSwiping]);
224
+
225
+ const handlePointerUp = React.useCallback((event: React.PointerEvent) => {
226
+ if (!isSwiping || !startPointRef.current) {
227
+ return;
228
+ }
229
+
230
+ const duration = Date.now() - startTimeRef.current;
231
+ const velocity = Math.abs(displacement.y) / Math.max(1, duration);
232
+ const viewportHeight = window.innerHeight;
233
+ const ratio = Math.abs(displacement.y) / viewportHeight;
234
+
235
+ // Check if should dismiss (downward swipe)
236
+ const shouldDismiss = displacement.y > 0 && (ratio >= dismissThreshold || velocity >= VELOCITY_THRESHOLD);
237
+
238
+ if (shouldDismiss) {
239
+ collapse();
240
+ } else {
241
+ // Snap back
242
+ setDisplacement({ x: 0, y: 0 });
243
+ }
244
+
245
+ setIsSwiping(false);
246
+ startPointRef.current = null;
247
+ }, [isSwiping, displacement, dismissThreshold, collapse]);
248
+
249
+ const handlePointerCancel = React.useCallback(() => {
250
+ setIsSwiping(false);
251
+ setDisplacement({ x: 0, y: 0 });
252
+ startPointRef.current = null;
253
+ }, []);
254
+
255
+ const getSourceProps = React.useCallback(
256
+ (item: T, nameIndex = 0): { style: React.CSSProperties } => {
257
+ const names = getTransitionName(item);
258
+ const nameArray = Array.isArray(names) ? names : [names];
259
+ const name = nameArray[nameIndex];
260
+
261
+ const itemKey = getItemKey(item);
262
+ const isThisItemExpanded = expandedItem !== null && getItemKey(expandedItem) === itemKey;
263
+ const isThisItemPending = pendingExpandItem !== null && getItemKey(pendingExpandItem) === itemKey;
264
+ const isThisItemCollapsing = collapsingItem !== null && getItemKey(collapsingItem) === itemKey;
265
+
266
+ // Only give view-transition-name to:
267
+ // - The pending item (clicked card, for old state capture during expand)
268
+ // - The collapsing item (card returning to, for new state capture during collapse)
269
+ // - Never to other cards (they don't participate in the transition)
270
+ const shouldHaveTransitionName = isThisItemPending || isThisItemCollapsing;
271
+
272
+ return {
273
+ style: {
274
+ viewTransitionName: shouldHaveTransitionName ? name : undefined,
275
+ // Hide the source card when expanded (it's now represented by the target)
276
+ visibility: isThisItemExpanded ? "hidden" : undefined,
277
+ },
278
+ };
279
+ },
280
+ [expandedItem, pendingExpandItem, collapsingItem, getTransitionName, getItemKey],
281
+ );
282
+
283
+ const getTargetProps = React.useCallback(
284
+ (nameIndex = 0): { style: React.CSSProperties } => {
285
+ if (expandedItem === null) {
286
+ return { style: {} };
287
+ }
288
+
289
+ const names = getTransitionName(expandedItem);
290
+ const nameArray = Array.isArray(names) ? names : [names];
291
+ const name = nameArray[nameIndex];
292
+
293
+ // Apply transform during swipe
294
+ const transform = isSwiping || displacement.x !== 0 || displacement.y !== 0
295
+ ? `translate(${displacement.x}px, ${displacement.y}px)`
296
+ : undefined;
297
+
298
+ return {
299
+ style: {
300
+ viewTransitionName: name,
301
+ transform,
302
+ transition: !isSwiping ? "transform 0.3s ease-out" : undefined,
303
+ },
304
+ };
305
+ },
306
+ [expandedItem, getTransitionName, isSwiping, displacement],
307
+ );
308
+
309
+ const getSwipeContainerProps = React.useCallback((): React.HTMLAttributes<HTMLElement> & { style: React.CSSProperties } => {
310
+ return {
311
+ onPointerDown: handlePointerDown,
312
+ onPointerMove: handlePointerMove,
313
+ onPointerUp: handlePointerUp,
314
+ onPointerCancel: handlePointerCancel,
315
+ style: {
316
+ touchAction: "none",
317
+ userSelect: "none",
318
+ },
319
+ };
320
+ }, [handlePointerDown, handlePointerMove, handlePointerUp, handlePointerCancel]);
321
+
322
+ return {
323
+ expandedItem,
324
+ expand,
325
+ collapse,
326
+ getSourceProps,
327
+ getTargetProps,
328
+ getSwipeContainerProps,
329
+ isSwiping,
330
+ displacement,
331
+ isSupported,
332
+ };
333
+ }
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @file Hook for snapping element transform animation.
3
+ *
4
+ * Built on top of useAnimationFrame, provides a convenient API
5
+ * for animating element transforms from one position to another.
6
+ */
7
+ import * as React from "react";
8
+ import { useAnimationFrame, interpolate, easings } from "./useAnimationFrame.js";
9
+ import type { EasingFunction } from "./useAnimationFrame.js";
10
+
11
+ // Re-export easings for convenience
12
+ export { easings } from "./useAnimationFrame.js";
13
+ export type { EasingFunction } from "./useAnimationFrame.js";
14
+
15
+ /**
16
+ * Options for useSnapAnimation hook.
17
+ */
18
+ export type UseSnapAnimationOptions = {
19
+ /** Reference to the element to animate */
20
+ elementRef: React.RefObject<HTMLElement | null>;
21
+ /** Duration of animation in milliseconds */
22
+ duration?: number;
23
+ /** Easing function for the animation */
24
+ easing?: EasingFunction;
25
+ /** Callback when animation completes */
26
+ onComplete?: () => void;
27
+ };
28
+
29
+ /**
30
+ * Result from useSnapAnimation hook.
31
+ */
32
+ export type UseSnapAnimationResult = {
33
+ /** Whether animation is currently running */
34
+ isAnimating: boolean;
35
+ /** Start a new animation from current value to target */
36
+ animate: (from: number, to: number, axis: "x" | "y") => void;
37
+ /** Cancel any running animation */
38
+ cancel: () => void;
39
+ };
40
+
41
+ /** Default animation duration in ms */
42
+ const DEFAULT_DURATION = 300;
43
+
44
+ /**
45
+ * Hook for snapping element transform animation.
46
+ *
47
+ * Animates an element's transform from one position to another
48
+ * using requestAnimationFrame for smooth animation.
49
+ *
50
+ * @example
51
+ * ```tsx
52
+ * const elementRef = useRef<HTMLDivElement>(null);
53
+ * const { animate, isAnimating } = useSnapAnimation({
54
+ * elementRef,
55
+ * duration: 300,
56
+ * easing: easings.easeOutExpo,
57
+ * });
58
+ *
59
+ * // Start animation
60
+ * animate(currentX, targetX, "x");
61
+ * ```
62
+ */
63
+ export function useSnapAnimation(options: UseSnapAnimationOptions): UseSnapAnimationResult {
64
+ const {
65
+ elementRef,
66
+ duration = DEFAULT_DURATION,
67
+ easing = easings.easeOutExpo,
68
+ onComplete,
69
+ } = options;
70
+
71
+ // Store animation parameters in refs for use in onFrame callback
72
+ const animParamsRef = React.useRef<{
73
+ from: number;
74
+ to: number;
75
+ axis: "x" | "y";
76
+ } | null>(null);
77
+
78
+ const handleFrame = React.useCallback(
79
+ ({ easedProgress }: { easedProgress: number }) => {
80
+ const element = elementRef.current;
81
+ const params = animParamsRef.current;
82
+ if (!element || !params) {
83
+ return;
84
+ }
85
+
86
+ const currentValue = interpolate(params.from, params.to, easedProgress);
87
+ const translateFn = params.axis === "x" ? "translateX" : "translateY";
88
+ element.style.transform = `${translateFn}(${currentValue}px)`;
89
+ },
90
+ [elementRef],
91
+ );
92
+
93
+ const { isAnimating, start, cancel } = useAnimationFrame({
94
+ duration,
95
+ easing,
96
+ onFrame: handleFrame,
97
+ onComplete,
98
+ });
99
+
100
+ const animate = React.useCallback(
101
+ (from: number, to: number, axis: "x" | "y") => {
102
+ const element = elementRef.current;
103
+ if (!element) {
104
+ return;
105
+ }
106
+
107
+ // If from and to are the same, no animation needed
108
+ if (Math.abs(from - to) < 0.5) {
109
+ const translateFn = axis === "x" ? "translateX" : "translateY";
110
+ element.style.transform = `${translateFn}(${to}px)`;
111
+ return;
112
+ }
113
+
114
+ // Store animation parameters
115
+ animParamsRef.current = { from, to, axis };
116
+
117
+ // Start animation
118
+ start();
119
+ },
120
+ [elementRef, start],
121
+ );
122
+
123
+ return {
124
+ isAnimating,
125
+ animate,
126
+ cancel,
127
+ };
128
+ }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * @file Tests for useSwipeContentTransform hook.
3
+ */
4
+ import { renderHook } from "@testing-library/react";
5
+ import { useSwipeContentTransform } from "./useSwipeContentTransform.js";
6
+
7
+ describe("useSwipeContentTransform", () => {
8
+ const createMockElementRef = (): { element: HTMLDivElement; ref: React.RefObject<HTMLDivElement> } => {
9
+ const element = document.createElement("div");
10
+ return { element, ref: { current: element } };
11
+ };
12
+
13
+ it("returns initial state correctly", () => {
14
+ const { ref } = createMockElementRef();
15
+ const { result } = renderHook(() =>
16
+ useSwipeContentTransform({
17
+ elementRef: ref,
18
+ targetPx: 0,
19
+ displacement: 0,
20
+ isOperating: false,
21
+ }),
22
+ );
23
+
24
+ expect(result.current.isAnimating).toBe(false);
25
+ expect(result.current.currentPx).toBe(0);
26
+ });
27
+
28
+ it("updates element transform during swipe", () => {
29
+ const { element, ref } = createMockElementRef();
30
+ const { rerender } = renderHook(
31
+ ({ displacement, isOperating }) =>
32
+ useSwipeContentTransform({
33
+ elementRef: ref,
34
+ targetPx: 0,
35
+ displacement,
36
+ isOperating,
37
+ }),
38
+ {
39
+ initialProps: { displacement: 0, isOperating: true },
40
+ },
41
+ );
42
+
43
+ // Simulate swipe movement
44
+ rerender({ displacement: 100, isOperating: true });
45
+
46
+ expect(element.style.transform).toBe("translateX(100px)");
47
+ });
48
+
49
+ it("uses correct transform function for vertical axis", () => {
50
+ const { element, ref } = createMockElementRef();
51
+ const { rerender } = renderHook(
52
+ ({ displacement, isOperating }) =>
53
+ useSwipeContentTransform({
54
+ elementRef: ref,
55
+ targetPx: 0,
56
+ displacement,
57
+ isOperating,
58
+ axis: "vertical",
59
+ }),
60
+ {
61
+ initialProps: { displacement: 0, isOperating: true },
62
+ },
63
+ );
64
+
65
+ rerender({ displacement: 50, isOperating: true });
66
+
67
+ expect(element.style.transform).toBe("translateY(50px)");
68
+ });
69
+
70
+ it("applies target position with displacement", () => {
71
+ const { element, ref } = createMockElementRef();
72
+ const { rerender } = renderHook(
73
+ ({ displacement, isOperating }) =>
74
+ useSwipeContentTransform({
75
+ elementRef: ref,
76
+ targetPx: -300, // target is off-screen left
77
+ displacement,
78
+ isOperating,
79
+ }),
80
+ {
81
+ initialProps: { displacement: 0, isOperating: true },
82
+ },
83
+ );
84
+
85
+ // During swipe, position = targetPx + displacement
86
+ rerender({ displacement: 100, isOperating: true });
87
+
88
+ expect(element.style.transform).toBe("translateX(-200px)");
89
+ });
90
+
91
+ it("does not update transform when element ref is null", () => {
92
+ const nullRef: React.RefObject<HTMLElement | null> = { current: null };
93
+
94
+ const { rerender } = renderHook(
95
+ ({ displacement, isOperating }) =>
96
+ useSwipeContentTransform({
97
+ elementRef: nullRef,
98
+ targetPx: 0,
99
+ displacement,
100
+ isOperating,
101
+ }),
102
+ {
103
+ initialProps: { displacement: 0, isOperating: true },
104
+ },
105
+ );
106
+
107
+ // Should not throw
108
+ expect(() => {
109
+ rerender({ displacement: 100, isOperating: true });
110
+ }).not.toThrow();
111
+ });
112
+
113
+ it("snaps to target when target changes and not swiping", () => {
114
+ const { element, ref } = createMockElementRef();
115
+ const { rerender } = renderHook(
116
+ ({ targetPx }) =>
117
+ useSwipeContentTransform({
118
+ elementRef: ref,
119
+ targetPx,
120
+ displacement: 0,
121
+ isOperating: false,
122
+ }),
123
+ {
124
+ initialProps: { targetPx: 0 },
125
+ },
126
+ );
127
+
128
+ // Change target without swiping - should snap
129
+ rerender({ targetPx: 300 });
130
+
131
+ expect(element.style.transform).toBe("translateX(300px)");
132
+ });
133
+ });