@y14e/tabs 2.0.8 → 2.0.10

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 CHANGED
@@ -10,14 +10,14 @@ npm i @y14e/tabs
10
10
 
11
11
  ```ts
12
12
  // npm
13
- import Tabs from '@y14e/tabs';
13
+ import Tabs from "@y14e/tabs";
14
14
 
15
15
  // CDNs
16
- import Tabs from 'https://esm.sh/@y14e/tabs@2.0.8';
16
+ import Tabs from "https://esm.sh/@y14e/tabs@2.0.10";
17
17
  // or
18
- import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@2.0.8/+esm';
18
+ import Tabs from "https://cdn.jsdelivr.net/npm/@y14e/tabs@2.0.10/+esm";
19
19
  // or
20
- import Tabs from 'https://esm.unpkg.com/@y14e/tabs@2.0.8';
20
+ import Tabs from "https://esm.unpkg.com/@y14e/tabs@2.0.10";
21
21
  ```
22
22
 
23
23
  ## Usage
@@ -36,26 +36,26 @@ new Tabs(root, options);
36
36
  interface TabsOptions {
37
37
  animation: {
38
38
  content: {
39
- crossFade: boolean; // default: true
40
- duration: number; // ms (default: 300)
41
- easing: string; // <easing-function> (default: 'ease')
42
- fade: boolean; // default: true
39
+ crossFade: boolean; // default: true
40
+ duration: number; // ms (default: 300)
41
+ easing: string; // <easing-function> (default: 'ease')
42
+ fade: boolean; // default: true
43
43
  };
44
44
  indicator: {
45
- duration: number; // ms (default: 300)
46
- easing: string; // <easing-function> (default: 'ease')
45
+ duration: number; // ms (default: 300)
46
+ easing: string; // <easing-function> (default: 'ease')
47
47
  };
48
48
  };
49
49
  avoidDuplicates: boolean; // default: false
50
- manual: boolean; // default: false
50
+ manual: boolean; // default: false
51
51
  selector: {
52
- content: string; // default: '[role="tablist"] + *'
53
- indicator: string; // default: '[data-tabs-indicator]'
54
- list: string; // default: '[role="tablist"]'
55
- panel: string; // default: '[role="tabpanel"]'
56
- tab: string; // default: '[role="tab"]'
52
+ content: string; // default: '[role="tablist"] + *'
53
+ indicator: string; // default: '[data-tabs-indicator]'
54
+ list: string; // default: '[role="tablist"]'
55
+ panel: string; // default: '[role="tabpanel"]'
56
+ tab: string; // default: '[role="tab"]'
57
57
  };
58
- vertical: boolean; // default: false
58
+ vertical: boolean; // default: false
59
59
  }
60
60
  ```
61
61
 
@@ -68,7 +68,7 @@ If `true`, only the first tab list remains interactive; subsequent duplicates ar
68
68
  Override the global default settings applied to all accordion instances.
69
69
 
70
70
  ```ts
71
- import Tabs from '@y14e/tabs';
71
+ import Tabs from "@y14e/tabs";
72
72
 
73
73
  Tabs.defaults = {
74
74
  animation: {
@@ -76,7 +76,7 @@ Tabs.defaults = {
76
76
  crossFade: false,
77
77
  duration: 1000,
78
78
  fade: true,
79
- }
79
+ },
80
80
  },
81
81
  manual: true,
82
82
  };
@@ -3,8 +3,8 @@
3
3
  // node_modules/@y14e/attributes-utils/dist/index.js
4
4
  var DEFAULT_PARSER = (value) => value.split(/\s+/);
5
5
  var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
6
- function addTokenToAttribute(element, attribute, token, options = {}) {
7
- const value = element.getAttribute(attribute)?.trim();
6
+ function addAttributeToken(element, name, token, options = {}) {
7
+ const value = element.getAttribute(name)?.trim();
8
8
  const {
9
9
  caseInsensitive = false,
10
10
  parse = DEFAULT_PARSER,
@@ -15,12 +15,12 @@ function addTokenToAttribute(element, attribute, token, options = {}) {
15
15
  const lower = token.toLowerCase();
16
16
  if (tokens.every((token2) => token2.toLowerCase() !== lower)) {
17
17
  tokens.push(token);
18
- element.setAttribute(attribute, serialize(tokens));
18
+ element.setAttribute(name, serialize(tokens));
19
19
  }
20
20
  } else {
21
21
  const set = new Set(tokens);
22
22
  set.add(token);
23
- element.setAttribute(attribute, serialize([...set]));
23
+ element.setAttribute(name, serialize([...set]));
24
24
  }
25
25
  }
26
26
  var snapshots = /* @__PURE__ */ new WeakMap();
@@ -30,25 +30,26 @@ function restoreAttributes(element_or_elements) {
30
30
  if (!snapshot) {
31
31
  continue;
32
32
  }
33
- for (const [attribute, value] of snapshot.entries()) {
34
- value === null ? element.removeAttribute(attribute) : element.setAttribute(attribute, value);
33
+ for (const [name, value] of snapshot.entries()) {
34
+ value === null ? element.removeAttribute(name) : element.setAttribute(name, value);
35
35
  }
36
36
  snapshots.delete(element);
37
37
  }
38
38
  }
39
- function saveAttributes(element_or_elements, attribute_or_attributes) {
40
- const attributes = Array.isArray(attribute_or_attributes) ? attribute_or_attributes : [attribute_or_attributes];
39
+ function saveAttributes(element_or_elements, name_or_names) {
40
+ const names = Array.isArray(name_or_names) ? name_or_names : [name_or_names];
41
41
  (Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]).forEach((element) => {
42
42
  let snapshot = snapshots.get(element);
43
43
  if (!snapshot) {
44
44
  snapshot = /* @__PURE__ */ new Map();
45
45
  snapshots.set(element, snapshot);
46
46
  }
47
- attributes.forEach((attribute) => {
48
- snapshot.set(attribute, element.getAttribute(attribute));
47
+ names.forEach((name) => {
48
+ snapshot.set(name, element.getAttribute(name));
49
49
  });
50
50
  });
51
51
  }
52
+ var addTokenToAttribute = addAttributeToken;
52
53
 
53
54
  // node_modules/power-focusable/dist/index.js
54
55
  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"])`;
@@ -368,6 +369,56 @@ var Button = class {
368
369
  };
369
370
  };
370
371
 
372
+ // node_modules/@y14e/roving-tabindex/node_modules/@y14e/attributes-utils/dist/index.js
373
+ var DEFAULT_PARSER2 = (value) => value.split(/\s+/);
374
+ var DEFAULT_SERIALIZER2 = (tokens) => tokens.join(" ");
375
+ function addTokenToAttribute2(element, name, token, options = {}) {
376
+ const value = element.getAttribute(name)?.trim();
377
+ const {
378
+ caseInsensitive = false,
379
+ parse = DEFAULT_PARSER2,
380
+ serialize = DEFAULT_SERIALIZER2
381
+ } = options;
382
+ const tokens = value ? parse(value).filter(Boolean) : [];
383
+ if (caseInsensitive) {
384
+ const lower = token.toLowerCase();
385
+ if (tokens.every((token2) => token2.toLowerCase() !== lower)) {
386
+ tokens.push(token);
387
+ element.setAttribute(name, serialize(tokens));
388
+ }
389
+ } else {
390
+ const set = new Set(tokens);
391
+ set.add(token);
392
+ element.setAttribute(name, serialize([...set]));
393
+ }
394
+ }
395
+ var snapshots2 = /* @__PURE__ */ new WeakMap();
396
+ function restoreAttributes2(element_or_elements) {
397
+ for (const element of Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]) {
398
+ const snapshot = snapshots2.get(element);
399
+ if (!snapshot) {
400
+ continue;
401
+ }
402
+ for (const [name, value] of snapshot.entries()) {
403
+ value === null ? element.removeAttribute(name) : element.setAttribute(name, value);
404
+ }
405
+ snapshots2.delete(element);
406
+ }
407
+ }
408
+ function saveAttributes2(element_or_elements, name_or_names) {
409
+ const names = Array.isArray(name_or_names) ? name_or_names : [name_or_names];
410
+ (Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]).forEach((element) => {
411
+ let snapshot = snapshots2.get(element);
412
+ if (!snapshot) {
413
+ snapshot = /* @__PURE__ */ new Map();
414
+ snapshots2.set(element, snapshot);
415
+ }
416
+ names.forEach((name) => {
417
+ snapshot.set(name, element.getAttribute(name));
418
+ });
419
+ });
420
+ }
421
+
371
422
  // node_modules/@y14e/roving-tabindex/dist/index.js
372
423
  function createRovingTabIndex(container, options = {}) {
373
424
  if (!(container instanceof Element)) {
@@ -415,17 +466,20 @@ var RovingTabIndex = class _RovingTabIndex {
415
466
  noStart = false;
416
467
  }
417
468
  if (selector !== "") {
469
+ let hasError = false;
418
470
  if (typeof selector !== "string" || !selector.trim()) {
419
- console.warn("Invalid selector. Fallback: no selector string.");
420
- selector = "";
471
+ hasError = true;
421
472
  } else {
422
473
  try {
423
- container.querySelector(selector);
474
+ this.#container.querySelector(selector);
424
475
  } catch {
425
- console.warn("Invalid selector. Fallback: no selector string.");
426
- selector = "";
476
+ hasError = true;
427
477
  }
428
478
  }
479
+ if (hasError) {
480
+ console.warn("Invalid selector. Fallback: no selector string.");
481
+ selector = "";
482
+ }
429
483
  }
430
484
  if (typeof typeahead !== "boolean") {
431
485
  console.warn("Invalid typeahead option. Fallback: false.");
@@ -456,7 +510,7 @@ var RovingTabIndex = class _RovingTabIndex {
456
510
  this.#controller = null;
457
511
  this.#focusables.forEach((focusable) => {
458
512
  _RovingTabIndex.#initialized.delete(focusable);
459
- restoreAttributes(focusable);
513
+ restoreAttributes2(focusable);
460
514
  });
461
515
  this.#focusables.clear();
462
516
  this.#focusablesByFirstChar.clear();
@@ -506,20 +560,20 @@ var RovingTabIndex = class _RovingTabIndex {
506
560
  return;
507
561
  }
508
562
  }
563
+ const candidates = this.#getFocusables().filter(
564
+ (focusable2) => this.#focusables.has(focusable2)
565
+ );
509
566
  const active = getActiveElement();
510
567
  if (!(active instanceof Element)) {
511
568
  return;
512
569
  }
513
- const candidates = this.#getFocusables().filter(
514
- (focusable2) => this.#focusables.has(focusable2)
515
- );
516
570
  if (!candidates.includes(active)) {
517
571
  return;
518
572
  }
519
573
  event.preventDefault();
520
- const activeIndex = candidates.indexOf(active);
521
574
  let newIndex;
522
- let target = candidates;
575
+ const activeIndex = candidates.indexOf(active);
576
+ let focusables = candidates;
523
577
  switch (key) {
524
578
  case "End":
525
579
  newIndex = -1;
@@ -536,22 +590,24 @@ var RovingTabIndex = class _RovingTabIndex {
536
590
  case "ArrowRight":
537
591
  case "ArrowDown": {
538
592
  const rawIndex = activeIndex + 1;
539
- const length = target.length;
593
+ const length = focusables.length;
540
594
  newIndex = wrap ? rawIndex % length : Math.min(rawIndex, length - 1);
541
595
  break;
542
596
  }
543
597
  default: {
544
- const focusables = new Set(
598
+ const focusablesByFirstChar = new Set(
545
599
  this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
546
600
  );
547
- target = candidates.filter((focusable2) => focusables.has(focusable2));
548
- const afterIndex = target.findIndex(
601
+ focusables = candidates.filter(
602
+ (candidate) => focusablesByFirstChar.has(candidate)
603
+ );
604
+ const afterIndex = focusables.findIndex(
549
605
  (focusable2) => candidates.indexOf(focusable2) > activeIndex
550
606
  );
551
607
  newIndex = afterIndex >= 0 ? afterIndex : 0;
552
608
  }
553
609
  }
554
- const focusable = target.at(newIndex);
610
+ const focusable = focusables.at(newIndex);
555
611
  focusable && focusElement(focusable);
556
612
  };
557
613
  #update(active) {
@@ -559,7 +615,7 @@ var RovingTabIndex = class _RovingTabIndex {
559
615
  for (const focusable of this.#focusables) {
560
616
  if (!current.has(focusable)) {
561
617
  _RovingTabIndex.#initialized.delete(focusable);
562
- restoreAttributes(focusable);
618
+ restoreAttributes2(focusable);
563
619
  this.#focusables.delete(focusable);
564
620
  for (const [key, focusables] of this.#focusablesByFirstChar) {
565
621
  const index = focusables.indexOf(focusable);
@@ -581,7 +637,7 @@ var RovingTabIndex = class _RovingTabIndex {
581
637
  this.#focusables.add(focusable);
582
638
  _RovingTabIndex.#initialized.add(focusable);
583
639
  if (!navigationOnly) {
584
- saveAttributes(focusable, "tabindex");
640
+ saveAttributes2(focusable, "tabindex");
585
641
  focusable.setAttribute("tabindex", "-1");
586
642
  }
587
643
  if (!typeahead) {
@@ -594,8 +650,8 @@ var RovingTabIndex = class _RovingTabIndex {
594
650
  );
595
651
  if (char) {
596
652
  keys.add(char);
597
- saveAttributes(focusable, "aria-keyshortcuts");
598
- addTokenToAttribute(focusable, "aria-keyshortcuts", char, {
653
+ saveAttributes2(focusable, "aria-keyshortcuts");
654
+ addTokenToAttribute2(focusable, "aria-keyshortcuts", char, {
599
655
  caseInsensitive: true
600
656
  });
601
657
  }
@@ -1038,7 +1094,7 @@ var Tabs = class _Tabs {
1038
1094
  tab && this.activate(tab, true);
1039
1095
  };
1040
1096
  #createBinding(tabs, panel) {
1041
- return { tabs, panel, animation: null };
1097
+ return { animation: null, panel, tabs };
1042
1098
  }
1043
1099
  #hasFocusable(container) {
1044
1100
  return !![
@@ -1116,13 +1172,13 @@ var TabsIndicator = class {
1116
1172
  if (!tab) {
1117
1173
  return;
1118
1174
  }
1119
- const { x: tabX, y: tabY, width, height } = tab.getBoundingClientRect();
1120
- const { x: listX, y: listY } = this.#listElement.getBoundingClientRect();
1175
+ const tabRect = tab.getBoundingClientRect();
1176
+ const listRect = this.#listElement.getBoundingClientRect();
1121
1177
  const { duration, easing } = this.#settings.animation.indicator;
1122
1178
  this.#animation = this.#rootElement.animate(
1123
1179
  {
1124
- [position]: `${isHorizontal ? tabX - listX : tabY - listY}px`,
1125
- [size]: `${isHorizontal ? width : height}px`
1180
+ [position]: `${isHorizontal ? tabRect.left - listRect.left : tabRect.top - listRect.top}px`,
1181
+ [size]: `${isHorizontal ? tabRect.width : tabRect.height}px`
1126
1182
  },
1127
1183
  { duration, easing, fill: "forwards" }
1128
1184
  );
@@ -1150,7 +1206,7 @@ var TabsIndicator = class {
1150
1206
  * Tabs
1151
1207
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
1152
1208
  *
1153
- * @version 2.0.8
1209
+ * @version 2.0.10
1154
1210
  * @author Yusuke Kamiyamane
1155
1211
  * @license MIT
1156
1212
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1162,7 +1218,7 @@ var TabsIndicator = class {
1162
1218
  (**
1163
1219
  * Attributes Utils
1164
1220
  *
1165
- * @version 1.1.4
1221
+ * @version 2.0.0
1166
1222
  * @author Yusuke Kamiyamane
1167
1223
  * @license MIT
1168
1224
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1175,7 +1231,7 @@ power-focusable/dist/index.js:
1175
1231
  * High-precision focus management utility with full composed tree support.
1176
1232
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1177
1233
  *
1178
- * @version 4.3.21
1234
+ * @version 4.3.23
1179
1235
  * @author Yusuke Kamiyamane
1180
1236
  * @license MIT
1181
1237
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1193,13 +1249,24 @@ power-focusable/dist/index.js:
1193
1249
  * @see {@link https://github.com/y14e/button}
1194
1250
  *)
1195
1251
 
1252
+ @y14e/attributes-utils/dist/index.js:
1253
+ (**
1254
+ * Attributes Utils
1255
+ *
1256
+ * @version 1.1.7
1257
+ * @author Yusuke Kamiyamane
1258
+ * @license MIT
1259
+ * @copyright Copyright (c) Yusuke Kamiyamane
1260
+ * @see {@link https://github.com/y14e/attributes-utils}
1261
+ *)
1262
+
1196
1263
  @y14e/roving-tabindex/dist/index.js:
1197
1264
  (**
1198
1265
  * Roving Tabindex
1199
1266
  * Lightweight roving tabindex utility with fully focus management.
1200
1267
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1201
1268
  *
1202
- * @version 3.1.18
1269
+ * @version 3.1.20
1203
1270
  * @author Yusuke Kamiyamane
1204
1271
  * @license MIT
1205
1272
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1,8 +1,8 @@
1
1
  // node_modules/@y14e/attributes-utils/dist/index.js
2
2
  var DEFAULT_PARSER = (value) => value.split(/\s+/);
3
3
  var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
4
- function addTokenToAttribute(element, attribute, token, options = {}) {
5
- const value = element.getAttribute(attribute)?.trim();
4
+ function addAttributeToken(element, name, token, options = {}) {
5
+ const value = element.getAttribute(name)?.trim();
6
6
  const {
7
7
  caseInsensitive = false,
8
8
  parse = DEFAULT_PARSER,
@@ -13,12 +13,12 @@ function addTokenToAttribute(element, attribute, token, options = {}) {
13
13
  const lower = token.toLowerCase();
14
14
  if (tokens.every((token2) => token2.toLowerCase() !== lower)) {
15
15
  tokens.push(token);
16
- element.setAttribute(attribute, serialize(tokens));
16
+ element.setAttribute(name, serialize(tokens));
17
17
  }
18
18
  } else {
19
19
  const set = new Set(tokens);
20
20
  set.add(token);
21
- element.setAttribute(attribute, serialize([...set]));
21
+ element.setAttribute(name, serialize([...set]));
22
22
  }
23
23
  }
24
24
  var snapshots = /* @__PURE__ */ new WeakMap();
@@ -28,25 +28,26 @@ function restoreAttributes(element_or_elements) {
28
28
  if (!snapshot) {
29
29
  continue;
30
30
  }
31
- for (const [attribute, value] of snapshot.entries()) {
32
- value === null ? element.removeAttribute(attribute) : element.setAttribute(attribute, value);
31
+ for (const [name, value] of snapshot.entries()) {
32
+ value === null ? element.removeAttribute(name) : element.setAttribute(name, value);
33
33
  }
34
34
  snapshots.delete(element);
35
35
  }
36
36
  }
37
- function saveAttributes(element_or_elements, attribute_or_attributes) {
38
- const attributes = Array.isArray(attribute_or_attributes) ? attribute_or_attributes : [attribute_or_attributes];
37
+ function saveAttributes(element_or_elements, name_or_names) {
38
+ const names = Array.isArray(name_or_names) ? name_or_names : [name_or_names];
39
39
  (Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]).forEach((element) => {
40
40
  let snapshot = snapshots.get(element);
41
41
  if (!snapshot) {
42
42
  snapshot = /* @__PURE__ */ new Map();
43
43
  snapshots.set(element, snapshot);
44
44
  }
45
- attributes.forEach((attribute) => {
46
- snapshot.set(attribute, element.getAttribute(attribute));
45
+ names.forEach((name) => {
46
+ snapshot.set(name, element.getAttribute(name));
47
47
  });
48
48
  });
49
49
  }
50
+ var addTokenToAttribute = addAttributeToken;
50
51
 
51
52
  // node_modules/power-focusable/dist/index.js
52
53
  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"])`;
@@ -366,6 +367,56 @@ var Button = class {
366
367
  };
367
368
  };
368
369
 
370
+ // node_modules/@y14e/roving-tabindex/node_modules/@y14e/attributes-utils/dist/index.js
371
+ var DEFAULT_PARSER2 = (value) => value.split(/\s+/);
372
+ var DEFAULT_SERIALIZER2 = (tokens) => tokens.join(" ");
373
+ function addTokenToAttribute2(element, name, token, options = {}) {
374
+ const value = element.getAttribute(name)?.trim();
375
+ const {
376
+ caseInsensitive = false,
377
+ parse = DEFAULT_PARSER2,
378
+ serialize = DEFAULT_SERIALIZER2
379
+ } = options;
380
+ const tokens = value ? parse(value).filter(Boolean) : [];
381
+ if (caseInsensitive) {
382
+ const lower = token.toLowerCase();
383
+ if (tokens.every((token2) => token2.toLowerCase() !== lower)) {
384
+ tokens.push(token);
385
+ element.setAttribute(name, serialize(tokens));
386
+ }
387
+ } else {
388
+ const set = new Set(tokens);
389
+ set.add(token);
390
+ element.setAttribute(name, serialize([...set]));
391
+ }
392
+ }
393
+ var snapshots2 = /* @__PURE__ */ new WeakMap();
394
+ function restoreAttributes2(element_or_elements) {
395
+ for (const element of Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]) {
396
+ const snapshot = snapshots2.get(element);
397
+ if (!snapshot) {
398
+ continue;
399
+ }
400
+ for (const [name, value] of snapshot.entries()) {
401
+ value === null ? element.removeAttribute(name) : element.setAttribute(name, value);
402
+ }
403
+ snapshots2.delete(element);
404
+ }
405
+ }
406
+ function saveAttributes2(element_or_elements, name_or_names) {
407
+ const names = Array.isArray(name_or_names) ? name_or_names : [name_or_names];
408
+ (Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]).forEach((element) => {
409
+ let snapshot = snapshots2.get(element);
410
+ if (!snapshot) {
411
+ snapshot = /* @__PURE__ */ new Map();
412
+ snapshots2.set(element, snapshot);
413
+ }
414
+ names.forEach((name) => {
415
+ snapshot.set(name, element.getAttribute(name));
416
+ });
417
+ });
418
+ }
419
+
369
420
  // node_modules/@y14e/roving-tabindex/dist/index.js
370
421
  function createRovingTabIndex(container, options = {}) {
371
422
  if (!(container instanceof Element)) {
@@ -413,17 +464,20 @@ var RovingTabIndex = class _RovingTabIndex {
413
464
  noStart = false;
414
465
  }
415
466
  if (selector !== "") {
467
+ let hasError = false;
416
468
  if (typeof selector !== "string" || !selector.trim()) {
417
- console.warn("Invalid selector. Fallback: no selector string.");
418
- selector = "";
469
+ hasError = true;
419
470
  } else {
420
471
  try {
421
- container.querySelector(selector);
472
+ this.#container.querySelector(selector);
422
473
  } catch {
423
- console.warn("Invalid selector. Fallback: no selector string.");
424
- selector = "";
474
+ hasError = true;
425
475
  }
426
476
  }
477
+ if (hasError) {
478
+ console.warn("Invalid selector. Fallback: no selector string.");
479
+ selector = "";
480
+ }
427
481
  }
428
482
  if (typeof typeahead !== "boolean") {
429
483
  console.warn("Invalid typeahead option. Fallback: false.");
@@ -454,7 +508,7 @@ var RovingTabIndex = class _RovingTabIndex {
454
508
  this.#controller = null;
455
509
  this.#focusables.forEach((focusable) => {
456
510
  _RovingTabIndex.#initialized.delete(focusable);
457
- restoreAttributes(focusable);
511
+ restoreAttributes2(focusable);
458
512
  });
459
513
  this.#focusables.clear();
460
514
  this.#focusablesByFirstChar.clear();
@@ -504,20 +558,20 @@ var RovingTabIndex = class _RovingTabIndex {
504
558
  return;
505
559
  }
506
560
  }
561
+ const candidates = this.#getFocusables().filter(
562
+ (focusable2) => this.#focusables.has(focusable2)
563
+ );
507
564
  const active = getActiveElement();
508
565
  if (!(active instanceof Element)) {
509
566
  return;
510
567
  }
511
- const candidates = this.#getFocusables().filter(
512
- (focusable2) => this.#focusables.has(focusable2)
513
- );
514
568
  if (!candidates.includes(active)) {
515
569
  return;
516
570
  }
517
571
  event.preventDefault();
518
- const activeIndex = candidates.indexOf(active);
519
572
  let newIndex;
520
- let target = candidates;
573
+ const activeIndex = candidates.indexOf(active);
574
+ let focusables = candidates;
521
575
  switch (key) {
522
576
  case "End":
523
577
  newIndex = -1;
@@ -534,22 +588,24 @@ var RovingTabIndex = class _RovingTabIndex {
534
588
  case "ArrowRight":
535
589
  case "ArrowDown": {
536
590
  const rawIndex = activeIndex + 1;
537
- const length = target.length;
591
+ const length = focusables.length;
538
592
  newIndex = wrap ? rawIndex % length : Math.min(rawIndex, length - 1);
539
593
  break;
540
594
  }
541
595
  default: {
542
- const focusables = new Set(
596
+ const focusablesByFirstChar = new Set(
543
597
  this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
544
598
  );
545
- target = candidates.filter((focusable2) => focusables.has(focusable2));
546
- const afterIndex = target.findIndex(
599
+ focusables = candidates.filter(
600
+ (candidate) => focusablesByFirstChar.has(candidate)
601
+ );
602
+ const afterIndex = focusables.findIndex(
547
603
  (focusable2) => candidates.indexOf(focusable2) > activeIndex
548
604
  );
549
605
  newIndex = afterIndex >= 0 ? afterIndex : 0;
550
606
  }
551
607
  }
552
- const focusable = target.at(newIndex);
608
+ const focusable = focusables.at(newIndex);
553
609
  focusable && focusElement(focusable);
554
610
  };
555
611
  #update(active) {
@@ -557,7 +613,7 @@ var RovingTabIndex = class _RovingTabIndex {
557
613
  for (const focusable of this.#focusables) {
558
614
  if (!current.has(focusable)) {
559
615
  _RovingTabIndex.#initialized.delete(focusable);
560
- restoreAttributes(focusable);
616
+ restoreAttributes2(focusable);
561
617
  this.#focusables.delete(focusable);
562
618
  for (const [key, focusables] of this.#focusablesByFirstChar) {
563
619
  const index = focusables.indexOf(focusable);
@@ -579,7 +635,7 @@ var RovingTabIndex = class _RovingTabIndex {
579
635
  this.#focusables.add(focusable);
580
636
  _RovingTabIndex.#initialized.add(focusable);
581
637
  if (!navigationOnly) {
582
- saveAttributes(focusable, "tabindex");
638
+ saveAttributes2(focusable, "tabindex");
583
639
  focusable.setAttribute("tabindex", "-1");
584
640
  }
585
641
  if (!typeahead) {
@@ -592,8 +648,8 @@ var RovingTabIndex = class _RovingTabIndex {
592
648
  );
593
649
  if (char) {
594
650
  keys.add(char);
595
- saveAttributes(focusable, "aria-keyshortcuts");
596
- addTokenToAttribute(focusable, "aria-keyshortcuts", char, {
651
+ saveAttributes2(focusable, "aria-keyshortcuts");
652
+ addTokenToAttribute2(focusable, "aria-keyshortcuts", char, {
597
653
  caseInsensitive: true
598
654
  });
599
655
  }
@@ -1036,7 +1092,7 @@ var Tabs = class _Tabs {
1036
1092
  tab && this.activate(tab, true);
1037
1093
  };
1038
1094
  #createBinding(tabs, panel) {
1039
- return { tabs, panel, animation: null };
1095
+ return { animation: null, panel, tabs };
1040
1096
  }
1041
1097
  #hasFocusable(container) {
1042
1098
  return !![
@@ -1114,13 +1170,13 @@ var TabsIndicator = class {
1114
1170
  if (!tab) {
1115
1171
  return;
1116
1172
  }
1117
- const { x: tabX, y: tabY, width, height } = tab.getBoundingClientRect();
1118
- const { x: listX, y: listY } = this.#listElement.getBoundingClientRect();
1173
+ const tabRect = tab.getBoundingClientRect();
1174
+ const listRect = this.#listElement.getBoundingClientRect();
1119
1175
  const { duration, easing } = this.#settings.animation.indicator;
1120
1176
  this.#animation = this.#rootElement.animate(
1121
1177
  {
1122
- [position]: `${isHorizontal ? tabX - listX : tabY - listY}px`,
1123
- [size]: `${isHorizontal ? width : height}px`
1178
+ [position]: `${isHorizontal ? tabRect.left - listRect.left : tabRect.top - listRect.top}px`,
1179
+ [size]: `${isHorizontal ? tabRect.width : tabRect.height}px`
1124
1180
  },
1125
1181
  { duration, easing, fill: "forwards" }
1126
1182
  );
@@ -1148,7 +1204,7 @@ var TabsIndicator = class {
1148
1204
  * Tabs
1149
1205
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
1150
1206
  *
1151
- * @version 2.0.8
1207
+ * @version 2.0.10
1152
1208
  * @author Yusuke Kamiyamane
1153
1209
  * @license MIT
1154
1210
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1160,7 +1216,7 @@ var TabsIndicator = class {
1160
1216
  (**
1161
1217
  * Attributes Utils
1162
1218
  *
1163
- * @version 1.1.4
1219
+ * @version 2.0.0
1164
1220
  * @author Yusuke Kamiyamane
1165
1221
  * @license MIT
1166
1222
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1173,7 +1229,7 @@ power-focusable/dist/index.js:
1173
1229
  * High-precision focus management utility with full composed tree support.
1174
1230
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1175
1231
  *
1176
- * @version 4.3.21
1232
+ * @version 4.3.23
1177
1233
  * @author Yusuke Kamiyamane
1178
1234
  * @license MIT
1179
1235
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1191,13 +1247,24 @@ power-focusable/dist/index.js:
1191
1247
  * @see {@link https://github.com/y14e/button}
1192
1248
  *)
1193
1249
 
1250
+ @y14e/attributes-utils/dist/index.js:
1251
+ (**
1252
+ * Attributes Utils
1253
+ *
1254
+ * @version 1.1.7
1255
+ * @author Yusuke Kamiyamane
1256
+ * @license MIT
1257
+ * @copyright Copyright (c) Yusuke Kamiyamane
1258
+ * @see {@link https://github.com/y14e/attributes-utils}
1259
+ *)
1260
+
1194
1261
  @y14e/roving-tabindex/dist/index.js:
1195
1262
  (**
1196
1263
  * Roving Tabindex
1197
1264
  * Lightweight roving tabindex utility with fully focus management.
1198
1265
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1199
1266
  *
1200
- * @version 3.1.18
1267
+ * @version 3.1.20
1201
1268
  * @author Yusuke Kamiyamane
1202
1269
  * @license MIT
1203
1270
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.cjs CHANGED
@@ -415,7 +415,7 @@ var Tabs = class _Tabs {
415
415
  tab && this.activate(tab, true);
416
416
  };
417
417
  #createBinding(tabs, panel) {
418
- return { tabs, panel, animation: null };
418
+ return { animation: null, panel, tabs };
419
419
  }
420
420
  #hasFocusable(container) {
421
421
  return !![
@@ -493,13 +493,13 @@ var TabsIndicator = class {
493
493
  if (!tab) {
494
494
  return;
495
495
  }
496
- const { x: tabX, y: tabY, width, height } = tab.getBoundingClientRect();
497
- const { x: listX, y: listY } = this.#listElement.getBoundingClientRect();
496
+ const tabRect = tab.getBoundingClientRect();
497
+ const listRect = this.#listElement.getBoundingClientRect();
498
498
  const { duration, easing } = this.#settings.animation.indicator;
499
499
  this.#animation = this.#rootElement.animate(
500
500
  {
501
- [position]: `${isHorizontal ? tabX - listX : tabY - listY}px`,
502
- [size]: `${isHorizontal ? width : height}px`
501
+ [position]: `${isHorizontal ? tabRect.left - listRect.left : tabRect.top - listRect.top}px`,
502
+ [size]: `${isHorizontal ? tabRect.width : tabRect.height}px`
503
503
  },
504
504
  { duration, easing, fill: "forwards" }
505
505
  );
@@ -527,7 +527,7 @@ var TabsIndicator = class {
527
527
  * Tabs
528
528
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
529
529
  *
530
- * @version 2.0.8
530
+ * @version 2.0.10
531
531
  * @author Yusuke Kamiyamane
532
532
  * @license MIT
533
533
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.d.cts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Tabs
3
3
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
4
4
  *
5
- * @version 2.0.8
5
+ * @version 2.0.10
6
6
  * @author Yusuke Kamiyamane
7
7
  * @license MIT
8
8
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Tabs
3
3
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
4
4
  *
5
- * @version 2.0.8
5
+ * @version 2.0.10
6
6
  * @author Yusuke Kamiyamane
7
7
  * @license MIT
8
8
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -409,7 +409,7 @@ var Tabs = class _Tabs {
409
409
  tab && this.activate(tab, true);
410
410
  };
411
411
  #createBinding(tabs, panel) {
412
- return { tabs, panel, animation: null };
412
+ return { animation: null, panel, tabs };
413
413
  }
414
414
  #hasFocusable(container) {
415
415
  return !![
@@ -487,13 +487,13 @@ var TabsIndicator = class {
487
487
  if (!tab) {
488
488
  return;
489
489
  }
490
- const { x: tabX, y: tabY, width, height } = tab.getBoundingClientRect();
491
- const { x: listX, y: listY } = this.#listElement.getBoundingClientRect();
490
+ const tabRect = tab.getBoundingClientRect();
491
+ const listRect = this.#listElement.getBoundingClientRect();
492
492
  const { duration, easing } = this.#settings.animation.indicator;
493
493
  this.#animation = this.#rootElement.animate(
494
494
  {
495
- [position]: `${isHorizontal ? tabX - listX : tabY - listY}px`,
496
- [size]: `${isHorizontal ? width : height}px`
495
+ [position]: `${isHorizontal ? tabRect.left - listRect.left : tabRect.top - listRect.top}px`,
496
+ [size]: `${isHorizontal ? tabRect.width : tabRect.height}px`
497
497
  },
498
498
  { duration, easing, fill: "forwards" }
499
499
  );
@@ -521,7 +521,7 @@ var TabsIndicator = class {
521
521
  * Tabs
522
522
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
523
523
  *
524
- * @version 2.0.8
524
+ * @version 2.0.10
525
525
  * @author Yusuke Kamiyamane
526
526
  * @license MIT
527
527
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/tabs",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "description": "WAI-ARIA compliant tabs pattern implementation in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -50,8 +50,8 @@
50
50
  "node": ">=18"
51
51
  },
52
52
  "dependencies": {
53
- "@y14e/attributes-utils": "^1.1.4",
53
+ "@y14e/attributes-utils": "^2.0.0",
54
54
  "@y14e/button": "^1.0.6",
55
- "@y14e/roving-tabindex": "^3.1.18"
55
+ "@y14e/roving-tabindex": "^3.1.20"
56
56
  }
57
57
  }