@radix-ui/react-focus-scope
Advanced tools
Comparing version 1.1.0-rc.2 to 1.1.0-rc.3
"use strict"; | ||
"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 __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { | ||
get: (a, b) => (typeof require !== "undefined" ? require : a)[b] | ||
}) : x)(function(x) { | ||
if (typeof require !== "undefined") return require.apply(this, arguments); | ||
throw Error('Dynamic require of "' + x + '" is not supported'); | ||
}); | ||
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 }); | ||
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); | ||
// packages/react/focus-scope/src/index.ts | ||
var src_exports = {}; | ||
__export(src_exports, { | ||
FocusScope: () => FocusScope, | ||
Root: () => Root | ||
}); | ||
module.exports = __toCommonJS(src_exports); | ||
// packages/react/focus-scope/src/FocusScope.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; | ||
} | ||
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 | ||
)); | ||
// packages/react/focus-scope/src/FocusScope.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 }); | ||
}).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); | ||
} | ||
}, 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 }); | ||
} | ||
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; | ||
}, | ||
[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 findVisible(elements, container) { | ||
for (const element of elements) { | ||
if (!isHidden(element, { upTo: container })) return element; | ||
} | ||
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 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; | ||
} | ||
function isSelectableInput(element) { | ||
return element instanceof HTMLInputElement && "select" in element; | ||
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(); | ||
} | ||
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(); | ||
} | ||
var focusScopesStack = createFocusScopesStack(); | ||
function createFocusScopesStack() { | ||
let stack = []; | ||
return { | ||
add(focusScope) { | ||
const activeFocusScope = stack[0]; | ||
if (focusScope !== activeFocusScope) { | ||
activeFocusScope?.pause(); | ||
} | ||
}; | ||
} | ||
function arrayRemove(array, item) { | ||
const updatedArray = [...array]; | ||
const index = updatedArray.indexOf(item); | ||
if (index !== -1) { | ||
updatedArray.splice(index, 1); | ||
stack = arrayRemove(stack, focusScope); | ||
stack.unshift(focusScope); | ||
}, | ||
remove(focusScope) { | ||
stack = arrayRemove(stack, focusScope); | ||
stack[0]?.resume(); | ||
} | ||
return updatedArray; | ||
}; | ||
} | ||
function arrayRemove(array, item) { | ||
const updatedArray = [...array]; | ||
const index = updatedArray.indexOf(item); | ||
if (index !== -1) { | ||
updatedArray.splice(index, 1); | ||
} | ||
function removeLinks(items) { | ||
return items.filter((item) => item.tagName !== "A"); | ||
} | ||
var Root = FocusScope; | ||
})(); | ||
return updatedArray; | ||
} | ||
function removeLinks(items) { | ||
return items.filter((item) => item.tagName !== "A"); | ||
} | ||
var Root = FocusScope; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@radix-ui/react-focus-scope", | ||
"version": "1.1.0-rc.2", | ||
"version": "1.1.0-rc.3", | ||
"license": "MIT", | ||
@@ -31,5 +31,5 @@ "exports": { | ||
"dependencies": { | ||
"@radix-ui/react-compose-refs": "1.1.0-rc.2", | ||
"@radix-ui/react-primitive": "1.1.0-rc.2", | ||
"@radix-ui/react-use-callback-ref": "1.1.0-rc.2" | ||
"@radix-ui/react-compose-refs": "1.1.0-rc.3", | ||
"@radix-ui/react-primitive": "1.1.0-rc.3", | ||
"@radix-ui/react-use-callback-ref": "1.1.0-rc.3" | ||
}, | ||
@@ -36,0 +36,0 @@ "peerDependencies": { |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
488
0
60583
+ Added@radix-ui/react-compose-refs@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-primitive@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-slot@1.1.0-rc.3(transitive)
+ Added@radix-ui/react-use-callback-ref@1.1.0-rc.3(transitive)
- Removed@radix-ui/react-compose-refs@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-primitive@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-slot@1.1.0-rc.2(transitive)
- Removed@radix-ui/react-use-callback-ref@1.1.0-rc.2(transitive)