@y14e/tabs 1.5.7 → 1.5.9

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@1.5.7';
13
+ import Tabs from '@y14e/tabs@1.5.9';
14
14
 
15
15
  // CDNs
16
- import Tabs from 'https://esm.sh/@y14e/tabs@1.5.7';
16
+ import Tabs from 'https://esm.sh/@y14e/tabs@1.5.9';
17
17
  // or
18
- import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@1.5.7/+esm';
18
+ import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@1.5.9/+esm';
19
19
  // or
20
- import Tabs from 'https://esm.unpkg.com/@y14e/tabs@1.5.7';
20
+ import Tabs from 'https://esm.unpkg.com/@y14e/tabs@1.5.9';
21
21
  ```
22
22
 
23
23
  ## Usage
package/dist/index.cjs CHANGED
@@ -1,13 +1,13 @@
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
+ var DEFAULT_PARSER = (value) => value.split(/\s+/);
5
+ var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
6
6
  function addTokenToAttribute(element, attribute, token, options = {}) {
7
7
  const {
8
8
  caseInsensitive = false,
9
- parse = defaultParser,
10
- serialize = defaultSerializer
9
+ parse = DEFAULT_PARSER,
10
+ serialize = DEFAULT_SERIALIZER
11
11
  } = options;
12
12
  const value = element.getAttribute(attribute)?.trim();
13
13
  const tokens = value ? parse(value).filter(Boolean) : [];
@@ -17,11 +17,11 @@ function addTokenToAttribute(element, attribute, token, options = {}) {
17
17
  tokens.push(token);
18
18
  element.setAttribute(attribute, serialize(tokens));
19
19
  }
20
- return;
20
+ } else {
21
+ const set = new Set(tokens);
22
+ set.add(token);
23
+ element.setAttribute(attribute, serialize([...set]));
21
24
  }
22
- const set = new Set(tokens);
23
- set.add(token);
24
- element.setAttribute(attribute, serialize([...set]));
25
25
  }
26
26
  var snapshots = /* @__PURE__ */ new WeakMap();
27
27
  function restoreAttributes(elements) {
@@ -106,13 +106,13 @@ function getActiveElement() {
106
106
  }
107
107
 
108
108
  // node_modules/@y14e/roving-tabindex/dist/index.js
109
- var defaultParser2 = (value) => value.split(/\s+/);
110
- var defaultSerializer2 = (tokens) => tokens.join(" ");
109
+ var DEFAULT_PARSER2 = (value) => value.split(/\s+/);
110
+ var DEFAULT_SERIALIZER2 = (tokens) => tokens.join(" ");
111
111
  function addTokenToAttribute2(element, attribute, token, options = {}) {
112
112
  const {
113
113
  caseInsensitive = false,
114
- parse = defaultParser2,
115
- serialize = defaultSerializer2
114
+ parse = DEFAULT_PARSER2,
115
+ serialize = DEFAULT_SERIALIZER2
116
116
  } = options;
117
117
  const value = element.getAttribute(attribute)?.trim();
118
118
  const tokens = value ? parse(value).filter(Boolean) : [];
@@ -122,11 +122,11 @@ function addTokenToAttribute2(element, attribute, token, options = {}) {
122
122
  tokens.push(token);
123
123
  element.setAttribute(attribute, serialize(tokens));
124
124
  }
125
- return;
125
+ } else {
126
+ const set = new Set(tokens);
127
+ set.add(token);
128
+ element.setAttribute(attribute, serialize([...set]));
126
129
  }
127
- const set = new Set(tokens);
128
- set.add(token);
129
- element.setAttribute(attribute, serialize([...set]));
130
130
  }
131
131
  var snapshots2 = /* @__PURE__ */ new WeakMap();
132
132
  function restoreAttributes2(elements) {
@@ -193,21 +193,16 @@ function getFocusables(container = document.body, options = {}) {
193
193
  const elements = [];
194
194
  if (composed || include) {
195
195
  let traverse2 = function(node) {
196
- if (node instanceof Element) {
197
- if (isFocusable(node, {
198
- skipNegativeTabIndexCheck,
199
- skipVisibilityCheck
200
- }) || include?.(node)) {
201
- elements[elements.length] = node;
202
- }
196
+ if (!(node instanceof Element)) {
197
+ return;
198
+ }
199
+ if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
200
+ elements[elements.length] = node;
203
201
  }
204
202
  const children = getComposedChildren(node);
205
203
  for (let i = 0, l = children.length; i < l; i++) {
206
204
  const child = children[i];
207
- if (!child) {
208
- continue;
209
- }
210
- traverse2(child);
205
+ child && traverse2(child);
211
206
  }
212
207
  };
213
208
  traverse2(container);
@@ -215,10 +210,7 @@ function getFocusables(container = document.body, options = {}) {
215
210
  const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
216
211
  for (let i = 0, l = candidates.length; i < l; i++) {
217
212
  const candidate = candidates[i];
218
- if (!(candidate instanceof Element)) {
219
- continue;
220
- }
221
- if (isFocusable(candidate, {
213
+ if (candidate && isFocusable(candidate, {
222
214
  skipNegativeTabIndexCheck,
223
215
  skipVisibilityCheck
224
216
  })) {
@@ -321,23 +313,19 @@ function normalizeRadioGroup(elements) {
321
313
  for (const group of map.values()) {
322
314
  placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
323
315
  }
324
- return elements.filter((element) => {
325
- if (isUngroupedRadio(element)) {
326
- return placeholder.has(element);
327
- }
328
- return true;
329
- });
316
+ return elements.filter(
317
+ (element) => isUngroupedRadio(element) ? placeholder.has(element) : true
318
+ );
330
319
  }
331
320
  function sortByTabIndex(elements) {
332
321
  const ordered = [];
333
322
  const natural = [];
334
323
  for (let i = 0, l = elements.length; i < l; i++) {
335
324
  const element = elements[i];
336
- if (!element) {
337
- continue;
325
+ if (element) {
326
+ const target = getTabIndex(element) > 0 ? ordered : natural;
327
+ target[target.length] = element;
338
328
  }
339
- const target = getTabIndex(element) > 0 ? ordered : natural;
340
- target[target.length] = element;
341
329
  }
342
330
  ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
343
331
  let count = 0;
@@ -436,7 +424,13 @@ function createRovingTabIndex(container, options = {}) {
436
424
  console.warn("Invalid wrap option. Fallback: false.");
437
425
  wrap = false;
438
426
  }
439
- const settings = { navigationOnly, noMemory, noStart, typeahead, wrap };
427
+ const settings = {
428
+ navigationOnly,
429
+ noMemory,
430
+ noStart,
431
+ typeahead,
432
+ wrap
433
+ };
440
434
  direction && Object.assign(settings, { direction });
441
435
  selector && Object.assign(settings, { selector });
442
436
  const roving = new RovingTabIndex(container, settings);
@@ -488,11 +482,7 @@ var RovingTabIndex = class {
488
482
  return;
489
483
  }
490
484
  const isFocusable22 = this.#focusables.has(target);
491
- if (this.#options.noMemory && !isFocusable22) {
492
- this.#update(null);
493
- return;
494
- }
495
- isFocusable22 && this.#update(target);
485
+ this.#options.noMemory && !isFocusable22 ? this.#update(null) : isFocusable22 && this.#update(target);
496
486
  };
497
487
  #onKeyDown = (event) => {
498
488
  if (!event.composedPath().includes(this.#container)) {
@@ -524,10 +514,8 @@ var RovingTabIndex = class {
524
514
  return;
525
515
  }
526
516
  event.preventDefault();
527
- event.stopPropagation();
528
517
  const currentIndex = current.indexOf(active);
529
- let rawIndex;
530
- let newIndex = currentIndex;
518
+ let newIndex;
531
519
  let target = current;
532
520
  switch (key) {
533
521
  case "End":
@@ -537,15 +525,17 @@ var RovingTabIndex = class {
537
525
  newIndex = 0;
538
526
  break;
539
527
  case "ArrowLeft":
540
- case "ArrowUp":
541
- rawIndex = currentIndex - 1;
528
+ case "ArrowUp": {
529
+ const rawIndex = currentIndex - 1;
542
530
  newIndex = wrap ? rawIndex : Math.max(rawIndex, 0);
543
531
  break;
532
+ }
544
533
  case "ArrowRight":
545
- case "ArrowDown":
546
- rawIndex = currentIndex + 1;
534
+ case "ArrowDown": {
535
+ const rawIndex = currentIndex + 1;
547
536
  newIndex = wrap ? rawIndex % current.length : Math.min(rawIndex, current.length - 1);
548
537
  break;
538
+ }
549
539
  default: {
550
540
  target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
551
541
  const foundIndex = target.findIndex(
@@ -560,15 +550,14 @@ var RovingTabIndex = class {
560
550
  #update(active) {
561
551
  const current = new Set(this.#getFocusables());
562
552
  for (const focusable of this.#focusables) {
563
- if (current.has(focusable)) {
564
- continue;
553
+ if (!current.has(focusable)) {
554
+ focusable.isConnected && restoreAttributes2([focusable]);
555
+ this.#focusables.delete(focusable);
556
+ this.#focusablesByFirstChar.forEach((focusables) => {
557
+ const index = focusables.indexOf(focusable);
558
+ index >= 0 && focusables.splice(index, 1);
559
+ });
565
560
  }
566
- focusable.isConnected && restoreAttributes2([focusable]);
567
- this.#focusables.delete(focusable);
568
- this.#focusablesByFirstChar.forEach((focusables) => {
569
- const index = focusables.indexOf(focusable);
570
- index >= 0 && focusables.splice(index, 1);
571
- });
572
561
  }
573
562
  const { navigationOnly, noStart, typeahead } = this.#options;
574
563
  for (const focusable of current) {
@@ -601,18 +590,17 @@ var RovingTabIndex = class {
601
590
  this.#focusablesByFirstChar.set(key, focusables);
602
591
  });
603
592
  }
604
- if (navigationOnly) {
605
- return;
606
- }
607
- if (active && this.#focusables.has(active)) {
608
- this.#focusables.forEach((focusable) => {
609
- focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
610
- });
611
- return;
593
+ if (!navigationOnly) {
594
+ if (active && this.#focusables.has(active)) {
595
+ this.#focusables.forEach((focusable) => {
596
+ focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
597
+ });
598
+ } else {
599
+ [...this.#focusables].forEach((focusable, i) => {
600
+ focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
601
+ });
602
+ }
612
603
  }
613
- [...this.#focusables].forEach((focusable, i) => {
614
- focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
615
- });
616
604
  }
617
605
  #createSelectorFilter() {
618
606
  const { selector } = this.#options;
@@ -677,7 +665,6 @@ var Tabs = class _Tabs {
677
665
  #animationController = null;
678
666
  #cleanupsRovingTabIndex = [];
679
667
  #animation = null;
680
- #animationId = 0;
681
668
  #buttons = [];
682
669
  #indicators = [];
683
670
  #isDestroyed = false;
@@ -801,16 +788,12 @@ var Tabs = class _Tabs {
801
788
  p.removeAttribute("hidden");
802
789
  } else {
803
790
  const tab2 = this.#tabElements[i];
804
- if (!tab2) {
805
- return;
806
- }
807
- p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
791
+ tab2 && p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
808
792
  }
809
793
  });
810
- const animationId = ++this.#animationId;
811
794
  this.#animation?.cancel();
812
795
  const { duration, easing } = this.#settings.animation.content;
813
- this.#animation = this.#contentElement.animate(
796
+ const animation = this.#contentElement.animate(
814
797
  {
815
798
  blockSize: [
816
799
  `${size}px`,
@@ -822,8 +805,9 @@ var Tabs = class _Tabs {
822
805
  easing
823
806
  }
824
807
  );
808
+ this.#animation = animation;
825
809
  const cleanup = () => {
826
- if (animationId === this.#animationId) {
810
+ if (animation === this.#animation) {
827
811
  this.#animation = null;
828
812
  }
829
813
  };
@@ -836,7 +820,7 @@ var Tabs = class _Tabs {
836
820
  this.#animation.addEventListener(
837
821
  "finish",
838
822
  () => {
839
- if (animationId === this.#animationId) {
823
+ if (this.#animation === animation) {
840
824
  this.#onAnimationFinish();
841
825
  cleanup();
842
826
  }
@@ -854,7 +838,7 @@ var Tabs = class _Tabs {
854
838
  const opacity = getComputedStyle(p).getPropertyValue("opacity");
855
839
  binding.animation?.cancel();
856
840
  const isSelected = p === panel;
857
- const animation = p.animate(
841
+ const animation2 = p.animate(
858
842
  {
859
843
  opacity: fade ? isSelected ? [opacity, opacity, "1"] : [opacity, "0", "0"] : isSelected ? [opacity, "1"] : [opacity, "0"]
860
844
  },
@@ -863,16 +847,16 @@ var Tabs = class _Tabs {
863
847
  easing: "ease"
864
848
  }
865
849
  );
866
- binding.animation = animation;
850
+ binding.animation = animation2;
867
851
  const cleanup2 = () => {
868
- if (binding.animation === animation) {
852
+ if (binding.animation === animation2) {
869
853
  binding.animation = null;
870
854
  }
871
855
  };
872
856
  this.#animationController = new AbortController();
873
857
  const { signal: signal2 } = this.#animationController;
874
- animation.addEventListener("cancel", cleanup2, { once: true, signal: signal2 });
875
- animation.addEventListener("finish", cleanup2, { once: true, signal: signal2 });
858
+ animation2.addEventListener("cancel", cleanup2, { once: true, signal: signal2 });
859
+ animation2.addEventListener("finish", cleanup2, { once: true, signal: signal2 });
876
860
  });
877
861
  }
878
862
  async destroy(force = false) {
@@ -1029,10 +1013,7 @@ var Tabs = class _Tabs {
1029
1013
  return;
1030
1014
  }
1031
1015
  const tab = this.#bindings.get(panel)?.tabs[0];
1032
- if (!tab) {
1033
- return;
1034
- }
1035
- this.activate(tab, true);
1016
+ tab && this.activate(tab, true);
1036
1017
  };
1037
1018
  #isAvoidedTab(tab) {
1038
1019
  const binding = this.#bindings.get(tab);
@@ -1164,7 +1145,7 @@ function isFocusable2(element) {
1164
1145
  * Tabs
1165
1146
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
1166
1147
  *
1167
- * @version 1.5.7
1148
+ * @version 1.5.9
1168
1149
  * @author Yusuke Kamiyamane
1169
1150
  * @license MIT
1170
1151
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1176,7 +1157,7 @@ function isFocusable2(element) {
1176
1157
  (**
1177
1158
  * Attributes Utils
1178
1159
  *
1179
- * @version 1.1.1
1160
+ * @version 1.1.2
1180
1161
  * @author Yusuke Kamiyamane
1181
1162
  * @license MIT
1182
1163
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1200,7 +1181,7 @@ function isFocusable2(element) {
1200
1181
  * Lightweight roving tabindex utility with fully focus management.
1201
1182
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1202
1183
  *
1203
- * @version 2.2.0
1184
+ * @version 3.0.2
1204
1185
  * @author Yusuke Kamiyamane
1205
1186
  * @license MIT
1206
1187
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1212,7 +1193,7 @@ function isFocusable2(element) {
1212
1193
  (**
1213
1194
  * Attributes Utils
1214
1195
  *
1215
- * @version 1.1.1
1196
+ * @version 1.1.2
1216
1197
  * @author Yusuke Kamiyamane
1217
1198
  * @license MIT
1218
1199
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1225,7 +1206,7 @@ function isFocusable2(element) {
1225
1206
  * High-precision focus management utility with full composed tree support.
1226
1207
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1227
1208
  *
1228
- * @version 4.3.2
1209
+ * @version 4.3.3
1229
1210
  * @author Yusuke Kamiyamane
1230
1211
  * @license MIT
1231
1212
  * @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 1.5.7
5
+ * @version 1.5.9
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 1.5.7
5
+ * @version 1.5.9
6
6
  * @author Yusuke Kamiyamane
7
7
  * @license MIT
8
8
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // node_modules/@y14e/attributes-utils/dist/index.js
2
- var defaultParser = (value) => value.split(/\s+/);
3
- var defaultSerializer = (tokens) => tokens.join(" ");
2
+ var DEFAULT_PARSER = (value) => value.split(/\s+/);
3
+ var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
4
4
  function addTokenToAttribute(element, attribute, token, options = {}) {
5
5
  const {
6
6
  caseInsensitive = false,
7
- parse = defaultParser,
8
- serialize = defaultSerializer
7
+ parse = DEFAULT_PARSER,
8
+ serialize = DEFAULT_SERIALIZER
9
9
  } = options;
10
10
  const value = element.getAttribute(attribute)?.trim();
11
11
  const tokens = value ? parse(value).filter(Boolean) : [];
@@ -15,11 +15,11 @@ function addTokenToAttribute(element, attribute, token, options = {}) {
15
15
  tokens.push(token);
16
16
  element.setAttribute(attribute, serialize(tokens));
17
17
  }
18
- return;
18
+ } else {
19
+ const set = new Set(tokens);
20
+ set.add(token);
21
+ element.setAttribute(attribute, serialize([...set]));
19
22
  }
20
- const set = new Set(tokens);
21
- set.add(token);
22
- element.setAttribute(attribute, serialize([...set]));
23
23
  }
24
24
  var snapshots = /* @__PURE__ */ new WeakMap();
25
25
  function restoreAttributes(elements) {
@@ -104,13 +104,13 @@ function getActiveElement() {
104
104
  }
105
105
 
106
106
  // node_modules/@y14e/roving-tabindex/dist/index.js
107
- var defaultParser2 = (value) => value.split(/\s+/);
108
- var defaultSerializer2 = (tokens) => tokens.join(" ");
107
+ var DEFAULT_PARSER2 = (value) => value.split(/\s+/);
108
+ var DEFAULT_SERIALIZER2 = (tokens) => tokens.join(" ");
109
109
  function addTokenToAttribute2(element, attribute, token, options = {}) {
110
110
  const {
111
111
  caseInsensitive = false,
112
- parse = defaultParser2,
113
- serialize = defaultSerializer2
112
+ parse = DEFAULT_PARSER2,
113
+ serialize = DEFAULT_SERIALIZER2
114
114
  } = options;
115
115
  const value = element.getAttribute(attribute)?.trim();
116
116
  const tokens = value ? parse(value).filter(Boolean) : [];
@@ -120,11 +120,11 @@ function addTokenToAttribute2(element, attribute, token, options = {}) {
120
120
  tokens.push(token);
121
121
  element.setAttribute(attribute, serialize(tokens));
122
122
  }
123
- return;
123
+ } else {
124
+ const set = new Set(tokens);
125
+ set.add(token);
126
+ element.setAttribute(attribute, serialize([...set]));
124
127
  }
125
- const set = new Set(tokens);
126
- set.add(token);
127
- element.setAttribute(attribute, serialize([...set]));
128
128
  }
129
129
  var snapshots2 = /* @__PURE__ */ new WeakMap();
130
130
  function restoreAttributes2(elements) {
@@ -191,21 +191,16 @@ function getFocusables(container = document.body, options = {}) {
191
191
  const elements = [];
192
192
  if (composed || include) {
193
193
  let traverse2 = function(node) {
194
- if (node instanceof Element) {
195
- if (isFocusable(node, {
196
- skipNegativeTabIndexCheck,
197
- skipVisibilityCheck
198
- }) || include?.(node)) {
199
- elements[elements.length] = node;
200
- }
194
+ if (!(node instanceof Element)) {
195
+ return;
196
+ }
197
+ if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
198
+ elements[elements.length] = node;
201
199
  }
202
200
  const children = getComposedChildren(node);
203
201
  for (let i = 0, l = children.length; i < l; i++) {
204
202
  const child = children[i];
205
- if (!child) {
206
- continue;
207
- }
208
- traverse2(child);
203
+ child && traverse2(child);
209
204
  }
210
205
  };
211
206
  traverse2(container);
@@ -213,10 +208,7 @@ function getFocusables(container = document.body, options = {}) {
213
208
  const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
214
209
  for (let i = 0, l = candidates.length; i < l; i++) {
215
210
  const candidate = candidates[i];
216
- if (!(candidate instanceof Element)) {
217
- continue;
218
- }
219
- if (isFocusable(candidate, {
211
+ if (candidate && isFocusable(candidate, {
220
212
  skipNegativeTabIndexCheck,
221
213
  skipVisibilityCheck
222
214
  })) {
@@ -319,23 +311,19 @@ function normalizeRadioGroup(elements) {
319
311
  for (const group of map.values()) {
320
312
  placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
321
313
  }
322
- return elements.filter((element) => {
323
- if (isUngroupedRadio(element)) {
324
- return placeholder.has(element);
325
- }
326
- return true;
327
- });
314
+ return elements.filter(
315
+ (element) => isUngroupedRadio(element) ? placeholder.has(element) : true
316
+ );
328
317
  }
329
318
  function sortByTabIndex(elements) {
330
319
  const ordered = [];
331
320
  const natural = [];
332
321
  for (let i = 0, l = elements.length; i < l; i++) {
333
322
  const element = elements[i];
334
- if (!element) {
335
- continue;
323
+ if (element) {
324
+ const target = getTabIndex(element) > 0 ? ordered : natural;
325
+ target[target.length] = element;
336
326
  }
337
- const target = getTabIndex(element) > 0 ? ordered : natural;
338
- target[target.length] = element;
339
327
  }
340
328
  ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
341
329
  let count = 0;
@@ -434,7 +422,13 @@ function createRovingTabIndex(container, options = {}) {
434
422
  console.warn("Invalid wrap option. Fallback: false.");
435
423
  wrap = false;
436
424
  }
437
- const settings = { navigationOnly, noMemory, noStart, typeahead, wrap };
425
+ const settings = {
426
+ navigationOnly,
427
+ noMemory,
428
+ noStart,
429
+ typeahead,
430
+ wrap
431
+ };
438
432
  direction && Object.assign(settings, { direction });
439
433
  selector && Object.assign(settings, { selector });
440
434
  const roving = new RovingTabIndex(container, settings);
@@ -486,11 +480,7 @@ var RovingTabIndex = class {
486
480
  return;
487
481
  }
488
482
  const isFocusable22 = this.#focusables.has(target);
489
- if (this.#options.noMemory && !isFocusable22) {
490
- this.#update(null);
491
- return;
492
- }
493
- isFocusable22 && this.#update(target);
483
+ this.#options.noMemory && !isFocusable22 ? this.#update(null) : isFocusable22 && this.#update(target);
494
484
  };
495
485
  #onKeyDown = (event) => {
496
486
  if (!event.composedPath().includes(this.#container)) {
@@ -522,10 +512,8 @@ var RovingTabIndex = class {
522
512
  return;
523
513
  }
524
514
  event.preventDefault();
525
- event.stopPropagation();
526
515
  const currentIndex = current.indexOf(active);
527
- let rawIndex;
528
- let newIndex = currentIndex;
516
+ let newIndex;
529
517
  let target = current;
530
518
  switch (key) {
531
519
  case "End":
@@ -535,15 +523,17 @@ var RovingTabIndex = class {
535
523
  newIndex = 0;
536
524
  break;
537
525
  case "ArrowLeft":
538
- case "ArrowUp":
539
- rawIndex = currentIndex - 1;
526
+ case "ArrowUp": {
527
+ const rawIndex = currentIndex - 1;
540
528
  newIndex = wrap ? rawIndex : Math.max(rawIndex, 0);
541
529
  break;
530
+ }
542
531
  case "ArrowRight":
543
- case "ArrowDown":
544
- rawIndex = currentIndex + 1;
532
+ case "ArrowDown": {
533
+ const rawIndex = currentIndex + 1;
545
534
  newIndex = wrap ? rawIndex % current.length : Math.min(rawIndex, current.length - 1);
546
535
  break;
536
+ }
547
537
  default: {
548
538
  target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
549
539
  const foundIndex = target.findIndex(
@@ -558,15 +548,14 @@ var RovingTabIndex = class {
558
548
  #update(active) {
559
549
  const current = new Set(this.#getFocusables());
560
550
  for (const focusable of this.#focusables) {
561
- if (current.has(focusable)) {
562
- continue;
551
+ if (!current.has(focusable)) {
552
+ focusable.isConnected && restoreAttributes2([focusable]);
553
+ this.#focusables.delete(focusable);
554
+ this.#focusablesByFirstChar.forEach((focusables) => {
555
+ const index = focusables.indexOf(focusable);
556
+ index >= 0 && focusables.splice(index, 1);
557
+ });
563
558
  }
564
- focusable.isConnected && restoreAttributes2([focusable]);
565
- this.#focusables.delete(focusable);
566
- this.#focusablesByFirstChar.forEach((focusables) => {
567
- const index = focusables.indexOf(focusable);
568
- index >= 0 && focusables.splice(index, 1);
569
- });
570
559
  }
571
560
  const { navigationOnly, noStart, typeahead } = this.#options;
572
561
  for (const focusable of current) {
@@ -599,18 +588,17 @@ var RovingTabIndex = class {
599
588
  this.#focusablesByFirstChar.set(key, focusables);
600
589
  });
601
590
  }
602
- if (navigationOnly) {
603
- return;
604
- }
605
- if (active && this.#focusables.has(active)) {
606
- this.#focusables.forEach((focusable) => {
607
- focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
608
- });
609
- return;
591
+ if (!navigationOnly) {
592
+ if (active && this.#focusables.has(active)) {
593
+ this.#focusables.forEach((focusable) => {
594
+ focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
595
+ });
596
+ } else {
597
+ [...this.#focusables].forEach((focusable, i) => {
598
+ focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
599
+ });
600
+ }
610
601
  }
611
- [...this.#focusables].forEach((focusable, i) => {
612
- focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
613
- });
614
602
  }
615
603
  #createSelectorFilter() {
616
604
  const { selector } = this.#options;
@@ -675,7 +663,6 @@ var Tabs = class _Tabs {
675
663
  #animationController = null;
676
664
  #cleanupsRovingTabIndex = [];
677
665
  #animation = null;
678
- #animationId = 0;
679
666
  #buttons = [];
680
667
  #indicators = [];
681
668
  #isDestroyed = false;
@@ -799,16 +786,12 @@ var Tabs = class _Tabs {
799
786
  p.removeAttribute("hidden");
800
787
  } else {
801
788
  const tab2 = this.#tabElements[i];
802
- if (!tab2) {
803
- return;
804
- }
805
- p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
789
+ tab2 && p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
806
790
  }
807
791
  });
808
- const animationId = ++this.#animationId;
809
792
  this.#animation?.cancel();
810
793
  const { duration, easing } = this.#settings.animation.content;
811
- this.#animation = this.#contentElement.animate(
794
+ const animation = this.#contentElement.animate(
812
795
  {
813
796
  blockSize: [
814
797
  `${size}px`,
@@ -820,8 +803,9 @@ var Tabs = class _Tabs {
820
803
  easing
821
804
  }
822
805
  );
806
+ this.#animation = animation;
823
807
  const cleanup = () => {
824
- if (animationId === this.#animationId) {
808
+ if (animation === this.#animation) {
825
809
  this.#animation = null;
826
810
  }
827
811
  };
@@ -834,7 +818,7 @@ var Tabs = class _Tabs {
834
818
  this.#animation.addEventListener(
835
819
  "finish",
836
820
  () => {
837
- if (animationId === this.#animationId) {
821
+ if (this.#animation === animation) {
838
822
  this.#onAnimationFinish();
839
823
  cleanup();
840
824
  }
@@ -852,7 +836,7 @@ var Tabs = class _Tabs {
852
836
  const opacity = getComputedStyle(p).getPropertyValue("opacity");
853
837
  binding.animation?.cancel();
854
838
  const isSelected = p === panel;
855
- const animation = p.animate(
839
+ const animation2 = p.animate(
856
840
  {
857
841
  opacity: fade ? isSelected ? [opacity, opacity, "1"] : [opacity, "0", "0"] : isSelected ? [opacity, "1"] : [opacity, "0"]
858
842
  },
@@ -861,16 +845,16 @@ var Tabs = class _Tabs {
861
845
  easing: "ease"
862
846
  }
863
847
  );
864
- binding.animation = animation;
848
+ binding.animation = animation2;
865
849
  const cleanup2 = () => {
866
- if (binding.animation === animation) {
850
+ if (binding.animation === animation2) {
867
851
  binding.animation = null;
868
852
  }
869
853
  };
870
854
  this.#animationController = new AbortController();
871
855
  const { signal: signal2 } = this.#animationController;
872
- animation.addEventListener("cancel", cleanup2, { once: true, signal: signal2 });
873
- animation.addEventListener("finish", cleanup2, { once: true, signal: signal2 });
856
+ animation2.addEventListener("cancel", cleanup2, { once: true, signal: signal2 });
857
+ animation2.addEventListener("finish", cleanup2, { once: true, signal: signal2 });
874
858
  });
875
859
  }
876
860
  async destroy(force = false) {
@@ -1027,10 +1011,7 @@ var Tabs = class _Tabs {
1027
1011
  return;
1028
1012
  }
1029
1013
  const tab = this.#bindings.get(panel)?.tabs[0];
1030
- if (!tab) {
1031
- return;
1032
- }
1033
- this.activate(tab, true);
1014
+ tab && this.activate(tab, true);
1034
1015
  };
1035
1016
  #isAvoidedTab(tab) {
1036
1017
  const binding = this.#bindings.get(tab);
@@ -1162,7 +1143,7 @@ function isFocusable2(element) {
1162
1143
  * Tabs
1163
1144
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
1164
1145
  *
1165
- * @version 1.5.7
1146
+ * @version 1.5.9
1166
1147
  * @author Yusuke Kamiyamane
1167
1148
  * @license MIT
1168
1149
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1174,7 +1155,7 @@ function isFocusable2(element) {
1174
1155
  (**
1175
1156
  * Attributes Utils
1176
1157
  *
1177
- * @version 1.1.1
1158
+ * @version 1.1.2
1178
1159
  * @author Yusuke Kamiyamane
1179
1160
  * @license MIT
1180
1161
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1198,7 +1179,7 @@ function isFocusable2(element) {
1198
1179
  * Lightweight roving tabindex utility with fully focus management.
1199
1180
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1200
1181
  *
1201
- * @version 2.2.0
1182
+ * @version 3.0.2
1202
1183
  * @author Yusuke Kamiyamane
1203
1184
  * @license MIT
1204
1185
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1210,7 +1191,7 @@ function isFocusable2(element) {
1210
1191
  (**
1211
1192
  * Attributes Utils
1212
1193
  *
1213
- * @version 1.1.1
1194
+ * @version 1.1.2
1214
1195
  * @author Yusuke Kamiyamane
1215
1196
  * @license MIT
1216
1197
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1223,7 +1204,7 @@ function isFocusable2(element) {
1223
1204
  * High-precision focus management utility with full composed tree support.
1224
1205
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1225
1206
  *
1226
- * @version 4.3.2
1207
+ * @version 4.3.3
1227
1208
  * @author Yusuke Kamiyamane
1228
1209
  * @license MIT
1229
1210
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/tabs",
3
- "version": "1.5.7",
3
+ "version": "1.5.9",
4
4
  "description": "WAI-ARIA compliant tabs pattern implementation in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -42,9 +42,9 @@
42
42
  },
43
43
  "homepage": "https://github.com/y14e/tabs#readme",
44
44
  "devDependencies": {
45
- "@y14e/attributes-utils": "^1.1.1",
45
+ "@y14e/attributes-utils": "^1.1.2",
46
46
  "@y14e/button": "^1.0.0",
47
- "@y14e/roving-tabindex": "^2.2.0",
47
+ "@y14e/roving-tabindex": "^3.0.2",
48
48
  "bun-types": "latest",
49
49
  "tsup": "^8.0.0",
50
50
  "typescript": "^5.6.0",