Spaces:
Runtime error
Runtime error
| ; | |
| "use client"; | |
| var __create = Object.create; | |
| var __defProp = Object.defineProperty; | |
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | |
| var __getOwnPropNames = Object.getOwnPropertyNames; | |
| var __getProtoOf = Object.getPrototypeOf; | |
| var __hasOwnProp = Object.prototype.hasOwnProperty; | |
| var __export = (target, all) => { | |
| for (var name in all) | |
| __defProp(target, name, { get: all[name], enumerable: true }); | |
| }; | |
| var __copyProps = (to, from, except, desc) => { | |
| if (from && typeof from === "object" || typeof from === "function") { | |
| for (let key of __getOwnPropNames(from)) | |
| if (!__hasOwnProp.call(to, key) && key !== except) | |
| __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); | |
| } | |
| return to; | |
| }; | |
| var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | |
| // If the importer is in node compatibility mode or this is not an ESM | |
| // file that has been converted to a CommonJS file using a Babel- | |
| // compatible transform (i.e. "__esModule" has not been set), then set | |
| // "default" to the CommonJS "module.exports" for node compatibility. | |
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | |
| mod | |
| )); | |
| var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); | |
| // src/index.ts | |
| var index_exports = {}; | |
| __export(index_exports, { | |
| FocusScope: () => FocusScope, | |
| Root: () => Root | |
| }); | |
| module.exports = __toCommonJS(index_exports); | |
| // src/focus-scope.tsx | |
| var React = __toESM(require("react")); | |
| var import_react_compose_refs = require("@radix-ui/react-compose-refs"); | |
| var import_react_primitive = require("@radix-ui/react-primitive"); | |
| var import_react_use_callback_ref = require("@radix-ui/react-use-callback-ref"); | |
| var import_jsx_runtime = require("react/jsx-runtime"); | |
| var AUTOFOCUS_ON_MOUNT = "focusScope.autoFocusOnMount"; | |
| var AUTOFOCUS_ON_UNMOUNT = "focusScope.autoFocusOnUnmount"; | |
| var EVENT_OPTIONS = { bubbles: false, cancelable: true }; | |
| var FOCUS_SCOPE_NAME = "FocusScope"; | |
| var FocusScope = React.forwardRef((props, forwardedRef) => { | |
| const { | |
| loop = false, | |
| trapped = false, | |
| onMountAutoFocus: onMountAutoFocusProp, | |
| onUnmountAutoFocus: onUnmountAutoFocusProp, | |
| ...scopeProps | |
| } = props; | |
| const [container, setContainer] = React.useState(null); | |
| const onMountAutoFocus = (0, import_react_use_callback_ref.useCallbackRef)(onMountAutoFocusProp); | |
| const onUnmountAutoFocus = (0, import_react_use_callback_ref.useCallbackRef)(onUnmountAutoFocusProp); | |
| const lastFocusedElementRef = React.useRef(null); | |
| const composedRefs = (0, import_react_compose_refs.useComposedRefs)(forwardedRef, (node) => setContainer(node)); | |
| const focusScope = React.useRef({ | |
| paused: false, | |
| pause() { | |
| this.paused = true; | |
| }, | |
| resume() { | |
| this.paused = false; | |
| } | |
| }).current; | |
| React.useEffect(() => { | |
| if (trapped) { | |
| let handleFocusIn2 = function(event) { | |
| if (focusScope.paused || !container) return; | |
| const target = event.target; | |
| if (container.contains(target)) { | |
| lastFocusedElementRef.current = target; | |
| } else { | |
| focus(lastFocusedElementRef.current, { select: true }); | |
| } | |
| }, handleFocusOut2 = function(event) { | |
| if (focusScope.paused || !container) return; | |
| const relatedTarget = event.relatedTarget; | |
| if (relatedTarget === null) return; | |
| if (!container.contains(relatedTarget)) { | |
| focus(lastFocusedElementRef.current, { select: true }); | |
| } | |
| }, handleMutations2 = function(mutations) { | |
| const focusedElement = document.activeElement; | |
| if (focusedElement !== document.body) return; | |
| for (const mutation of mutations) { | |
| if (mutation.removedNodes.length > 0) focus(container); | |
| } | |
| }; | |
| var handleFocusIn = handleFocusIn2, handleFocusOut = handleFocusOut2, handleMutations = handleMutations2; | |
| document.addEventListener("focusin", handleFocusIn2); | |
| document.addEventListener("focusout", handleFocusOut2); | |
| const mutationObserver = new MutationObserver(handleMutations2); | |
| if (container) mutationObserver.observe(container, { childList: true, subtree: true }); | |
| return () => { | |
| document.removeEventListener("focusin", handleFocusIn2); | |
| document.removeEventListener("focusout", handleFocusOut2); | |
| mutationObserver.disconnect(); | |
| }; | |
| } | |
| }, [trapped, container, focusScope.paused]); | |
| React.useEffect(() => { | |
| if (container) { | |
| focusScopesStack.add(focusScope); | |
| const previouslyFocusedElement = document.activeElement; | |
| const hasFocusedCandidate = container.contains(previouslyFocusedElement); | |
| if (!hasFocusedCandidate) { | |
| const mountEvent = new CustomEvent(AUTOFOCUS_ON_MOUNT, EVENT_OPTIONS); | |
| container.addEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus); | |
| container.dispatchEvent(mountEvent); | |
| if (!mountEvent.defaultPrevented) { | |
| focusFirst(removeLinks(getTabbableCandidates(container)), { select: true }); | |
| if (document.activeElement === previouslyFocusedElement) { | |
| focus(container); | |
| } | |
| } | |
| } | |
| return () => { | |
| container.removeEventListener(AUTOFOCUS_ON_MOUNT, onMountAutoFocus); | |
| setTimeout(() => { | |
| const unmountEvent = new CustomEvent(AUTOFOCUS_ON_UNMOUNT, EVENT_OPTIONS); | |
| container.addEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus); | |
| container.dispatchEvent(unmountEvent); | |
| if (!unmountEvent.defaultPrevented) { | |
| focus(previouslyFocusedElement ?? document.body, { select: true }); | |
| } | |
| container.removeEventListener(AUTOFOCUS_ON_UNMOUNT, onUnmountAutoFocus); | |
| focusScopesStack.remove(focusScope); | |
| }, 0); | |
| }; | |
| } | |
| }, [container, onMountAutoFocus, onUnmountAutoFocus, focusScope]); | |
| const handleKeyDown = React.useCallback( | |
| (event) => { | |
| if (!loop && !trapped) return; | |
| if (focusScope.paused) return; | |
| const isTabKey = event.key === "Tab" && !event.altKey && !event.ctrlKey && !event.metaKey; | |
| const focusedElement = document.activeElement; | |
| if (isTabKey && focusedElement) { | |
| const container2 = event.currentTarget; | |
| const [first, last] = getTabbableEdges(container2); | |
| const hasTabbableElementsInside = first && last; | |
| if (!hasTabbableElementsInside) { | |
| if (focusedElement === container2) event.preventDefault(); | |
| } else { | |
| if (!event.shiftKey && focusedElement === last) { | |
| event.preventDefault(); | |
| if (loop) focus(first, { select: true }); | |
| } else if (event.shiftKey && focusedElement === first) { | |
| event.preventDefault(); | |
| if (loop) focus(last, { select: true }); | |
| } | |
| } | |
| } | |
| }, | |
| [loop, trapped, focusScope.paused] | |
| ); | |
| return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_primitive.Primitive.div, { tabIndex: -1, ...scopeProps, ref: composedRefs, onKeyDown: handleKeyDown }); | |
| }); | |
| FocusScope.displayName = FOCUS_SCOPE_NAME; | |
| function focusFirst(candidates, { select = false } = {}) { | |
| const previouslyFocusedElement = document.activeElement; | |
| for (const candidate of candidates) { | |
| focus(candidate, { select }); | |
| if (document.activeElement !== previouslyFocusedElement) return; | |
| } | |
| } | |
| function getTabbableEdges(container) { | |
| const candidates = getTabbableCandidates(container); | |
| const first = findVisible(candidates, container); | |
| const last = findVisible(candidates.reverse(), container); | |
| return [first, last]; | |
| } | |
| function getTabbableCandidates(container) { | |
| const nodes = []; | |
| const walker = document.createTreeWalker(container, NodeFilter.SHOW_ELEMENT, { | |
| acceptNode: (node) => { | |
| const isHiddenInput = node.tagName === "INPUT" && node.type === "hidden"; | |
| if (node.disabled || node.hidden || isHiddenInput) return NodeFilter.FILTER_SKIP; | |
| return node.tabIndex >= 0 ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; | |
| } | |
| }); | |
| while (walker.nextNode()) nodes.push(walker.currentNode); | |
| return nodes; | |
| } | |
| function findVisible(elements, container) { | |
| for (const element of elements) { | |
| if (!isHidden(element, { upTo: container })) return element; | |
| } | |
| } | |
| function isHidden(node, { upTo }) { | |
| if (getComputedStyle(node).visibility === "hidden") return true; | |
| while (node) { | |
| if (upTo !== void 0 && node === upTo) return false; | |
| if (getComputedStyle(node).display === "none") return true; | |
| node = node.parentElement; | |
| } | |
| return false; | |
| } | |
| function isSelectableInput(element) { | |
| return element instanceof HTMLInputElement && "select" in element; | |
| } | |
| function focus(element, { select = false } = {}) { | |
| if (element && element.focus) { | |
| const previouslyFocusedElement = document.activeElement; | |
| element.focus({ preventScroll: true }); | |
| if (element !== previouslyFocusedElement && isSelectableInput(element) && select) | |
| element.select(); | |
| } | |
| } | |
| var focusScopesStack = createFocusScopesStack(); | |
| function createFocusScopesStack() { | |
| let stack = []; | |
| return { | |
| add(focusScope) { | |
| const activeFocusScope = stack[0]; | |
| if (focusScope !== activeFocusScope) { | |
| activeFocusScope?.pause(); | |
| } | |
| stack = arrayRemove(stack, focusScope); | |
| stack.unshift(focusScope); | |
| }, | |
| remove(focusScope) { | |
| stack = arrayRemove(stack, focusScope); | |
| stack[0]?.resume(); | |
| } | |
| }; | |
| } | |
| function arrayRemove(array, item) { | |
| const updatedArray = [...array]; | |
| const index = updatedArray.indexOf(item); | |
| if (index !== -1) { | |
| updatedArray.splice(index, 1); | |
| } | |
| return updatedArray; | |
| } | |
| function removeLinks(items) { | |
| return items.filter((item) => item.tagName !== "A"); | |
| } | |
| var Root = FocusScope; | |
| //# sourceMappingURL=index.js.map | |