@y14e/roving-tabindex 1.2.2 → 1.2.4
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/dist/index.cjs +34 -35
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +34 -35
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,23 +1,28 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// node_modules/@y14e/attributes-utils/dist/index.js
|
|
4
|
+
var defaultParser = (value) => value.split(/\s+/);
|
|
5
|
+
var defaultSerializer = (tokens) => tokens.join(" ");
|
|
4
6
|
function addTokenToAttribute(element, attribute, token, options = {}) {
|
|
5
|
-
const {
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
const {
|
|
8
|
+
caseInsensitive = false,
|
|
9
|
+
parse = defaultParser,
|
|
10
|
+
serialize = defaultSerializer
|
|
11
|
+
} = options;
|
|
12
|
+
const raw = element.getAttribute(attribute)?.trim();
|
|
13
|
+
const tokens = raw ? parse(raw).filter(Boolean) : [];
|
|
8
14
|
if (caseInsensitive) {
|
|
9
15
|
const lower = token.toLowerCase();
|
|
10
16
|
if (tokens.some((token2) => token2.toLowerCase() === lower)) {
|
|
11
17
|
return;
|
|
12
18
|
}
|
|
13
19
|
tokens.push(token);
|
|
14
|
-
element.setAttribute(attribute, tokens
|
|
20
|
+
element.setAttribute(attribute, serialize(tokens));
|
|
15
21
|
return;
|
|
16
22
|
}
|
|
17
23
|
const set = new Set(tokens);
|
|
18
24
|
set.add(token);
|
|
19
|
-
element.setAttribute(attribute, [...set]
|
|
20
|
-
return;
|
|
25
|
+
element.setAttribute(attribute, serialize([...set]));
|
|
21
26
|
}
|
|
22
27
|
var snapshots = /* @__PURE__ */ new WeakMap();
|
|
23
28
|
function restoreAttributes(elements) {
|
|
@@ -27,11 +32,7 @@ function restoreAttributes(elements) {
|
|
|
27
32
|
continue;
|
|
28
33
|
}
|
|
29
34
|
for (const [attribute, value] of snapshot.entries()) {
|
|
30
|
-
|
|
31
|
-
element.removeAttribute(attribute);
|
|
32
|
-
} else {
|
|
33
|
-
element.setAttribute(attribute, value);
|
|
34
|
-
}
|
|
35
|
+
value === null ? element.removeAttribute(attribute) : element.setAttribute(attribute, value);
|
|
35
36
|
}
|
|
36
37
|
snapshots.delete(element);
|
|
37
38
|
}
|
|
@@ -337,10 +338,8 @@ var RovingTabIndex = class {
|
|
|
337
338
|
"Home",
|
|
338
339
|
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
339
340
|
...isBoth ? ["ArrowRight", "ArrowDown"] : [`Arrow${isHorizontal ? "Right" : "Down"}`]
|
|
340
|
-
].includes(key)) {
|
|
341
|
-
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
341
|
+
].includes(key) && (!typeahead || !/^\S$/i.test(key) || !this.#focusablesByFirstChar.has(key.toUpperCase()))) {
|
|
342
|
+
return;
|
|
344
343
|
}
|
|
345
344
|
const active = getActiveElement();
|
|
346
345
|
if (!(active instanceof HTMLElement)) {
|
|
@@ -392,7 +391,7 @@ var RovingTabIndex = class {
|
|
|
392
391
|
focusElement(focusable);
|
|
393
392
|
};
|
|
394
393
|
#update(active) {
|
|
395
|
-
const
|
|
394
|
+
const focusables = /* @__PURE__ */ new Set([
|
|
396
395
|
...this.#getFocusables(),
|
|
397
396
|
...getFocusables(this.#container, {
|
|
398
397
|
composed: true,
|
|
@@ -400,46 +399,46 @@ var RovingTabIndex = class {
|
|
|
400
399
|
})
|
|
401
400
|
]);
|
|
402
401
|
for (const focusable of this.#focusables) {
|
|
403
|
-
if (
|
|
402
|
+
if (focusables.has(focusable)) {
|
|
404
403
|
continue;
|
|
405
404
|
}
|
|
406
405
|
if (focusable.isConnected) {
|
|
407
406
|
restoreAttributes([focusable]);
|
|
408
407
|
}
|
|
409
408
|
this.#focusables.delete(focusable);
|
|
410
|
-
this.#focusablesByFirstChar.forEach((
|
|
411
|
-
const index =
|
|
409
|
+
this.#focusablesByFirstChar.forEach((focusables2) => {
|
|
410
|
+
const index = focusables2.indexOf(focusable);
|
|
412
411
|
if (index !== -1) {
|
|
413
|
-
|
|
412
|
+
focusables2.splice(index, 1);
|
|
414
413
|
}
|
|
415
414
|
});
|
|
416
415
|
}
|
|
417
|
-
for (const
|
|
418
|
-
if (this.#focusables.has(
|
|
416
|
+
for (const focusable of focusables) {
|
|
417
|
+
if (this.#focusables.has(focusable)) {
|
|
419
418
|
continue;
|
|
420
419
|
}
|
|
421
|
-
this.#focusables.add(
|
|
422
|
-
saveAttributes([
|
|
423
|
-
|
|
420
|
+
this.#focusables.add(focusable);
|
|
421
|
+
saveAttributes([focusable], ["tabindex"]);
|
|
422
|
+
focusable.setAttribute("tabindex", "-1");
|
|
424
423
|
if (!this.#options.typeahead) {
|
|
425
424
|
continue;
|
|
426
425
|
}
|
|
427
|
-
const
|
|
426
|
+
const raw = focusable.ariaKeyShortcuts?.trim();
|
|
428
427
|
const keys = new Set(
|
|
429
|
-
|
|
428
|
+
raw ? raw.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
|
|
430
429
|
);
|
|
431
|
-
const char =
|
|
430
|
+
const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
|
|
432
431
|
if (char) {
|
|
433
432
|
keys.add(char);
|
|
434
|
-
saveAttributes([
|
|
435
|
-
addTokenToAttribute(
|
|
433
|
+
saveAttributes([focusable], ["aria-keyshortcuts"]);
|
|
434
|
+
addTokenToAttribute(focusable, "aria-keyshortcuts", char, {
|
|
436
435
|
caseInsensitive: true
|
|
437
436
|
});
|
|
438
437
|
}
|
|
439
438
|
keys.forEach((key) => {
|
|
440
|
-
const
|
|
441
|
-
|
|
442
|
-
this.#focusablesByFirstChar.set(key,
|
|
439
|
+
const focusables2 = this.#focusablesByFirstChar.get(key) ?? [];
|
|
440
|
+
focusables2.push(focusable);
|
|
441
|
+
this.#focusablesByFirstChar.set(key, focusables2);
|
|
443
442
|
});
|
|
444
443
|
}
|
|
445
444
|
if (active && this.#focusables.has(active)) {
|
|
@@ -479,7 +478,7 @@ function getActiveElement() {
|
|
|
479
478
|
* Lightweight roving tabindex utility with fully focus management.
|
|
480
479
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
481
480
|
*
|
|
482
|
-
* @version 1.2.
|
|
481
|
+
* @version 1.2.4
|
|
483
482
|
* @author Yusuke Kamiyamane
|
|
484
483
|
* @license MIT
|
|
485
484
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -491,7 +490,7 @@ function getActiveElement() {
|
|
|
491
490
|
(**
|
|
492
491
|
* Attributes Utils
|
|
493
492
|
*
|
|
494
|
-
* @version 1.0.
|
|
493
|
+
* @version 1.0.4
|
|
495
494
|
* @author Yusuke Kamiyamane
|
|
496
495
|
* @license MIT
|
|
497
496
|
* @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 1.2.
|
|
6
|
+
* @version 1.2.4
|
|
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 1.2.
|
|
6
|
+
* @version 1.2.4
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.js
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
// node_modules/@y14e/attributes-utils/dist/index.js
|
|
2
|
+
var defaultParser = (value) => value.split(/\s+/);
|
|
3
|
+
var defaultSerializer = (tokens) => tokens.join(" ");
|
|
2
4
|
function addTokenToAttribute(element, attribute, token, options = {}) {
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
const {
|
|
6
|
+
caseInsensitive = false,
|
|
7
|
+
parse = defaultParser,
|
|
8
|
+
serialize = defaultSerializer
|
|
9
|
+
} = options;
|
|
10
|
+
const raw = element.getAttribute(attribute)?.trim();
|
|
11
|
+
const tokens = raw ? parse(raw).filter(Boolean) : [];
|
|
6
12
|
if (caseInsensitive) {
|
|
7
13
|
const lower = token.toLowerCase();
|
|
8
14
|
if (tokens.some((token2) => token2.toLowerCase() === lower)) {
|
|
9
15
|
return;
|
|
10
16
|
}
|
|
11
17
|
tokens.push(token);
|
|
12
|
-
element.setAttribute(attribute, tokens
|
|
18
|
+
element.setAttribute(attribute, serialize(tokens));
|
|
13
19
|
return;
|
|
14
20
|
}
|
|
15
21
|
const set = new Set(tokens);
|
|
16
22
|
set.add(token);
|
|
17
|
-
element.setAttribute(attribute, [...set]
|
|
18
|
-
return;
|
|
23
|
+
element.setAttribute(attribute, serialize([...set]));
|
|
19
24
|
}
|
|
20
25
|
var snapshots = /* @__PURE__ */ new WeakMap();
|
|
21
26
|
function restoreAttributes(elements) {
|
|
@@ -25,11 +30,7 @@ function restoreAttributes(elements) {
|
|
|
25
30
|
continue;
|
|
26
31
|
}
|
|
27
32
|
for (const [attribute, value] of snapshot.entries()) {
|
|
28
|
-
|
|
29
|
-
element.removeAttribute(attribute);
|
|
30
|
-
} else {
|
|
31
|
-
element.setAttribute(attribute, value);
|
|
32
|
-
}
|
|
33
|
+
value === null ? element.removeAttribute(attribute) : element.setAttribute(attribute, value);
|
|
33
34
|
}
|
|
34
35
|
snapshots.delete(element);
|
|
35
36
|
}
|
|
@@ -335,10 +336,8 @@ var RovingTabIndex = class {
|
|
|
335
336
|
"Home",
|
|
336
337
|
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
337
338
|
...isBoth ? ["ArrowRight", "ArrowDown"] : [`Arrow${isHorizontal ? "Right" : "Down"}`]
|
|
338
|
-
].includes(key)) {
|
|
339
|
-
|
|
340
|
-
return;
|
|
341
|
-
}
|
|
339
|
+
].includes(key) && (!typeahead || !/^\S$/i.test(key) || !this.#focusablesByFirstChar.has(key.toUpperCase()))) {
|
|
340
|
+
return;
|
|
342
341
|
}
|
|
343
342
|
const active = getActiveElement();
|
|
344
343
|
if (!(active instanceof HTMLElement)) {
|
|
@@ -390,7 +389,7 @@ var RovingTabIndex = class {
|
|
|
390
389
|
focusElement(focusable);
|
|
391
390
|
};
|
|
392
391
|
#update(active) {
|
|
393
|
-
const
|
|
392
|
+
const focusables = /* @__PURE__ */ new Set([
|
|
394
393
|
...this.#getFocusables(),
|
|
395
394
|
...getFocusables(this.#container, {
|
|
396
395
|
composed: true,
|
|
@@ -398,46 +397,46 @@ var RovingTabIndex = class {
|
|
|
398
397
|
})
|
|
399
398
|
]);
|
|
400
399
|
for (const focusable of this.#focusables) {
|
|
401
|
-
if (
|
|
400
|
+
if (focusables.has(focusable)) {
|
|
402
401
|
continue;
|
|
403
402
|
}
|
|
404
403
|
if (focusable.isConnected) {
|
|
405
404
|
restoreAttributes([focusable]);
|
|
406
405
|
}
|
|
407
406
|
this.#focusables.delete(focusable);
|
|
408
|
-
this.#focusablesByFirstChar.forEach((
|
|
409
|
-
const index =
|
|
407
|
+
this.#focusablesByFirstChar.forEach((focusables2) => {
|
|
408
|
+
const index = focusables2.indexOf(focusable);
|
|
410
409
|
if (index !== -1) {
|
|
411
|
-
|
|
410
|
+
focusables2.splice(index, 1);
|
|
412
411
|
}
|
|
413
412
|
});
|
|
414
413
|
}
|
|
415
|
-
for (const
|
|
416
|
-
if (this.#focusables.has(
|
|
414
|
+
for (const focusable of focusables) {
|
|
415
|
+
if (this.#focusables.has(focusable)) {
|
|
417
416
|
continue;
|
|
418
417
|
}
|
|
419
|
-
this.#focusables.add(
|
|
420
|
-
saveAttributes([
|
|
421
|
-
|
|
418
|
+
this.#focusables.add(focusable);
|
|
419
|
+
saveAttributes([focusable], ["tabindex"]);
|
|
420
|
+
focusable.setAttribute("tabindex", "-1");
|
|
422
421
|
if (!this.#options.typeahead) {
|
|
423
422
|
continue;
|
|
424
423
|
}
|
|
425
|
-
const
|
|
424
|
+
const raw = focusable.ariaKeyShortcuts?.trim();
|
|
426
425
|
const keys = new Set(
|
|
427
|
-
|
|
426
|
+
raw ? raw.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
|
|
428
427
|
);
|
|
429
|
-
const char =
|
|
428
|
+
const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
|
|
430
429
|
if (char) {
|
|
431
430
|
keys.add(char);
|
|
432
|
-
saveAttributes([
|
|
433
|
-
addTokenToAttribute(
|
|
431
|
+
saveAttributes([focusable], ["aria-keyshortcuts"]);
|
|
432
|
+
addTokenToAttribute(focusable, "aria-keyshortcuts", char, {
|
|
434
433
|
caseInsensitive: true
|
|
435
434
|
});
|
|
436
435
|
}
|
|
437
436
|
keys.forEach((key) => {
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
this.#focusablesByFirstChar.set(key,
|
|
437
|
+
const focusables2 = this.#focusablesByFirstChar.get(key) ?? [];
|
|
438
|
+
focusables2.push(focusable);
|
|
439
|
+
this.#focusablesByFirstChar.set(key, focusables2);
|
|
441
440
|
});
|
|
442
441
|
}
|
|
443
442
|
if (active && this.#focusables.has(active)) {
|
|
@@ -477,7 +476,7 @@ function getActiveElement() {
|
|
|
477
476
|
* Lightweight roving tabindex utility with fully focus management.
|
|
478
477
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
479
478
|
*
|
|
480
|
-
* @version 1.2.
|
|
479
|
+
* @version 1.2.4
|
|
481
480
|
* @author Yusuke Kamiyamane
|
|
482
481
|
* @license MIT
|
|
483
482
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -489,7 +488,7 @@ function getActiveElement() {
|
|
|
489
488
|
(**
|
|
490
489
|
* Attributes Utils
|
|
491
490
|
*
|
|
492
|
-
* @version 1.0.
|
|
491
|
+
* @version 1.0.4
|
|
493
492
|
* @author Yusuke Kamiyamane
|
|
494
493
|
* @license MIT
|
|
495
494
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y14e/roving-tabindex",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
4
4
|
"description": "Lightweight roving tabindex utility with fully focus management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
},
|
|
49
49
|
"homepage": "https://github.com/y14e/roving-tabindex#readme",
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@y14e/attributes-utils": "^1.0.
|
|
51
|
+
"@y14e/attributes-utils": "^1.0.4",
|
|
52
52
|
"bun-types": "latest",
|
|
53
53
|
"power-focusable": "^4.1.7",
|
|
54
54
|
"tsup": "^8.0.0",
|