@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 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 { caseInsensitive = false } = options;
6
- const value = element.getAttribute(attribute)?.trim();
7
- const tokens = value ? value.split(/\s+/) : [];
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.join(" "));
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].join(" "));
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
- if (value === null) {
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
- if (!typeahead || !/^\S$/i.test(key) || !this.#focusablesByFirstChar.has(key.toUpperCase())) {
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 current = /* @__PURE__ */ new Set([
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 (current.has(focusable)) {
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((focusables) => {
411
- const index = focusables.indexOf(focusable);
409
+ this.#focusablesByFirstChar.forEach((focusables2) => {
410
+ const index = focusables2.indexOf(focusable);
412
411
  if (index !== -1) {
413
- focusables.splice(index, 1);
412
+ focusables2.splice(index, 1);
414
413
  }
415
414
  });
416
415
  }
417
- for (const c of current) {
418
- if (this.#focusables.has(c)) {
416
+ for (const focusable of focusables) {
417
+ if (this.#focusables.has(focusable)) {
419
418
  continue;
420
419
  }
421
- this.#focusables.add(c);
422
- saveAttributes([c], ["tabindex"]);
423
- c.setAttribute("tabindex", "-1");
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 shortcuts = c.ariaKeyShortcuts?.trim() ?? "";
426
+ const raw = focusable.ariaKeyShortcuts?.trim();
428
427
  const keys = new Set(
429
- shortcuts ? shortcuts.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
428
+ raw ? raw.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
430
429
  );
431
- const char = c.textContent?.trim()?.at(0)?.toUpperCase();
430
+ const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
432
431
  if (char) {
433
432
  keys.add(char);
434
- saveAttributes([c], ["aria-keyshortcuts"]);
435
- addTokenToAttribute(c, "aria-keyshortcuts", char, {
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 focusables = this.#focusablesByFirstChar.get(key) ?? [];
441
- focusables.push(c);
442
- this.#focusablesByFirstChar.set(key, focusables);
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.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.3
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.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.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 { caseInsensitive = false } = options;
4
- const value = element.getAttribute(attribute)?.trim();
5
- const tokens = value ? value.split(/\s+/) : [];
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.join(" "));
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].join(" "));
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
- if (value === null) {
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
- if (!typeahead || !/^\S$/i.test(key) || !this.#focusablesByFirstChar.has(key.toUpperCase())) {
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 current = /* @__PURE__ */ new Set([
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 (current.has(focusable)) {
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((focusables) => {
409
- const index = focusables.indexOf(focusable);
407
+ this.#focusablesByFirstChar.forEach((focusables2) => {
408
+ const index = focusables2.indexOf(focusable);
410
409
  if (index !== -1) {
411
- focusables.splice(index, 1);
410
+ focusables2.splice(index, 1);
412
411
  }
413
412
  });
414
413
  }
415
- for (const c of current) {
416
- if (this.#focusables.has(c)) {
414
+ for (const focusable of focusables) {
415
+ if (this.#focusables.has(focusable)) {
417
416
  continue;
418
417
  }
419
- this.#focusables.add(c);
420
- saveAttributes([c], ["tabindex"]);
421
- c.setAttribute("tabindex", "-1");
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 shortcuts = c.ariaKeyShortcuts?.trim() ?? "";
424
+ const raw = focusable.ariaKeyShortcuts?.trim();
426
425
  const keys = new Set(
427
- shortcuts ? shortcuts.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
426
+ raw ? raw.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
428
427
  );
429
- const char = c.textContent?.trim()?.at(0)?.toUpperCase();
428
+ const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
430
429
  if (char) {
431
430
  keys.add(char);
432
- saveAttributes([c], ["aria-keyshortcuts"]);
433
- addTokenToAttribute(c, "aria-keyshortcuts", char, {
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 focusables = this.#focusablesByFirstChar.get(key) ?? [];
439
- focusables.push(c);
440
- this.#focusablesByFirstChar.set(key, focusables);
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.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.3
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.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.3",
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",