@adyen/adyen-platform-experience-web
Version:

120 lines (119 loc) • 3.98 kB
JavaScript
import { some as h } from "../../../utils/collection/main.js";
import { isUndefined as R, isNullish as N, isNumber as m } from "../../../utils/value/is.js";
import { mod as x } from "../../../utils/value/number.js";
const k = `:scope ${`
a[href],
audio[controls],
video[controls],
button,
input,
select,
textarea,
[contenteditable],
[tabindex]
`.replace(/\s+/g, "")}`, I = ["contenteditable", "controls", "disabled", "hidden", "href", "inert", "tabindex"], p = /* @__PURE__ */ new Map(), E = (t) => t.tagName === "INPUT", T = (t) => E(t) && t.type === "radio", A = (t) => {
const e = t.name, n = t.form, r = p.get(n);
let c = r?.get(e);
return R(c) && n && (c = n.querySelector(`:scope input[type=radio][name='${e}']:checked`) || null, p.set(n, (r || /* @__PURE__ */ new Map()).set(e, c))), c === t;
}, g = (t = document) => {
let e = t.activeElement;
for (; e && e.shadowRoot && e.shadowRoot.activeElement; )
e = e.shadowRoot.activeElement;
return e;
}, w = (t = document.body, e) => {
if (R(t))
return !1;
if (N(e)) {
const r = g();
return !!r && w(t, r);
}
let n = e.parentNode;
for (; n; ) {
if (n === t)
return !0;
n = n instanceof ShadowRoot ? n.host : n?.parentNode || null;
}
return !1;
}, C = (t) => !// [TODO]: Include all of these checks
// (1) matches focusable elements selector
// (2) is disabled element
// (3) is inert or inert subtree child
// (4) is hidden input
// (5) with visibility: hidden
// (6) is summary of open details element
// (7) is details with summary element
// (8) is disabled fieldset subtree child
/* (1) */
(!t.matches(k) || /* (2) */
t?.disabled || /* (3) */
/^(true)?$/.test(t.getAttribute("inert")) || /* (4) */
E(t) && t.hidden), b = (t) => !(T(t) && !A(t) || // (1) is not checked radio button
t?.tabIndex < 0 || // (2) has negative tabindex
!C(t)), L = () => {
const t = new MutationObserver((o) => v(o) && l()), e = [];
let n = -1, r = null;
const c = (o) => {
if (o < 0) return;
const s = Math.min(o, e.length - 1);
n !== s && (n = s), e[n]?.focus();
}, l = () => {
if (e.length = 0, !r) return;
const o = {
attributeFilter: I,
attributes: !0,
childList: !0,
subtree: !0
};
t.observe(r, o);
const s = (i) => {
const a = document.createTreeWalker(i, NodeFilter.SHOW_ELEMENT, {
acceptNode: () => NodeFilter.FILTER_ACCEPT
});
let u = a.nextNode();
for (; u; ) {
const d = u;
b(d) && e.push(d), d.shadowRoot && (t.observe(d.shadowRoot, o), s(d.shadowRoot)), u = a.nextNode();
}
};
s(r), w(r) && (f.current = g());
}, v = (o) => {
let s = !1;
for (const i of o)
if (i.type === "attributes" ? s ||= i.target instanceof Element && // Target is a tabbable element (possibly due to attribute changes)
// For example, disabled set to false, tabindex set to a number, etc.
(b(i.target) || // Target is already contained in the list of tabbables
// Attribute changes could make it no longer tabbable (e.g. disabled set to true)
e.includes(i.target)) : s ||= // At least one element was added or removed from the DOM tree of the root element
h(i.addedNodes, (a) => a instanceof Element) || h(i.removedNodes, (a) => a instanceof Element), s) break;
return s;
}, f = Object.create(null, {
current: {
get: () => e[n] ?? null,
set: (o) => {
if (o) {
if (!m(o))
return c(e.indexOf(o));
if (o === ~~o)
return c(x(n + o, e.length));
}
}
},
root: {
get: () => r,
set: (o) => {
o !== r && (r && t.disconnect(), r = o instanceof Element ? o : null, l());
}
},
tabbables: { value: e }
});
return f;
};
export {
k as SELECTORS,
L as default,
w as focusIsWithin,
g as getDeepActiveElement,
C as isFocusable,
b as isTabbable,
L as withTabbableRoot
};