@radix-ui/react-focus-scope
Advanced tools
+36
-1
@@ -19,2 +19,11 @@ import * as React from 'react'; | ||
| /** | ||
| * A list of nodes that should be treated as part of the focus scope even | ||
| * though they don't live within the scope's DOM subtree (eg. portalled | ||
| * content of a nested, non-modal layer). When the scope is `trapped`, focus | ||
| * is allowed to move into these branches without being reclaimed. | ||
| * | ||
| * See: https://github.com/radix-ui/primitives/issues/3423 | ||
| */ | ||
| branches?: HTMLElement[]; | ||
| /** | ||
| * Event handler called when auto-focusing on mount. | ||
@@ -31,3 +40,29 @@ * Can be prevented. | ||
| declare const FocusScope: React.ForwardRefExoticComponent<FocusScopeProps & React.RefAttributes<HTMLDivElement>>; | ||
| /** | ||
| * Lets portalled content that is a React descendant of a (modal) layer — but rendered outside of | ||
| * that layer's DOM subtree — register itself as a "branch" of the layer's focus scope. | ||
| * | ||
| * A modal container (eg. `Dialog`) creates a registry via `useFocusScopeBranchRegistry`, renders a | ||
| * `FocusScopeBranchProvider` around its children, and passes the collected `nodes` to its trapped | ||
| * `FocusScope` (so focus isn't reclaimed from the branch) and, if applicable, to its `RemoveScroll` | ||
| * `shards` (so the branch remains scrollable). Nested layers (eg. a non-modal `Popover`) register | ||
| * their content node with `useFocusScopeBranch`. | ||
| * | ||
| * See: https://github.com/radix-ui/primitives/issues/3423 | ||
| */ | ||
| interface FocusScopeBranchRegistry { | ||
| add: (node: HTMLElement) => void; | ||
| remove: (node: HTMLElement) => void; | ||
| } | ||
| declare const FocusScopeBranchProvider: React.Provider<FocusScopeBranchRegistry | null>; | ||
| declare function useFocusScopeBranchRegistry(): { | ||
| readonly nodes: HTMLElement[]; | ||
| readonly registry: FocusScopeBranchRegistry; | ||
| }; | ||
| /** | ||
| * Registers `node` as a branch of the nearest ancestor `FocusScopeBranchProvider`. No-ops when | ||
| * there is no ancestor registry (eg. the layer isn't nested inside a modal layer). | ||
| */ | ||
| declare function useFocusScopeBranch(node: HTMLElement | null): void; | ||
| export { FocusScope, type FocusScopeProps, FocusScope as Root }; | ||
| export { FocusScope, FocusScopeBranchProvider, type FocusScopeBranchRegistry, type FocusScopeProps, FocusScope as Root, useFocusScopeBranch, useFocusScopeBranchRegistry }; |
+36
-1
@@ -19,2 +19,11 @@ import * as React from 'react'; | ||
| /** | ||
| * A list of nodes that should be treated as part of the focus scope even | ||
| * though they don't live within the scope's DOM subtree (eg. portalled | ||
| * content of a nested, non-modal layer). When the scope is `trapped`, focus | ||
| * is allowed to move into these branches without being reclaimed. | ||
| * | ||
| * See: https://github.com/radix-ui/primitives/issues/3423 | ||
| */ | ||
| branches?: HTMLElement[]; | ||
| /** | ||
| * Event handler called when auto-focusing on mount. | ||
@@ -31,3 +40,29 @@ * Can be prevented. | ||
| declare const FocusScope: React.ForwardRefExoticComponent<FocusScopeProps & React.RefAttributes<HTMLDivElement>>; | ||
| /** | ||
| * Lets portalled content that is a React descendant of a (modal) layer — but rendered outside of | ||
| * that layer's DOM subtree — register itself as a "branch" of the layer's focus scope. | ||
| * | ||
| * A modal container (eg. `Dialog`) creates a registry via `useFocusScopeBranchRegistry`, renders a | ||
| * `FocusScopeBranchProvider` around its children, and passes the collected `nodes` to its trapped | ||
| * `FocusScope` (so focus isn't reclaimed from the branch) and, if applicable, to its `RemoveScroll` | ||
| * `shards` (so the branch remains scrollable). Nested layers (eg. a non-modal `Popover`) register | ||
| * their content node with `useFocusScopeBranch`. | ||
| * | ||
| * See: https://github.com/radix-ui/primitives/issues/3423 | ||
| */ | ||
| interface FocusScopeBranchRegistry { | ||
| add: (node: HTMLElement) => void; | ||
| remove: (node: HTMLElement) => void; | ||
| } | ||
| declare const FocusScopeBranchProvider: React.Provider<FocusScopeBranchRegistry | null>; | ||
| declare function useFocusScopeBranchRegistry(): { | ||
| readonly nodes: HTMLElement[]; | ||
| readonly registry: FocusScopeBranchRegistry; | ||
| }; | ||
| /** | ||
| * Registers `node` as a branch of the nearest ancestor `FocusScopeBranchProvider`. No-ops when | ||
| * there is no ancestor registry (eg. the layer isn't nested inside a modal layer). | ||
| */ | ||
| declare function useFocusScopeBranch(node: HTMLElement | null): void; | ||
| export { FocusScope, type FocusScopeProps, FocusScope as Root }; | ||
| export { FocusScope, FocusScopeBranchProvider, type FocusScopeBranchRegistry, type FocusScopeProps, FocusScope as Root, useFocusScopeBranch, useFocusScopeBranchRegistry }; |
+43
-4
@@ -36,3 +36,6 @@ "use strict"; | ||
| FocusScope: () => FocusScope, | ||
| Root: () => FocusScope | ||
| FocusScopeBranchProvider: () => FocusScopeBranchProvider, | ||
| Root: () => FocusScope, | ||
| useFocusScopeBranch: () => useFocusScopeBranch, | ||
| useFocusScopeBranchRegistry: () => useFocusScopeBranchRegistry | ||
| }); | ||
@@ -55,2 +58,3 @@ module.exports = __toCommonJS(index_exports); | ||
| trapped = false, | ||
| branches, | ||
| onMountAutoFocus: onMountAutoFocusProp, | ||
@@ -65,2 +69,14 @@ onUnmountAutoFocus: onUnmountAutoFocusProp, | ||
| const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, setContainer); | ||
| const branchesRef = React.useRef(branches); | ||
| React.useEffect(() => { | ||
| branchesRef.current = branches; | ||
| }); | ||
| const isTargetInScope = React.useCallback( | ||
| (target) => { | ||
| if (!target) return false; | ||
| if (container?.contains(target)) return true; | ||
| return Boolean(branchesRef.current?.some((branch) => branch.contains(target))); | ||
| }, | ||
| [container] | ||
| ); | ||
| const focusScope = React.useRef({ | ||
@@ -80,3 +96,3 @@ paused: false, | ||
| const target = event.target; | ||
| if (container.contains(target)) { | ||
| if (isTargetInScope(target)) { | ||
| lastFocusedElementRef.current = target; | ||
@@ -90,3 +106,3 @@ } else { | ||
| if (relatedTarget === null) return; | ||
| if (!container.contains(relatedTarget)) { | ||
| if (!isTargetInScope(relatedTarget)) { | ||
| focus(lastFocusedElementRef.current, { select: true }); | ||
@@ -115,3 +131,3 @@ } | ||
| } | ||
| }, [trapped, container, focusScope.paused]); | ||
| }, [trapped, container, focusScope.paused, isTargetInScope]); | ||
| React.useEffect(() => { | ||
@@ -176,2 +192,25 @@ if (container) { | ||
| ); | ||
| var FocusScopeBranchContext = React.createContext(null); | ||
| var FocusScopeBranchProvider = FocusScopeBranchContext.Provider; | ||
| function useFocusScopeBranchRegistry() { | ||
| const [nodes, setNodes] = React.useState([]); | ||
| const registry = React.useMemo( | ||
| () => ({ | ||
| add: /* @__PURE__ */ __name((node) => setNodes((prev) => prev.includes(node) ? prev : [...prev, node]), "add"), | ||
| remove: /* @__PURE__ */ __name((node) => setNodes((prev) => prev.filter((current) => current !== node)), "remove") | ||
| }), | ||
| [] | ||
| ); | ||
| return { nodes, registry }; | ||
| } | ||
| __name(useFocusScopeBranchRegistry, "useFocusScopeBranchRegistry"); | ||
| function useFocusScopeBranch(node) { | ||
| const registry = React.useContext(FocusScopeBranchContext); | ||
| React.useEffect(() => { | ||
| if (!node || !registry) return; | ||
| registry.add(node); | ||
| return () => registry.remove(node); | ||
| }, [node, registry]); | ||
| } | ||
| __name(useFocusScopeBranch, "useFocusScopeBranch"); | ||
| function focusFirst(candidates, { select = false } = {}) { | ||
@@ -178,0 +217,0 @@ const previouslyFocusedElement = document.activeElement; |
| { | ||
| "version": 3, | ||
| "sources": ["../src/index.ts", "../src/focus-scope.tsx"], | ||
| "sourcesContent": ["'use client';\nexport {\n FocusScope,\n //\n Root,\n} from './focus-scope';\nexport type { FocusScopeProps } from './focus-scope';\n", "import * as React from 'react';\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { useCallbackRef } from '@radix-ui/react-use-callback-ref';\n\nconst AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';\nconst AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\ntype FocusableTarget = HTMLElement | { focus(): void };\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeElement = React.ComponentRef<typeof Primitive.div>;\ntype PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FocusScopeProps extends PrimitiveDivProps {\n /**\n * When `true`, tabbing from last item will focus first tabbable\n * and shift+tab from first item will focus last tababble.\n * @defaultValue false\n */\n loop?: boolean;\n\n /**\n * When `true`, focus cannot escape the focus scope via keyboard,\n * pointer, or a programmatic focus.\n * @defaultValue false\n */\n trapped?: boolean;\n\n /**\n * Event handler called when auto-focusing on mount.\n * Can be prevented.\n */\n onMountAutoFocus?: (event: Event) => void;\n\n /**\n * Event handler called when auto-focusing on unmount.\n * Can be prevented.\n */\n onUnmountAutoFocus?: (event: Event) => void;\n}\n\nconst FocusScope = /* @__PURE__ */ React.forwardRef<FocusScopeElement, FocusScopeProps>(\n function FocusScope(props, forwardedRef) {\n const {\n loop = false,\n trapped = false,\n onMountAutoFocus: onMountAutoFocusProp,\n onUnmountAutoFocus: onUnmountAutoFocusProp,\n ...scopeProps\n } = props;\n const [container, setContainer] = React.useState<HTMLElement | null>(null);\n const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);\n const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const composedRefs = useComposedRefs(forwardedRef, setContainer);\n\n const focusScope = React.useRef({\n paused: false,\n pause() {\n this.paused = true;\n },\n resume() {\n this.paused = false;\n },\n }).current;\n\n // Takes care of trapping focus if focus is moved outside programmatically for example\n React.useEffect(() => {\n if (trapped) {\n function handleFocusIn(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const target = event.target as HTMLElement | null;\n if (container.contains(target)) {\n lastFocusedElementRef.current = target;\n } else {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n function handleFocusOut(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const relatedTarget = event.relatedTarget as HTMLElement | null;\n\n // A `focusout` event with a `null` `relatedTarget` will happen in at least two cases:\n //\n // 1. When the user switches app/tabs/windows/the browser itself loses focus.\n // 2. In Google Chrome, when the focused element is removed from the DOM.\n //\n // We let the browser do its thing here because:\n //\n // 1. The browser already keeps a memory of what's focused for when the page gets refocused.\n // 2. In Google Chrome, if we try to focus the deleted focused element (as per below), it\n // throws the CPU to 100%, so we avoid doing anything for this reason here too.\n if (relatedTarget === null) return;\n\n // If the focus has moved to an actual legitimate element (`relatedTarget !== null`)\n // that is outside the container, we move focus to the last valid focused element inside.\n if (!container.contains(relatedTarget)) {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n // When the focused element gets removed from the DOM, browsers move focus\n // back to the document.body. In this case, we move focus to the container\n // to keep focus trapped correctly.\n function handleMutations(mutations: MutationRecord[]) {\n const focusedElement = document.activeElement as HTMLElement | null;\n if (focusedElement !== document.body) return;\n for (const mutation of mutations) {\n if (mutation.removedNodes.length > 0) focus(container);\n }\n }\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n const mutationObserver = new MutationObserver(handleMutations);\n if (container) mutationObserver.observe(container, { childList: true, subtree: true });\n\n return () => {\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n mutationObserver.disconnect();\n };\n }\n }, [trapped, container, focusScope.paused]);\n\n React.useEffect(() => {\n if (container) {\n focusScopesStack.add(focusScope);\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = container.contains(previouslyFocusedElement);\n\n if (!hasFocusedCandidate) {\n const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n container.dispatchEvent(mountEvent);\n if (!mountEvent.defaultPrevented) {\n focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });\n if (document.activeElement === previouslyFocusedElement) {\n focus(container);\n }\n }\n }\n\n return () => {\n container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n\n // We hit a react bug (fixed in v17) with focusing in unmount.\n // We need to delay the focus a little to get around it for now.\n // See: https://github.com/facebook/react/issues/17894\n setTimeout(() => {\n const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n container.dispatchEvent(unmountEvent);\n if (!unmountEvent.defaultPrevented) {\n focus(previouslyFocusedElement ?? document.body, { select: true });\n }\n // we need to remove the listener after we `dispatchEvent`\n container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n\n focusScopesStack.remove(focusScope);\n }, 0);\n };\n }\n }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);\n\n // Takes care of looping focus (when tabbing whilst at the edges)\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (!loop && !trapped) return;\n if (focusScope.paused) return;\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) event.preventDefault();\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n if (loop) focus(first, { select: true });\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n if (loop) focus(last, { select: true });\n }\n }\n }\n },\n [loop, trapped, focusScope.paused],\n );\n\n return (\n <Primitive.div tabIndex={-1} {...scopeProps} ref={composedRefs} onKeyDown={handleKeyDown} />\n );\n },\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Attempts focusing the first element in a list of candidates.\n * Stops when focus has actually moved.\n */\nfunction focusFirst(candidates: HTMLElement[], { select = false } = {}) {\n const previouslyFocusedElement = document.activeElement;\n for (const candidate of candidates) {\n focus(candidate, { select });\n if (document.activeElement !== previouslyFocusedElement) return;\n }\n}\n\n/**\n * Returns the first and last tabbable elements inside a container.\n */\nfunction getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates, container);\n const last = findVisible(candidates.reverse(), container);\n return [first, last] as const;\n}\n\n/**\n * Returns a list of potential tabbable candidates.\n *\n * NOTE: This is only a close approximation. For example it doesn't take into account cases like when\n * elements are not visible. This cannot be worked out easily by just reading a property, but rather\n * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker\n * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1\n */\nfunction getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: any) => {\n const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';\n if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;\n // `.tabIndex` is not the same as the `tabindex` attribute. It works on the\n // runtime's understanding of tabbability, so this automatically accounts\n // for any kind of element that could be tabbed to.\n return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);\n // we do not take into account the order of nodes with positive `tabIndex` as it\n // hinders accessibility to have tab order different from visual order.\n return nodes;\n}\n\n/**\n * Returns the first visible element in a list.\n * NOTE: Only checks visibility up to the `container`.\n */\nfunction findVisible(elements: HTMLElement[], container: HTMLElement) {\n // `checkVisibility` performs a single native check for `visibility: hidden`\n // and `display: none` across the ancestor chain. This avoids the repeated\n // `getComputedStyle` calls per ancestor that the fallback path requires,\n // which reduces the cost of style resolution triggered by earlier DOM writes\n // (e.g. react-remove-scroll, DismissableLayer setting body styles).\n const canUseCheckVisibility =\n typeof container.checkVisibility === 'function' &&\n container.checkVisibility({ checkVisibilityCSS: true });\n\n for (const element of elements) {\n const hidden = canUseCheckVisibility\n ? !element.checkVisibility({ checkVisibilityCSS: true })\n : isHidden(element, { upTo: container });\n // we stop checking if it's hidden at the `container` level (excluding)\n if (!hidden) {\n return element;\n }\n }\n}\n\nfunction isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {\n if (getComputedStyle(node).visibility === 'hidden') return true;\n while (node) {\n // we stop at `upTo` (excluding it)\n if (upTo !== undefined && node === upTo) return false;\n if (getComputedStyle(node).display === 'none') return true;\n node = node.parentElement as HTMLElement;\n }\n return false;\n}\n\nfunction isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {\n return element instanceof HTMLInputElement && 'select' in element;\n}\n\nfunction focus(element?: FocusableTarget | null, { select = false } = {}) {\n // only focus if that element is focusable\n if (element && element.focus) {\n const previouslyFocusedElement = document.activeElement;\n // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users\n element.focus({ preventScroll: true });\n // only select if its not the same element, it supports selection and we need to select\n if (element !== previouslyFocusedElement && isSelectableInput(element) && select)\n element.select();\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope stack\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeAPI = { paused: boolean; pause(): void; resume(): void };\nconst focusScopesStack = createFocusScopesStack();\n\nfunction createFocusScopesStack() {\n /** A stack of focus scopes, with the active one at the top */\n let stack: FocusScopeAPI[] = [];\n\n return {\n add(focusScope: FocusScopeAPI) {\n // pause the currently active focus scope (at the top of the stack)\n const activeFocusScope = stack[0];\n if (focusScope !== activeFocusScope) {\n activeFocusScope?.pause();\n }\n // remove in case it already exists (because we'll re-add it at the top of the stack)\n stack = arrayRemove(stack, focusScope);\n stack.unshift(focusScope);\n },\n\n remove(focusScope: FocusScopeAPI) {\n stack = arrayRemove(stack, focusScope);\n stack[0]?.resume();\n },\n };\n}\n\nfunction arrayRemove<T>(array: T[], item: T) {\n const updatedArray = [...array];\n const index = updatedArray.indexOf(item);\n if (index !== -1) {\n updatedArray.splice(index, 1);\n }\n return updatedArray;\n}\n\nfunction removeLinks(items: HTMLElement[]) {\n return items.filter((item) => item.tagName !== 'A');\n}\n\nexport {\n FocusScope,\n //\n FocusScope as Root,\n};\nexport type { FocusScopeProps };\n"], | ||
| "mappings": "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", | ||
| "sourcesContent": ["'use client';\nexport {\n FocusScope,\n FocusScopeBranchProvider,\n useFocusScopeBranchRegistry,\n useFocusScopeBranch,\n //\n Root,\n} from './focus-scope';\nexport type { FocusScopeProps, FocusScopeBranchRegistry } from './focus-scope';\n", "import * as React from 'react';\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { useCallbackRef } from '@radix-ui/react-use-callback-ref';\n\nconst AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';\nconst AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\ntype FocusableTarget = HTMLElement | { focus(): void };\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeElement = React.ComponentRef<typeof Primitive.div>;\ntype PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FocusScopeProps extends PrimitiveDivProps {\n /**\n * When `true`, tabbing from last item will focus first tabbable\n * and shift+tab from first item will focus last tababble.\n * @defaultValue false\n */\n loop?: boolean;\n\n /**\n * When `true`, focus cannot escape the focus scope via keyboard,\n * pointer, or a programmatic focus.\n * @defaultValue false\n */\n trapped?: boolean;\n\n /**\n * A list of nodes that should be treated as part of the focus scope even\n * though they don't live within the scope's DOM subtree (eg. portalled\n * content of a nested, non-modal layer). When the scope is `trapped`, focus\n * is allowed to move into these branches without being reclaimed.\n *\n * See: https://github.com/radix-ui/primitives/issues/3423\n */\n branches?: HTMLElement[];\n\n /**\n * Event handler called when auto-focusing on mount.\n * Can be prevented.\n */\n onMountAutoFocus?: (event: Event) => void;\n\n /**\n * Event handler called when auto-focusing on unmount.\n * Can be prevented.\n */\n onUnmountAutoFocus?: (event: Event) => void;\n}\n\nconst FocusScope = /* @__PURE__ */ React.forwardRef<FocusScopeElement, FocusScopeProps>(\n function FocusScope(props, forwardedRef) {\n const {\n loop = false,\n trapped = false,\n branches,\n onMountAutoFocus: onMountAutoFocusProp,\n onUnmountAutoFocus: onUnmountAutoFocusProp,\n ...scopeProps\n } = props;\n const [container, setContainer] = React.useState<HTMLElement | null>(null);\n const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);\n const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const composedRefs = useComposedRefs(forwardedRef, setContainer);\n\n // Keep the latest branches in a ref so the trap effect below doesn't need to resubscribe its\n // listeners whenever the branch list updates. We sync it in the commit phase (not during render)\n // to stay safe under concurrent rendering, where a render can be discarded or replayed. The trap's\n // focus event handlers only run in response to user interaction (well after commit), so reading\n // the ref from them always sees the committed branch list.\n const branchesRef = React.useRef(branches);\n React.useEffect(() => {\n branchesRef.current = branches;\n });\n const isTargetInScope = React.useCallback(\n (target: HTMLElement | null) => {\n if (!target) return false;\n if (container?.contains(target)) return true;\n return Boolean(branchesRef.current?.some((branch) => branch.contains(target)));\n },\n [container],\n );\n\n const focusScope = React.useRef({\n paused: false,\n pause() {\n this.paused = true;\n },\n resume() {\n this.paused = false;\n },\n }).current;\n\n // Takes care of trapping focus if focus is moved outside programmatically for example\n React.useEffect(() => {\n if (trapped) {\n function handleFocusIn(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const target = event.target as HTMLElement | null;\n if (isTargetInScope(target)) {\n lastFocusedElementRef.current = target;\n } else {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n function handleFocusOut(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const relatedTarget = event.relatedTarget as HTMLElement | null;\n\n // A `focusout` event with a `null` `relatedTarget` will happen in at\n // least two cases:\n // 1. When the user switches app/tabs/windows/the browser itself loses\n // focus.\n // 2. In Google Chrome, when the focused element is removed from the\n // DOM.\n //\n // We let the browser do its thing here because:\n // 1. The browser already keeps a memory of what's focused for when\n // the page gets refocused.\n // 2. In Google Chrome, if we try to focus the deleted focused element\n // (as per below), it throws the CPU to 100%, so we avoid doing\n // anything for this reason here too.\n if (relatedTarget === null) return;\n\n // If the focus has moved to an actual legitimate element\n // (`relatedTarget !== null`) that is outside the container (and any\n // registered branches), we move focus to the last valid focused\n // element inside.\n if (!isTargetInScope(relatedTarget)) {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n // When the focused element gets removed from the DOM, browsers move focus\n // back to the document.body. In this case, we move focus to the container\n // to keep focus trapped correctly.\n function handleMutations(mutations: MutationRecord[]) {\n const focusedElement = document.activeElement as HTMLElement | null;\n if (focusedElement !== document.body) return;\n for (const mutation of mutations) {\n if (mutation.removedNodes.length > 0) focus(container);\n }\n }\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n const mutationObserver = new MutationObserver(handleMutations);\n if (container) mutationObserver.observe(container, { childList: true, subtree: true });\n\n return () => {\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n mutationObserver.disconnect();\n };\n }\n }, [trapped, container, focusScope.paused, isTargetInScope]);\n\n React.useEffect(() => {\n if (container) {\n focusScopesStack.add(focusScope);\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = container.contains(previouslyFocusedElement);\n\n if (!hasFocusedCandidate) {\n const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n container.dispatchEvent(mountEvent);\n if (!mountEvent.defaultPrevented) {\n focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });\n if (document.activeElement === previouslyFocusedElement) {\n focus(container);\n }\n }\n }\n\n return () => {\n container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n\n // We hit a react bug (fixed in v17) with focusing in unmount.\n // We need to delay the focus a little to get around it for now.\n // See: https://github.com/facebook/react/issues/17894\n setTimeout(() => {\n const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n container.dispatchEvent(unmountEvent);\n if (!unmountEvent.defaultPrevented) {\n focus(previouslyFocusedElement ?? document.body, { select: true });\n }\n // we need to remove the listener after we `dispatchEvent`\n container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n\n focusScopesStack.remove(focusScope);\n }, 0);\n };\n }\n }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);\n\n // Takes care of looping focus (when tabbing whilst at the edges)\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (!loop && !trapped) return;\n if (focusScope.paused) return;\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) event.preventDefault();\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n if (loop) focus(first, { select: true });\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n if (loop) focus(last, { select: true });\n }\n }\n }\n },\n [loop, trapped, focusScope.paused],\n );\n\n return (\n <Primitive.div tabIndex={-1} {...scopeProps} ref={composedRefs} onKeyDown={handleKeyDown} />\n );\n },\n);\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope branch registry\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Lets portalled content that is a React descendant of a (modal) layer \u2014 but rendered outside of\n * that layer's DOM subtree \u2014 register itself as a \"branch\" of the layer's focus scope.\n *\n * A modal container (eg. `Dialog`) creates a registry via `useFocusScopeBranchRegistry`, renders a\n * `FocusScopeBranchProvider` around its children, and passes the collected `nodes` to its trapped\n * `FocusScope` (so focus isn't reclaimed from the branch) and, if applicable, to its `RemoveScroll`\n * `shards` (so the branch remains scrollable). Nested layers (eg. a non-modal `Popover`) register\n * their content node with `useFocusScopeBranch`.\n *\n * See: https://github.com/radix-ui/primitives/issues/3423\n */\ninterface FocusScopeBranchRegistry {\n add: (node: HTMLElement) => void;\n remove: (node: HTMLElement) => void;\n}\n\nconst FocusScopeBranchContext = React.createContext<FocusScopeBranchRegistry | null>(null);\n\nconst FocusScopeBranchProvider = FocusScopeBranchContext.Provider;\n\nfunction useFocusScopeBranchRegistry() {\n const [nodes, setNodes] = React.useState<HTMLElement[]>([]);\n const registry = React.useMemo<FocusScopeBranchRegistry>(\n () => ({\n add: (node) => setNodes((prev) => (prev.includes(node) ? prev : [...prev, node])),\n remove: (node) => setNodes((prev) => prev.filter((current) => current !== node)),\n }),\n [],\n );\n return { nodes, registry } as const;\n}\n\n/**\n * Registers `node` as a branch of the nearest ancestor `FocusScopeBranchProvider`. No-ops when\n * there is no ancestor registry (eg. the layer isn't nested inside a modal layer).\n */\nfunction useFocusScopeBranch(node: HTMLElement | null) {\n const registry = React.useContext(FocusScopeBranchContext);\n React.useEffect(() => {\n if (!node || !registry) return;\n registry.add(node);\n return () => registry.remove(node);\n }, [node, registry]);\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Attempts focusing the first element in a list of candidates.\n * Stops when focus has actually moved.\n */\nfunction focusFirst(candidates: HTMLElement[], { select = false } = {}) {\n const previouslyFocusedElement = document.activeElement;\n for (const candidate of candidates) {\n focus(candidate, { select });\n if (document.activeElement !== previouslyFocusedElement) return;\n }\n}\n\n/**\n * Returns the first and last tabbable elements inside a container.\n */\nfunction getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates, container);\n const last = findVisible(candidates.reverse(), container);\n return [first, last] as const;\n}\n\n/**\n * Returns a list of potential tabbable candidates.\n *\n * NOTE: This is only a close approximation. For example it doesn't take into account cases like when\n * elements are not visible. This cannot be worked out easily by just reading a property, but rather\n * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker\n * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1\n */\nfunction getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: any) => {\n const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';\n if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;\n // `.tabIndex` is not the same as the `tabindex` attribute. It works on the\n // runtime's understanding of tabbability, so this automatically accounts\n // for any kind of element that could be tabbed to.\n return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);\n // we do not take into account the order of nodes with positive `tabIndex` as it\n // hinders accessibility to have tab order different from visual order.\n return nodes;\n}\n\n/**\n * Returns the first visible element in a list.\n * NOTE: Only checks visibility up to the `container`.\n */\nfunction findVisible(elements: HTMLElement[], container: HTMLElement) {\n // `checkVisibility` performs a single native check for `visibility: hidden`\n // and `display: none` across the ancestor chain. This avoids the repeated\n // `getComputedStyle` calls per ancestor that the fallback path requires,\n // which reduces the cost of style resolution triggered by earlier DOM writes\n // (e.g. react-remove-scroll, DismissableLayer setting body styles).\n const canUseCheckVisibility =\n typeof container.checkVisibility === 'function' &&\n container.checkVisibility({ checkVisibilityCSS: true });\n\n for (const element of elements) {\n const hidden = canUseCheckVisibility\n ? !element.checkVisibility({ checkVisibilityCSS: true })\n : isHidden(element, { upTo: container });\n // we stop checking if it's hidden at the `container` level (excluding)\n if (!hidden) {\n return element;\n }\n }\n}\n\nfunction isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {\n if (getComputedStyle(node).visibility === 'hidden') return true;\n while (node) {\n // we stop at `upTo` (excluding it)\n if (upTo !== undefined && node === upTo) return false;\n if (getComputedStyle(node).display === 'none') return true;\n node = node.parentElement as HTMLElement;\n }\n return false;\n}\n\nfunction isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {\n return element instanceof HTMLInputElement && 'select' in element;\n}\n\nfunction focus(element?: FocusableTarget | null, { select = false } = {}) {\n // only focus if that element is focusable\n if (element && element.focus) {\n const previouslyFocusedElement = document.activeElement;\n // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users\n element.focus({ preventScroll: true });\n // only select if its not the same element, it supports selection and we need to select\n if (element !== previouslyFocusedElement && isSelectableInput(element) && select)\n element.select();\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope stack\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeAPI = { paused: boolean; pause(): void; resume(): void };\nconst focusScopesStack = createFocusScopesStack();\n\nfunction createFocusScopesStack() {\n /** A stack of focus scopes, with the active one at the top */\n let stack: FocusScopeAPI[] = [];\n\n return {\n add(focusScope: FocusScopeAPI) {\n // pause the currently active focus scope (at the top of the stack)\n const activeFocusScope = stack[0];\n if (focusScope !== activeFocusScope) {\n activeFocusScope?.pause();\n }\n // remove in case it already exists (because we'll re-add it at the top of the stack)\n stack = arrayRemove(stack, focusScope);\n stack.unshift(focusScope);\n },\n\n remove(focusScope: FocusScopeAPI) {\n stack = arrayRemove(stack, focusScope);\n stack[0]?.resume();\n },\n };\n}\n\nfunction arrayRemove<T>(array: T[], item: T) {\n const updatedArray = [...array];\n const index = updatedArray.indexOf(item);\n if (index !== -1) {\n updatedArray.splice(index, 1);\n }\n return updatedArray;\n}\n\nfunction removeLinks(items: HTMLElement[]) {\n return items.filter((item) => item.tagName !== 'A');\n}\n\nexport {\n FocusScope,\n FocusScopeBranchProvider,\n useFocusScopeBranchRegistry,\n useFocusScopeBranch,\n //\n FocusScope as Root,\n};\nexport type { FocusScopeProps, FocusScopeBranchRegistry };\n"], | ||
| "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,YAAuB;AACvB,gCAAgC;AAChC,6BAA0B;AAC1B,oCAA+B;AAyOzB;AAvON,IAAM,qBAAqB;AAC3B,IAAM,uBAAuB;AAC7B,IAAM,gBAAgB,EAAE,SAAS,OAAO,YAAY,KAAK;AAgDzD,IAAM,aAA6B,gBAAM;AAAA,EACvC,gCAASA,YAAW,OAAO,cAAc;AACvC,UAAM;AAAA,MACJ,OAAO;AAAA,MACP,UAAU;AAAA,MACV;AAAA,MACA,kBAAkB;AAAA,MAClB,oBAAoB;AAAA,MACpB,GAAG;AAAA,IACL,IAAI;AACJ,UAAM,CAAC,WAAW,YAAY,IAAU,eAA6B,IAAI;AACzE,UAAM,uBAAmB,8CAAe,oBAAoB;AAC5D,UAAM,yBAAqB,8CAAe,sBAAsB;AAChE,UAAM,wBAA8B,aAA2B,IAAI;AACnE,UAAM,mBAAe,2CAAgB,cAAc,YAAY;AAO/D,UAAM,cAAoB,aAAO,QAAQ;AACzC,IAAM,gBAAU,MAAM;AACpB,kBAAY,UAAU;AAAA,IACxB,CAAC;AACD,UAAM,kBAAwB;AAAA,MAC5B,CAAC,WAA+B;AAC9B,YAAI,CAAC,OAAQ,QAAO;AACpB,YAAI,WAAW,SAAS,MAAM,EAAG,QAAO;AACxC,eAAO,QAAQ,YAAY,SAAS,KAAK,CAAC,WAAW,OAAO,SAAS,MAAM,CAAC,CAAC;AAAA,MAC/E;AAAA,MACA,CAAC,SAAS;AAAA,IACZ;AAEA,UAAM,aAAmB,aAAO;AAAA,MAC9B,QAAQ;AAAA,MACR,QAAQ;AACN,aAAK,SAAS;AAAA,MAChB;AAAA,MACA,SAAS;AACP,aAAK,SAAS;AAAA,MAChB;AAAA,IACF,CAAC,EAAE;AAGH,IAAM,gBAAU,MAAM;AACpB,UAAI,SAAS;AACX,YAASC,iBAAT,SAAuB,OAAmB;AACxC,cAAI,WAAW,UAAU,CAAC,UAAW;AACrC,gBAAM,SAAS,MAAM;AACrB,cAAI,gBAAgB,MAAM,GAAG;AAC3B,kCAAsB,UAAU;AAAA,UAClC,OAAO;AACL,kBAAM,sBAAsB,SAAS,EAAE,QAAQ,KAAK,CAAC;AAAA,UACvD;AAAA,QACF,GAESC,kBAAT,SAAwB,OAAmB;AACzC,cAAI,WAAW,UAAU,CAAC,UAAW;AACrC,gBAAM,gBAAgB,MAAM;AAe5B,cAAI,kBAAkB,KAAM;AAM5B,cAAI,CAAC,gBAAgB,aAAa,GAAG;AACnC,kBAAM,sBAAsB,SAAS,EAAE,QAAQ,KAAK,CAAC;AAAA,UACvD;AAAA,QACF,GAKSC,mBAAT,SAAyB,WAA6B;AACpD,gBAAM,iBAAiB,SAAS;AAChC,cAAI,mBAAmB,SAAS,KAAM;AACtC,qBAAW,YAAY,WAAW;AAChC,gBAAI,SAAS,aAAa,SAAS,EAAG,OAAM,SAAS;AAAA,UACvD;AAAA,QACF;AA/CS,4BAAAF,gBAUA,iBAAAC,iBA+BA,kBAAAC;AAzCA,eAAAF,gBAAA;AAUA,eAAAC,iBAAA;AA+BA,eAAAC,kBAAA;AAQT,iBAAS,iBAAiB,WAAWF,cAAa;AAClD,iBAAS,iBAAiB,YAAYC,eAAc;AACpD,cAAM,mBAAmB,IAAI,iBAAiBC,gBAAe;AAC7D,YAAI,UAAW,kBAAiB,QAAQ,WAAW,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AAErF,eAAO,MAAM;AACX,mBAAS,oBAAoB,WAAWF,cAAa;AACrD,mBAAS,oBAAoB,YAAYC,eAAc;AACvD,2BAAiB,WAAW;AAAA,QAC9B;AAAA,MACF;AAAA,IACF,GAAG,CAAC,SAAS,WAAW,WAAW,QAAQ,eAAe,CAAC;AAE3D,IAAM,gBAAU,MAAM;AACpB,UAAI,WAAW;AACb,yBAAiB,IAAI,UAAU;AAC/B,cAAM,2BAA2B,SAAS;AAC1C,cAAM,sBAAsB,UAAU,SAAS,wBAAwB;AAEvE,YAAI,CAAC,qBAAqB;AACxB,gBAAM,aAAa,IAAI,YAAY,oBAAoB,aAAa;AACpE,oBAAU,iBAAiB,oBAAoB,gBAAgB;AAC/D,oBAAU,cAAc,UAAU;AAClC,cAAI,CAAC,WAAW,kBAAkB;AAChC,uBAAW,YAAY,sBAAsB,SAAS,CAAC,GAAG,EAAE,QAAQ,KAAK,CAAC;AAC1E,gBAAI,SAAS,kBAAkB,0BAA0B;AACvD,oBAAM,SAAS;AAAA,YACjB;AAAA,UACF;AAAA,QACF;AAEA,eAAO,MAAM;AACX,oBAAU,oBAAoB,oBAAoB,gBAAgB;AAKlE,qBAAW,MAAM;AACf,kBAAM,eAAe,IAAI,YAAY,sBAAsB,aAAa;AACxE,sBAAU,iBAAiB,sBAAsB,kBAAkB;AACnE,sBAAU,cAAc,YAAY;AACpC,gBAAI,CAAC,aAAa,kBAAkB;AAClC,oBAAM,4BAA4B,SAAS,MAAM,EAAE,QAAQ,KAAK,CAAC;AAAA,YACnE;AAEA,sBAAU,oBAAoB,sBAAsB,kBAAkB;AAEtE,6BAAiB,OAAO,UAAU;AAAA,UACpC,GAAG,CAAC;AAAA,QACN;AAAA,MACF;AAAA,IACF,GAAG,CAAC,WAAW,kBAAkB,oBAAoB,UAAU,CAAC;AAGhE,UAAM,gBAAsB;AAAA,MAC1B,CAAC,UAA+B;AAC9B,YAAI,CAAC,QAAQ,CAAC,QAAS;AACvB,YAAI,WAAW,OAAQ;AAEvB,cAAM,WAAW,MAAM,QAAQ,SAAS,CAAC,MAAM,UAAU,CAAC,MAAM,WAAW,CAAC,MAAM;AAClF,cAAM,iBAAiB,SAAS;AAEhC,YAAI,YAAY,gBAAgB;AAC9B,gBAAME,aAAY,MAAM;AACxB,gBAAM,CAAC,OAAO,IAAI,IAAI,iBAAiBA,UAAS;AAChD,gBAAM,4BAA4B,SAAS;AAG3C,cAAI,CAAC,2BAA2B;AAC9B,gBAAI,mBAAmBA,WAAW,OAAM,eAAe;AAAA,UACzD,OAAO;AACL,gBAAI,CAAC,MAAM,YAAY,mBAAmB,MAAM;AAC9C,oBAAM,eAAe;AACrB,kBAAI,KAAM,OAAM,OAAO,EAAE,QAAQ,KAAK,CAAC;AAAA,YACzC,WAAW,MAAM,YAAY,mBAAmB,OAAO;AACrD,oBAAM,eAAe;AACrB,kBAAI,KAAM,OAAM,MAAM,EAAE,QAAQ,KAAK,CAAC;AAAA,YACxC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,CAAC,MAAM,SAAS,WAAW,MAAM;AAAA,IACnC;AAEA,WACE,4CAAC,iCAAU,KAAV,EAAc,UAAU,IAAK,GAAG,YAAY,KAAK,cAAc,WAAW,eAAe;AAAA,EAE9F,GAtLA;AAuLF;AAuBA,IAAM,0BAAgC,oBAA+C,IAAI;AAEzF,IAAM,2BAA2B,wBAAwB;AAEzD,SAAS,8BAA8B;AACrC,QAAM,CAAC,OAAO,QAAQ,IAAU,eAAwB,CAAC,CAAC;AAC1D,QAAM,WAAiB;AAAA,IACrB,OAAO;AAAA,MACL,KAAK,wBAAC,SAAS,SAAS,CAAC,SAAU,KAAK,SAAS,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,IAAI,CAAE,GAA3E;AAAA,MACL,QAAQ,wBAAC,SAAS,SAAS,CAAC,SAAS,KAAK,OAAO,CAAC,YAAY,YAAY,IAAI,CAAC,GAAvE;AAAA,IACV;AAAA,IACA,CAAC;AAAA,EACH;AACA,SAAO,EAAE,OAAO,SAAS;AAC3B;AAVS;AAgBT,SAAS,oBAAoB,MAA0B;AACrD,QAAM,WAAiB,iBAAW,uBAAuB;AACzD,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,QAAQ,CAAC,SAAU;AACxB,aAAS,IAAI,IAAI;AACjB,WAAO,MAAM,SAAS,OAAO,IAAI;AAAA,EACnC,GAAG,CAAC,MAAM,QAAQ,CAAC;AACrB;AAPS;AAiBT,SAAS,WAAW,YAA2B,EAAE,SAAS,MAAM,IAAI,CAAC,GAAG;AACtE,QAAM,2BAA2B,SAAS;AAC1C,aAAW,aAAa,YAAY;AAClC,UAAM,WAAW,EAAE,OAAO,CAAC;AAC3B,QAAI,SAAS,kBAAkB,yBAA0B;AAAA,EAC3D;AACF;AANS;AAWT,SAAS,iBAAiB,WAAwB;AAChD,QAAM,aAAa,sBAAsB,SAAS;AAClD,QAAM,QAAQ,YAAY,YAAY,SAAS;AAC/C,QAAM,OAAO,YAAY,WAAW,QAAQ,GAAG,SAAS;AACxD,SAAO,CAAC,OAAO,IAAI;AACrB;AALS;AAiBT,SAAS,sBAAsB,WAAwB;AACrD,QAAM,QAAuB,CAAC;AAC9B,QAAM,SAAS,SAAS,iBAAiB,WAAW,WAAW,cAAc;AAAA,IAC3E,YAAY,wBAAC,SAAc;AACzB,YAAM,gBAAgB,KAAK,YAAY,WAAW,KAAK,SAAS;AAChE,UAAI,KAAK,YAAY,KAAK,UAAU,cAAe,QAAO,WAAW;AAIrE,aAAO,KAAK,YAAY,IAAI,WAAW,gBAAgB,WAAW;AAAA,IACpE,GAPY;AAAA,EAQd,CAAC;AACD,SAAO,OAAO,SAAS,EAAG,OAAM,KAAK,OAAO,WAA0B;AAGtE,SAAO;AACT;AAhBS;AAsBT,SAAS,YAAY,UAAyB,WAAwB;AAMpE,QAAM,wBACJ,OAAO,UAAU,oBAAoB,cACrC,UAAU,gBAAgB,EAAE,oBAAoB,KAAK,CAAC;AAExD,aAAW,WAAW,UAAU;AAC9B,UAAM,SAAS,wBACX,CAAC,QAAQ,gBAAgB,EAAE,oBAAoB,KAAK,CAAC,IACrD,SAAS,SAAS,EAAE,MAAM,UAAU,CAAC;AAEzC,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAnBS;AAqBT,SAAS,SAAS,MAAmB,EAAE,KAAK,GAA2B;AACrE,MAAI,iBAAiB,IAAI,EAAE,eAAe,SAAU,QAAO;AAC3D,SAAO,MAAM;AAEX,QAAI,SAAS,UAAa,SAAS,KAAM,QAAO;AAChD,QAAI,iBAAiB,IAAI,EAAE,YAAY,OAAQ,QAAO;AACtD,WAAO,KAAK;AAAA,EACd;AACA,SAAO;AACT;AATS;AAWT,SAAS,kBAAkB,SAAmE;AAC5F,SAAO,mBAAmB,oBAAoB,YAAY;AAC5D;AAFS;AAIT,SAAS,MAAM,SAAkC,EAAE,SAAS,MAAM,IAAI,CAAC,GAAG;AAExE,MAAI,WAAW,QAAQ,OAAO;AAC5B,UAAM,2BAA2B,SAAS;AAE1C,YAAQ,MAAM,EAAE,eAAe,KAAK,CAAC;AAErC,QAAI,YAAY,4BAA4B,kBAAkB,OAAO,KAAK;AACxE,cAAQ,OAAO;AAAA,EACnB;AACF;AAVS;AAiBT,IAAM,mBAAmB,uBAAuB;AAEhD,SAAS,yBAAyB;AAEhC,MAAI,QAAyB,CAAC;AAE9B,SAAO;AAAA,IACL,IAAI,YAA2B;AAE7B,YAAM,mBAAmB,MAAM,CAAC;AAChC,UAAI,eAAe,kBAAkB;AACnC,0BAAkB,MAAM;AAAA,MAC1B;AAEA,cAAQ,YAAY,OAAO,UAAU;AACrC,YAAM,QAAQ,UAAU;AAAA,IAC1B;AAAA,IAEA,OAAO,YAA2B;AAChC,cAAQ,YAAY,OAAO,UAAU;AACrC,YAAM,CAAC,GAAG,OAAO;AAAA,IACnB;AAAA,EACF;AACF;AArBS;AAuBT,SAAS,YAAe,OAAY,MAAS;AAC3C,QAAM,eAAe,CAAC,GAAG,KAAK;AAC9B,QAAM,QAAQ,aAAa,QAAQ,IAAI;AACvC,MAAI,UAAU,IAAI;AAChB,iBAAa,OAAO,OAAO,CAAC;AAAA,EAC9B;AACA,SAAO;AACT;AAPS;AAST,SAAS,YAAY,OAAsB;AACzC,SAAO,MAAM,OAAO,CAAC,SAAS,KAAK,YAAY,GAAG;AACpD;AAFS;", | ||
| "names": ["FocusScope", "handleFocusIn", "handleFocusOut", "handleMutations", "container"] | ||
| } |
+43
-4
@@ -19,2 +19,3 @@ "use client"; | ||
| trapped = false, | ||
| branches, | ||
| onMountAutoFocus: onMountAutoFocusProp, | ||
@@ -29,2 +30,14 @@ onUnmountAutoFocus: onUnmountAutoFocusProp, | ||
| const composedRefs = useComposedRefs(forwardedRef, setContainer); | ||
| const branchesRef = React.useRef(branches); | ||
| React.useEffect(() => { | ||
| branchesRef.current = branches; | ||
| }); | ||
| const isTargetInScope = React.useCallback( | ||
| (target) => { | ||
| if (!target) return false; | ||
| if (container?.contains(target)) return true; | ||
| return Boolean(branchesRef.current?.some((branch) => branch.contains(target))); | ||
| }, | ||
| [container] | ||
| ); | ||
| const focusScope = React.useRef({ | ||
@@ -44,3 +57,3 @@ paused: false, | ||
| const target = event.target; | ||
| if (container.contains(target)) { | ||
| if (isTargetInScope(target)) { | ||
| lastFocusedElementRef.current = target; | ||
@@ -54,3 +67,3 @@ } else { | ||
| if (relatedTarget === null) return; | ||
| if (!container.contains(relatedTarget)) { | ||
| if (!isTargetInScope(relatedTarget)) { | ||
| focus(lastFocusedElementRef.current, { select: true }); | ||
@@ -79,3 +92,3 @@ } | ||
| } | ||
| }, [trapped, container, focusScope.paused]); | ||
| }, [trapped, container, focusScope.paused, isTargetInScope]); | ||
| React.useEffect(() => { | ||
@@ -140,2 +153,25 @@ if (container) { | ||
| ); | ||
| var FocusScopeBranchContext = React.createContext(null); | ||
| var FocusScopeBranchProvider = FocusScopeBranchContext.Provider; | ||
| function useFocusScopeBranchRegistry() { | ||
| const [nodes, setNodes] = React.useState([]); | ||
| const registry = React.useMemo( | ||
| () => ({ | ||
| add: /* @__PURE__ */ __name((node) => setNodes((prev) => prev.includes(node) ? prev : [...prev, node]), "add"), | ||
| remove: /* @__PURE__ */ __name((node) => setNodes((prev) => prev.filter((current) => current !== node)), "remove") | ||
| }), | ||
| [] | ||
| ); | ||
| return { nodes, registry }; | ||
| } | ||
| __name(useFocusScopeBranchRegistry, "useFocusScopeBranchRegistry"); | ||
| function useFocusScopeBranch(node) { | ||
| const registry = React.useContext(FocusScopeBranchContext); | ||
| React.useEffect(() => { | ||
| if (!node || !registry) return; | ||
| registry.add(node); | ||
| return () => registry.remove(node); | ||
| }, [node, registry]); | ||
| } | ||
| __name(useFocusScopeBranch, "useFocusScopeBranch"); | ||
| function focusFirst(candidates, { select = false } = {}) { | ||
@@ -236,4 +272,7 @@ const previouslyFocusedElement = document.activeElement; | ||
| FocusScope, | ||
| FocusScope as Root | ||
| FocusScopeBranchProvider, | ||
| FocusScope as Root, | ||
| useFocusScopeBranch, | ||
| useFocusScopeBranchRegistry | ||
| }; | ||
| //# sourceMappingURL=index.mjs.map |
| { | ||
| "version": 3, | ||
| "sources": ["../src/focus-scope.tsx"], | ||
| "sourcesContent": ["import * as React from 'react';\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { useCallbackRef } from '@radix-ui/react-use-callback-ref';\n\nconst AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';\nconst AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\ntype FocusableTarget = HTMLElement | { focus(): void };\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeElement = React.ComponentRef<typeof Primitive.div>;\ntype PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FocusScopeProps extends PrimitiveDivProps {\n /**\n * When `true`, tabbing from last item will focus first tabbable\n * and shift+tab from first item will focus last tababble.\n * @defaultValue false\n */\n loop?: boolean;\n\n /**\n * When `true`, focus cannot escape the focus scope via keyboard,\n * pointer, or a programmatic focus.\n * @defaultValue false\n */\n trapped?: boolean;\n\n /**\n * Event handler called when auto-focusing on mount.\n * Can be prevented.\n */\n onMountAutoFocus?: (event: Event) => void;\n\n /**\n * Event handler called when auto-focusing on unmount.\n * Can be prevented.\n */\n onUnmountAutoFocus?: (event: Event) => void;\n}\n\nconst FocusScope = /* @__PURE__ */ React.forwardRef<FocusScopeElement, FocusScopeProps>(\n function FocusScope(props, forwardedRef) {\n const {\n loop = false,\n trapped = false,\n onMountAutoFocus: onMountAutoFocusProp,\n onUnmountAutoFocus: onUnmountAutoFocusProp,\n ...scopeProps\n } = props;\n const [container, setContainer] = React.useState<HTMLElement | null>(null);\n const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);\n const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const composedRefs = useComposedRefs(forwardedRef, setContainer);\n\n const focusScope = React.useRef({\n paused: false,\n pause() {\n this.paused = true;\n },\n resume() {\n this.paused = false;\n },\n }).current;\n\n // Takes care of trapping focus if focus is moved outside programmatically for example\n React.useEffect(() => {\n if (trapped) {\n function handleFocusIn(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const target = event.target as HTMLElement | null;\n if (container.contains(target)) {\n lastFocusedElementRef.current = target;\n } else {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n function handleFocusOut(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const relatedTarget = event.relatedTarget as HTMLElement | null;\n\n // A `focusout` event with a `null` `relatedTarget` will happen in at least two cases:\n //\n // 1. When the user switches app/tabs/windows/the browser itself loses focus.\n // 2. In Google Chrome, when the focused element is removed from the DOM.\n //\n // We let the browser do its thing here because:\n //\n // 1. The browser already keeps a memory of what's focused for when the page gets refocused.\n // 2. In Google Chrome, if we try to focus the deleted focused element (as per below), it\n // throws the CPU to 100%, so we avoid doing anything for this reason here too.\n if (relatedTarget === null) return;\n\n // If the focus has moved to an actual legitimate element (`relatedTarget !== null`)\n // that is outside the container, we move focus to the last valid focused element inside.\n if (!container.contains(relatedTarget)) {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n // When the focused element gets removed from the DOM, browsers move focus\n // back to the document.body. In this case, we move focus to the container\n // to keep focus trapped correctly.\n function handleMutations(mutations: MutationRecord[]) {\n const focusedElement = document.activeElement as HTMLElement | null;\n if (focusedElement !== document.body) return;\n for (const mutation of mutations) {\n if (mutation.removedNodes.length > 0) focus(container);\n }\n }\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n const mutationObserver = new MutationObserver(handleMutations);\n if (container) mutationObserver.observe(container, { childList: true, subtree: true });\n\n return () => {\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n mutationObserver.disconnect();\n };\n }\n }, [trapped, container, focusScope.paused]);\n\n React.useEffect(() => {\n if (container) {\n focusScopesStack.add(focusScope);\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = container.contains(previouslyFocusedElement);\n\n if (!hasFocusedCandidate) {\n const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n container.dispatchEvent(mountEvent);\n if (!mountEvent.defaultPrevented) {\n focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });\n if (document.activeElement === previouslyFocusedElement) {\n focus(container);\n }\n }\n }\n\n return () => {\n container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n\n // We hit a react bug (fixed in v17) with focusing in unmount.\n // We need to delay the focus a little to get around it for now.\n // See: https://github.com/facebook/react/issues/17894\n setTimeout(() => {\n const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n container.dispatchEvent(unmountEvent);\n if (!unmountEvent.defaultPrevented) {\n focus(previouslyFocusedElement ?? document.body, { select: true });\n }\n // we need to remove the listener after we `dispatchEvent`\n container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n\n focusScopesStack.remove(focusScope);\n }, 0);\n };\n }\n }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);\n\n // Takes care of looping focus (when tabbing whilst at the edges)\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (!loop && !trapped) return;\n if (focusScope.paused) return;\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) event.preventDefault();\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n if (loop) focus(first, { select: true });\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n if (loop) focus(last, { select: true });\n }\n }\n }\n },\n [loop, trapped, focusScope.paused],\n );\n\n return (\n <Primitive.div tabIndex={-1} {...scopeProps} ref={composedRefs} onKeyDown={handleKeyDown} />\n );\n },\n);\n\n/* -------------------------------------------------------------------------------------------------\n * Utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Attempts focusing the first element in a list of candidates.\n * Stops when focus has actually moved.\n */\nfunction focusFirst(candidates: HTMLElement[], { select = false } = {}) {\n const previouslyFocusedElement = document.activeElement;\n for (const candidate of candidates) {\n focus(candidate, { select });\n if (document.activeElement !== previouslyFocusedElement) return;\n }\n}\n\n/**\n * Returns the first and last tabbable elements inside a container.\n */\nfunction getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates, container);\n const last = findVisible(candidates.reverse(), container);\n return [first, last] as const;\n}\n\n/**\n * Returns a list of potential tabbable candidates.\n *\n * NOTE: This is only a close approximation. For example it doesn't take into account cases like when\n * elements are not visible. This cannot be worked out easily by just reading a property, but rather\n * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker\n * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1\n */\nfunction getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: any) => {\n const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';\n if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;\n // `.tabIndex` is not the same as the `tabindex` attribute. It works on the\n // runtime's understanding of tabbability, so this automatically accounts\n // for any kind of element that could be tabbed to.\n return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);\n // we do not take into account the order of nodes with positive `tabIndex` as it\n // hinders accessibility to have tab order different from visual order.\n return nodes;\n}\n\n/**\n * Returns the first visible element in a list.\n * NOTE: Only checks visibility up to the `container`.\n */\nfunction findVisible(elements: HTMLElement[], container: HTMLElement) {\n // `checkVisibility` performs a single native check for `visibility: hidden`\n // and `display: none` across the ancestor chain. This avoids the repeated\n // `getComputedStyle` calls per ancestor that the fallback path requires,\n // which reduces the cost of style resolution triggered by earlier DOM writes\n // (e.g. react-remove-scroll, DismissableLayer setting body styles).\n const canUseCheckVisibility =\n typeof container.checkVisibility === 'function' &&\n container.checkVisibility({ checkVisibilityCSS: true });\n\n for (const element of elements) {\n const hidden = canUseCheckVisibility\n ? !element.checkVisibility({ checkVisibilityCSS: true })\n : isHidden(element, { upTo: container });\n // we stop checking if it's hidden at the `container` level (excluding)\n if (!hidden) {\n return element;\n }\n }\n}\n\nfunction isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {\n if (getComputedStyle(node).visibility === 'hidden') return true;\n while (node) {\n // we stop at `upTo` (excluding it)\n if (upTo !== undefined && node === upTo) return false;\n if (getComputedStyle(node).display === 'none') return true;\n node = node.parentElement as HTMLElement;\n }\n return false;\n}\n\nfunction isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {\n return element instanceof HTMLInputElement && 'select' in element;\n}\n\nfunction focus(element?: FocusableTarget | null, { select = false } = {}) {\n // only focus if that element is focusable\n if (element && element.focus) {\n const previouslyFocusedElement = document.activeElement;\n // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users\n element.focus({ preventScroll: true });\n // only select if its not the same element, it supports selection and we need to select\n if (element !== previouslyFocusedElement && isSelectableInput(element) && select)\n element.select();\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope stack\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeAPI = { paused: boolean; pause(): void; resume(): void };\nconst focusScopesStack = createFocusScopesStack();\n\nfunction createFocusScopesStack() {\n /** A stack of focus scopes, with the active one at the top */\n let stack: FocusScopeAPI[] = [];\n\n return {\n add(focusScope: FocusScopeAPI) {\n // pause the currently active focus scope (at the top of the stack)\n const activeFocusScope = stack[0];\n if (focusScope !== activeFocusScope) {\n activeFocusScope?.pause();\n }\n // remove in case it already exists (because we'll re-add it at the top of the stack)\n stack = arrayRemove(stack, focusScope);\n stack.unshift(focusScope);\n },\n\n remove(focusScope: FocusScopeAPI) {\n stack = arrayRemove(stack, focusScope);\n stack[0]?.resume();\n },\n };\n}\n\nfunction arrayRemove<T>(array: T[], item: T) {\n const updatedArray = [...array];\n const index = updatedArray.indexOf(item);\n if (index !== -1) {\n updatedArray.splice(index, 1);\n }\n return updatedArray;\n}\n\nfunction removeLinks(items: HTMLElement[]) {\n return items.filter((item) => item.tagName !== 'A');\n}\n\nexport {\n FocusScope,\n //\n FocusScope as Root,\n};\nexport type { FocusScopeProps };\n"], | ||
| "mappings": "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", | ||
| "sourcesContent": ["import * as React from 'react';\nimport { useComposedRefs } from '@radix-ui/react-compose-refs';\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { useCallbackRef } from '@radix-ui/react-use-callback-ref';\n\nconst AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';\nconst AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';\nconst EVENT_OPTIONS = { bubbles: false, cancelable: true };\n\ntype FocusableTarget = HTMLElement | { focus(): void };\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeElement = React.ComponentRef<typeof Primitive.div>;\ntype PrimitiveDivProps = React.ComponentPropsWithoutRef<typeof Primitive.div>;\ninterface FocusScopeProps extends PrimitiveDivProps {\n /**\n * When `true`, tabbing from last item will focus first tabbable\n * and shift+tab from first item will focus last tababble.\n * @defaultValue false\n */\n loop?: boolean;\n\n /**\n * When `true`, focus cannot escape the focus scope via keyboard,\n * pointer, or a programmatic focus.\n * @defaultValue false\n */\n trapped?: boolean;\n\n /**\n * A list of nodes that should be treated as part of the focus scope even\n * though they don't live within the scope's DOM subtree (eg. portalled\n * content of a nested, non-modal layer). When the scope is `trapped`, focus\n * is allowed to move into these branches without being reclaimed.\n *\n * See: https://github.com/radix-ui/primitives/issues/3423\n */\n branches?: HTMLElement[];\n\n /**\n * Event handler called when auto-focusing on mount.\n * Can be prevented.\n */\n onMountAutoFocus?: (event: Event) => void;\n\n /**\n * Event handler called when auto-focusing on unmount.\n * Can be prevented.\n */\n onUnmountAutoFocus?: (event: Event) => void;\n}\n\nconst FocusScope = /* @__PURE__ */ React.forwardRef<FocusScopeElement, FocusScopeProps>(\n function FocusScope(props, forwardedRef) {\n const {\n loop = false,\n trapped = false,\n branches,\n onMountAutoFocus: onMountAutoFocusProp,\n onUnmountAutoFocus: onUnmountAutoFocusProp,\n ...scopeProps\n } = props;\n const [container, setContainer] = React.useState<HTMLElement | null>(null);\n const onMountAutoFocus = useCallbackRef(onMountAutoFocusProp);\n const onUnmountAutoFocus = useCallbackRef(onUnmountAutoFocusProp);\n const lastFocusedElementRef = React.useRef<HTMLElement | null>(null);\n const composedRefs = useComposedRefs(forwardedRef, setContainer);\n\n // Keep the latest branches in a ref so the trap effect below doesn't need to resubscribe its\n // listeners whenever the branch list updates. We sync it in the commit phase (not during render)\n // to stay safe under concurrent rendering, where a render can be discarded or replayed. The trap's\n // focus event handlers only run in response to user interaction (well after commit), so reading\n // the ref from them always sees the committed branch list.\n const branchesRef = React.useRef(branches);\n React.useEffect(() => {\n branchesRef.current = branches;\n });\n const isTargetInScope = React.useCallback(\n (target: HTMLElement | null) => {\n if (!target) return false;\n if (container?.contains(target)) return true;\n return Boolean(branchesRef.current?.some((branch) => branch.contains(target)));\n },\n [container],\n );\n\n const focusScope = React.useRef({\n paused: false,\n pause() {\n this.paused = true;\n },\n resume() {\n this.paused = false;\n },\n }).current;\n\n // Takes care of trapping focus if focus is moved outside programmatically for example\n React.useEffect(() => {\n if (trapped) {\n function handleFocusIn(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const target = event.target as HTMLElement | null;\n if (isTargetInScope(target)) {\n lastFocusedElementRef.current = target;\n } else {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n function handleFocusOut(event: FocusEvent) {\n if (focusScope.paused || !container) return;\n const relatedTarget = event.relatedTarget as HTMLElement | null;\n\n // A `focusout` event with a `null` `relatedTarget` will happen in at\n // least two cases:\n // 1. When the user switches app/tabs/windows/the browser itself loses\n // focus.\n // 2. In Google Chrome, when the focused element is removed from the\n // DOM.\n //\n // We let the browser do its thing here because:\n // 1. The browser already keeps a memory of what's focused for when\n // the page gets refocused.\n // 2. In Google Chrome, if we try to focus the deleted focused element\n // (as per below), it throws the CPU to 100%, so we avoid doing\n // anything for this reason here too.\n if (relatedTarget === null) return;\n\n // If the focus has moved to an actual legitimate element\n // (`relatedTarget !== null`) that is outside the container (and any\n // registered branches), we move focus to the last valid focused\n // element inside.\n if (!isTargetInScope(relatedTarget)) {\n focus(lastFocusedElementRef.current, { select: true });\n }\n }\n\n // When the focused element gets removed from the DOM, browsers move focus\n // back to the document.body. In this case, we move focus to the container\n // to keep focus trapped correctly.\n function handleMutations(mutations: MutationRecord[]) {\n const focusedElement = document.activeElement as HTMLElement | null;\n if (focusedElement !== document.body) return;\n for (const mutation of mutations) {\n if (mutation.removedNodes.length > 0) focus(container);\n }\n }\n\n document.addEventListener('focusin', handleFocusIn);\n document.addEventListener('focusout', handleFocusOut);\n const mutationObserver = new MutationObserver(handleMutations);\n if (container) mutationObserver.observe(container, { childList: true, subtree: true });\n\n return () => {\n document.removeEventListener('focusin', handleFocusIn);\n document.removeEventListener('focusout', handleFocusOut);\n mutationObserver.disconnect();\n };\n }\n }, [trapped, container, focusScope.paused, isTargetInScope]);\n\n React.useEffect(() => {\n if (container) {\n focusScopesStack.add(focusScope);\n const previouslyFocusedElement = document.activeElement as HTMLElement | null;\n const hasFocusedCandidate = container.contains(previouslyFocusedElement);\n\n if (!hasFocusedCandidate) {\n const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n container.dispatchEvent(mountEvent);\n if (!mountEvent.defaultPrevented) {\n focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });\n if (document.activeElement === previouslyFocusedElement) {\n focus(container);\n }\n }\n }\n\n return () => {\n container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus);\n\n // We hit a react bug (fixed in v17) with focusing in unmount.\n // We need to delay the focus a little to get around it for now.\n // See: https://github.com/facebook/react/issues/17894\n setTimeout(() => {\n const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS);\n container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n container.dispatchEvent(unmountEvent);\n if (!unmountEvent.defaultPrevented) {\n focus(previouslyFocusedElement ?? document.body, { select: true });\n }\n // we need to remove the listener after we `dispatchEvent`\n container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus);\n\n focusScopesStack.remove(focusScope);\n }, 0);\n };\n }\n }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]);\n\n // Takes care of looping focus (when tabbing whilst at the edges)\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent) => {\n if (!loop && !trapped) return;\n if (focusScope.paused) return;\n\n const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;\n const focusedElement = document.activeElement as HTMLElement | null;\n\n if (isTabKey && focusedElement) {\n const container = event.currentTarget as HTMLElement;\n const [first, last] = getTabbableEdges(container);\n const hasTabbableElementsInside = first && last;\n\n // we can only wrap focus if we have tabbable edges\n if (!hasTabbableElementsInside) {\n if (focusedElement === container) event.preventDefault();\n } else {\n if (!event.shiftKey && focusedElement === last) {\n event.preventDefault();\n if (loop) focus(first, { select: true });\n } else if (event.shiftKey && focusedElement === first) {\n event.preventDefault();\n if (loop) focus(last, { select: true });\n }\n }\n }\n },\n [loop, trapped, focusScope.paused],\n );\n\n return (\n <Primitive.div tabIndex={-1} {...scopeProps} ref={composedRefs} onKeyDown={handleKeyDown} />\n );\n },\n);\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope branch registry\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Lets portalled content that is a React descendant of a (modal) layer \u2014 but rendered outside of\n * that layer's DOM subtree \u2014 register itself as a \"branch\" of the layer's focus scope.\n *\n * A modal container (eg. `Dialog`) creates a registry via `useFocusScopeBranchRegistry`, renders a\n * `FocusScopeBranchProvider` around its children, and passes the collected `nodes` to its trapped\n * `FocusScope` (so focus isn't reclaimed from the branch) and, if applicable, to its `RemoveScroll`\n * `shards` (so the branch remains scrollable). Nested layers (eg. a non-modal `Popover`) register\n * their content node with `useFocusScopeBranch`.\n *\n * See: https://github.com/radix-ui/primitives/issues/3423\n */\ninterface FocusScopeBranchRegistry {\n add: (node: HTMLElement) => void;\n remove: (node: HTMLElement) => void;\n}\n\nconst FocusScopeBranchContext = React.createContext<FocusScopeBranchRegistry | null>(null);\n\nconst FocusScopeBranchProvider = FocusScopeBranchContext.Provider;\n\nfunction useFocusScopeBranchRegistry() {\n const [nodes, setNodes] = React.useState<HTMLElement[]>([]);\n const registry = React.useMemo<FocusScopeBranchRegistry>(\n () => ({\n add: (node) => setNodes((prev) => (prev.includes(node) ? prev : [...prev, node])),\n remove: (node) => setNodes((prev) => prev.filter((current) => current !== node)),\n }),\n [],\n );\n return { nodes, registry } as const;\n}\n\n/**\n * Registers `node` as a branch of the nearest ancestor `FocusScopeBranchProvider`. No-ops when\n * there is no ancestor registry (eg. the layer isn't nested inside a modal layer).\n */\nfunction useFocusScopeBranch(node: HTMLElement | null) {\n const registry = React.useContext(FocusScopeBranchContext);\n React.useEffect(() => {\n if (!node || !registry) return;\n registry.add(node);\n return () => registry.remove(node);\n }, [node, registry]);\n}\n\n/* -------------------------------------------------------------------------------------------------\n * Utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * Attempts focusing the first element in a list of candidates.\n * Stops when focus has actually moved.\n */\nfunction focusFirst(candidates: HTMLElement[], { select = false } = {}) {\n const previouslyFocusedElement = document.activeElement;\n for (const candidate of candidates) {\n focus(candidate, { select });\n if (document.activeElement !== previouslyFocusedElement) return;\n }\n}\n\n/**\n * Returns the first and last tabbable elements inside a container.\n */\nfunction getTabbableEdges(container: HTMLElement) {\n const candidates = getTabbableCandidates(container);\n const first = findVisible(candidates, container);\n const last = findVisible(candidates.reverse(), container);\n return [first, last] as const;\n}\n\n/**\n * Returns a list of potential tabbable candidates.\n *\n * NOTE: This is only a close approximation. For example it doesn't take into account cases like when\n * elements are not visible. This cannot be worked out easily by just reading a property, but rather\n * necessitate runtime knowledge (computed styles, etc). We deal with these cases separately.\n *\n * See: https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker\n * Credit: https://github.com/discord/focus-layers/blob/master/src/util/wrapFocus.tsx#L1\n */\nfunction getTabbableCandidates(container: HTMLElement) {\n const nodes: HTMLElement[] = [];\n const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (node: any) => {\n const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden';\n if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP;\n // `.tabIndex` is not the same as the `tabindex` attribute. It works on the\n // runtime's understanding of tabbability, so this automatically accounts\n // for any kind of element that could be tabbed to.\n return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP;\n },\n });\n while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement);\n // we do not take into account the order of nodes with positive `tabIndex` as it\n // hinders accessibility to have tab order different from visual order.\n return nodes;\n}\n\n/**\n * Returns the first visible element in a list.\n * NOTE: Only checks visibility up to the `container`.\n */\nfunction findVisible(elements: HTMLElement[], container: HTMLElement) {\n // `checkVisibility` performs a single native check for `visibility: hidden`\n // and `display: none` across the ancestor chain. This avoids the repeated\n // `getComputedStyle` calls per ancestor that the fallback path requires,\n // which reduces the cost of style resolution triggered by earlier DOM writes\n // (e.g. react-remove-scroll, DismissableLayer setting body styles).\n const canUseCheckVisibility =\n typeof container.checkVisibility === 'function' &&\n container.checkVisibility({ checkVisibilityCSS: true });\n\n for (const element of elements) {\n const hidden = canUseCheckVisibility\n ? !element.checkVisibility({ checkVisibilityCSS: true })\n : isHidden(element, { upTo: container });\n // we stop checking if it's hidden at the `container` level (excluding)\n if (!hidden) {\n return element;\n }\n }\n}\n\nfunction isHidden(node: HTMLElement, { upTo }: { upTo?: HTMLElement }) {\n if (getComputedStyle(node).visibility === 'hidden') return true;\n while (node) {\n // we stop at `upTo` (excluding it)\n if (upTo !== undefined && node === upTo) return false;\n if (getComputedStyle(node).display === 'none') return true;\n node = node.parentElement as HTMLElement;\n }\n return false;\n}\n\nfunction isSelectableInput(element: any): element is FocusableTarget & { select: () => void } {\n return element instanceof HTMLInputElement && 'select' in element;\n}\n\nfunction focus(element?: FocusableTarget | null, { select = false } = {}) {\n // only focus if that element is focusable\n if (element && element.focus) {\n const previouslyFocusedElement = document.activeElement;\n // NOTE: we prevent scrolling on focus, to minimize jarring transitions for users\n element.focus({ preventScroll: true });\n // only select if its not the same element, it supports selection and we need to select\n if (element !== previouslyFocusedElement && isSelectableInput(element) && select)\n element.select();\n }\n}\n\n/* -------------------------------------------------------------------------------------------------\n * FocusScope stack\n * -----------------------------------------------------------------------------------------------*/\n\ntype FocusScopeAPI = { paused: boolean; pause(): void; resume(): void };\nconst focusScopesStack = createFocusScopesStack();\n\nfunction createFocusScopesStack() {\n /** A stack of focus scopes, with the active one at the top */\n let stack: FocusScopeAPI[] = [];\n\n return {\n add(focusScope: FocusScopeAPI) {\n // pause the currently active focus scope (at the top of the stack)\n const activeFocusScope = stack[0];\n if (focusScope !== activeFocusScope) {\n activeFocusScope?.pause();\n }\n // remove in case it already exists (because we'll re-add it at the top of the stack)\n stack = arrayRemove(stack, focusScope);\n stack.unshift(focusScope);\n },\n\n remove(focusScope: FocusScopeAPI) {\n stack = arrayRemove(stack, focusScope);\n stack[0]?.resume();\n },\n };\n}\n\nfunction arrayRemove<T>(array: T[], item: T) {\n const updatedArray = [...array];\n const index = updatedArray.indexOf(item);\n if (index !== -1) {\n updatedArray.splice(index, 1);\n }\n return updatedArray;\n}\n\nfunction removeLinks(items: HTMLElement[]) {\n return items.filter((item) => item.tagName !== 'A');\n}\n\nexport {\n FocusScope,\n FocusScopeBranchProvider,\n useFocusScopeBranchRegistry,\n useFocusScopeBranch,\n //\n FocusScope as Root,\n};\nexport type { FocusScopeProps, FocusScopeBranchRegistry };\n"], | ||
| "mappings": "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", | ||
| "names": ["FocusScope", "handleFocusIn", "handleFocusOut", "handleMutations", "container"] | ||
| } |
+5
-5
| { | ||
| "name": "@radix-ui/react-focus-scope", | ||
| "version": "1.1.14", | ||
| "version": "1.1.15", | ||
| "license": "MIT", | ||
@@ -15,4 +15,4 @@ "source": "./src/index.ts", | ||
| "@radix-ui/react-compose-refs": "1.1.4", | ||
| "@radix-ui/react-use-callback-ref": "1.1.3", | ||
| "@radix-ui/react-primitive": "2.1.8" | ||
| "@radix-ui/react-primitive": "2.1.9", | ||
| "@radix-ui/react-use-callback-ref": "1.1.3" | ||
| }, | ||
@@ -25,5 +25,5 @@ "devDependencies": { | ||
| "typescript": "^5.9.3", | ||
| "@repo/builder": "0.0.0", | ||
| "@repo/test-utils": "0.0.0", | ||
| "@repo/typescript-config": "0.0.0", | ||
| "@repo/builder": "0.0.0" | ||
| "@repo/typescript-config": "0.0.0" | ||
| }, | ||
@@ -30,0 +30,0 @@ "peerDependencies": { |
82116
24.28%634
21.69%+ Added
+ Added
- Removed
- Removed