@clayui/shared
Version:
ClayShared component
236 lines (235 loc) • 8.31 kB
JavaScript
;
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);
var useFocusManagement_exports = {};
__export(useFocusManagement_exports, {
FOCUSABLE_ELEMENTS: () => FOCUSABLE_ELEMENTS,
isFocusable: () => isFocusable,
useFocusManagement: () => useFocusManagement
});
module.exports = __toCommonJS(useFocusManagement_exports);
var import_react = __toESM(require("react"));
const HostComponent = 5;
let minimalTabIndex = 0;
function isFocusable({
contentEditable,
disabled,
href,
offsetParent,
rel,
tabIndex,
tagName,
type
}) {
tagName = tagName?.toLowerCase();
if (!offsetParent) {
return false;
}
if (disabled) {
return false;
}
if (tabIndex !== null && tabIndex !== void 0 && tabIndex < minimalTabIndex) {
return false;
}
if (tabIndex !== null && tabIndex !== void 0 && tabIndex >= minimalTabIndex || contentEditable === true || contentEditable === "true") {
return true;
}
if (tagName === "a" || tagName === "area") {
return !!href && rel !== "ignore";
}
if (tagName === "input") {
return type !== "file" && type !== "hidden";
}
return tagName === "button" || tagName === "embed" || tagName === "iframe" || tagName === "object" || tagName === "select" || tagName === "textarea";
}
const FOCUS_SCOPE_MARKERS = [
'span[data-focus-scope-end="true"]',
'span[data-focus-scope-start="true"]'
];
const FOCUSABLE_ELEMENTS = [
"a[href]",
"[contenteditable]",
'[tabindex]:not([tabindex^="-"])',
"area[href]",
"button:not([disabled])",
"embed",
"iframe",
'input:not([disabled]):not([type="hidden"])',
"object",
"select:not([disabled]):not([aria-hidden])",
"textarea:not([disabled]):not([aria-hidden])"
];
let hasSibling = false;
function collectDocumentFocusTargets() {
const focusTargets = [...FOCUSABLE_ELEMENTS, ...FOCUS_SCOPE_MARKERS];
return Array.from(
document.querySelectorAll(focusTargets.join(","))
).filter((element) => {
const isFocusScopeMarker = element.dataset["focusScopeEnd"] || element.dataset["focusScopeStart"];
if (isFocusable(element) || isFocusScopeMarker) {
return window.getComputedStyle(element).visibility !== "hidden";
}
return false;
});
}
function isFiberFocusable(fiber) {
const { memoizedProps, stateNode, type } = fiber;
if (memoizedProps === null) {
return false;
}
return isFocusable({
contentEditable: memoizedProps.contentEditable,
disabled: memoizedProps.disabled,
href: memoizedProps.href,
offsetParent: stateNode.offsetParent,
rel: memoizedProps.rel,
tabIndex: memoizedProps.tabIndex,
tagName: type,
type: memoizedProps.type
});
}
function isFiberFocusScopeMarker(fiber) {
return fiber.stateNode.dataset["focusScopeEnd"] || fiber.stateNode.dataset["focusScopeStart"];
}
function collectFocusTargets(node, focusTargets) {
const isFiberFocusTarget = node.tag === HostComponent && (isFiberFocusable(node) || isFiberFocusScopeMarker(node));
if (isFiberFocusTarget) {
focusTargets.push(node.stateNode);
}
const child = node.child;
if (child !== null) {
collectFocusTargets(child, focusTargets);
}
const sibling = node.sibling;
if (sibling) {
hasSibling = true;
collectFocusTargets(sibling, focusTargets);
}
}
function getFiber(scope) {
if (!scope.current) {
return null;
}
const internalKey = Object.keys(scope.current).find(
(key) => key.indexOf("__reactInternalInstance") === 0 || key.indexOf("__reactFiber") === 0
);
if (internalKey) {
return scope.current[internalKey];
}
return null;
}
function getFocusTargetsInScope(fiberNode) {
const focusTargets = [];
const { child } = fiberNode;
if (child !== null) {
collectFocusTargets(child, focusTargets);
}
return focusTargets;
}
function useFocusManagement(scope) {
const nextFocusInDocRef = import_react.default.useRef(null);
const prevFocusInDocRef = import_react.default.useRef(null);
const moveFocusInScope = (scope2, backwards = false, persistOnScope = false) => {
let fiberFocusTargets = getFocusTargetsInScope(
scope2.alternate ?? scope2
);
if (!hasSibling) {
fiberFocusTargets = getFocusTargetsInScope(scope2);
} else {
hasSibling = false;
}
if (!fiberFocusTargets.length) {
return null;
}
const activeElement = document.activeElement;
if (!activeElement) {
return;
}
const docFocusTargets = collectDocumentFocusTargets();
const docPosition = docFocusTargets.indexOf(activeElement);
const reactFiberPosition = fiberFocusTargets.indexOf(activeElement);
const startFocusTrap = fiberFocusTargets.find(
(element) => element.getAttribute("data-focus-scope-start") === "true"
);
const endFocusTrap = fiberFocusTargets.find(
(element) => element.getAttribute("data-focus-scope-end") === "true"
);
const nextFocusInDoc = docFocusTargets[docPosition + 1];
const prevFocusInDoc = docFocusTargets[docPosition - 1];
if (reactFiberPosition < 0 && !prevFocusInDocRef.current && !nextFocusInDocRef.current && nextFocusInDoc !== endFocusTrap && prevFocusInDoc !== startFocusTrap) {
return null;
}
let nextFocusInFiber = fiberFocusTargets[reactFiberPosition + 1];
let prevFocusInFiber = fiberFocusTargets[reactFiberPosition - 1];
if (startFocusTrap && endFocusTrap && startFocusTrap !== prevFocusInDoc && endFocusTrap !== nextFocusInDoc) {
return null;
}
if (endFocusTrap && endFocusTrap === nextFocusInDoc) {
nextFocusInFiber = docFocusTargets.find(
(_, index, array) => array[index - 1] === startFocusTrap
);
}
if (startFocusTrap && startFocusTrap === prevFocusInDoc) {
prevFocusInFiber = docFocusTargets.find(
(_, index, array) => array[index + 1] === endFocusTrap
);
}
if (persistOnScope && (!nextFocusInFiber || backwards && !prevFocusInFiber)) {
return null;
}
if (nextFocusInFiber !== nextFocusInDoc) {
nextFocusInDocRef.current = nextFocusInDoc;
}
if (prevFocusInFiber !== prevFocusInDoc) {
prevFocusInDocRef.current = prevFocusInDoc;
}
let nextActive = backwards ? prevFocusInFiber : nextFocusInFiber;
if (!nextActive) {
nextActive = backwards ? prevFocusInDocRef.current : nextFocusInDocRef.current;
}
if (nextActive) {
nextActive.focus();
if (nextActive === prevFocusInDocRef.current || nextActive === nextFocusInDocRef.current) {
nextFocusInDocRef.current = null;
prevFocusInDocRef.current = null;
}
return nextActive;
}
return null;
};
return {
focusFirst: () => {
minimalTabIndex = -1;
const next = moveFocusInScope(getFiber(scope), false, true);
minimalTabIndex = 0;
return next;
},
focusNext: (persistOnScope) => moveFocusInScope(getFiber(scope), false, persistOnScope),
focusPrevious: (persistOnScope) => moveFocusInScope(getFiber(scope), true, persistOnScope)
};
}