@y14e/roving-tabindex 3.1.0 → 3.1.2
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 +4 -4
- package/dist/index.bundle.cjs +10 -132
- package/dist/index.bundle.js +10 -132
- package/dist/index.cjs +10 -37
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +11 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,14 +10,14 @@ npm i @y14e/roving-tabindex
|
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
12
|
// npm
|
|
13
|
-
import { createRovingTabIndex } from '@y14e/roving-tabindex@3.1.
|
|
13
|
+
import { createRovingTabIndex } from '@y14e/roving-tabindex@3.1.2';
|
|
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.2';
|
|
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.2/+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.2';
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## 📦 APIs
|
package/dist/index.bundle.cjs
CHANGED
|
@@ -118,12 +118,6 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
118
118
|
const unfiltered = normalizeRadioGroup(sortByTabIndex(elements));
|
|
119
119
|
return filter ? unfiltered.filter(filter) : unfiltered;
|
|
120
120
|
}
|
|
121
|
-
function getNextFocusable(container = document.body, options = {}) {
|
|
122
|
-
return getRelativeFocusable(container, 1, options);
|
|
123
|
-
}
|
|
124
|
-
function getPreviousFocusable(container = document.body, options = {}) {
|
|
125
|
-
return getRelativeFocusable(container, -1, options);
|
|
126
|
-
}
|
|
127
121
|
function isFocusable(element, options = {}) {
|
|
128
122
|
if (!(element instanceof Element)) {
|
|
129
123
|
console.warn("Invalid element");
|
|
@@ -161,84 +155,6 @@ function isFocusable(element, options = {}) {
|
|
|
161
155
|
}
|
|
162
156
|
return true;
|
|
163
157
|
}
|
|
164
|
-
function getRelativeFocusable(container, offset, options) {
|
|
165
|
-
if (!(container instanceof Element)) {
|
|
166
|
-
console.warn("Invalid container element. Fallback: <body> element.");
|
|
167
|
-
container = document.body;
|
|
168
|
-
}
|
|
169
|
-
let {
|
|
170
|
-
anchor = getActiveElement(),
|
|
171
|
-
composed = false,
|
|
172
|
-
filter,
|
|
173
|
-
include,
|
|
174
|
-
skipNegativeTabIndexCheck = false,
|
|
175
|
-
skipVisibilityCheck = false,
|
|
176
|
-
wrap = false
|
|
177
|
-
} = options;
|
|
178
|
-
if (!(anchor instanceof Element)) {
|
|
179
|
-
const active = getActiveElement();
|
|
180
|
-
if (active instanceof Element) {
|
|
181
|
-
console.warn("Invalid anchor element. Fallback: active element.");
|
|
182
|
-
anchor = active;
|
|
183
|
-
} else {
|
|
184
|
-
console.warn("Invalid anchor element");
|
|
185
|
-
return null;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
if (!containsComposed(container, anchor)) {
|
|
189
|
-
console.warn("Anchor (active) element not within container");
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
if (typeof composed !== "boolean") {
|
|
193
|
-
console.warn("Invalid composed option. Fallback: false.");
|
|
194
|
-
composed = false;
|
|
195
|
-
}
|
|
196
|
-
if (typeof filter !== "undefined" && typeof filter !== "function") {
|
|
197
|
-
console.warn(
|
|
198
|
-
"Invalid filter function. Fallback: no filter function (undefined)."
|
|
199
|
-
);
|
|
200
|
-
filter = void 0;
|
|
201
|
-
}
|
|
202
|
-
if (typeof include !== "undefined" && typeof include !== "function") {
|
|
203
|
-
console.warn(
|
|
204
|
-
"Invalid include function. Fallback: no include function (undefined)."
|
|
205
|
-
);
|
|
206
|
-
include = void 0;
|
|
207
|
-
}
|
|
208
|
-
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
209
|
-
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
210
|
-
skipNegativeTabIndexCheck = false;
|
|
211
|
-
}
|
|
212
|
-
if (typeof skipVisibilityCheck !== "boolean") {
|
|
213
|
-
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
214
|
-
skipVisibilityCheck = false;
|
|
215
|
-
}
|
|
216
|
-
if (typeof wrap !== "boolean") {
|
|
217
|
-
console.warn("Invalid wrap option. Fallback: false.");
|
|
218
|
-
wrap = false;
|
|
219
|
-
}
|
|
220
|
-
const settings = { composed, skipNegativeTabIndexCheck, skipVisibilityCheck };
|
|
221
|
-
if (filter !== void 0) {
|
|
222
|
-
Object.assign(settings, { filter });
|
|
223
|
-
}
|
|
224
|
-
if (include !== void 0) {
|
|
225
|
-
Object.assign(settings, { include });
|
|
226
|
-
}
|
|
227
|
-
const focusables = getFocusables(container, settings);
|
|
228
|
-
const { length } = focusables;
|
|
229
|
-
if (!length) {
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
const currentIndex = focusables.indexOf(anchor);
|
|
233
|
-
if (currentIndex === -1) {
|
|
234
|
-
return null;
|
|
235
|
-
}
|
|
236
|
-
const offsetIndex = currentIndex + offset;
|
|
237
|
-
if ((offsetIndex < 0 || offsetIndex >= length) && !wrap) {
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
return focusables[(offsetIndex + length) % length] ?? null;
|
|
241
|
-
}
|
|
242
158
|
function isDisabledDeep(element) {
|
|
243
159
|
let current = element;
|
|
244
160
|
while (current) {
|
|
@@ -319,17 +235,6 @@ function sortByTabIndex(elements) {
|
|
|
319
235
|
}
|
|
320
236
|
return sorted;
|
|
321
237
|
}
|
|
322
|
-
function containsComposed(container, element) {
|
|
323
|
-
let current = element;
|
|
324
|
-
while (current) {
|
|
325
|
-
if (current === container) {
|
|
326
|
-
return true;
|
|
327
|
-
} else {
|
|
328
|
-
current = current instanceof ShadowRoot ? current.mode === "open" ? current.host : null : current.parentNode;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
238
|
function getComposedChildren(node) {
|
|
334
239
|
if (node instanceof ShadowRoot) {
|
|
335
240
|
return getChildren(node);
|
|
@@ -478,18 +383,9 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
478
383
|
}
|
|
479
384
|
this.#controller = new AbortController();
|
|
480
385
|
const { signal } = this.#controller;
|
|
481
|
-
document.addEventListener("focusin", this.#onFocusIn, {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
});
|
|
485
|
-
this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, {
|
|
486
|
-
capture: true,
|
|
487
|
-
signal
|
|
488
|
-
});
|
|
489
|
-
this.#container.addEventListener("keydown", this.#onKeyDown, {
|
|
490
|
-
capture: true,
|
|
491
|
-
signal
|
|
492
|
-
});
|
|
386
|
+
document.addEventListener("focusin", this.#onFocusIn, { signal });
|
|
387
|
+
this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, { signal });
|
|
388
|
+
this.#container.addEventListener("keydown", this.#onKeyDown, { signal });
|
|
493
389
|
}
|
|
494
390
|
#onFocusIn = (event) => {
|
|
495
391
|
const { target } = event;
|
|
@@ -506,14 +402,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
506
402
|
};
|
|
507
403
|
#onKeyDown = (event) => {
|
|
508
404
|
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
509
|
-
if (
|
|
405
|
+
if (altKey || ctrlKey || metaKey || shiftKey) {
|
|
510
406
|
return;
|
|
511
407
|
}
|
|
512
408
|
const { direction, typeahead, wrap } = this.#settings;
|
|
513
409
|
const isBoth = !direction;
|
|
514
410
|
const isHorizontal = direction === "horizontal";
|
|
515
411
|
if (![
|
|
516
|
-
"Tab",
|
|
517
412
|
"End",
|
|
518
413
|
"Home",
|
|
519
414
|
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
@@ -531,14 +426,11 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
531
426
|
if (!current.includes(active)) {
|
|
532
427
|
return;
|
|
533
428
|
}
|
|
534
|
-
|
|
429
|
+
event.preventDefault();
|
|
535
430
|
const currentIndex = current.indexOf(active);
|
|
536
|
-
let newIndex
|
|
431
|
+
let newIndex;
|
|
537
432
|
let target = current;
|
|
538
433
|
switch (key) {
|
|
539
|
-
case "Tab":
|
|
540
|
-
shouldPrevent = this.#moveFocus(shiftKey ? "previous" : "next");
|
|
541
|
-
break;
|
|
542
434
|
case "End":
|
|
543
435
|
newIndex = -1;
|
|
544
436
|
break;
|
|
@@ -560,16 +452,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
560
452
|
default: {
|
|
561
453
|
target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
|
|
562
454
|
const foundIndex = target.findIndex(
|
|
563
|
-
(
|
|
455
|
+
(focusable2) => current.indexOf(focusable2) > currentIndex
|
|
564
456
|
);
|
|
565
457
|
newIndex = foundIndex >= 0 ? foundIndex : 0;
|
|
566
458
|
}
|
|
567
459
|
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
const focusable = target.at(newIndex);
|
|
571
|
-
focusable && focusElement(focusable);
|
|
572
|
-
}
|
|
460
|
+
const focusable = target.at(newIndex);
|
|
461
|
+
focusable && focusElement(focusable);
|
|
573
462
|
};
|
|
574
463
|
#update(active) {
|
|
575
464
|
const current = new Set(this.#getFocusables());
|
|
@@ -642,24 +531,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
642
531
|
skipVisibilityCheck: true
|
|
643
532
|
});
|
|
644
533
|
}
|
|
645
|
-
#moveFocus(direction) {
|
|
646
|
-
const options = {
|
|
647
|
-
composed: true
|
|
648
|
-
};
|
|
649
|
-
const focusable = direction === "previous" ? getPreviousFocusable(document.body, options) : getNextFocusable(document.body, options);
|
|
650
|
-
if (focusable) {
|
|
651
|
-
focusElement(focusable);
|
|
652
|
-
return true;
|
|
653
|
-
}
|
|
654
|
-
return false;
|
|
655
|
-
}
|
|
656
534
|
};
|
|
657
535
|
/**
|
|
658
536
|
* Roving Tabindex
|
|
659
537
|
* Lightweight roving tabindex utility with fully focus management.
|
|
660
538
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
661
539
|
*
|
|
662
|
-
* @version 3.1.
|
|
540
|
+
* @version 3.1.2
|
|
663
541
|
* @author Yusuke Kamiyamane
|
|
664
542
|
* @license MIT
|
|
665
543
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.bundle.js
CHANGED
|
@@ -116,12 +116,6 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
116
116
|
const unfiltered = normalizeRadioGroup(sortByTabIndex(elements));
|
|
117
117
|
return filter ? unfiltered.filter(filter) : unfiltered;
|
|
118
118
|
}
|
|
119
|
-
function getNextFocusable(container = document.body, options = {}) {
|
|
120
|
-
return getRelativeFocusable(container, 1, options);
|
|
121
|
-
}
|
|
122
|
-
function getPreviousFocusable(container = document.body, options = {}) {
|
|
123
|
-
return getRelativeFocusable(container, -1, options);
|
|
124
|
-
}
|
|
125
119
|
function isFocusable(element, options = {}) {
|
|
126
120
|
if (!(element instanceof Element)) {
|
|
127
121
|
console.warn("Invalid element");
|
|
@@ -159,84 +153,6 @@ function isFocusable(element, options = {}) {
|
|
|
159
153
|
}
|
|
160
154
|
return true;
|
|
161
155
|
}
|
|
162
|
-
function getRelativeFocusable(container, offset, options) {
|
|
163
|
-
if (!(container instanceof Element)) {
|
|
164
|
-
console.warn("Invalid container element. Fallback: <body> element.");
|
|
165
|
-
container = document.body;
|
|
166
|
-
}
|
|
167
|
-
let {
|
|
168
|
-
anchor = getActiveElement(),
|
|
169
|
-
composed = false,
|
|
170
|
-
filter,
|
|
171
|
-
include,
|
|
172
|
-
skipNegativeTabIndexCheck = false,
|
|
173
|
-
skipVisibilityCheck = false,
|
|
174
|
-
wrap = false
|
|
175
|
-
} = options;
|
|
176
|
-
if (!(anchor instanceof Element)) {
|
|
177
|
-
const active = getActiveElement();
|
|
178
|
-
if (active instanceof Element) {
|
|
179
|
-
console.warn("Invalid anchor element. Fallback: active element.");
|
|
180
|
-
anchor = active;
|
|
181
|
-
} else {
|
|
182
|
-
console.warn("Invalid anchor element");
|
|
183
|
-
return null;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
if (!containsComposed(container, anchor)) {
|
|
187
|
-
console.warn("Anchor (active) element not within container");
|
|
188
|
-
return null;
|
|
189
|
-
}
|
|
190
|
-
if (typeof composed !== "boolean") {
|
|
191
|
-
console.warn("Invalid composed option. Fallback: false.");
|
|
192
|
-
composed = false;
|
|
193
|
-
}
|
|
194
|
-
if (typeof filter !== "undefined" && typeof filter !== "function") {
|
|
195
|
-
console.warn(
|
|
196
|
-
"Invalid filter function. Fallback: no filter function (undefined)."
|
|
197
|
-
);
|
|
198
|
-
filter = void 0;
|
|
199
|
-
}
|
|
200
|
-
if (typeof include !== "undefined" && typeof include !== "function") {
|
|
201
|
-
console.warn(
|
|
202
|
-
"Invalid include function. Fallback: no include function (undefined)."
|
|
203
|
-
);
|
|
204
|
-
include = void 0;
|
|
205
|
-
}
|
|
206
|
-
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
207
|
-
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
208
|
-
skipNegativeTabIndexCheck = false;
|
|
209
|
-
}
|
|
210
|
-
if (typeof skipVisibilityCheck !== "boolean") {
|
|
211
|
-
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
212
|
-
skipVisibilityCheck = false;
|
|
213
|
-
}
|
|
214
|
-
if (typeof wrap !== "boolean") {
|
|
215
|
-
console.warn("Invalid wrap option. Fallback: false.");
|
|
216
|
-
wrap = false;
|
|
217
|
-
}
|
|
218
|
-
const settings = { composed, skipNegativeTabIndexCheck, skipVisibilityCheck };
|
|
219
|
-
if (filter !== void 0) {
|
|
220
|
-
Object.assign(settings, { filter });
|
|
221
|
-
}
|
|
222
|
-
if (include !== void 0) {
|
|
223
|
-
Object.assign(settings, { include });
|
|
224
|
-
}
|
|
225
|
-
const focusables = getFocusables(container, settings);
|
|
226
|
-
const { length } = focusables;
|
|
227
|
-
if (!length) {
|
|
228
|
-
return null;
|
|
229
|
-
}
|
|
230
|
-
const currentIndex = focusables.indexOf(anchor);
|
|
231
|
-
if (currentIndex === -1) {
|
|
232
|
-
return null;
|
|
233
|
-
}
|
|
234
|
-
const offsetIndex = currentIndex + offset;
|
|
235
|
-
if ((offsetIndex < 0 || offsetIndex >= length) && !wrap) {
|
|
236
|
-
return null;
|
|
237
|
-
}
|
|
238
|
-
return focusables[(offsetIndex + length) % length] ?? null;
|
|
239
|
-
}
|
|
240
156
|
function isDisabledDeep(element) {
|
|
241
157
|
let current = element;
|
|
242
158
|
while (current) {
|
|
@@ -317,17 +233,6 @@ function sortByTabIndex(elements) {
|
|
|
317
233
|
}
|
|
318
234
|
return sorted;
|
|
319
235
|
}
|
|
320
|
-
function containsComposed(container, element) {
|
|
321
|
-
let current = element;
|
|
322
|
-
while (current) {
|
|
323
|
-
if (current === container) {
|
|
324
|
-
return true;
|
|
325
|
-
} else {
|
|
326
|
-
current = current instanceof ShadowRoot ? current.mode === "open" ? current.host : null : current.parentNode;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
return false;
|
|
330
|
-
}
|
|
331
236
|
function getComposedChildren(node) {
|
|
332
237
|
if (node instanceof ShadowRoot) {
|
|
333
238
|
return getChildren(node);
|
|
@@ -476,18 +381,9 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
476
381
|
}
|
|
477
382
|
this.#controller = new AbortController();
|
|
478
383
|
const { signal } = this.#controller;
|
|
479
|
-
document.addEventListener("focusin", this.#onFocusIn, {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
});
|
|
483
|
-
this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, {
|
|
484
|
-
capture: true,
|
|
485
|
-
signal
|
|
486
|
-
});
|
|
487
|
-
this.#container.addEventListener("keydown", this.#onKeyDown, {
|
|
488
|
-
capture: true,
|
|
489
|
-
signal
|
|
490
|
-
});
|
|
384
|
+
document.addEventListener("focusin", this.#onFocusIn, { signal });
|
|
385
|
+
this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, { signal });
|
|
386
|
+
this.#container.addEventListener("keydown", this.#onKeyDown, { signal });
|
|
491
387
|
}
|
|
492
388
|
#onFocusIn = (event) => {
|
|
493
389
|
const { target } = event;
|
|
@@ -504,14 +400,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
504
400
|
};
|
|
505
401
|
#onKeyDown = (event) => {
|
|
506
402
|
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
507
|
-
if (
|
|
403
|
+
if (altKey || ctrlKey || metaKey || shiftKey) {
|
|
508
404
|
return;
|
|
509
405
|
}
|
|
510
406
|
const { direction, typeahead, wrap } = this.#settings;
|
|
511
407
|
const isBoth = !direction;
|
|
512
408
|
const isHorizontal = direction === "horizontal";
|
|
513
409
|
if (![
|
|
514
|
-
"Tab",
|
|
515
410
|
"End",
|
|
516
411
|
"Home",
|
|
517
412
|
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
@@ -529,14 +424,11 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
529
424
|
if (!current.includes(active)) {
|
|
530
425
|
return;
|
|
531
426
|
}
|
|
532
|
-
|
|
427
|
+
event.preventDefault();
|
|
533
428
|
const currentIndex = current.indexOf(active);
|
|
534
|
-
let newIndex
|
|
429
|
+
let newIndex;
|
|
535
430
|
let target = current;
|
|
536
431
|
switch (key) {
|
|
537
|
-
case "Tab":
|
|
538
|
-
shouldPrevent = this.#moveFocus(shiftKey ? "previous" : "next");
|
|
539
|
-
break;
|
|
540
432
|
case "End":
|
|
541
433
|
newIndex = -1;
|
|
542
434
|
break;
|
|
@@ -558,16 +450,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
558
450
|
default: {
|
|
559
451
|
target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
|
|
560
452
|
const foundIndex = target.findIndex(
|
|
561
|
-
(
|
|
453
|
+
(focusable2) => current.indexOf(focusable2) > currentIndex
|
|
562
454
|
);
|
|
563
455
|
newIndex = foundIndex >= 0 ? foundIndex : 0;
|
|
564
456
|
}
|
|
565
457
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
const focusable = target.at(newIndex);
|
|
569
|
-
focusable && focusElement(focusable);
|
|
570
|
-
}
|
|
458
|
+
const focusable = target.at(newIndex);
|
|
459
|
+
focusable && focusElement(focusable);
|
|
571
460
|
};
|
|
572
461
|
#update(active) {
|
|
573
462
|
const current = new Set(this.#getFocusables());
|
|
@@ -640,24 +529,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
640
529
|
skipVisibilityCheck: true
|
|
641
530
|
});
|
|
642
531
|
}
|
|
643
|
-
#moveFocus(direction) {
|
|
644
|
-
const options = {
|
|
645
|
-
composed: true
|
|
646
|
-
};
|
|
647
|
-
const focusable = direction === "previous" ? getPreviousFocusable(document.body, options) : getNextFocusable(document.body, options);
|
|
648
|
-
if (focusable) {
|
|
649
|
-
focusElement(focusable);
|
|
650
|
-
return true;
|
|
651
|
-
}
|
|
652
|
-
return false;
|
|
653
|
-
}
|
|
654
532
|
};
|
|
655
533
|
/**
|
|
656
534
|
* Roving Tabindex
|
|
657
535
|
* Lightweight roving tabindex utility with fully focus management.
|
|
658
536
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
659
537
|
*
|
|
660
|
-
* @version 3.1.
|
|
538
|
+
* @version 3.1.2
|
|
661
539
|
* @author Yusuke Kamiyamane
|
|
662
540
|
* @license MIT
|
|
663
541
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.cjs
CHANGED
|
@@ -99,18 +99,9 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
99
99
|
}
|
|
100
100
|
this.#controller = new AbortController();
|
|
101
101
|
const { signal } = this.#controller;
|
|
102
|
-
document.addEventListener("focusin", this.#onFocusIn, {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
106
|
-
this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, {
|
|
107
|
-
capture: true,
|
|
108
|
-
signal
|
|
109
|
-
});
|
|
110
|
-
this.#container.addEventListener("keydown", this.#onKeyDown, {
|
|
111
|
-
capture: true,
|
|
112
|
-
signal
|
|
113
|
-
});
|
|
102
|
+
document.addEventListener("focusin", this.#onFocusIn, { signal });
|
|
103
|
+
this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, { signal });
|
|
104
|
+
this.#container.addEventListener("keydown", this.#onKeyDown, { signal });
|
|
114
105
|
}
|
|
115
106
|
#onFocusIn = (event) => {
|
|
116
107
|
const { target } = event;
|
|
@@ -127,14 +118,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
127
118
|
};
|
|
128
119
|
#onKeyDown = (event) => {
|
|
129
120
|
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
130
|
-
if (
|
|
121
|
+
if (altKey || ctrlKey || metaKey || shiftKey) {
|
|
131
122
|
return;
|
|
132
123
|
}
|
|
133
124
|
const { direction, typeahead, wrap } = this.#settings;
|
|
134
125
|
const isBoth = !direction;
|
|
135
126
|
const isHorizontal = direction === "horizontal";
|
|
136
127
|
if (![
|
|
137
|
-
"Tab",
|
|
138
128
|
"End",
|
|
139
129
|
"Home",
|
|
140
130
|
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
@@ -152,14 +142,11 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
152
142
|
if (!current.includes(active)) {
|
|
153
143
|
return;
|
|
154
144
|
}
|
|
155
|
-
|
|
145
|
+
event.preventDefault();
|
|
156
146
|
const currentIndex = current.indexOf(active);
|
|
157
|
-
let newIndex
|
|
147
|
+
let newIndex;
|
|
158
148
|
let target = current;
|
|
159
149
|
switch (key) {
|
|
160
|
-
case "Tab":
|
|
161
|
-
shouldPrevent = this.#moveFocus(shiftKey ? "previous" : "next");
|
|
162
|
-
break;
|
|
163
150
|
case "End":
|
|
164
151
|
newIndex = -1;
|
|
165
152
|
break;
|
|
@@ -181,16 +168,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
181
168
|
default: {
|
|
182
169
|
target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
|
|
183
170
|
const foundIndex = target.findIndex(
|
|
184
|
-
(
|
|
171
|
+
(focusable2) => current.indexOf(focusable2) > currentIndex
|
|
185
172
|
);
|
|
186
173
|
newIndex = foundIndex >= 0 ? foundIndex : 0;
|
|
187
174
|
}
|
|
188
175
|
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const focusable = target.at(newIndex);
|
|
192
|
-
focusable && powerFocusable.focusElement(focusable);
|
|
193
|
-
}
|
|
176
|
+
const focusable = target.at(newIndex);
|
|
177
|
+
focusable && powerFocusable.focusElement(focusable);
|
|
194
178
|
};
|
|
195
179
|
#update(active) {
|
|
196
180
|
const current = new Set(this.#getFocusables());
|
|
@@ -263,24 +247,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
263
247
|
skipVisibilityCheck: true
|
|
264
248
|
});
|
|
265
249
|
}
|
|
266
|
-
#moveFocus(direction) {
|
|
267
|
-
const options = {
|
|
268
|
-
composed: true
|
|
269
|
-
};
|
|
270
|
-
const focusable = direction === "previous" ? powerFocusable.getPreviousFocusable(document.body, options) : powerFocusable.getNextFocusable(document.body, options);
|
|
271
|
-
if (focusable) {
|
|
272
|
-
powerFocusable.focusElement(focusable);
|
|
273
|
-
return true;
|
|
274
|
-
}
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
250
|
};
|
|
278
251
|
/**
|
|
279
252
|
* Roving Tabindex
|
|
280
253
|
* Lightweight roving tabindex utility with fully focus management.
|
|
281
254
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
282
255
|
*
|
|
283
|
-
* @version 3.1.
|
|
256
|
+
* @version 3.1.2
|
|
284
257
|
* @author Yusuke Kamiyamane
|
|
285
258
|
* @license MIT
|
|
286
259
|
* @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.2
|
|
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.2
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { restoreAttributes, saveAttributes, addTokenToAttribute } from '@y14e/attributes-utils';
|
|
2
|
-
import { getActiveElement, focusElement, getFocusables
|
|
2
|
+
import { getActiveElement, focusElement, getFocusables } from 'power-focusable';
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
5
|
function createRovingTabIndex(container, options = {}) {
|
|
@@ -97,18 +97,9 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
97
97
|
}
|
|
98
98
|
this.#controller = new AbortController();
|
|
99
99
|
const { signal } = this.#controller;
|
|
100
|
-
document.addEventListener("focusin", this.#onFocusIn, {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
});
|
|
104
|
-
this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, {
|
|
105
|
-
capture: true,
|
|
106
|
-
signal
|
|
107
|
-
});
|
|
108
|
-
this.#container.addEventListener("keydown", this.#onKeyDown, {
|
|
109
|
-
capture: true,
|
|
110
|
-
signal
|
|
111
|
-
});
|
|
100
|
+
document.addEventListener("focusin", this.#onFocusIn, { signal });
|
|
101
|
+
this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, { signal });
|
|
102
|
+
this.#container.addEventListener("keydown", this.#onKeyDown, { signal });
|
|
112
103
|
}
|
|
113
104
|
#onFocusIn = (event) => {
|
|
114
105
|
const { target } = event;
|
|
@@ -125,14 +116,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
125
116
|
};
|
|
126
117
|
#onKeyDown = (event) => {
|
|
127
118
|
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
128
|
-
if (
|
|
119
|
+
if (altKey || ctrlKey || metaKey || shiftKey) {
|
|
129
120
|
return;
|
|
130
121
|
}
|
|
131
122
|
const { direction, typeahead, wrap } = this.#settings;
|
|
132
123
|
const isBoth = !direction;
|
|
133
124
|
const isHorizontal = direction === "horizontal";
|
|
134
125
|
if (![
|
|
135
|
-
"Tab",
|
|
136
126
|
"End",
|
|
137
127
|
"Home",
|
|
138
128
|
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
@@ -150,14 +140,11 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
150
140
|
if (!current.includes(active)) {
|
|
151
141
|
return;
|
|
152
142
|
}
|
|
153
|
-
|
|
143
|
+
event.preventDefault();
|
|
154
144
|
const currentIndex = current.indexOf(active);
|
|
155
|
-
let newIndex
|
|
145
|
+
let newIndex;
|
|
156
146
|
let target = current;
|
|
157
147
|
switch (key) {
|
|
158
|
-
case "Tab":
|
|
159
|
-
shouldPrevent = this.#moveFocus(shiftKey ? "previous" : "next");
|
|
160
|
-
break;
|
|
161
148
|
case "End":
|
|
162
149
|
newIndex = -1;
|
|
163
150
|
break;
|
|
@@ -179,16 +166,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
179
166
|
default: {
|
|
180
167
|
target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
|
|
181
168
|
const foundIndex = target.findIndex(
|
|
182
|
-
(
|
|
169
|
+
(focusable2) => current.indexOf(focusable2) > currentIndex
|
|
183
170
|
);
|
|
184
171
|
newIndex = foundIndex >= 0 ? foundIndex : 0;
|
|
185
172
|
}
|
|
186
173
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const focusable = target.at(newIndex);
|
|
190
|
-
focusable && focusElement(focusable);
|
|
191
|
-
}
|
|
174
|
+
const focusable = target.at(newIndex);
|
|
175
|
+
focusable && focusElement(focusable);
|
|
192
176
|
};
|
|
193
177
|
#update(active) {
|
|
194
178
|
const current = new Set(this.#getFocusables());
|
|
@@ -261,24 +245,13 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
261
245
|
skipVisibilityCheck: true
|
|
262
246
|
});
|
|
263
247
|
}
|
|
264
|
-
#moveFocus(direction) {
|
|
265
|
-
const options = {
|
|
266
|
-
composed: true
|
|
267
|
-
};
|
|
268
|
-
const focusable = direction === "previous" ? getPreviousFocusable(document.body, options) : getNextFocusable(document.body, options);
|
|
269
|
-
if (focusable) {
|
|
270
|
-
focusElement(focusable);
|
|
271
|
-
return true;
|
|
272
|
-
}
|
|
273
|
-
return false;
|
|
274
|
-
}
|
|
275
248
|
};
|
|
276
249
|
/**
|
|
277
250
|
* Roving Tabindex
|
|
278
251
|
* Lightweight roving tabindex utility with fully focus management.
|
|
279
252
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
280
253
|
*
|
|
281
|
-
* @version 3.1.
|
|
254
|
+
* @version 3.1.2
|
|
282
255
|
* @author Yusuke Kamiyamane
|
|
283
256
|
* @license MIT
|
|
284
257
|
* @copyright Copyright (c) Yusuke Kamiyamane
|