power-focusable 4.3.10 → 4.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/dist/index.cjs +75 -54
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +75 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,25 +24,27 @@ import {
|
|
|
24
24
|
} from 'power-focusable';
|
|
25
25
|
|
|
26
26
|
// CDNs
|
|
27
|
-
import { ... } 'https://esm.sh/power-focusable@4.3.
|
|
27
|
+
import { ... } 'https://esm.sh/power-focusable@4.3.12';
|
|
28
28
|
// or
|
|
29
|
-
import { ... } 'https://cdn.jsdelivr.net/npm/power-focusable@4.3.
|
|
29
|
+
import { ... } 'https://cdn.jsdelivr.net/npm/power-focusable@4.3.12/+esm';
|
|
30
30
|
// or
|
|
31
|
-
import { ... } 'https://esm.unpkg.com/power-focusable@4.3.
|
|
31
|
+
import { ... } 'https://esm.unpkg.com/power-focusable@4.3.12';
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## 🪄 Options
|
|
35
35
|
|
|
36
36
|
```ts
|
|
37
37
|
interface PowerFocusableOptions {
|
|
38
|
-
anchor: Element | null; // default:
|
|
38
|
+
anchor: Element | null; // default: DocumentOrShadowRoot.activeElement
|
|
39
39
|
composed: boolean; // default: false
|
|
40
|
-
filter:
|
|
41
|
-
include:
|
|
40
|
+
filter: PowerFocusableFunction; // default: undefined
|
|
41
|
+
include: PowerFocusableFunction; // default: undefined
|
|
42
42
|
skipNegativeTabIndexCheck: boolean; // default: false
|
|
43
43
|
skipVisibilityCheck: boolean; // default: false
|
|
44
44
|
wrap: boolean; // default: false
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
type PowerFocusableFunction = ((element: Element) => boolean) | undefined;
|
|
46
48
|
```
|
|
47
49
|
|
|
48
50
|
### `anchor`
|
package/dist/index.cjs
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
var FOCUSABLE_SELECTOR = `:is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])`;
|
|
5
|
+
var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX = FOCUSABLE_SELECTOR.replace(
|
|
6
|
+
/(,\s*)?\[tabindex="-1"\]/g,
|
|
7
|
+
""
|
|
8
|
+
);
|
|
5
9
|
function createFocusTrap(container = document.body) {
|
|
6
10
|
if (!(container instanceof Element)) {
|
|
7
11
|
console.warn("Invalid container element");
|
|
@@ -95,21 +99,27 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
95
99
|
const elements = [];
|
|
96
100
|
if (composed || include) {
|
|
97
101
|
let traverse2 = function(node) {
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
if (isFocusable(node, {
|
|
103
|
+
skipNegativeTabIndexCheck,
|
|
104
|
+
skipVisibilityCheck
|
|
105
|
+
}) || include?.(node)) {
|
|
102
106
|
elements[elements.length] = node;
|
|
103
107
|
}
|
|
104
|
-
const
|
|
105
|
-
for (let i = 0, l =
|
|
106
|
-
const child =
|
|
108
|
+
const children2 = composed ? getComposedChildren(node) : getChildren(node);
|
|
109
|
+
for (let i = 0, l = children2.length; i < l; i++) {
|
|
110
|
+
const child = children2[i];
|
|
107
111
|
child && traverse2(child);
|
|
108
112
|
}
|
|
109
113
|
};
|
|
110
|
-
|
|
114
|
+
const children = composed ? getComposedChildren(container) : getChildren(container);
|
|
115
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
116
|
+
const child = children[i];
|
|
117
|
+
child && traverse2(child);
|
|
118
|
+
}
|
|
111
119
|
} else {
|
|
112
|
-
const candidates = container.querySelectorAll(
|
|
120
|
+
const candidates = container.querySelectorAll(
|
|
121
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX : FOCUSABLE_SELECTOR
|
|
122
|
+
);
|
|
113
123
|
for (let i = 0, l = candidates.length; i < l; i++) {
|
|
114
124
|
const candidate = candidates[i];
|
|
115
125
|
if (candidate && isFocusable(candidate, {
|
|
@@ -120,8 +130,8 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
120
130
|
}
|
|
121
131
|
}
|
|
122
132
|
}
|
|
123
|
-
const
|
|
124
|
-
return
|
|
133
|
+
const filtered = filter ? elements.filter(filter) : elements;
|
|
134
|
+
return normalizeRadioGroup(sortByTabIndex(filtered));
|
|
125
135
|
}
|
|
126
136
|
function getNextFocusable(container = document.body, options = {}) {
|
|
127
137
|
return getRelativeFocusable(container, 1, options);
|
|
@@ -176,7 +186,7 @@ function isFocusable(element, options = {}) {
|
|
|
176
186
|
return false;
|
|
177
187
|
}
|
|
178
188
|
if (!element.matches(
|
|
179
|
-
skipNegativeTabIndexCheck ?
|
|
189
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX : FOCUSABLE_SELECTOR
|
|
180
190
|
)) {
|
|
181
191
|
return false;
|
|
182
192
|
}
|
|
@@ -248,9 +258,13 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
248
258
|
console.warn("Invalid wrap option. Fallback: false.");
|
|
249
259
|
wrap = false;
|
|
250
260
|
}
|
|
251
|
-
const settings = {
|
|
252
|
-
|
|
253
|
-
|
|
261
|
+
const settings = {
|
|
262
|
+
composed,
|
|
263
|
+
filter,
|
|
264
|
+
include,
|
|
265
|
+
skipNegativeTabIndexCheck,
|
|
266
|
+
skipVisibilityCheck
|
|
267
|
+
};
|
|
254
268
|
const focusables = getFocusables(container, settings);
|
|
255
269
|
const { length } = focusables;
|
|
256
270
|
if (!length) {
|
|
@@ -296,7 +310,7 @@ function isDisabledDeep(element) {
|
|
|
296
310
|
return false;
|
|
297
311
|
}
|
|
298
312
|
function normalizeRadioGroup(elements) {
|
|
299
|
-
let
|
|
313
|
+
let rootMap = null;
|
|
300
314
|
for (let i = 0, l = elements.length; i < l; i++) {
|
|
301
315
|
const element = elements[i];
|
|
302
316
|
if (!(element instanceof HTMLInputElement)) {
|
|
@@ -305,25 +319,45 @@ function normalizeRadioGroup(elements) {
|
|
|
305
319
|
if (!isUngroupedRadio(element)) {
|
|
306
320
|
continue;
|
|
307
321
|
}
|
|
308
|
-
if (!
|
|
309
|
-
|
|
322
|
+
if (!rootMap) {
|
|
323
|
+
rootMap = /* @__PURE__ */ new Map();
|
|
310
324
|
}
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
if (
|
|
314
|
-
|
|
325
|
+
const root = element.getRootNode();
|
|
326
|
+
let formMap = rootMap.get(root);
|
|
327
|
+
if (!formMap) {
|
|
328
|
+
formMap = /* @__PURE__ */ new Map();
|
|
329
|
+
rootMap.set(root, formMap);
|
|
315
330
|
}
|
|
331
|
+
let nameMap = formMap.get(element.form);
|
|
332
|
+
if (!nameMap) {
|
|
333
|
+
nameMap = /* @__PURE__ */ new Map();
|
|
334
|
+
formMap.set(element.form, nameMap);
|
|
335
|
+
}
|
|
336
|
+
let group = nameMap.get(element.name);
|
|
337
|
+
if (!group) {
|
|
338
|
+
group = [];
|
|
339
|
+
nameMap.set(element.name, group);
|
|
340
|
+
}
|
|
341
|
+
group[group.length] = element;
|
|
316
342
|
}
|
|
317
|
-
if (!
|
|
343
|
+
if (!rootMap) {
|
|
318
344
|
return elements;
|
|
319
345
|
}
|
|
320
346
|
const placeholder = /* @__PURE__ */ new Set();
|
|
321
|
-
for (const
|
|
322
|
-
|
|
347
|
+
for (const formMap of rootMap.values()) {
|
|
348
|
+
for (const nameMap of formMap.values()) {
|
|
349
|
+
for (const group of nameMap.values()) {
|
|
350
|
+
const radio = group.find((element) => element.checked) ?? group[0];
|
|
351
|
+
radio && placeholder.add(radio);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
323
354
|
}
|
|
324
|
-
return elements.filter(
|
|
325
|
-
|
|
326
|
-
|
|
355
|
+
return elements.filter((element) => {
|
|
356
|
+
if (!(element instanceof HTMLInputElement)) {
|
|
357
|
+
return true;
|
|
358
|
+
}
|
|
359
|
+
return !isUngroupedRadio(element) || placeholder.has(element);
|
|
360
|
+
});
|
|
327
361
|
}
|
|
328
362
|
function sortByTabIndex(elements) {
|
|
329
363
|
const ordered = [];
|
|
@@ -384,19 +418,19 @@ function getComposedParent(node) {
|
|
|
384
418
|
}
|
|
385
419
|
}
|
|
386
420
|
function getComposedSiblings(node) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
421
|
+
const parent = getComposedParent(node);
|
|
422
|
+
if (!parent) {
|
|
423
|
+
return [];
|
|
424
|
+
}
|
|
425
|
+
const siblings = parent instanceof HTMLSlotElement ? parent.assignedElements({ flatten: true }) : getComposedChildren(parent);
|
|
426
|
+
const filtered = [];
|
|
427
|
+
for (let i = 0, l = siblings.length; i < l; i++) {
|
|
428
|
+
const sibling = siblings[i];
|
|
429
|
+
if (sibling && sibling !== node) {
|
|
430
|
+
filtered[filtered.length] = sibling;
|
|
395
431
|
}
|
|
396
|
-
return filtered;
|
|
397
|
-
} else {
|
|
398
|
-
return getComposedParent(node) ? getSiblings(node) : [];
|
|
399
432
|
}
|
|
433
|
+
return filtered;
|
|
400
434
|
}
|
|
401
435
|
var inertRefCounts = /* @__PURE__ */ new WeakMap();
|
|
402
436
|
function applyInert(element) {
|
|
@@ -438,19 +472,6 @@ function getChildren(node) {
|
|
|
438
472
|
}
|
|
439
473
|
return elements;
|
|
440
474
|
}
|
|
441
|
-
function getSiblings(node) {
|
|
442
|
-
const parent = getComposedParent(node);
|
|
443
|
-
if (!parent) {
|
|
444
|
-
return [];
|
|
445
|
-
}
|
|
446
|
-
const elements = [];
|
|
447
|
-
for (let child = parent.firstElementChild; child; child = child.nextElementSibling) {
|
|
448
|
-
if (child !== node) {
|
|
449
|
-
elements[elements.length] = child;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
return elements;
|
|
453
|
-
}
|
|
454
475
|
function getTabIndex(element) {
|
|
455
476
|
return "tabIndex" in element ? Number(element.tabIndex) : 0;
|
|
456
477
|
}
|
|
@@ -465,14 +486,14 @@ function isInert(element) {
|
|
|
465
486
|
return "inert" in element && !!element.inert;
|
|
466
487
|
}
|
|
467
488
|
function isUngroupedRadio(element) {
|
|
468
|
-
return element
|
|
489
|
+
return element.type === "radio" && !!element.name;
|
|
469
490
|
}
|
|
470
491
|
/**
|
|
471
492
|
* Power Focusable
|
|
472
493
|
* High-precision focus management utility with full composed tree support.
|
|
473
494
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
474
495
|
*
|
|
475
|
-
* @version 4.3.
|
|
496
|
+
* @version 4.3.12
|
|
476
497
|
* @author Yusuke Kamiyamane
|
|
477
498
|
* @license MIT
|
|
478
499
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* High-precision focus management utility with full composed tree support.
|
|
4
4
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
5
5
|
*
|
|
6
|
-
* @version 4.3.
|
|
6
|
+
* @version 4.3.12
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
interface PowerFocusableOptions {
|
|
13
13
|
anchor: Element | null;
|
|
14
14
|
composed: boolean;
|
|
15
|
-
filter:
|
|
16
|
-
include:
|
|
15
|
+
filter: PowerFocusableFunction;
|
|
16
|
+
include: PowerFocusableFunction;
|
|
17
17
|
skipNegativeTabIndexCheck: boolean;
|
|
18
18
|
skipVisibilityCheck: boolean;
|
|
19
19
|
wrap: boolean;
|
|
20
20
|
}
|
|
21
|
+
type PowerFocusableFunction = ((element: Element) => boolean) | undefined;
|
|
21
22
|
declare function createFocusTrap(container?: Element): () => void;
|
|
22
23
|
declare function getFocusables(container?: Element, options?: Partial<Omit<PowerFocusableOptions, 'anchor' | 'wrap'>>): Element[];
|
|
23
24
|
declare function getNextFocusable(container?: Element, options?: Partial<PowerFocusableOptions>): Element | null;
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* High-precision focus management utility with full composed tree support.
|
|
4
4
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
5
5
|
*
|
|
6
|
-
* @version 4.3.
|
|
6
|
+
* @version 4.3.12
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
interface PowerFocusableOptions {
|
|
13
13
|
anchor: Element | null;
|
|
14
14
|
composed: boolean;
|
|
15
|
-
filter:
|
|
16
|
-
include:
|
|
15
|
+
filter: PowerFocusableFunction;
|
|
16
|
+
include: PowerFocusableFunction;
|
|
17
17
|
skipNegativeTabIndexCheck: boolean;
|
|
18
18
|
skipVisibilityCheck: boolean;
|
|
19
19
|
wrap: boolean;
|
|
20
20
|
}
|
|
21
|
+
type PowerFocusableFunction = ((element: Element) => boolean) | undefined;
|
|
21
22
|
declare function createFocusTrap(container?: Element): () => void;
|
|
22
23
|
declare function getFocusables(container?: Element, options?: Partial<Omit<PowerFocusableOptions, 'anchor' | 'wrap'>>): Element[];
|
|
23
24
|
declare function getNextFocusable(container?: Element, options?: Partial<PowerFocusableOptions>): Element | null;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
var FOCUSABLE_SELECTOR = `:is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])`;
|
|
3
|
+
var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX = FOCUSABLE_SELECTOR.replace(
|
|
4
|
+
/(,\s*)?\[tabindex="-1"\]/g,
|
|
5
|
+
""
|
|
6
|
+
);
|
|
3
7
|
function createFocusTrap(container = document.body) {
|
|
4
8
|
if (!(container instanceof Element)) {
|
|
5
9
|
console.warn("Invalid container element");
|
|
@@ -93,21 +97,27 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
93
97
|
const elements = [];
|
|
94
98
|
if (composed || include) {
|
|
95
99
|
let traverse2 = function(node) {
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
if (isFocusable(node, {
|
|
101
|
+
skipNegativeTabIndexCheck,
|
|
102
|
+
skipVisibilityCheck
|
|
103
|
+
}) || include?.(node)) {
|
|
100
104
|
elements[elements.length] = node;
|
|
101
105
|
}
|
|
102
|
-
const
|
|
103
|
-
for (let i = 0, l =
|
|
104
|
-
const child =
|
|
106
|
+
const children2 = composed ? getComposedChildren(node) : getChildren(node);
|
|
107
|
+
for (let i = 0, l = children2.length; i < l; i++) {
|
|
108
|
+
const child = children2[i];
|
|
105
109
|
child && traverse2(child);
|
|
106
110
|
}
|
|
107
111
|
};
|
|
108
|
-
|
|
112
|
+
const children = composed ? getComposedChildren(container) : getChildren(container);
|
|
113
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
114
|
+
const child = children[i];
|
|
115
|
+
child && traverse2(child);
|
|
116
|
+
}
|
|
109
117
|
} else {
|
|
110
|
-
const candidates = container.querySelectorAll(
|
|
118
|
+
const candidates = container.querySelectorAll(
|
|
119
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX : FOCUSABLE_SELECTOR
|
|
120
|
+
);
|
|
111
121
|
for (let i = 0, l = candidates.length; i < l; i++) {
|
|
112
122
|
const candidate = candidates[i];
|
|
113
123
|
if (candidate && isFocusable(candidate, {
|
|
@@ -118,8 +128,8 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
118
128
|
}
|
|
119
129
|
}
|
|
120
130
|
}
|
|
121
|
-
const
|
|
122
|
-
return
|
|
131
|
+
const filtered = filter ? elements.filter(filter) : elements;
|
|
132
|
+
return normalizeRadioGroup(sortByTabIndex(filtered));
|
|
123
133
|
}
|
|
124
134
|
function getNextFocusable(container = document.body, options = {}) {
|
|
125
135
|
return getRelativeFocusable(container, 1, options);
|
|
@@ -174,7 +184,7 @@ function isFocusable(element, options = {}) {
|
|
|
174
184
|
return false;
|
|
175
185
|
}
|
|
176
186
|
if (!element.matches(
|
|
177
|
-
skipNegativeTabIndexCheck ?
|
|
187
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX : FOCUSABLE_SELECTOR
|
|
178
188
|
)) {
|
|
179
189
|
return false;
|
|
180
190
|
}
|
|
@@ -246,9 +256,13 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
246
256
|
console.warn("Invalid wrap option. Fallback: false.");
|
|
247
257
|
wrap = false;
|
|
248
258
|
}
|
|
249
|
-
const settings = {
|
|
250
|
-
|
|
251
|
-
|
|
259
|
+
const settings = {
|
|
260
|
+
composed,
|
|
261
|
+
filter,
|
|
262
|
+
include,
|
|
263
|
+
skipNegativeTabIndexCheck,
|
|
264
|
+
skipVisibilityCheck
|
|
265
|
+
};
|
|
252
266
|
const focusables = getFocusables(container, settings);
|
|
253
267
|
const { length } = focusables;
|
|
254
268
|
if (!length) {
|
|
@@ -294,7 +308,7 @@ function isDisabledDeep(element) {
|
|
|
294
308
|
return false;
|
|
295
309
|
}
|
|
296
310
|
function normalizeRadioGroup(elements) {
|
|
297
|
-
let
|
|
311
|
+
let rootMap = null;
|
|
298
312
|
for (let i = 0, l = elements.length; i < l; i++) {
|
|
299
313
|
const element = elements[i];
|
|
300
314
|
if (!(element instanceof HTMLInputElement)) {
|
|
@@ -303,25 +317,45 @@ function normalizeRadioGroup(elements) {
|
|
|
303
317
|
if (!isUngroupedRadio(element)) {
|
|
304
318
|
continue;
|
|
305
319
|
}
|
|
306
|
-
if (!
|
|
307
|
-
|
|
320
|
+
if (!rootMap) {
|
|
321
|
+
rootMap = /* @__PURE__ */ new Map();
|
|
308
322
|
}
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
if (
|
|
312
|
-
|
|
323
|
+
const root = element.getRootNode();
|
|
324
|
+
let formMap = rootMap.get(root);
|
|
325
|
+
if (!formMap) {
|
|
326
|
+
formMap = /* @__PURE__ */ new Map();
|
|
327
|
+
rootMap.set(root, formMap);
|
|
313
328
|
}
|
|
329
|
+
let nameMap = formMap.get(element.form);
|
|
330
|
+
if (!nameMap) {
|
|
331
|
+
nameMap = /* @__PURE__ */ new Map();
|
|
332
|
+
formMap.set(element.form, nameMap);
|
|
333
|
+
}
|
|
334
|
+
let group = nameMap.get(element.name);
|
|
335
|
+
if (!group) {
|
|
336
|
+
group = [];
|
|
337
|
+
nameMap.set(element.name, group);
|
|
338
|
+
}
|
|
339
|
+
group[group.length] = element;
|
|
314
340
|
}
|
|
315
|
-
if (!
|
|
341
|
+
if (!rootMap) {
|
|
316
342
|
return elements;
|
|
317
343
|
}
|
|
318
344
|
const placeholder = /* @__PURE__ */ new Set();
|
|
319
|
-
for (const
|
|
320
|
-
|
|
345
|
+
for (const formMap of rootMap.values()) {
|
|
346
|
+
for (const nameMap of formMap.values()) {
|
|
347
|
+
for (const group of nameMap.values()) {
|
|
348
|
+
const radio = group.find((element) => element.checked) ?? group[0];
|
|
349
|
+
radio && placeholder.add(radio);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
321
352
|
}
|
|
322
|
-
return elements.filter(
|
|
323
|
-
|
|
324
|
-
|
|
353
|
+
return elements.filter((element) => {
|
|
354
|
+
if (!(element instanceof HTMLInputElement)) {
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
return !isUngroupedRadio(element) || placeholder.has(element);
|
|
358
|
+
});
|
|
325
359
|
}
|
|
326
360
|
function sortByTabIndex(elements) {
|
|
327
361
|
const ordered = [];
|
|
@@ -382,19 +416,19 @@ function getComposedParent(node) {
|
|
|
382
416
|
}
|
|
383
417
|
}
|
|
384
418
|
function getComposedSiblings(node) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
419
|
+
const parent = getComposedParent(node);
|
|
420
|
+
if (!parent) {
|
|
421
|
+
return [];
|
|
422
|
+
}
|
|
423
|
+
const siblings = parent instanceof HTMLSlotElement ? parent.assignedElements({ flatten: true }) : getComposedChildren(parent);
|
|
424
|
+
const filtered = [];
|
|
425
|
+
for (let i = 0, l = siblings.length; i < l; i++) {
|
|
426
|
+
const sibling = siblings[i];
|
|
427
|
+
if (sibling && sibling !== node) {
|
|
428
|
+
filtered[filtered.length] = sibling;
|
|
393
429
|
}
|
|
394
|
-
return filtered;
|
|
395
|
-
} else {
|
|
396
|
-
return getComposedParent(node) ? getSiblings(node) : [];
|
|
397
430
|
}
|
|
431
|
+
return filtered;
|
|
398
432
|
}
|
|
399
433
|
var inertRefCounts = /* @__PURE__ */ new WeakMap();
|
|
400
434
|
function applyInert(element) {
|
|
@@ -436,19 +470,6 @@ function getChildren(node) {
|
|
|
436
470
|
}
|
|
437
471
|
return elements;
|
|
438
472
|
}
|
|
439
|
-
function getSiblings(node) {
|
|
440
|
-
const parent = getComposedParent(node);
|
|
441
|
-
if (!parent) {
|
|
442
|
-
return [];
|
|
443
|
-
}
|
|
444
|
-
const elements = [];
|
|
445
|
-
for (let child = parent.firstElementChild; child; child = child.nextElementSibling) {
|
|
446
|
-
if (child !== node) {
|
|
447
|
-
elements[elements.length] = child;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
return elements;
|
|
451
|
-
}
|
|
452
473
|
function getTabIndex(element) {
|
|
453
474
|
return "tabIndex" in element ? Number(element.tabIndex) : 0;
|
|
454
475
|
}
|
|
@@ -463,14 +484,14 @@ function isInert(element) {
|
|
|
463
484
|
return "inert" in element && !!element.inert;
|
|
464
485
|
}
|
|
465
486
|
function isUngroupedRadio(element) {
|
|
466
|
-
return element
|
|
487
|
+
return element.type === "radio" && !!element.name;
|
|
467
488
|
}
|
|
468
489
|
/**
|
|
469
490
|
* Power Focusable
|
|
470
491
|
* High-precision focus management utility with full composed tree support.
|
|
471
492
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
472
493
|
*
|
|
473
|
-
* @version 4.3.
|
|
494
|
+
* @version 4.3.12
|
|
474
495
|
* @author Yusuke Kamiyamane
|
|
475
496
|
* @license MIT
|
|
476
497
|
* @copyright Copyright (c) Yusuke Kamiyamane
|