react-panel-layout 0.6.0 → 0.7.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 (258) hide show
  1. package/dist/{FloatingPanelFrame-SgYLc6Ud.js → FloatingPanelFrame-3eU9AwPo.js} +2 -2
  2. package/dist/{FloatingPanelFrame-SgYLc6Ud.js.map → FloatingPanelFrame-3eU9AwPo.js.map} +1 -1
  3. package/dist/FloatingWindow-Bw2djgpz.js +1542 -0
  4. package/dist/FloatingWindow-Bw2djgpz.js.map +1 -0
  5. package/dist/FloatingWindow-Cvyokf0m.cjs +2 -0
  6. package/dist/FloatingWindow-Cvyokf0m.cjs.map +1 -0
  7. package/dist/GridLayout-B4aCqSyd.js +947 -0
  8. package/dist/{GridLayout-BltqeCPK.js.map → GridLayout-B4aCqSyd.js.map} +1 -1
  9. package/dist/GridLayout-DNOClFzz.cjs +2 -0
  10. package/dist/{GridLayout-B4VRsC0r.cjs.map → GridLayout-DNOClFzz.cjs.map} +1 -1
  11. package/dist/{HorizontalDivider-WF1k_qND.js → HorizontalDivider-DdxzfV0l.js} +3 -3
  12. package/dist/{HorizontalDivider-WF1k_qND.js.map → HorizontalDivider-DdxzfV0l.js.map} +1 -1
  13. package/dist/{HorizontalDivider-B5Z-KZLk.cjs → HorizontalDivider-_pgV4Mcv.cjs} +2 -2
  14. package/dist/{HorizontalDivider-B5Z-KZLk.cjs.map → HorizontalDivider-_pgV4Mcv.cjs.map} +1 -1
  15. package/dist/PanelSystem-B8Igvnb2.cjs +3 -0
  16. package/dist/PanelSystem-B8Igvnb2.cjs.map +1 -0
  17. package/dist/{PanelSystem-Dr1TBhxM.js → PanelSystem-DDUSFjXD.js} +209 -248
  18. package/dist/PanelSystem-DDUSFjXD.js.map +1 -0
  19. package/dist/ResizeHandle-CBcAS918.cjs +2 -0
  20. package/dist/{ResizeHandle-CScipO5l.cjs.map → ResizeHandle-CBcAS918.cjs.map} +1 -1
  21. package/dist/{ResizeHandle-CdA_JYfN.js → ResizeHandle-CXjc1meV.js} +28 -29
  22. package/dist/{ResizeHandle-CdA_JYfN.js.map → ResizeHandle-CXjc1meV.js.map} +1 -1
  23. package/dist/SwipePivotTabBar-DWrCuwEI.js +411 -0
  24. package/dist/SwipePivotTabBar-DWrCuwEI.js.map +1 -0
  25. package/dist/SwipePivotTabBar-fjjXkpj7.cjs +2 -0
  26. package/dist/SwipePivotTabBar-fjjXkpj7.cjs.map +1 -0
  27. package/dist/components/gesture/SwipeSafeZone.d.ts +40 -0
  28. package/dist/components/window/Drawer.d.ts +4 -1
  29. package/dist/components/window/DrawerLayers.d.ts +1 -1
  30. package/dist/components/window/DrawerRevealContext.d.ts +61 -0
  31. package/dist/components/window/drawerRevealAnimationUtils.d.ts +212 -0
  32. package/dist/components/window/drawerStyles.d.ts +74 -0
  33. package/dist/components/window/drawerSwipeConfig.d.ts +29 -0
  34. package/dist/components/window/useDrawerSwipeTransform.d.ts +29 -0
  35. package/dist/components/window/useDrawerTransform.d.ts +68 -0
  36. package/dist/components/window/useRevealDrawerTransform.d.ts +56 -0
  37. package/dist/config.cjs +1 -1
  38. package/dist/config.cjs.map +1 -1
  39. package/dist/config.js +9 -8
  40. package/dist/config.js.map +1 -1
  41. package/dist/constants/styles.d.ts +17 -0
  42. package/dist/dialog/index.d.ts +69 -0
  43. package/dist/floating.js +1 -1
  44. package/dist/grid.cjs +1 -1
  45. package/dist/grid.js +2 -2
  46. package/dist/hooks/gesture/testing/createGestureSimulator.d.ts +7 -0
  47. package/dist/hooks/gesture/types.d.ts +48 -5
  48. package/dist/hooks/gesture/utils.d.ts +19 -0
  49. package/dist/hooks/useAnimationFrame.d.ts +2 -0
  50. package/dist/hooks/useOperationContinuity.d.ts +64 -0
  51. package/dist/hooks/useResizeObserver.d.ts +33 -1
  52. package/dist/hooks/useSharedElementTransition.d.ts +112 -0
  53. package/dist/hooks/useSwipeContentTransform.d.ts +9 -2
  54. package/dist/index.cjs +1 -1
  55. package/dist/index.js +7 -7
  56. package/dist/modules/dialog/AlertDialog.d.ts +9 -0
  57. package/dist/modules/dialog/DialogContainer.d.ts +37 -0
  58. package/dist/modules/dialog/Modal.d.ts +26 -0
  59. package/dist/modules/dialog/SwipeDialogContainer.d.ts +16 -0
  60. package/dist/modules/dialog/dialogAnimationUtils.d.ts +113 -0
  61. package/dist/modules/dialog/types.d.ts +183 -0
  62. package/dist/modules/dialog/useDialog.d.ts +39 -0
  63. package/dist/modules/dialog/useDialogContainer.d.ts +47 -0
  64. package/dist/modules/dialog/useDialogSwipeInput.d.ts +70 -0
  65. package/dist/modules/dialog/useDialogTransform.d.ts +82 -0
  66. package/dist/modules/drawer/drawerStateMachine.d.ts +168 -0
  67. package/dist/modules/drawer/revealDrawerConstants.d.ts +33 -0
  68. package/dist/modules/drawer/revealDrawerStateMachine.d.ts +146 -0
  69. package/dist/modules/drawer/strategies/index.d.ts +8 -0
  70. package/dist/modules/drawer/strategies/overlayStrategy.d.ts +12 -0
  71. package/dist/modules/drawer/strategies/revealStrategy.d.ts +12 -0
  72. package/dist/modules/drawer/strategies/types.d.ts +116 -0
  73. package/dist/modules/drawer/types.d.ts +74 -0
  74. package/dist/modules/drawer/useDrawerSwipeInput.d.ts +24 -0
  75. package/dist/modules/pivot/SwipePivotTabBar.d.ts +3 -0
  76. package/dist/modules/stack/SwipeStackContent.d.ts +6 -3
  77. package/dist/modules/stack/SwipeStackOutlet.d.ts +4 -4
  78. package/dist/modules/stack/computeSwipeStackTransform.d.ts +1 -1
  79. package/dist/panels.cjs +1 -1
  80. package/dist/panels.js +1 -1
  81. package/dist/pivot.cjs +1 -1
  82. package/dist/pivot.js +1 -1
  83. package/dist/resizer.cjs +1 -1
  84. package/dist/resizer.js +2 -2
  85. package/dist/stack.cjs +1 -1
  86. package/dist/stack.cjs.map +1 -1
  87. package/dist/stack.js +480 -780
  88. package/dist/stack.js.map +1 -1
  89. package/dist/sticky-header/calculateStickyMetrics.d.ts +28 -0
  90. package/dist/sticky-header.cjs +1 -1
  91. package/dist/sticky-header.cjs.map +1 -1
  92. package/dist/sticky-header.js +59 -51
  93. package/dist/sticky-header.js.map +1 -1
  94. package/dist/{styles-DPPuJ0sf.js → styles-NkjuMOVS.js} +13 -13
  95. package/dist/{styles-DPPuJ0sf.js.map → styles-NkjuMOVS.js.map} +1 -1
  96. package/dist/styles-qf6ptVLD.cjs.map +1 -1
  97. package/dist/types.d.ts +30 -0
  98. package/dist/useAnimationFrame-BZ6D2lMq.cjs +2 -0
  99. package/dist/useAnimationFrame-BZ6D2lMq.cjs.map +1 -0
  100. package/dist/useAnimationFrame-Bg4e-H8O.js +394 -0
  101. package/dist/useAnimationFrame-Bg4e-H8O.js.map +1 -0
  102. package/dist/useDocumentPointerEvents-DXxw3qWj.js +54 -0
  103. package/dist/useDocumentPointerEvents-DXxw3qWj.js.map +1 -0
  104. package/dist/useDocumentPointerEvents-DxDSOtip.cjs +2 -0
  105. package/dist/useDocumentPointerEvents-DxDSOtip.cjs.map +1 -0
  106. package/dist/window/index.d.ts +2 -0
  107. package/dist/window.cjs +1 -1
  108. package/dist/window.cjs.map +1 -1
  109. package/dist/window.js +114 -103
  110. package/dist/window.js.map +1 -1
  111. package/package.json +6 -1
  112. package/src/components/gesture/SwipeSafeZone.tsx +70 -0
  113. package/src/components/grid/GridLayout.tsx +110 -38
  114. package/src/components/window/Drawer.tsx +353 -162
  115. package/src/components/window/DrawerLayers.tsx +54 -11
  116. package/src/components/window/DrawerRevealContext.spec.ts +20 -0
  117. package/src/components/window/DrawerRevealContext.tsx +99 -0
  118. package/src/components/window/drawerRevealAnimationUtils.spec.ts +375 -0
  119. package/src/components/window/drawerRevealAnimationUtils.ts +415 -0
  120. package/src/components/window/drawerStyles.spec.ts +302 -0
  121. package/src/components/window/drawerStyles.ts +252 -0
  122. package/src/components/window/drawerSwipeConfig.spec.ts +131 -0
  123. package/src/components/window/drawerSwipeConfig.ts +112 -0
  124. package/src/components/window/useDrawerSwipeTransform.ts +67 -0
  125. package/src/components/window/useDrawerTransform.ts +505 -0
  126. package/src/components/window/useRevealDrawerTransform.spec.ts +1936 -0
  127. package/src/components/window/useRevealDrawerTransform.ts +105 -0
  128. package/src/constants/styles.ts +19 -0
  129. package/src/demo/components/FullscreenDemoPage.tsx +47 -0
  130. package/src/demo/fullscreenRoutes.tsx +32 -0
  131. package/src/demo/index.tsx +5 -0
  132. package/src/demo/pages/Dialog/alerts/index.tsx +22 -0
  133. package/src/demo/pages/Dialog/card/index.tsx +22 -0
  134. package/src/demo/pages/Dialog/components/AlertDialogDemo.tsx +124 -0
  135. package/src/demo/pages/Dialog/components/CardExpandDemo.module.css +243 -0
  136. package/src/demo/pages/Dialog/components/CardExpandDemo.tsx +219 -0
  137. package/src/demo/pages/Dialog/components/CustomAlertDialogDemo.tsx +219 -0
  138. package/src/demo/pages/Dialog/components/DialogDemos.module.css +77 -0
  139. package/src/demo/pages/Dialog/components/ModalBasics.tsx +45 -0
  140. package/src/demo/pages/Dialog/components/SwipeDialogDemo.module.css +77 -0
  141. package/src/demo/pages/Dialog/components/SwipeDialogDemo.tsx +181 -0
  142. package/src/demo/pages/Dialog/custom-alert/index.tsx +22 -0
  143. package/src/demo/pages/Dialog/modal/index.tsx +17 -0
  144. package/src/demo/pages/Dialog/swipe/index.tsx +22 -0
  145. package/src/demo/pages/Drawer/components/DrawerBasics.module.css +6 -1
  146. package/src/demo/pages/Drawer/components/DrawerBasics.tsx +14 -4
  147. package/src/demo/pages/Drawer/components/DrawerReveal.module.css +157 -0
  148. package/src/demo/pages/Drawer/components/DrawerReveal.tsx +128 -0
  149. package/src/demo/pages/Drawer/components/DrawerSwipe.module.css +316 -0
  150. package/src/demo/pages/Drawer/components/DrawerSwipe.tsx +178 -0
  151. package/src/demo/pages/Drawer/reveal/index.tsx +17 -0
  152. package/src/demo/pages/Drawer/reveal-fullscreen/index.tsx +135 -0
  153. package/src/demo/pages/Drawer/reveal-fullscreen/styles.module.css +233 -0
  154. package/src/demo/pages/Drawer/swipe/index.tsx +17 -0
  155. package/src/demo/pages/Pivot/components/SwipeTabsPivot.tsx +54 -23
  156. package/src/demo/pages/Pivot/swipe-debug/index.tsx +1 -1
  157. package/src/demo/pages/Stack/components/StackBasics.spec.tsx +156 -0
  158. package/src/demo/pages/Stack/components/StackBasics.tsx +179 -95
  159. package/src/demo/pages/Stack/components/StackTablet.spec.tsx +110 -0
  160. package/src/demo/pages/Stack/components/StackTablet.tsx +42 -21
  161. package/src/demo/routes.tsx +24 -1
  162. package/src/dialog/index.ts +85 -0
  163. package/src/hooks/gesture/testing/createGestureSimulator.spec.ts +68 -64
  164. package/src/hooks/gesture/testing/createGestureSimulator.ts +113 -37
  165. package/src/hooks/gesture/types.ts +83 -6
  166. package/src/hooks/gesture/useEdgeSwipeInput.spec.ts +22 -14
  167. package/src/hooks/gesture/useNativeGestureGuard.spec.ts +99 -31
  168. package/src/hooks/gesture/useNativeGestureGuard.ts +3 -1
  169. package/src/hooks/gesture/utils.ts +102 -0
  170. package/src/hooks/useAnimatedVisibility.spec.ts +44 -24
  171. package/src/hooks/useAnimatedVisibility.ts +28 -2
  172. package/src/hooks/useAnimationFrame.ts +8 -0
  173. package/src/hooks/useOperationContinuity.spec.ts +394 -0
  174. package/src/hooks/useOperationContinuity.ts +135 -0
  175. package/src/hooks/useResizeObserver.spec.tsx +277 -0
  176. package/src/hooks/useResizeObserver.tsx +108 -39
  177. package/src/hooks/useScrollContainer.ts +4 -10
  178. package/src/hooks/useSharedElementTransition.ts +354 -0
  179. package/src/hooks/useSwipeContentTransform.spec.ts +18 -18
  180. package/src/hooks/useSwipeContentTransform.ts +166 -28
  181. package/src/modules/dialog/AlertDialog.spec.tsx +387 -0
  182. package/src/modules/dialog/AlertDialog.tsx +221 -0
  183. package/src/modules/dialog/DialogContainer.spec.tsx +228 -0
  184. package/src/modules/dialog/DialogContainer.tsx +188 -0
  185. package/src/modules/dialog/Modal.spec.tsx +220 -0
  186. package/src/modules/dialog/Modal.tsx +182 -0
  187. package/src/modules/dialog/SwipeDialogContainer.tsx +208 -0
  188. package/src/modules/dialog/dialogAnimationUtils.spec.ts +252 -0
  189. package/src/modules/dialog/dialogAnimationUtils.ts +297 -0
  190. package/src/modules/dialog/types.ts +186 -0
  191. package/src/modules/dialog/useDialog.spec.tsx +447 -0
  192. package/src/modules/dialog/useDialog.ts +214 -0
  193. package/src/modules/dialog/useDialogContainer.spec.ts +339 -0
  194. package/src/modules/dialog/useDialogContainer.ts +150 -0
  195. package/src/modules/dialog/useDialogSwipeInput.spec.ts +178 -0
  196. package/src/modules/dialog/useDialogSwipeInput.ts +350 -0
  197. package/src/modules/dialog/useDialogTransform.spec.ts +403 -0
  198. package/src/modules/dialog/useDialogTransform.ts +407 -0
  199. package/src/modules/drawer/drawerStateMachine.ts +500 -0
  200. package/src/modules/drawer/revealDrawerConstants.ts +38 -0
  201. package/src/modules/drawer/revealDrawerStateMachine.spec.ts +558 -0
  202. package/src/modules/drawer/revealDrawerStateMachine.ts +197 -0
  203. package/src/modules/drawer/strategies/index.ts +9 -0
  204. package/src/modules/drawer/strategies/overlayStrategy.ts +133 -0
  205. package/src/modules/drawer/strategies/revealStrategy.ts +111 -0
  206. package/src/modules/drawer/strategies/types.ts +160 -0
  207. package/src/modules/drawer/types.ts +102 -0
  208. package/src/modules/drawer/useDrawerSwipeInput.spec.ts +566 -0
  209. package/src/modules/drawer/useDrawerSwipeInput.ts +402 -0
  210. package/src/modules/panels/rendering/ContentRegistry.spec.tsx +21 -14
  211. package/src/modules/pivot/SwipePivotContent.position.spec.tsx +12 -8
  212. package/src/modules/pivot/SwipePivotContent.spec.tsx +66 -25
  213. package/src/modules/pivot/SwipePivotContent.tsx +2 -2
  214. package/src/modules/pivot/SwipePivotTabBar.spec.tsx +85 -68
  215. package/src/modules/pivot/SwipePivotTabBar.tsx +75 -15
  216. package/src/modules/pivot/scaleInputState.spec.ts +11 -2
  217. package/src/modules/pivot/usePivot.spec.ts +17 -3
  218. package/src/modules/pivot/usePivotSwipeInput.spec.ts +182 -123
  219. package/src/modules/stack/SwipeStackContent.spec.tsx +387 -100
  220. package/src/modules/stack/SwipeStackContent.tsx +43 -33
  221. package/src/modules/stack/SwipeStackOutlet.spec.tsx +14 -16
  222. package/src/modules/stack/SwipeStackOutlet.tsx +6 -6
  223. package/src/modules/stack/computeSwipeStackTransform.spec.ts +5 -5
  224. package/src/modules/stack/computeSwipeStackTransform.ts +3 -3
  225. package/src/modules/stack/swipeTransitionContinuity.spec.tsx +1133 -0
  226. package/src/modules/stack/useStackAnimationState.spec.ts +3 -1
  227. package/src/modules/stack/useStackAnimationState.ts +18 -13
  228. package/src/modules/stack/useStackNavigation.spec.ts +198 -3
  229. package/src/modules/stack/useStackNavigation.tsx +113 -56
  230. package/src/modules/stack/useStackSwipeInput.spec.ts +65 -32
  231. package/src/modules/stack/useStackSwipeInput.ts +1 -1
  232. package/src/sticky-header/StickyArea.tsx +29 -57
  233. package/src/sticky-header/calculateStickyMetrics.spec.ts +105 -0
  234. package/src/sticky-header/calculateStickyMetrics.ts +50 -0
  235. package/src/types.ts +33 -0
  236. package/src/window/index.ts +2 -0
  237. package/dist/FloatingWindow-BpdOpg_L.js +0 -400
  238. package/dist/FloatingWindow-BpdOpg_L.js.map +0 -1
  239. package/dist/FloatingWindow-TCDNY5gE.cjs +0 -2
  240. package/dist/FloatingWindow-TCDNY5gE.cjs.map +0 -1
  241. package/dist/GridLayout-B4VRsC0r.cjs +0 -2
  242. package/dist/GridLayout-BltqeCPK.js +0 -927
  243. package/dist/PanelSystem-Bs8bQwQF.cjs +0 -3
  244. package/dist/PanelSystem-Bs8bQwQF.cjs.map +0 -1
  245. package/dist/PanelSystem-Dr1TBhxM.js.map +0 -1
  246. package/dist/ResizeHandle-CScipO5l.cjs +0 -2
  247. package/dist/SwipePivotTabBar-BGO9X94m.js +0 -407
  248. package/dist/SwipePivotTabBar-BGO9X94m.js.map +0 -1
  249. package/dist/SwipePivotTabBar-BrQismcZ.cjs +0 -2
  250. package/dist/SwipePivotTabBar-BrQismcZ.cjs.map +0 -1
  251. package/dist/useDocumentPointerEvents-CKdhGXd0.js +0 -46
  252. package/dist/useDocumentPointerEvents-CKdhGXd0.js.map +0 -1
  253. package/dist/useDocumentPointerEvents-ChqrKXDk.cjs +0 -2
  254. package/dist/useDocumentPointerEvents-ChqrKXDk.cjs.map +0 -1
  255. package/dist/useEffectEvent-Dp7HLCf0.js +0 -13
  256. package/dist/useEffectEvent-Dp7HLCf0.js.map +0 -1
  257. package/dist/useEffectEvent-huSsGUnl.cjs +0 -2
  258. package/dist/useEffectEvent-huSsGUnl.cjs.map +0 -1
package/dist/window.js CHANGED
@@ -1,149 +1,160 @@
1
- import { D as $, b as A, F as G, P as K, d as W } from "./FloatingWindow-BpdOpg_L.js";
1
+ import { D as A, b as G, F as K, P as T, S as W, d as q } from "./FloatingWindow-Bw2djgpz.js";
2
2
  import { jsx as m } from "react/jsx-runtime";
3
- import * as i from "react";
4
- import { u as p } from "./useEffectEvent-Dp7HLCf0.js";
5
- import { u as D } from "./useIsomorphicLayoutEffect-DhmEnmZ_.js";
6
- import { D as E } from "./styles-DPPuJ0sf.js";
7
- import { u as q } from "./useFloatingState-tEfA_wbc.js";
8
- const M = () => typeof window > "u" ? { width: 0, height: 0 } : {
3
+ import * as c from "react";
4
+ import { u as p } from "./useDocumentPointerEvents-DXxw3qWj.js";
5
+ import { u as x } from "./useIsomorphicLayoutEffect-DhmEnmZ_.js";
6
+ import { D as z } from "./styles-NkjuMOVS.js";
7
+ import { u as J } from "./useFloatingState-tEfA_wbc.js";
8
+ const D = () => typeof window > "u" ? { width: 0, height: 0 } : {
9
9
  width: window.innerWidth,
10
10
  height: window.innerHeight
11
- }, O = (e, o, t, c, n) => {
12
- const r = e + t > n.width ? Math.max(0, n.width - t) : e, s = o + c > n.height ? Math.max(0, n.height - c) : o;
13
- return { x: r, y: s };
14
- }, b = /* @__PURE__ */ new Map(), z = (e) => {
15
- const { box: o = "content-box" } = e, t = `resize-box:${o}`, c = b.get(t);
16
- if (c)
17
- return c;
18
- const n = new class {
19
- #e = /* @__PURE__ */ new Map();
20
- #t = new ResizeObserver((r, s) => {
21
- r.forEach((u) => {
22
- const a = this.#e.get(u.target);
23
- a && a(u, s);
24
- });
25
- });
26
- observe(r, s) {
27
- return this.#e.set(r, s), this.#t.observe(r, e), () => {
28
- this.#e.delete(r), this.#t.unobserve(r);
11
+ }, O = (e, t, n, o, r) => {
12
+ const s = e + n > r.width ? Math.max(0, r.width - n) : e, i = t + o > r.height ? Math.max(0, r.height - o) : t;
13
+ return { x: s, y: i };
14
+ }, b = /* @__PURE__ */ new Map(), R = (e) => {
15
+ const t = `resize-box:${e}`, n = b.get(t);
16
+ if (n)
17
+ return n;
18
+ const o = /* @__PURE__ */ new Map(), r = new ResizeObserver((i) => {
19
+ for (const a of i) {
20
+ const u = o.get(a.target);
21
+ u && u(a);
22
+ }
23
+ }), s = {
24
+ observe(i, a) {
25
+ return o.set(i, a), r.observe(i, { box: e }), () => {
26
+ o.delete(i), r.unobserve(i);
29
27
  };
30
28
  }
31
- }();
32
- return b.set(t, n), n;
29
+ };
30
+ return b.set(t, s), s;
31
+ }, E = (e) => {
32
+ const t = e.getBoundingClientRect();
33
+ return {
34
+ target: e,
35
+ contentRect: t,
36
+ borderBoxSize: [{ inlineSize: t.width, blockSize: t.height }],
37
+ contentBoxSize: [{ inlineSize: t.width, blockSize: t.height }],
38
+ devicePixelContentBoxSize: []
39
+ };
40
+ }, M = (e) => {
41
+ if (e.borderBoxSize?.length > 0) {
42
+ const t = e.borderBoxSize[0];
43
+ return new DOMRect(0, 0, t.inlineSize, t.blockSize);
44
+ }
45
+ return e.contentRect;
33
46
  };
34
- function R(e, { box: o }) {
35
- const [t, c] = i.useState(null), n = e.current;
36
- i.useEffect(() => n ? z({ box: o }).observe(n, (u) => {
37
- c(u);
38
- }) : void 0, [o, n]);
39
- const r = i.useMemo(() => {
40
- if (!t)
41
- return null;
42
- if (t.borderBoxSize?.length > 0) {
43
- const s = t.borderBoxSize[0];
44
- return new DOMRect(0, 0, s.inlineSize, s.blockSize);
47
+ function C(e, { box: t = "content-box" }) {
48
+ const [n, o] = c.useState(null);
49
+ x(() => {
50
+ const s = e.current;
51
+ if (!s) {
52
+ o(null);
53
+ return;
45
54
  }
46
- return t.contentRect;
47
- }, [t]);
48
- return { entry: t, rect: r };
55
+ return o(E(s)), R(t).observe(s, o);
56
+ }, [e, t]);
57
+ const r = c.useMemo(() => n ? M(n) : null, [n]);
58
+ return { entry: n, rect: r };
49
59
  }
50
- const S = {
60
+ const P = {
51
61
  border: "none",
52
62
  padding: 0,
53
63
  background: "transparent"
54
- }, P = {
64
+ }, k = {
55
65
  position: "fixed",
56
- zIndex: E
57
- }, C = typeof window < "u" && typeof document < "u", L = ({
66
+ zIndex: z
67
+ }, B = typeof window < "u" && typeof document < "u", L = ({
58
68
  anchor: e,
59
- onClose: o,
60
- children: t,
61
- contentClassName: c,
62
- contentStyle: n,
63
- dataAttributes: r,
64
- onKeyDown: s,
65
- onPositionChange: u
69
+ onClose: t,
70
+ children: n,
71
+ contentClassName: o,
72
+ contentStyle: r,
73
+ dataAttributes: s,
74
+ onKeyDown: i,
75
+ onPositionChange: a
66
76
  }) => {
67
- const a = i.useRef(null), { rect: d } = R(a, { box: "border-box" }), l = i.useMemo(() => {
68
- const f = M(), w = d?.width ?? 0, g = d?.height ?? 0;
69
- return O(e.x, e.y, w, g, f);
70
- }, [e.x, e.y, d?.width, d?.height]), h = p(u);
71
- i.useEffect(() => {
77
+ const u = c.useRef(null), { rect: d } = C(u, { box: "border-box" }), l = c.useMemo(() => {
78
+ const f = D(), g = d?.width ?? 0, w = d?.height ?? 0;
79
+ return O(e.x, e.y, g, w, f);
80
+ }, [e.x, e.y, d?.width, d?.height]), h = p(a);
81
+ c.useEffect(() => {
72
82
  h?.(l);
73
83
  }, [l]);
74
- const y = p(o);
75
- i.useEffect(() => {
76
- const f = (w) => {
77
- w.target instanceof Node && a.current && !a.current.contains(w.target) && y();
84
+ const y = p(t);
85
+ c.useEffect(() => {
86
+ const f = (g) => {
87
+ g.target instanceof Node && u.current && !u.current.contains(g.target) && y();
78
88
  };
79
89
  return document.addEventListener("pointerdown", f), () => document.removeEventListener("pointerdown", f);
80
90
  }, []);
81
- const x = i.useMemo(
91
+ const v = c.useMemo(
82
92
  () => ({
83
- ...P,
84
- ...n,
93
+ ...k,
94
+ ...r,
85
95
  left: l.x,
86
96
  top: l.y
87
97
  }),
88
- [n, l.x, l.y]
89
- ), v = i.useMemo(() => r ? Object.entries(r).reduce((f, [w, g]) => (g == null || (f[`data-${w}`] = g), f), {}) : {}, [r]);
98
+ [r, l.x, l.y]
99
+ ), S = c.useMemo(() => s ? Object.entries(s).reduce((f, [g, w]) => (w == null || (f[`data-${g}`] = w), f), {}) : {}, [s]);
90
100
  return /* @__PURE__ */ m(
91
101
  "div",
92
102
  {
93
- ref: a,
94
- className: c,
95
- style: x,
96
- onKeyDown: s,
97
- ...v,
98
- children: t
103
+ ref: u,
104
+ className: o,
105
+ style: v,
106
+ onKeyDown: i,
107
+ ...S,
108
+ children: n
99
109
  }
100
110
  );
101
111
  }, I = ({
102
112
  visible: e,
103
- onClose: o,
104
- anchor: t,
105
- children: c,
106
- contentClassName: n,
107
- contentStyle: r,
108
- dataAttributes: s,
109
- onKeyDown: u,
110
- onPositionChange: a
113
+ onClose: t,
114
+ anchor: n,
115
+ children: o,
116
+ contentClassName: r,
117
+ contentStyle: s,
118
+ dataAttributes: i,
119
+ onKeyDown: a,
120
+ onPositionChange: u
111
121
  }) => {
112
- const d = i.useRef(null);
113
- D(() => {
122
+ const d = c.useRef(null);
123
+ x(() => {
114
124
  if (!d.current)
115
125
  return;
116
126
  const h = d.current;
117
127
  e ? h.showModal() : h.open && h.close();
118
128
  }, [e]);
119
- const l = i.useCallback(
129
+ const l = c.useCallback(
120
130
  (h) => {
121
- h.preventDefault(), o();
131
+ h.preventDefault(), t();
122
132
  },
123
- [o]
133
+ [t]
124
134
  );
125
- return /* @__PURE__ */ m("dialog", { ref: d, style: S, onCancel: l, children: /* @__PURE__ */ m(i.Activity, { mode: e ? "visible" : "hidden", children: /* @__PURE__ */ m(
135
+ return /* @__PURE__ */ m("dialog", { ref: d, style: P, onCancel: l, children: /* @__PURE__ */ m(c.Activity, { mode: e ? "visible" : "hidden", children: /* @__PURE__ */ m(
126
136
  L,
127
137
  {
128
- anchor: t,
129
- onClose: o,
130
- contentClassName: n,
131
- contentStyle: r,
132
- dataAttributes: s,
133
- onKeyDown: u,
134
- onPositionChange: a,
135
- children: c
138
+ anchor: n,
139
+ onClose: t,
140
+ contentClassName: r,
141
+ contentStyle: s,
142
+ dataAttributes: i,
143
+ onKeyDown: a,
144
+ onPositionChange: u,
145
+ children: o
136
146
  }
137
147
  ) }) });
138
- }, k = (e) => C ? /* @__PURE__ */ m(I, { ...e }) : null;
139
- k.displayName = "DialogOverlay";
148
+ }, N = (e) => B ? /* @__PURE__ */ m(I, { ...e }) : null;
149
+ N.displayName = "DialogOverlay";
140
150
  export {
141
- k as DialogOverlay,
142
- $ as Drawer,
143
- A as DrawerLayers,
144
- G as FloatingWindow,
145
- K as PopupLayerPortal,
146
- W as useDrawerState,
147
- q as useFloatingState
151
+ N as DialogOverlay,
152
+ A as Drawer,
153
+ G as DrawerLayers,
154
+ K as FloatingWindow,
155
+ T as PopupLayerPortal,
156
+ W as SwipeSafeZone,
157
+ q as useDrawerState,
158
+ J as useFloatingState
148
159
  };
149
160
  //# sourceMappingURL=window.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"window.js","sources":["../src/utils/dialogUtils.ts","../src/hooks/useResizeObserver.tsx","../src/components/window/DialogOverlay.tsx"],"sourcesContent":["/**\n * @file Dialog positioning utilities\n */\n\nexport type ViewportInfo = {\n width: number;\n height: number;\n};\n\n/**\n * Get viewport dimensions\n */\nexport const getViewportInfo = (): ViewportInfo => {\n if (typeof window === \"undefined\") {\n return { width: 0, height: 0 };\n }\n\n return {\n width: window.innerWidth,\n height: window.innerHeight,\n };\n};\n\n/**\n * Calculate context menu position to keep it within viewport\n */\nexport const calculateContextMenuPosition = (\n anchorX: number,\n anchorY: number,\n menuWidth: number,\n menuHeight: number,\n viewport: ViewportInfo,\n): { x: number; y: number } => {\n // Adjust horizontal position if menu would overflow\n const x =\n anchorX + menuWidth > viewport.width ? Math.max(0, viewport.width - menuWidth) : anchorX;\n\n // Adjust vertical position if menu would overflow\n const y =\n anchorY + menuHeight > viewport.height ? Math.max(0, viewport.height - menuHeight) : anchorY;\n\n return { x, y };\n};\n","/**\n * @file Shared useResizeObserver hook with cached observer instances.\n */\nimport * as React from \"react\";\n\ntype Unobserve = () => void;\ntype Callback = (entry: ResizeObserverEntry, observer: ResizeObserver) => void;\ntype SharedObserver = {\n observe: (target: Element, callback: Callback) => Unobserve;\n};\nconst observerCache = new Map<string, SharedObserver>();\nconst getSharedObserver = (options: ResizeObserverOptions) => {\n const { box = \"content-box\" } = options;\n const observerKey = `resize-box:${box}`;\n const cached = observerCache.get(observerKey);\n if (cached) {\n return cached;\n }\n const observer = new (class {\n #callbackMap = new Map<Element, Callback>();\n #resizeObserver = new ResizeObserver((entries, observer) => {\n entries.forEach((entry) => {\n const callback = this.#callbackMap.get(entry.target);\n if (callback) {\n callback(entry, observer);\n }\n });\n });\n observe(target: Element, callback: Callback) {\n this.#callbackMap.set(target, callback);\n this.#resizeObserver.observe(target, options);\n return () => {\n this.#callbackMap.delete(target);\n this.#resizeObserver.unobserve(target);\n };\n }\n })();\n observerCache.set(observerKey, observer);\n\n return observer;\n};\n/**\n * Observe size changes for a given element reference using shared resize observers.\n *\n * @param ref - Ref holding the element whose size to monitor.\n * @param options - Resize observer configuration.\n * @returns Latest resize entry and a derived DOMRect snapshot.\n */\nexport function useResizeObserver<T extends HTMLElement>(\n ref: React.RefObject<T | null>,\n { box }: ResizeObserverOptions,\n) {\n const [entry, setEntry] = React.useState<ResizeObserverEntry | null>(null);\n const target = ref.current;\n\n React.useEffect(() => {\n if (!target) {\n return;\n }\n\n const observer = getSharedObserver({ box });\n return observer.observe(target, (nextEntry) => {\n setEntry(nextEntry);\n });\n }, [box, target]);\n\n const rect = React.useMemo(() => {\n if (!entry) {\n return null;\n }\n\n if (entry.borderBoxSize?.length > 0) {\n const size = entry.borderBoxSize[0];\n return new DOMRect(0, 0, size.inlineSize, size.blockSize);\n }\n\n return entry.contentRect;\n }, [entry]);\n\n return { entry, rect };\n}\n","/**\n * @file Dialog-based overlay component with automatic positioning\n */\nimport * as React from \"react\";\nimport type { Position } from \"../../types\";\nimport { calculateContextMenuPosition, getViewportInfo } from \"../../utils/dialogUtils\";\nimport { ensureDialogPolyfill } from \"../../utils/polyfills/createDialogPolyfill\";\nimport { useEffectEvent } from \"../../hooks/useEffectEvent\";\nimport { useIsomorphicLayoutEffect } from \"../../hooks/useIsomorphicLayoutEffect\";\nimport { useResizeObserver } from \"../../hooks/useResizeObserver\";\nimport { DIALOG_OVERLAY_Z_INDEX } from \"../../constants/styles\";\n\nconst contextDialogStyle: React.CSSProperties = {\n border: \"none\",\n padding: 0,\n background: \"transparent\",\n};\n\nconst contextContentStyle: React.CSSProperties = {\n position: \"fixed\",\n zIndex: DIALOG_OVERLAY_Z_INDEX,\n};\n\ntype DataAttributes = Record<string, string | number | boolean>;\n\nexport type DialogOverlayProps = {\n anchor: Position;\n visible: boolean;\n onClose: () => void;\n children: React.ReactNode;\n contentClassName?: string;\n contentStyle?: React.CSSProperties;\n dataAttributes?: Record<string, string | number | boolean | null | undefined>;\n onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;\n onPositionChange?: (position: Position) => void;\n};\n\nconst isBrowser = typeof window !== \"undefined\" && typeof document !== \"undefined\";\n\nensureDialogPolyfill();\n\nconst DialogOverlayContent: React.FC<Omit<DialogOverlayProps, \"visible\">> = ({\n anchor,\n onClose,\n children,\n contentClassName,\n contentStyle,\n dataAttributes,\n onKeyDown,\n onPositionChange,\n}) => {\n const contentRef = React.useRef<HTMLDivElement>(null);\n const { rect } = useResizeObserver(contentRef, { box: \"border-box\" });\n\n const computedPosition = React.useMemo(() => {\n const viewport = getViewportInfo();\n const width = rect?.width ?? 0;\n const height = rect?.height ?? 0;\n return calculateContextMenuPosition(anchor.x, anchor.y, width, height, viewport);\n }, [anchor.x, anchor.y, rect?.width, rect?.height]);\n\n const handlePositionChange = useEffectEvent(onPositionChange);\n\n React.useEffect(() => {\n handlePositionChange?.(computedPosition);\n }, [computedPosition]);\n\n const handleClose = useEffectEvent(onClose);\n\n React.useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n if (!(event.target instanceof Node)) {\n return;\n }\n if (contentRef.current && !contentRef.current.contains(event.target)) {\n handleClose();\n }\n };\n\n document.addEventListener(\"pointerdown\", handlePointerDown);\n return () => document.removeEventListener(\"pointerdown\", handlePointerDown);\n }, []);\n\n const mergedStyle: React.CSSProperties = React.useMemo(\n () => ({\n ...contextContentStyle,\n ...contentStyle,\n left: computedPosition.x,\n top: computedPosition.y,\n }),\n [contentStyle, computedPosition.x, computedPosition.y],\n );\n\n const dataProps = React.useMemo<DataAttributes>(() => {\n if (!dataAttributes) {\n return {};\n }\n return Object.entries(dataAttributes).reduce<DataAttributes>((acc, [key, value]) => {\n if (value === null || value === undefined) {\n return acc;\n }\n acc[`data-${key}`] = value;\n return acc;\n }, {});\n }, [dataAttributes]);\n\n return (\n <div\n ref={contentRef}\n className={contentClassName}\n style={mergedStyle}\n onKeyDown={onKeyDown}\n {...dataProps}\n >\n {children}\n </div>\n );\n};\n\nconst DialogOverlayImpl: React.FC<DialogOverlayProps> = ({\n visible,\n onClose,\n anchor,\n children,\n contentClassName,\n contentStyle,\n dataAttributes,\n onKeyDown,\n onPositionChange,\n}) => {\n const dialogRef = React.useRef<HTMLDialogElement>(null);\n\n useIsomorphicLayoutEffect(() => {\n if (!dialogRef.current) {\n return;\n }\n\n const dialog = dialogRef.current;\n if (visible) {\n dialog.showModal();\n } else if (dialog.open) {\n dialog.close();\n }\n }, [visible]);\n\n const handleCancel = React.useCallback(\n (event: React.SyntheticEvent) => {\n event.preventDefault();\n onClose();\n },\n [onClose],\n );\n\n return (\n <dialog ref={dialogRef} style={contextDialogStyle} onCancel={handleCancel}>\n <React.Activity mode={visible ? \"visible\" : \"hidden\"}>\n <DialogOverlayContent\n anchor={anchor}\n onClose={onClose}\n contentClassName={contentClassName}\n contentStyle={contentStyle}\n dataAttributes={dataAttributes}\n onKeyDown={onKeyDown}\n onPositionChange={onPositionChange}\n >\n {children}\n </DialogOverlayContent>\n </React.Activity>\n </dialog>\n );\n};\n\nexport const DialogOverlay: React.FC<DialogOverlayProps> = (props) => {\n if (!isBrowser) {\n return null;\n }\n return <DialogOverlayImpl {...props} />;\n};\n\nDialogOverlay.displayName = \"DialogOverlay\";\n"],"names":["getViewportInfo","calculateContextMenuPosition","anchorX","anchorY","menuWidth","menuHeight","viewport","x","y","observerCache","getSharedObserver","options","box","observerKey","cached","observer","#callbackMap","#resizeObserver","entries","entry","callback","target","useResizeObserver","ref","setEntry","React","nextEntry","rect","size","contextDialogStyle","contextContentStyle","DIALOG_OVERLAY_Z_INDEX","isBrowser","DialogOverlayContent","anchor","onClose","children","contentClassName","contentStyle","dataAttributes","onKeyDown","onPositionChange","contentRef","computedPosition","width","height","handlePositionChange","useEffectEvent","handleClose","handlePointerDown","event","mergedStyle","dataProps","acc","key","value","jsx","DialogOverlayImpl","visible","dialogRef","useIsomorphicLayoutEffect","dialog","handleCancel","DialogOverlay","props"],"mappings":"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"}
1
+ {"version":3,"file":"window.js","sources":["../src/utils/dialogUtils.ts","../src/hooks/useResizeObserver.tsx","../src/components/window/DialogOverlay.tsx"],"sourcesContent":["/**\n * @file Dialog positioning utilities\n */\n\nexport type ViewportInfo = {\n width: number;\n height: number;\n};\n\n/**\n * Get viewport dimensions\n */\nexport const getViewportInfo = (): ViewportInfo => {\n if (typeof window === \"undefined\") {\n return { width: 0, height: 0 };\n }\n\n return {\n width: window.innerWidth,\n height: window.innerHeight,\n };\n};\n\n/**\n * Calculate context menu position to keep it within viewport\n */\nexport const calculateContextMenuPosition = (\n anchorX: number,\n anchorY: number,\n menuWidth: number,\n menuHeight: number,\n viewport: ViewportInfo,\n): { x: number; y: number } => {\n // Adjust horizontal position if menu would overflow\n const x =\n anchorX + menuWidth > viewport.width ? Math.max(0, viewport.width - menuWidth) : anchorX;\n\n // Adjust vertical position if menu would overflow\n const y =\n anchorY + menuHeight > viewport.height ? Math.max(0, viewport.height - menuHeight) : anchorY;\n\n return { x, y };\n};\n","/**\n * @file Shared useResizeObserver hook with cached observer instances.\n *\n * Provides element size observation with shared observers for memory efficiency.\n * Size becomes available after the first useLayoutEffect cycle completes.\n *\n * Note: Due to React's effect execution order (children before parents),\n * child components may see containerSize=0 on their first effect run.\n * This is a React constraint, not a bug. Consumers should check for\n * valid size before using it for calculations like animation positions.\n */\nimport * as React from \"react\";\nimport { useIsomorphicLayoutEffect } from \"./useIsomorphicLayoutEffect.js\";\n\n/**\n * Shared ResizeObserver that can observe multiple elements.\n */\ntype SharedObserver = {\n observe: (target: Element, callback: (entry: ResizeObserverEntry) => void) => () => void;\n};\n\n/** Cache of shared observers per box option */\nconst observerCache = new Map<string, SharedObserver>();\n\n/**\n * Get or create a shared ResizeObserver for the given box option.\n */\nconst getSharedObserver = (box: ResizeObserverBoxOptions): SharedObserver => {\n const observerKey = `resize-box:${box}`;\n const cached = observerCache.get(observerKey);\n if (cached) {\n return cached;\n }\n\n const callbacks = new Map<Element, (entry: ResizeObserverEntry) => void>();\n\n const resizeObserver = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const callback = callbacks.get(entry.target);\n if (callback) {\n callback(entry);\n }\n }\n });\n\n const sharedObserver: SharedObserver = {\n observe(target, callback) {\n callbacks.set(target, callback);\n resizeObserver.observe(target, { box });\n\n return () => {\n callbacks.delete(target);\n resizeObserver.unobserve(target);\n };\n },\n };\n\n observerCache.set(observerKey, sharedObserver);\n return sharedObserver;\n};\n\n/**\n * Create a ResizeObserverEntry from getBoundingClientRect.\n */\nconst measureElement = (target: Element): ResizeObserverEntry => {\n const rect = target.getBoundingClientRect();\n return {\n target,\n contentRect: rect,\n borderBoxSize: [{ inlineSize: rect.width, blockSize: rect.height }],\n contentBoxSize: [{ inlineSize: rect.width, blockSize: rect.height }],\n devicePixelContentBoxSize: [],\n };\n};\n\n/**\n * Extract DOMRect from ResizeObserverEntry.\n */\nconst entryToRect = (entry: ResizeObserverEntry): DOMRect => {\n if (entry.borderBoxSize?.length > 0) {\n const size = entry.borderBoxSize[0];\n return new DOMRect(0, 0, size.inlineSize, size.blockSize);\n }\n return entry.contentRect;\n};\n\n/**\n * Clear observer cache. Exported for testing purposes.\n */\nexport function clearObserverCache(): void {\n observerCache.clear();\n}\n\n/**\n * Observe size changes for a given element reference using shared resize observers.\n *\n * @param ref - Ref holding the element whose size to monitor.\n * @param options - Resize observer configuration.\n * @returns Latest resize entry and a derived DOMRect snapshot.\n *\n * @remarks\n * The `rect` will be `null` on the first render. After the initial\n * useLayoutEffect runs and triggers a re-render, `rect` will contain\n * the measured size.\n *\n * Due to React's effect execution order, child components' effects run\n * before parent effects. If you pass `rect.width` to a child as a prop,\n * the child's first effect will see `0` (or whatever default you use).\n * This is expected React behavior.\n *\n * @example\n * ```tsx\n * const containerRef = useRef<HTMLDivElement>(null);\n * const { rect } = useResizeObserver(containerRef, { box: \"border-box\" });\n * const width = rect?.width ?? 0;\n *\n * // Check if size is ready before using for calculations\n * const isReady = rect !== null;\n * ```\n */\nexport function useResizeObserver<T extends HTMLElement>(\n ref: React.RefObject<T | null>,\n { box = \"content-box\" }: ResizeObserverOptions,\n) {\n const [entry, setEntry] = React.useState<ResizeObserverEntry | null>(null);\n\n useIsomorphicLayoutEffect(() => {\n const target = ref.current;\n if (!target) {\n setEntry(null);\n return;\n }\n\n // Measure immediately\n setEntry(measureElement(target));\n\n // Set up ResizeObserver for subsequent updates\n const observer = getSharedObserver(box);\n return observer.observe(target, setEntry);\n }, [ref, box]);\n\n const rect = React.useMemo(() => {\n if (!entry) {\n return null;\n }\n return entryToRect(entry);\n }, [entry]);\n\n return { entry, rect };\n}\n","/**\n * @file Dialog-based overlay component with automatic positioning\n */\nimport * as React from \"react\";\nimport type { Position } from \"../../types\";\nimport { calculateContextMenuPosition, getViewportInfo } from \"../../utils/dialogUtils\";\nimport { ensureDialogPolyfill } from \"../../utils/polyfills/createDialogPolyfill\";\nimport { useEffectEvent } from \"../../hooks/useEffectEvent\";\nimport { useIsomorphicLayoutEffect } from \"../../hooks/useIsomorphicLayoutEffect\";\nimport { useResizeObserver } from \"../../hooks/useResizeObserver\";\nimport { DIALOG_OVERLAY_Z_INDEX } from \"../../constants/styles\";\n\nconst contextDialogStyle: React.CSSProperties = {\n border: \"none\",\n padding: 0,\n background: \"transparent\",\n};\n\nconst contextContentStyle: React.CSSProperties = {\n position: \"fixed\",\n zIndex: DIALOG_OVERLAY_Z_INDEX,\n};\n\ntype DataAttributes = Record<string, string | number | boolean>;\n\nexport type DialogOverlayProps = {\n anchor: Position;\n visible: boolean;\n onClose: () => void;\n children: React.ReactNode;\n contentClassName?: string;\n contentStyle?: React.CSSProperties;\n dataAttributes?: Record<string, string | number | boolean | null | undefined>;\n onKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;\n onPositionChange?: (position: Position) => void;\n};\n\nconst isBrowser = typeof window !== \"undefined\" && typeof document !== \"undefined\";\n\nensureDialogPolyfill();\n\nconst DialogOverlayContent: React.FC<Omit<DialogOverlayProps, \"visible\">> = ({\n anchor,\n onClose,\n children,\n contentClassName,\n contentStyle,\n dataAttributes,\n onKeyDown,\n onPositionChange,\n}) => {\n const contentRef = React.useRef<HTMLDivElement>(null);\n const { rect } = useResizeObserver(contentRef, { box: \"border-box\" });\n\n const computedPosition = React.useMemo(() => {\n const viewport = getViewportInfo();\n const width = rect?.width ?? 0;\n const height = rect?.height ?? 0;\n return calculateContextMenuPosition(anchor.x, anchor.y, width, height, viewport);\n }, [anchor.x, anchor.y, rect?.width, rect?.height]);\n\n const handlePositionChange = useEffectEvent(onPositionChange);\n\n React.useEffect(() => {\n handlePositionChange?.(computedPosition);\n }, [computedPosition]);\n\n const handleClose = useEffectEvent(onClose);\n\n React.useEffect(() => {\n const handlePointerDown = (event: PointerEvent) => {\n if (!(event.target instanceof Node)) {\n return;\n }\n if (contentRef.current && !contentRef.current.contains(event.target)) {\n handleClose();\n }\n };\n\n document.addEventListener(\"pointerdown\", handlePointerDown);\n return () => document.removeEventListener(\"pointerdown\", handlePointerDown);\n }, []);\n\n const mergedStyle: React.CSSProperties = React.useMemo(\n () => ({\n ...contextContentStyle,\n ...contentStyle,\n left: computedPosition.x,\n top: computedPosition.y,\n }),\n [contentStyle, computedPosition.x, computedPosition.y],\n );\n\n const dataProps = React.useMemo<DataAttributes>(() => {\n if (!dataAttributes) {\n return {};\n }\n return Object.entries(dataAttributes).reduce<DataAttributes>((acc, [key, value]) => {\n if (value === null || value === undefined) {\n return acc;\n }\n acc[`data-${key}`] = value;\n return acc;\n }, {});\n }, [dataAttributes]);\n\n return (\n <div\n ref={contentRef}\n className={contentClassName}\n style={mergedStyle}\n onKeyDown={onKeyDown}\n {...dataProps}\n >\n {children}\n </div>\n );\n};\n\nconst DialogOverlayImpl: React.FC<DialogOverlayProps> = ({\n visible,\n onClose,\n anchor,\n children,\n contentClassName,\n contentStyle,\n dataAttributes,\n onKeyDown,\n onPositionChange,\n}) => {\n const dialogRef = React.useRef<HTMLDialogElement>(null);\n\n useIsomorphicLayoutEffect(() => {\n if (!dialogRef.current) {\n return;\n }\n\n const dialog = dialogRef.current;\n if (visible) {\n dialog.showModal();\n } else if (dialog.open) {\n dialog.close();\n }\n }, [visible]);\n\n const handleCancel = React.useCallback(\n (event: React.SyntheticEvent) => {\n event.preventDefault();\n onClose();\n },\n [onClose],\n );\n\n return (\n <dialog ref={dialogRef} style={contextDialogStyle} onCancel={handleCancel}>\n <React.Activity mode={visible ? \"visible\" : \"hidden\"}>\n <DialogOverlayContent\n anchor={anchor}\n onClose={onClose}\n contentClassName={contentClassName}\n contentStyle={contentStyle}\n dataAttributes={dataAttributes}\n onKeyDown={onKeyDown}\n onPositionChange={onPositionChange}\n >\n {children}\n </DialogOverlayContent>\n </React.Activity>\n </dialog>\n );\n};\n\nexport const DialogOverlay: React.FC<DialogOverlayProps> = (props) => {\n if (!isBrowser) {\n return null;\n }\n return <DialogOverlayImpl {...props} />;\n};\n\nDialogOverlay.displayName = \"DialogOverlay\";\n"],"names":["getViewportInfo","calculateContextMenuPosition","anchorX","anchorY","menuWidth","menuHeight","viewport","x","y","observerCache","getSharedObserver","box","observerKey","cached","callbacks","resizeObserver","entries","entry","callback","sharedObserver","target","measureElement","rect","entryToRect","size","useResizeObserver","ref","setEntry","React","useIsomorphicLayoutEffect","contextDialogStyle","contextContentStyle","DIALOG_OVERLAY_Z_INDEX","isBrowser","DialogOverlayContent","anchor","onClose","children","contentClassName","contentStyle","dataAttributes","onKeyDown","onPositionChange","contentRef","computedPosition","width","height","handlePositionChange","useEffectEvent","handleClose","handlePointerDown","event","mergedStyle","dataProps","acc","key","value","jsx","DialogOverlayImpl","visible","dialogRef","dialog","handleCancel","DialogOverlay","props"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-panel-layout",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "license": "Unlicense",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -62,6 +62,11 @@
62
62
  "import": "./dist/panels.js",
63
63
  "require": "./dist/panels.cjs"
64
64
  },
65
+ "./dialog": {
66
+ "types": "./dist/dialog/index.d.ts",
67
+ "import": "./dist/dialog.js",
68
+ "require": "./dist/dialog.cjs"
69
+ },
65
70
  "./package.json": "./package.json"
66
71
  },
67
72
  "files": [
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @file SwipeSafeZone component
3
+ *
4
+ * A wrapper component that marks an area as exempt from swipe gesture detection.
5
+ * Content inside this zone will not trigger swipe-to-close or other swipe gestures.
6
+ *
7
+ * Use this for:
8
+ * - Scrollable content areas
9
+ * - Input fields and text areas
10
+ * - Interactive elements that need drag/swipe for their own purposes
11
+ */
12
+ import * as React from "react";
13
+
14
+ /**
15
+ * Data attribute used to identify swipe-safe zones.
16
+ * Swipe gesture handlers should check for this attribute on target elements.
17
+ */
18
+ export const SWIPE_SAFE_ZONE_ATTR = "data-swipe-safe-zone";
19
+
20
+ export type SwipeSafeZoneProps = {
21
+ /** Content to render inside the safe zone */
22
+ children: React.ReactNode;
23
+ /** Additional CSS class name */
24
+ className?: string;
25
+ /** Additional inline styles */
26
+ style?: React.CSSProperties;
27
+ };
28
+
29
+ /**
30
+ * SwipeSafeZone marks an area where swipe gestures should not be triggered.
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * <SwipeSafeZone>
35
+ * <ScrollableList items={items} />
36
+ * </SwipeSafeZone>
37
+ * ```
38
+ */
39
+ export const SwipeSafeZone: React.FC<SwipeSafeZoneProps> = ({
40
+ children,
41
+ className,
42
+ style,
43
+ }) => {
44
+ return (
45
+ <div
46
+ className={className}
47
+ style={style}
48
+ data-swipe-safe-zone="true"
49
+ >
50
+ {children}
51
+ </div>
52
+ );
53
+ };
54
+
55
+ /**
56
+ * Check if an element is inside a SwipeSafeZone.
57
+ */
58
+ export function isInSwipeSafeZone(element: HTMLElement, container: HTMLElement): boolean {
59
+ // eslint-disable-next-line no-restricted-syntax -- loop variable requires let
60
+ let current: HTMLElement | null = element;
61
+
62
+ while (current && current !== container) {
63
+ if (current.hasAttribute(SWIPE_SAFE_ZONE_ATTR)) {
64
+ return true;
65
+ }
66
+ current = current.parentElement;
67
+ }
68
+
69
+ return false;
70
+ }
@@ -5,6 +5,7 @@ import * as React from "react";
5
5
  import { useIntersectionObserver } from "../../hooks/useIntersectionObserver";
6
6
  import type { LayerDefinition, PanelLayoutConfig } from "../../types";
7
7
  import { DrawerLayers } from "../window/DrawerLayers";
8
+ import { DrawerRevealProvider, useDrawerReveal, isRevealMode } from "../window/DrawerRevealContext";
8
9
  import { GridLayerList } from "./GridLayerList";
9
10
  import { GridTrackResizeHandle } from "./GridTrackResizeHandle";
10
11
  import { PanelSystemProvider, usePanelSystem } from "../../PanelSystemContext";
@@ -18,6 +19,7 @@ const gridLayoutBaseStyle: React.CSSProperties = {
18
19
  width: "100%",
19
20
  height: "100%",
20
21
  overflow: "hidden",
22
+ position: "relative",
21
23
  };
22
24
 
23
25
  const gridLayoutDraggingStyle: React.CSSProperties = {
@@ -55,7 +57,9 @@ export const GridLayout: React.FC<GridLayoutProps> = ({ config, layers, style: s
55
57
 
56
58
  return (
57
59
  <PanelSystemProvider config={config} layers={layers} style={styleProp}>
58
- <GridLayoutInner gridRef={gridRef} isIntersecting={isIntersecting} isRoot={root} />
60
+ <DrawerRevealProvider>
61
+ <GridLayoutInner gridRef={gridRef} isIntersecting={isIntersecting} isRoot={root} />
62
+ </DrawerRevealProvider>
59
63
  </PanelSystemProvider>
60
64
  );
61
65
  };
@@ -74,6 +78,15 @@ const GridLayoutInner: React.FC<{
74
78
  isRootLevel: isRoot,
75
79
  });
76
80
 
81
+ // Register gridRef in reveal context for inline mode drawers
82
+ const { setGridRef } = useDrawerReveal();
83
+ React.useLayoutEffect(() => {
84
+ setGridRef(gridRef);
85
+ return () => {
86
+ setGridRef(null);
87
+ };
88
+ }, [gridRef, setGridRef]);
89
+
77
90
  const isDraggingOrResizing = draggingLayerId ? true : Boolean(resizingLayerId);
78
91
  const combinedStyle = React.useMemo(() => {
79
92
  const baseStyle = resolveGridBaseStyle(isRoot);
@@ -84,45 +97,104 @@ const GridLayoutInner: React.FC<{
84
97
  };
85
98
  }, [gridStyle, isDraggingOrResizing, isRoot]);
86
99
 
100
+ // Split drawer layers for proper rendering context:
101
+ // - Overlay inline drawers: inside grid container (for proper absolute positioning)
102
+ // - Reveal inline drawers: grid sibling in wrapper (drawer stays fixed while grid transforms)
103
+ // - Non-inline drawers: outside wrapper (viewport-relative fixed positioning)
104
+ const overlayInlineDrawerLayers = React.useMemo(
105
+ () => visibleLayers.filter((layer) => {
106
+ if (!layer.drawer?.inline) {
107
+ return false;
108
+ }
109
+ return !isRevealMode(layer.drawer.animationMode);
110
+ }),
111
+ [visibleLayers],
112
+ );
113
+ const revealInlineDrawerLayers = React.useMemo(
114
+ () => visibleLayers.filter((layer) => {
115
+ if (!layer.drawer?.inline) {
116
+ return false;
117
+ }
118
+ return isRevealMode(layer.drawer.animationMode);
119
+ }),
120
+ [visibleLayers],
121
+ );
122
+ const nonInlineDrawerLayers = React.useMemo(
123
+ () => visibleLayers.filter((layer) => {
124
+ if (!layer.drawer) {
125
+ return false;
126
+ }
127
+ return !layer.drawer.inline;
128
+ }),
129
+ [visibleLayers],
130
+ );
131
+
132
+ const hasRevealInlineDrawers = revealInlineDrawerLayers.length > 0;
133
+
134
+ // Grid container element
135
+ const gridElement = (
136
+ <div
137
+ ref={gridRef}
138
+ style={combinedStyle}
139
+ data-dragging={Boolean(draggingLayerId)}
140
+ data-resizing={Boolean(resizingLayerId)}
141
+ data-visible={isIntersecting}
142
+ >
143
+ <GridLayoutProvider value={providerValue}>
144
+ <GridLayerList layers={regularLayers} />
145
+ </GridLayoutProvider>
146
+
147
+ {columnHandles.map(({ trackIndex, align, span }) => (
148
+ <GridTrackResizeHandle
149
+ key={`col-${trackIndex}:${align}`}
150
+ direction="col"
151
+ trackIndex={trackIndex}
152
+ align={align}
153
+ gap={gapSizes.columnGap}
154
+ span={span}
155
+ onResize={handleResize}
156
+ />
157
+ ))}
158
+
159
+ {rowHandles.map(({ trackIndex, align, span }) => (
160
+ <GridTrackResizeHandle
161
+ key={`row-${trackIndex}:${align}`}
162
+ direction="row"
163
+ trackIndex={trackIndex}
164
+ align={align}
165
+ gap={gapSizes.rowGap}
166
+ span={span}
167
+ onResize={handleResize}
168
+ />
169
+ ))}
170
+
171
+ {/* Inline overlay drawers rendered inside grid container for proper absolute positioning */}
172
+ <DrawerLayers layers={overlayInlineDrawerLayers} />
173
+ </div>
174
+ );
175
+
176
+ // For reveal inline drawers, wrap grid and drawer in a container
177
+ // so drawer can be positioned relative to the container (not viewport)
178
+ // while grid transforms without affecting drawer position
179
+ if (hasRevealInlineDrawers) {
180
+ return (
181
+ <>
182
+ <div style={{ position: "relative", width: "100%", height: "100%" }}>
183
+ {gridElement}
184
+ {/* Reveal inline drawers as grid siblings - stay fixed while grid transforms */}
185
+ <DrawerLayers layers={revealInlineDrawerLayers} />
186
+ </div>
187
+ {/* Non-inline drawers outside wrapper for viewport-relative positioning */}
188
+ <DrawerLayers layers={nonInlineDrawerLayers} />
189
+ </>
190
+ );
191
+ }
192
+
87
193
  return (
88
194
  <>
89
- <div
90
- ref={gridRef}
91
- style={combinedStyle}
92
- data-dragging={Boolean(draggingLayerId)}
93
- data-resizing={Boolean(resizingLayerId)}
94
- data-visible={isIntersecting}
95
- >
96
- <GridLayoutProvider value={providerValue}>
97
- <GridLayerList layers={regularLayers} />
98
- </GridLayoutProvider>
99
-
100
- {columnHandles.map(({ trackIndex, align, span }) => (
101
- <GridTrackResizeHandle
102
- key={`col-${trackIndex}:${align}`}
103
- direction="col"
104
- trackIndex={trackIndex}
105
- align={align}
106
- gap={gapSizes.columnGap}
107
- span={span}
108
- onResize={handleResize}
109
- />
110
- ))}
111
-
112
- {rowHandles.map(({ trackIndex, align, span }) => (
113
- <GridTrackResizeHandle
114
- key={`row-${trackIndex}:${align}`}
115
- direction="row"
116
- trackIndex={trackIndex}
117
- align={align}
118
- gap={gapSizes.rowGap}
119
- span={span}
120
- onResize={handleResize}
121
- />
122
- ))}
123
- </div>
124
-
125
- <DrawerLayers layers={visibleLayers} />
195
+ {gridElement}
196
+ {/* Non-inline drawers for viewport-relative positioning */}
197
+ <DrawerLayers layers={nonInlineDrawerLayers} />
126
198
  </>
127
199
  );
128
200
  };