@y14e/roving-tabindex 1.0.1 → 1.1.0
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 +5 -0
- package/dist/index.cjs +89 -25
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +89 -25
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -43,10 +43,15 @@ const cleanup = createRovingTabIndex(container, options);
|
|
|
43
43
|
interface RovingTabIndexOptions {
|
|
44
44
|
direction?: 'horizontal' | 'vertical'; // default: both (undefined)
|
|
45
45
|
selector?: string;
|
|
46
|
+
typeahead?: boolean; // default: false
|
|
46
47
|
wrap?: boolean; // default: false
|
|
47
48
|
}
|
|
48
49
|
```
|
|
49
50
|
|
|
51
|
+
### `typeahead`
|
|
52
|
+
|
|
53
|
+
If `true`, enables character-based focus navigation. Typing a character moves focus to the next matching element.
|
|
54
|
+
|
|
50
55
|
### `wrap`
|
|
51
56
|
|
|
52
57
|
If `true`, wraps around to the first or last element when reaching the end.
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// node_modules/@y14e/attributes-utils/dist/index.js
|
|
4
|
+
var snapshots = /* @__PURE__ */ new WeakMap();
|
|
5
|
+
function restoreAttributes(elements) {
|
|
6
|
+
elements.forEach((element) => {
|
|
7
|
+
const snapshot = snapshots.get(element);
|
|
8
|
+
if (!snapshot) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
for (const [attribute, value] of snapshot.entries()) {
|
|
12
|
+
if (value === null) {
|
|
13
|
+
element.removeAttribute(attribute);
|
|
14
|
+
} else {
|
|
15
|
+
element.setAttribute(attribute, value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
snapshots.delete(element);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function saveAttributes(elements, attributes) {
|
|
22
|
+
elements.forEach((element) => {
|
|
23
|
+
let snapshot = snapshots.get(element);
|
|
24
|
+
if (!snapshot) {
|
|
25
|
+
snapshot = /* @__PURE__ */ new Map();
|
|
26
|
+
snapshots.set(element, snapshot);
|
|
27
|
+
}
|
|
28
|
+
attributes.forEach((attribute) => {
|
|
29
|
+
snapshot.set(attribute, element.getAttribute(attribute));
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
3
34
|
// node_modules/power-focusable/dist/index.js
|
|
4
35
|
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
36
|
function getFocusables(container = document.body, options = {}) {
|
|
@@ -207,7 +238,7 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
207
238
|
if (!(container instanceof Element)) {
|
|
208
239
|
throw new Error("Invalid container element");
|
|
209
240
|
}
|
|
210
|
-
const { direction, selector, wrap = false } = options;
|
|
241
|
+
const { direction, selector, typeahead = false, wrap = false } = options;
|
|
211
242
|
if (direction && !["horizontal", "vertical"].includes(direction)) {
|
|
212
243
|
console.warn("Invalid direction. Fallback: both (undefined).");
|
|
213
244
|
Object.assign(options, { direction: void 0 });
|
|
@@ -216,6 +247,10 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
216
247
|
console.warn("Invalid selector. Fallback: all focusable elements.");
|
|
217
248
|
Object.assign(options, { selector: void 0 });
|
|
218
249
|
}
|
|
250
|
+
if (typeof typeahead !== "boolean") {
|
|
251
|
+
console.warn("Invalid typeahead. Fallback: false.");
|
|
252
|
+
Object.assign(options, { typeahead: false });
|
|
253
|
+
}
|
|
219
254
|
if (typeof wrap !== "boolean") {
|
|
220
255
|
console.warn("Invalid wrap. Fallback: false.");
|
|
221
256
|
Object.assign(options, { wrap: false });
|
|
@@ -227,7 +262,7 @@ var RovingTabIndex = class {
|
|
|
227
262
|
#container;
|
|
228
263
|
#options;
|
|
229
264
|
#focusables = /* @__PURE__ */ new Set();
|
|
230
|
-
#
|
|
265
|
+
#focusablesByFirstChar = /* @__PURE__ */ new Map();
|
|
231
266
|
#selectorFilter;
|
|
232
267
|
#controller = null;
|
|
233
268
|
#isDestroyed = false;
|
|
@@ -244,16 +279,9 @@ var RovingTabIndex = class {
|
|
|
244
279
|
this.#isDestroyed = true;
|
|
245
280
|
this.#controller?.abort();
|
|
246
281
|
this.#controller = null;
|
|
247
|
-
this.#focusables
|
|
248
|
-
const index = this.#tabIndexes.get(focusable);
|
|
249
|
-
if (index == null) {
|
|
250
|
-
focusable.removeAttribute("tabindex");
|
|
251
|
-
} else {
|
|
252
|
-
focusable.setAttribute("tabindex", index);
|
|
253
|
-
}
|
|
254
|
-
});
|
|
282
|
+
restoreAttributes([...this.#focusables]);
|
|
255
283
|
this.#focusables.clear();
|
|
256
|
-
this.#
|
|
284
|
+
this.#focusablesByFirstChar.clear();
|
|
257
285
|
this.#container.removeAttribute("data-roving-tabindex-initialized");
|
|
258
286
|
}
|
|
259
287
|
#initialize() {
|
|
@@ -273,7 +301,7 @@ var RovingTabIndex = class {
|
|
|
273
301
|
if (altKey || ctrlKey || metaKey) {
|
|
274
302
|
return;
|
|
275
303
|
}
|
|
276
|
-
const { direction } = this.#options;
|
|
304
|
+
const { direction, typeahead, wrap } = this.#options;
|
|
277
305
|
const isBoth = !direction;
|
|
278
306
|
const isHorizontal = direction === "horizontal";
|
|
279
307
|
if (![
|
|
@@ -282,7 +310,9 @@ var RovingTabIndex = class {
|
|
|
282
310
|
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
283
311
|
...isBoth ? ["ArrowRight", "ArrowDown"] : [`Arrow${isHorizontal ? "Right" : "Down"}`]
|
|
284
312
|
].includes(key)) {
|
|
285
|
-
|
|
313
|
+
if (!typeahead || !/^\S$/i.test(key) || !this.#focusablesByFirstChar.has(key.toLowerCase())) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
286
316
|
}
|
|
287
317
|
const active = getActiveElement();
|
|
288
318
|
if (!(active instanceof HTMLElement)) {
|
|
@@ -295,9 +325,9 @@ var RovingTabIndex = class {
|
|
|
295
325
|
event.preventDefault();
|
|
296
326
|
event.stopPropagation();
|
|
297
327
|
const currentIndex = focusables.indexOf(active);
|
|
298
|
-
let rawIndex;
|
|
328
|
+
let rawIndex = currentIndex;
|
|
299
329
|
let newIndex = currentIndex;
|
|
300
|
-
|
|
330
|
+
let target = focusables;
|
|
301
331
|
switch (key) {
|
|
302
332
|
case "End":
|
|
303
333
|
newIndex = -1;
|
|
@@ -315,8 +345,18 @@ var RovingTabIndex = class {
|
|
|
315
345
|
rawIndex = currentIndex + 1;
|
|
316
346
|
newIndex = wrap ? rawIndex % focusables.length : Math.min(rawIndex, focusables.length - 1);
|
|
317
347
|
break;
|
|
348
|
+
default: {
|
|
349
|
+
if (!typeahead) {
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
target = this.#focusablesByFirstChar.get(key.toLowerCase()) ?? [];
|
|
353
|
+
const foundIndex = target.findIndex(
|
|
354
|
+
(focusable2) => focusables.indexOf(focusable2) > currentIndex
|
|
355
|
+
);
|
|
356
|
+
newIndex = foundIndex !== -1 ? foundIndex : 0;
|
|
357
|
+
}
|
|
318
358
|
}
|
|
319
|
-
const focusable =
|
|
359
|
+
const focusable = target.at(newIndex);
|
|
320
360
|
if (!focusable) {
|
|
321
361
|
return;
|
|
322
362
|
}
|
|
@@ -336,23 +376,36 @@ var RovingTabIndex = class {
|
|
|
336
376
|
return;
|
|
337
377
|
}
|
|
338
378
|
if (focusable.isConnected) {
|
|
339
|
-
|
|
340
|
-
if (index == null) {
|
|
341
|
-
focusable.removeAttribute("tabindex");
|
|
342
|
-
} else {
|
|
343
|
-
focusable.setAttribute("tabindex", index);
|
|
344
|
-
}
|
|
379
|
+
restoreAttributes([focusable]);
|
|
345
380
|
}
|
|
346
381
|
this.#focusables.delete(focusable);
|
|
347
|
-
this.#
|
|
382
|
+
this.#focusablesByFirstChar.forEach((focusables) => {
|
|
383
|
+
const index = focusables.indexOf(focusable);
|
|
384
|
+
if (index !== -1) {
|
|
385
|
+
focusables.splice(index, 1);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
348
388
|
});
|
|
349
389
|
current.forEach((c) => {
|
|
350
390
|
if (this.#focusables.has(c)) {
|
|
351
391
|
return;
|
|
352
392
|
}
|
|
353
393
|
this.#focusables.add(c);
|
|
354
|
-
|
|
394
|
+
saveAttributes([c], ["tabindex"]);
|
|
355
395
|
c.setAttribute("tabindex", "-1");
|
|
396
|
+
if (!this.#options.typeahead) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const shortcuts = c.ariaKeyShortcuts;
|
|
400
|
+
const keys = (shortcuts?.split(/\s+/) ?? [c.textContent?.trim()[0] ?? ""]).filter((key) => /^\S$/i.test(key)).map((key) => key.toLowerCase());
|
|
401
|
+
keys.forEach((key) => {
|
|
402
|
+
const focusables = this.#focusablesByFirstChar.get(key) ?? [];
|
|
403
|
+
focusables.push(c);
|
|
404
|
+
this.#focusablesByFirstChar.set(key, focusables);
|
|
405
|
+
});
|
|
406
|
+
const first = keys[0];
|
|
407
|
+
saveAttributes([c], ["aria-keyshortcuts"]);
|
|
408
|
+
!shortcuts && first && c.setAttribute("aria-keyshortcuts", first);
|
|
356
409
|
});
|
|
357
410
|
if (active && this.#focusables.has(active)) {
|
|
358
411
|
this.#focusables.forEach((focusable) => {
|
|
@@ -391,7 +444,7 @@ function getActiveElement() {
|
|
|
391
444
|
* Lightweight roving tabindex utility with fully focus management.
|
|
392
445
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
393
446
|
*
|
|
394
|
-
* @version 1.0
|
|
447
|
+
* @version 1.1.0
|
|
395
448
|
* @author Yusuke Kamiyamane
|
|
396
449
|
* @license MIT
|
|
397
450
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -399,6 +452,17 @@ function getActiveElement() {
|
|
|
399
452
|
*/
|
|
400
453
|
/*! Bundled license information:
|
|
401
454
|
|
|
455
|
+
@y14e/attributes-utils/dist/index.js:
|
|
456
|
+
(**
|
|
457
|
+
* Attributes Utils
|
|
458
|
+
*
|
|
459
|
+
* @version 1.0.0
|
|
460
|
+
* @author Yusuke Kamiyamane
|
|
461
|
+
* @license MIT
|
|
462
|
+
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
463
|
+
* @see {@link https://github.com/y14e/attributes-utils}
|
|
464
|
+
*)
|
|
465
|
+
|
|
402
466
|
power-focusable/dist/index.js:
|
|
403
467
|
(**
|
|
404
468
|
* Power Focusable
|
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 1.0
|
|
6
|
+
* @version 1.1.0
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
interface RovingTabIndexOptions {
|
|
13
13
|
readonly direction?: 'horizontal' | 'vertical';
|
|
14
14
|
readonly selector?: string;
|
|
15
|
+
readonly typeahead?: boolean;
|
|
15
16
|
readonly wrap?: boolean;
|
|
16
17
|
}
|
|
17
18
|
declare function createRovingTabIndex(container: Element, options?: RovingTabIndexOptions): () => void;
|
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 1.0
|
|
6
|
+
* @version 1.1.0
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
interface RovingTabIndexOptions {
|
|
13
13
|
readonly direction?: 'horizontal' | 'vertical';
|
|
14
14
|
readonly selector?: string;
|
|
15
|
+
readonly typeahead?: boolean;
|
|
15
16
|
readonly wrap?: boolean;
|
|
16
17
|
}
|
|
17
18
|
declare function createRovingTabIndex(container: Element, options?: RovingTabIndexOptions): () => void;
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,34 @@
|
|
|
1
|
+
// node_modules/@y14e/attributes-utils/dist/index.js
|
|
2
|
+
var snapshots = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function restoreAttributes(elements) {
|
|
4
|
+
elements.forEach((element) => {
|
|
5
|
+
const snapshot = snapshots.get(element);
|
|
6
|
+
if (!snapshot) {
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
for (const [attribute, value] of snapshot.entries()) {
|
|
10
|
+
if (value === null) {
|
|
11
|
+
element.removeAttribute(attribute);
|
|
12
|
+
} else {
|
|
13
|
+
element.setAttribute(attribute, value);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
snapshots.delete(element);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function saveAttributes(elements, attributes) {
|
|
20
|
+
elements.forEach((element) => {
|
|
21
|
+
let snapshot = snapshots.get(element);
|
|
22
|
+
if (!snapshot) {
|
|
23
|
+
snapshot = /* @__PURE__ */ new Map();
|
|
24
|
+
snapshots.set(element, snapshot);
|
|
25
|
+
}
|
|
26
|
+
attributes.forEach((attribute) => {
|
|
27
|
+
snapshot.set(attribute, element.getAttribute(attribute));
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
1
32
|
// node_modules/power-focusable/dist/index.js
|
|
2
33
|
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
34
|
function getFocusables(container = document.body, options = {}) {
|
|
@@ -205,7 +236,7 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
205
236
|
if (!(container instanceof Element)) {
|
|
206
237
|
throw new Error("Invalid container element");
|
|
207
238
|
}
|
|
208
|
-
const { direction, selector, wrap = false } = options;
|
|
239
|
+
const { direction, selector, typeahead = false, wrap = false } = options;
|
|
209
240
|
if (direction && !["horizontal", "vertical"].includes(direction)) {
|
|
210
241
|
console.warn("Invalid direction. Fallback: both (undefined).");
|
|
211
242
|
Object.assign(options, { direction: void 0 });
|
|
@@ -214,6 +245,10 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
214
245
|
console.warn("Invalid selector. Fallback: all focusable elements.");
|
|
215
246
|
Object.assign(options, { selector: void 0 });
|
|
216
247
|
}
|
|
248
|
+
if (typeof typeahead !== "boolean") {
|
|
249
|
+
console.warn("Invalid typeahead. Fallback: false.");
|
|
250
|
+
Object.assign(options, { typeahead: false });
|
|
251
|
+
}
|
|
217
252
|
if (typeof wrap !== "boolean") {
|
|
218
253
|
console.warn("Invalid wrap. Fallback: false.");
|
|
219
254
|
Object.assign(options, { wrap: false });
|
|
@@ -225,7 +260,7 @@ var RovingTabIndex = class {
|
|
|
225
260
|
#container;
|
|
226
261
|
#options;
|
|
227
262
|
#focusables = /* @__PURE__ */ new Set();
|
|
228
|
-
#
|
|
263
|
+
#focusablesByFirstChar = /* @__PURE__ */ new Map();
|
|
229
264
|
#selectorFilter;
|
|
230
265
|
#controller = null;
|
|
231
266
|
#isDestroyed = false;
|
|
@@ -242,16 +277,9 @@ var RovingTabIndex = class {
|
|
|
242
277
|
this.#isDestroyed = true;
|
|
243
278
|
this.#controller?.abort();
|
|
244
279
|
this.#controller = null;
|
|
245
|
-
this.#focusables
|
|
246
|
-
const index = this.#tabIndexes.get(focusable);
|
|
247
|
-
if (index == null) {
|
|
248
|
-
focusable.removeAttribute("tabindex");
|
|
249
|
-
} else {
|
|
250
|
-
focusable.setAttribute("tabindex", index);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
280
|
+
restoreAttributes([...this.#focusables]);
|
|
253
281
|
this.#focusables.clear();
|
|
254
|
-
this.#
|
|
282
|
+
this.#focusablesByFirstChar.clear();
|
|
255
283
|
this.#container.removeAttribute("data-roving-tabindex-initialized");
|
|
256
284
|
}
|
|
257
285
|
#initialize() {
|
|
@@ -271,7 +299,7 @@ var RovingTabIndex = class {
|
|
|
271
299
|
if (altKey || ctrlKey || metaKey) {
|
|
272
300
|
return;
|
|
273
301
|
}
|
|
274
|
-
const { direction } = this.#options;
|
|
302
|
+
const { direction, typeahead, wrap } = this.#options;
|
|
275
303
|
const isBoth = !direction;
|
|
276
304
|
const isHorizontal = direction === "horizontal";
|
|
277
305
|
if (![
|
|
@@ -280,7 +308,9 @@ var RovingTabIndex = class {
|
|
|
280
308
|
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
281
309
|
...isBoth ? ["ArrowRight", "ArrowDown"] : [`Arrow${isHorizontal ? "Right" : "Down"}`]
|
|
282
310
|
].includes(key)) {
|
|
283
|
-
|
|
311
|
+
if (!typeahead || !/^\S$/i.test(key) || !this.#focusablesByFirstChar.has(key.toLowerCase())) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
284
314
|
}
|
|
285
315
|
const active = getActiveElement();
|
|
286
316
|
if (!(active instanceof HTMLElement)) {
|
|
@@ -293,9 +323,9 @@ var RovingTabIndex = class {
|
|
|
293
323
|
event.preventDefault();
|
|
294
324
|
event.stopPropagation();
|
|
295
325
|
const currentIndex = focusables.indexOf(active);
|
|
296
|
-
let rawIndex;
|
|
326
|
+
let rawIndex = currentIndex;
|
|
297
327
|
let newIndex = currentIndex;
|
|
298
|
-
|
|
328
|
+
let target = focusables;
|
|
299
329
|
switch (key) {
|
|
300
330
|
case "End":
|
|
301
331
|
newIndex = -1;
|
|
@@ -313,8 +343,18 @@ var RovingTabIndex = class {
|
|
|
313
343
|
rawIndex = currentIndex + 1;
|
|
314
344
|
newIndex = wrap ? rawIndex % focusables.length : Math.min(rawIndex, focusables.length - 1);
|
|
315
345
|
break;
|
|
346
|
+
default: {
|
|
347
|
+
if (!typeahead) {
|
|
348
|
+
break;
|
|
349
|
+
}
|
|
350
|
+
target = this.#focusablesByFirstChar.get(key.toLowerCase()) ?? [];
|
|
351
|
+
const foundIndex = target.findIndex(
|
|
352
|
+
(focusable2) => focusables.indexOf(focusable2) > currentIndex
|
|
353
|
+
);
|
|
354
|
+
newIndex = foundIndex !== -1 ? foundIndex : 0;
|
|
355
|
+
}
|
|
316
356
|
}
|
|
317
|
-
const focusable =
|
|
357
|
+
const focusable = target.at(newIndex);
|
|
318
358
|
if (!focusable) {
|
|
319
359
|
return;
|
|
320
360
|
}
|
|
@@ -334,23 +374,36 @@ var RovingTabIndex = class {
|
|
|
334
374
|
return;
|
|
335
375
|
}
|
|
336
376
|
if (focusable.isConnected) {
|
|
337
|
-
|
|
338
|
-
if (index == null) {
|
|
339
|
-
focusable.removeAttribute("tabindex");
|
|
340
|
-
} else {
|
|
341
|
-
focusable.setAttribute("tabindex", index);
|
|
342
|
-
}
|
|
377
|
+
restoreAttributes([focusable]);
|
|
343
378
|
}
|
|
344
379
|
this.#focusables.delete(focusable);
|
|
345
|
-
this.#
|
|
380
|
+
this.#focusablesByFirstChar.forEach((focusables) => {
|
|
381
|
+
const index = focusables.indexOf(focusable);
|
|
382
|
+
if (index !== -1) {
|
|
383
|
+
focusables.splice(index, 1);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
346
386
|
});
|
|
347
387
|
current.forEach((c) => {
|
|
348
388
|
if (this.#focusables.has(c)) {
|
|
349
389
|
return;
|
|
350
390
|
}
|
|
351
391
|
this.#focusables.add(c);
|
|
352
|
-
|
|
392
|
+
saveAttributes([c], ["tabindex"]);
|
|
353
393
|
c.setAttribute("tabindex", "-1");
|
|
394
|
+
if (!this.#options.typeahead) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
const shortcuts = c.ariaKeyShortcuts;
|
|
398
|
+
const keys = (shortcuts?.split(/\s+/) ?? [c.textContent?.trim()[0] ?? ""]).filter((key) => /^\S$/i.test(key)).map((key) => key.toLowerCase());
|
|
399
|
+
keys.forEach((key) => {
|
|
400
|
+
const focusables = this.#focusablesByFirstChar.get(key) ?? [];
|
|
401
|
+
focusables.push(c);
|
|
402
|
+
this.#focusablesByFirstChar.set(key, focusables);
|
|
403
|
+
});
|
|
404
|
+
const first = keys[0];
|
|
405
|
+
saveAttributes([c], ["aria-keyshortcuts"]);
|
|
406
|
+
!shortcuts && first && c.setAttribute("aria-keyshortcuts", first);
|
|
354
407
|
});
|
|
355
408
|
if (active && this.#focusables.has(active)) {
|
|
356
409
|
this.#focusables.forEach((focusable) => {
|
|
@@ -389,7 +442,7 @@ function getActiveElement() {
|
|
|
389
442
|
* Lightweight roving tabindex utility with fully focus management.
|
|
390
443
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
391
444
|
*
|
|
392
|
-
* @version 1.0
|
|
445
|
+
* @version 1.1.0
|
|
393
446
|
* @author Yusuke Kamiyamane
|
|
394
447
|
* @license MIT
|
|
395
448
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -397,6 +450,17 @@ function getActiveElement() {
|
|
|
397
450
|
*/
|
|
398
451
|
/*! Bundled license information:
|
|
399
452
|
|
|
453
|
+
@y14e/attributes-utils/dist/index.js:
|
|
454
|
+
(**
|
|
455
|
+
* Attributes Utils
|
|
456
|
+
*
|
|
457
|
+
* @version 1.0.0
|
|
458
|
+
* @author Yusuke Kamiyamane
|
|
459
|
+
* @license MIT
|
|
460
|
+
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
461
|
+
* @see {@link https://github.com/y14e/attributes-utils}
|
|
462
|
+
*)
|
|
463
|
+
|
|
400
464
|
power-focusable/dist/index.js:
|
|
401
465
|
(**
|
|
402
466
|
* Power Focusable
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y14e/roving-tabindex",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Lightweight roving tabindex utility with fully focus management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"homepage": "https://github.com/y14e/roving-tabindex#readme",
|
|
50
50
|
"devDependencies": {
|
|
51
|
+
"@y14e/attributes-utils": "^1.0.0",
|
|
51
52
|
"bun-types": "latest",
|
|
52
53
|
"power-focusable": "^4.1.5",
|
|
53
54
|
"tsup": "^8.0.0",
|