@y14e/roving-tabindex 2.0.8 → 2.2.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 +14 -4
- package/dist/index.cjs +22 -7
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +22 -7
- 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@2.0
|
|
13
|
+
import { createRovingTabIndex } from '@y14e/roving-tabindex@2.2.0';
|
|
14
14
|
|
|
15
15
|
// CDNs
|
|
16
|
-
import { createRovingTabIndex } from 'https://esm.sh/@y14e/roving-tabindex@2.0
|
|
16
|
+
import { createRovingTabIndex } from 'https://esm.sh/@y14e/roving-tabindex@2.2.0';
|
|
17
17
|
// or
|
|
18
|
-
import { createRovingTabIndex } from 'https://cdn.jsdelivr.net/npm/@y14e/roving-tabindex@2.0
|
|
18
|
+
import { createRovingTabIndex } from 'https://cdn.jsdelivr.net/npm/@y14e/roving-tabindex@2.2.0/+esm';
|
|
19
19
|
// or
|
|
20
|
-
import { createRovingTabIndex } from 'https://esm.unpkg.com/@y14e/roving-tabindex@2.0
|
|
20
|
+
import { createRovingTabIndex } from 'https://esm.unpkg.com/@y14e/roving-tabindex@2.2.0';
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## 📦 APIs
|
|
@@ -40,6 +40,8 @@ const cleanup = createRovingTabIndex(container, options);
|
|
|
40
40
|
interface RovingTabIndexOptions {
|
|
41
41
|
direction?: 'horizontal' | 'vertical'; // default: both (undefined)
|
|
42
42
|
navigationOnly?: boolean; // default: false
|
|
43
|
+
noMemory?: boolean; // default: false
|
|
44
|
+
noStart?: boolean; // default: false
|
|
43
45
|
selector?: string;
|
|
44
46
|
typeahead?: boolean; // default: false
|
|
45
47
|
wrap?: boolean; // default: false
|
|
@@ -50,6 +52,14 @@ interface RovingTabIndexOptions {
|
|
|
50
52
|
|
|
51
53
|
If `true`, enables keyboard navigation without modifying `tabindex`. Useful for widgets like accordions where all items should remain tabbable while still supporting arrow key navigation.
|
|
52
54
|
|
|
55
|
+
### `noMemory`
|
|
56
|
+
|
|
57
|
+
If `true`, disables focus memory. Focus always starts from the first item.
|
|
58
|
+
|
|
59
|
+
### `noStart`
|
|
60
|
+
|
|
61
|
+
If `true`, does not assign `tabindex="0"` to the first item during initialization.
|
|
62
|
+
|
|
53
63
|
### `typeahead`
|
|
54
64
|
|
|
55
65
|
If `true`, enables character-based focus navigation. Typing a character moves focus to the next matching element.
|
package/dist/index.cjs
CHANGED
|
@@ -299,6 +299,8 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
299
299
|
let {
|
|
300
300
|
direction,
|
|
301
301
|
navigationOnly = false,
|
|
302
|
+
noMemory = false,
|
|
303
|
+
noStart = false,
|
|
302
304
|
selector,
|
|
303
305
|
typeahead = false,
|
|
304
306
|
wrap = false
|
|
@@ -311,6 +313,14 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
311
313
|
console.warn("Invalid navigationOnly option. Fallback: false.");
|
|
312
314
|
navigationOnly = false;
|
|
313
315
|
}
|
|
316
|
+
if (typeof noMemory !== "boolean") {
|
|
317
|
+
console.warn("Invalid noMemory option. Fallback: false.");
|
|
318
|
+
noMemory = false;
|
|
319
|
+
}
|
|
320
|
+
if (typeof noStart !== "boolean") {
|
|
321
|
+
console.warn("Invalid noStart option. Fallback: false.");
|
|
322
|
+
noStart = false;
|
|
323
|
+
}
|
|
314
324
|
if (typeof selector !== "undefined" && (typeof selector !== "string" || !selector.trim())) {
|
|
315
325
|
console.warn(
|
|
316
326
|
"Invalid selector. Fallback: all focusable elements (undefined)."
|
|
@@ -325,7 +335,7 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
325
335
|
console.warn("Invalid wrap option. Fallback: false.");
|
|
326
336
|
wrap = false;
|
|
327
337
|
}
|
|
328
|
-
const settings = { navigationOnly, typeahead, wrap };
|
|
338
|
+
const settings = { navigationOnly, noMemory, noStart, typeahead, wrap };
|
|
329
339
|
direction && Object.assign(settings, { direction });
|
|
330
340
|
selector && Object.assign(settings, { selector });
|
|
331
341
|
const roving = new RovingTabIndex(container, settings);
|
|
@@ -373,10 +383,15 @@ var RovingTabIndex = class {
|
|
|
373
383
|
}
|
|
374
384
|
#onFocusIn = (event) => {
|
|
375
385
|
const { target } = event;
|
|
376
|
-
if (!(target instanceof Element)
|
|
386
|
+
if (!(target instanceof Element)) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const isFocusable2 = this.#focusables.has(target);
|
|
390
|
+
if (this.#options.noMemory && !isFocusable2) {
|
|
391
|
+
this.#update(null);
|
|
377
392
|
return;
|
|
378
393
|
}
|
|
379
|
-
this.#update(target);
|
|
394
|
+
isFocusable2 && this.#update(target);
|
|
380
395
|
};
|
|
381
396
|
#onKeyDown = (event) => {
|
|
382
397
|
if (!event.composedPath().includes(this.#container)) {
|
|
@@ -454,7 +469,7 @@ var RovingTabIndex = class {
|
|
|
454
469
|
index >= 0 && focusables.splice(index, 1);
|
|
455
470
|
});
|
|
456
471
|
}
|
|
457
|
-
const { navigationOnly } = this.#options;
|
|
472
|
+
const { navigationOnly, noStart, typeahead } = this.#options;
|
|
458
473
|
for (const focusable of current) {
|
|
459
474
|
if (this.#focusables.has(focusable)) {
|
|
460
475
|
continue;
|
|
@@ -464,7 +479,7 @@ var RovingTabIndex = class {
|
|
|
464
479
|
saveAttributes([focusable], ["tabindex"]);
|
|
465
480
|
focusable.setAttribute("tabindex", "-1");
|
|
466
481
|
}
|
|
467
|
-
if (!
|
|
482
|
+
if (!typeahead) {
|
|
468
483
|
continue;
|
|
469
484
|
}
|
|
470
485
|
const value = focusable.ariaKeyShortcuts?.trim();
|
|
@@ -495,7 +510,7 @@ var RovingTabIndex = class {
|
|
|
495
510
|
return;
|
|
496
511
|
}
|
|
497
512
|
[...this.#focusables].forEach((focusable, i) => {
|
|
498
|
-
focusable.setAttribute("tabindex", i ? "-1" : "0");
|
|
513
|
+
focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
|
|
499
514
|
});
|
|
500
515
|
}
|
|
501
516
|
#createSelectorFilter() {
|
|
@@ -526,7 +541,7 @@ function getActiveElement() {
|
|
|
526
541
|
* Lightweight roving tabindex utility with fully focus management.
|
|
527
542
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
528
543
|
*
|
|
529
|
-
* @version 2.0
|
|
544
|
+
* @version 2.2.0
|
|
530
545
|
* @author Yusuke Kamiyamane
|
|
531
546
|
* @license MIT
|
|
532
547
|
* @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 2.0
|
|
6
|
+
* @version 2.2.0
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
interface RovingTabIndexOptions {
|
|
13
13
|
readonly direction?: 'horizontal' | 'vertical';
|
|
14
14
|
readonly navigationOnly?: boolean;
|
|
15
|
+
readonly noMemory?: boolean;
|
|
16
|
+
readonly noStart?: boolean;
|
|
15
17
|
readonly selector?: string;
|
|
16
18
|
readonly typeahead?: boolean;
|
|
17
19
|
readonly wrap?: boolean;
|
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 2.0
|
|
6
|
+
* @version 2.2.0
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
interface RovingTabIndexOptions {
|
|
13
13
|
readonly direction?: 'horizontal' | 'vertical';
|
|
14
14
|
readonly navigationOnly?: boolean;
|
|
15
|
+
readonly noMemory?: boolean;
|
|
16
|
+
readonly noStart?: boolean;
|
|
15
17
|
readonly selector?: string;
|
|
16
18
|
readonly typeahead?: boolean;
|
|
17
19
|
readonly wrap?: boolean;
|
package/dist/index.js
CHANGED
|
@@ -297,6 +297,8 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
297
297
|
let {
|
|
298
298
|
direction,
|
|
299
299
|
navigationOnly = false,
|
|
300
|
+
noMemory = false,
|
|
301
|
+
noStart = false,
|
|
300
302
|
selector,
|
|
301
303
|
typeahead = false,
|
|
302
304
|
wrap = false
|
|
@@ -309,6 +311,14 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
309
311
|
console.warn("Invalid navigationOnly option. Fallback: false.");
|
|
310
312
|
navigationOnly = false;
|
|
311
313
|
}
|
|
314
|
+
if (typeof noMemory !== "boolean") {
|
|
315
|
+
console.warn("Invalid noMemory option. Fallback: false.");
|
|
316
|
+
noMemory = false;
|
|
317
|
+
}
|
|
318
|
+
if (typeof noStart !== "boolean") {
|
|
319
|
+
console.warn("Invalid noStart option. Fallback: false.");
|
|
320
|
+
noStart = false;
|
|
321
|
+
}
|
|
312
322
|
if (typeof selector !== "undefined" && (typeof selector !== "string" || !selector.trim())) {
|
|
313
323
|
console.warn(
|
|
314
324
|
"Invalid selector. Fallback: all focusable elements (undefined)."
|
|
@@ -323,7 +333,7 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
323
333
|
console.warn("Invalid wrap option. Fallback: false.");
|
|
324
334
|
wrap = false;
|
|
325
335
|
}
|
|
326
|
-
const settings = { navigationOnly, typeahead, wrap };
|
|
336
|
+
const settings = { navigationOnly, noMemory, noStart, typeahead, wrap };
|
|
327
337
|
direction && Object.assign(settings, { direction });
|
|
328
338
|
selector && Object.assign(settings, { selector });
|
|
329
339
|
const roving = new RovingTabIndex(container, settings);
|
|
@@ -371,10 +381,15 @@ var RovingTabIndex = class {
|
|
|
371
381
|
}
|
|
372
382
|
#onFocusIn = (event) => {
|
|
373
383
|
const { target } = event;
|
|
374
|
-
if (!(target instanceof Element)
|
|
384
|
+
if (!(target instanceof Element)) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
const isFocusable2 = this.#focusables.has(target);
|
|
388
|
+
if (this.#options.noMemory && !isFocusable2) {
|
|
389
|
+
this.#update(null);
|
|
375
390
|
return;
|
|
376
391
|
}
|
|
377
|
-
this.#update(target);
|
|
392
|
+
isFocusable2 && this.#update(target);
|
|
378
393
|
};
|
|
379
394
|
#onKeyDown = (event) => {
|
|
380
395
|
if (!event.composedPath().includes(this.#container)) {
|
|
@@ -452,7 +467,7 @@ var RovingTabIndex = class {
|
|
|
452
467
|
index >= 0 && focusables.splice(index, 1);
|
|
453
468
|
});
|
|
454
469
|
}
|
|
455
|
-
const { navigationOnly } = this.#options;
|
|
470
|
+
const { navigationOnly, noStart, typeahead } = this.#options;
|
|
456
471
|
for (const focusable of current) {
|
|
457
472
|
if (this.#focusables.has(focusable)) {
|
|
458
473
|
continue;
|
|
@@ -462,7 +477,7 @@ var RovingTabIndex = class {
|
|
|
462
477
|
saveAttributes([focusable], ["tabindex"]);
|
|
463
478
|
focusable.setAttribute("tabindex", "-1");
|
|
464
479
|
}
|
|
465
|
-
if (!
|
|
480
|
+
if (!typeahead) {
|
|
466
481
|
continue;
|
|
467
482
|
}
|
|
468
483
|
const value = focusable.ariaKeyShortcuts?.trim();
|
|
@@ -493,7 +508,7 @@ var RovingTabIndex = class {
|
|
|
493
508
|
return;
|
|
494
509
|
}
|
|
495
510
|
[...this.#focusables].forEach((focusable, i) => {
|
|
496
|
-
focusable.setAttribute("tabindex", i ? "-1" : "0");
|
|
511
|
+
focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
|
|
497
512
|
});
|
|
498
513
|
}
|
|
499
514
|
#createSelectorFilter() {
|
|
@@ -524,7 +539,7 @@ function getActiveElement() {
|
|
|
524
539
|
* Lightweight roving tabindex utility with fully focus management.
|
|
525
540
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
526
541
|
*
|
|
527
|
-
* @version 2.0
|
|
542
|
+
* @version 2.2.0
|
|
528
543
|
* @author Yusuke Kamiyamane
|
|
529
544
|
* @license MIT
|
|
530
545
|
* @copyright Copyright (c) Yusuke Kamiyamane
|