@studiometa/js-toolkit
Version:
A set of useful little bits of JavaScript to boost your project! 🚀
58 lines (57 loc) • 1.77 kB
JavaScript
import { keyCodes } from "./keyCodes.js";
import { isFunction } from "./is.js";
const FOCUSABLE_ELEMENTS = [
'a[href]:not([tabindex^="-"]):not([inert])',
'area[href]:not([tabindex^="-"]):not([inert])',
"input:not([disabled]):not([inert])",
"select:not([disabled]):not([inert])",
"textarea:not([disabled]):not([inert])",
"button:not([disabled]):not([inert])",
'iframe:not([tabindex^="-"]):not([inert])',
'audio:not([tabindex^="-"]):not([inert])',
'video:not([tabindex^="-"]):not([inert])',
'[contenteditable]:not([tabindex^="-"]):not([inert])',
'[tabindex]:not([tabindex^="-"]):not([inert])'
];
let focusedBefore;
function saveActiveElement() {
focusedBefore = document.activeElement;
}
function trapFocus(element, event) {
if (event.keyCode !== keyCodes.TAB) {
return;
}
if (!focusedBefore) {
focusedBefore = document.activeElement;
}
const focusableChildren = Array.from(
element.querySelectorAll(FOCUSABLE_ELEMENTS.join(", "))
);
const focusedItemIndex = document.activeElement instanceof HTMLElement ? focusableChildren.indexOf(document.activeElement) : -1;
if (!focusableChildren.length) {
return;
}
if (focusedItemIndex < 0) {
focusableChildren[0].focus();
event.preventDefault();
}
if (event.shiftKey && focusedItemIndex === 0) {
focusableChildren.at(-1).focus();
event.preventDefault();
} else if (!event.shiftKey && focusedItemIndex === focusableChildren.length - 1) {
focusableChildren[0].focus();
event.preventDefault();
}
}
function untrapFocus() {
if (focusedBefore && isFunction(focusedBefore.focus)) {
focusedBefore.focus();
focusedBefore = null;
}
}
export {
saveActiveElement,
trapFocus,
untrapFocus
};
//# sourceMappingURL=trapFocus.js.map