@mortenbrudvik/waveui 0.10.0 → 0.11.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 (184) hide show
  1. package/README.md +357 -72
  2. package/dist/components/button/Toolbar.cjs +1 -1
  3. package/dist/components/button/Toolbar.cjs.map +1 -1
  4. package/dist/components/button/Toolbar.mjs +25 -30
  5. package/dist/components/button/Toolbar.mjs.map +1 -1
  6. package/dist/components/button/Toolbar.navigation.cjs +2 -0
  7. package/dist/components/button/Toolbar.navigation.cjs.map +1 -0
  8. package/dist/components/button/Toolbar.navigation.mjs +17 -0
  9. package/dist/components/button/Toolbar.navigation.mjs.map +1 -0
  10. package/dist/components/data-display/Avatar.cjs +1 -1
  11. package/dist/components/data-display/Avatar.cjs.map +1 -1
  12. package/dist/components/data-display/Avatar.context.cjs +2 -0
  13. package/dist/components/data-display/Avatar.context.cjs.map +1 -0
  14. package/dist/components/data-display/Avatar.context.mjs +9 -0
  15. package/dist/components/data-display/Avatar.context.mjs.map +1 -0
  16. package/dist/components/data-display/Avatar.mjs +66 -61
  17. package/dist/components/data-display/Avatar.mjs.map +1 -1
  18. package/dist/components/data-display/InteractionTag.cjs +2 -0
  19. package/dist/components/data-display/InteractionTag.cjs.map +1 -0
  20. package/dist/components/data-display/InteractionTag.mjs +234 -0
  21. package/dist/components/data-display/InteractionTag.mjs.map +1 -0
  22. package/dist/components/data-display/Tag.cjs +1 -1
  23. package/dist/components/data-display/Tag.cjs.map +1 -1
  24. package/dist/components/data-display/Tag.mjs +222 -90
  25. package/dist/components/data-display/Tag.mjs.map +1 -1
  26. package/dist/components/data-display/TagGroup.cjs +2 -0
  27. package/dist/components/data-display/TagGroup.cjs.map +1 -0
  28. package/dist/components/data-display/TagGroup.context.cjs +2 -0
  29. package/dist/components/data-display/TagGroup.context.cjs.map +1 -0
  30. package/dist/components/data-display/TagGroup.context.mjs +113 -0
  31. package/dist/components/data-display/TagGroup.context.mjs.map +1 -0
  32. package/dist/components/data-display/TagGroup.mjs +149 -0
  33. package/dist/components/data-display/TagGroup.mjs.map +1 -0
  34. package/dist/components/data-display/tagStyles.cjs +2 -0
  35. package/dist/components/data-display/tagStyles.cjs.map +1 -0
  36. package/dist/components/data-display/tagStyles.mjs +108 -0
  37. package/dist/components/data-display/tagStyles.mjs.map +1 -0
  38. package/dist/components/feedback/Toaster.cjs +1 -1
  39. package/dist/components/feedback/Toaster.cjs.map +1 -1
  40. package/dist/components/feedback/Toaster.mjs +213 -181
  41. package/dist/components/feedback/Toaster.mjs.map +1 -1
  42. package/dist/components/input/Combobox.expand.cjs +1 -1
  43. package/dist/components/input/Combobox.expand.cjs.map +1 -1
  44. package/dist/components/input/Combobox.expand.mjs +7 -7
  45. package/dist/components/input/Combobox.expand.mjs.map +1 -1
  46. package/dist/components/input/Option.cjs +1 -1
  47. package/dist/components/input/Option.cjs.map +1 -1
  48. package/dist/components/input/Option.mjs +16 -11
  49. package/dist/components/input/Option.mjs.map +1 -1
  50. package/dist/components/input/SwatchPicker.cjs.map +1 -1
  51. package/dist/components/input/SwatchPicker.context.cjs.map +1 -1
  52. package/dist/components/input/SwatchPicker.context.mjs.map +1 -1
  53. package/dist/components/input/SwatchPicker.mjs.map +1 -1
  54. package/dist/components/input/TagPicker.cjs +1 -1
  55. package/dist/components/input/TagPicker.cjs.map +1 -1
  56. package/dist/components/input/TagPicker.context.cjs +2 -0
  57. package/dist/components/input/TagPicker.context.cjs.map +1 -0
  58. package/dist/components/input/TagPicker.context.mjs +20 -0
  59. package/dist/components/input/TagPicker.context.mjs.map +1 -0
  60. package/dist/components/input/TagPicker.create.cjs +2 -0
  61. package/dist/components/input/TagPicker.create.cjs.map +1 -0
  62. package/dist/components/input/TagPicker.create.mjs +24 -0
  63. package/dist/components/input/TagPicker.create.mjs.map +1 -0
  64. package/dist/components/input/TagPicker.mjs +13 -279
  65. package/dist/components/input/TagPicker.mjs.map +1 -1
  66. package/dist/components/input/TagPicker.option.cjs +2 -0
  67. package/dist/components/input/TagPicker.option.cjs.map +1 -0
  68. package/dist/components/input/TagPicker.option.mjs +45 -0
  69. package/dist/components/input/TagPicker.option.mjs.map +1 -0
  70. package/dist/components/input/TagPicker.overflow.cjs +2 -0
  71. package/dist/components/input/TagPicker.overflow.cjs.map +1 -0
  72. package/dist/components/input/TagPicker.overflow.mjs +153 -0
  73. package/dist/components/input/TagPicker.overflow.mjs.map +1 -0
  74. package/dist/components/input/TagPicker.parts.cjs +2 -0
  75. package/dist/components/input/TagPicker.parts.cjs.map +1 -0
  76. package/dist/components/input/TagPicker.parts.mjs +425 -0
  77. package/dist/components/input/TagPicker.parts.mjs.map +1 -0
  78. package/dist/components/input/TagPicker.root.cjs +2 -0
  79. package/dist/components/input/TagPicker.root.cjs.map +1 -0
  80. package/dist/components/input/TagPicker.root.mjs +416 -0
  81. package/dist/components/input/TagPicker.root.mjs.map +1 -0
  82. package/dist/components/layout/Accordion.cjs.map +1 -1
  83. package/dist/components/layout/Accordion.mjs.map +1 -1
  84. package/dist/components/navigation/Hamburger.cjs +2 -0
  85. package/dist/components/navigation/Hamburger.cjs.map +1 -0
  86. package/dist/components/navigation/Hamburger.mjs +54 -0
  87. package/dist/components/navigation/Hamburger.mjs.map +1 -0
  88. package/dist/components/navigation/Nav.cjs +1 -1
  89. package/dist/components/navigation/Nav.cjs.map +1 -1
  90. package/dist/components/navigation/Nav.context.cjs +2 -0
  91. package/dist/components/navigation/Nav.context.cjs.map +1 -0
  92. package/dist/components/navigation/Nav.context.mjs +137 -0
  93. package/dist/components/navigation/Nav.context.mjs.map +1 -0
  94. package/dist/components/navigation/Nav.mjs +151 -258
  95. package/dist/components/navigation/Nav.mjs.map +1 -1
  96. package/dist/components/navigation/Nav.parts.cjs +2 -0
  97. package/dist/components/navigation/Nav.parts.cjs.map +1 -0
  98. package/dist/components/navigation/Nav.parts.mjs +77 -0
  99. package/dist/components/navigation/Nav.parts.mjs.map +1 -0
  100. package/dist/components/navigation/Nav.root.cjs +2 -0
  101. package/dist/components/navigation/Nav.root.cjs.map +1 -0
  102. package/dist/components/navigation/Nav.root.mjs +78 -0
  103. package/dist/components/navigation/Nav.root.mjs.map +1 -0
  104. package/dist/components/navigation/NavDrawer.cjs +2 -0
  105. package/dist/components/navigation/NavDrawer.cjs.map +1 -0
  106. package/dist/components/navigation/NavDrawer.context.cjs +2 -0
  107. package/dist/components/navigation/NavDrawer.context.cjs.map +1 -0
  108. package/dist/components/navigation/NavDrawer.context.mjs +11 -0
  109. package/dist/components/navigation/NavDrawer.context.mjs.map +1 -0
  110. package/dist/components/navigation/NavDrawer.mjs +179 -0
  111. package/dist/components/navigation/NavDrawer.mjs.map +1 -0
  112. package/dist/components/overlays/Dialog.cjs +1 -1
  113. package/dist/components/overlays/Dialog.cjs.map +1 -1
  114. package/dist/components/overlays/Dialog.mjs +190 -125
  115. package/dist/components/overlays/Dialog.mjs.map +1 -1
  116. package/dist/components/overlays/Dialog.shared.cjs +1 -1
  117. package/dist/components/overlays/Dialog.shared.cjs.map +1 -1
  118. package/dist/components/overlays/Dialog.shared.mjs +157 -81
  119. package/dist/components/overlays/Dialog.shared.mjs.map +1 -1
  120. package/dist/components/overlays/Dialog.slots.cjs +2 -0
  121. package/dist/components/overlays/Dialog.slots.cjs.map +1 -0
  122. package/dist/components/overlays/Dialog.slots.mjs +129 -0
  123. package/dist/components/overlays/Dialog.slots.mjs.map +1 -0
  124. package/dist/components/overlays/Drawer.cjs +1 -1
  125. package/dist/components/overlays/Drawer.cjs.map +1 -1
  126. package/dist/components/overlays/Drawer.context.cjs +2 -0
  127. package/dist/components/overlays/Drawer.context.cjs.map +1 -0
  128. package/dist/components/overlays/Drawer.context.mjs +29 -0
  129. package/dist/components/overlays/Drawer.context.mjs.map +1 -0
  130. package/dist/components/overlays/Drawer.mjs +12 -187
  131. package/dist/components/overlays/Drawer.mjs.map +1 -1
  132. package/dist/components/overlays/Drawer.panel.cjs +2 -0
  133. package/dist/components/overlays/Drawer.panel.cjs.map +1 -0
  134. package/dist/components/overlays/Drawer.panel.mjs +159 -0
  135. package/dist/components/overlays/Drawer.panel.mjs.map +1 -0
  136. package/dist/components/overlays/Drawer.parts.cjs +2 -0
  137. package/dist/components/overlays/Drawer.parts.cjs.map +1 -0
  138. package/dist/components/overlays/Drawer.parts.mjs +152 -0
  139. package/dist/components/overlays/Drawer.parts.mjs.map +1 -0
  140. package/dist/components/overlays/Drawer.root.cjs +2 -0
  141. package/dist/components/overlays/Drawer.root.cjs.map +1 -0
  142. package/dist/components/overlays/Drawer.root.mjs +207 -0
  143. package/dist/components/overlays/Drawer.root.mjs.map +1 -0
  144. package/dist/components/overlays/Drawer.scroll.cjs +2 -0
  145. package/dist/components/overlays/Drawer.scroll.cjs.map +1 -0
  146. package/dist/components/overlays/Drawer.scroll.mjs +42 -0
  147. package/dist/components/overlays/Drawer.scroll.mjs.map +1 -0
  148. package/dist/hooks/useDismiss.cjs.map +1 -1
  149. package/dist/hooks/useDismiss.mjs.map +1 -1
  150. package/dist/hooks/useFocusTrap.cjs +1 -1
  151. package/dist/hooks/useFocusTrap.cjs.map +1 -1
  152. package/dist/hooks/useFocusTrap.mjs +115 -98
  153. package/dist/hooks/useFocusTrap.mjs.map +1 -1
  154. package/dist/hooks/useModalLayer.cjs +1 -1
  155. package/dist/hooks/useModalLayer.cjs.map +1 -1
  156. package/dist/hooks/useModalLayer.mjs +35 -22
  157. package/dist/hooks/useModalLayer.mjs.map +1 -1
  158. package/dist/hooks/useRestoreFocus.cjs +1 -1
  159. package/dist/hooks/useRestoreFocus.cjs.map +1 -1
  160. package/dist/hooks/useRestoreFocus.mjs +91 -78
  161. package/dist/hooks/useRestoreFocus.mjs.map +1 -1
  162. package/dist/hooks/useRovingTabIndex.cjs +1 -1
  163. package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
  164. package/dist/hooks/useRovingTabIndex.mjs +102 -78
  165. package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
  166. package/dist/index.cjs +1 -1
  167. package/dist/index.d.cts +2226 -221
  168. package/dist/index.d.ts +2226 -221
  169. package/dist/index.mjs +115 -107
  170. package/dist/lib/classNames.cjs +1 -1
  171. package/dist/lib/classNames.cjs.map +1 -1
  172. package/dist/lib/classNames.mjs +137 -77
  173. package/dist/lib/classNames.mjs.map +1 -1
  174. package/dist/lib/icons.cjs +1 -1
  175. package/dist/lib/icons.cjs.map +1 -1
  176. package/dist/lib/icons.mjs +13 -6
  177. package/dist/lib/icons.mjs.map +1 -1
  178. package/dist/lib/layers.cjs +1 -1
  179. package/dist/lib/layers.cjs.map +1 -1
  180. package/dist/lib/layers.mjs +53 -47
  181. package/dist/lib/layers.mjs.map +1 -1
  182. package/dist/styles.css +1 -1
  183. package/package.json +1 -1
  184. package/src/styles/tokens.css +25 -0
@@ -0,0 +1,2 @@
1
+ "use client";const e=require("../../_virtual/_rolldown/runtime.cjs");let t=require("react");t=e.__toESM(t,1);var n=1;function r(e){let{scrollTop:t,scrollHeight:r,clientHeight:i}=e;return r-i<n?`none`:t<n?`top`:t+i>=r-n?`bottom`:`middle`}function i(e,t){e.addEventListener(`scroll`,t,{passive:!0});let n=typeof ResizeObserver>`u`?null:new ResizeObserver(()=>t()),r=()=>{if(n){n.disconnect(),n.observe(e);for(let t of Array.from(e.children))n.observe(t)}};r();let i=typeof MutationObserver>`u`?null:new MutationObserver(()=>{r(),t()});return i?.observe(e,{childList:!0,subtree:!0,characterData:!0,attributes:!0}),()=>{e.removeEventListener(`scroll`,t),n?.disconnect(),i?.disconnect()}}var a=()=>`none`;function o(e){let n=t.useCallback(t=>e?i(e,t):()=>{},[e]),o=t.useCallback(()=>e?r(e):`none`,[e]);return t.useSyncExternalStore(n,o,a)}var s={header:`border-b border-transparent data-[scroll-state=middle]:border-border data-[scroll-state=bottom]:border-border forced-colors:border-[CanvasText]`,footer:`border-t border-transparent data-[scroll-state=top]:border-border data-[scroll-state=middle]:border-border forced-colors:border-[CanvasText]`};exports.scrollSeparatorClasses=s,exports.useScrollState=o;
2
+ //# sourceMappingURL=Drawer.scroll.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Drawer.scroll.cjs","names":["React","require_runtime","react","SCROLL_TOLERANCE","getScrollState","element","scrollHeight","clientHeight","scrollTop","subscribeScrollState","onChange","resizeObserver","observeBoxes","child","mutationObserver","getServerSnapshot","useScrollState","subscribe","getSnapshot","scrollSeparatorClasses"],"sources":["../../../src/components/overlays/Drawer.scroll.ts"],"sourcesContent":["import * as React from 'react';\n\n/*\n * The scroll state of a drawer's scrolling body, which draws the separators of its header and\n * footer (the scroll store of D108's contract, module-only). Imports no component; the root, the\n * parts and NavDrawer read it.\n */\n\n/**\n * How far a scrolling body is scrolled: `none` (the content fits), `top` (at the top, more below),\n * `middle`, or `bottom` (at the end). Rendered as `data-scroll-state`.\n */\nexport type DrawerScrollState = 'none' | 'top' | 'middle' | 'bottom';\n\n/**\n * Below this distance (px) an overflow or a scroll offset counts as none: zoom and high-density\n * screens give fractional offsets, so the end of the content can sit a fraction of a pixel away.\n */\nconst SCROLL_TOLERANCE = 1;\n\n/** The scroll state of `element`, with a 1px tolerance on each threshold. */\nfunction getScrollState(element: HTMLElement): DrawerScrollState {\n const { scrollTop, scrollHeight, clientHeight } = element;\n if (scrollHeight - clientHeight < SCROLL_TOLERANCE) return 'none';\n if (scrollTop < SCROLL_TOLERANCE) return 'top';\n if (scrollTop + clientHeight >= scrollHeight - SCROLL_TOLERANCE) return 'bottom';\n return 'middle';\n}\n\n/**\n * Calls `onChange` whenever the scroll state of `element` may have changed: a scroll (a passive\n * listener on the element), a size change of the element or of one of its element children (a\n * `ResizeObserver`, where it exists), and a change of its content (a `MutationObserver`, which\n * also observes the children it adds). Content can grow without a render of its own (an\n * Accordion expanding, an image loading) while the element's box stays the same, which observing\n * only the element would miss. Adds no `document` listener. Returns the unsubscribe function.\n */\nfunction subscribeScrollState(element: HTMLElement, onChange: () => void): () => void {\n element.addEventListener('scroll', onChange, { passive: true });\n const resizeObserver =\n typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(() => onChange());\n const observeBoxes = () => {\n if (!resizeObserver) return;\n resizeObserver.disconnect();\n resizeObserver.observe(element);\n for (const child of Array.from(element.children)) resizeObserver.observe(child);\n };\n observeBoxes();\n const mutationObserver =\n typeof MutationObserver === 'undefined'\n ? null\n : new MutationObserver(() => {\n observeBoxes();\n onChange();\n });\n mutationObserver?.observe(element, {\n childList: true,\n subtree: true,\n characterData: true,\n attributes: true,\n });\n return () => {\n element.removeEventListener('scroll', onChange);\n resizeObserver?.disconnect();\n mutationObserver?.disconnect();\n };\n}\n\n/** The server snapshot: nothing is measured on the server. */\nconst getServerSnapshot = (): DrawerScrollState => 'none';\n\n/**\n * The scroll state of `element` (held in state through a callback ref), read through\n * `useSyncExternalStore`: the component re-renders only when the state changes. `'none'` for\n * `null` and on the server.\n */\nexport function useScrollState(element: HTMLElement | null): DrawerScrollState {\n const subscribe = React.useCallback(\n (onChange: () => void) => (element ? subscribeScrollState(element, onChange) : () => {}),\n [element],\n );\n const getSnapshot = React.useCallback(\n (): DrawerScrollState => (element ? getScrollState(element) : 'none'),\n [element],\n );\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\n/**\n * The separators of a drawer's header (`header`: a line under it while the body is scrolled away\n * from its top) and footer (`footer`: a line above it while content continues below). Each is a\n * border that always exists and only changes colour with the element's `data-scroll-state`, so it\n * never shifts the layout; forced colors draw both lines at all times. Literal strings, so the\n * module makes no call at load and the CSS build sees every class.\n */\nexport const scrollSeparatorClasses: { readonly header: string; readonly footer: string } = {\n header:\n 'border-b border-transparent data-[scroll-state=middle]:border-border data-[scroll-state=bottom]:border-border forced-colors:border-[CanvasText]',\n footer:\n 'border-t border-transparent data-[scroll-state=top]:border-border data-[scroll-state=middle]:border-border forced-colors:border-[CanvasText]',\n};\n"],"mappings":"6GAkBA,IAAMG,EAAmB,EAGzB,SAASC,EAAe,EAAyC,CAC/D,GAAM,CAAE,YAAW,eAAc,gBAAiBC,EAIlD,OAHIC,EAAeC,EAAeJ,EAAyB,OACvDK,EAAYL,EAAyB,MACrCK,EAAYD,GAAgBD,EAAeH,EAAyB,SACjE,QACT,CAUA,SAASM,EAAqB,EAAsB,EAAkC,CACpFJ,EAAQ,iBAAiB,SAAUK,EAAU,CAAE,QAAS,EAAK,CAAC,EAC9D,IAAMC,EACJ,OAAO,eAAmB,IAAc,KAAO,IAAI,mBAAqBD,EAAS,CAAC,EAC9EE,MAAqB,CACzB,GAAKD,EAEL,CADAA,EAAe,WAAW,EAC1BA,EAAe,QAAQN,CAAO,EAC9B,IAAK,IAAMQ,KAAS,MAAM,KAAKR,EAAQ,QAAQ,EAAGM,EAAe,QAAQE,CAAK,CADhD,CAEhC,EACAD,EAAa,EACb,IAAME,EACJ,OAAO,iBAAqB,IACxB,KACA,IAAI,qBAAuB,CACzBF,EAAa,EACbF,EAAS,CACX,CAAC,EAOP,OANAI,GAAkB,QAAQT,EAAS,CACjC,UAAW,GACX,QAAS,GACT,cAAe,GACf,WAAY,EACd,CAAC,MACY,CACXA,EAAQ,oBAAoB,SAAUK,CAAQ,EAC9CC,GAAgB,WAAW,EAC3BG,GAAkB,WAAW,CAC/B,CACF,CAGA,IAAMC,MAA6C,OAOnD,SAAgBC,EAAe,EAAgD,CAC7E,IAAMC,EAAYjB,EAAM,YACrB,GAA0BK,EAAUI,EAAqBJ,EAASK,CAAQ,MAAU,CAAC,EACtF,CAACL,CAAO,CACV,EACMa,EAAclB,EAAM,gBACEK,EAAUD,EAAeC,CAAO,EAAI,OAC9D,CAACA,CAAO,CACV,EACA,OAAOL,EAAM,qBAAqBiB,EAAWC,EAAaH,CAAiB,CAC7E,CASA,IAAaI,EAA+E,CAC1F,OACE,kJACF,OACE,8IACJ"}
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import * as e from "react";
3
+ //#region src/components/overlays/Drawer.scroll.ts
4
+ var t = 1;
5
+ function n(e) {
6
+ let { scrollTop: n, scrollHeight: r, clientHeight: i } = e;
7
+ return r - i < t ? "none" : n < t ? "top" : n + i >= r - t ? "bottom" : "middle";
8
+ }
9
+ function r(e, t) {
10
+ e.addEventListener("scroll", t, { passive: !0 });
11
+ let n = typeof ResizeObserver > "u" ? null : new ResizeObserver(() => t()), r = () => {
12
+ if (n) {
13
+ n.disconnect(), n.observe(e);
14
+ for (let t of Array.from(e.children)) n.observe(t);
15
+ }
16
+ };
17
+ r();
18
+ let i = typeof MutationObserver > "u" ? null : new MutationObserver(() => {
19
+ r(), t();
20
+ });
21
+ return i?.observe(e, {
22
+ childList: !0,
23
+ subtree: !0,
24
+ characterData: !0,
25
+ attributes: !0
26
+ }), () => {
27
+ e.removeEventListener("scroll", t), n?.disconnect(), i?.disconnect();
28
+ };
29
+ }
30
+ var i = () => "none";
31
+ function a(t) {
32
+ let a = e.useCallback((e) => t ? r(t, e) : () => {}, [t]), o = e.useCallback(() => t ? n(t) : "none", [t]);
33
+ return e.useSyncExternalStore(a, o, i);
34
+ }
35
+ var o = {
36
+ header: "border-b border-transparent data-[scroll-state=middle]:border-border data-[scroll-state=bottom]:border-border forced-colors:border-[CanvasText]",
37
+ footer: "border-t border-transparent data-[scroll-state=top]:border-border data-[scroll-state=middle]:border-border forced-colors:border-[CanvasText]"
38
+ };
39
+ //#endregion
40
+ export { o as scrollSeparatorClasses, a as useScrollState };
41
+
42
+ //# sourceMappingURL=Drawer.scroll.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Drawer.scroll.mjs","names":["React","SCROLL_TOLERANCE","getScrollState","element","scrollHeight","clientHeight","scrollTop","subscribeScrollState","onChange","resizeObserver","observeBoxes","child","mutationObserver","getServerSnapshot","useScrollState","subscribe","getSnapshot","scrollSeparatorClasses"],"sources":["../../../src/components/overlays/Drawer.scroll.ts"],"sourcesContent":["import * as React from 'react';\n\n/*\n * The scroll state of a drawer's scrolling body, which draws the separators of its header and\n * footer (the scroll store of D108's contract, module-only). Imports no component; the root, the\n * parts and NavDrawer read it.\n */\n\n/**\n * How far a scrolling body is scrolled: `none` (the content fits), `top` (at the top, more below),\n * `middle`, or `bottom` (at the end). Rendered as `data-scroll-state`.\n */\nexport type DrawerScrollState = 'none' | 'top' | 'middle' | 'bottom';\n\n/**\n * Below this distance (px) an overflow or a scroll offset counts as none: zoom and high-density\n * screens give fractional offsets, so the end of the content can sit a fraction of a pixel away.\n */\nconst SCROLL_TOLERANCE = 1;\n\n/** The scroll state of `element`, with a 1px tolerance on each threshold. */\nfunction getScrollState(element: HTMLElement): DrawerScrollState {\n const { scrollTop, scrollHeight, clientHeight } = element;\n if (scrollHeight - clientHeight < SCROLL_TOLERANCE) return 'none';\n if (scrollTop < SCROLL_TOLERANCE) return 'top';\n if (scrollTop + clientHeight >= scrollHeight - SCROLL_TOLERANCE) return 'bottom';\n return 'middle';\n}\n\n/**\n * Calls `onChange` whenever the scroll state of `element` may have changed: a scroll (a passive\n * listener on the element), a size change of the element or of one of its element children (a\n * `ResizeObserver`, where it exists), and a change of its content (a `MutationObserver`, which\n * also observes the children it adds). Content can grow without a render of its own (an\n * Accordion expanding, an image loading) while the element's box stays the same, which observing\n * only the element would miss. Adds no `document` listener. Returns the unsubscribe function.\n */\nfunction subscribeScrollState(element: HTMLElement, onChange: () => void): () => void {\n element.addEventListener('scroll', onChange, { passive: true });\n const resizeObserver =\n typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(() => onChange());\n const observeBoxes = () => {\n if (!resizeObserver) return;\n resizeObserver.disconnect();\n resizeObserver.observe(element);\n for (const child of Array.from(element.children)) resizeObserver.observe(child);\n };\n observeBoxes();\n const mutationObserver =\n typeof MutationObserver === 'undefined'\n ? null\n : new MutationObserver(() => {\n observeBoxes();\n onChange();\n });\n mutationObserver?.observe(element, {\n childList: true,\n subtree: true,\n characterData: true,\n attributes: true,\n });\n return () => {\n element.removeEventListener('scroll', onChange);\n resizeObserver?.disconnect();\n mutationObserver?.disconnect();\n };\n}\n\n/** The server snapshot: nothing is measured on the server. */\nconst getServerSnapshot = (): DrawerScrollState => 'none';\n\n/**\n * The scroll state of `element` (held in state through a callback ref), read through\n * `useSyncExternalStore`: the component re-renders only when the state changes. `'none'` for\n * `null` and on the server.\n */\nexport function useScrollState(element: HTMLElement | null): DrawerScrollState {\n const subscribe = React.useCallback(\n (onChange: () => void) => (element ? subscribeScrollState(element, onChange) : () => {}),\n [element],\n );\n const getSnapshot = React.useCallback(\n (): DrawerScrollState => (element ? getScrollState(element) : 'none'),\n [element],\n );\n return React.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\n/**\n * The separators of a drawer's header (`header`: a line under it while the body is scrolled away\n * from its top) and footer (`footer`: a line above it while content continues below). Each is a\n * border that always exists and only changes colour with the element's `data-scroll-state`, so it\n * never shifts the layout; forced colors draw both lines at all times. Literal strings, so the\n * module makes no call at load and the CSS build sees every class.\n */\nexport const scrollSeparatorClasses: { readonly header: string; readonly footer: string } = {\n header:\n 'border-b border-transparent data-[scroll-state=middle]:border-border data-[scroll-state=bottom]:border-border forced-colors:border-[CanvasText]',\n footer:\n 'border-t border-transparent data-[scroll-state=top]:border-border data-[scroll-state=middle]:border-border forced-colors:border-[CanvasText]',\n};\n"],"mappings":";;;AAkBA,IAAMC,IAAmB;AAGzB,SAASC,EAAe,GAAyC;CAC/D,IAAM,EAAE,cAAW,iBAAc,oBAAiBC;CAIlD,OAHIC,IAAeC,IAAeJ,IAAyB,SACvDK,IAAYL,IAAyB,QACrCK,IAAYD,KAAgBD,IAAeH,IAAyB,WACjE;AACT;AAUA,SAASM,EAAqB,GAAsB,GAAkC;CACpF,EAAQ,iBAAiB,UAAUC,GAAU,EAAE,SAAS,GAAK,CAAC;CAC9D,IAAMC,IACJ,OAAO,iBAAmB,MAAc,OAAO,IAAI,qBAAqBD,EAAS,CAAC,GAC9EE,UAAqB;EACzB,IAAKD,GAEL;GADAA,EAAe,WAAW,GAC1BA,EAAe,QAAQN,CAAO;GAC9B,KAAK,IAAMQ,KAAS,MAAM,KAAKR,EAAQ,QAAQ,GAAG,EAAe,QAAQQ,CAAK;EADhD;CAEhC;CACA,EAAa;CACb,IAAMC,IACJ,OAAO,mBAAqB,MACxB,OACA,IAAI,uBAAuB;EAEzB,AADAF,EAAa,GACbF,EAAS;CACX,CAAC;CAOP,OANAI,GAAkB,QAAQT,GAAS;EACjC,WAAW;EACX,SAAS;EACT,eAAe;EACf,YAAY;CACd,CAAC,SACY;EAGX,AAFAA,EAAQ,oBAAoB,UAAUK,CAAQ,GAC9CC,GAAgB,WAAW,GAC3BG,GAAkB,WAAW;CAC/B;AACF;AAGA,IAAMC,UAA6C;AAOnD,SAAgBC,EAAe,GAAgD;CAC7E,IAAMC,IAAYf,EAAM,aACrB,MAA0BG,IAAUI,EAAqBJ,GAASK,CAAQ,UAAU,CAAC,GACtF,CAACL,CAAO,CACV,GACMa,IAAchB,EAAM,kBACEG,IAAUD,EAAeC,CAAO,IAAI,QAC9D,CAACA,CAAO,CACV;CACA,OAAOH,EAAM,qBAAqBe,GAAWC,GAAaH,CAAiB;AAC7E;AASA,IAAaI,IAA+E;CAC1F,QACE;CACF,QACE;AACJ"}
@@ -1 +1 @@
1
- {"version":3,"file":"useDismiss.cjs","names":["React","useId","useRef","registerLayer","useMemo","getTopmostLayer","require_runtime","require_useId","require_layers","react","DismissLayerContext","DismissLayerProvider","props","useDismiss","layerId","parentId","latestRef","options","open","latest","ref","reason","event"],"sources":["../../src/hooks/useDismiss.ts"],"sourcesContent":["import * as React from 'react';\nimport { useInsertionEffect, useLayoutEffect, useMemo, useRef } from 'react';\nimport { useId } from './useId';\nimport {\n getTopmostLayer,\n registerLayer,\n type DismissReason,\n type LayerKind,\n type LayerRecord,\n} from '../lib/layers';\n\nexport type { DismissReason } from '../lib/layers';\n\n/** Options of {@link useDismiss}. */\nexport interface UseDismissOptions {\n /** Whether the layer is open; the layer is registered only while `true`. */\n open: boolean;\n /** Called when the layer should close (the component sets its `open` state to `false`). */\n onDismiss: (reason: DismissReason, event: Event) => void;\n /**\n * Elements that belong to the layer: the content surface, the trigger/anchor and any extra\n * targets that must not count as \"outside\" (read at event time).\n */\n refs: ReadonlyArray<React.RefObject<HTMLElement | null>>;\n /** The trigger; focus traps leave a descendant layer through it (Tab → the element after it). */\n anchorRef?: React.RefObject<HTMLElement | null>;\n /** @default 'popover' */\n kind?: LayerKind;\n /** Whether Escape dismisses the layer. @default true */\n escape?: boolean;\n /**\n * Whether a press outside the layer's tree dismisses it. A predicate receives the `pointerdown`\n * event; returning `false` ignores that press. @default true\n */\n outsidePress?: boolean | ((event: PointerEvent | MouseEvent) => boolean);\n /** Whether focus moving outside the layer's tree dismisses it (listboxes). @default false */\n focusOutside?: boolean;\n}\n\n/** Returned by {@link useDismiss}. */\nexport interface DismissLayer {\n /** The layer's id: pass it to `Portal layerId` or `DismissLayerProvider` around the surface. */\n layerId: string;\n /** Whether the layer is currently the topmost open layer (read at call time). */\n isTopmost(): boolean;\n}\n\n/**\n * The id of the enclosing dismiss layer. React context survives portals, so a popover opened from\n * inside a dialog knows the dialog is its parent layer. `null` outside any layer.\n */\nexport const DismissLayerContext: React.Context<string | null> = React.createContext<string | null>(\n null,\n);\nDismissLayerContext.displayName = 'DismissLayerContext';\n\n/**\n * Makes `layerId` the parent layer of everything rendered inside (`Portal layerId` does this for\n * its children automatically).\n */\nexport function DismissLayerProvider(props: {\n layerId: string;\n children: React.ReactNode;\n}): React.ReactElement {\n return React.createElement(\n DismissLayerContext.Provider,\n { value: props.layerId },\n props.children,\n );\n}\n\n/**\n * Registers an open overlay surface as a **dismiss layer** in the shared layer stack and closes it\n * on Escape, outside presses and (optionally) focus leaving it — with correct nesting:\n *\n * - **Escape** (document `keydown`, bubble phase) is routed by focus location: the innermost layer\n * whose tree contains the event target or the focused element is the scope, and the topmost\n * escape-enabled layer of that scope's subtree handles it — so a tooltip or popover opened from\n * the focused dialog closes before the dialog, while an unrelated layer opened later does not\n * steal the key. With no escape-enabled layer there, an escape-enabled ancestor handles it; when\n * no layer contains the focus (or none of those takes Escape), the global topmost\n * escape-enabled one. Layers stacked below the topmost **isolating** modal (a Dialog/Drawer\n * whose `useModalIsolation` is active — its ancestors and older siblings) never take Escape, so\n * a modal that ignores Escape blocks it whether it is nested in a dialog or opened beside it.\n * The handler calls `preventDefault()`. Events whose default is already prevented (an inner\n * widget consumed Escape) and IME composition events are ignored.\n * - **Outside press**: on `pointerdown` (capture) every open layer whose tree does not contain the\n * target is recorded; on the following `click` each recorded layer whose tree still does not\n * contain the click target is dismissed (children first). A drag from inside to outside never\n * dismisses, clicks inside nested portaled layers count as inside, a popup opened by the same\n * click survives, and an external toggle works. Layers stacked below the topmost isolating modal\n * are inert and never dismissed by presses on that modal or its backdrop; a `kind: 'modal'`\n * layer without isolation (the DatePicker calendar) shields nothing, so a page click closes it\n * and the layers around it. The pending press survives modifier keys (Shift/Ctrl+click) and\n * ends on Enter/Space, on `pointercancel`, or when no click follows a mouse `pointerup` in the\n * same task; touch and pen presses are kept until their click, which the browser dispatches\n * from a separate tap gesture.\n * - **Focus outside** (`focusOutside: true`): dismisses when focus moves outside the layer's tree.\n * That is decided in a microtask, once the current commit has run: an `autoFocus` field of a\n * popover, dialog or plain portal opened inside the layer gets focus before that surface's\n * portal and layer register, and keeps the layer open. Focus that is back inside the tree by\n * then keeps it open too.\n *\n * A layer's tree is its `refs`, the portal wrappers rendered inside it, its descendant layers and\n * the `[data-wave-focus-trap-allow]` regions (toasts). Parentage comes from\n * {@link DismissLayerContext}: wrap the surface in `Portal layerId={layerId}` (or\n * {@link DismissLayerProvider}) so layers opened inside it become its children.\n *\n * @example\n * const { layerId } = useDismiss({ open, onDismiss: () => setOpen(false), refs: [surfaceRef, triggerRef], anchorRef: triggerRef });\n * return open && <Portal layerId={layerId}><div ref={surfaceRef}>…</div></Portal>;\n */\nexport function useDismiss(options: UseDismissOptions): DismissLayer {\n const layerId = useId('wave-layer');\n const parentId = React.useContext(DismissLayerContext);\n const latestRef = useRef({ options, parentId });\n\n // Current before any layout effect or event handler of this commit reads it.\n useInsertionEffect(() => {\n latestRef.current = { options, parentId };\n });\n\n const { open } = options;\n\n useLayoutEffect(() => {\n if (!open) return;\n const latest = latestRef;\n const record: LayerRecord = {\n id: layerId,\n get parentId() {\n return latest.current.parentId;\n },\n get kind() {\n return latest.current.options.kind ?? 'popover';\n },\n order: 0,\n getElements: () => latest.current.options.refs.map((ref) => ref.current),\n getAnchor: () => latest.current.options.anchorRef?.current ?? null,\n get escape() {\n return latest.current.options.escape ?? true;\n },\n get outsidePress() {\n return latest.current.options.outsidePress ?? true;\n },\n get focusOutside() {\n return latest.current.options.focusOutside ?? false;\n },\n onDismiss: (reason, event) => latest.current.options.onDismiss(reason, event),\n };\n return registerLayer(record);\n }, [open, layerId]);\n\n return useMemo(\n () => ({\n layerId,\n isTopmost: () => getTopmostLayer()?.id === layerId,\n }),\n [layerId],\n );\n}\n"],"mappings":"kKAmDA,IAAaU,EAAoDV,EAAM,cACrE,IACF,EACA,EAAoB,YAAc,sBAMlC,SAAgBW,EAAqB,EAGd,CACrB,OAAOX,EAAM,cACXU,EAAoB,SACpB,CAAE,MAAOE,EAAM,OAAQ,EACvBA,EAAM,QACR,CACF,CA2CA,SAAgBC,EAAW,EAA0C,CACnE,IAAMC,EAAUb,EAAAA,MAAM,YAAY,EAC5Bc,EAAWf,EAAM,WAAWU,CAAmB,EAC/CM,GAAA,EAAYd,EAAAA,OAAAA,CAAO,CAAE,UAAS,UAAS,CAAC,GAG9C,EAAAO,EAAA,mBAAA,KAAyB,CACvB,EAAU,QAAU,CAAE,UAAS,UAAS,CAC1C,CAAC,EAED,GAAM,CAAE,QAASQ,EA8BjB,OA5BA,EAAAR,EAAA,gBAAA,KAAsB,CACpB,GAAI,CAACS,EAAM,OACX,IAAMC,EAASH,EAuBf,OAAOb,EAAAA,cAAc,CArBnB,GAAIW,EACJ,IAAI,UAAW,CACb,OAAOK,EAAO,QAAQ,QACxB,EACA,IAAI,MAAO,CACT,OAAOA,EAAO,QAAQ,QAAQ,MAAQ,SACxC,EACA,MAAO,EACP,gBAAmBA,EAAO,QAAQ,QAAQ,KAAK,IAAK,GAAQC,EAAI,OAAO,EACvE,cAAiBD,EAAO,QAAQ,QAAQ,WAAW,SAAW,KAC9D,IAAI,QAAS,CACX,OAAOA,EAAO,QAAQ,QAAQ,QAAU,EAC1C,EACA,IAAI,cAAe,CACjB,OAAOA,EAAO,QAAQ,QAAQ,cAAgB,EAChD,EACA,IAAI,cAAe,CACjB,OAAOA,EAAO,QAAQ,QAAQ,cAAgB,EAChD,EACA,WAAY,EAAQ,IAAUA,EAAO,QAAQ,QAAQ,UAAUE,EAAQC,CAAK,CAEzD,CAAM,CAC7B,EAAG,CAACJ,EAAMJ,CAAO,CAAC,GAElB,EAAOV,EAAAA,QAAAA,MACE,CACL,UACA,cAAiBC,EAAAA,gBAAgB,CAAC,EAAE,KAAOS,CAC7C,GACA,CAACA,CAAO,CACV,CACF"}
1
+ {"version":3,"file":"useDismiss.cjs","names":["React","useId","useRef","registerLayer","useMemo","getTopmostLayer","require_runtime","require_useId","require_layers","react","DismissLayerContext","DismissLayerProvider","props","useDismiss","layerId","parentId","latestRef","options","open","latest","ref","reason","event"],"sources":["../../src/hooks/useDismiss.ts"],"sourcesContent":["import * as React from 'react';\nimport { useInsertionEffect, useLayoutEffect, useMemo, useRef } from 'react';\nimport { useId } from './useId';\nimport {\n getTopmostLayer,\n registerLayer,\n type DismissReason,\n type LayerKind,\n type LayerRecord,\n} from '../lib/layers';\n\nexport type { DismissReason } from '../lib/layers';\n\n/** Options of {@link useDismiss}. */\nexport interface UseDismissOptions {\n /** Whether the layer is open; the layer is registered only while `true`. */\n open: boolean;\n /** Called when the layer should close (the component sets its `open` state to `false`). */\n onDismiss: (reason: DismissReason, event: Event) => void;\n /**\n * Elements that belong to the layer: the content surface, the trigger/anchor and any extra\n * targets that must not count as \"outside\" (read at event time).\n */\n refs: ReadonlyArray<React.RefObject<HTMLElement | null>>;\n /** The trigger; focus traps leave a descendant layer through it (Tab → the element after it). */\n anchorRef?: React.RefObject<HTMLElement | null>;\n /** @default 'popover' */\n kind?: LayerKind;\n /**\n * Whether Escape dismisses the layer: always (`true`), never (`false`), or only while the key's\n * target or the focused element is in the layer's tree (`'inside'`).\n * @default true\n */\n escape?: boolean | 'inside';\n /**\n * Whether a press outside the layer's tree dismisses it. A predicate receives the `pointerdown`\n * event; returning `false` ignores that press. @default true\n */\n outsidePress?: boolean | ((event: PointerEvent | MouseEvent) => boolean);\n /** Whether focus moving outside the layer's tree dismisses it (listboxes). @default false */\n focusOutside?: boolean;\n}\n\n/** Returned by {@link useDismiss}. */\nexport interface DismissLayer {\n /** The layer's id: pass it to `Portal layerId` or `DismissLayerProvider` around the surface. */\n layerId: string;\n /** Whether the layer is currently the topmost open layer (read at call time). */\n isTopmost(): boolean;\n}\n\n/**\n * The id of the enclosing dismiss layer. React context survives portals, so a popover opened from\n * inside a dialog knows the dialog is its parent layer. `null` outside any layer.\n */\nexport const DismissLayerContext: React.Context<string | null> = React.createContext<string | null>(\n null,\n);\nDismissLayerContext.displayName = 'DismissLayerContext';\n\n/**\n * Makes `layerId` the parent layer of everything rendered inside (`Portal layerId` does this for\n * its children automatically).\n */\nexport function DismissLayerProvider(props: {\n layerId: string;\n children: React.ReactNode;\n}): React.ReactElement {\n return React.createElement(\n DismissLayerContext.Provider,\n { value: props.layerId },\n props.children,\n );\n}\n\n/**\n * Registers an open overlay surface as a **dismiss layer** in the shared layer stack and closes it\n * on Escape, outside presses and (optionally) focus leaving it — with correct nesting:\n *\n * - **Escape** (document `keydown`, bubble phase) is routed by focus location: the innermost layer\n * whose tree contains the event target or the focused element is the scope, and the topmost\n * escape-enabled layer of that scope's subtree handles it — so a tooltip or popover opened from\n * the focused dialog closes before the dialog, while an unrelated layer opened later does not\n * steal the key. With no escape-enabled layer there, an escape-enabled ancestor handles it; when\n * no layer contains the focus (or none of those takes Escape), the global topmost\n * escape-enabled one. Layers stacked below the topmost **isolating** modal (a Dialog/Drawer\n * whose `useModalIsolation` is active — its ancestors and older siblings) never take Escape, so\n * a modal that ignores Escape blocks it whether it is nested in a dialog or opened beside it.\n * A layer with `escape: 'inside'` (a non-modal Dialog or Drawer) takes Escape only while the\n * event target or the focused element is in its tree, so an Escape typed on the page leaves it\n * open and goes to the layers below it.\n * The handler calls `preventDefault()`. Events whose default is already prevented (an inner\n * widget consumed Escape) and IME composition events are ignored.\n * - **Outside press**: on `pointerdown` (capture) every open layer whose tree does not contain the\n * target is recorded; on the following `click` each recorded layer whose tree still does not\n * contain the click target is dismissed (children first). A drag from inside to outside never\n * dismisses, clicks inside nested portaled layers count as inside, a popup opened by the same\n * click survives, and an external toggle works. Layers stacked below the topmost isolating modal\n * are inert and never dismissed by presses on that modal or its backdrop; a `kind: 'modal'`\n * layer without isolation (the DatePicker calendar) shields nothing, so a page click closes it\n * and the layers around it. The pending press survives modifier keys (Shift/Ctrl+click) and\n * ends on Enter/Space, on `pointercancel`, or when no click follows a mouse `pointerup` in the\n * same task; touch and pen presses are kept until their click, which the browser dispatches\n * from a separate tap gesture.\n * - **Focus outside** (`focusOutside: true`): dismisses when focus moves outside the layer's tree.\n * That is decided in a microtask, once the current commit has run: an `autoFocus` field of a\n * popover, dialog or plain portal opened inside the layer gets focus before that surface's\n * portal and layer register, and keeps the layer open. Focus that is back inside the tree by\n * then keeps it open too.\n *\n * A layer's tree is its `refs`, the portal wrappers rendered inside it, its descendant layers and\n * the `[data-wave-focus-trap-allow]` regions (toasts). Parentage comes from\n * {@link DismissLayerContext}: wrap the surface in `Portal layerId={layerId}` (or\n * {@link DismissLayerProvider}) so layers opened inside it become its children.\n *\n * @example\n * const { layerId } = useDismiss({ open, onDismiss: () => setOpen(false), refs: [surfaceRef, triggerRef], anchorRef: triggerRef });\n * return open && <Portal layerId={layerId}><div ref={surfaceRef}>…</div></Portal>;\n */\nexport function useDismiss(options: UseDismissOptions): DismissLayer {\n const layerId = useId('wave-layer');\n const parentId = React.useContext(DismissLayerContext);\n const latestRef = useRef({ options, parentId });\n\n // Current before any layout effect or event handler of this commit reads it.\n useInsertionEffect(() => {\n latestRef.current = { options, parentId };\n });\n\n const { open } = options;\n\n useLayoutEffect(() => {\n if (!open) return;\n const latest = latestRef;\n const record: LayerRecord = {\n id: layerId,\n get parentId() {\n return latest.current.parentId;\n },\n get kind() {\n return latest.current.options.kind ?? 'popover';\n },\n order: 0,\n getElements: () => latest.current.options.refs.map((ref) => ref.current),\n getAnchor: () => latest.current.options.anchorRef?.current ?? null,\n get escape() {\n return latest.current.options.escape ?? true;\n },\n get outsidePress() {\n return latest.current.options.outsidePress ?? true;\n },\n get focusOutside() {\n return latest.current.options.focusOutside ?? false;\n },\n onDismiss: (reason, event) => latest.current.options.onDismiss(reason, event),\n };\n return registerLayer(record);\n }, [open, layerId]);\n\n return useMemo(\n () => ({\n layerId,\n isTopmost: () => getTopmostLayer()?.id === layerId,\n }),\n [layerId],\n );\n}\n"],"mappings":"kKAuDA,IAAaU,EAAoDV,EAAM,cACrE,IACF,EACA,EAAoB,YAAc,sBAMlC,SAAgBW,EAAqB,EAGd,CACrB,OAAOX,EAAM,cACXU,EAAoB,SACpB,CAAE,MAAOE,EAAM,OAAQ,EACvBA,EAAM,QACR,CACF,CA8CA,SAAgBC,EAAW,EAA0C,CACnE,IAAMC,EAAUb,EAAAA,MAAM,YAAY,EAC5Bc,EAAWf,EAAM,WAAWU,CAAmB,EAC/CM,GAAA,EAAYd,EAAAA,OAAAA,CAAO,CAAE,UAAS,UAAS,CAAC,GAG9C,EAAAO,EAAA,mBAAA,KAAyB,CACvB,EAAU,QAAU,CAAE,UAAS,UAAS,CAC1C,CAAC,EAED,GAAM,CAAE,QAASQ,EA8BjB,OA5BA,EAAAR,EAAA,gBAAA,KAAsB,CACpB,GAAI,CAACS,EAAM,OACX,IAAMC,EAASH,EAuBf,OAAOb,EAAAA,cAAc,CArBnB,GAAIW,EACJ,IAAI,UAAW,CACb,OAAOK,EAAO,QAAQ,QACxB,EACA,IAAI,MAAO,CACT,OAAOA,EAAO,QAAQ,QAAQ,MAAQ,SACxC,EACA,MAAO,EACP,gBAAmBA,EAAO,QAAQ,QAAQ,KAAK,IAAK,GAAQC,EAAI,OAAO,EACvE,cAAiBD,EAAO,QAAQ,QAAQ,WAAW,SAAW,KAC9D,IAAI,QAAS,CACX,OAAOA,EAAO,QAAQ,QAAQ,QAAU,EAC1C,EACA,IAAI,cAAe,CACjB,OAAOA,EAAO,QAAQ,QAAQ,cAAgB,EAChD,EACA,IAAI,cAAe,CACjB,OAAOA,EAAO,QAAQ,QAAQ,cAAgB,EAChD,EACA,WAAY,EAAQ,IAAUA,EAAO,QAAQ,QAAQ,UAAUE,EAAQC,CAAK,CAEzD,CAAM,CAC7B,EAAG,CAACJ,EAAMJ,CAAO,CAAC,GAElB,EAAOV,EAAAA,QAAAA,MACE,CACL,UACA,cAAiBC,EAAAA,gBAAgB,CAAC,EAAE,KAAOS,CAC7C,GACA,CAACA,CAAO,CACV,CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"useDismiss.mjs","names":["useId","useId$1","React","DismissLayerContext","DismissLayerProvider","props","useDismiss","layerId","parentId","latestRef","useRef","options","useLayoutEffect","open","latest","registerLayer","ref","reason","event","useMemo","getTopmostLayer"],"sources":["../../src/hooks/useDismiss.ts"],"sourcesContent":["import * as React from 'react';\nimport { useInsertionEffect, useLayoutEffect, useMemo, useRef } from 'react';\nimport { useId } from './useId';\nimport {\n getTopmostLayer,\n registerLayer,\n type DismissReason,\n type LayerKind,\n type LayerRecord,\n} from '../lib/layers';\n\nexport type { DismissReason } from '../lib/layers';\n\n/** Options of {@link useDismiss}. */\nexport interface UseDismissOptions {\n /** Whether the layer is open; the layer is registered only while `true`. */\n open: boolean;\n /** Called when the layer should close (the component sets its `open` state to `false`). */\n onDismiss: (reason: DismissReason, event: Event) => void;\n /**\n * Elements that belong to the layer: the content surface, the trigger/anchor and any extra\n * targets that must not count as \"outside\" (read at event time).\n */\n refs: ReadonlyArray<React.RefObject<HTMLElement | null>>;\n /** The trigger; focus traps leave a descendant layer through it (Tab → the element after it). */\n anchorRef?: React.RefObject<HTMLElement | null>;\n /** @default 'popover' */\n kind?: LayerKind;\n /** Whether Escape dismisses the layer. @default true */\n escape?: boolean;\n /**\n * Whether a press outside the layer's tree dismisses it. A predicate receives the `pointerdown`\n * event; returning `false` ignores that press. @default true\n */\n outsidePress?: boolean | ((event: PointerEvent | MouseEvent) => boolean);\n /** Whether focus moving outside the layer's tree dismisses it (listboxes). @default false */\n focusOutside?: boolean;\n}\n\n/** Returned by {@link useDismiss}. */\nexport interface DismissLayer {\n /** The layer's id: pass it to `Portal layerId` or `DismissLayerProvider` around the surface. */\n layerId: string;\n /** Whether the layer is currently the topmost open layer (read at call time). */\n isTopmost(): boolean;\n}\n\n/**\n * The id of the enclosing dismiss layer. React context survives portals, so a popover opened from\n * inside a dialog knows the dialog is its parent layer. `null` outside any layer.\n */\nexport const DismissLayerContext: React.Context<string | null> = React.createContext<string | null>(\n null,\n);\nDismissLayerContext.displayName = 'DismissLayerContext';\n\n/**\n * Makes `layerId` the parent layer of everything rendered inside (`Portal layerId` does this for\n * its children automatically).\n */\nexport function DismissLayerProvider(props: {\n layerId: string;\n children: React.ReactNode;\n}): React.ReactElement {\n return React.createElement(\n DismissLayerContext.Provider,\n { value: props.layerId },\n props.children,\n );\n}\n\n/**\n * Registers an open overlay surface as a **dismiss layer** in the shared layer stack and closes it\n * on Escape, outside presses and (optionally) focus leaving it — with correct nesting:\n *\n * - **Escape** (document `keydown`, bubble phase) is routed by focus location: the innermost layer\n * whose tree contains the event target or the focused element is the scope, and the topmost\n * escape-enabled layer of that scope's subtree handles it — so a tooltip or popover opened from\n * the focused dialog closes before the dialog, while an unrelated layer opened later does not\n * steal the key. With no escape-enabled layer there, an escape-enabled ancestor handles it; when\n * no layer contains the focus (or none of those takes Escape), the global topmost\n * escape-enabled one. Layers stacked below the topmost **isolating** modal (a Dialog/Drawer\n * whose `useModalIsolation` is active — its ancestors and older siblings) never take Escape, so\n * a modal that ignores Escape blocks it whether it is nested in a dialog or opened beside it.\n * The handler calls `preventDefault()`. Events whose default is already prevented (an inner\n * widget consumed Escape) and IME composition events are ignored.\n * - **Outside press**: on `pointerdown` (capture) every open layer whose tree does not contain the\n * target is recorded; on the following `click` each recorded layer whose tree still does not\n * contain the click target is dismissed (children first). A drag from inside to outside never\n * dismisses, clicks inside nested portaled layers count as inside, a popup opened by the same\n * click survives, and an external toggle works. Layers stacked below the topmost isolating modal\n * are inert and never dismissed by presses on that modal or its backdrop; a `kind: 'modal'`\n * layer without isolation (the DatePicker calendar) shields nothing, so a page click closes it\n * and the layers around it. The pending press survives modifier keys (Shift/Ctrl+click) and\n * ends on Enter/Space, on `pointercancel`, or when no click follows a mouse `pointerup` in the\n * same task; touch and pen presses are kept until their click, which the browser dispatches\n * from a separate tap gesture.\n * - **Focus outside** (`focusOutside: true`): dismisses when focus moves outside the layer's tree.\n * That is decided in a microtask, once the current commit has run: an `autoFocus` field of a\n * popover, dialog or plain portal opened inside the layer gets focus before that surface's\n * portal and layer register, and keeps the layer open. Focus that is back inside the tree by\n * then keeps it open too.\n *\n * A layer's tree is its `refs`, the portal wrappers rendered inside it, its descendant layers and\n * the `[data-wave-focus-trap-allow]` regions (toasts). Parentage comes from\n * {@link DismissLayerContext}: wrap the surface in `Portal layerId={layerId}` (or\n * {@link DismissLayerProvider}) so layers opened inside it become its children.\n *\n * @example\n * const { layerId } = useDismiss({ open, onDismiss: () => setOpen(false), refs: [surfaceRef, triggerRef], anchorRef: triggerRef });\n * return open && <Portal layerId={layerId}><div ref={surfaceRef}>…</div></Portal>;\n */\nexport function useDismiss(options: UseDismissOptions): DismissLayer {\n const layerId = useId('wave-layer');\n const parentId = React.useContext(DismissLayerContext);\n const latestRef = useRef({ options, parentId });\n\n // Current before any layout effect or event handler of this commit reads it.\n useInsertionEffect(() => {\n latestRef.current = { options, parentId };\n });\n\n const { open } = options;\n\n useLayoutEffect(() => {\n if (!open) return;\n const latest = latestRef;\n const record: LayerRecord = {\n id: layerId,\n get parentId() {\n return latest.current.parentId;\n },\n get kind() {\n return latest.current.options.kind ?? 'popover';\n },\n order: 0,\n getElements: () => latest.current.options.refs.map((ref) => ref.current),\n getAnchor: () => latest.current.options.anchorRef?.current ?? null,\n get escape() {\n return latest.current.options.escape ?? true;\n },\n get outsidePress() {\n return latest.current.options.outsidePress ?? true;\n },\n get focusOutside() {\n return latest.current.options.focusOutside ?? false;\n },\n onDismiss: (reason, event) => latest.current.options.onDismiss(reason, event),\n };\n return registerLayer(record);\n }, [open, layerId]);\n\n return useMemo(\n () => ({\n layerId,\n isTopmost: () => getTopmostLayer()?.id === layerId,\n }),\n [layerId],\n );\n}\n"],"mappings":";;;;;;AAmDA,IAAaG,IAAoDD,EAAM,cACrE,IACF;AACA,EAAoB,cAAc;AAMlC,SAAgBE,EAAqB,GAGd;CACrB,OAAOF,EAAM,cACXC,EAAoB,UACpB,EAAE,OAAOE,EAAM,QAAQ,GACvBA,EAAM,QACR;AACF;AA2CA,SAAgBC,EAAW,GAA0C;CACnE,IAAMC,IAAUP,EAAM,YAAY,GAC5BQ,IAAWN,EAAM,WAAWC,CAAmB,GAC/CM,IAAYC,EAAO;EAAE;EAAS;CAAS,CAAC;CAG9C,QAAyB;EACvB,EAAU,UAAU;GAAE;GAAS;EAAS;CAC1C,CAAC;CAED,IAAM,EAAE,YAASC;CA8BjB,OA5BAC,QAAsB;EACpB,IAAI,CAACC,GAAM;EACX,IAAMC,IAASL;EAuBf,OAAOM,EAAc;GArBnB,IAAIR;GACJ,IAAI,WAAW;IACb,OAAOO,EAAO,QAAQ;GACxB;GACA,IAAI,OAAO;IACT,OAAOA,EAAO,QAAQ,QAAQ,QAAQ;GACxC;GACA,OAAO;GACP,mBAAmBA,EAAO,QAAQ,QAAQ,KAAK,KAAK,MAAQE,EAAI,OAAO;GACvE,iBAAiBF,EAAO,QAAQ,QAAQ,WAAW,WAAW;GAC9D,IAAI,SAAS;IACX,OAAOA,EAAO,QAAQ,QAAQ,UAAU;GAC1C;GACA,IAAI,eAAe;IACjB,OAAOA,EAAO,QAAQ,QAAQ,gBAAgB;GAChD;GACA,IAAI,eAAe;IACjB,OAAOA,EAAO,QAAQ,QAAQ,gBAAgB;GAChD;GACA,YAAY,GAAQ,MAAUA,EAAO,QAAQ,QAAQ,UAAUG,GAAQC,CAAK;EAEzD,CAAM;CAC7B,GAAG,CAACL,GAAMN,CAAO,CAAC,GAEXY,SACE;EACL;EACA,iBAAiBC,EAAgB,CAAC,EAAE,OAAOb;CAC7C,IACA,CAACA,CAAO,CACV;AACF"}
1
+ {"version":3,"file":"useDismiss.mjs","names":["useId","useId$1","React","DismissLayerContext","DismissLayerProvider","props","useDismiss","layerId","parentId","latestRef","useRef","options","useLayoutEffect","open","latest","registerLayer","ref","reason","event","useMemo","getTopmostLayer"],"sources":["../../src/hooks/useDismiss.ts"],"sourcesContent":["import * as React from 'react';\nimport { useInsertionEffect, useLayoutEffect, useMemo, useRef } from 'react';\nimport { useId } from './useId';\nimport {\n getTopmostLayer,\n registerLayer,\n type DismissReason,\n type LayerKind,\n type LayerRecord,\n} from '../lib/layers';\n\nexport type { DismissReason } from '../lib/layers';\n\n/** Options of {@link useDismiss}. */\nexport interface UseDismissOptions {\n /** Whether the layer is open; the layer is registered only while `true`. */\n open: boolean;\n /** Called when the layer should close (the component sets its `open` state to `false`). */\n onDismiss: (reason: DismissReason, event: Event) => void;\n /**\n * Elements that belong to the layer: the content surface, the trigger/anchor and any extra\n * targets that must not count as \"outside\" (read at event time).\n */\n refs: ReadonlyArray<React.RefObject<HTMLElement | null>>;\n /** The trigger; focus traps leave a descendant layer through it (Tab → the element after it). */\n anchorRef?: React.RefObject<HTMLElement | null>;\n /** @default 'popover' */\n kind?: LayerKind;\n /**\n * Whether Escape dismisses the layer: always (`true`), never (`false`), or only while the key's\n * target or the focused element is in the layer's tree (`'inside'`).\n * @default true\n */\n escape?: boolean | 'inside';\n /**\n * Whether a press outside the layer's tree dismisses it. A predicate receives the `pointerdown`\n * event; returning `false` ignores that press. @default true\n */\n outsidePress?: boolean | ((event: PointerEvent | MouseEvent) => boolean);\n /** Whether focus moving outside the layer's tree dismisses it (listboxes). @default false */\n focusOutside?: boolean;\n}\n\n/** Returned by {@link useDismiss}. */\nexport interface DismissLayer {\n /** The layer's id: pass it to `Portal layerId` or `DismissLayerProvider` around the surface. */\n layerId: string;\n /** Whether the layer is currently the topmost open layer (read at call time). */\n isTopmost(): boolean;\n}\n\n/**\n * The id of the enclosing dismiss layer. React context survives portals, so a popover opened from\n * inside a dialog knows the dialog is its parent layer. `null` outside any layer.\n */\nexport const DismissLayerContext: React.Context<string | null> = React.createContext<string | null>(\n null,\n);\nDismissLayerContext.displayName = 'DismissLayerContext';\n\n/**\n * Makes `layerId` the parent layer of everything rendered inside (`Portal layerId` does this for\n * its children automatically).\n */\nexport function DismissLayerProvider(props: {\n layerId: string;\n children: React.ReactNode;\n}): React.ReactElement {\n return React.createElement(\n DismissLayerContext.Provider,\n { value: props.layerId },\n props.children,\n );\n}\n\n/**\n * Registers an open overlay surface as a **dismiss layer** in the shared layer stack and closes it\n * on Escape, outside presses and (optionally) focus leaving it — with correct nesting:\n *\n * - **Escape** (document `keydown`, bubble phase) is routed by focus location: the innermost layer\n * whose tree contains the event target or the focused element is the scope, and the topmost\n * escape-enabled layer of that scope's subtree handles it — so a tooltip or popover opened from\n * the focused dialog closes before the dialog, while an unrelated layer opened later does not\n * steal the key. With no escape-enabled layer there, an escape-enabled ancestor handles it; when\n * no layer contains the focus (or none of those takes Escape), the global topmost\n * escape-enabled one. Layers stacked below the topmost **isolating** modal (a Dialog/Drawer\n * whose `useModalIsolation` is active — its ancestors and older siblings) never take Escape, so\n * a modal that ignores Escape blocks it whether it is nested in a dialog or opened beside it.\n * A layer with `escape: 'inside'` (a non-modal Dialog or Drawer) takes Escape only while the\n * event target or the focused element is in its tree, so an Escape typed on the page leaves it\n * open and goes to the layers below it.\n * The handler calls `preventDefault()`. Events whose default is already prevented (an inner\n * widget consumed Escape) and IME composition events are ignored.\n * - **Outside press**: on `pointerdown` (capture) every open layer whose tree does not contain the\n * target is recorded; on the following `click` each recorded layer whose tree still does not\n * contain the click target is dismissed (children first). A drag from inside to outside never\n * dismisses, clicks inside nested portaled layers count as inside, a popup opened by the same\n * click survives, and an external toggle works. Layers stacked below the topmost isolating modal\n * are inert and never dismissed by presses on that modal or its backdrop; a `kind: 'modal'`\n * layer without isolation (the DatePicker calendar) shields nothing, so a page click closes it\n * and the layers around it. The pending press survives modifier keys (Shift/Ctrl+click) and\n * ends on Enter/Space, on `pointercancel`, or when no click follows a mouse `pointerup` in the\n * same task; touch and pen presses are kept until their click, which the browser dispatches\n * from a separate tap gesture.\n * - **Focus outside** (`focusOutside: true`): dismisses when focus moves outside the layer's tree.\n * That is decided in a microtask, once the current commit has run: an `autoFocus` field of a\n * popover, dialog or plain portal opened inside the layer gets focus before that surface's\n * portal and layer register, and keeps the layer open. Focus that is back inside the tree by\n * then keeps it open too.\n *\n * A layer's tree is its `refs`, the portal wrappers rendered inside it, its descendant layers and\n * the `[data-wave-focus-trap-allow]` regions (toasts). Parentage comes from\n * {@link DismissLayerContext}: wrap the surface in `Portal layerId={layerId}` (or\n * {@link DismissLayerProvider}) so layers opened inside it become its children.\n *\n * @example\n * const { layerId } = useDismiss({ open, onDismiss: () => setOpen(false), refs: [surfaceRef, triggerRef], anchorRef: triggerRef });\n * return open && <Portal layerId={layerId}><div ref={surfaceRef}>…</div></Portal>;\n */\nexport function useDismiss(options: UseDismissOptions): DismissLayer {\n const layerId = useId('wave-layer');\n const parentId = React.useContext(DismissLayerContext);\n const latestRef = useRef({ options, parentId });\n\n // Current before any layout effect or event handler of this commit reads it.\n useInsertionEffect(() => {\n latestRef.current = { options, parentId };\n });\n\n const { open } = options;\n\n useLayoutEffect(() => {\n if (!open) return;\n const latest = latestRef;\n const record: LayerRecord = {\n id: layerId,\n get parentId() {\n return latest.current.parentId;\n },\n get kind() {\n return latest.current.options.kind ?? 'popover';\n },\n order: 0,\n getElements: () => latest.current.options.refs.map((ref) => ref.current),\n getAnchor: () => latest.current.options.anchorRef?.current ?? null,\n get escape() {\n return latest.current.options.escape ?? true;\n },\n get outsidePress() {\n return latest.current.options.outsidePress ?? true;\n },\n get focusOutside() {\n return latest.current.options.focusOutside ?? false;\n },\n onDismiss: (reason, event) => latest.current.options.onDismiss(reason, event),\n };\n return registerLayer(record);\n }, [open, layerId]);\n\n return useMemo(\n () => ({\n layerId,\n isTopmost: () => getTopmostLayer()?.id === layerId,\n }),\n [layerId],\n );\n}\n"],"mappings":";;;;;;AAuDA,IAAaG,IAAoDD,EAAM,cACrE,IACF;AACA,EAAoB,cAAc;AAMlC,SAAgBE,EAAqB,GAGd;CACrB,OAAOF,EAAM,cACXC,EAAoB,UACpB,EAAE,OAAOE,EAAM,QAAQ,GACvBA,EAAM,QACR;AACF;AA8CA,SAAgBC,EAAW,GAA0C;CACnE,IAAMC,IAAUP,EAAM,YAAY,GAC5BQ,IAAWN,EAAM,WAAWC,CAAmB,GAC/CM,IAAYC,EAAO;EAAE;EAAS;CAAS,CAAC;CAG9C,QAAyB;EACvB,EAAU,UAAU;GAAE;GAAS;EAAS;CAC1C,CAAC;CAED,IAAM,EAAE,YAASC;CA8BjB,OA5BAC,QAAsB;EACpB,IAAI,CAACC,GAAM;EACX,IAAMC,IAASL;EAuBf,OAAOM,EAAc;GArBnB,IAAIR;GACJ,IAAI,WAAW;IACb,OAAOO,EAAO,QAAQ;GACxB;GACA,IAAI,OAAO;IACT,OAAOA,EAAO,QAAQ,QAAQ,QAAQ;GACxC;GACA,OAAO;GACP,mBAAmBA,EAAO,QAAQ,QAAQ,KAAK,KAAK,MAAQE,EAAI,OAAO;GACvE,iBAAiBF,EAAO,QAAQ,QAAQ,WAAW,WAAW;GAC9D,IAAI,SAAS;IACX,OAAOA,EAAO,QAAQ,QAAQ,UAAU;GAC1C;GACA,IAAI,eAAe;IACjB,OAAOA,EAAO,QAAQ,QAAQ,gBAAgB;GAChD;GACA,IAAI,eAAe;IACjB,OAAOA,EAAO,QAAQ,QAAQ,gBAAgB;GAChD;GACA,YAAY,GAAQ,MAAUA,EAAO,QAAQ,QAAQ,UAAUG,GAAQC,CAAK;EAEzD,CAAM;CAC7B,GAAG,CAACL,GAAMN,CAAO,CAAC,GAEXY,SACE;EACL;EACA,iBAAiBC,EAAgB,CAAC,EAAE,OAAOb;CAC7C,IACA,CAACA,CAAO,CACV;AACF"}
@@ -1,2 +1,2 @@
1
- "use client";const e=require("../lib/globalRegistry.cjs"),t=require("../lib/focus.cjs"),n=require("../lib/layers.cjs");let r=require("react");function i(){return e.getGlobalRegistry(`traps`,()=>({traps:[],seq:0,listeners:null}))}function a(e,t){let r=e.layerId,i=t.layerId;if(r!==void 0&&i!==void 0&&r!==i){if(n.isDescendantLayer(r,i))return 1;if(n.isDescendantLayer(i,r))return-1;let e=n.getLayer(r),t=n.getLayer(i);if(e&&t)return n.compareLayers(e,t)}return e.seq-t.seq}function o(e){let t=null;for(let n of e.traps)(!t||a(n,t)>0)&&(t=n);return t}var s=4,c=2;function l(e){let t=e.container.ownerDocument,n=Array.from(t.querySelectorAll(e.allowOutsideSelector));return n.filter(t=>!e.container.contains(t)&&!t.contains(e.container)&&!n.some(e=>e!==t&&e.contains(t)))}function u(e,n){let r=t.getTabbableElements(e.container).map(e=>({el:e,segment:0}));return n.forEach((e,n)=>{for(let i of t.getTabbableElements(e))r.push({el:i,segment:n+1})}),r}function d(e,t){return(e.compareDocumentPosition(t)&s)!==0}function f(e,t){return(e.compareDocumentPosition(t)&c)!==0&&!t.contains(e)}function p(e,t,n,r){if(!r){let r=e.find(e=>e.segment===n&&d(t,e.el));return r?r.el:(e.find(e=>e.segment>n)??e[0]).el}for(let r=e.length-1;r>=0;r--){let i=e[r];if(i.segment===n&&f(t,i.el))return i.el}for(let t=e.length-1;t>=0;t--)if(e[t].segment<n)return e[t].el;return e[e.length-1].el}function m(e,t){return e!==void 0&&n.getLayerTreeElements(e,{includeOwnElements:!1}).some(e=>e.contains(t))}function h(e,t){if(e.container.contains(t))return!0;let n=t.nodeType===1?t:t.parentElement;return n&&n.closest(e.allowOutsideSelector)?!0:m(e.layerId,t)}function g(e,t){let r=e.layerId;if(r===void 0)return null;let i=null;for(let a of n.getOpenLayers()){if(a.id===r||!n.isDescendantLayer(a.id,r))continue;let o=a.getAnchor(),s=a.getElements().find(n=>!!n&&n.contains(t)&&!e.container.contains(n)&&!(o&&n.contains(o)));s&&(!i||n.compareLayers(a,i.layer)>0)&&(i={layer:a,region:s})}return i}function _(e,t){if(e.layerId===void 0)return null;let r=n.getLayerTreeElements(e.layerId,{includeOwnElements:!1}).filter(e=>e.contains(t));return r.find(e=>!r.some(t=>t!==e&&t.contains(e)))??null}function v(e){for(let n of e)if(n&&t.focusElement(n))return}function y(e,n,r){let i=t.getTabbableElements(e),a=i.indexOf(n);return a===-1?r?!i.some(e=>f(n,e)):!i.some(e=>d(n,e)):r?a===0:a===i.length-1}function b(e,t,n){let r=u(e,t);v([n?r[r.length-1]?.el:r[0]?.el,e.container])}function x(e,t,n,r){let i=_(e,n);return i?!y(i,n,t.shiftKey)||(t.preventDefault(),b(e,r,t.shiftKey),!0):!1}function S(e,n,r,i){let a=r,o=n.shiftKey;for(let s=0;s<10;s++){let s=g(e,a);if(!s)return!1;let{layer:c,region:l}=s;if(a===r&&!y(l,a,o))return!0;let d=c.getAnchor();if(n.preventDefault(),!d||!d.isConnected)return b(e,i,o),!0;if(o&&t.isFocusable(d))return t.focusElement(d),!0;if(e.container.contains(d)){let n=u(e,i);return n.length===0?(t.focusElement(e.container),!0):(v([n.some(e=>e.el===d)?w(n,d,o):p(n,d,0,o),e.container]),!0)}let f=g(e,d);if(!f){let n=_(e,d);if(!n)return v([d,e.container]),!0;let r=C(t.getTabbableElements(n),d,o);return r?t.focusElement(r):b(e,i,o),!0}let m=C(t.getTabbableElements(f.region),d,o);if(m)return t.focusElement(m),!0;a=d}return!0}function C(e,t,n){return n?[...e].reverse().find(e=>f(t,e)):e.find(e=>d(t,e)&&!t.contains(e))}function w(e,t,n){let r=e.findIndex(e=>e.el===t);return e[((n?r-1:r+1)+e.length)%e.length].el}function T(e,n){let{container:r}=e;if(!r.isConnected)return;let i=r.ownerDocument,a=i.activeElement,o=n.shiftKey,s=l(e),c=!!a&&r.contains(a),d=a&&!c?s.findIndex(e=>e.contains(a)):-1;if(a&&!c&&d===-1&&a!==i.body&&m(e.layerId,a)&&(S(e,n,a,s)||x(e,n,a,s)))return;let f=u(e,s);if(f.length===0){n.preventDefault(),t.focusElement(r);return}let h=a?f.findIndex(e=>e.el===a):-1;if(h!==-1){let e=o?h-1:h+1;if(e<0||e>=f.length){n.preventDefault(),t.focusElement(f[o?f.length-1:0].el);return}let r=f[e];r.segment!==f[h].segment&&(n.preventDefault(),t.focusElement(r.el));return}if(n.preventDefault(),a&&(c||d!==-1)){let e=c?0:d+1;t.focusElement(p(f,a,e,o));return}t.focusElement(f[o?f.length-1:0].el)}function E(e){if(e.key!==`Tab`||e.defaultPrevented||e.altKey||e.ctrlKey||e.metaKey||e.isComposing)return;let t=o(i());t&&T(t,e)}function D(e){let t=o(i());if(!t)return;let n=e.target;if(!n||typeof n.nodeType!=`number`)return;let r=n;if(r.nodeType!==1)return;let a=r;if(h(t,a)){t.lastFocused=a;return}O||queueMicrotask(()=>A(a))}var O=!1;function k(e){let t=e.activeElement;return!t||t===e.body||t===e.documentElement}function A(e){let n=e.ownerDocument,r=n.activeElement!==e;if(r&&!k(n))return;let a=o(i());if(!a||!a.container.isConnected)return;if(!r&&h(a,e)){a.lastFocused=e;return}let s=a.lastFocused,c=!!s&&s.isConnected&&h(a,s)&&t.isFocusable(s);O=!0;try{v([c?s:null,t.getFirstTabbable(a.container),a.container])}finally{O=!1}}function j(e){if(e.listeners||typeof document>`u`)return;let t=document;t.addEventListener(`keydown`,E),t.addEventListener(`focusin`,D,!0),e.listeners={remove(){t.removeEventListener(`keydown`,E),t.removeEventListener(`focusin`,D,!0)}}}function M(e){let t=i();return t.traps.push(e),j(t),()=>{let n=t.traps.indexOf(e);n!==-1&&t.traps.splice(n,1),t.traps.length===0&&(t.listeners?.remove(),t.listeners=null)}}function N(e,n){let r=t.getFirstTabbable(e);return n===`container`?[e]:n===void 0||n===`first`?[r,e]:[typeof n==`function`?n():n.current,r,e]}function P(e,t){let{enabled:n}=t,a=(0,r.useRef)(t);(0,r.useInsertionEffect)(()=>{a.current=t}),(0,r.useLayoutEffect)(()=>{if(!n||!e)return;let t=a,r=i();r.seq+=1;let o={container:e,seq:r.seq,get layerId(){return t.current.layerId},get allowOutsideSelector(){return t.current.allowOutsideSelector??`[data-wave-focus-trap-allow]`},lastFocused:null},s=M(o),c=e.ownerDocument.activeElement;if(c&&(e.contains(c)||!c.closest(o.allowOutsideSelector)&&m(t.current.layerId,c)))o.lastFocused=c;else{v(N(e,t.current.initialFocus));let n=e.ownerDocument.activeElement;n&&e.contains(n)&&(o.lastFocused=n)}return s},[n,e])}exports.useFocusTrap=P;
1
+ "use client";const e=require("../lib/globalRegistry.cjs"),t=require("../lib/focus.cjs"),n=require("../lib/layers.cjs");let r=require("react");function i(){return e.getGlobalRegistry(`traps`,()=>({traps:[],seq:0,listeners:null}))}function a(e,t){let r=e.layerId,i=t.layerId;if(r!==void 0&&i!==void 0&&r!==i){if(n.isDescendantLayer(r,i))return 1;if(n.isDescendantLayer(i,r))return-1;let e=n.getLayer(r),t=n.getLayer(i);if(e&&t)return n.compareLayers(e,t)}return e.seq-t.seq}function o(e){let t=null;for(let n of e.traps)(!t||a(n,t)>0)&&(t=n);return t}var s=4,c=2;function l(e){let t=e.container.ownerDocument,n=Array.from(t.querySelectorAll(e.allowOutsideSelector));return n.filter(t=>!e.container.contains(t)&&!t.contains(e.container)&&!n.some(e=>e!==t&&e.contains(t)))}function u(e,n){let r=t.getTabbableElements(e.container).map(e=>({el:e,segment:0}));return n.forEach((e,n)=>{for(let i of t.getTabbableElements(e))r.push({el:i,segment:n+1})}),r}function d(e,t){return(e.compareDocumentPosition(t)&s)!==0}function f(e,t){return(e.compareDocumentPosition(t)&c)!==0&&!t.contains(e)}function p(e,t,n,r){if(!r){let r=e.find(e=>e.segment===n&&d(t,e.el));return r?r.el:(e.find(e=>e.segment>n)??e[0]).el}for(let r=e.length-1;r>=0;r--){let i=e[r];if(i.segment===n&&f(t,i.el))return i.el}for(let t=e.length-1;t>=0;t--)if(e[t].segment<n)return e[t].el;return e[e.length-1].el}function m(e,t){return e!==void 0&&n.getLayerTreeElements(e,{includeOwnElements:!1}).some(e=>e.contains(t))}function h(e,t){if(e.container.contains(t))return!0;let n=t.nodeType===1?t:t.parentElement;return n&&n.closest(e.allowOutsideSelector)?!0:m(e.layerId,t)}function g(e,t){let r=e.layerId;if(r===void 0)return null;let i=null;for(let a of n.getOpenLayers()){if(a.id===r||!n.isDescendantLayer(a.id,r))continue;let o=a.getAnchor(),s=a.getElements().find(n=>!!n&&n.contains(t)&&!e.container.contains(n)&&!(o&&n.contains(o)));s&&(!i||n.compareLayers(a,i.layer)>0)&&(i={layer:a,region:s})}return i}function _(e,t){if(e.layerId===void 0)return null;let r=n.getLayerTreeElements(e.layerId,{includeOwnElements:!1}).filter(e=>e.contains(t));return r.find(e=>!r.some(t=>t!==e&&t.contains(e)))??null}function v(e){for(let n of e)if(n&&t.focusElement(n))return}function y(e,n,r){let i=t.getTabbableElements(e),a=i.indexOf(n);return a===-1?r?!i.some(e=>f(n,e)):!i.some(e=>d(n,e)):r?a===0:a===i.length-1}function b(e,t,n){let r=u(e,t);v([n?r[r.length-1]?.el:r[0]?.el,e.container])}function x(e,t,n,r){let i=_(e,n);return i?!y(i,n,t.shiftKey)||(t.preventDefault(),b(e,r,t.shiftKey),!0):!1}function S(e,n,r,i){let a=r,o=n.shiftKey;for(let s=0;s<10;s++){let s=g(e,a);if(!s)return!1;let{layer:c,region:l}=s;if(a===r&&!y(l,a,o))return!0;let d=c.getAnchor();if(n.preventDefault(),!d||!d.isConnected)return b(e,i,o),!0;if(o&&t.isFocusable(d))return t.focusElement(d),!0;if(e.container.contains(d)){let n=u(e,i);return n.length===0?(t.focusElement(e.container),!0):(v([n.some(e=>e.el===d)?w(n,d,o):p(n,d,0,o),e.container]),!0)}let f=g(e,d);if(!f){let n=_(e,d);if(!n)return v([d,e.container]),!0;let r=C(t.getTabbableElements(n),d,o);return r?t.focusElement(r):b(e,i,o),!0}let m=C(t.getTabbableElements(f.region),d,o);if(m)return t.focusElement(m),!0;a=d}return!0}function C(e,t,n){return n?[...e].reverse().find(e=>f(t,e)):e.find(e=>d(t,e)&&!t.contains(e))}function w(e,t,n){let r=e.findIndex(e=>e.el===t);return e[((n?r-1:r+1)+e.length)%e.length].el}function T(e,n){let{container:r}=e;if(!r.isConnected)return;let i=r.ownerDocument,a=i.activeElement,o=n.shiftKey,s=l(e),c=!!a&&r.contains(a),d=a&&!c?s.findIndex(e=>e.contains(a)):-1;if(a&&!c&&d===-1&&a!==i.body&&m(e.layerId,a)&&(S(e,n,a,s)||x(e,n,a,s)))return;let f=u(e,s);if(f.length===0){n.preventDefault(),t.focusElement(r);return}let h=a?f.findIndex(e=>e.el===a):-1;if(h!==-1){let e=o?h-1:h+1;if(e<0||e>=f.length){n.preventDefault(),t.focusElement(f[o?f.length-1:0].el);return}let r=f[e];r.segment!==f[h].segment&&(n.preventDefault(),t.focusElement(r.el));return}if(n.preventDefault(),a&&(c||d!==-1)){let e=c?0:d+1;t.focusElement(p(f,a,e,o));return}t.focusElement(f[o?f.length-1:0].el)}function E(e){if(e.key!==`Tab`||e.defaultPrevented||e.altKey||e.ctrlKey||e.metaKey||e.isComposing)return;let t=o(i());t&&T(t,e)}function D(e){let t=o(i());if(!t)return;let n=e.target;if(!n||typeof n.nodeType!=`number`)return;let r=n;if(r.nodeType!==1)return;let a=r;if(h(t,a)){t.lastFocused=a;return}O||queueMicrotask(()=>A(a))}var O=!1;function k(e){let t=e.activeElement;return!t||t===e.body||t===e.documentElement}function A(e){let n=e.ownerDocument,r=n.activeElement!==e;if(r&&!k(n))return;let a=o(i());if(!a||!a.container.isConnected)return;if(!r&&h(a,e)){a.lastFocused=e;return}let s=a.lastFocused,c=!!s&&s.isConnected&&h(a,s)&&t.isFocusable(s);O=!0;try{v([c?s:null,t.getFirstTabbable(a.container),a.container])}finally{O=!1}}function j(e){if(e.listeners||typeof document>`u`)return;let t=document;t.addEventListener(`keydown`,E),t.addEventListener(`focusin`,D,!0),e.listeners={remove(){t.removeEventListener(`keydown`,E),t.removeEventListener(`focusin`,D,!0)}}}function M(e){let t=i();return t.traps.push(e),j(t),()=>{let n=t.traps.indexOf(e);n!==-1&&t.traps.splice(n,1),t.traps.length===0&&(t.listeners?.remove(),t.listeners=null)}}function N(e,n){let r=t.getFirstTabbable(e);return n===`container`?[e]:n===void 0||n===`first`?[r,e]:[typeof n==`function`?n():n.current,r,e]}function P(e,t){let{enabled:n}=t,a=(0,r.useRef)(t);(0,r.useInsertionEffect)(()=>{a.current=t}),(0,r.useLayoutEffect)(()=>{if(!n||!e)return;let t=a,r=i();r.seq+=1;let o={container:e,seq:r.seq,get layerId(){return t.current.layerId},get allowOutsideSelector(){return t.current.allowOutsideSelector??`[data-wave-focus-trap-allow]`},lastFocused:null},s=M(o),c=F(e,{layerId:t.current.layerId,initialFocus:t.current.initialFocus,allowOutsideSelector:o.allowOutsideSelector});return c&&(o.lastFocused=c),s},[n,e])}function F(e,t){let n=e.ownerDocument.activeElement;if(n&&(e.contains(n)||!n.closest(t.allowOutsideSelector)&&m(t.layerId,n)))return n;v(N(e,t.initialFocus));let r=e.ownerDocument.activeElement;return r&&e.contains(r)?r:null}function I(e,t){let{enabled:i}=t,a=(0,r.useRef)(t);(0,r.useInsertionEffect)(()=>{a.current=t}),(0,r.useLayoutEffect)(()=>{i&&e&&F(e,{layerId:a.current.layerId,initialFocus:a.current.initialFocus,allowOutsideSelector:n.ALLOW_OUTSIDE_SELECTOR})},[i,e])}exports.useFocusTrap=P,exports.useInitialFocus=I;
2
2
  //# sourceMappingURL=useFocusTrap.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useFocusTrap.cjs","names":["getGlobalRegistry","isDescendantLayer","getLayer","compareLayers","getTabbableElements","getLayerTreeElements","getOpenLayers","focusElement","isFocusable","getFirstTabbable","useRef","require_globalRegistry","require_focus","require_layers","react","getState","compareTraps","idA","a","idB","b","layerA","layerB","getActiveTrap","active","trap","state","FOLLOWING","PRECEDING","getAllowRegions","doc","all","region","other","getCycle","entries","regions","el","index","follows","reference","precedes","findFromPosition","backward","sameSegment","cycle","entry","segment","from","i","isInsideDescendantLayers","layerId","node","isInsideTrap","findDescendantLayer","found","layer","anchor","findPortalWrapper","containing","focusFirstPossible","candidate","candidates","isAtRegionEdge","tabbables","focusCycleEdge","handlePortalWrapperTab","wrapper","event","handleDescendantLayerTab","depth","neighbour","outer","next","findNextTo","handleTab","container","inContainer","regionIndex","nextIndex","handleKeyDown","handleFocusIn","target","reclaiming","reclaimFocus","isFocusLost","lost","last","lastIsValid","ensureListeners","pushTrap","resolveInitialFocus","first","initialFocus","useFocusTrap","options","latestRef","enabled","latest","release","now"],"sources":["../../src/hooks/useFocusTrap.ts"],"sourcesContent":["import { useInsertionEffect, useLayoutEffect, useRef } from 'react';\nimport type * as React from 'react';\nimport { getGlobalRegistry } from '../lib/globalRegistry';\nimport { focusElement, getFirstTabbable, getTabbableElements, isFocusable } from '../lib/focus';\nimport {\n ALLOW_OUTSIDE_SELECTOR,\n compareLayers,\n getLayer,\n getLayerTreeElements,\n getOpenLayers,\n isDescendantLayer,\n type LayerRecord,\n} from '../lib/layers';\n\n/** Options of {@link useFocusTrap}. */\nexport interface UseFocusTrapOptions {\n /** Whether the trap is active. */\n enabled: boolean;\n /**\n * The surface's dismiss layer; focus inside its descendant layers (portaled popovers opened from\n * inside) is allowed. The layer's own `refs` outside the container (its trigger) are not.\n */\n layerId?: string;\n /**\n * What to focus when the trap starts, unless focus is already inside (an `autoFocus` element\n * wins). @default 'first' (the first tabbable element, else the container)\n */\n initialFocus?:\n React.RefObject<HTMLElement | null> | 'first' | 'container' | (() => HTMLElement | null);\n /** Regions outside the container whose tabbables join the Tab cycle. @default ALLOW_OUTSIDE_SELECTOR */\n allowOutsideSelector?: string;\n}\n\ninterface TrapEntry {\n container: HTMLElement;\n seq: number;\n readonly layerId: string | undefined;\n readonly allowOutsideSelector: string;\n lastFocused: HTMLElement | null;\n}\n\ninterface TrapState {\n traps: TrapEntry[];\n seq: number;\n listeners: { remove(): void } | null;\n}\n\nfunction getState(): TrapState {\n return getGlobalRegistry<TrapState>('traps', () => ({ traps: [], seq: 0, listeners: null }));\n}\n\n// ---------------------------------------------------------------------------\n// Trap stack\n// ---------------------------------------------------------------------------\n\n/** `> 0` when trap `a` is above trap `b`: layer parentage/stacking first, then activation order. */\nfunction compareTraps(a: TrapEntry, b: TrapEntry): number {\n const idA = a.layerId;\n const idB = b.layerId;\n if (idA !== undefined && idB !== undefined && idA !== idB) {\n if (isDescendantLayer(idA, idB)) return 1;\n if (isDescendantLayer(idB, idA)) return -1;\n const layerA = getLayer(idA);\n const layerB = getLayer(idB);\n if (layerA && layerB) return compareLayers(layerA, layerB);\n }\n return a.seq - b.seq;\n}\n\nfunction getActiveTrap(state: TrapState): TrapEntry | null {\n let active: TrapEntry | null = null;\n for (const trap of state.traps) {\n if (!active || compareTraps(trap, active) > 0) active = trap;\n }\n return active;\n}\n\n// ---------------------------------------------------------------------------\n// Tab cycle\n// ---------------------------------------------------------------------------\n\ninterface CycleEntry {\n el: HTMLElement;\n /** 0 = the container, 1… = allow-listed regions in document order. */\n segment: number;\n}\n\nconst FOLLOWING = 4; // Node.DOCUMENT_POSITION_FOLLOWING\nconst PRECEDING = 2; // Node.DOCUMENT_POSITION_PRECEDING\n\n/** Top-level allow-listed regions outside the container. */\nfunction getAllowRegions(trap: TrapEntry): HTMLElement[] {\n const doc = trap.container.ownerDocument;\n const all = Array.from(doc.querySelectorAll<HTMLElement>(trap.allowOutsideSelector));\n return all.filter(\n (region) =>\n !trap.container.contains(region) &&\n !region.contains(trap.container) &&\n !all.some((other) => other !== region && other.contains(region)),\n );\n}\n\nfunction getCycle(trap: TrapEntry, regions: HTMLElement[]): CycleEntry[] {\n const entries: CycleEntry[] = getTabbableElements(trap.container).map((el) => ({\n el,\n segment: 0,\n }));\n regions.forEach((region, index) => {\n for (const el of getTabbableElements(region)) entries.push({ el, segment: index + 1 });\n });\n return entries;\n}\n\nfunction follows(reference: Node, el: Node): boolean {\n return (reference.compareDocumentPosition(el) & FOLLOWING) !== 0;\n}\n\nfunction precedes(reference: Node, el: Node): boolean {\n // An ancestor also \"precedes\"; it is not a place Tab goes back to.\n return (reference.compareDocumentPosition(el) & PRECEDING) !== 0 && !el.contains(reference);\n}\n\n/** The cycle entry Tab (or Shift+Tab) reaches from `from`, an element not in the cycle. */\nfunction findFromPosition(\n cycle: CycleEntry[],\n from: Element,\n segment: number,\n backward: boolean,\n): HTMLElement {\n if (!backward) {\n const sameSegment = cycle.find((entry) => entry.segment === segment && follows(from, entry.el));\n if (sameSegment) return sameSegment.el;\n const later = cycle.find((entry) => entry.segment > segment);\n return (later ?? cycle[0]).el;\n }\n for (let i = cycle.length - 1; i >= 0; i--) {\n const entry = cycle[i];\n if (entry.segment === segment && precedes(from, entry.el)) return entry.el;\n }\n for (let i = cycle.length - 1; i >= 0; i--) {\n if (cycle[i].segment < segment) return cycle[i].el;\n }\n return cycle[cycle.length - 1].el;\n}\n\n/**\n * Whether `node` is inside a **descendant** of the layer `layerId`: the portal wrappers registered\n * with it (overlays rendered inside the trapped surface) and the trees of its descendant layers.\n * The layer's own `getElements()` are left out — they usually include its trigger, which lives\n * outside the container (a DatePicker toggle) and must not count as inside the trap.\n */\nfunction isInsideDescendantLayers(layerId: string | undefined, node: Node): boolean {\n if (layerId === undefined) return false;\n return getLayerTreeElements(layerId, { includeOwnElements: false }).some((el) =>\n el.contains(node),\n );\n}\n\nfunction isInsideTrap(trap: TrapEntry, node: Node): boolean {\n if (trap.container.contains(node)) return true;\n const el = node.nodeType === 1 ? (node as Element) : node.parentElement;\n if (el && el.closest(trap.allowOutsideSelector)) return true;\n return isInsideDescendantLayers(trap.layerId, node);\n}\n\n/**\n * The open descendant layer of the trap's layer that `node` is in (the topmost when several\n * contain it), with the element of that layer containing `node` (its portaled surface). A layer's\n * trigger is not its surface: an element that is, or contains, the layer's anchor (an info\n * button, a tooltip's wrapper) belongs to the region around it — the container, the surface of\n * an enclosing descendant layer or a plain portal.\n */\nfunction findDescendantLayer(\n trap: TrapEntry,\n node: Node,\n): { layer: LayerRecord; region: HTMLElement } | null {\n const layerId = trap.layerId;\n if (layerId === undefined) return null;\n let found: { layer: LayerRecord; region: HTMLElement } | null = null;\n for (const layer of getOpenLayers()) {\n if (layer.id === layerId || !isDescendantLayer(layer.id, layerId)) continue;\n const anchor = layer.getAnchor();\n const region = layer\n .getElements()\n .find(\n (el): el is HTMLElement =>\n !!el &&\n el.contains(node) &&\n !trap.container.contains(el) &&\n !(anchor && el.contains(anchor)),\n );\n if (region && (!found || compareLayers(layer, found.layer) > 0)) found = { layer, region };\n }\n return found;\n}\n\n/**\n * The outermost element of the trap's layer tree (its own layer's elements left out) that contains\n * `node`. Asked once no descendant layer's surface contains `node`, this is the wrapper of a plain\n * `<Portal>` rendered inside the trapped surface (or inside one of its descendant layers).\n */\nfunction findPortalWrapper(trap: TrapEntry, node: Node): HTMLElement | null {\n if (trap.layerId === undefined) return null;\n const containing = getLayerTreeElements(trap.layerId, { includeOwnElements: false }).filter(\n (el) => el.contains(node),\n );\n return (\n containing.find((el) => !containing.some((other) => other !== el && other.contains(el))) ?? null\n );\n}\n\nfunction focusFirstPossible(candidates: Array<HTMLElement | null | undefined>): void {\n for (const candidate of candidates) {\n if (candidate && focusElement(candidate)) return;\n }\n}\n\n/** Whether Tab (Shift+Tab) from `from` leaves `region`: no tabbable of it follows (precedes). */\nfunction isAtRegionEdge(region: HTMLElement, from: HTMLElement, backward: boolean): boolean {\n const tabbables = getTabbableElements(region);\n const index = tabbables.indexOf(from);\n if (index === -1) {\n return backward\n ? !tabbables.some((el) => precedes(from, el))\n : !tabbables.some((el) => follows(from, el));\n }\n return backward ? index === 0 : index === tabbables.length - 1;\n}\n\n/** Leaving a region without an anchor: the first (Shift+Tab: last) element of the Tab cycle. */\nfunction focusCycleEdge(trap: TrapEntry, regions: HTMLElement[], backward: boolean): void {\n const cycle = getCycle(trap, regions);\n focusFirstPossible([backward ? cycle[cycle.length - 1]?.el : cycle[0]?.el, trap.container]);\n}\n\n/**\n * Tab inside a plain portal wrapper of the trap's layer tree (see {@link findPortalWrapper}):\n * native inside it; it has no anchor, so leaving it continues at the edge of the Tab cycle.\n * Returns `true` when it handled the event.\n */\nfunction handlePortalWrapperTab(\n trap: TrapEntry,\n event: KeyboardEvent,\n active: HTMLElement,\n regions: HTMLElement[],\n): boolean {\n const wrapper = findPortalWrapper(trap, active);\n if (!wrapper) return false;\n if (!isAtRegionEdge(wrapper, active, event.shiftKey)) return true; // native Tab inside it\n event.preventDefault();\n focusCycleEdge(trap, regions, event.shiftKey);\n return true;\n}\n\n/**\n * Tab inside a descendant layer: native inside it; leaving it forward goes to the tabbable after\n * the layer's anchor, backward to the anchor itself. Returns `true` when it handled the event.\n */\nfunction handleDescendantLayerTab(\n trap: TrapEntry,\n event: KeyboardEvent,\n active: HTMLElement,\n regions: HTMLElement[],\n): boolean {\n let from: HTMLElement = active;\n const backward = event.shiftKey;\n // Nested descendant layers: leave each one whose edge is reached, up to the container.\n for (let depth = 0; depth < 10; depth++) {\n const found = findDescendantLayer(trap, from);\n if (!found) return false;\n const { layer, region } = found;\n // Native Tab inside the layer.\n if (from === active && !isAtRegionEdge(region, from, backward)) return true;\n\n const anchor = layer.getAnchor();\n event.preventDefault();\n if (!anchor || !anchor.isConnected) {\n focusCycleEdge(trap, regions, backward);\n return true;\n }\n if (backward && isFocusable(anchor)) {\n focusElement(anchor);\n return true;\n }\n if (trap.container.contains(anchor)) {\n const cycle = getCycle(trap, regions);\n if (cycle.length === 0) {\n focusElement(trap.container);\n return true;\n }\n const target = cycle.some((entry) => entry.el === anchor)\n ? neighbour(cycle, anchor, backward)\n : findFromPosition(cycle, anchor, 0, backward);\n focusFirstPossible([target, trap.container]);\n return true;\n }\n // The anchor lives in another descendant layer: continue from there.\n const outer = findDescendantLayer(trap, anchor);\n if (!outer) {\n // Or in a plain portal of the trap's tree: the element next to it there, else the edge of\n // the Tab cycle (as when Tab leaves that portal).\n const wrapper = findPortalWrapper(trap, anchor);\n if (!wrapper) {\n focusFirstPossible([anchor, trap.container]);\n return true;\n }\n const next = findNextTo(getTabbableElements(wrapper), anchor, backward);\n if (next) focusElement(next);\n else focusCycleEdge(trap, regions, backward);\n return true;\n }\n const next = findNextTo(getTabbableElements(outer.region), anchor, backward);\n if (next) {\n focusElement(next);\n return true;\n }\n from = anchor;\n }\n return true;\n}\n\n/** The tabbable after `anchor` (backward: before it) in `tabbables`, never one inside it. */\nfunction findNextTo(\n tabbables: HTMLElement[],\n anchor: HTMLElement,\n backward: boolean,\n): HTMLElement | undefined {\n return backward\n ? [...tabbables].reverse().find((el) => precedes(anchor, el))\n : tabbables.find((el) => follows(anchor, el) && !anchor.contains(el));\n}\n\nfunction neighbour(cycle: CycleEntry[], el: HTMLElement, backward: boolean): HTMLElement {\n const index = cycle.findIndex((entry) => entry.el === el);\n const next = backward ? index - 1 : index + 1;\n return cycle[(next + cycle.length) % cycle.length].el;\n}\n\nfunction handleTab(trap: TrapEntry, event: KeyboardEvent): void {\n const { container } = trap;\n if (!container.isConnected) return;\n const doc = container.ownerDocument;\n const active = doc.activeElement as HTMLElement | null;\n const backward = event.shiftKey;\n const regions = getAllowRegions(trap);\n\n const inContainer = !!active && container.contains(active);\n const regionIndex =\n active && !inContainer ? regions.findIndex((region) => region.contains(active)) : -1;\n\n if (active && !inContainer && regionIndex === -1 && active !== doc.body) {\n if (isInsideDescendantLayers(trap.layerId, active)) {\n if (handleDescendantLayerTab(trap, event, active, regions)) return;\n if (handlePortalWrapperTab(trap, event, active, regions)) return;\n }\n }\n\n const cycle = getCycle(trap, regions);\n if (cycle.length === 0) {\n event.preventDefault();\n focusElement(container);\n return;\n }\n\n const index = active ? cycle.findIndex((entry) => entry.el === active) : -1;\n if (index !== -1) {\n const nextIndex = backward ? index - 1 : index + 1;\n if (nextIndex < 0 || nextIndex >= cycle.length) {\n event.preventDefault();\n focusElement(cycle[backward ? cycle.length - 1 : 0].el);\n return;\n }\n // Inside one segment the browser's own Tab order is used; crossing segments is explicit.\n const next = cycle[nextIndex];\n if (next.segment !== cycle[index].segment) {\n event.preventDefault();\n focusElement(next.el);\n }\n return;\n }\n\n event.preventDefault();\n if (active && (inContainer || regionIndex !== -1)) {\n const segment = inContainer ? 0 : regionIndex + 1;\n focusElement(findFromPosition(cycle, active, segment, backward));\n return;\n }\n focusElement(cycle[backward ? cycle.length - 1 : 0].el);\n}\n\n// ---------------------------------------------------------------------------\n// Document listeners\n// ---------------------------------------------------------------------------\n\nfunction handleKeyDown(event: KeyboardEvent): void {\n if (event.key !== 'Tab' || event.defaultPrevented) return;\n if (event.altKey || event.ctrlKey || event.metaKey || event.isComposing) return;\n const trap = getActiveTrap(getState());\n if (trap) handleTab(trap, event);\n}\n\nfunction handleFocusIn(event: FocusEvent): void {\n const trap = getActiveTrap(getState());\n if (!trap) return;\n const target = event.target as { nodeType?: unknown } | null;\n if (!target || typeof target.nodeType !== 'number') return;\n const node = target as Node;\n if (node.nodeType !== 1) return;\n const el = node as HTMLElement;\n if (isInsideTrap(trap, el)) {\n trap.lastFocused = el;\n return;\n }\n // Pulled out again by the focus being returned (another focus trap on the page): leave it there\n // rather than fight forever.\n if (reclaiming) return;\n // Not in this dispatch: React applies `autoFocus` in the layout phase of the commit that mounts\n // a surface, before the surface's portal wrapper and dismiss layer register and before its own\n // trap starts (a nested dialog, a confirm dialog over a drawer, a popover opened from a dialog).\n // Once that commit has run, the element is inside the trap that is active then.\n queueMicrotask(() => reclaimFocus(el));\n}\n\n/** Whether {@link reclaimFocus} is moving focus (its `focusin` events are dispatched meanwhile). */\nlet reclaiming = false;\n\n/** Whether focus is on no element: `<body>`, the document element or nothing. */\nfunction isFocusLost(doc: Document): boolean {\n const active = doc.activeElement;\n return !active || active === doc.body || active === doc.documentElement;\n}\n\n/**\n * Returns focus that landed on `el`, outside the trap, to the last focused element inside — also\n * when `el` lost it again before this ran (removed or blurred: focus is on `<body>` then, and no\n * later `focusin` would bring it back). Focus that moved on to another element is left to that\n * element's own check.\n */\nfunction reclaimFocus(el: HTMLElement): void {\n const doc = el.ownerDocument;\n const lost = doc.activeElement !== el;\n if (lost && !isFocusLost(doc)) return; // focus has moved on since\n const trap = getActiveTrap(getState());\n if (!trap || !trap.container.isConnected) return;\n if (!lost && isInsideTrap(trap, el)) {\n trap.lastFocused = el;\n return;\n }\n const last = trap.lastFocused;\n const lastIsValid = !!last && last.isConnected && isInsideTrap(trap, last) && isFocusable(last);\n reclaiming = true;\n try {\n focusFirstPossible([\n lastIsValid ? last : null,\n getFirstTabbable(trap.container),\n trap.container,\n ]);\n } finally {\n reclaiming = false;\n }\n}\n\nfunction ensureListeners(state: TrapState): void {\n if (state.listeners || typeof document === 'undefined') return;\n const doc = document;\n doc.addEventListener('keydown', handleKeyDown);\n doc.addEventListener('focusin', handleFocusIn, true);\n state.listeners = {\n remove() {\n doc.removeEventListener('keydown', handleKeyDown);\n doc.removeEventListener('focusin', handleFocusIn, true);\n },\n };\n}\n\nfunction pushTrap(entry: TrapEntry): () => void {\n const state = getState();\n state.traps.push(entry);\n ensureListeners(state);\n return () => {\n const index = state.traps.indexOf(entry);\n if (index !== -1) state.traps.splice(index, 1);\n if (state.traps.length === 0) {\n state.listeners?.remove();\n state.listeners = null;\n }\n };\n}\n\nfunction resolveInitialFocus(\n container: HTMLElement,\n initialFocus: UseFocusTrapOptions['initialFocus'],\n): Array<HTMLElement | null> {\n const first = getFirstTabbable(container);\n if (initialFocus === 'container') return [container];\n if (initialFocus === undefined || initialFocus === 'first') return [first, container];\n const chosen = typeof initialFocus === 'function' ? initialFocus() : initialFocus.current;\n return [chosen, first, container];\n}\n\n/**\n * Keeps keyboard focus inside `container` while `enabled` (modal dialogs, drawers, the DatePicker\n * calendar). Element-based: pass the surface held in state via a callback ref, so the trap starts\n * when the element appears.\n *\n * - **Initial focus** runs synchronously in the commit in which the container appears (no\n * `requestAnimationFrame`), and does nothing when focus is already inside (an `autoFocus`\n * element wins).\n * - **Tab / Shift+Tab** are handled by a document bubble-phase `keydown` listener that ignores\n * events whose default is already prevented, so a React handler inside (a menu closing on Tab, a\n * grid) can take the key first. Focus wraps at the edges, and from the container itself or a\n * non-tabbable element it continues in document order. Tabbable elements are computed on every\n * keydown (content may change; radio-group stops depend on focus), never cached.\n * - Tabbables inside `[data-wave-focus-trap-allow]` regions (the Toaster viewport) join the cycle.\n * - **Descendant layers** (a popover or menu opened from inside, identified through `layerId`):\n * Tab moves natively inside them; leaving one moves focus to the element after its anchor\n * (Shift+Tab: the anchor itself). Inside a plain `<Portal>` rendered in the surface (no layer,\n * no anchor) Tab is native too; leaving it wraps to the first (Shift+Tab: last) element. A\n * layer's trigger (its anchor, or an element around it such as a tooltip's wrapper) belongs to\n * the region it sits in, so Tab from an open info button or a button showing its tooltip moves\n * on as from any other element of that portal or popover.\n * - Focus that lands outside (not in the container, an allowed region or a descendant layer)\n * returns to the last focused element inside, also when that outside element loses it again\n * (removed or blurred, leaving focus on `<body>`). That is decided in a microtask, once the\n * current commit has run: an `autoFocus` element of a surface opened above the trap (a nested or\n * stacked dialog, a popover opened from the surface) gets focus before that surface's layer and\n * trap exist, and keeps it. The layer's own `refs` (its trigger, outside the container) are\n * outside: opening from the focused trigger still moves focus in, and focus moving back onto\n * the trigger is returned. Focus pulled out again while it is being returned (another focus\n * trap on the page) is left there.\n * - Traps form a stack (shared through the global registry): only the topmost acts.\n */\nexport function useFocusTrap(container: HTMLElement | null, options: UseFocusTrapOptions): void {\n const { enabled } = options;\n const latestRef = useRef(options);\n\n useInsertionEffect(() => {\n latestRef.current = options;\n });\n\n useLayoutEffect(() => {\n if (!enabled || !container) return;\n const latest = latestRef;\n const state = getState();\n state.seq += 1;\n const entry: TrapEntry = {\n container,\n seq: state.seq,\n get layerId() {\n return latest.current.layerId;\n },\n get allowOutsideSelector() {\n return latest.current.allowOutsideSelector ?? ALLOW_OUTSIDE_SELECTOR;\n },\n lastFocused: null,\n };\n const release = pushTrap(entry);\n\n // Initial focus is skipped only when focus is already inside the container or one of its\n // descendant layers (never for the layer's own trigger or an allow-listed toast).\n const active = container.ownerDocument.activeElement as HTMLElement | null;\n const focusInside =\n !!active &&\n (container.contains(active) ||\n (!active.closest(entry.allowOutsideSelector) &&\n isInsideDescendantLayers(latest.current.layerId, active)));\n if (focusInside) {\n entry.lastFocused = active;\n } else {\n focusFirstPossible(resolveInitialFocus(container, latest.current.initialFocus));\n const now = container.ownerDocument.activeElement as HTMLElement | null;\n if (now && container.contains(now)) entry.lastFocused = now;\n }\n return release;\n }, [enabled, container]);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useFocusTrap.cjs","names":["getGlobalRegistry","isDescendantLayer","getLayer","compareLayers","getTabbableElements","getLayerTreeElements","getOpenLayers","focusElement","isFocusable","getFirstTabbable","useRef","ALLOW_OUTSIDE_SELECTOR","require_globalRegistry","require_focus","require_layers","react","getState","compareTraps","idA","a","idB","b","layerA","layerB","getActiveTrap","active","trap","state","FOLLOWING","PRECEDING","getAllowRegions","doc","all","region","other","getCycle","entries","regions","el","index","follows","reference","precedes","findFromPosition","backward","sameSegment","cycle","entry","segment","from","i","isInsideDescendantLayers","layerId","node","isInsideTrap","findDescendantLayer","found","layer","anchor","findPortalWrapper","containing","focusFirstPossible","candidate","candidates","isAtRegionEdge","tabbables","focusCycleEdge","handlePortalWrapperTab","wrapper","event","handleDescendantLayerTab","depth","neighbour","outer","next","findNextTo","handleTab","container","inContainer","regionIndex","nextIndex","handleKeyDown","handleFocusIn","target","reclaiming","reclaimFocus","isFocusLost","lost","last","lastIsValid","ensureListeners","pushTrap","resolveInitialFocus","first","initialFocus","useFocusTrap","options","latestRef","enabled","latest","release","focused","applyInitialFocus","now","useInitialFocus"],"sources":["../../src/hooks/useFocusTrap.ts"],"sourcesContent":["import { useInsertionEffect, useLayoutEffect, useRef } from 'react';\nimport type * as React from 'react';\nimport { getGlobalRegistry } from '../lib/globalRegistry';\nimport { focusElement, getFirstTabbable, getTabbableElements, isFocusable } from '../lib/focus';\nimport {\n ALLOW_OUTSIDE_SELECTOR,\n compareLayers,\n getLayer,\n getLayerTreeElements,\n getOpenLayers,\n isDescendantLayer,\n type LayerRecord,\n} from '../lib/layers';\n\n/** Options of {@link useFocusTrap}. */\nexport interface UseFocusTrapOptions {\n /** Whether the trap is active. */\n enabled: boolean;\n /**\n * The surface's dismiss layer; focus inside its descendant layers (portaled popovers opened from\n * inside) is allowed. The layer's own `refs` outside the container (its trigger) are not.\n */\n layerId?: string;\n /**\n * What to focus when the trap starts, unless focus is already inside (an `autoFocus` element\n * wins). @default 'first' (the first tabbable element, else the container)\n */\n initialFocus?:\n React.RefObject<HTMLElement | null> | 'first' | 'container' | (() => HTMLElement | null);\n /** Regions outside the container whose tabbables join the Tab cycle. @default ALLOW_OUTSIDE_SELECTOR */\n allowOutsideSelector?: string;\n}\n\ninterface TrapEntry {\n container: HTMLElement;\n seq: number;\n readonly layerId: string | undefined;\n readonly allowOutsideSelector: string;\n lastFocused: HTMLElement | null;\n}\n\ninterface TrapState {\n traps: TrapEntry[];\n seq: number;\n listeners: { remove(): void } | null;\n}\n\nfunction getState(): TrapState {\n return getGlobalRegistry<TrapState>('traps', () => ({ traps: [], seq: 0, listeners: null }));\n}\n\n// ---------------------------------------------------------------------------\n// Trap stack\n// ---------------------------------------------------------------------------\n\n/** `> 0` when trap `a` is above trap `b`: layer parentage/stacking first, then activation order. */\nfunction compareTraps(a: TrapEntry, b: TrapEntry): number {\n const idA = a.layerId;\n const idB = b.layerId;\n if (idA !== undefined && idB !== undefined && idA !== idB) {\n if (isDescendantLayer(idA, idB)) return 1;\n if (isDescendantLayer(idB, idA)) return -1;\n const layerA = getLayer(idA);\n const layerB = getLayer(idB);\n if (layerA && layerB) return compareLayers(layerA, layerB);\n }\n return a.seq - b.seq;\n}\n\nfunction getActiveTrap(state: TrapState): TrapEntry | null {\n let active: TrapEntry | null = null;\n for (const trap of state.traps) {\n if (!active || compareTraps(trap, active) > 0) active = trap;\n }\n return active;\n}\n\n// ---------------------------------------------------------------------------\n// Tab cycle\n// ---------------------------------------------------------------------------\n\ninterface CycleEntry {\n el: HTMLElement;\n /** 0 = the container, 1… = allow-listed regions in document order. */\n segment: number;\n}\n\nconst FOLLOWING = 4; // Node.DOCUMENT_POSITION_FOLLOWING\nconst PRECEDING = 2; // Node.DOCUMENT_POSITION_PRECEDING\n\n/** Top-level allow-listed regions outside the container. */\nfunction getAllowRegions(trap: TrapEntry): HTMLElement[] {\n const doc = trap.container.ownerDocument;\n const all = Array.from(doc.querySelectorAll<HTMLElement>(trap.allowOutsideSelector));\n return all.filter(\n (region) =>\n !trap.container.contains(region) &&\n !region.contains(trap.container) &&\n !all.some((other) => other !== region && other.contains(region)),\n );\n}\n\nfunction getCycle(trap: TrapEntry, regions: HTMLElement[]): CycleEntry[] {\n const entries: CycleEntry[] = getTabbableElements(trap.container).map((el) => ({\n el,\n segment: 0,\n }));\n regions.forEach((region, index) => {\n for (const el of getTabbableElements(region)) entries.push({ el, segment: index + 1 });\n });\n return entries;\n}\n\nfunction follows(reference: Node, el: Node): boolean {\n return (reference.compareDocumentPosition(el) & FOLLOWING) !== 0;\n}\n\nfunction precedes(reference: Node, el: Node): boolean {\n // An ancestor also \"precedes\"; it is not a place Tab goes back to.\n return (reference.compareDocumentPosition(el) & PRECEDING) !== 0 && !el.contains(reference);\n}\n\n/** The cycle entry Tab (or Shift+Tab) reaches from `from`, an element not in the cycle. */\nfunction findFromPosition(\n cycle: CycleEntry[],\n from: Element,\n segment: number,\n backward: boolean,\n): HTMLElement {\n if (!backward) {\n const sameSegment = cycle.find((entry) => entry.segment === segment && follows(from, entry.el));\n if (sameSegment) return sameSegment.el;\n const later = cycle.find((entry) => entry.segment > segment);\n return (later ?? cycle[0]).el;\n }\n for (let i = cycle.length - 1; i >= 0; i--) {\n const entry = cycle[i];\n if (entry.segment === segment && precedes(from, entry.el)) return entry.el;\n }\n for (let i = cycle.length - 1; i >= 0; i--) {\n if (cycle[i].segment < segment) return cycle[i].el;\n }\n return cycle[cycle.length - 1].el;\n}\n\n/**\n * Whether `node` is inside a **descendant** of the layer `layerId`: the portal wrappers registered\n * with it (overlays rendered inside the trapped surface) and the trees of its descendant layers.\n * The layer's own `getElements()` are left out — they usually include its trigger, which lives\n * outside the container (a DatePicker toggle) and must not count as inside the trap.\n */\nfunction isInsideDescendantLayers(layerId: string | undefined, node: Node): boolean {\n if (layerId === undefined) return false;\n return getLayerTreeElements(layerId, { includeOwnElements: false }).some((el) =>\n el.contains(node),\n );\n}\n\nfunction isInsideTrap(trap: TrapEntry, node: Node): boolean {\n if (trap.container.contains(node)) return true;\n const el = node.nodeType === 1 ? (node as Element) : node.parentElement;\n if (el && el.closest(trap.allowOutsideSelector)) return true;\n return isInsideDescendantLayers(trap.layerId, node);\n}\n\n/**\n * The open descendant layer of the trap's layer that `node` is in (the topmost when several\n * contain it), with the element of that layer containing `node` (its portaled surface). A layer's\n * trigger is not its surface: an element that is, or contains, the layer's anchor (an info\n * button, a tooltip's wrapper) belongs to the region around it — the container, the surface of\n * an enclosing descendant layer or a plain portal.\n */\nfunction findDescendantLayer(\n trap: TrapEntry,\n node: Node,\n): { layer: LayerRecord; region: HTMLElement } | null {\n const layerId = trap.layerId;\n if (layerId === undefined) return null;\n let found: { layer: LayerRecord; region: HTMLElement } | null = null;\n for (const layer of getOpenLayers()) {\n if (layer.id === layerId || !isDescendantLayer(layer.id, layerId)) continue;\n const anchor = layer.getAnchor();\n const region = layer\n .getElements()\n .find(\n (el): el is HTMLElement =>\n !!el &&\n el.contains(node) &&\n !trap.container.contains(el) &&\n !(anchor && el.contains(anchor)),\n );\n if (region && (!found || compareLayers(layer, found.layer) > 0)) found = { layer, region };\n }\n return found;\n}\n\n/**\n * The outermost element of the trap's layer tree (its own layer's elements left out) that contains\n * `node`. Asked once no descendant layer's surface contains `node`, this is the wrapper of a plain\n * `<Portal>` rendered inside the trapped surface (or inside one of its descendant layers).\n */\nfunction findPortalWrapper(trap: TrapEntry, node: Node): HTMLElement | null {\n if (trap.layerId === undefined) return null;\n const containing = getLayerTreeElements(trap.layerId, { includeOwnElements: false }).filter(\n (el) => el.contains(node),\n );\n return (\n containing.find((el) => !containing.some((other) => other !== el && other.contains(el))) ?? null\n );\n}\n\nfunction focusFirstPossible(candidates: Array<HTMLElement | null | undefined>): void {\n for (const candidate of candidates) {\n if (candidate && focusElement(candidate)) return;\n }\n}\n\n/** Whether Tab (Shift+Tab) from `from` leaves `region`: no tabbable of it follows (precedes). */\nfunction isAtRegionEdge(region: HTMLElement, from: HTMLElement, backward: boolean): boolean {\n const tabbables = getTabbableElements(region);\n const index = tabbables.indexOf(from);\n if (index === -1) {\n return backward\n ? !tabbables.some((el) => precedes(from, el))\n : !tabbables.some((el) => follows(from, el));\n }\n return backward ? index === 0 : index === tabbables.length - 1;\n}\n\n/** Leaving a region without an anchor: the first (Shift+Tab: last) element of the Tab cycle. */\nfunction focusCycleEdge(trap: TrapEntry, regions: HTMLElement[], backward: boolean): void {\n const cycle = getCycle(trap, regions);\n focusFirstPossible([backward ? cycle[cycle.length - 1]?.el : cycle[0]?.el, trap.container]);\n}\n\n/**\n * Tab inside a plain portal wrapper of the trap's layer tree (see {@link findPortalWrapper}):\n * native inside it; it has no anchor, so leaving it continues at the edge of the Tab cycle.\n * Returns `true` when it handled the event.\n */\nfunction handlePortalWrapperTab(\n trap: TrapEntry,\n event: KeyboardEvent,\n active: HTMLElement,\n regions: HTMLElement[],\n): boolean {\n const wrapper = findPortalWrapper(trap, active);\n if (!wrapper) return false;\n if (!isAtRegionEdge(wrapper, active, event.shiftKey)) return true; // native Tab inside it\n event.preventDefault();\n focusCycleEdge(trap, regions, event.shiftKey);\n return true;\n}\n\n/**\n * Tab inside a descendant layer: native inside it; leaving it forward goes to the tabbable after\n * the layer's anchor, backward to the anchor itself. Returns `true` when it handled the event.\n */\nfunction handleDescendantLayerTab(\n trap: TrapEntry,\n event: KeyboardEvent,\n active: HTMLElement,\n regions: HTMLElement[],\n): boolean {\n let from: HTMLElement = active;\n const backward = event.shiftKey;\n // Nested descendant layers: leave each one whose edge is reached, up to the container.\n for (let depth = 0; depth < 10; depth++) {\n const found = findDescendantLayer(trap, from);\n if (!found) return false;\n const { layer, region } = found;\n // Native Tab inside the layer.\n if (from === active && !isAtRegionEdge(region, from, backward)) return true;\n\n const anchor = layer.getAnchor();\n event.preventDefault();\n if (!anchor || !anchor.isConnected) {\n focusCycleEdge(trap, regions, backward);\n return true;\n }\n if (backward && isFocusable(anchor)) {\n focusElement(anchor);\n return true;\n }\n if (trap.container.contains(anchor)) {\n const cycle = getCycle(trap, regions);\n if (cycle.length === 0) {\n focusElement(trap.container);\n return true;\n }\n const target = cycle.some((entry) => entry.el === anchor)\n ? neighbour(cycle, anchor, backward)\n : findFromPosition(cycle, anchor, 0, backward);\n focusFirstPossible([target, trap.container]);\n return true;\n }\n // The anchor lives in another descendant layer: continue from there.\n const outer = findDescendantLayer(trap, anchor);\n if (!outer) {\n // Or in a plain portal of the trap's tree: the element next to it there, else the edge of\n // the Tab cycle (as when Tab leaves that portal).\n const wrapper = findPortalWrapper(trap, anchor);\n if (!wrapper) {\n focusFirstPossible([anchor, trap.container]);\n return true;\n }\n const next = findNextTo(getTabbableElements(wrapper), anchor, backward);\n if (next) focusElement(next);\n else focusCycleEdge(trap, regions, backward);\n return true;\n }\n const next = findNextTo(getTabbableElements(outer.region), anchor, backward);\n if (next) {\n focusElement(next);\n return true;\n }\n from = anchor;\n }\n return true;\n}\n\n/** The tabbable after `anchor` (backward: before it) in `tabbables`, never one inside it. */\nfunction findNextTo(\n tabbables: HTMLElement[],\n anchor: HTMLElement,\n backward: boolean,\n): HTMLElement | undefined {\n return backward\n ? [...tabbables].reverse().find((el) => precedes(anchor, el))\n : tabbables.find((el) => follows(anchor, el) && !anchor.contains(el));\n}\n\nfunction neighbour(cycle: CycleEntry[], el: HTMLElement, backward: boolean): HTMLElement {\n const index = cycle.findIndex((entry) => entry.el === el);\n const next = backward ? index - 1 : index + 1;\n return cycle[(next + cycle.length) % cycle.length].el;\n}\n\nfunction handleTab(trap: TrapEntry, event: KeyboardEvent): void {\n const { container } = trap;\n if (!container.isConnected) return;\n const doc = container.ownerDocument;\n const active = doc.activeElement as HTMLElement | null;\n const backward = event.shiftKey;\n const regions = getAllowRegions(trap);\n\n const inContainer = !!active && container.contains(active);\n const regionIndex =\n active && !inContainer ? regions.findIndex((region) => region.contains(active)) : -1;\n\n if (active && !inContainer && regionIndex === -1 && active !== doc.body) {\n if (isInsideDescendantLayers(trap.layerId, active)) {\n if (handleDescendantLayerTab(trap, event, active, regions)) return;\n if (handlePortalWrapperTab(trap, event, active, regions)) return;\n }\n }\n\n const cycle = getCycle(trap, regions);\n if (cycle.length === 0) {\n event.preventDefault();\n focusElement(container);\n return;\n }\n\n const index = active ? cycle.findIndex((entry) => entry.el === active) : -1;\n if (index !== -1) {\n const nextIndex = backward ? index - 1 : index + 1;\n if (nextIndex < 0 || nextIndex >= cycle.length) {\n event.preventDefault();\n focusElement(cycle[backward ? cycle.length - 1 : 0].el);\n return;\n }\n // Inside one segment the browser's own Tab order is used; crossing segments is explicit.\n const next = cycle[nextIndex];\n if (next.segment !== cycle[index].segment) {\n event.preventDefault();\n focusElement(next.el);\n }\n return;\n }\n\n event.preventDefault();\n if (active && (inContainer || regionIndex !== -1)) {\n const segment = inContainer ? 0 : regionIndex + 1;\n focusElement(findFromPosition(cycle, active, segment, backward));\n return;\n }\n focusElement(cycle[backward ? cycle.length - 1 : 0].el);\n}\n\n// ---------------------------------------------------------------------------\n// Document listeners\n// ---------------------------------------------------------------------------\n\nfunction handleKeyDown(event: KeyboardEvent): void {\n if (event.key !== 'Tab' || event.defaultPrevented) return;\n if (event.altKey || event.ctrlKey || event.metaKey || event.isComposing) return;\n const trap = getActiveTrap(getState());\n if (trap) handleTab(trap, event);\n}\n\nfunction handleFocusIn(event: FocusEvent): void {\n const trap = getActiveTrap(getState());\n if (!trap) return;\n const target = event.target as { nodeType?: unknown } | null;\n if (!target || typeof target.nodeType !== 'number') return;\n const node = target as Node;\n if (node.nodeType !== 1) return;\n const el = node as HTMLElement;\n if (isInsideTrap(trap, el)) {\n trap.lastFocused = el;\n return;\n }\n // Pulled out again by the focus being returned (another focus trap on the page): leave it there\n // rather than fight forever.\n if (reclaiming) return;\n // Not in this dispatch: React applies `autoFocus` in the layout phase of the commit that mounts\n // a surface, before the surface's portal wrapper and dismiss layer register and before its own\n // trap starts (a nested dialog, a confirm dialog over a drawer, a popover opened from a dialog).\n // Once that commit has run, the element is inside the trap that is active then.\n queueMicrotask(() => reclaimFocus(el));\n}\n\n/** Whether {@link reclaimFocus} is moving focus (its `focusin` events are dispatched meanwhile). */\nlet reclaiming = false;\n\n/** Whether focus is on no element: `<body>`, the document element or nothing. */\nfunction isFocusLost(doc: Document): boolean {\n const active = doc.activeElement;\n return !active || active === doc.body || active === doc.documentElement;\n}\n\n/**\n * Returns focus that landed on `el`, outside the trap, to the last focused element inside — also\n * when `el` lost it again before this ran (removed or blurred: focus is on `<body>` then, and no\n * later `focusin` would bring it back). Focus that moved on to another element is left to that\n * element's own check.\n */\nfunction reclaimFocus(el: HTMLElement): void {\n const doc = el.ownerDocument;\n const lost = doc.activeElement !== el;\n if (lost && !isFocusLost(doc)) return; // focus has moved on since\n const trap = getActiveTrap(getState());\n if (!trap || !trap.container.isConnected) return;\n if (!lost && isInsideTrap(trap, el)) {\n trap.lastFocused = el;\n return;\n }\n const last = trap.lastFocused;\n const lastIsValid = !!last && last.isConnected && isInsideTrap(trap, last) && isFocusable(last);\n reclaiming = true;\n try {\n focusFirstPossible([\n lastIsValid ? last : null,\n getFirstTabbable(trap.container),\n trap.container,\n ]);\n } finally {\n reclaiming = false;\n }\n}\n\nfunction ensureListeners(state: TrapState): void {\n if (state.listeners || typeof document === 'undefined') return;\n const doc = document;\n doc.addEventListener('keydown', handleKeyDown);\n doc.addEventListener('focusin', handleFocusIn, true);\n state.listeners = {\n remove() {\n doc.removeEventListener('keydown', handleKeyDown);\n doc.removeEventListener('focusin', handleFocusIn, true);\n },\n };\n}\n\nfunction pushTrap(entry: TrapEntry): () => void {\n const state = getState();\n state.traps.push(entry);\n ensureListeners(state);\n return () => {\n const index = state.traps.indexOf(entry);\n if (index !== -1) state.traps.splice(index, 1);\n if (state.traps.length === 0) {\n state.listeners?.remove();\n state.listeners = null;\n }\n };\n}\n\nfunction resolveInitialFocus(\n container: HTMLElement,\n initialFocus: UseFocusTrapOptions['initialFocus'],\n): Array<HTMLElement | null> {\n const first = getFirstTabbable(container);\n if (initialFocus === 'container') return [container];\n if (initialFocus === undefined || initialFocus === 'first') return [first, container];\n const chosen = typeof initialFocus === 'function' ? initialFocus() : initialFocus.current;\n return [chosen, first, container];\n}\n\n/**\n * Keeps keyboard focus inside `container` while `enabled` (modal dialogs, drawers, the DatePicker\n * calendar). Element-based: pass the surface held in state via a callback ref, so the trap starts\n * when the element appears.\n *\n * - **Initial focus** runs synchronously in the commit in which the container appears (no\n * `requestAnimationFrame`), and does nothing when focus is already inside (an `autoFocus`\n * element wins).\n * - **Tab / Shift+Tab** are handled by a document bubble-phase `keydown` listener that ignores\n * events whose default is already prevented, so a React handler inside (a menu closing on Tab, a\n * grid) can take the key first. Focus wraps at the edges, and from the container itself or a\n * non-tabbable element it continues in document order. Tabbable elements are computed on every\n * keydown (content may change; radio-group stops depend on focus), never cached.\n * - Tabbables inside `[data-wave-focus-trap-allow]` regions (the Toaster viewport) join the cycle.\n * - **Descendant layers** (a popover or menu opened from inside, identified through `layerId`):\n * Tab moves natively inside them; leaving one moves focus to the element after its anchor\n * (Shift+Tab: the anchor itself). Inside a plain `<Portal>` rendered in the surface (no layer,\n * no anchor) Tab is native too; leaving it wraps to the first (Shift+Tab: last) element. A\n * layer's trigger (its anchor, or an element around it such as a tooltip's wrapper) belongs to\n * the region it sits in, so Tab from an open info button or a button showing its tooltip moves\n * on as from any other element of that portal or popover.\n * - Focus that lands outside (not in the container, an allowed region or a descendant layer)\n * returns to the last focused element inside, also when that outside element loses it again\n * (removed or blurred, leaving focus on `<body>`). That is decided in a microtask, once the\n * current commit has run: an `autoFocus` element of a surface opened above the trap (a nested or\n * stacked dialog, a popover opened from the surface) gets focus before that surface's layer and\n * trap exist, and keeps it. The layer's own `refs` (its trigger, outside the container) are\n * outside: opening from the focused trigger still moves focus in, and focus moving back onto\n * the trigger is returned. Focus pulled out again while it is being returned (another focus\n * trap on the page) is left there.\n * - Traps form a stack (shared through the global registry): only the topmost acts.\n */\nexport function useFocusTrap(container: HTMLElement | null, options: UseFocusTrapOptions): void {\n const { enabled } = options;\n const latestRef = useRef(options);\n\n useInsertionEffect(() => {\n latestRef.current = options;\n });\n\n useLayoutEffect(() => {\n if (!enabled || !container) return;\n const latest = latestRef;\n const state = getState();\n state.seq += 1;\n const entry: TrapEntry = {\n container,\n seq: state.seq,\n get layerId() {\n return latest.current.layerId;\n },\n get allowOutsideSelector() {\n return latest.current.allowOutsideSelector ?? ALLOW_OUTSIDE_SELECTOR;\n },\n lastFocused: null,\n };\n const release = pushTrap(entry);\n const focused = applyInitialFocus(container, {\n layerId: latest.current.layerId,\n initialFocus: latest.current.initialFocus,\n allowOutsideSelector: entry.allowOutsideSelector,\n });\n if (focused) entry.lastFocused = focused;\n return release;\n }, [enabled, container]);\n}\n\n/**\n * The initial focus of a surface (the trap's, and {@link useInitialFocus}'s): skipped when focus is\n * already inside the container or one of the descendant layers of `layerId` (never for the\n * layer's own trigger or an allow-listed toast), else `initialFocus` (default: the first tabbable\n * element), else the container. Returns the focused element when it is inside the container or\n * those layers (the trap's `lastFocused`), else `null`.\n */\nfunction applyInitialFocus(\n container: HTMLElement,\n options: {\n layerId: string | undefined;\n initialFocus: UseFocusTrapOptions['initialFocus'];\n allowOutsideSelector: string;\n },\n): HTMLElement | null {\n const active = container.ownerDocument.activeElement as HTMLElement | null;\n const focusInside =\n !!active &&\n (container.contains(active) ||\n (!active.closest(options.allowOutsideSelector) &&\n isInsideDescendantLayers(options.layerId, active)));\n if (focusInside) return active;\n focusFirstPossible(resolveInitialFocus(container, options.initialFocus));\n const now = container.ownerDocument.activeElement as HTMLElement | null;\n return now && container.contains(now) ? now : null;\n}\n\n/** Options of {@link useInitialFocus}. */\nexport interface UseInitialFocusOptions {\n /** Whether the surface is open: focus moves in when it becomes `true` with a container. */\n enabled: boolean;\n /** The surface's dismiss layer: focus already in one of its descendant layers stays there. */\n layerId?: string;\n /** What to focus first. @default 'first' (the first tabbable element, else the container) */\n initialFocus?: UseFocusTrapOptions['initialFocus'];\n}\n\n/**\n * The trap's initial focus without the trap (a non-modal Dialog or Drawer, which moves focus in\n * when it opens but does not keep it there): in the layout phase of the commit in which\n * `enabled && container` becomes true, does nothing when focus is already inside the container or\n * one of the layer's descendant layers (an `autoFocus` element wins), else focuses\n * `initialFocus` (default: the first tabbable element), else the container. `useFocusTrap` runs\n * the same code when it starts. It adds no listener.\n */\nexport function useInitialFocus(\n container: HTMLElement | null,\n options: UseInitialFocusOptions,\n): void {\n const { enabled } = options;\n const latestRef = useRef(options);\n\n useInsertionEffect(() => {\n latestRef.current = options;\n });\n\n useLayoutEffect(() => {\n if (!enabled || !container) return;\n applyInitialFocus(container, {\n layerId: latestRef.current.layerId,\n initialFocus: latestRef.current.initialFocus,\n allowOutsideSelector: ALLOW_OUTSIDE_SELECTOR,\n });\n }, [enabled, container]);\n}\n"],"mappings":"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"}