@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.
- package/README.md +357 -72
- package/dist/components/button/Toolbar.cjs +1 -1
- package/dist/components/button/Toolbar.cjs.map +1 -1
- package/dist/components/button/Toolbar.mjs +25 -30
- package/dist/components/button/Toolbar.mjs.map +1 -1
- package/dist/components/button/Toolbar.navigation.cjs +2 -0
- package/dist/components/button/Toolbar.navigation.cjs.map +1 -0
- package/dist/components/button/Toolbar.navigation.mjs +17 -0
- package/dist/components/button/Toolbar.navigation.mjs.map +1 -0
- package/dist/components/data-display/Avatar.cjs +1 -1
- package/dist/components/data-display/Avatar.cjs.map +1 -1
- package/dist/components/data-display/Avatar.context.cjs +2 -0
- package/dist/components/data-display/Avatar.context.cjs.map +1 -0
- package/dist/components/data-display/Avatar.context.mjs +9 -0
- package/dist/components/data-display/Avatar.context.mjs.map +1 -0
- package/dist/components/data-display/Avatar.mjs +66 -61
- package/dist/components/data-display/Avatar.mjs.map +1 -1
- package/dist/components/data-display/InteractionTag.cjs +2 -0
- package/dist/components/data-display/InteractionTag.cjs.map +1 -0
- package/dist/components/data-display/InteractionTag.mjs +234 -0
- package/dist/components/data-display/InteractionTag.mjs.map +1 -0
- package/dist/components/data-display/Tag.cjs +1 -1
- package/dist/components/data-display/Tag.cjs.map +1 -1
- package/dist/components/data-display/Tag.mjs +222 -90
- package/dist/components/data-display/Tag.mjs.map +1 -1
- package/dist/components/data-display/TagGroup.cjs +2 -0
- package/dist/components/data-display/TagGroup.cjs.map +1 -0
- package/dist/components/data-display/TagGroup.context.cjs +2 -0
- package/dist/components/data-display/TagGroup.context.cjs.map +1 -0
- package/dist/components/data-display/TagGroup.context.mjs +113 -0
- package/dist/components/data-display/TagGroup.context.mjs.map +1 -0
- package/dist/components/data-display/TagGroup.mjs +149 -0
- package/dist/components/data-display/TagGroup.mjs.map +1 -0
- package/dist/components/data-display/tagStyles.cjs +2 -0
- package/dist/components/data-display/tagStyles.cjs.map +1 -0
- package/dist/components/data-display/tagStyles.mjs +108 -0
- package/dist/components/data-display/tagStyles.mjs.map +1 -0
- package/dist/components/feedback/Toaster.cjs +1 -1
- package/dist/components/feedback/Toaster.cjs.map +1 -1
- package/dist/components/feedback/Toaster.mjs +213 -181
- package/dist/components/feedback/Toaster.mjs.map +1 -1
- package/dist/components/input/Combobox.expand.cjs +1 -1
- package/dist/components/input/Combobox.expand.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.mjs +7 -7
- package/dist/components/input/Combobox.expand.mjs.map +1 -1
- package/dist/components/input/Option.cjs +1 -1
- package/dist/components/input/Option.cjs.map +1 -1
- package/dist/components/input/Option.mjs +16 -11
- package/dist/components/input/Option.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.cjs.map +1 -1
- package/dist/components/input/SwatchPicker.context.cjs.map +1 -1
- package/dist/components/input/SwatchPicker.context.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.mjs.map +1 -1
- package/dist/components/input/TagPicker.cjs +1 -1
- package/dist/components/input/TagPicker.cjs.map +1 -1
- package/dist/components/input/TagPicker.context.cjs +2 -0
- package/dist/components/input/TagPicker.context.cjs.map +1 -0
- package/dist/components/input/TagPicker.context.mjs +20 -0
- package/dist/components/input/TagPicker.context.mjs.map +1 -0
- package/dist/components/input/TagPicker.create.cjs +2 -0
- package/dist/components/input/TagPicker.create.cjs.map +1 -0
- package/dist/components/input/TagPicker.create.mjs +24 -0
- package/dist/components/input/TagPicker.create.mjs.map +1 -0
- package/dist/components/input/TagPicker.mjs +13 -279
- package/dist/components/input/TagPicker.mjs.map +1 -1
- package/dist/components/input/TagPicker.option.cjs +2 -0
- package/dist/components/input/TagPicker.option.cjs.map +1 -0
- package/dist/components/input/TagPicker.option.mjs +45 -0
- package/dist/components/input/TagPicker.option.mjs.map +1 -0
- package/dist/components/input/TagPicker.overflow.cjs +2 -0
- package/dist/components/input/TagPicker.overflow.cjs.map +1 -0
- package/dist/components/input/TagPicker.overflow.mjs +153 -0
- package/dist/components/input/TagPicker.overflow.mjs.map +1 -0
- package/dist/components/input/TagPicker.parts.cjs +2 -0
- package/dist/components/input/TagPicker.parts.cjs.map +1 -0
- package/dist/components/input/TagPicker.parts.mjs +425 -0
- package/dist/components/input/TagPicker.parts.mjs.map +1 -0
- package/dist/components/input/TagPicker.root.cjs +2 -0
- package/dist/components/input/TagPicker.root.cjs.map +1 -0
- package/dist/components/input/TagPicker.root.mjs +416 -0
- package/dist/components/input/TagPicker.root.mjs.map +1 -0
- package/dist/components/layout/Accordion.cjs.map +1 -1
- package/dist/components/layout/Accordion.mjs.map +1 -1
- package/dist/components/navigation/Hamburger.cjs +2 -0
- package/dist/components/navigation/Hamburger.cjs.map +1 -0
- package/dist/components/navigation/Hamburger.mjs +54 -0
- package/dist/components/navigation/Hamburger.mjs.map +1 -0
- package/dist/components/navigation/Nav.cjs +1 -1
- package/dist/components/navigation/Nav.cjs.map +1 -1
- package/dist/components/navigation/Nav.context.cjs +2 -0
- package/dist/components/navigation/Nav.context.cjs.map +1 -0
- package/dist/components/navigation/Nav.context.mjs +137 -0
- package/dist/components/navigation/Nav.context.mjs.map +1 -0
- package/dist/components/navigation/Nav.mjs +151 -258
- package/dist/components/navigation/Nav.mjs.map +1 -1
- package/dist/components/navigation/Nav.parts.cjs +2 -0
- package/dist/components/navigation/Nav.parts.cjs.map +1 -0
- package/dist/components/navigation/Nav.parts.mjs +77 -0
- package/dist/components/navigation/Nav.parts.mjs.map +1 -0
- package/dist/components/navigation/Nav.root.cjs +2 -0
- package/dist/components/navigation/Nav.root.cjs.map +1 -0
- package/dist/components/navigation/Nav.root.mjs +78 -0
- package/dist/components/navigation/Nav.root.mjs.map +1 -0
- package/dist/components/navigation/NavDrawer.cjs +2 -0
- package/dist/components/navigation/NavDrawer.cjs.map +1 -0
- package/dist/components/navigation/NavDrawer.context.cjs +2 -0
- package/dist/components/navigation/NavDrawer.context.cjs.map +1 -0
- package/dist/components/navigation/NavDrawer.context.mjs +11 -0
- package/dist/components/navigation/NavDrawer.context.mjs.map +1 -0
- package/dist/components/navigation/NavDrawer.mjs +179 -0
- package/dist/components/navigation/NavDrawer.mjs.map +1 -0
- package/dist/components/overlays/Dialog.cjs +1 -1
- package/dist/components/overlays/Dialog.cjs.map +1 -1
- package/dist/components/overlays/Dialog.mjs +190 -125
- package/dist/components/overlays/Dialog.mjs.map +1 -1
- package/dist/components/overlays/Dialog.shared.cjs +1 -1
- package/dist/components/overlays/Dialog.shared.cjs.map +1 -1
- package/dist/components/overlays/Dialog.shared.mjs +157 -81
- package/dist/components/overlays/Dialog.shared.mjs.map +1 -1
- package/dist/components/overlays/Dialog.slots.cjs +2 -0
- package/dist/components/overlays/Dialog.slots.cjs.map +1 -0
- package/dist/components/overlays/Dialog.slots.mjs +129 -0
- package/dist/components/overlays/Dialog.slots.mjs.map +1 -0
- package/dist/components/overlays/Drawer.cjs +1 -1
- package/dist/components/overlays/Drawer.cjs.map +1 -1
- package/dist/components/overlays/Drawer.context.cjs +2 -0
- package/dist/components/overlays/Drawer.context.cjs.map +1 -0
- package/dist/components/overlays/Drawer.context.mjs +29 -0
- package/dist/components/overlays/Drawer.context.mjs.map +1 -0
- package/dist/components/overlays/Drawer.mjs +12 -187
- package/dist/components/overlays/Drawer.mjs.map +1 -1
- package/dist/components/overlays/Drawer.panel.cjs +2 -0
- package/dist/components/overlays/Drawer.panel.cjs.map +1 -0
- package/dist/components/overlays/Drawer.panel.mjs +159 -0
- package/dist/components/overlays/Drawer.panel.mjs.map +1 -0
- package/dist/components/overlays/Drawer.parts.cjs +2 -0
- package/dist/components/overlays/Drawer.parts.cjs.map +1 -0
- package/dist/components/overlays/Drawer.parts.mjs +152 -0
- package/dist/components/overlays/Drawer.parts.mjs.map +1 -0
- package/dist/components/overlays/Drawer.root.cjs +2 -0
- package/dist/components/overlays/Drawer.root.cjs.map +1 -0
- package/dist/components/overlays/Drawer.root.mjs +207 -0
- package/dist/components/overlays/Drawer.root.mjs.map +1 -0
- package/dist/components/overlays/Drawer.scroll.cjs +2 -0
- package/dist/components/overlays/Drawer.scroll.cjs.map +1 -0
- package/dist/components/overlays/Drawer.scroll.mjs +42 -0
- package/dist/components/overlays/Drawer.scroll.mjs.map +1 -0
- package/dist/hooks/useDismiss.cjs.map +1 -1
- package/dist/hooks/useDismiss.mjs.map +1 -1
- package/dist/hooks/useFocusTrap.cjs +1 -1
- package/dist/hooks/useFocusTrap.cjs.map +1 -1
- package/dist/hooks/useFocusTrap.mjs +115 -98
- package/dist/hooks/useFocusTrap.mjs.map +1 -1
- package/dist/hooks/useModalLayer.cjs +1 -1
- package/dist/hooks/useModalLayer.cjs.map +1 -1
- package/dist/hooks/useModalLayer.mjs +35 -22
- package/dist/hooks/useModalLayer.mjs.map +1 -1
- package/dist/hooks/useRestoreFocus.cjs +1 -1
- package/dist/hooks/useRestoreFocus.cjs.map +1 -1
- package/dist/hooks/useRestoreFocus.mjs +91 -78
- package/dist/hooks/useRestoreFocus.mjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.cjs +1 -1
- package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.mjs +102 -78
- package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2226 -221
- package/dist/index.d.ts +2226 -221
- package/dist/index.mjs +115 -107
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +137 -77
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/icons.cjs +1 -1
- package/dist/lib/icons.cjs.map +1 -1
- package/dist/lib/icons.mjs +13 -6
- package/dist/lib/icons.mjs.map +1 -1
- package/dist/lib/layers.cjs +1 -1
- package/dist/lib/layers.cjs.map +1 -1
- package/dist/lib/layers.mjs +53 -47
- package/dist/lib/layers.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/tokens.css +25 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useModalLayer.mjs","names":["useModalLayer","dismissOptions","options","layer","useDismiss","useFocusTrap","container","
|
|
1
|
+
{"version":3,"file":"useModalLayer.mjs","names":["useModalLayer","dismissOptions","options","nonModal","modalType","modal","open","layer","useDismiss","useFocusTrap","container","useInitialFocus","useModalIsolation","useScrollLock","useRestoreFocus"],"sources":["../../src/hooks/useModalLayer.ts"],"sourcesContent":["import type * as React from 'react';\nimport type { ModalType } from '../lib/types';\nimport { useDismiss, type DismissLayer, type UseDismissOptions } from './useDismiss';\nimport { useFocusTrap, useInitialFocus, type UseFocusTrapOptions } from './useFocusTrap';\nimport { useModalIsolation } from './useModalIsolation';\nimport { useRestoreFocus } from './useRestoreFocus';\nimport { useScrollLock } from './useScrollLock';\n\n/**\n * Options of {@link useModalLayer}: `useDismiss` options (the kind follows `modalType`) plus focus.\n */\nexport interface UseModalLayerOptions extends Omit<UseDismissOptions, 'kind'> {\n /** The modal surface, held in state via a callback ref. */\n container: HTMLElement | null;\n /**\n * `modal` (default) and `alert` register a `modal` layer, trap focus, isolate the page, lock its\n * scroll and restore focus (an `alert` layer ignores outside presses); `non-modal` registers a\n * `dialog` layer (`escape: 'inside'`, no outside press, no focus-outside), traps, isolates and\n * locks nothing, moves focus in on open with the trap's initial-focus rule and restores focus only\n * from inside (`requireFocusInside`).\n * @default 'modal'\n */\n modalType?: ModalType;\n /** What the focus trap (or a non-modal surface's initial focus) focuses first. @default 'first' */\n initialFocus?: UseFocusTrapOptions['initialFocus'];\n /** The trigger: preferred focus-restore target. */\n triggerRef?: React.RefObject<HTMLElement | null>;\n /** Consumer override for the focus-restore target. */\n finalFocusRef?: React.RefObject<HTMLElement | null>;\n}\n\n/**\n * Everything a modal surface (Dialog, Drawer) needs, composed in the order that works:\n *\n * 1. `useDismiss({ kind: 'modal' })` — Escape and outside presses (the backdrop is outside the\n * content surface, so a click on it dismisses; a drag from the content does not).\n * 2. `useFocusTrap` — initial focus, Tab cycle incl. toasts and descendant layers.\n * 3. `useModalIsolation` — the rest of the page is `inert` (instead of `aria-modal`).\n * 4. `useScrollLock` — ref-counted page scroll lock.\n * 5. `useRestoreFocus` — the opener (or `triggerRef`/`finalFocusRef`) gets focus back.\n *\n * On close the trap is released before the isolation is lifted, and the isolation is lifted\n * before focus is restored (an inert opener cannot take focus). Wrap the surface in\n * `Portal layerId={layerId}` so layers opened inside the modal become its descendants.\n *\n * `modalType: 'alert'` composes the same with `outsidePress: false`. `modalType: 'non-modal'`\n * registers a `dialog` layer (Escape only from inside its tree, no outside press, no focus-outside\n * dismissal), keeps the trap, the isolation and the scroll lock off, moves focus in on open with\n * the trap's initial-focus rule (`useInitialFocus`) and restores focus only when it is inside the\n * surface (or in a layer opened from it) at close, or was lost to `<body>` from there. Every hook\n * is always called and keys on `open`: a `modalType` that changes while open applies at once (the\n * trap, isolation and lock follow). It leaves focus inside the surface where it is; focus outside\n * it moves in, as on open: a switch to `modal` or `alert` starts the trap (the page turns inert),\n * and a switch to `non-modal` runs the initial focus (focus in the toast region, which a trap lets\n * in, moves into the surface). The Tab order of a non-modal surface (its place after the opener)\n * is the component's.\n *\n * A surface that mounts through the presence core (Dialog, Drawer) passes its open state as\n * `open`, never its mount (`isMounted`), and its element as `container` also while it is mounted\n * closed: the layer, the trap, the isolation and the scroll lock end and focus is restored in the\n * commit that closes it, while the element still runs its exit motion (`inert`) or stays mounted\n * (`hidden`, with `unmountOnClose={false}`); the next open starts them again with the same\n * element.\n */\nexport function useModalLayer(options: UseModalLayerOptions): DismissLayer {\n const {\n container,\n modalType = 'modal',\n initialFocus,\n triggerRef,\n finalFocusRef,\n ...dismissOptions\n } = options;\n const { open } = options;\n const nonModal = modalType === 'non-modal';\n const modal = open && !nonModal;\n\n const layer = useDismiss(\n nonModal\n ? {\n ...dismissOptions,\n kind: 'dialog',\n escape: 'inside',\n outsidePress: false,\n focusOutside: false,\n }\n : {\n ...dismissOptions,\n kind: 'modal',\n ...(modalType === 'alert' && { outsidePress: false }),\n },\n );\n useFocusTrap(container, { enabled: modal, layerId: layer.layerId, initialFocus });\n useInitialFocus(container, { enabled: open && nonModal, layerId: layer.layerId, initialFocus });\n useModalIsolation(modal, { layerId: layer.layerId, container });\n useScrollLock(modal);\n useRestoreFocus({\n enabled: open,\n container,\n triggerRef,\n finalFocusRef,\n requireFocusInside: nonModal,\n layerId: layer.layerId,\n });\n\n return layer;\n}\n"],"mappings":";;;;;;;AAgEA,SAAgBA,EAAc,GAA6C;CACzE,IAAM,EACJ,cACA,eAAY,SACZ,iBACA,eACA,kBACA,GAAGC,MACDC,GACE,EAAE,YAASA,GACXC,IAAWC,MAAc,aACzBC,IAAQC,KAAQ,CAACH,GAEjBI,IAAQC,EACZL,IACI;EACE,GAAGF;EACH,MAAM;EACN,QAAQ;EACR,cAAc;EACd,cAAc;CAChB,IACA;EACE,GAAGA;EACH,MAAM;EACN,GAAIG,MAAc,WAAW,EAAE,cAAc,GAAM;CACrD,CACN;CAcA,OAbAK,EAAaC,GAAW;EAAE,SAASL;EAAO,SAASE,EAAM;EAAS;CAAa,CAAC,GAChFI,EAAgBD,GAAW;EAAE,SAASJ,KAAQH;EAAU,SAASI,EAAM;EAAS;CAAa,CAAC,GAC9FK,EAAkBP,GAAO;EAAE,SAASE,EAAM;EAAS;CAAU,CAAC,GAC9DM,EAAcR,CAAK,GACnBS,EAAgB;EACd,SAASR;EACT;EACA;EACA;EACA,oBAAoBH;EACpB,SAASI,EAAM;CACjB,CAAC,GAEMA;AACT"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../lib/globalRegistry.cjs"),n=require("../lib/focus.cjs"),r=require("../lib/layers.cjs"),i=require("./useDismiss.cjs");let a=require("react");a=e.__toESM(a,1);var o=4,s=`[data-wave-portal]`;function c(e){return!e||!e.isConnected||!n.isFocusable(e)||e.closest(`[aria-hidden="true"]`)?!1:!r.isInsideOtherOpenModal(e)}function l(e){let t={path:[],next:[],previous:[]},n=e.ownerDocument.body;for(let r=e;r&&(t.path.push(r),t.next.push(r.nextElementSibling),t.previous.push(r.previousElementSibling),r!==n);r=r.parentElement);return t}function u(e,t){if(e.closest(`[data-wave-focus-trap-allow]`))return[];let n=r.getOpenLayers().filter(t=>r.isInsideLayerTree(t.id,e)).sort((e,t)=>r.compareLayers(t,e)),i=[];for(let r of n){let n=r.getAnchor();!n||n===e||t&&t.contains(n)||i.some(e=>e.element===n)||i.push({element:n,position:l(n)})}return i}function d(){let e=m();return e.surfaces??=new Set,e.surfaces}function f(e,t=new Set){if(t.has(e))return!1;if(t.add(e),e.isHoverClose())return!0;let n=e.getOpener();if(!n)return!1;for(let r of d()){let i=r===e?null:r.getContainer();if(i&&i.contains(n)&&f(r,t))return!0}return!1}function p(e,t){return e?f(e):t.isHoverClose?.()===!0}function m(){return t.getGlobalRegistry(`restoreFocusTracker`,()=>({users:0,last:null,uninstall:null}))}var h=1;function g(e){return!!e&&e.nodeType===h}function _(e,t){let n=t.ownerDocument;if(t===n.body||t===n.documentElement){e.last=null;return}e.last={element:t,position:l(t),anchors:u(t,null)}}function v(e){let t=e.last;if(!t||!t.element.isConnected)return;let n=u(t.element,null);for(let e of t.anchors)n.some(t=>t.element===e.element)||n.push(e);e.last={element:t.element,position:l(t.element),anchors:n}}function y(){if(typeof document>`u`)return()=>{};let e=m();if(e.users+=1,!e.uninstall){let t=document,i=t=>{g(t.target)&&_(e,t.target)},a=t=>{let r=t.target;!t.relatedTarget&&g(r)&&queueMicrotask(()=>{e.last?.element===r&&r.isConnected&&n.isFocusable(r)&&r.ownerDocument.activeElement!==r&&(e.last=null)})};t.addEventListener(`focusin`,i,!0),t.addEventListener(`focusout`,a,!0);let o=r.subscribeLayers(()=>v(e));g(t.activeElement)&&_(e,t.activeElement),e.uninstall=()=>{t.removeEventListener(`focusin`,i,!0),t.removeEventListener(`focusout`,a,!0),o(),e.last=null}}let t=!0;return()=>{t&&(t=!1,e.users=Math.max(0,e.users-1),!(e.users>0)&&(e.uninstall?.(),e.uninstall=null))}}function b(){let e=m().last;if(!e)return null;let{element:t}=e;return t.ownerDocument.activeElement===t||t.isConnected&&n.isFocusable(t)?null:e}function x(e){if(typeof document>`u`)return null;let{container:t,triggerRef:n}=e,r=e=>!!e&&e!==e.ownerDocument.body&&e!==e.ownerDocument.documentElement&&!(t&&t.contains(e)),i=n?.current,a=document.activeElement,o=null;if(r(i)?o=i:r(a)&&(o=a),o)return{element:o,position:l(o),anchors:u(o,t)};let s=b();return!s||!r(s.element)?null:{element:s.element,position:s.position,anchors:s.anchors.filter(e=>!(t&&t.contains(e.element)))}}function S(e){if(!e)return[];let t=[];for(let r of e.getElements()){if(!r)continue;t.push(r);let e=n.getFirstTabbable(r);e&&t.push(e)}return t}function C(e,t){let{ref:n,placement:r}=t;if(e===n)return r===`before`;let i=(n.compareDocumentPosition(e)&o)!==0;return r===`before`?i:i&&!n.contains(e)}function w(e){let{path:t}=e,n=t.findIndex(e=>e.isConnected);if(n===-1)return null;if(n===0){let e=t[0].parentElement;return e?{root:e,point:{ref:t[0],placement:`after`}}:null}if(t.slice(0,n).some(e=>e.matches(s)))return null;let r=t[n],i=e.next[n-1];if(i&&i.parentElement===r)return{root:r,point:{ref:i,placement:`before`}};let a=e.previous[n-1];return a&&a.parentElement===r?{root:r,point:{ref:a,placement:`after`}}:{root:r,point:{ref:r,placement:`before`}}}function T(e,t){let i=w(e);if(!i)return[];let{root:a,point:l}=i,u=a.ownerDocument.body,d=[];for(let e=a;e&&!(r.isInsideOtherOpenModal(e)||(d.push(e),e===u||e.matches(s)));e=e.parentElement);if(d.length===0)return[];let f=n.getTabbableElements(d[d.length-1]).filter(e=>!(t&&t.contains(e))&&c(e)).sort((e,t)=>(e.compareDocumentPosition(t)&o)===0?1:-1),p=[];for(let e of d){let t=f.filter(t=>e.contains(t)&&!p.includes(t)),n=t.find(e=>C(e,l)),r=t.filter(e=>!C(e,l)).pop();n&&p.push(n),r&&p.push(r)}return p}function E(e,t){if(typeof document>`u`)return!1;let n=document.activeElement,r=!n||n===document.body||n===document.documentElement;return!r&&e.container?.contains(n)?!0:!r&&e.onlyIfFocusInside?!1:!t()}function*
|
|
1
|
+
"use client";const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../lib/globalRegistry.cjs"),n=require("../lib/focus.cjs"),r=require("../lib/layers.cjs"),i=require("./useDismiss.cjs");let a=require("react");a=e.__toESM(a,1);var o=4,s=`[data-wave-portal]`;function c(e){return!e||!e.isConnected||!n.isFocusable(e)||e.closest(`[aria-hidden="true"]`)?!1:!r.isInsideOtherOpenModal(e)}function l(e){let t={path:[],next:[],previous:[]},n=e.ownerDocument.body;for(let r=e;r&&(t.path.push(r),t.next.push(r.nextElementSibling),t.previous.push(r.previousElementSibling),r!==n);r=r.parentElement);return t}function u(e,t){if(e.closest(`[data-wave-focus-trap-allow]`))return[];let n=r.getOpenLayers().filter(t=>r.isInsideLayerTree(t.id,e)).sort((e,t)=>r.compareLayers(t,e)),i=[];for(let r of n){let n=r.getAnchor();!n||n===e||t&&t.contains(n)||i.some(e=>e.element===n)||i.push({element:n,position:l(n)})}return i}function d(){let e=m();return e.surfaces??=new Set,e.surfaces}function f(e,t=new Set){if(t.has(e))return!1;if(t.add(e),e.isHoverClose())return!0;let n=e.getOpener();if(!n)return!1;for(let r of d()){let i=r===e?null:r.getContainer();if(i&&i.contains(n)&&f(r,t))return!0}return!1}function p(e,t){return e?f(e):t.isHoverClose?.()===!0}function m(){return t.getGlobalRegistry(`restoreFocusTracker`,()=>({users:0,last:null,uninstall:null}))}var h=1;function g(e){return!!e&&e.nodeType===h}function _(e,t){let n=t.ownerDocument;if(t===n.body||t===n.documentElement){e.last=null;return}e.last={element:t,position:l(t),anchors:u(t,null)}}function v(e){let t=e.last;if(!t||!t.element.isConnected)return;let n=u(t.element,null);for(let e of t.anchors)n.some(t=>t.element===e.element)||n.push(e);e.last={element:t.element,position:l(t.element),anchors:n}}function y(){if(typeof document>`u`)return()=>{};let e=m();if(e.users+=1,!e.uninstall){let t=document,i=t=>{g(t.target)&&_(e,t.target)},a=t=>{let r=t.target;!t.relatedTarget&&g(r)&&queueMicrotask(()=>{e.last?.element===r&&r.isConnected&&n.isFocusable(r)&&r.ownerDocument.activeElement!==r&&(e.last=null)})};t.addEventListener(`focusin`,i,!0),t.addEventListener(`focusout`,a,!0);let o=r.subscribeLayers(()=>v(e));g(t.activeElement)&&_(e,t.activeElement),e.uninstall=()=>{t.removeEventListener(`focusin`,i,!0),t.removeEventListener(`focusout`,a,!0),o(),e.last=null}}let t=!0;return()=>{t&&(t=!1,e.users=Math.max(0,e.users-1),!(e.users>0)&&(e.uninstall?.(),e.uninstall=null))}}function b(){let e=m().last;if(!e)return null;let{element:t}=e;return t.ownerDocument.activeElement===t||t.isConnected&&n.isFocusable(t)?null:e}function x(e){if(typeof document>`u`)return null;let{container:t,triggerRef:n}=e,r=e=>!!e&&e!==e.ownerDocument.body&&e!==e.ownerDocument.documentElement&&!(t&&t.contains(e)),i=n?.current,a=document.activeElement,o=null;if(r(i)?o=i:r(a)&&(o=a),o)return{element:o,position:l(o),anchors:u(o,t)};let s=b();return!s||!r(s.element)?null:{element:s.element,position:s.position,anchors:s.anchors.filter(e=>!(t&&t.contains(e.element)))}}function S(e){if(!e)return[];let t=[];for(let r of e.getElements()){if(!r)continue;t.push(r);let e=n.getFirstTabbable(r);e&&t.push(e)}return t}function C(e,t){let{ref:n,placement:r}=t;if(e===n)return r===`before`;let i=(n.compareDocumentPosition(e)&o)!==0;return r===`before`?i:i&&!n.contains(e)}function w(e){let{path:t}=e,n=t.findIndex(e=>e.isConnected);if(n===-1)return null;if(n===0){let e=t[0].parentElement;return e?{root:e,point:{ref:t[0],placement:`after`}}:null}if(t.slice(0,n).some(e=>e.matches(s)))return null;let r=t[n],i=e.next[n-1];if(i&&i.parentElement===r)return{root:r,point:{ref:i,placement:`before`}};let a=e.previous[n-1];return a&&a.parentElement===r?{root:r,point:{ref:a,placement:`after`}}:{root:r,point:{ref:r,placement:`before`}}}function T(e,t){let i=w(e);if(!i)return[];let{root:a,point:l}=i,u=a.ownerDocument.body,d=[];for(let e=a;e&&!(r.isInsideOtherOpenModal(e)||(d.push(e),e===u||e.matches(s)));e=e.parentElement);if(d.length===0)return[];let f=n.getTabbableElements(d[d.length-1]).filter(e=>!(t&&t.contains(e))&&c(e)).sort((e,t)=>(e.compareDocumentPosition(t)&o)===0?1:-1),p=[];for(let e of d){let t=f.filter(t=>e.contains(t)&&!p.includes(t)),n=t.find(e=>C(e,l)),r=t.filter(e=>!C(e,l)).pop();n&&p.push(n),r&&p.push(r)}return p}function E(e){if(!e)return!1;let t=b();return t?t.position.path.includes(e)?!0:t.anchors.some(t=>t.position.path.includes(e)):!1}function D(e,t,n){return!t||e.closest(`[data-wave-focus-trap-allow]`)?!1:r.getOpenLayers().some(i=>{if(i.id===n||!r.isInsideLayerTree(i.id,e))return!1;if(n!==void 0&&r.isDescendantLayer(i.id,n))return!0;let a=i.getAnchor();return!!a&&t.contains(a)})}function O(e,t){if(typeof document>`u`)return!1;let n=document.activeElement,r=!n||n===document.body||n===document.documentElement;return!r&&e.container?.contains(n)?!0:e.requireFocusInside?r?E(e.container)&&!t():D(n,e.container,e.layerId):!r&&e.onlyIfFocusInside?!1:!t()}function*k(e,t){yield*T(e.position,t);for(let t of e.anchors)yield t.element;for(let n of e.anchors)yield*T(n.position,t)}function*A(e,t){let{options:n,parentLayerId:i}=e;yield n.finalFocusRef?.current,yield t?.element,yield n.triggerRef?.current,yield n.fallback?.();let a=t?k(t,n.container):null,o=i===null?null:r.getLayer(i),s=[];if(o){for(let e of a??[])r.isInsideLayerTree(o.id,e)?yield e:s.push(e);yield*S(o),yield*s}else a&&(yield*a);yield*S(r.getTopmostLayer(e=>e.kind===`modal`))}function j(e,t){let r=e.options.container;for(let i of A(e,t))if(!(r&&i&&r.contains(i))&&c(i)&&n.focusElement(i,{preventScroll:!0}))return}function M(e){let t=a.useContext(i.DismissLayerContext),n=(0,a.useRef)({options:e,parentLayerId:t}),r=(0,a.useRef)(null),o=(0,a.useRef)(!1),s=(0,a.useRef)(!1),c=(0,a.useRef)(null),l=(0,a.useRef)(null),{enabled:u}=e;(0,a.useLayoutEffect)(()=>{let e=y(),t={isHoverClose:()=>n.current.options.isHoverClose?.()===!0,getContainer:()=>n.current.options.container??null,getOpener:()=>r.current?.element??n.current.options.triggerRef?.current??null};l.current=t;let i=d();return i.add(t),()=>{e(),queueMicrotask(()=>i.delete(t))}},[]),(0,a.useInsertionEffect)(()=>{n.current={options:e,parentLayerId:t};let i=o.current;o.current=e.enabled,e.enabled&&!i&&(r.current=x(e))}),(0,a.useLayoutEffect)(()=>{let e=s.current;if(s.current=u,u&&!e&&!r.current&&(r.current=x(n.current.options)),!e||u)return;let t=n.current,i=r.current,a=l.current,o=O(t.options,()=>p(a,t.options));r.current=null,o&&j(t,i)},[u]),(0,a.useLayoutEffect)(()=>{let e=n,t=r,i=c,a=l;return i.current=null,()=>{let n=e.current;if(!n.options.enabled)return;let r=a.current;if(!O(n.options,()=>p(r,n.options)))return;let o={};i.current=o;let s=t.current;queueMicrotask(()=>{if(i.current!==o)return;i.current=null;let e=typeof document>`u`?null:document.activeElement,t=n.options.container;(!e||e===document.body||e===document.documentElement||t&&t.contains(e))&&j(n,s)})}},[])}exports.useRestoreFocus=M;
|
|
2
2
|
//# sourceMappingURL=useRestoreFocus.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useRestoreFocus.cjs","names":["isFocusable","isInsideOtherOpenModal","getOpenLayers","isInsideLayerTree","compareLayers","getGlobalRegistry","subscribeLayers","getFirstTabbable","getTabbableElements","getLayer","getTopmostLayer","focusElement","React","DismissLayerContext","useRef","require_runtime","require_globalRegistry","require_focus","require_layers","require_useDismiss","react","FOLLOWING","PORTAL_SELECTOR","isValidTarget","el","recordPosition","position","body","node","captureAnchors","opener","layers","layer","b","a","anchors","anchor","container","entry","getSurfaceEntries","tracker","getFocusTracker","isClosingByHover","seen","other","isHoverCloseOf","options","ELEMENT_NODE","isElementTarget","target","recordFocus","doc","refreshFocusRecord","last","retainFocusTracker","onFocusIn","event","onFocusOut","unsubscribe","retained","getLostFocus","element","captureOpener","isCandidate","trigger","triggerRef","active","lost","getLayerTargets","targets","first","isAfterPoint","point","ref","placement","follows","resolvePoint","index","path","root","next","previous","getNearbyTargets","resolved","levels","level","candidates","inLevel","after","before","shouldRestore","onBody","isHoverClose","getReplacementTargets","restoreCandidates","latest","replacements","parentLayer","parentLayerId","outsideParent","restore","candidate","useRestoreFocus","latestRef","capturedRef","insertionEnabledRef","layoutEnabledRef","scheduledRef","entryRef","release","surfaces","wasEnabled","enabled","captured","acts","scheduled","entryHolder","snapshot","token"],"sources":["../../src/hooks/useRestoreFocus.ts"],"sourcesContent":["import * as React from 'react';\nimport { useInsertionEffect, useLayoutEffect, useRef } from 'react';\nimport { focusElement, getFirstTabbable, getTabbableElements, isFocusable } from '../lib/focus';\nimport { getGlobalRegistry } from '../lib/globalRegistry';\nimport {\n ALLOW_OUTSIDE_SELECTOR,\n compareLayers,\n getLayer,\n getOpenLayers,\n getTopmostLayer,\n isInsideLayerTree,\n isInsideOtherOpenModal,\n subscribeLayers,\n type LayerRecord,\n} from '../lib/layers';\nimport { DismissLayerContext } from './useDismiss';\n\n/** Options of {@link useRestoreFocus}. */\nexport interface UseRestoreFocusOptions {\n /** `true` while the surface is open. */\n enabled: boolean;\n /** The layer surface: opener candidates inside it are ignored. */\n container?: HTMLElement | null;\n /** The trigger: preferred restore target. */\n triggerRef?: React.RefObject<HTMLElement | null>;\n /** Consumer override: focused first when valid. */\n finalFocusRef?: React.RefObject<HTMLElement | null>;\n /** Used when neither the override, the opener nor the trigger can take focus. */\n fallback?: () => HTMLElement | null;\n /**\n * Popovers: restore only when focus was inside the surface (or lost to `<body>`) at close, so a\n * click that moved focus elsewhere is respected. @default false\n */\n onlyIfFocusInside?: boolean;\n /**\n * Read when the surface closes, or unmounts while open: `true` when the hover intent closed it\n * (Popover and Menu `openOnHover`, a submenu closing by hover). A hover close never moves focus:\n * it restores only while focus is inside the surface, so focus on `<body>` (where a hover-opened\n * surface leaves it) or elsewhere stays where it is. A surface opened from inside one that closes\n * by hover (its opener, else its trigger, lies in that surface: a submenu, a hover card in a\n * hover card, at any depth) is taken along, and its close counts as a hover close too. Every\n * other close keeps the rules above.\n */\n isHoverClose?: () => boolean;\n}\n\ninterface Latest {\n options: UseRestoreFocusOptions;\n parentLayerId: string | null;\n}\n\n/** Where an element sat in the document, recorded so a spot near it can be found once it is gone. */\ninterface DomPosition {\n /** The element and its ancestors up to `<body>`, innermost first. */\n path: Element[];\n /** The next element sibling of each `path` entry when it was recorded. */\n next: Array<Element | null>;\n /** The previous element sibling of each `path` entry when it was recorded. */\n previous: Array<Element | null>;\n}\n\n/** What is captured about the opener when the surface opens. */\ninterface OpenerRecord {\n element: HTMLElement;\n /** Its place in the document, used when it is removed or can no longer take focus. */\n position: DomPosition;\n /** The anchors (triggers) of the open layers whose tree held it, innermost layer first. */\n anchors: Array<{ element: HTMLElement; position: DomPosition }>;\n}\n\n/** A point in document order: just before `ref`, or just after `ref` and its subtree. */\ninterface DomPoint {\n ref: Element;\n placement: 'before' | 'after';\n}\n\nconst FOLLOWING = 4; // Node.DOCUMENT_POSITION_FOLLOWING\nconst PORTAL_SELECTOR = '[data-wave-portal]';\n\nfunction isValidTarget(el: HTMLElement | null | undefined): el is HTMLElement {\n if (!el || !el.isConnected) return false;\n if (!isFocusable(el)) return false; // also rejects [inert] ancestors, hidden and disabled\n if (el.closest('[aria-hidden=\"true\"]')) return false;\n return !isInsideOtherOpenModal(el);\n}\n\nfunction recordPosition(el: Element): DomPosition {\n const position: DomPosition = { path: [], next: [], previous: [] };\n const body = el.ownerDocument.body;\n for (let node: Element | null = el; node; node = node.parentElement) {\n position.path.push(node);\n position.next.push(node.nextElementSibling);\n position.previous.push(node.previousElementSibling);\n if (node === body) break;\n }\n return position;\n}\n\n/**\n * The anchors of the open layers whose tree contains `opener` (a menu item's menu button),\n * innermost layer first. An opener in an allow-listed region (a toast) belongs to no layer.\n */\nfunction captureAnchors(\n opener: HTMLElement,\n container: HTMLElement | null | undefined,\n): OpenerRecord['anchors'] {\n if (opener.closest(ALLOW_OUTSIDE_SELECTOR)) return [];\n const layers = getOpenLayers()\n .filter((layer) => isInsideLayerTree(layer.id, opener))\n .sort((a, b) => compareLayers(b, a));\n const anchors: OpenerRecord['anchors'] = [];\n for (const layer of layers) {\n const anchor = layer.getAnchor();\n if (!anchor || anchor === opener || (container && container.contains(anchor))) continue;\n if (anchors.some((entry) => entry.element === anchor)) continue;\n anchors.push({ element: anchor, position: recordPosition(anchor) });\n }\n return anchors;\n}\n\n// ---------------------------------------------------------------------------\n// Focus tracker\n// ---------------------------------------------------------------------------\n\n/**\n * Remembers the last focused element, with its place in the document and the anchors of the\n * overlays that held it, recorded while it is still in the document. A surface captures its opener\n * in the mutation phase, and by then React has already deleted anything earlier in the tree that\n * the same commit removes. A popover rendered before a dialog, whose menu item closes the popover\n * and opens the dialog, has lost its menu item (and focus is on `<body>`) when the dialog captures.\n * The record still leads the restore to the popover's trigger. It lives in\n * `getGlobalRegistry('restoreFocusTracker')`, so two copies of the library share one set of\n * listeners.\n */\ninterface FocusTracker {\n /** Mounted `useRestoreFocus` instances: the listeners are installed while there is one. */\n users: number;\n /** The last focused element; `null` once focus was moved away from it on purpose. */\n last: OpenerRecord | null;\n /** Removes the listeners; `null` while none are installed. */\n uninstall: (() => void) | null;\n /**\n * The mounted surfaces, as the other instances see them (see {@link isClosingByHover}). Created\n * on first use: a tracker made by another copy of the library does not have it.\n */\n surfaces?: Set<SurfaceEntry>;\n}\n\n/** A mounted `useRestoreFocus`, as the other instances see it. */\ninterface SurfaceEntry {\n /** Whether the surface is closing by hover (its `isHoverClose`). */\n isHoverClose(): boolean;\n /** The surface element, while there is one. */\n getContainer(): HTMLElement | null;\n /** The element the surface was opened from: its captured opener, else its trigger. */\n getOpener(): HTMLElement | null;\n}\n\nfunction getSurfaceEntries(): Set<SurfaceEntry> {\n const tracker = getFocusTracker();\n tracker.surfaces ??= new Set();\n return tracker.surfaces;\n}\n\n/**\n * Whether the close of `entry` is a hover close: its own, or that of a surface holding the element\n * it was opened from (a submenu in a menu that closes by hover, a hover card inside a hover card,\n * at any depth), which takes it along.\n */\nfunction isClosingByHover(entry: SurfaceEntry, seen = new Set<SurfaceEntry>()): boolean {\n if (seen.has(entry)) return false;\n seen.add(entry);\n if (entry.isHoverClose()) return true;\n const opener = entry.getOpener();\n if (!opener) return false;\n for (const other of getSurfaceEntries()) {\n const container = other === entry ? null : other.getContainer();\n if (container && container.contains(opener) && isClosingByHover(other, seen)) return true;\n }\n return false;\n}\n\n/** Whether this close is a hover close: the surface's own, or that of a surface it was opened from. */\nfunction isHoverCloseOf(entry: SurfaceEntry | null, options: UseRestoreFocusOptions): boolean {\n return entry ? isClosingByHover(entry) : options.isHoverClose?.() === true;\n}\n\nfunction getFocusTracker(): FocusTracker {\n return getGlobalRegistry<FocusTracker>('restoreFocusTracker', () => ({\n users: 0,\n last: null,\n uninstall: null,\n }));\n}\n\nconst ELEMENT_NODE = 1;\n\nfunction isElementTarget(target: EventTarget | null): target is HTMLElement {\n return !!target && (target as Partial<Node>).nodeType === ELEMENT_NODE;\n}\n\nfunction recordFocus(tracker: FocusTracker, el: HTMLElement): void {\n const doc = el.ownerDocument;\n if (el === doc.body || el === doc.documentElement) {\n tracker.last = null;\n return;\n }\n tracker.last = { element: el, position: recordPosition(el), anchors: captureAnchors(el, null) };\n}\n\n/**\n * A layer opened or closed: re-record the focused element's place and overlays while it is still in\n * the document. An element focused as its popover opens (autoFocus) gets focus before the\n * popover's layer registers. Anchors found earlier are kept (a layer unregistering as its content\n * is deleted no longer reports it).\n */\nfunction refreshFocusRecord(tracker: FocusTracker): void {\n const last = tracker.last;\n if (!last || !last.element.isConnected) return;\n const anchors = captureAnchors(last.element, null);\n for (const anchor of last.anchors) {\n if (!anchors.some((entry) => entry.element === anchor.element)) anchors.push(anchor);\n }\n tracker.last = { element: last.element, position: recordPosition(last.element), anchors };\n}\n\n/** Installs the tracker's listeners while at least one `useRestoreFocus` is mounted. */\nfunction retainFocusTracker(): () => void {\n if (typeof document === 'undefined') return () => {};\n const tracker = getFocusTracker();\n tracker.users += 1;\n if (!tracker.uninstall) {\n const doc = document;\n const onFocusIn = (event: FocusEvent) => {\n if (isElementTarget(event.target)) recordFocus(tracker, event.target);\n };\n // Focus leaves for nowhere when the element is removed (some browsers fire focusout then) or\n // when the user presses a non-focusable spot. Decide once the current task has run: an element\n // still in the document that can take focus was left on purpose and is no opener to return to.\n const onFocusOut = (event: FocusEvent) => {\n const target = event.target;\n if (event.relatedTarget || !isElementTarget(target)) return;\n queueMicrotask(() => {\n if (tracker.last?.element !== target) return;\n if (!target.isConnected || !isFocusable(target)) return;\n if (target.ownerDocument.activeElement !== target) tracker.last = null;\n });\n };\n doc.addEventListener('focusin', onFocusIn, true);\n doc.addEventListener('focusout', onFocusOut, true);\n const unsubscribe = subscribeLayers(() => refreshFocusRecord(tracker));\n if (isElementTarget(doc.activeElement)) recordFocus(tracker, doc.activeElement);\n tracker.uninstall = () => {\n doc.removeEventListener('focusin', onFocusIn, true);\n doc.removeEventListener('focusout', onFocusOut, true);\n unsubscribe();\n tracker.last = null;\n };\n }\n let retained = true;\n return () => {\n if (!retained) return;\n retained = false;\n tracker.users = Math.max(0, tracker.users - 1);\n if (tracker.users > 0) return;\n tracker.uninstall?.();\n tracker.uninstall = null;\n };\n}\n\n/**\n * The tracker's record of the element focus was lost from: it no longer has focus and was removed,\n * or can no longer take focus (disabled, hidden, made inert). `null` when focus was moved away from\n * it on purpose, or it still has focus.\n */\nfunction getLostFocus(): OpenerRecord | null {\n const last = getFocusTracker().last;\n if (!last) return null;\n const { element } = last;\n if (element.ownerDocument.activeElement === element) return null;\n if (element.isConnected && isFocusable(element)) return null;\n return last;\n}\n\n/**\n * The element to restore to when the surface opens: the trigger, else the focused element, else —\n * focus already lost to `<body>` — the element the focus tracker saw lose it.\n */\nfunction captureOpener(options: UseRestoreFocusOptions): OpenerRecord | null {\n if (typeof document === 'undefined') return null;\n const { container, triggerRef } = options;\n const isCandidate = (el: Element | null | undefined): el is HTMLElement =>\n !!el &&\n el !== el.ownerDocument.body &&\n el !== el.ownerDocument.documentElement &&\n !(container && container.contains(el));\n const trigger = triggerRef?.current;\n const active = document.activeElement;\n let element: HTMLElement | null = null;\n if (isCandidate(trigger)) element = trigger;\n else if (isCandidate(active)) element = active;\n if (element) {\n return {\n element,\n position: recordPosition(element),\n anchors: captureAnchors(element, container),\n };\n }\n // The opener was removed earlier in this commit (a menu item in a popover that closed as this\n // surface opened), or can no longer take focus: use what the tracker recorded while it could.\n const lost = getLostFocus();\n if (!lost || !isCandidate(lost.element)) return null;\n return {\n element: lost.element,\n position: lost.position,\n anchors: lost.anchors.filter((anchor) => !(container && container.contains(anchor.element))),\n };\n}\n\n/** A layer's surface (or its first tabbable element), for the last-resort fallbacks. */\nfunction getLayerTargets(layer: LayerRecord | null): HTMLElement[] {\n if (!layer) return [];\n const targets: HTMLElement[] = [];\n for (const el of layer.getElements()) {\n if (!el) continue;\n targets.push(el);\n const first = getFirstTabbable(el);\n if (first) targets.push(first);\n }\n return targets;\n}\n\nfunction isAfterPoint(el: Element, point: DomPoint): boolean {\n const { ref, placement } = point;\n if (el === ref) return placement === 'before';\n const follows = (ref.compareDocumentPosition(el) & FOLLOWING) !== 0;\n return placement === 'before' ? follows : follows && !ref.contains(el);\n}\n\n/**\n * Where to look once the recorded element is gone (or cannot take focus): its nearest ancestor\n * still in the document, and the point where the element used to be. `null` when its whole overlay\n * (the portal wrapper) was removed: that spot means nothing on the page.\n */\nfunction resolvePoint(position: DomPosition): { root: Element; point: DomPoint } | null {\n const { path } = position;\n const index = path.findIndex((el) => el.isConnected);\n if (index === -1) return null;\n if (index === 0) {\n const root = path[0].parentElement;\n return root ? { root, point: { ref: path[0], placement: 'after' } } : null;\n }\n if (path.slice(0, index).some((el) => el.matches(PORTAL_SELECTOR))) return null;\n const root = path[index];\n const next = position.next[index - 1];\n if (next && next.parentElement === root) {\n return { root, point: { ref: next, placement: 'before' } };\n }\n const previous = position.previous[index - 1];\n if (previous && previous.parentElement === root) {\n return { root, point: { ref: previous, placement: 'after' } };\n }\n return { root, point: { ref: root, placement: 'before' } };\n}\n\n/**\n * Tabbable elements near a recorded position, nearest first. In the innermost surviving ancestor\n * that holds a valid one: the first after the old spot (where Tab would have gone from there),\n * else the last before it; then the same one level up. The search stops at the element's overlay\n * (its portal wrapper) and never reaches behind an open modal.\n */\nfunction getNearbyTargets(\n position: DomPosition,\n container: HTMLElement | null | undefined,\n): HTMLElement[] {\n const resolved = resolvePoint(position);\n if (!resolved) return [];\n const { root, point } = resolved;\n const body = root.ownerDocument.body;\n const levels: Element[] = [];\n for (let level: Element | null = root; level; level = level.parentElement) {\n if (isInsideOtherOpenModal(level)) break;\n levels.push(level);\n if (level === body || level.matches(PORTAL_SELECTOR)) break;\n }\n if (levels.length === 0) return [];\n const candidates = getTabbableElements(levels[levels.length - 1])\n .filter((el) => !(container && container.contains(el)) && isValidTarget(el))\n .sort((a, b) => ((a.compareDocumentPosition(b) & FOLLOWING) !== 0 ? -1 : 1));\n const targets: HTMLElement[] = [];\n for (const level of levels) {\n const inLevel = candidates.filter((el) => level.contains(el) && !targets.includes(el));\n const after = inLevel.find((el) => isAfterPoint(el, point));\n const before = inLevel.filter((el) => !isAfterPoint(el, point)).pop();\n if (after) targets.push(after);\n if (before) targets.push(before);\n }\n return targets;\n}\n\n/**\n * Whether the restore acts for this close: always while focus is inside the surface; otherwise\n * never for a hover close (`isClosingByHover`, asked only then), and with `onlyIfFocusInside` only\n * when focus was lost to `<body>`.\n */\nfunction shouldRestore(options: UseRestoreFocusOptions, isHoverClose: () => boolean): boolean {\n if (typeof document === 'undefined') return false;\n const active = document.activeElement;\n const onBody = !active || active === document.body || active === document.documentElement;\n if (!onBody && options.container?.contains(active)) return true;\n if (!onBody && options.onlyIfFocusInside) return false;\n return !isHoverClose();\n}\n\n/**\n * Where to go when the opener was removed or can no longer take focus, nearest first: the tabbable\n * element next to where it was, else the trigger of the overlay it was in (a menu item's menu\n * button), else the element next to that trigger.\n */\nfunction* getReplacementTargets(\n opener: OpenerRecord,\n container: HTMLElement | null | undefined,\n): Generator<HTMLElement> {\n yield* getNearbyTargets(opener.position, container);\n for (const anchor of opener.anchors) yield anchor.element;\n for (const anchor of opener.anchors) yield* getNearbyTargets(anchor.position, container);\n}\n\n/** Restore targets in order of preference, computed lazily (the later ones cost more). */\nfunction* restoreCandidates(\n latest: Latest,\n opener: OpenerRecord | null,\n): Generator<HTMLElement | null | undefined> {\n const { options, parentLayerId } = latest;\n yield options.finalFocusRef?.current;\n yield opener?.element;\n yield options.triggerRef?.current;\n yield options.fallback?.();\n const replacements = opener ? getReplacementTargets(opener, options.container) : null;\n const parentLayer = parentLayerId === null ? null : getLayer(parentLayerId);\n const outsideParent: HTMLElement[] = [];\n if (parentLayer) {\n // The surface was rendered inside a layer that stays open (a confirm Dialog in a Drawer): the\n // opener's replacement inside that layer (the next row after a delete) comes before the\n // layer's surface, so where the surface sits in the React tree does not change the result.\n for (const target of replacements ?? []) {\n if (isInsideLayerTree(parentLayer.id, target)) yield target;\n else outsideParent.push(target);\n }\n yield* getLayerTargets(parentLayer);\n yield* outsideParent;\n } else if (replacements) {\n yield* replacements;\n }\n // Still nothing: into the modal that stays open, never onto the inert page behind it.\n yield* getLayerTargets(getTopmostLayer((layer) => layer.kind === 'modal'));\n}\n\nfunction restore(latest: Latest, opener: OpenerRecord | null): void {\n const container = latest.options.container;\n for (const candidate of restoreCandidates(latest, opener)) {\n if (container && candidate && container.contains(candidate)) continue;\n if (isValidTarget(candidate) && focusElement(candidate, { preventScroll: true })) return;\n }\n}\n\n/**\n * Returns focus to where it came from when a surface closes (dialogs, drawers, popovers, menus,\n * the DatePicker calendar, TeachingPopover).\n *\n * - **Capture**: when `enabled` flips to `true`, the opener is captured in an insertion effect —\n * before React applies `autoFocus` inside the new surface — preferring `triggerRef.current` and\n * ignoring `<body>` and elements inside `container`. Its place in the document and the triggers\n * of the overlays it sits in are recorded with it. When focus is already on `<body>` because\n * the focused element was removed earlier in the same commit (a menu item in a popover that\n * closes as the dialog it opens appears, the popover coming first in the tree), a document\n * focus tracker supplies that element with its recorded place and overlay triggers. The tracker\n * runs while any instance of the hook is mounted, and it forgets an element the user moved focus\n * away from on purpose.\n * - **Restore** when `enabled` flips to `false` (layout phase) and when the component unmounts\n * while enabled. The unmount restore runs in a microtask and is cancelled if the same instance\n * mounts again, so React StrictMode's simulated unmount does not pull focus out of a surface\n * that just opened.\n * - **Targets**, first valid wins:\n * 1. `finalFocusRef` → the captured opener → `triggerRef` → `fallback()`.\n * 2. When the opener was removed or cannot take focus, its replacement, nearest first: the\n * tabbable element next to where it was (in the innermost surviving ancestor that holds one,\n * the next one — the next row's action after a delete — else the previous one; then the same\n * one level up), else the trigger of the overlay it was in (a menu item's menu button), else\n * the element next to that trigger. When the surface is rendered inside another open layer\n * (its parent layer, from `DismissLayerContext`: a confirm Dialog in a Drawer's content),\n * only the replacements inside that layer's tree are tried here.\n * 3. The parent layer's surface, then the replacements outside the parent layer.\n * 4. The surface of the modal layer that stays open.\n *\n * So a confirm Dialog rendered in a Drawer's content and one rendered next to the Drawer both\n * return focus to the adjacent row, not to the Drawer's panel. A target is valid when it is\n * connected, focusable, not inside `[inert]` or `[aria-hidden=\"true\"]`, and not cut off behind\n * another open modal layer — so focus never lands on the inert page behind a Drawer that stays\n * open, and is not dropped on `<body>` while a valid target exists. Focus uses `preventScroll`.\n * - `onlyIfFocusInside` (popovers): restores only when focus is inside the surface or was lost to\n * `<body>`.\n * - `isHoverClose`: a close by the hover intent restores only when focus is inside the surface, so\n * a hover close never moves focus from `<body>` or from where the user put it. The same holds for\n * a surface opened from inside one that closes by hover (a submenu, a hover card in a hover\n * card): every mounted instance is known to the others through the focus tracker's record.\n */\nexport function useRestoreFocus(options: UseRestoreFocusOptions): void {\n const parentLayerId = React.useContext(DismissLayerContext);\n const latestRef = useRef<Latest>({ options, parentLayerId });\n const capturedRef = useRef<OpenerRecord | null>(null);\n const insertionEnabledRef = useRef(false);\n const layoutEnabledRef = useRef(false);\n const scheduledRef = useRef<object | null>(null);\n const entryRef = useRef<SurfaceEntry | null>(null);\n const { enabled } = options;\n\n // Track focus while mounted, so an opener removed in the commit that opens the surface is known.\n // And be known to the other instances: a surface closing by hover takes along the surfaces opened\n // from inside it, whose closes are then hover closes too.\n useLayoutEffect(() => {\n const release = retainFocusTracker();\n const entry: SurfaceEntry = {\n isHoverClose: () => latestRef.current.options.isHoverClose?.() === true,\n getContainer: () => latestRef.current.options.container ?? null,\n getOpener: () =>\n capturedRef.current?.element ?? latestRef.current.options.triggerRef?.current ?? null,\n };\n entryRef.current = entry;\n const surfaces = getSurfaceEntries();\n surfaces.add(entry);\n return () => {\n release();\n // Kept to the end of the commit: a surface opened from inside this one, closing along with\n // it, still asks about it.\n queueMicrotask(() => surfaces.delete(entry));\n };\n }, []);\n\n // Mutation phase: record the latest options and capture the opener when `enabled` turns on,\n // before autoFocus (layout phase) or a focus trap's initial focus moves focus into the surface.\n useInsertionEffect(() => {\n latestRef.current = { options, parentLayerId };\n const wasEnabled = insertionEnabledRef.current;\n insertionEnabledRef.current = options.enabled;\n if (options.enabled && !wasEnabled) capturedRef.current = captureOpener(options);\n });\n\n // `enabled` true → false: restore in the layout phase (after every cleanup of this commit, so a\n // modal's isolation is already gone).\n useLayoutEffect(() => {\n const wasEnabled = layoutEnabledRef.current;\n layoutEnabledRef.current = enabled;\n if (!wasEnabled || enabled) return;\n const latest = latestRef.current;\n const captured = capturedRef.current;\n const entry = entryRef.current;\n // Decided before the opener is dropped: a hover close is also recognised through it.\n const acts = shouldRestore(latest.options, () => isHoverCloseOf(entry, latest.options));\n capturedRef.current = null;\n if (acts) restore(latest, captured);\n }, [enabled]);\n\n // Unmount while enabled: restore in a microtask, cancelled by a remount of this instance.\n useLayoutEffect(() => {\n const latest = latestRef;\n const captured = capturedRef;\n const scheduled = scheduledRef;\n const entryHolder = entryRef;\n scheduled.current = null;\n return () => {\n const snapshot = latest.current;\n if (!snapshot.options.enabled) return;\n // Decide now, while the surface is still in the document.\n const entry = entryHolder.current;\n if (!shouldRestore(snapshot.options, () => isHoverCloseOf(entry, snapshot.options))) return;\n const token = {};\n scheduled.current = token;\n const opener = captured.current;\n queueMicrotask(() => {\n if (scheduled.current !== token) return;\n scheduled.current = null;\n const active = typeof document === 'undefined' ? null : document.activeElement;\n const container = snapshot.options.container;\n // Focus placed elsewhere in the meantime (another surface opened) wins.\n if (\n active &&\n active !== document.body &&\n active !== document.documentElement &&\n !(container && container.contains(active))\n ) {\n return;\n }\n restore(snapshot, opener);\n });\n };\n }, []);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useRestoreFocus.cjs","names":["isFocusable","isInsideOtherOpenModal","getOpenLayers","isInsideLayerTree","compareLayers","getGlobalRegistry","subscribeLayers","getFirstTabbable","getTabbableElements","isDescendantLayer","getLayer","getTopmostLayer","focusElement","React","DismissLayerContext","useRef","require_runtime","require_globalRegistry","require_focus","require_layers","require_useDismiss","react","FOLLOWING","PORTAL_SELECTOR","isValidTarget","el","recordPosition","position","body","node","captureAnchors","opener","layers","layer","b","a","anchors","anchor","container","entry","getSurfaceEntries","tracker","getFocusTracker","isClosingByHover","seen","other","isHoverCloseOf","options","ELEMENT_NODE","isElementTarget","target","recordFocus","doc","refreshFocusRecord","last","retainFocusTracker","onFocusIn","event","onFocusOut","unsubscribe","retained","getLostFocus","element","captureOpener","isCandidate","trigger","triggerRef","active","lost","getLayerTargets","targets","first","isAfterPoint","point","ref","placement","follows","resolvePoint","index","path","root","next","previous","getNearbyTargets","resolved","levels","level","candidates","inLevel","after","before","isFocusLostFromInside","isInLayerOpenedFrom","layerId","shouldRestore","onBody","isHoverClose","getReplacementTargets","restoreCandidates","latest","replacements","parentLayer","parentLayerId","outsideParent","restore","candidate","useRestoreFocus","latestRef","capturedRef","insertionEnabledRef","layoutEnabledRef","scheduledRef","entryRef","release","surfaces","wasEnabled","enabled","captured","acts","scheduled","entryHolder","snapshot","token"],"sources":["../../src/hooks/useRestoreFocus.ts"],"sourcesContent":["import * as React from 'react';\nimport { useInsertionEffect, useLayoutEffect, useRef } from 'react';\nimport { focusElement, getFirstTabbable, getTabbableElements, isFocusable } from '../lib/focus';\nimport { getGlobalRegistry } from '../lib/globalRegistry';\nimport {\n ALLOW_OUTSIDE_SELECTOR,\n compareLayers,\n getLayer,\n getOpenLayers,\n getTopmostLayer,\n isDescendantLayer,\n isInsideLayerTree,\n isInsideOtherOpenModal,\n subscribeLayers,\n type LayerRecord,\n} from '../lib/layers';\nimport { DismissLayerContext } from './useDismiss';\n\n/** Options of {@link useRestoreFocus}. */\nexport interface UseRestoreFocusOptions {\n /** `true` while the surface is open. */\n enabled: boolean;\n /** The layer surface: opener candidates inside it are ignored. */\n container?: HTMLElement | null;\n /** The trigger: preferred restore target. */\n triggerRef?: React.RefObject<HTMLElement | null>;\n /** Consumer override: focused first when valid. */\n finalFocusRef?: React.RefObject<HTMLElement | null>;\n /** Used when neither the override, the opener nor the trigger can take focus. */\n fallback?: () => HTMLElement | null;\n /**\n * Popovers: restore only when focus was inside the surface (or lost to `<body>`) at close, so a\n * click that moved focus elsewhere is respected. @default false\n */\n onlyIfFocusInside?: boolean;\n /**\n * Read when the surface closes, or unmounts while open: `true` when the hover intent closed it\n * (Popover and Menu `openOnHover`, a submenu closing by hover). A hover close never moves focus:\n * it restores only while focus is inside the surface, so focus on `<body>` (where a hover-opened\n * surface leaves it) or elsewhere stays where it is. A surface opened from inside one that closes\n * by hover (its opener, else its trigger, lies in that surface: a submenu, a hover card in a\n * hover card, at any depth) is taken along, and its close counts as a hover close too. Every\n * other close keeps the rules above.\n */\n isHoverClose?: () => boolean;\n /**\n * Surfaces that do not trap focus (a non-modal Dialog or Drawer, an inline Drawer): restore only\n * when focus is inside the surface at close, or was lost to `<body>` from an element inside it\n * (removed, or made unable to take focus). Focus elsewhere, or on `<body>` for another reason\n * (nothing had focus, a press on a spot that takes no focus, a close from code), stays where it\n * is. Wins over `onlyIfFocusInside`. Focus in a layer opened from the surface (a Popover or a\n * confirm Dialog, portaled outside it) counts as inside: a descendant layer of `layerId`, or a\n * layer anchored to an element inside the surface; so does focus lost to `<body>` from one.\n * @default false\n */\n requireFocusInside?: boolean;\n /**\n * The surface's own dismiss layer, with `requireFocusInside`: focus in one of its descendant\n * layers counts as inside the surface, also after the surface's layer has unregistered (in the\n * commit that closes it).\n */\n layerId?: string;\n}\n\ninterface Latest {\n options: UseRestoreFocusOptions;\n parentLayerId: string | null;\n}\n\n/** Where an element sat in the document, recorded so a spot near it can be found once it is gone. */\ninterface DomPosition {\n /** The element and its ancestors up to `<body>`, innermost first. */\n path: Element[];\n /** The next element sibling of each `path` entry when it was recorded. */\n next: Array<Element | null>;\n /** The previous element sibling of each `path` entry when it was recorded. */\n previous: Array<Element | null>;\n}\n\n/** What is captured about the opener when the surface opens. */\ninterface OpenerRecord {\n element: HTMLElement;\n /** Its place in the document, used when it is removed or can no longer take focus. */\n position: DomPosition;\n /** The anchors (triggers) of the open layers whose tree held it, innermost layer first. */\n anchors: Array<{ element: HTMLElement; position: DomPosition }>;\n}\n\n/** A point in document order: just before `ref`, or just after `ref` and its subtree. */\ninterface DomPoint {\n ref: Element;\n placement: 'before' | 'after';\n}\n\nconst FOLLOWING = 4; // Node.DOCUMENT_POSITION_FOLLOWING\nconst PORTAL_SELECTOR = '[data-wave-portal]';\n\nfunction isValidTarget(el: HTMLElement | null | undefined): el is HTMLElement {\n if (!el || !el.isConnected) return false;\n if (!isFocusable(el)) return false; // also rejects [inert] ancestors, hidden and disabled\n if (el.closest('[aria-hidden=\"true\"]')) return false;\n return !isInsideOtherOpenModal(el);\n}\n\nfunction recordPosition(el: Element): DomPosition {\n const position: DomPosition = { path: [], next: [], previous: [] };\n const body = el.ownerDocument.body;\n for (let node: Element | null = el; node; node = node.parentElement) {\n position.path.push(node);\n position.next.push(node.nextElementSibling);\n position.previous.push(node.previousElementSibling);\n if (node === body) break;\n }\n return position;\n}\n\n/**\n * The anchors of the open layers whose tree contains `opener` (a menu item's menu button),\n * innermost layer first. An opener in an allow-listed region (a toast) belongs to no layer.\n */\nfunction captureAnchors(\n opener: HTMLElement,\n container: HTMLElement | null | undefined,\n): OpenerRecord['anchors'] {\n if (opener.closest(ALLOW_OUTSIDE_SELECTOR)) return [];\n const layers = getOpenLayers()\n .filter((layer) => isInsideLayerTree(layer.id, opener))\n .sort((a, b) => compareLayers(b, a));\n const anchors: OpenerRecord['anchors'] = [];\n for (const layer of layers) {\n const anchor = layer.getAnchor();\n if (!anchor || anchor === opener || (container && container.contains(anchor))) continue;\n if (anchors.some((entry) => entry.element === anchor)) continue;\n anchors.push({ element: anchor, position: recordPosition(anchor) });\n }\n return anchors;\n}\n\n// ---------------------------------------------------------------------------\n// Focus tracker\n// ---------------------------------------------------------------------------\n\n/**\n * Remembers the last focused element, with its place in the document and the anchors of the\n * overlays that held it, recorded while it is still in the document. A surface captures its opener\n * in the mutation phase, and by then React has already deleted anything earlier in the tree that\n * the same commit removes. A popover rendered before a dialog, whose menu item closes the popover\n * and opens the dialog, has lost its menu item (and focus is on `<body>`) when the dialog captures.\n * The record still leads the restore to the popover's trigger. It lives in\n * `getGlobalRegistry('restoreFocusTracker')`, so two copies of the library share one set of\n * listeners.\n */\ninterface FocusTracker {\n /** Mounted `useRestoreFocus` instances: the listeners are installed while there is one. */\n users: number;\n /** The last focused element; `null` once focus was moved away from it on purpose. */\n last: OpenerRecord | null;\n /** Removes the listeners; `null` while none are installed. */\n uninstall: (() => void) | null;\n /**\n * The mounted surfaces, as the other instances see them (see {@link isClosingByHover}). Created\n * on first use: a tracker made by another copy of the library does not have it.\n */\n surfaces?: Set<SurfaceEntry>;\n}\n\n/** A mounted `useRestoreFocus`, as the other instances see it. */\ninterface SurfaceEntry {\n /** Whether the surface is closing by hover (its `isHoverClose`). */\n isHoverClose(): boolean;\n /** The surface element, while there is one. */\n getContainer(): HTMLElement | null;\n /** The element the surface was opened from: its captured opener, else its trigger. */\n getOpener(): HTMLElement | null;\n}\n\nfunction getSurfaceEntries(): Set<SurfaceEntry> {\n const tracker = getFocusTracker();\n tracker.surfaces ??= new Set();\n return tracker.surfaces;\n}\n\n/**\n * Whether the close of `entry` is a hover close: its own, or that of a surface holding the element\n * it was opened from (a submenu in a menu that closes by hover, a hover card inside a hover card,\n * at any depth), which takes it along.\n */\nfunction isClosingByHover(entry: SurfaceEntry, seen = new Set<SurfaceEntry>()): boolean {\n if (seen.has(entry)) return false;\n seen.add(entry);\n if (entry.isHoverClose()) return true;\n const opener = entry.getOpener();\n if (!opener) return false;\n for (const other of getSurfaceEntries()) {\n const container = other === entry ? null : other.getContainer();\n if (container && container.contains(opener) && isClosingByHover(other, seen)) return true;\n }\n return false;\n}\n\n/** Whether this close is a hover close: the surface's own, or that of a surface it was opened from. */\nfunction isHoverCloseOf(entry: SurfaceEntry | null, options: UseRestoreFocusOptions): boolean {\n return entry ? isClosingByHover(entry) : options.isHoverClose?.() === true;\n}\n\nfunction getFocusTracker(): FocusTracker {\n return getGlobalRegistry<FocusTracker>('restoreFocusTracker', () => ({\n users: 0,\n last: null,\n uninstall: null,\n }));\n}\n\nconst ELEMENT_NODE = 1;\n\nfunction isElementTarget(target: EventTarget | null): target is HTMLElement {\n return !!target && (target as Partial<Node>).nodeType === ELEMENT_NODE;\n}\n\nfunction recordFocus(tracker: FocusTracker, el: HTMLElement): void {\n const doc = el.ownerDocument;\n if (el === doc.body || el === doc.documentElement) {\n tracker.last = null;\n return;\n }\n tracker.last = { element: el, position: recordPosition(el), anchors: captureAnchors(el, null) };\n}\n\n/**\n * A layer opened or closed: re-record the focused element's place and overlays while it is still in\n * the document. An element focused as its popover opens (autoFocus) gets focus before the\n * popover's layer registers. Anchors found earlier are kept (a layer unregistering as its content\n * is deleted no longer reports it).\n */\nfunction refreshFocusRecord(tracker: FocusTracker): void {\n const last = tracker.last;\n if (!last || !last.element.isConnected) return;\n const anchors = captureAnchors(last.element, null);\n for (const anchor of last.anchors) {\n if (!anchors.some((entry) => entry.element === anchor.element)) anchors.push(anchor);\n }\n tracker.last = { element: last.element, position: recordPosition(last.element), anchors };\n}\n\n/** Installs the tracker's listeners while at least one `useRestoreFocus` is mounted. */\nfunction retainFocusTracker(): () => void {\n if (typeof document === 'undefined') return () => {};\n const tracker = getFocusTracker();\n tracker.users += 1;\n if (!tracker.uninstall) {\n const doc = document;\n const onFocusIn = (event: FocusEvent) => {\n if (isElementTarget(event.target)) recordFocus(tracker, event.target);\n };\n // Focus leaves for nowhere when the element is removed (some browsers fire focusout then) or\n // when the user presses a non-focusable spot. Decide once the current task has run: an element\n // still in the document that can take focus was left on purpose and is no opener to return to.\n const onFocusOut = (event: FocusEvent) => {\n const target = event.target;\n if (event.relatedTarget || !isElementTarget(target)) return;\n queueMicrotask(() => {\n if (tracker.last?.element !== target) return;\n if (!target.isConnected || !isFocusable(target)) return;\n if (target.ownerDocument.activeElement !== target) tracker.last = null;\n });\n };\n doc.addEventListener('focusin', onFocusIn, true);\n doc.addEventListener('focusout', onFocusOut, true);\n const unsubscribe = subscribeLayers(() => refreshFocusRecord(tracker));\n if (isElementTarget(doc.activeElement)) recordFocus(tracker, doc.activeElement);\n tracker.uninstall = () => {\n doc.removeEventListener('focusin', onFocusIn, true);\n doc.removeEventListener('focusout', onFocusOut, true);\n unsubscribe();\n tracker.last = null;\n };\n }\n let retained = true;\n return () => {\n if (!retained) return;\n retained = false;\n tracker.users = Math.max(0, tracker.users - 1);\n if (tracker.users > 0) return;\n tracker.uninstall?.();\n tracker.uninstall = null;\n };\n}\n\n/**\n * The tracker's record of the element focus was lost from: it no longer has focus and was removed,\n * or can no longer take focus (disabled, hidden, made inert). `null` when focus was moved away from\n * it on purpose, or it still has focus.\n */\nfunction getLostFocus(): OpenerRecord | null {\n const last = getFocusTracker().last;\n if (!last) return null;\n const { element } = last;\n if (element.ownerDocument.activeElement === element) return null;\n if (element.isConnected && isFocusable(element)) return null;\n return last;\n}\n\n/**\n * The element to restore to when the surface opens: the trigger, else the focused element, else —\n * focus already lost to `<body>` — the element the focus tracker saw lose it.\n */\nfunction captureOpener(options: UseRestoreFocusOptions): OpenerRecord | null {\n if (typeof document === 'undefined') return null;\n const { container, triggerRef } = options;\n const isCandidate = (el: Element | null | undefined): el is HTMLElement =>\n !!el &&\n el !== el.ownerDocument.body &&\n el !== el.ownerDocument.documentElement &&\n !(container && container.contains(el));\n const trigger = triggerRef?.current;\n const active = document.activeElement;\n let element: HTMLElement | null = null;\n if (isCandidate(trigger)) element = trigger;\n else if (isCandidate(active)) element = active;\n if (element) {\n return {\n element,\n position: recordPosition(element),\n anchors: captureAnchors(element, container),\n };\n }\n // The opener was removed earlier in this commit (a menu item in a popover that closed as this\n // surface opened), or can no longer take focus: use what the tracker recorded while it could.\n const lost = getLostFocus();\n if (!lost || !isCandidate(lost.element)) return null;\n return {\n element: lost.element,\n position: lost.position,\n anchors: lost.anchors.filter((anchor) => !(container && container.contains(anchor.element))),\n };\n}\n\n/** A layer's surface (or its first tabbable element), for the last-resort fallbacks. */\nfunction getLayerTargets(layer: LayerRecord | null): HTMLElement[] {\n if (!layer) return [];\n const targets: HTMLElement[] = [];\n for (const el of layer.getElements()) {\n if (!el) continue;\n targets.push(el);\n const first = getFirstTabbable(el);\n if (first) targets.push(first);\n }\n return targets;\n}\n\nfunction isAfterPoint(el: Element, point: DomPoint): boolean {\n const { ref, placement } = point;\n if (el === ref) return placement === 'before';\n const follows = (ref.compareDocumentPosition(el) & FOLLOWING) !== 0;\n return placement === 'before' ? follows : follows && !ref.contains(el);\n}\n\n/**\n * Where to look once the recorded element is gone (or cannot take focus): its nearest ancestor\n * still in the document, and the point where the element used to be. `null` when its whole overlay\n * (the portal wrapper) was removed: that spot means nothing on the page.\n */\nfunction resolvePoint(position: DomPosition): { root: Element; point: DomPoint } | null {\n const { path } = position;\n const index = path.findIndex((el) => el.isConnected);\n if (index === -1) return null;\n if (index === 0) {\n const root = path[0].parentElement;\n return root ? { root, point: { ref: path[0], placement: 'after' } } : null;\n }\n if (path.slice(0, index).some((el) => el.matches(PORTAL_SELECTOR))) return null;\n const root = path[index];\n const next = position.next[index - 1];\n if (next && next.parentElement === root) {\n return { root, point: { ref: next, placement: 'before' } };\n }\n const previous = position.previous[index - 1];\n if (previous && previous.parentElement === root) {\n return { root, point: { ref: previous, placement: 'after' } };\n }\n return { root, point: { ref: root, placement: 'before' } };\n}\n\n/**\n * Tabbable elements near a recorded position, nearest first. In the innermost surviving ancestor\n * that holds a valid one: the first after the old spot (where Tab would have gone from there),\n * else the last before it; then the same one level up. The search stops at the element's overlay\n * (its portal wrapper) and never reaches behind an open modal.\n */\nfunction getNearbyTargets(\n position: DomPosition,\n container: HTMLElement | null | undefined,\n): HTMLElement[] {\n const resolved = resolvePoint(position);\n if (!resolved) return [];\n const { root, point } = resolved;\n const body = root.ownerDocument.body;\n const levels: Element[] = [];\n for (let level: Element | null = root; level; level = level.parentElement) {\n if (isInsideOtherOpenModal(level)) break;\n levels.push(level);\n if (level === body || level.matches(PORTAL_SELECTOR)) break;\n }\n if (levels.length === 0) return [];\n const candidates = getTabbableElements(levels[levels.length - 1])\n .filter((el) => !(container && container.contains(el)) && isValidTarget(el))\n .sort((a, b) => ((a.compareDocumentPosition(b) & FOLLOWING) !== 0 ? -1 : 1));\n const targets: HTMLElement[] = [];\n for (const level of levels) {\n const inLevel = candidates.filter((el) => level.contains(el) && !targets.includes(el));\n const after = inLevel.find((el) => isAfterPoint(el, point));\n const before = inLevel.filter((el) => !isAfterPoint(el, point)).pop();\n if (after) targets.push(after);\n if (before) targets.push(before);\n }\n return targets;\n}\n\n/**\n * Whether focus was lost to `<body>` from an element inside `container`: the focus tracker's record\n * of the element that lost it ({@link getLostFocus}) lies in the container (its recorded path holds\n * it), also when the element has been removed since.\n */\nfunction isFocusLostFromInside(container: HTMLElement | null | undefined): boolean {\n if (!container) return false;\n const lost = getLostFocus();\n if (!lost) return false;\n if (lost.position.path.includes(container)) return true;\n // Lost from a layer opened from the surface: the overlays that held it are anchored inside.\n return lost.anchors.some((anchor) => anchor.position.path.includes(container));\n}\n\n/**\n * Whether `active` is in a layer opened from the surface (portaled outside it): a descendant layer\n * of the surface's layer (`layerId`), or an open layer whose tree holds it and whose anchor (its\n * trigger) is inside the surface. The toast region counts as inside every layer, never here.\n */\nfunction isInLayerOpenedFrom(\n active: Element,\n container: HTMLElement | null | undefined,\n layerId: string | undefined,\n): boolean {\n if (!container || active.closest(ALLOW_OUTSIDE_SELECTOR)) return false;\n return getOpenLayers().some((layer) => {\n if (layer.id === layerId || !isInsideLayerTree(layer.id, active)) return false;\n if (layerId !== undefined && isDescendantLayer(layer.id, layerId)) return true;\n const anchor = layer.getAnchor();\n return !!anchor && container.contains(anchor);\n });\n}\n\n/**\n * Whether the restore acts for this close: always while focus is inside the surface; otherwise\n * never for a hover close (`isClosingByHover`, asked only then), and with `onlyIfFocusInside` only\n * when focus was lost to `<body>`. With `requireFocusInside`, also while focus is in a layer opened\n * from the surface, from `<body>` only when focus was lost there from inside the surface (or from\n * such a layer), and never from anywhere else.\n */\nfunction shouldRestore(options: UseRestoreFocusOptions, isHoverClose: () => boolean): boolean {\n if (typeof document === 'undefined') return false;\n const active = document.activeElement;\n const onBody = !active || active === document.body || active === document.documentElement;\n if (!onBody && options.container?.contains(active)) return true;\n if (options.requireFocusInside) {\n if (!onBody) return isInLayerOpenedFrom(active, options.container, options.layerId);\n return isFocusLostFromInside(options.container) && !isHoverClose();\n }\n if (!onBody && options.onlyIfFocusInside) return false;\n return !isHoverClose();\n}\n\n/**\n * Where to go when the opener was removed or can no longer take focus, nearest first: the tabbable\n * element next to where it was, else the trigger of the overlay it was in (a menu item's menu\n * button), else the element next to that trigger.\n */\nfunction* getReplacementTargets(\n opener: OpenerRecord,\n container: HTMLElement | null | undefined,\n): Generator<HTMLElement> {\n yield* getNearbyTargets(opener.position, container);\n for (const anchor of opener.anchors) yield anchor.element;\n for (const anchor of opener.anchors) yield* getNearbyTargets(anchor.position, container);\n}\n\n/** Restore targets in order of preference, computed lazily (the later ones cost more). */\nfunction* restoreCandidates(\n latest: Latest,\n opener: OpenerRecord | null,\n): Generator<HTMLElement | null | undefined> {\n const { options, parentLayerId } = latest;\n yield options.finalFocusRef?.current;\n yield opener?.element;\n yield options.triggerRef?.current;\n yield options.fallback?.();\n const replacements = opener ? getReplacementTargets(opener, options.container) : null;\n const parentLayer = parentLayerId === null ? null : getLayer(parentLayerId);\n const outsideParent: HTMLElement[] = [];\n if (parentLayer) {\n // The surface was rendered inside a layer that stays open (a confirm Dialog in a Drawer): the\n // opener's replacement inside that layer (the next row after a delete) comes before the\n // layer's surface, so where the surface sits in the React tree does not change the result.\n for (const target of replacements ?? []) {\n if (isInsideLayerTree(parentLayer.id, target)) yield target;\n else outsideParent.push(target);\n }\n yield* getLayerTargets(parentLayer);\n yield* outsideParent;\n } else if (replacements) {\n yield* replacements;\n }\n // Still nothing: into the modal that stays open, never onto the inert page behind it.\n yield* getLayerTargets(getTopmostLayer((layer) => layer.kind === 'modal'));\n}\n\nfunction restore(latest: Latest, opener: OpenerRecord | null): void {\n const container = latest.options.container;\n for (const candidate of restoreCandidates(latest, opener)) {\n if (container && candidate && container.contains(candidate)) continue;\n if (isValidTarget(candidate) && focusElement(candidate, { preventScroll: true })) return;\n }\n}\n\n/**\n * Returns focus to where it came from when a surface closes (dialogs, drawers, popovers, menus,\n * the DatePicker calendar, TeachingPopover).\n *\n * - **Capture**: when `enabled` flips to `true`, the opener is captured in an insertion effect —\n * before React applies `autoFocus` inside the new surface — preferring `triggerRef.current` and\n * ignoring `<body>` and elements inside `container`. When that finds nothing (a surface that\n * mounts open, before the refs of its commit are attached), it is captured again in the layout\n * phase of the same commit. Its place in the document and the triggers of the overlays it sits\n * in are recorded with it. When focus is already on `<body>` because\n * the focused element was removed earlier in the same commit (a menu item in a popover that\n * closes as the dialog it opens appears, the popover coming first in the tree), a document\n * focus tracker supplies that element with its recorded place and overlay triggers. The tracker\n * runs while any instance of the hook is mounted, and it forgets an element the user moved focus\n * away from on purpose.\n * - **Restore** when `enabled` flips to `false` (layout phase) and when the component unmounts\n * while enabled. The unmount restore runs in a microtask and is cancelled if the same instance\n * mounts again, so React StrictMode's simulated unmount does not pull focus out of a surface\n * that just opened.\n * - **Targets**, first valid wins:\n * 1. `finalFocusRef` → the captured opener → `triggerRef` → `fallback()`.\n * 2. When the opener was removed or cannot take focus, its replacement, nearest first: the\n * tabbable element next to where it was (in the innermost surviving ancestor that holds one,\n * the next one — the next row's action after a delete — else the previous one; then the same\n * one level up), else the trigger of the overlay it was in (a menu item's menu button), else\n * the element next to that trigger. When the surface is rendered inside another open layer\n * (its parent layer, from `DismissLayerContext`: a confirm Dialog in a Drawer's content),\n * only the replacements inside that layer's tree are tried here.\n * 3. The parent layer's surface, then the replacements outside the parent layer.\n * 4. The surface of the modal layer that stays open.\n *\n * So a confirm Dialog rendered in a Drawer's content and one rendered next to the Drawer both\n * return focus to the adjacent row, not to the Drawer's panel. A target is valid when it is\n * connected, focusable, not inside `[inert]` or `[aria-hidden=\"true\"]`, and not cut off behind\n * another open modal layer — so focus never lands on the inert page behind a Drawer that stays\n * open, and is not dropped on `<body>` while a valid target exists. Focus uses `preventScroll`.\n * - `onlyIfFocusInside` (popovers): restores only when focus is inside the surface or was lost to\n * `<body>`.\n * - `requireFocusInside` (surfaces that do not trap focus: a non-modal Dialog or Drawer, an inline\n * Drawer): restores only when focus is inside the surface or in a layer opened from it (a\n * descendant layer of `layerId`, or a layer anchored inside the surface), or was lost to\n * `<body>` from an element in either; a close from code while focus is on `<body>` or on the\n * page moves nothing.\n * - `isHoverClose`: a close by the hover intent restores only when focus is inside the surface, so\n * a hover close never moves focus from `<body>` or from where the user put it. The same holds for\n * a surface opened from inside one that closes by hover (a submenu, a hover card in a hover\n * card): every mounted instance is known to the others through the focus tracker's record.\n */\nexport function useRestoreFocus(options: UseRestoreFocusOptions): void {\n const parentLayerId = React.useContext(DismissLayerContext);\n const latestRef = useRef<Latest>({ options, parentLayerId });\n const capturedRef = useRef<OpenerRecord | null>(null);\n const insertionEnabledRef = useRef(false);\n const layoutEnabledRef = useRef(false);\n const scheduledRef = useRef<object | null>(null);\n const entryRef = useRef<SurfaceEntry | null>(null);\n const { enabled } = options;\n\n // Track focus while mounted, so an opener removed in the commit that opens the surface is known.\n // And be known to the other instances: a surface closing by hover takes along the surfaces opened\n // from inside it, whose closes are then hover closes too.\n useLayoutEffect(() => {\n const release = retainFocusTracker();\n const entry: SurfaceEntry = {\n isHoverClose: () => latestRef.current.options.isHoverClose?.() === true,\n getContainer: () => latestRef.current.options.container ?? null,\n getOpener: () =>\n capturedRef.current?.element ?? latestRef.current.options.triggerRef?.current ?? null,\n };\n entryRef.current = entry;\n const surfaces = getSurfaceEntries();\n surfaces.add(entry);\n return () => {\n release();\n // Kept to the end of the commit: a surface opened from inside this one, closing along with\n // it, still asks about it.\n queueMicrotask(() => surfaces.delete(entry));\n };\n }, []);\n\n // Mutation phase: record the latest options and capture the opener when `enabled` turns on,\n // before autoFocus (layout phase) or a focus trap's initial focus moves focus into the surface.\n useInsertionEffect(() => {\n latestRef.current = { options, parentLayerId };\n const wasEnabled = insertionEnabledRef.current;\n insertionEnabledRef.current = options.enabled;\n if (options.enabled && !wasEnabled) capturedRef.current = captureOpener(options);\n });\n\n // `enabled` false → true with nothing captured: capture again in the layout phase. A surface\n // that mounts open (an inline Drawer with `defaultOpen`) captured before the refs of this commit\n // were attached, so its trigger was not known yet.\n // `enabled` true → false: restore in the layout phase (after every cleanup of this commit, so a\n // modal's isolation is already gone).\n useLayoutEffect(() => {\n const wasEnabled = layoutEnabledRef.current;\n layoutEnabledRef.current = enabled;\n if (enabled && !wasEnabled && !capturedRef.current) {\n capturedRef.current = captureOpener(latestRef.current.options);\n }\n if (!wasEnabled || enabled) return;\n const latest = latestRef.current;\n const captured = capturedRef.current;\n const entry = entryRef.current;\n // Decided before the opener is dropped: a hover close is also recognised through it.\n const acts = shouldRestore(latest.options, () => isHoverCloseOf(entry, latest.options));\n capturedRef.current = null;\n if (acts) restore(latest, captured);\n }, [enabled]);\n\n // Unmount while enabled: restore in a microtask, cancelled by a remount of this instance.\n useLayoutEffect(() => {\n const latest = latestRef;\n const captured = capturedRef;\n const scheduled = scheduledRef;\n const entryHolder = entryRef;\n scheduled.current = null;\n return () => {\n const snapshot = latest.current;\n if (!snapshot.options.enabled) return;\n // Decide now, while the surface is still in the document.\n const entry = entryHolder.current;\n if (!shouldRestore(snapshot.options, () => isHoverCloseOf(entry, snapshot.options))) return;\n const token = {};\n scheduled.current = token;\n const opener = captured.current;\n queueMicrotask(() => {\n if (scheduled.current !== token) return;\n scheduled.current = null;\n const active = typeof document === 'undefined' ? null : document.activeElement;\n const container = snapshot.options.container;\n // Focus placed elsewhere in the meantime (another surface opened) wins.\n if (\n active &&\n active !== document.body &&\n active !== document.documentElement &&\n !(container && container.contains(active))\n ) {\n return;\n }\n restore(snapshot, opener);\n });\n };\n }, []);\n}\n"],"mappings":"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"}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { getGlobalRegistry as e } from "../lib/globalRegistry.mjs";
|
|
3
3
|
import { focusElement as t, getFirstTabbable as n, getTabbableElements as r, isFocusable as i } from "../lib/focus.mjs";
|
|
4
|
-
import { compareLayers as a, getLayer as o, getOpenLayers as s, getTopmostLayer as c,
|
|
5
|
-
import { DismissLayerContext as
|
|
6
|
-
import * as
|
|
7
|
-
import { useInsertionEffect as
|
|
4
|
+
import { compareLayers as a, getLayer as o, getOpenLayers as s, getTopmostLayer as c, isDescendantLayer as l, isInsideLayerTree as u, isInsideOtherOpenModal as d, subscribeLayers as f } from "../lib/layers.mjs";
|
|
5
|
+
import { DismissLayerContext as p } from "./useDismiss.mjs";
|
|
6
|
+
import * as m from "react";
|
|
7
|
+
import { useInsertionEffect as h, useLayoutEffect as g, useRef as _ } from "react";
|
|
8
8
|
//#region src/hooks/useRestoreFocus.ts
|
|
9
|
-
var
|
|
10
|
-
function y(e) {
|
|
11
|
-
return !e || !e.isConnected || !i(e) || e.closest("[aria-hidden=\"true\"]") ? !1 : !u(e);
|
|
12
|
-
}
|
|
9
|
+
var v = 4, y = "[data-wave-portal]";
|
|
13
10
|
function b(e) {
|
|
11
|
+
return !e || !e.isConnected || !i(e) || e.closest("[aria-hidden=\"true\"]") ? !1 : !d(e);
|
|
12
|
+
}
|
|
13
|
+
function x(e) {
|
|
14
14
|
let t = {
|
|
15
15
|
path: [],
|
|
16
16
|
next: [],
|
|
@@ -19,48 +19,48 @@ function b(e) {
|
|
|
19
19
|
for (let r = e; r && (t.path.push(r), t.next.push(r.nextElementSibling), t.previous.push(r.previousElementSibling), r !== n); r = r.parentElement);
|
|
20
20
|
return t;
|
|
21
21
|
}
|
|
22
|
-
function
|
|
22
|
+
function S(e, t) {
|
|
23
23
|
if (e.closest("[data-wave-focus-trap-allow]")) return [];
|
|
24
|
-
let n = s().filter((t) =>
|
|
24
|
+
let n = s().filter((t) => u(t.id, e)).sort((e, t) => a(t, e)), r = [];
|
|
25
25
|
for (let i of n) {
|
|
26
26
|
let n = i.getAnchor();
|
|
27
27
|
!n || n === e || t && t.contains(n) || r.some((e) => e.element === n) || r.push({
|
|
28
28
|
element: n,
|
|
29
|
-
position:
|
|
29
|
+
position: x(n)
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
return r;
|
|
33
33
|
}
|
|
34
|
-
function
|
|
35
|
-
let e =
|
|
34
|
+
function C() {
|
|
35
|
+
let e = E();
|
|
36
36
|
return e.surfaces ??= /* @__PURE__ */ new Set(), e.surfaces;
|
|
37
37
|
}
|
|
38
|
-
function
|
|
38
|
+
function w(e, t = /* @__PURE__ */ new Set()) {
|
|
39
39
|
if (t.has(e)) return !1;
|
|
40
40
|
if (t.add(e), e.isHoverClose()) return !0;
|
|
41
41
|
let n = e.getOpener();
|
|
42
42
|
if (!n) return !1;
|
|
43
|
-
for (let r of
|
|
43
|
+
for (let r of C()) {
|
|
44
44
|
let i = r === e ? null : r.getContainer();
|
|
45
|
-
if (i && i.contains(n) &&
|
|
45
|
+
if (i && i.contains(n) && w(r, t)) return !0;
|
|
46
46
|
}
|
|
47
47
|
return !1;
|
|
48
48
|
}
|
|
49
|
-
function
|
|
50
|
-
return e ?
|
|
49
|
+
function T(e, t) {
|
|
50
|
+
return e ? w(e) : t.isHoverClose?.() === !0;
|
|
51
51
|
}
|
|
52
|
-
function
|
|
52
|
+
function E() {
|
|
53
53
|
return e("restoreFocusTracker", () => ({
|
|
54
54
|
users: 0,
|
|
55
55
|
last: null,
|
|
56
56
|
uninstall: null
|
|
57
57
|
}));
|
|
58
58
|
}
|
|
59
|
-
var
|
|
60
|
-
function
|
|
61
|
-
return !!e && e.nodeType ===
|
|
59
|
+
var D = 1;
|
|
60
|
+
function O(e) {
|
|
61
|
+
return !!e && e.nodeType === D;
|
|
62
62
|
}
|
|
63
|
-
function
|
|
63
|
+
function k(e, t) {
|
|
64
64
|
let n = t.ownerDocument;
|
|
65
65
|
if (t === n.body || t === n.documentElement) {
|
|
66
66
|
e.last = null;
|
|
@@ -68,36 +68,36 @@ function O(e, t) {
|
|
|
68
68
|
}
|
|
69
69
|
e.last = {
|
|
70
70
|
element: t,
|
|
71
|
-
position:
|
|
72
|
-
anchors:
|
|
71
|
+
position: x(t),
|
|
72
|
+
anchors: S(t, null)
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
|
-
function
|
|
75
|
+
function A(e) {
|
|
76
76
|
let t = e.last;
|
|
77
77
|
if (!t || !t.element.isConnected) return;
|
|
78
|
-
let n =
|
|
78
|
+
let n = S(t.element, null);
|
|
79
79
|
for (let e of t.anchors) n.some((t) => t.element === e.element) || n.push(e);
|
|
80
80
|
e.last = {
|
|
81
81
|
element: t.element,
|
|
82
|
-
position:
|
|
82
|
+
position: x(t.element),
|
|
83
83
|
anchors: n
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
-
function
|
|
86
|
+
function j() {
|
|
87
87
|
if (typeof document > "u") return () => {};
|
|
88
|
-
let e =
|
|
88
|
+
let e = E();
|
|
89
89
|
if (e.users += 1, !e.uninstall) {
|
|
90
90
|
let t = document, n = (t) => {
|
|
91
|
-
|
|
91
|
+
O(t.target) && k(e, t.target);
|
|
92
92
|
}, r = (t) => {
|
|
93
93
|
let n = t.target;
|
|
94
|
-
!t.relatedTarget &&
|
|
94
|
+
!t.relatedTarget && O(n) && queueMicrotask(() => {
|
|
95
95
|
e.last?.element === n && n.isConnected && i(n) && n.ownerDocument.activeElement !== n && (e.last = null);
|
|
96
96
|
});
|
|
97
97
|
};
|
|
98
98
|
t.addEventListener("focusin", n, !0), t.addEventListener("focusout", r, !0);
|
|
99
|
-
let a =
|
|
100
|
-
|
|
99
|
+
let a = f(() => A(e));
|
|
100
|
+
O(t.activeElement) && k(e, t.activeElement), e.uninstall = () => {
|
|
101
101
|
t.removeEventListener("focusin", n, !0), t.removeEventListener("focusout", r, !0), a(), e.last = null;
|
|
102
102
|
};
|
|
103
103
|
}
|
|
@@ -106,28 +106,28 @@ function A() {
|
|
|
106
106
|
t && (t = !1, e.users = Math.max(0, e.users - 1), !(e.users > 0) && (e.uninstall?.(), e.uninstall = null));
|
|
107
107
|
};
|
|
108
108
|
}
|
|
109
|
-
function
|
|
110
|
-
let e =
|
|
109
|
+
function M() {
|
|
110
|
+
let e = E().last;
|
|
111
111
|
if (!e) return null;
|
|
112
112
|
let { element: t } = e;
|
|
113
113
|
return t.ownerDocument.activeElement === t || t.isConnected && i(t) ? null : e;
|
|
114
114
|
}
|
|
115
|
-
function
|
|
115
|
+
function N(e) {
|
|
116
116
|
if (typeof document > "u") return null;
|
|
117
117
|
let { container: t, triggerRef: n } = e, r = (e) => !!e && e !== e.ownerDocument.body && e !== e.ownerDocument.documentElement && !(t && t.contains(e)), i = n?.current, a = document.activeElement, o = null;
|
|
118
118
|
if (r(i) ? o = i : r(a) && (o = a), o) return {
|
|
119
119
|
element: o,
|
|
120
|
-
position:
|
|
121
|
-
anchors:
|
|
120
|
+
position: x(o),
|
|
121
|
+
anchors: S(o, t)
|
|
122
122
|
};
|
|
123
|
-
let s =
|
|
123
|
+
let s = M();
|
|
124
124
|
return !s || !r(s.element) ? null : {
|
|
125
125
|
element: s.element,
|
|
126
126
|
position: s.position,
|
|
127
127
|
anchors: s.anchors.filter((e) => !(t && t.contains(e.element)))
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
|
-
function
|
|
130
|
+
function P(e) {
|
|
131
131
|
if (!e) return [];
|
|
132
132
|
let t = [];
|
|
133
133
|
for (let r of e.getElements()) {
|
|
@@ -138,13 +138,13 @@ function N(e) {
|
|
|
138
138
|
}
|
|
139
139
|
return t;
|
|
140
140
|
}
|
|
141
|
-
function
|
|
141
|
+
function F(e, t) {
|
|
142
142
|
let { ref: n, placement: r } = t;
|
|
143
143
|
if (e === n) return r === "before";
|
|
144
|
-
let i = (n.compareDocumentPosition(e) &
|
|
144
|
+
let i = (n.compareDocumentPosition(e) & v) !== 0;
|
|
145
145
|
return r === "before" ? i : i && !n.contains(e);
|
|
146
146
|
}
|
|
147
|
-
function
|
|
147
|
+
function I(e) {
|
|
148
148
|
let { path: t } = e, n = t.findIndex((e) => e.isConnected);
|
|
149
149
|
if (n === -1) return null;
|
|
150
150
|
if (n === 0) {
|
|
@@ -157,7 +157,7 @@ function F(e) {
|
|
|
157
157
|
}
|
|
158
158
|
} : null;
|
|
159
159
|
}
|
|
160
|
-
if (t.slice(0, n).some((e) => e.matches(
|
|
160
|
+
if (t.slice(0, n).some((e) => e.matches(y))) return null;
|
|
161
161
|
let r = t[n], i = e.next[n - 1];
|
|
162
162
|
if (i && i.parentElement === r) return {
|
|
163
163
|
root: r,
|
|
@@ -181,78 +181,91 @@ function F(e) {
|
|
|
181
181
|
}
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
|
-
function
|
|
185
|
-
let n =
|
|
184
|
+
function L(e, t) {
|
|
185
|
+
let n = I(e);
|
|
186
186
|
if (!n) return [];
|
|
187
187
|
let { root: i, point: a } = n, o = i.ownerDocument.body, s = [];
|
|
188
|
-
for (let e = i; e && !(
|
|
188
|
+
for (let e = i; e && !(d(e) || (s.push(e), e === o || e.matches(y))); e = e.parentElement);
|
|
189
189
|
if (s.length === 0) return [];
|
|
190
|
-
let c = r(s[s.length - 1]).filter((e) => !(t && t.contains(e)) &&
|
|
190
|
+
let c = r(s[s.length - 1]).filter((e) => !(t && t.contains(e)) && b(e)).sort((e, t) => (e.compareDocumentPosition(t) & v) === 0 ? 1 : -1), l = [];
|
|
191
191
|
for (let e of s) {
|
|
192
|
-
let t = c.filter((t) => e.contains(t) && !l.includes(t)), n = t.find((e) =>
|
|
192
|
+
let t = c.filter((t) => e.contains(t) && !l.includes(t)), n = t.find((e) => F(e, a)), r = t.filter((e) => !F(e, a)).pop();
|
|
193
193
|
n && l.push(n), r && l.push(r);
|
|
194
194
|
}
|
|
195
195
|
return l;
|
|
196
196
|
}
|
|
197
|
-
function
|
|
197
|
+
function R(e) {
|
|
198
|
+
if (!e) return !1;
|
|
199
|
+
let t = M();
|
|
200
|
+
return t ? t.position.path.includes(e) ? !0 : t.anchors.some((t) => t.position.path.includes(e)) : !1;
|
|
201
|
+
}
|
|
202
|
+
function z(e, t, n) {
|
|
203
|
+
return !t || e.closest("[data-wave-focus-trap-allow]") ? !1 : s().some((r) => {
|
|
204
|
+
if (r.id === n || !u(r.id, e)) return !1;
|
|
205
|
+
if (n !== void 0 && l(r.id, n)) return !0;
|
|
206
|
+
let i = r.getAnchor();
|
|
207
|
+
return !!i && t.contains(i);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
function B(e, t) {
|
|
198
211
|
if (typeof document > "u") return !1;
|
|
199
212
|
let n = document.activeElement, r = !n || n === document.body || n === document.documentElement;
|
|
200
|
-
return !r && e.container?.contains(n) ? !0 : !r && e.onlyIfFocusInside ? !1 : !t();
|
|
213
|
+
return !r && e.container?.contains(n) ? !0 : e.requireFocusInside ? r ? R(e.container) && !t() : z(n, e.container, e.layerId) : !r && e.onlyIfFocusInside ? !1 : !t();
|
|
201
214
|
}
|
|
202
|
-
function*
|
|
203
|
-
yield*
|
|
215
|
+
function* V(e, t) {
|
|
216
|
+
yield* L(e.position, t);
|
|
204
217
|
for (let t of e.anchors) yield t.element;
|
|
205
|
-
for (let n of e.anchors) yield*
|
|
218
|
+
for (let n of e.anchors) yield* L(n.position, t);
|
|
206
219
|
}
|
|
207
|
-
function*
|
|
220
|
+
function* H(e, t) {
|
|
208
221
|
let { options: n, parentLayerId: r } = e;
|
|
209
222
|
yield n.finalFocusRef?.current, yield t?.element, yield n.triggerRef?.current, yield n.fallback?.();
|
|
210
|
-
let i = t ?
|
|
223
|
+
let i = t ? V(t, n.container) : null, a = r === null ? null : o(r), s = [];
|
|
211
224
|
if (a) {
|
|
212
|
-
for (let e of i ?? [])
|
|
213
|
-
yield*
|
|
225
|
+
for (let e of i ?? []) u(a.id, e) ? yield e : s.push(e);
|
|
226
|
+
yield* P(a), yield* s;
|
|
214
227
|
} else i && (yield* i);
|
|
215
|
-
yield*
|
|
228
|
+
yield* P(c((e) => e.kind === "modal"));
|
|
216
229
|
}
|
|
217
|
-
function
|
|
230
|
+
function U(e, n) {
|
|
218
231
|
let r = e.options.container;
|
|
219
|
-
for (let i of
|
|
232
|
+
for (let i of H(e, n)) if (!(r && i && r.contains(i)) && b(i) && t(i, { preventScroll: !0 })) return;
|
|
220
233
|
}
|
|
221
|
-
function
|
|
222
|
-
let t =
|
|
234
|
+
function W(e) {
|
|
235
|
+
let t = m.useContext(p), n = _({
|
|
223
236
|
options: e,
|
|
224
237
|
parentLayerId: t
|
|
225
|
-
}), r =
|
|
226
|
-
|
|
227
|
-
let e =
|
|
238
|
+
}), r = _(null), i = _(!1), a = _(!1), o = _(null), s = _(null), { enabled: c } = e;
|
|
239
|
+
g(() => {
|
|
240
|
+
let e = j(), t = {
|
|
228
241
|
isHoverClose: () => n.current.options.isHoverClose?.() === !0,
|
|
229
242
|
getContainer: () => n.current.options.container ?? null,
|
|
230
243
|
getOpener: () => r.current?.element ?? n.current.options.triggerRef?.current ?? null
|
|
231
244
|
};
|
|
232
245
|
s.current = t;
|
|
233
|
-
let i =
|
|
246
|
+
let i = C();
|
|
234
247
|
return i.add(t), () => {
|
|
235
248
|
e(), queueMicrotask(() => i.delete(t));
|
|
236
249
|
};
|
|
237
|
-
}, []),
|
|
250
|
+
}, []), h(() => {
|
|
238
251
|
n.current = {
|
|
239
252
|
options: e,
|
|
240
253
|
parentLayerId: t
|
|
241
254
|
};
|
|
242
255
|
let a = i.current;
|
|
243
|
-
i.current = e.enabled, e.enabled && !a && (r.current =
|
|
244
|
-
}),
|
|
256
|
+
i.current = e.enabled, e.enabled && !a && (r.current = N(e));
|
|
257
|
+
}), g(() => {
|
|
245
258
|
let e = a.current;
|
|
246
|
-
if (a.current = c, !e || c) return;
|
|
247
|
-
let t = n.current, i = r.current, o = s.current, l =
|
|
248
|
-
r.current = null, l &&
|
|
249
|
-
}, [c]),
|
|
259
|
+
if (a.current = c, c && !e && !r.current && (r.current = N(n.current.options)), !e || c) return;
|
|
260
|
+
let t = n.current, i = r.current, o = s.current, l = B(t.options, () => T(o, t.options));
|
|
261
|
+
r.current = null, l && U(t, i);
|
|
262
|
+
}, [c]), g(() => {
|
|
250
263
|
let e = n, t = r, i = o, a = s;
|
|
251
264
|
return i.current = null, () => {
|
|
252
265
|
let n = e.current;
|
|
253
266
|
if (!n.options.enabled) return;
|
|
254
267
|
let r = a.current;
|
|
255
|
-
if (!
|
|
268
|
+
if (!B(n.options, () => T(r, n.options))) return;
|
|
256
269
|
let o = {};
|
|
257
270
|
i.current = o;
|
|
258
271
|
let s = t.current;
|
|
@@ -260,12 +273,12 @@ function V(e) {
|
|
|
260
273
|
if (i.current !== o) return;
|
|
261
274
|
i.current = null;
|
|
262
275
|
let e = typeof document > "u" ? null : document.activeElement, t = n.options.container;
|
|
263
|
-
(!e || e === document.body || e === document.documentElement || t && t.contains(e)) &&
|
|
276
|
+
(!e || e === document.body || e === document.documentElement || t && t.contains(e)) && U(n, s);
|
|
264
277
|
});
|
|
265
278
|
};
|
|
266
279
|
}, []);
|
|
267
280
|
}
|
|
268
281
|
//#endregion
|
|
269
|
-
export {
|
|
282
|
+
export { W as useRestoreFocus };
|
|
270
283
|
|
|
271
284
|
//# sourceMappingURL=useRestoreFocus.mjs.map
|