@y14e/roving-tabindex 1.3.2 → 2.0.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 +0 -5
- package/dist/index.cjs +26 -16
- package/dist/index.d.cts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +26 -16
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -44,7 +44,6 @@ interface RovingTabIndexOptions {
|
|
|
44
44
|
direction?: 'horizontal' | 'vertical' | undefined; // default: both (undefined)
|
|
45
45
|
navigationOnly?: boolean; // default: false
|
|
46
46
|
selector?: string | undefined;
|
|
47
|
-
skipVisibilityCheck?: boolean; // default: false
|
|
48
47
|
typeahead?: boolean; // default: false
|
|
49
48
|
wrap?: boolean; // default: false
|
|
50
49
|
}
|
|
@@ -54,10 +53,6 @@ interface RovingTabIndexOptions {
|
|
|
54
53
|
|
|
55
54
|
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.
|
|
56
55
|
|
|
57
|
-
### `skipVisibilityCheck`
|
|
58
|
-
|
|
59
|
-
If `true`, skips `checkVisibility()` when determining focusability. Useful for initializing.
|
|
60
|
-
|
|
61
56
|
### `typeahead`
|
|
62
57
|
|
|
63
58
|
If `true`, enables character-based focus navigation. Typing a character moves focus to the next matching element.
|
package/dist/index.cjs
CHANGED
|
@@ -61,6 +61,7 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
61
61
|
composed = false,
|
|
62
62
|
filter,
|
|
63
63
|
include,
|
|
64
|
+
skipNegativeTabIndexCheck = false,
|
|
64
65
|
skipVisibilityCheck = false
|
|
65
66
|
} = options;
|
|
66
67
|
if (typeof composed !== "boolean") {
|
|
@@ -79,6 +80,10 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
79
80
|
);
|
|
80
81
|
include = void 0;
|
|
81
82
|
}
|
|
83
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
84
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
85
|
+
skipNegativeTabIndexCheck = false;
|
|
86
|
+
}
|
|
82
87
|
if (typeof skipVisibilityCheck !== "boolean") {
|
|
83
88
|
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
84
89
|
skipVisibilityCheck = false;
|
|
@@ -87,7 +92,10 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
87
92
|
if (composed || include) {
|
|
88
93
|
let traverse2 = function(node) {
|
|
89
94
|
if (node instanceof Element) {
|
|
90
|
-
if (isFocusable(node, {
|
|
95
|
+
if (isFocusable(node, {
|
|
96
|
+
skipNegativeTabIndexCheck,
|
|
97
|
+
skipVisibilityCheck
|
|
98
|
+
}) || include?.(node)) {
|
|
91
99
|
elements[elements.length] = node;
|
|
92
100
|
}
|
|
93
101
|
}
|
|
@@ -108,7 +116,10 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
108
116
|
if (!(candidate instanceof Element)) {
|
|
109
117
|
continue;
|
|
110
118
|
}
|
|
111
|
-
if (isFocusable(candidate, {
|
|
119
|
+
if (isFocusable(candidate, {
|
|
120
|
+
skipNegativeTabIndexCheck,
|
|
121
|
+
skipVisibilityCheck
|
|
122
|
+
})) {
|
|
112
123
|
elements[elements.length] = candidate;
|
|
113
124
|
}
|
|
114
125
|
}
|
|
@@ -121,7 +132,11 @@ function isFocusable(element, options = {}) {
|
|
|
121
132
|
console.warn("Invalid element");
|
|
122
133
|
return false;
|
|
123
134
|
}
|
|
124
|
-
let { skipVisibilityCheck = false } = options;
|
|
135
|
+
let { skipNegativeTabIndexCheck = false, skipVisibilityCheck = false } = options;
|
|
136
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
137
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
138
|
+
skipNegativeTabIndexCheck = false;
|
|
139
|
+
}
|
|
125
140
|
if (typeof skipVisibilityCheck !== "boolean") {
|
|
126
141
|
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
127
142
|
skipVisibilityCheck = false;
|
|
@@ -129,10 +144,12 @@ function isFocusable(element, options = {}) {
|
|
|
129
144
|
if (element.hasAttribute("hidden") || isInert(element)) {
|
|
130
145
|
return false;
|
|
131
146
|
}
|
|
132
|
-
if (getTabIndex(element) < 0) {
|
|
147
|
+
if (!skipNegativeTabIndexCheck && getTabIndex(element) < 0) {
|
|
133
148
|
return false;
|
|
134
149
|
}
|
|
135
|
-
if (!element.matches(
|
|
150
|
+
if (!element.matches(
|
|
151
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR.replace(/(,\s*)?\[tabindex="-1"\]/g, "") : FOCUSABLE_SELECTOR
|
|
152
|
+
)) {
|
|
136
153
|
return false;
|
|
137
154
|
}
|
|
138
155
|
if (isDisabledDeep(element)) {
|
|
@@ -284,7 +301,6 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
284
301
|
direction,
|
|
285
302
|
navigationOnly = false,
|
|
286
303
|
selector,
|
|
287
|
-
skipVisibilityCheck = false,
|
|
288
304
|
typeahead = false,
|
|
289
305
|
wrap = false
|
|
290
306
|
} = options;
|
|
@@ -302,10 +318,6 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
302
318
|
);
|
|
303
319
|
selector = void 0;
|
|
304
320
|
}
|
|
305
|
-
if (typeof skipVisibilityCheck !== "boolean") {
|
|
306
|
-
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
307
|
-
skipVisibilityCheck = false;
|
|
308
|
-
}
|
|
309
321
|
if (typeof typeahead !== "boolean") {
|
|
310
322
|
console.warn("Invalid typeahead option. Fallback: false.");
|
|
311
323
|
typeahead = false;
|
|
@@ -318,7 +330,6 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
318
330
|
direction,
|
|
319
331
|
navigationOnly,
|
|
320
332
|
selector,
|
|
321
|
-
skipVisibilityCheck,
|
|
322
333
|
typeahead,
|
|
323
334
|
wrap
|
|
324
335
|
});
|
|
@@ -432,7 +443,7 @@ var RovingTabIndex = class {
|
|
|
432
443
|
...getFocusables(this.#container, {
|
|
433
444
|
composed: true,
|
|
434
445
|
filter: this.#selectorFilter,
|
|
435
|
-
|
|
446
|
+
skipNegativeTabIndexCheck: !this.#options.navigationOnly
|
|
436
447
|
})
|
|
437
448
|
]);
|
|
438
449
|
for (const focusable of this.#focusables) {
|
|
@@ -498,8 +509,7 @@ var RovingTabIndex = class {
|
|
|
498
509
|
return getFocusables(this.#container, {
|
|
499
510
|
composed: true,
|
|
500
511
|
filter: this.#selectorFilter,
|
|
501
|
-
|
|
502
|
-
skipVisibilityCheck: !!this.#options.skipVisibilityCheck
|
|
512
|
+
skipNegativeTabIndexCheck: !this.#options.navigationOnly
|
|
503
513
|
});
|
|
504
514
|
}
|
|
505
515
|
};
|
|
@@ -518,7 +528,7 @@ function getActiveElement() {
|
|
|
518
528
|
* Lightweight roving tabindex utility with fully focus management.
|
|
519
529
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
520
530
|
*
|
|
521
|
-
* @version
|
|
531
|
+
* @version 2.0.0
|
|
522
532
|
* @author Yusuke Kamiyamane
|
|
523
533
|
* @license MIT
|
|
524
534
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -543,7 +553,7 @@ power-focusable/dist/index.js:
|
|
|
543
553
|
* High-precision focus management utility with full composed tree support.
|
|
544
554
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
545
555
|
*
|
|
546
|
-
* @version 4.
|
|
556
|
+
* @version 4.3.0
|
|
547
557
|
* @author Yusuke Kamiyamane
|
|
548
558
|
* @license MIT
|
|
549
559
|
* @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
|
|
6
|
+
* @version 2.0.0
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -13,7 +13,6 @@ interface RovingTabIndexOptions {
|
|
|
13
13
|
readonly direction?: 'horizontal' | 'vertical' | undefined;
|
|
14
14
|
readonly navigationOnly?: boolean;
|
|
15
15
|
readonly selector?: string | undefined;
|
|
16
|
-
readonly skipVisibilityCheck?: boolean;
|
|
17
16
|
readonly typeahead?: boolean;
|
|
18
17
|
readonly wrap?: boolean;
|
|
19
18
|
}
|
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
|
|
6
|
+
* @version 2.0.0
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -13,7 +13,6 @@ interface RovingTabIndexOptions {
|
|
|
13
13
|
readonly direction?: 'horizontal' | 'vertical' | undefined;
|
|
14
14
|
readonly navigationOnly?: boolean;
|
|
15
15
|
readonly selector?: string | undefined;
|
|
16
|
-
readonly skipVisibilityCheck?: boolean;
|
|
17
16
|
readonly typeahead?: boolean;
|
|
18
17
|
readonly wrap?: boolean;
|
|
19
18
|
}
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
59
59
|
composed = false,
|
|
60
60
|
filter,
|
|
61
61
|
include,
|
|
62
|
+
skipNegativeTabIndexCheck = false,
|
|
62
63
|
skipVisibilityCheck = false
|
|
63
64
|
} = options;
|
|
64
65
|
if (typeof composed !== "boolean") {
|
|
@@ -77,6 +78,10 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
77
78
|
);
|
|
78
79
|
include = void 0;
|
|
79
80
|
}
|
|
81
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
82
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
83
|
+
skipNegativeTabIndexCheck = false;
|
|
84
|
+
}
|
|
80
85
|
if (typeof skipVisibilityCheck !== "boolean") {
|
|
81
86
|
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
82
87
|
skipVisibilityCheck = false;
|
|
@@ -85,7 +90,10 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
85
90
|
if (composed || include) {
|
|
86
91
|
let traverse2 = function(node) {
|
|
87
92
|
if (node instanceof Element) {
|
|
88
|
-
if (isFocusable(node, {
|
|
93
|
+
if (isFocusable(node, {
|
|
94
|
+
skipNegativeTabIndexCheck,
|
|
95
|
+
skipVisibilityCheck
|
|
96
|
+
}) || include?.(node)) {
|
|
89
97
|
elements[elements.length] = node;
|
|
90
98
|
}
|
|
91
99
|
}
|
|
@@ -106,7 +114,10 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
106
114
|
if (!(candidate instanceof Element)) {
|
|
107
115
|
continue;
|
|
108
116
|
}
|
|
109
|
-
if (isFocusable(candidate, {
|
|
117
|
+
if (isFocusable(candidate, {
|
|
118
|
+
skipNegativeTabIndexCheck,
|
|
119
|
+
skipVisibilityCheck
|
|
120
|
+
})) {
|
|
110
121
|
elements[elements.length] = candidate;
|
|
111
122
|
}
|
|
112
123
|
}
|
|
@@ -119,7 +130,11 @@ function isFocusable(element, options = {}) {
|
|
|
119
130
|
console.warn("Invalid element");
|
|
120
131
|
return false;
|
|
121
132
|
}
|
|
122
|
-
let { skipVisibilityCheck = false } = options;
|
|
133
|
+
let { skipNegativeTabIndexCheck = false, skipVisibilityCheck = false } = options;
|
|
134
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
135
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
136
|
+
skipNegativeTabIndexCheck = false;
|
|
137
|
+
}
|
|
123
138
|
if (typeof skipVisibilityCheck !== "boolean") {
|
|
124
139
|
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
125
140
|
skipVisibilityCheck = false;
|
|
@@ -127,10 +142,12 @@ function isFocusable(element, options = {}) {
|
|
|
127
142
|
if (element.hasAttribute("hidden") || isInert(element)) {
|
|
128
143
|
return false;
|
|
129
144
|
}
|
|
130
|
-
if (getTabIndex(element) < 0) {
|
|
145
|
+
if (!skipNegativeTabIndexCheck && getTabIndex(element) < 0) {
|
|
131
146
|
return false;
|
|
132
147
|
}
|
|
133
|
-
if (!element.matches(
|
|
148
|
+
if (!element.matches(
|
|
149
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR.replace(/(,\s*)?\[tabindex="-1"\]/g, "") : FOCUSABLE_SELECTOR
|
|
150
|
+
)) {
|
|
134
151
|
return false;
|
|
135
152
|
}
|
|
136
153
|
if (isDisabledDeep(element)) {
|
|
@@ -282,7 +299,6 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
282
299
|
direction,
|
|
283
300
|
navigationOnly = false,
|
|
284
301
|
selector,
|
|
285
|
-
skipVisibilityCheck = false,
|
|
286
302
|
typeahead = false,
|
|
287
303
|
wrap = false
|
|
288
304
|
} = options;
|
|
@@ -300,10 +316,6 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
300
316
|
);
|
|
301
317
|
selector = void 0;
|
|
302
318
|
}
|
|
303
|
-
if (typeof skipVisibilityCheck !== "boolean") {
|
|
304
|
-
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
305
|
-
skipVisibilityCheck = false;
|
|
306
|
-
}
|
|
307
319
|
if (typeof typeahead !== "boolean") {
|
|
308
320
|
console.warn("Invalid typeahead option. Fallback: false.");
|
|
309
321
|
typeahead = false;
|
|
@@ -316,7 +328,6 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
316
328
|
direction,
|
|
317
329
|
navigationOnly,
|
|
318
330
|
selector,
|
|
319
|
-
skipVisibilityCheck,
|
|
320
331
|
typeahead,
|
|
321
332
|
wrap
|
|
322
333
|
});
|
|
@@ -430,7 +441,7 @@ var RovingTabIndex = class {
|
|
|
430
441
|
...getFocusables(this.#container, {
|
|
431
442
|
composed: true,
|
|
432
443
|
filter: this.#selectorFilter,
|
|
433
|
-
|
|
444
|
+
skipNegativeTabIndexCheck: !this.#options.navigationOnly
|
|
434
445
|
})
|
|
435
446
|
]);
|
|
436
447
|
for (const focusable of this.#focusables) {
|
|
@@ -496,8 +507,7 @@ var RovingTabIndex = class {
|
|
|
496
507
|
return getFocusables(this.#container, {
|
|
497
508
|
composed: true,
|
|
498
509
|
filter: this.#selectorFilter,
|
|
499
|
-
|
|
500
|
-
skipVisibilityCheck: !!this.#options.skipVisibilityCheck
|
|
510
|
+
skipNegativeTabIndexCheck: !this.#options.navigationOnly
|
|
501
511
|
});
|
|
502
512
|
}
|
|
503
513
|
};
|
|
@@ -516,7 +526,7 @@ function getActiveElement() {
|
|
|
516
526
|
* Lightweight roving tabindex utility with fully focus management.
|
|
517
527
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
518
528
|
*
|
|
519
|
-
* @version
|
|
529
|
+
* @version 2.0.0
|
|
520
530
|
* @author Yusuke Kamiyamane
|
|
521
531
|
* @license MIT
|
|
522
532
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -541,7 +551,7 @@ power-focusable/dist/index.js:
|
|
|
541
551
|
* High-precision focus management utility with full composed tree support.
|
|
542
552
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
543
553
|
*
|
|
544
|
-
* @version 4.
|
|
554
|
+
* @version 4.3.0
|
|
545
555
|
* @author Yusuke Kamiyamane
|
|
546
556
|
* @license MIT
|
|
547
557
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y14e/roving-tabindex",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Lightweight roving tabindex utility with fully focus management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@y14e/attributes-utils": "^1.0.5",
|
|
52
52
|
"bun-types": "latest",
|
|
53
|
-
"power-focusable": "^4.
|
|
53
|
+
"power-focusable": "^4.3.0",
|
|
54
54
|
"tsup": "^8.0.0",
|
|
55
55
|
"typescript": "^5.6.0"
|
|
56
56
|
},
|