@y14e/roving-tabindex 3.1.11 → 3.1.13
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 +3 -3
- package/dist/index.bundle.cjs +93 -48
- package/dist/index.bundle.js +93 -48
- package/dist/index.cjs +36 -21
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +36 -21
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,11 +13,11 @@ npm i @y14e/roving-tabindex
|
|
|
13
13
|
import { createRovingTabIndex } from '@y14e/roving-tabindex';
|
|
14
14
|
|
|
15
15
|
// CDNs
|
|
16
|
-
import { createRovingTabIndex } from 'https://esm.sh/@y14e/roving-tabindex@3.1.
|
|
16
|
+
import { createRovingTabIndex } from 'https://esm.sh/@y14e/roving-tabindex@3.1.13';
|
|
17
17
|
// or
|
|
18
|
-
import { createRovingTabIndex } from 'https://cdn.jsdelivr.net/npm/@y14e/roving-tabindex@3.1.
|
|
18
|
+
import { createRovingTabIndex } from 'https://cdn.jsdelivr.net/npm/@y14e/roving-tabindex@3.1.13/+esm';
|
|
19
19
|
// or
|
|
20
|
-
import { createRovingTabIndex } from 'https://esm.unpkg.com/@y14e/roving-tabindex@3.1.
|
|
20
|
+
import { createRovingTabIndex } from 'https://esm.unpkg.com/@y14e/roving-tabindex@3.1.13';
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## 📦 APIs
|
package/dist/index.bundle.cjs
CHANGED
|
@@ -51,6 +51,10 @@ function saveAttributes(elements, attributes) {
|
|
|
51
51
|
|
|
52
52
|
// node_modules/power-focusable/dist/index.js
|
|
53
53
|
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"])`;
|
|
54
|
+
var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX = FOCUSABLE_SELECTOR.replace(
|
|
55
|
+
/(,\s*)?\[tabindex="-1"\]/g,
|
|
56
|
+
""
|
|
57
|
+
);
|
|
54
58
|
function getFocusables(container = document.body, options = {}) {
|
|
55
59
|
if (!(container instanceof Element)) {
|
|
56
60
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
@@ -90,21 +94,27 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
90
94
|
const elements = [];
|
|
91
95
|
if (composed || include) {
|
|
92
96
|
let traverse2 = function(node) {
|
|
93
|
-
if (
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
if (isFocusable(node, {
|
|
98
|
+
skipNegativeTabIndexCheck,
|
|
99
|
+
skipVisibilityCheck
|
|
100
|
+
}) || include?.(node)) {
|
|
97
101
|
elements[elements.length] = node;
|
|
98
102
|
}
|
|
99
|
-
const
|
|
100
|
-
for (let i = 0, l =
|
|
101
|
-
const child =
|
|
103
|
+
const children2 = composed ? getComposedChildren(node) : getChildren(node);
|
|
104
|
+
for (let i = 0, l = children2.length; i < l; i++) {
|
|
105
|
+
const child = children2[i];
|
|
102
106
|
child && traverse2(child);
|
|
103
107
|
}
|
|
104
108
|
};
|
|
105
|
-
|
|
109
|
+
const children = composed ? getComposedChildren(container) : getChildren(container);
|
|
110
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
111
|
+
const child = children[i];
|
|
112
|
+
child && traverse2(child);
|
|
113
|
+
}
|
|
106
114
|
} else {
|
|
107
|
-
const candidates = container.querySelectorAll(
|
|
115
|
+
const candidates = container.querySelectorAll(
|
|
116
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX : FOCUSABLE_SELECTOR
|
|
117
|
+
);
|
|
108
118
|
for (let i = 0, l = candidates.length; i < l; i++) {
|
|
109
119
|
const candidate = candidates[i];
|
|
110
120
|
if (candidate && isFocusable(candidate, {
|
|
@@ -115,8 +125,8 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
115
125
|
}
|
|
116
126
|
}
|
|
117
127
|
}
|
|
118
|
-
const
|
|
119
|
-
return
|
|
128
|
+
const filtered = filter ? elements.filter(filter) : elements;
|
|
129
|
+
return normalizeRadioGroup(sortByTabIndex(filtered));
|
|
120
130
|
}
|
|
121
131
|
function isFocusable(element, options = {}) {
|
|
122
132
|
if (!(element instanceof Element)) {
|
|
@@ -139,7 +149,7 @@ function isFocusable(element, options = {}) {
|
|
|
139
149
|
return false;
|
|
140
150
|
}
|
|
141
151
|
if (!element.matches(
|
|
142
|
-
skipNegativeTabIndexCheck ?
|
|
152
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX : FOCUSABLE_SELECTOR
|
|
143
153
|
)) {
|
|
144
154
|
return false;
|
|
145
155
|
}
|
|
@@ -185,7 +195,7 @@ function isDisabledDeep(element) {
|
|
|
185
195
|
return false;
|
|
186
196
|
}
|
|
187
197
|
function normalizeRadioGroup(elements) {
|
|
188
|
-
let
|
|
198
|
+
let rootMap = null;
|
|
189
199
|
for (let i = 0, l = elements.length; i < l; i++) {
|
|
190
200
|
const element = elements[i];
|
|
191
201
|
if (!(element instanceof HTMLInputElement)) {
|
|
@@ -194,25 +204,45 @@ function normalizeRadioGroup(elements) {
|
|
|
194
204
|
if (!isUngroupedRadio(element)) {
|
|
195
205
|
continue;
|
|
196
206
|
}
|
|
197
|
-
if (!
|
|
198
|
-
|
|
207
|
+
if (!rootMap) {
|
|
208
|
+
rootMap = /* @__PURE__ */ new Map();
|
|
199
209
|
}
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
if (
|
|
203
|
-
|
|
210
|
+
const root = element.getRootNode();
|
|
211
|
+
let formMap = rootMap.get(root);
|
|
212
|
+
if (!formMap) {
|
|
213
|
+
formMap = /* @__PURE__ */ new Map();
|
|
214
|
+
rootMap.set(root, formMap);
|
|
204
215
|
}
|
|
216
|
+
let nameMap = formMap.get(element.form);
|
|
217
|
+
if (!nameMap) {
|
|
218
|
+
nameMap = /* @__PURE__ */ new Map();
|
|
219
|
+
formMap.set(element.form, nameMap);
|
|
220
|
+
}
|
|
221
|
+
let group = nameMap.get(element.name);
|
|
222
|
+
if (!group) {
|
|
223
|
+
group = [];
|
|
224
|
+
nameMap.set(element.name, group);
|
|
225
|
+
}
|
|
226
|
+
group[group.length] = element;
|
|
205
227
|
}
|
|
206
|
-
if (!
|
|
228
|
+
if (!rootMap) {
|
|
207
229
|
return elements;
|
|
208
230
|
}
|
|
209
231
|
const placeholder = /* @__PURE__ */ new Set();
|
|
210
|
-
for (const
|
|
211
|
-
|
|
232
|
+
for (const formMap of rootMap.values()) {
|
|
233
|
+
for (const nameMap of formMap.values()) {
|
|
234
|
+
for (const group of nameMap.values()) {
|
|
235
|
+
const radio = group.find((element) => element.checked) ?? group[0];
|
|
236
|
+
radio && placeholder.add(radio);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
212
239
|
}
|
|
213
|
-
return elements.filter(
|
|
214
|
-
|
|
215
|
-
|
|
240
|
+
return elements.filter((element) => {
|
|
241
|
+
if (!(element instanceof HTMLInputElement)) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
return !isUngroupedRadio(element) || placeholder.has(element);
|
|
245
|
+
});
|
|
216
246
|
}
|
|
217
247
|
function sortByTabIndex(elements) {
|
|
218
248
|
const ordered = [];
|
|
@@ -284,7 +314,7 @@ function isInert(element) {
|
|
|
284
314
|
return "inert" in element && !!element.inert;
|
|
285
315
|
}
|
|
286
316
|
function isUngroupedRadio(element) {
|
|
287
|
-
return element
|
|
317
|
+
return element.type === "radio" && !!element.name;
|
|
288
318
|
}
|
|
289
319
|
|
|
290
320
|
// src/index.ts
|
|
@@ -294,14 +324,8 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
294
324
|
return () => {
|
|
295
325
|
};
|
|
296
326
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
return () => roving.destroy();
|
|
300
|
-
} catch (error) {
|
|
301
|
-
error instanceof Error && console.warn(error.message || error);
|
|
302
|
-
return () => {
|
|
303
|
-
};
|
|
304
|
-
}
|
|
327
|
+
const roving = new RovingTabIndex(container, options);
|
|
328
|
+
return () => roving.destroy();
|
|
305
329
|
}
|
|
306
330
|
var RovingTabIndex = class _RovingTabIndex {
|
|
307
331
|
static #initialized = /* @__PURE__ */ new Set();
|
|
@@ -339,9 +363,18 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
339
363
|
console.warn("Invalid noStart option. Fallback: false.");
|
|
340
364
|
noStart = false;
|
|
341
365
|
}
|
|
342
|
-
if (selector !== ""
|
|
343
|
-
|
|
344
|
-
|
|
366
|
+
if (selector !== "") {
|
|
367
|
+
if (typeof selector !== "string" || !selector.trim()) {
|
|
368
|
+
console.warn("Invalid selector. Fallback: no selector string.");
|
|
369
|
+
selector = "";
|
|
370
|
+
} else {
|
|
371
|
+
try {
|
|
372
|
+
container.querySelector(selector);
|
|
373
|
+
} catch {
|
|
374
|
+
console.warn("Invalid selector. Fallback: no selector string.");
|
|
375
|
+
selector = "";
|
|
376
|
+
}
|
|
377
|
+
}
|
|
345
378
|
}
|
|
346
379
|
if (typeof typeahead !== "boolean") {
|
|
347
380
|
console.warn("Invalid typeahead option. Fallback: false.");
|
|
@@ -370,7 +403,10 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
370
403
|
this.#isDestroyed = true;
|
|
371
404
|
this.#controller?.abort();
|
|
372
405
|
this.#controller = null;
|
|
373
|
-
|
|
406
|
+
this.#focusables.forEach((focusable) => {
|
|
407
|
+
_RovingTabIndex.#initialized.delete(focusable);
|
|
408
|
+
restoreAttributes([focusable]);
|
|
409
|
+
});
|
|
374
410
|
this.#focusables.clear();
|
|
375
411
|
this.#focusablesByFirstChar.clear();
|
|
376
412
|
}
|
|
@@ -423,7 +459,9 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
423
459
|
if (!(active instanceof Element)) {
|
|
424
460
|
return;
|
|
425
461
|
}
|
|
426
|
-
const current = this.#getFocusables()
|
|
462
|
+
const current = this.#getFocusables().filter(
|
|
463
|
+
(focusable2) => this.#focusables.has(focusable2)
|
|
464
|
+
);
|
|
427
465
|
if (!current.includes(active)) {
|
|
428
466
|
return;
|
|
429
467
|
}
|
|
@@ -451,7 +489,10 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
451
489
|
break;
|
|
452
490
|
}
|
|
453
491
|
default: {
|
|
454
|
-
|
|
492
|
+
const focusables = new Set(
|
|
493
|
+
this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
|
|
494
|
+
);
|
|
495
|
+
target = current.filter((focusable2) => focusables.has(focusable2));
|
|
455
496
|
const foundIndex = target.findIndex(
|
|
456
497
|
(focusable2) => current.indexOf(focusable2) > currentIndex
|
|
457
498
|
);
|
|
@@ -465,12 +506,16 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
465
506
|
const current = new Set(this.#getFocusables());
|
|
466
507
|
for (const focusable of this.#focusables) {
|
|
467
508
|
if (!current.has(focusable)) {
|
|
468
|
-
|
|
509
|
+
_RovingTabIndex.#initialized.delete(focusable);
|
|
510
|
+
restoreAttributes([focusable]);
|
|
469
511
|
this.#focusables.delete(focusable);
|
|
470
|
-
this.#focusablesByFirstChar
|
|
512
|
+
for (const [key, focusables] of this.#focusablesByFirstChar) {
|
|
471
513
|
const index = focusables.indexOf(focusable);
|
|
472
|
-
index >= 0
|
|
473
|
-
|
|
514
|
+
if (index >= 0) {
|
|
515
|
+
focusables.splice(index, 1);
|
|
516
|
+
!focusables.length && this.#focusablesByFirstChar.delete(key);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
474
519
|
}
|
|
475
520
|
}
|
|
476
521
|
const { navigationOnly, noStart, typeahead } = this.#settings;
|
|
@@ -479,7 +524,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
479
524
|
continue;
|
|
480
525
|
}
|
|
481
526
|
if (_RovingTabIndex.#initialized.has(focusable)) {
|
|
482
|
-
|
|
527
|
+
continue;
|
|
483
528
|
}
|
|
484
529
|
this.#focusables.add(focusable);
|
|
485
530
|
_RovingTabIndex.#initialized.add(focusable);
|
|
@@ -522,7 +567,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
522
567
|
}
|
|
523
568
|
#createSelectorFilter() {
|
|
524
569
|
const { selector } = this.#settings;
|
|
525
|
-
return (element) => !selector ||
|
|
570
|
+
return (element) => !selector || element.matches(selector);
|
|
526
571
|
}
|
|
527
572
|
#getFocusables() {
|
|
528
573
|
return getFocusables(this.#container, {
|
|
@@ -538,7 +583,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
538
583
|
* Lightweight roving tabindex utility with fully focus management.
|
|
539
584
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
540
585
|
*
|
|
541
|
-
* @version 3.1.
|
|
586
|
+
* @version 3.1.13
|
|
542
587
|
* @author Yusuke Kamiyamane
|
|
543
588
|
* @license MIT
|
|
544
589
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -563,7 +608,7 @@ power-focusable/dist/index.js:
|
|
|
563
608
|
* High-precision focus management utility with full composed tree support.
|
|
564
609
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
565
610
|
*
|
|
566
|
-
* @version 4.3.
|
|
611
|
+
* @version 4.3.12
|
|
567
612
|
* @author Yusuke Kamiyamane
|
|
568
613
|
* @license MIT
|
|
569
614
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.bundle.js
CHANGED
|
@@ -49,6 +49,10 @@ function saveAttributes(elements, attributes) {
|
|
|
49
49
|
|
|
50
50
|
// node_modules/power-focusable/dist/index.js
|
|
51
51
|
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"])`;
|
|
52
|
+
var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX = FOCUSABLE_SELECTOR.replace(
|
|
53
|
+
/(,\s*)?\[tabindex="-1"\]/g,
|
|
54
|
+
""
|
|
55
|
+
);
|
|
52
56
|
function getFocusables(container = document.body, options = {}) {
|
|
53
57
|
if (!(container instanceof Element)) {
|
|
54
58
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
@@ -88,21 +92,27 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
88
92
|
const elements = [];
|
|
89
93
|
if (composed || include) {
|
|
90
94
|
let traverse2 = function(node) {
|
|
91
|
-
if (
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
if (isFocusable(node, {
|
|
96
|
+
skipNegativeTabIndexCheck,
|
|
97
|
+
skipVisibilityCheck
|
|
98
|
+
}) || include?.(node)) {
|
|
95
99
|
elements[elements.length] = node;
|
|
96
100
|
}
|
|
97
|
-
const
|
|
98
|
-
for (let i = 0, l =
|
|
99
|
-
const child =
|
|
101
|
+
const children2 = composed ? getComposedChildren(node) : getChildren(node);
|
|
102
|
+
for (let i = 0, l = children2.length; i < l; i++) {
|
|
103
|
+
const child = children2[i];
|
|
100
104
|
child && traverse2(child);
|
|
101
105
|
}
|
|
102
106
|
};
|
|
103
|
-
|
|
107
|
+
const children = composed ? getComposedChildren(container) : getChildren(container);
|
|
108
|
+
for (let i = 0, l = children.length; i < l; i++) {
|
|
109
|
+
const child = children[i];
|
|
110
|
+
child && traverse2(child);
|
|
111
|
+
}
|
|
104
112
|
} else {
|
|
105
|
-
const candidates = container.querySelectorAll(
|
|
113
|
+
const candidates = container.querySelectorAll(
|
|
114
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX : FOCUSABLE_SELECTOR
|
|
115
|
+
);
|
|
106
116
|
for (let i = 0, l = candidates.length; i < l; i++) {
|
|
107
117
|
const candidate = candidates[i];
|
|
108
118
|
if (candidate && isFocusable(candidate, {
|
|
@@ -113,8 +123,8 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
113
123
|
}
|
|
114
124
|
}
|
|
115
125
|
}
|
|
116
|
-
const
|
|
117
|
-
return
|
|
126
|
+
const filtered = filter ? elements.filter(filter) : elements;
|
|
127
|
+
return normalizeRadioGroup(sortByTabIndex(filtered));
|
|
118
128
|
}
|
|
119
129
|
function isFocusable(element, options = {}) {
|
|
120
130
|
if (!(element instanceof Element)) {
|
|
@@ -137,7 +147,7 @@ function isFocusable(element, options = {}) {
|
|
|
137
147
|
return false;
|
|
138
148
|
}
|
|
139
149
|
if (!element.matches(
|
|
140
|
-
skipNegativeTabIndexCheck ?
|
|
150
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TAB_INDEX : FOCUSABLE_SELECTOR
|
|
141
151
|
)) {
|
|
142
152
|
return false;
|
|
143
153
|
}
|
|
@@ -183,7 +193,7 @@ function isDisabledDeep(element) {
|
|
|
183
193
|
return false;
|
|
184
194
|
}
|
|
185
195
|
function normalizeRadioGroup(elements) {
|
|
186
|
-
let
|
|
196
|
+
let rootMap = null;
|
|
187
197
|
for (let i = 0, l = elements.length; i < l; i++) {
|
|
188
198
|
const element = elements[i];
|
|
189
199
|
if (!(element instanceof HTMLInputElement)) {
|
|
@@ -192,25 +202,45 @@ function normalizeRadioGroup(elements) {
|
|
|
192
202
|
if (!isUngroupedRadio(element)) {
|
|
193
203
|
continue;
|
|
194
204
|
}
|
|
195
|
-
if (!
|
|
196
|
-
|
|
205
|
+
if (!rootMap) {
|
|
206
|
+
rootMap = /* @__PURE__ */ new Map();
|
|
197
207
|
}
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
if (
|
|
201
|
-
|
|
208
|
+
const root = element.getRootNode();
|
|
209
|
+
let formMap = rootMap.get(root);
|
|
210
|
+
if (!formMap) {
|
|
211
|
+
formMap = /* @__PURE__ */ new Map();
|
|
212
|
+
rootMap.set(root, formMap);
|
|
202
213
|
}
|
|
214
|
+
let nameMap = formMap.get(element.form);
|
|
215
|
+
if (!nameMap) {
|
|
216
|
+
nameMap = /* @__PURE__ */ new Map();
|
|
217
|
+
formMap.set(element.form, nameMap);
|
|
218
|
+
}
|
|
219
|
+
let group = nameMap.get(element.name);
|
|
220
|
+
if (!group) {
|
|
221
|
+
group = [];
|
|
222
|
+
nameMap.set(element.name, group);
|
|
223
|
+
}
|
|
224
|
+
group[group.length] = element;
|
|
203
225
|
}
|
|
204
|
-
if (!
|
|
226
|
+
if (!rootMap) {
|
|
205
227
|
return elements;
|
|
206
228
|
}
|
|
207
229
|
const placeholder = /* @__PURE__ */ new Set();
|
|
208
|
-
for (const
|
|
209
|
-
|
|
230
|
+
for (const formMap of rootMap.values()) {
|
|
231
|
+
for (const nameMap of formMap.values()) {
|
|
232
|
+
for (const group of nameMap.values()) {
|
|
233
|
+
const radio = group.find((element) => element.checked) ?? group[0];
|
|
234
|
+
radio && placeholder.add(radio);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
210
237
|
}
|
|
211
|
-
return elements.filter(
|
|
212
|
-
|
|
213
|
-
|
|
238
|
+
return elements.filter((element) => {
|
|
239
|
+
if (!(element instanceof HTMLInputElement)) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
return !isUngroupedRadio(element) || placeholder.has(element);
|
|
243
|
+
});
|
|
214
244
|
}
|
|
215
245
|
function sortByTabIndex(elements) {
|
|
216
246
|
const ordered = [];
|
|
@@ -282,7 +312,7 @@ function isInert(element) {
|
|
|
282
312
|
return "inert" in element && !!element.inert;
|
|
283
313
|
}
|
|
284
314
|
function isUngroupedRadio(element) {
|
|
285
|
-
return element
|
|
315
|
+
return element.type === "radio" && !!element.name;
|
|
286
316
|
}
|
|
287
317
|
|
|
288
318
|
// src/index.ts
|
|
@@ -292,14 +322,8 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
292
322
|
return () => {
|
|
293
323
|
};
|
|
294
324
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
return () => roving.destroy();
|
|
298
|
-
} catch (error) {
|
|
299
|
-
error instanceof Error && console.warn(error.message || error);
|
|
300
|
-
return () => {
|
|
301
|
-
};
|
|
302
|
-
}
|
|
325
|
+
const roving = new RovingTabIndex(container, options);
|
|
326
|
+
return () => roving.destroy();
|
|
303
327
|
}
|
|
304
328
|
var RovingTabIndex = class _RovingTabIndex {
|
|
305
329
|
static #initialized = /* @__PURE__ */ new Set();
|
|
@@ -337,9 +361,18 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
337
361
|
console.warn("Invalid noStart option. Fallback: false.");
|
|
338
362
|
noStart = false;
|
|
339
363
|
}
|
|
340
|
-
if (selector !== ""
|
|
341
|
-
|
|
342
|
-
|
|
364
|
+
if (selector !== "") {
|
|
365
|
+
if (typeof selector !== "string" || !selector.trim()) {
|
|
366
|
+
console.warn("Invalid selector. Fallback: no selector string.");
|
|
367
|
+
selector = "";
|
|
368
|
+
} else {
|
|
369
|
+
try {
|
|
370
|
+
container.querySelector(selector);
|
|
371
|
+
} catch {
|
|
372
|
+
console.warn("Invalid selector. Fallback: no selector string.");
|
|
373
|
+
selector = "";
|
|
374
|
+
}
|
|
375
|
+
}
|
|
343
376
|
}
|
|
344
377
|
if (typeof typeahead !== "boolean") {
|
|
345
378
|
console.warn("Invalid typeahead option. Fallback: false.");
|
|
@@ -368,7 +401,10 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
368
401
|
this.#isDestroyed = true;
|
|
369
402
|
this.#controller?.abort();
|
|
370
403
|
this.#controller = null;
|
|
371
|
-
|
|
404
|
+
this.#focusables.forEach((focusable) => {
|
|
405
|
+
_RovingTabIndex.#initialized.delete(focusable);
|
|
406
|
+
restoreAttributes([focusable]);
|
|
407
|
+
});
|
|
372
408
|
this.#focusables.clear();
|
|
373
409
|
this.#focusablesByFirstChar.clear();
|
|
374
410
|
}
|
|
@@ -421,7 +457,9 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
421
457
|
if (!(active instanceof Element)) {
|
|
422
458
|
return;
|
|
423
459
|
}
|
|
424
|
-
const current = this.#getFocusables()
|
|
460
|
+
const current = this.#getFocusables().filter(
|
|
461
|
+
(focusable2) => this.#focusables.has(focusable2)
|
|
462
|
+
);
|
|
425
463
|
if (!current.includes(active)) {
|
|
426
464
|
return;
|
|
427
465
|
}
|
|
@@ -449,7 +487,10 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
449
487
|
break;
|
|
450
488
|
}
|
|
451
489
|
default: {
|
|
452
|
-
|
|
490
|
+
const focusables = new Set(
|
|
491
|
+
this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
|
|
492
|
+
);
|
|
493
|
+
target = current.filter((focusable2) => focusables.has(focusable2));
|
|
453
494
|
const foundIndex = target.findIndex(
|
|
454
495
|
(focusable2) => current.indexOf(focusable2) > currentIndex
|
|
455
496
|
);
|
|
@@ -463,12 +504,16 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
463
504
|
const current = new Set(this.#getFocusables());
|
|
464
505
|
for (const focusable of this.#focusables) {
|
|
465
506
|
if (!current.has(focusable)) {
|
|
466
|
-
|
|
507
|
+
_RovingTabIndex.#initialized.delete(focusable);
|
|
508
|
+
restoreAttributes([focusable]);
|
|
467
509
|
this.#focusables.delete(focusable);
|
|
468
|
-
this.#focusablesByFirstChar
|
|
510
|
+
for (const [key, focusables] of this.#focusablesByFirstChar) {
|
|
469
511
|
const index = focusables.indexOf(focusable);
|
|
470
|
-
index >= 0
|
|
471
|
-
|
|
512
|
+
if (index >= 0) {
|
|
513
|
+
focusables.splice(index, 1);
|
|
514
|
+
!focusables.length && this.#focusablesByFirstChar.delete(key);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
472
517
|
}
|
|
473
518
|
}
|
|
474
519
|
const { navigationOnly, noStart, typeahead } = this.#settings;
|
|
@@ -477,7 +522,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
477
522
|
continue;
|
|
478
523
|
}
|
|
479
524
|
if (_RovingTabIndex.#initialized.has(focusable)) {
|
|
480
|
-
|
|
525
|
+
continue;
|
|
481
526
|
}
|
|
482
527
|
this.#focusables.add(focusable);
|
|
483
528
|
_RovingTabIndex.#initialized.add(focusable);
|
|
@@ -520,7 +565,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
520
565
|
}
|
|
521
566
|
#createSelectorFilter() {
|
|
522
567
|
const { selector } = this.#settings;
|
|
523
|
-
return (element) => !selector ||
|
|
568
|
+
return (element) => !selector || element.matches(selector);
|
|
524
569
|
}
|
|
525
570
|
#getFocusables() {
|
|
526
571
|
return getFocusables(this.#container, {
|
|
@@ -536,7 +581,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
536
581
|
* Lightweight roving tabindex utility with fully focus management.
|
|
537
582
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
538
583
|
*
|
|
539
|
-
* @version 3.1.
|
|
584
|
+
* @version 3.1.13
|
|
540
585
|
* @author Yusuke Kamiyamane
|
|
541
586
|
* @license MIT
|
|
542
587
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -561,7 +606,7 @@ power-focusable/dist/index.js:
|
|
|
561
606
|
* High-precision focus management utility with full composed tree support.
|
|
562
607
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
563
608
|
*
|
|
564
|
-
* @version 4.3.
|
|
609
|
+
* @version 4.3.12
|
|
565
610
|
* @author Yusuke Kamiyamane
|
|
566
611
|
* @license MIT
|
|
567
612
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.cjs
CHANGED
|
@@ -10,14 +10,8 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
10
10
|
return () => {
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
return () => roving.destroy();
|
|
16
|
-
} catch (error) {
|
|
17
|
-
error instanceof Error && console.warn(error.message || error);
|
|
18
|
-
return () => {
|
|
19
|
-
};
|
|
20
|
-
}
|
|
13
|
+
const roving = new RovingTabIndex(container, options);
|
|
14
|
+
return () => roving.destroy();
|
|
21
15
|
}
|
|
22
16
|
var RovingTabIndex = class _RovingTabIndex {
|
|
23
17
|
static #initialized = /* @__PURE__ */ new Set();
|
|
@@ -55,9 +49,18 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
55
49
|
console.warn("Invalid noStart option. Fallback: false.");
|
|
56
50
|
noStart = false;
|
|
57
51
|
}
|
|
58
|
-
if (selector !== ""
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
if (selector !== "") {
|
|
53
|
+
if (typeof selector !== "string" || !selector.trim()) {
|
|
54
|
+
console.warn("Invalid selector. Fallback: no selector string.");
|
|
55
|
+
selector = "";
|
|
56
|
+
} else {
|
|
57
|
+
try {
|
|
58
|
+
container.querySelector(selector);
|
|
59
|
+
} catch {
|
|
60
|
+
console.warn("Invalid selector. Fallback: no selector string.");
|
|
61
|
+
selector = "";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
61
64
|
}
|
|
62
65
|
if (typeof typeahead !== "boolean") {
|
|
63
66
|
console.warn("Invalid typeahead option. Fallback: false.");
|
|
@@ -86,7 +89,10 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
86
89
|
this.#isDestroyed = true;
|
|
87
90
|
this.#controller?.abort();
|
|
88
91
|
this.#controller = null;
|
|
89
|
-
|
|
92
|
+
this.#focusables.forEach((focusable) => {
|
|
93
|
+
_RovingTabIndex.#initialized.delete(focusable);
|
|
94
|
+
attributesUtils.restoreAttributes([focusable]);
|
|
95
|
+
});
|
|
90
96
|
this.#focusables.clear();
|
|
91
97
|
this.#focusablesByFirstChar.clear();
|
|
92
98
|
}
|
|
@@ -139,7 +145,9 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
139
145
|
if (!(active instanceof Element)) {
|
|
140
146
|
return;
|
|
141
147
|
}
|
|
142
|
-
const current = this.#getFocusables()
|
|
148
|
+
const current = this.#getFocusables().filter(
|
|
149
|
+
(focusable2) => this.#focusables.has(focusable2)
|
|
150
|
+
);
|
|
143
151
|
if (!current.includes(active)) {
|
|
144
152
|
return;
|
|
145
153
|
}
|
|
@@ -167,7 +175,10 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
167
175
|
break;
|
|
168
176
|
}
|
|
169
177
|
default: {
|
|
170
|
-
|
|
178
|
+
const focusables = new Set(
|
|
179
|
+
this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
|
|
180
|
+
);
|
|
181
|
+
target = current.filter((focusable2) => focusables.has(focusable2));
|
|
171
182
|
const foundIndex = target.findIndex(
|
|
172
183
|
(focusable2) => current.indexOf(focusable2) > currentIndex
|
|
173
184
|
);
|
|
@@ -181,12 +192,16 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
181
192
|
const current = new Set(this.#getFocusables());
|
|
182
193
|
for (const focusable of this.#focusables) {
|
|
183
194
|
if (!current.has(focusable)) {
|
|
184
|
-
|
|
195
|
+
_RovingTabIndex.#initialized.delete(focusable);
|
|
196
|
+
attributesUtils.restoreAttributes([focusable]);
|
|
185
197
|
this.#focusables.delete(focusable);
|
|
186
|
-
this.#focusablesByFirstChar
|
|
198
|
+
for (const [key, focusables] of this.#focusablesByFirstChar) {
|
|
187
199
|
const index = focusables.indexOf(focusable);
|
|
188
|
-
index >= 0
|
|
189
|
-
|
|
200
|
+
if (index >= 0) {
|
|
201
|
+
focusables.splice(index, 1);
|
|
202
|
+
!focusables.length && this.#focusablesByFirstChar.delete(key);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
190
205
|
}
|
|
191
206
|
}
|
|
192
207
|
const { navigationOnly, noStart, typeahead } = this.#settings;
|
|
@@ -195,7 +210,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
195
210
|
continue;
|
|
196
211
|
}
|
|
197
212
|
if (_RovingTabIndex.#initialized.has(focusable)) {
|
|
198
|
-
|
|
213
|
+
continue;
|
|
199
214
|
}
|
|
200
215
|
this.#focusables.add(focusable);
|
|
201
216
|
_RovingTabIndex.#initialized.add(focusable);
|
|
@@ -238,7 +253,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
238
253
|
}
|
|
239
254
|
#createSelectorFilter() {
|
|
240
255
|
const { selector } = this.#settings;
|
|
241
|
-
return (element) => !selector ||
|
|
256
|
+
return (element) => !selector || element.matches(selector);
|
|
242
257
|
}
|
|
243
258
|
#getFocusables() {
|
|
244
259
|
return powerFocusable.getFocusables(this.#container, {
|
|
@@ -254,7 +269,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
254
269
|
* Lightweight roving tabindex utility with fully focus management.
|
|
255
270
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
256
271
|
*
|
|
257
|
-
* @version 3.1.
|
|
272
|
+
* @version 3.1.13
|
|
258
273
|
* @author Yusuke Kamiyamane
|
|
259
274
|
* @license MIT
|
|
260
275
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Lightweight roving tabindex utility with fully focus management.
|
|
4
4
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
5
5
|
*
|
|
6
|
-
* @version 3.1.
|
|
6
|
+
* @version 3.1.13
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Lightweight roving tabindex utility with fully focus management.
|
|
4
4
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
5
5
|
*
|
|
6
|
-
* @version 3.1.
|
|
6
|
+
* @version 3.1.13
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.js
CHANGED
|
@@ -8,14 +8,8 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
8
8
|
return () => {
|
|
9
9
|
};
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return () => roving.destroy();
|
|
14
|
-
} catch (error) {
|
|
15
|
-
error instanceof Error && console.warn(error.message || error);
|
|
16
|
-
return () => {
|
|
17
|
-
};
|
|
18
|
-
}
|
|
11
|
+
const roving = new RovingTabIndex(container, options);
|
|
12
|
+
return () => roving.destroy();
|
|
19
13
|
}
|
|
20
14
|
var RovingTabIndex = class _RovingTabIndex {
|
|
21
15
|
static #initialized = /* @__PURE__ */ new Set();
|
|
@@ -53,9 +47,18 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
53
47
|
console.warn("Invalid noStart option. Fallback: false.");
|
|
54
48
|
noStart = false;
|
|
55
49
|
}
|
|
56
|
-
if (selector !== ""
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
if (selector !== "") {
|
|
51
|
+
if (typeof selector !== "string" || !selector.trim()) {
|
|
52
|
+
console.warn("Invalid selector. Fallback: no selector string.");
|
|
53
|
+
selector = "";
|
|
54
|
+
} else {
|
|
55
|
+
try {
|
|
56
|
+
container.querySelector(selector);
|
|
57
|
+
} catch {
|
|
58
|
+
console.warn("Invalid selector. Fallback: no selector string.");
|
|
59
|
+
selector = "";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
59
62
|
}
|
|
60
63
|
if (typeof typeahead !== "boolean") {
|
|
61
64
|
console.warn("Invalid typeahead option. Fallback: false.");
|
|
@@ -84,7 +87,10 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
84
87
|
this.#isDestroyed = true;
|
|
85
88
|
this.#controller?.abort();
|
|
86
89
|
this.#controller = null;
|
|
87
|
-
|
|
90
|
+
this.#focusables.forEach((focusable) => {
|
|
91
|
+
_RovingTabIndex.#initialized.delete(focusable);
|
|
92
|
+
restoreAttributes([focusable]);
|
|
93
|
+
});
|
|
88
94
|
this.#focusables.clear();
|
|
89
95
|
this.#focusablesByFirstChar.clear();
|
|
90
96
|
}
|
|
@@ -137,7 +143,9 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
137
143
|
if (!(active instanceof Element)) {
|
|
138
144
|
return;
|
|
139
145
|
}
|
|
140
|
-
const current = this.#getFocusables()
|
|
146
|
+
const current = this.#getFocusables().filter(
|
|
147
|
+
(focusable2) => this.#focusables.has(focusable2)
|
|
148
|
+
);
|
|
141
149
|
if (!current.includes(active)) {
|
|
142
150
|
return;
|
|
143
151
|
}
|
|
@@ -165,7 +173,10 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
165
173
|
break;
|
|
166
174
|
}
|
|
167
175
|
default: {
|
|
168
|
-
|
|
176
|
+
const focusables = new Set(
|
|
177
|
+
this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
|
|
178
|
+
);
|
|
179
|
+
target = current.filter((focusable2) => focusables.has(focusable2));
|
|
169
180
|
const foundIndex = target.findIndex(
|
|
170
181
|
(focusable2) => current.indexOf(focusable2) > currentIndex
|
|
171
182
|
);
|
|
@@ -179,12 +190,16 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
179
190
|
const current = new Set(this.#getFocusables());
|
|
180
191
|
for (const focusable of this.#focusables) {
|
|
181
192
|
if (!current.has(focusable)) {
|
|
182
|
-
|
|
193
|
+
_RovingTabIndex.#initialized.delete(focusable);
|
|
194
|
+
restoreAttributes([focusable]);
|
|
183
195
|
this.#focusables.delete(focusable);
|
|
184
|
-
this.#focusablesByFirstChar
|
|
196
|
+
for (const [key, focusables] of this.#focusablesByFirstChar) {
|
|
185
197
|
const index = focusables.indexOf(focusable);
|
|
186
|
-
index >= 0
|
|
187
|
-
|
|
198
|
+
if (index >= 0) {
|
|
199
|
+
focusables.splice(index, 1);
|
|
200
|
+
!focusables.length && this.#focusablesByFirstChar.delete(key);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
188
203
|
}
|
|
189
204
|
}
|
|
190
205
|
const { navigationOnly, noStart, typeahead } = this.#settings;
|
|
@@ -193,7 +208,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
193
208
|
continue;
|
|
194
209
|
}
|
|
195
210
|
if (_RovingTabIndex.#initialized.has(focusable)) {
|
|
196
|
-
|
|
211
|
+
continue;
|
|
197
212
|
}
|
|
198
213
|
this.#focusables.add(focusable);
|
|
199
214
|
_RovingTabIndex.#initialized.add(focusable);
|
|
@@ -236,7 +251,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
236
251
|
}
|
|
237
252
|
#createSelectorFilter() {
|
|
238
253
|
const { selector } = this.#settings;
|
|
239
|
-
return (element) => !selector ||
|
|
254
|
+
return (element) => !selector || element.matches(selector);
|
|
240
255
|
}
|
|
241
256
|
#getFocusables() {
|
|
242
257
|
return getFocusables(this.#container, {
|
|
@@ -252,7 +267,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
252
267
|
* Lightweight roving tabindex utility with fully focus management.
|
|
253
268
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
254
269
|
*
|
|
255
|
-
* @version 3.1.
|
|
270
|
+
* @version 3.1.13
|
|
256
271
|
* @author Yusuke Kamiyamane
|
|
257
272
|
* @license MIT
|
|
258
273
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y14e/roving-tabindex",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.13",
|
|
4
4
|
"description": "Lightweight roving tabindex utility with fully focus management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -57,6 +57,6 @@
|
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"@y14e/attributes-utils": "^1.1.3",
|
|
60
|
-
"power-focusable": "^4.3.
|
|
60
|
+
"power-focusable": "^4.3.12"
|
|
61
61
|
}
|
|
62
62
|
}
|