@y14e/tabs 2.0.5 → 2.0.7

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
@@ -13,11 +13,11 @@ npm i @y14e/tabs
13
13
  import Tabs from '@y14e/tabs';
14
14
 
15
15
  // CDNs
16
- import Tabs from 'https://esm.sh/@y14e/tabs@2.0.5';
16
+ import Tabs from 'https://esm.sh/@y14e/tabs@2.0.7';
17
17
  // or
18
- import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@2.0.5/+esm';
18
+ import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@2.0.7/+esm';
19
19
  // or
20
- import Tabs from 'https://esm.unpkg.com/@y14e/tabs@2.0.5';
20
+ import Tabs from 'https://esm.unpkg.com/@y14e/tabs@2.0.7';
21
21
  ```
22
22
 
23
23
  ## Usage
@@ -34,28 +34,28 @@ new Tabs(root, options);
34
34
 
35
35
  ```ts
36
36
  interface TabsOptions {
37
- animation?: {
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
37
+ animation: {
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
43
43
  };
44
- indicator?: {
45
- duration?: number; // ms (default: 300)
46
- easing?: string; // <easing-function> (default: 'ease')
44
+ indicator: {
45
+ duration: number; // ms (default: 300)
46
+ easing: string; // <easing-function> (default: 'ease')
47
47
  };
48
48
  };
49
- avoidDuplicates?: boolean; // default: false
50
- manual?: boolean; // default: false
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"]'
49
+ avoidDuplicates: boolean; // default: false
50
+ manual: boolean; // default: false
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"]'
57
57
  };
58
- vertical?: boolean; // default: false
58
+ vertical: boolean; // default: false
59
59
  }
60
60
  ```
61
61
 
@@ -4,12 +4,12 @@
4
4
  var DEFAULT_PARSER = (value) => value.split(/\s+/);
5
5
  var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
6
6
  function addTokenToAttribute(element, attribute, token, options = {}) {
7
+ const value = element.getAttribute(attribute)?.trim();
7
8
  const {
8
9
  caseInsensitive = false,
9
10
  parse = DEFAULT_PARSER,
10
11
  serialize = DEFAULT_SERIALIZER
11
12
  } = options;
12
- const value = element.getAttribute(attribute)?.trim();
13
13
  const tokens = value ? parse(value).filter(Boolean) : [];
14
14
  if (caseInsensitive) {
15
15
  const lower = token.toLowerCase();
@@ -402,13 +402,7 @@ var RovingTabIndex = class _RovingTabIndex {
402
402
  console.warn("Invalid wrap option. Fallback: false.");
403
403
  wrap = false;
404
404
  }
405
- this.#settings = {
406
- navigationOnly,
407
- noMemory,
408
- noStart,
409
- typeahead,
410
- wrap
411
- };
405
+ this.#settings = { navigationOnly, noMemory, noStart, typeahead, wrap };
412
406
  direction && Object.assign(this.#settings, { direction });
413
407
  selector && Object.assign(this.#settings, { selector });
414
408
  this.#selectorFilter = this.#createSelectorFilter();
@@ -427,29 +421,32 @@ var RovingTabIndex = class _RovingTabIndex {
427
421
  }
428
422
  #initialize() {
429
423
  this.#update(getActiveElement());
430
- if (!(this.#container instanceof HTMLElement)) {
431
- return;
432
- }
433
424
  this.#controller = new AbortController();
434
425
  const { signal } = this.#controller;
435
- document.addEventListener("focusin", this.#onFocusIn, { signal });
436
- this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, { signal });
426
+ this.#container.addEventListener("focusin", this.#onFocusIn, { signal });
427
+ this.#settings.noMemory && this.#container.addEventListener("focusout", this.#onFocusOut, {
428
+ signal
429
+ });
437
430
  this.#container.addEventListener("keydown", this.#onKeyDown, { signal });
438
431
  }
439
432
  #onFocusIn = (event) => {
440
- const { target } = event;
441
- if (!(target instanceof Element)) {
433
+ if (!(event instanceof FocusEvent)) {
442
434
  return;
443
435
  }
444
- const isFocusable2 = this.#focusables.has(target);
445
- this.#settings.noMemory && !isFocusable2 ? this.#update() : isFocusable2 && this.#update(target);
436
+ const { target } = event;
437
+ target instanceof Element && this.#update(target);
446
438
  };
447
439
  #onFocusOut = (event) => {
448
- if (!event.relatedTarget) {
449
- this.#update();
440
+ if (!(event instanceof FocusEvent)) {
441
+ return;
450
442
  }
443
+ const target = event.relatedTarget;
444
+ (!(target instanceof Element) || !this.#focusables.has(target)) && this.#update();
451
445
  };
452
446
  #onKeyDown = (event) => {
447
+ if (!(event instanceof KeyboardEvent)) {
448
+ return;
449
+ }
453
450
  const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
454
451
  if (altKey || ctrlKey || metaKey || shiftKey) {
455
452
  return;
@@ -468,7 +465,7 @@ var RovingTabIndex = class _RovingTabIndex {
468
465
  }
469
466
  }
470
467
  const active = getActiveElement();
471
- if (!(active instanceof HTMLElement)) {
468
+ if (!(active instanceof Element)) {
472
469
  return;
473
470
  }
474
471
  const current = this.#getFocusables();
@@ -722,7 +719,6 @@ var Tabs = class _Tabs {
722
719
  this.#rootElement.setAttribute("data-tabs-animating", "");
723
720
  const { style } = this.#contentElement;
724
721
  style.setProperty("overflow", "clip");
725
- style.setProperty("position", "relative");
726
722
  const { crossFade, fade } = this.#settings.animation.content;
727
723
  const panel = this.#bindings.get(tab)?.panel;
728
724
  if (!panel) {
@@ -732,11 +728,8 @@ var Tabs = class _Tabs {
732
728
  const { style: style2 } = p;
733
729
  if (fade) {
734
730
  style2.setProperty("content-visibility", "visible");
735
- style2.setProperty("display", "block");
736
731
  style2.setProperty("opacity", p.hidden ? "0" : "1");
737
732
  }
738
- style2.setProperty("inline-size", "100%");
739
- style2.setProperty("position", "absolute");
740
733
  p === panel && !this.#hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
741
734
  });
742
735
  this.#panelElements.forEach((p, i) => {
@@ -863,6 +856,7 @@ var Tabs = class _Tabs {
863
856
  ...this.#indicatorElements,
864
857
  ...this.#panelElements
865
858
  ]);
859
+ this.#contentElement && restoreAttributes([this.#contentElement]);
866
860
  this.#listElements.length = 0;
867
861
  this.#tabElements.length = 0;
868
862
  this.#contentElement = null;
@@ -884,11 +878,13 @@ var Tabs = class _Tabs {
884
878
  "tabindex"
885
879
  ]);
886
880
  saveAttributes(this.#indicatorElements, ["style"]);
881
+ this.#contentElement && saveAttributes([this.#contentElement], ["style"]);
887
882
  saveAttributes(this.#panelElements, [
888
883
  "aria-controls",
889
884
  "aria-labelledby",
890
885
  "id",
891
886
  "role",
887
+ "style",
892
888
  "tabindex"
893
889
  ]);
894
890
  this.#eventController = new AbortController();
@@ -920,13 +916,20 @@ var Tabs = class _Tabs {
920
916
  });
921
917
  this.#indicatorElements.forEach((indicator) => {
922
918
  indicator.closest(this.#settings.selector.list)?.style.setProperty("position", "relative");
923
- const { style } = indicator;
924
- style.setProperty("display", "block");
925
- style.setProperty("position", "absolute");
919
+ const { style: style2 } = indicator;
920
+ style2.setProperty("display", "block");
921
+ style2.setProperty("position", "absolute");
926
922
  this.#indicators.push(new TabsIndicator(indicator, this.#settings));
927
923
  });
924
+ if (!this.#contentElement) {
925
+ return;
926
+ }
927
+ const { style } = this.#contentElement;
928
+ style.setProperty("align-items", "start");
929
+ style.setProperty("display", "grid");
928
930
  this.#panelElements.forEach((panel) => {
929
931
  panel.setAttribute("role", "tabpanel");
932
+ panel.style.setProperty("grid-area", "1 / 1");
930
933
  !panel.hasAttribute("hidden") && !this.#hasFocusable(panel) && panel.setAttribute("tabindex", "0");
931
934
  panel.addEventListener("beforematch", this.#onPanelBeforeMatch, {
932
935
  signal
@@ -964,17 +967,11 @@ var Tabs = class _Tabs {
964
967
  this.#isAvoidedTab(tab) && tab.blur();
965
968
  };
966
969
  #onContentAnimationFinish() {
967
- ["block-size", "overflow", "position"].forEach((name) => {
970
+ ["block-size", "overflow"].forEach((name) => {
968
971
  this.#contentElement?.style.removeProperty(name);
969
972
  });
970
973
  this.#panelElements.forEach((panel) => {
971
- [
972
- "content-visibility",
973
- "display",
974
- "inline-size",
975
- "opacity",
976
- "position"
977
- ].forEach((name) => {
974
+ ["content-visibility", "opacity"].forEach((name) => {
978
975
  panel.style.removeProperty(name);
979
976
  });
980
977
  });
@@ -1101,7 +1098,7 @@ var TabsIndicator = class {
1101
1098
  * Tabs
1102
1099
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
1103
1100
  *
1104
- * @version 2.0.5
1101
+ * @version 2.0.7
1105
1102
  * @author Yusuke Kamiyamane
1106
1103
  * @license MIT
1107
1104
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1113,7 +1110,7 @@ var TabsIndicator = class {
1113
1110
  (**
1114
1111
  * Attributes Utils
1115
1112
  *
1116
- * @version 1.1.2
1113
+ * @version 1.1.3
1117
1114
  * @author Yusuke Kamiyamane
1118
1115
  * @license MIT
1119
1116
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1126,7 +1123,7 @@ power-focusable/dist/index.js:
1126
1123
  * High-precision focus management utility with full composed tree support.
1127
1124
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1128
1125
  *
1129
- * @version 4.3.5
1126
+ * @version 4.3.10
1130
1127
  * @author Yusuke Kamiyamane
1131
1128
  * @license MIT
1132
1129
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1150,7 +1147,7 @@ power-focusable/dist/index.js:
1150
1147
  * Lightweight roving tabindex utility with fully focus management.
1151
1148
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1152
1149
  *
1153
- * @version 3.1.2
1150
+ * @version 3.1.9
1154
1151
  * @author Yusuke Kamiyamane
1155
1152
  * @license MIT
1156
1153
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -2,12 +2,12 @@
2
2
  var DEFAULT_PARSER = (value) => value.split(/\s+/);
3
3
  var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
4
4
  function addTokenToAttribute(element, attribute, token, options = {}) {
5
+ const value = element.getAttribute(attribute)?.trim();
5
6
  const {
6
7
  caseInsensitive = false,
7
8
  parse = DEFAULT_PARSER,
8
9
  serialize = DEFAULT_SERIALIZER
9
10
  } = options;
10
- const value = element.getAttribute(attribute)?.trim();
11
11
  const tokens = value ? parse(value).filter(Boolean) : [];
12
12
  if (caseInsensitive) {
13
13
  const lower = token.toLowerCase();
@@ -400,13 +400,7 @@ var RovingTabIndex = class _RovingTabIndex {
400
400
  console.warn("Invalid wrap option. Fallback: false.");
401
401
  wrap = false;
402
402
  }
403
- this.#settings = {
404
- navigationOnly,
405
- noMemory,
406
- noStart,
407
- typeahead,
408
- wrap
409
- };
403
+ this.#settings = { navigationOnly, noMemory, noStart, typeahead, wrap };
410
404
  direction && Object.assign(this.#settings, { direction });
411
405
  selector && Object.assign(this.#settings, { selector });
412
406
  this.#selectorFilter = this.#createSelectorFilter();
@@ -425,29 +419,32 @@ var RovingTabIndex = class _RovingTabIndex {
425
419
  }
426
420
  #initialize() {
427
421
  this.#update(getActiveElement());
428
- if (!(this.#container instanceof HTMLElement)) {
429
- return;
430
- }
431
422
  this.#controller = new AbortController();
432
423
  const { signal } = this.#controller;
433
- document.addEventListener("focusin", this.#onFocusIn, { signal });
434
- this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, { signal });
424
+ this.#container.addEventListener("focusin", this.#onFocusIn, { signal });
425
+ this.#settings.noMemory && this.#container.addEventListener("focusout", this.#onFocusOut, {
426
+ signal
427
+ });
435
428
  this.#container.addEventListener("keydown", this.#onKeyDown, { signal });
436
429
  }
437
430
  #onFocusIn = (event) => {
438
- const { target } = event;
439
- if (!(target instanceof Element)) {
431
+ if (!(event instanceof FocusEvent)) {
440
432
  return;
441
433
  }
442
- const isFocusable2 = this.#focusables.has(target);
443
- this.#settings.noMemory && !isFocusable2 ? this.#update() : isFocusable2 && this.#update(target);
434
+ const { target } = event;
435
+ target instanceof Element && this.#update(target);
444
436
  };
445
437
  #onFocusOut = (event) => {
446
- if (!event.relatedTarget) {
447
- this.#update();
438
+ if (!(event instanceof FocusEvent)) {
439
+ return;
448
440
  }
441
+ const target = event.relatedTarget;
442
+ (!(target instanceof Element) || !this.#focusables.has(target)) && this.#update();
449
443
  };
450
444
  #onKeyDown = (event) => {
445
+ if (!(event instanceof KeyboardEvent)) {
446
+ return;
447
+ }
451
448
  const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
452
449
  if (altKey || ctrlKey || metaKey || shiftKey) {
453
450
  return;
@@ -466,7 +463,7 @@ var RovingTabIndex = class _RovingTabIndex {
466
463
  }
467
464
  }
468
465
  const active = getActiveElement();
469
- if (!(active instanceof HTMLElement)) {
466
+ if (!(active instanceof Element)) {
470
467
  return;
471
468
  }
472
469
  const current = this.#getFocusables();
@@ -720,7 +717,6 @@ var Tabs = class _Tabs {
720
717
  this.#rootElement.setAttribute("data-tabs-animating", "");
721
718
  const { style } = this.#contentElement;
722
719
  style.setProperty("overflow", "clip");
723
- style.setProperty("position", "relative");
724
720
  const { crossFade, fade } = this.#settings.animation.content;
725
721
  const panel = this.#bindings.get(tab)?.panel;
726
722
  if (!panel) {
@@ -730,11 +726,8 @@ var Tabs = class _Tabs {
730
726
  const { style: style2 } = p;
731
727
  if (fade) {
732
728
  style2.setProperty("content-visibility", "visible");
733
- style2.setProperty("display", "block");
734
729
  style2.setProperty("opacity", p.hidden ? "0" : "1");
735
730
  }
736
- style2.setProperty("inline-size", "100%");
737
- style2.setProperty("position", "absolute");
738
731
  p === panel && !this.#hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
739
732
  });
740
733
  this.#panelElements.forEach((p, i) => {
@@ -861,6 +854,7 @@ var Tabs = class _Tabs {
861
854
  ...this.#indicatorElements,
862
855
  ...this.#panelElements
863
856
  ]);
857
+ this.#contentElement && restoreAttributes([this.#contentElement]);
864
858
  this.#listElements.length = 0;
865
859
  this.#tabElements.length = 0;
866
860
  this.#contentElement = null;
@@ -882,11 +876,13 @@ var Tabs = class _Tabs {
882
876
  "tabindex"
883
877
  ]);
884
878
  saveAttributes(this.#indicatorElements, ["style"]);
879
+ this.#contentElement && saveAttributes([this.#contentElement], ["style"]);
885
880
  saveAttributes(this.#panelElements, [
886
881
  "aria-controls",
887
882
  "aria-labelledby",
888
883
  "id",
889
884
  "role",
885
+ "style",
890
886
  "tabindex"
891
887
  ]);
892
888
  this.#eventController = new AbortController();
@@ -918,13 +914,20 @@ var Tabs = class _Tabs {
918
914
  });
919
915
  this.#indicatorElements.forEach((indicator) => {
920
916
  indicator.closest(this.#settings.selector.list)?.style.setProperty("position", "relative");
921
- const { style } = indicator;
922
- style.setProperty("display", "block");
923
- style.setProperty("position", "absolute");
917
+ const { style: style2 } = indicator;
918
+ style2.setProperty("display", "block");
919
+ style2.setProperty("position", "absolute");
924
920
  this.#indicators.push(new TabsIndicator(indicator, this.#settings));
925
921
  });
922
+ if (!this.#contentElement) {
923
+ return;
924
+ }
925
+ const { style } = this.#contentElement;
926
+ style.setProperty("align-items", "start");
927
+ style.setProperty("display", "grid");
926
928
  this.#panelElements.forEach((panel) => {
927
929
  panel.setAttribute("role", "tabpanel");
930
+ panel.style.setProperty("grid-area", "1 / 1");
928
931
  !panel.hasAttribute("hidden") && !this.#hasFocusable(panel) && panel.setAttribute("tabindex", "0");
929
932
  panel.addEventListener("beforematch", this.#onPanelBeforeMatch, {
930
933
  signal
@@ -962,17 +965,11 @@ var Tabs = class _Tabs {
962
965
  this.#isAvoidedTab(tab) && tab.blur();
963
966
  };
964
967
  #onContentAnimationFinish() {
965
- ["block-size", "overflow", "position"].forEach((name) => {
968
+ ["block-size", "overflow"].forEach((name) => {
966
969
  this.#contentElement?.style.removeProperty(name);
967
970
  });
968
971
  this.#panelElements.forEach((panel) => {
969
- [
970
- "content-visibility",
971
- "display",
972
- "inline-size",
973
- "opacity",
974
- "position"
975
- ].forEach((name) => {
972
+ ["content-visibility", "opacity"].forEach((name) => {
976
973
  panel.style.removeProperty(name);
977
974
  });
978
975
  });
@@ -1099,7 +1096,7 @@ var TabsIndicator = class {
1099
1096
  * Tabs
1100
1097
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
1101
1098
  *
1102
- * @version 2.0.5
1099
+ * @version 2.0.7
1103
1100
  * @author Yusuke Kamiyamane
1104
1101
  * @license MIT
1105
1102
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1111,7 +1108,7 @@ var TabsIndicator = class {
1111
1108
  (**
1112
1109
  * Attributes Utils
1113
1110
  *
1114
- * @version 1.1.2
1111
+ * @version 1.1.3
1115
1112
  * @author Yusuke Kamiyamane
1116
1113
  * @license MIT
1117
1114
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1124,7 +1121,7 @@ power-focusable/dist/index.js:
1124
1121
  * High-precision focus management utility with full composed tree support.
1125
1122
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1126
1123
  *
1127
- * @version 4.3.5
1124
+ * @version 4.3.10
1128
1125
  * @author Yusuke Kamiyamane
1129
1126
  * @license MIT
1130
1127
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1148,7 +1145,7 @@ power-focusable/dist/index.js:
1148
1145
  * Lightweight roving tabindex utility with fully focus management.
1149
1146
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1150
1147
  *
1151
- * @version 3.1.2
1148
+ * @version 3.1.9
1152
1149
  * @author Yusuke Kamiyamane
1153
1150
  * @license MIT
1154
1151
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.cjs CHANGED
@@ -148,7 +148,6 @@ var Tabs = class _Tabs {
148
148
  this.#rootElement.setAttribute("data-tabs-animating", "");
149
149
  const { style } = this.#contentElement;
150
150
  style.setProperty("overflow", "clip");
151
- style.setProperty("position", "relative");
152
151
  const { crossFade, fade } = this.#settings.animation.content;
153
152
  const panel = this.#bindings.get(tab)?.panel;
154
153
  if (!panel) {
@@ -158,11 +157,8 @@ var Tabs = class _Tabs {
158
157
  const { style: style2 } = p;
159
158
  if (fade) {
160
159
  style2.setProperty("content-visibility", "visible");
161
- style2.setProperty("display", "block");
162
160
  style2.setProperty("opacity", p.hidden ? "0" : "1");
163
161
  }
164
- style2.setProperty("inline-size", "100%");
165
- style2.setProperty("position", "absolute");
166
162
  p === panel && !this.#hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
167
163
  });
168
164
  this.#panelElements.forEach((p, i) => {
@@ -289,6 +285,7 @@ var Tabs = class _Tabs {
289
285
  ...this.#indicatorElements,
290
286
  ...this.#panelElements
291
287
  ]);
288
+ this.#contentElement && attributesUtils.restoreAttributes([this.#contentElement]);
292
289
  this.#listElements.length = 0;
293
290
  this.#tabElements.length = 0;
294
291
  this.#contentElement = null;
@@ -310,11 +307,13 @@ var Tabs = class _Tabs {
310
307
  "tabindex"
311
308
  ]);
312
309
  attributesUtils.saveAttributes(this.#indicatorElements, ["style"]);
310
+ this.#contentElement && attributesUtils.saveAttributes([this.#contentElement], ["style"]);
313
311
  attributesUtils.saveAttributes(this.#panelElements, [
314
312
  "aria-controls",
315
313
  "aria-labelledby",
316
314
  "id",
317
315
  "role",
316
+ "style",
318
317
  "tabindex"
319
318
  ]);
320
319
  this.#eventController = new AbortController();
@@ -346,13 +345,20 @@ var Tabs = class _Tabs {
346
345
  });
347
346
  this.#indicatorElements.forEach((indicator) => {
348
347
  indicator.closest(this.#settings.selector.list)?.style.setProperty("position", "relative");
349
- const { style } = indicator;
350
- style.setProperty("display", "block");
351
- style.setProperty("position", "absolute");
348
+ const { style: style2 } = indicator;
349
+ style2.setProperty("display", "block");
350
+ style2.setProperty("position", "absolute");
352
351
  this.#indicators.push(new TabsIndicator(indicator, this.#settings));
353
352
  });
353
+ if (!this.#contentElement) {
354
+ return;
355
+ }
356
+ const { style } = this.#contentElement;
357
+ style.setProperty("align-items", "start");
358
+ style.setProperty("display", "grid");
354
359
  this.#panelElements.forEach((panel) => {
355
360
  panel.setAttribute("role", "tabpanel");
361
+ panel.style.setProperty("grid-area", "1 / 1");
356
362
  !panel.hasAttribute("hidden") && !this.#hasFocusable(panel) && panel.setAttribute("tabindex", "0");
357
363
  panel.addEventListener("beforematch", this.#onPanelBeforeMatch, {
358
364
  signal
@@ -390,17 +396,11 @@ var Tabs = class _Tabs {
390
396
  this.#isAvoidedTab(tab) && tab.blur();
391
397
  };
392
398
  #onContentAnimationFinish() {
393
- ["block-size", "overflow", "position"].forEach((name) => {
399
+ ["block-size", "overflow"].forEach((name) => {
394
400
  this.#contentElement?.style.removeProperty(name);
395
401
  });
396
402
  this.#panelElements.forEach((panel) => {
397
- [
398
- "content-visibility",
399
- "display",
400
- "inline-size",
401
- "opacity",
402
- "position"
403
- ].forEach((name) => {
403
+ ["content-visibility", "opacity"].forEach((name) => {
404
404
  panel.style.removeProperty(name);
405
405
  });
406
406
  });
@@ -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.5
530
+ * @version 2.0.7
531
531
  * @author Yusuke Kamiyamane
532
532
  * @license MIT
533
533
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.d.cts CHANGED
@@ -2,40 +2,40 @@
2
2
  * Tabs
3
3
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
4
4
  *
5
- * @version 2.0.5
5
+ * @version 2.0.7
6
6
  * @author Yusuke Kamiyamane
7
7
  * @license MIT
8
8
  * @copyright Copyright (c) Yusuke Kamiyamane
9
9
  * @see {@link https://github.com/y14e/tabs}
10
10
  */
11
11
  interface TabsOptions {
12
- readonly animation?: {
13
- readonly content?: {
14
- readonly crossFade?: boolean;
15
- readonly duration?: number;
16
- readonly easing?: string;
17
- readonly fade?: boolean;
12
+ animation: {
13
+ content: {
14
+ crossFade: boolean;
15
+ duration: number;
16
+ easing: string;
17
+ fade: boolean;
18
18
  };
19
- readonly indicator?: {
20
- readonly duration?: number;
21
- readonly easing?: string;
19
+ indicator: {
20
+ duration: number;
21
+ easing: string;
22
22
  };
23
23
  };
24
- readonly avoidDuplicates?: boolean;
25
- readonly manual?: boolean;
26
- readonly selector?: {
27
- readonly content?: string;
28
- readonly indicator?: string;
29
- readonly list?: string;
30
- readonly panel?: string;
31
- readonly tab?: string;
24
+ avoidDuplicates: boolean;
25
+ manual: boolean;
26
+ selector: {
27
+ content: string;
28
+ indicator: string;
29
+ list: string;
30
+ panel: string;
31
+ tab: string;
32
32
  };
33
- readonly vertical?: boolean;
33
+ vertical: boolean;
34
34
  }
35
35
  declare class Tabs {
36
36
  #private;
37
- static defaults: TabsOptions;
38
- constructor(root: HTMLElement, options?: TabsOptions);
37
+ static defaults: Partial<TabsOptions>;
38
+ constructor(root: HTMLElement, options?: Partial<TabsOptions>);
39
39
  activate(tab: HTMLElement, isMatch?: boolean): void;
40
40
  destroy(force?: boolean): Promise<void>;
41
41
  }
package/dist/index.d.ts CHANGED
@@ -2,40 +2,40 @@
2
2
  * Tabs
3
3
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
4
4
  *
5
- * @version 2.0.5
5
+ * @version 2.0.7
6
6
  * @author Yusuke Kamiyamane
7
7
  * @license MIT
8
8
  * @copyright Copyright (c) Yusuke Kamiyamane
9
9
  * @see {@link https://github.com/y14e/tabs}
10
10
  */
11
11
  interface TabsOptions {
12
- readonly animation?: {
13
- readonly content?: {
14
- readonly crossFade?: boolean;
15
- readonly duration?: number;
16
- readonly easing?: string;
17
- readonly fade?: boolean;
12
+ animation: {
13
+ content: {
14
+ crossFade: boolean;
15
+ duration: number;
16
+ easing: string;
17
+ fade: boolean;
18
18
  };
19
- readonly indicator?: {
20
- readonly duration?: number;
21
- readonly easing?: string;
19
+ indicator: {
20
+ duration: number;
21
+ easing: string;
22
22
  };
23
23
  };
24
- readonly avoidDuplicates?: boolean;
25
- readonly manual?: boolean;
26
- readonly selector?: {
27
- readonly content?: string;
28
- readonly indicator?: string;
29
- readonly list?: string;
30
- readonly panel?: string;
31
- readonly tab?: string;
24
+ avoidDuplicates: boolean;
25
+ manual: boolean;
26
+ selector: {
27
+ content: string;
28
+ indicator: string;
29
+ list: string;
30
+ panel: string;
31
+ tab: string;
32
32
  };
33
- readonly vertical?: boolean;
33
+ vertical: boolean;
34
34
  }
35
35
  declare class Tabs {
36
36
  #private;
37
- static defaults: TabsOptions;
38
- constructor(root: HTMLElement, options?: TabsOptions);
37
+ static defaults: Partial<TabsOptions>;
38
+ constructor(root: HTMLElement, options?: Partial<TabsOptions>);
39
39
  activate(tab: HTMLElement, isMatch?: boolean): void;
40
40
  destroy(force?: boolean): Promise<void>;
41
41
  }
package/dist/index.js CHANGED
@@ -142,7 +142,6 @@ var Tabs = class _Tabs {
142
142
  this.#rootElement.setAttribute("data-tabs-animating", "");
143
143
  const { style } = this.#contentElement;
144
144
  style.setProperty("overflow", "clip");
145
- style.setProperty("position", "relative");
146
145
  const { crossFade, fade } = this.#settings.animation.content;
147
146
  const panel = this.#bindings.get(tab)?.panel;
148
147
  if (!panel) {
@@ -152,11 +151,8 @@ var Tabs = class _Tabs {
152
151
  const { style: style2 } = p;
153
152
  if (fade) {
154
153
  style2.setProperty("content-visibility", "visible");
155
- style2.setProperty("display", "block");
156
154
  style2.setProperty("opacity", p.hidden ? "0" : "1");
157
155
  }
158
- style2.setProperty("inline-size", "100%");
159
- style2.setProperty("position", "absolute");
160
156
  p === panel && !this.#hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
161
157
  });
162
158
  this.#panelElements.forEach((p, i) => {
@@ -283,6 +279,7 @@ var Tabs = class _Tabs {
283
279
  ...this.#indicatorElements,
284
280
  ...this.#panelElements
285
281
  ]);
282
+ this.#contentElement && restoreAttributes([this.#contentElement]);
286
283
  this.#listElements.length = 0;
287
284
  this.#tabElements.length = 0;
288
285
  this.#contentElement = null;
@@ -304,11 +301,13 @@ var Tabs = class _Tabs {
304
301
  "tabindex"
305
302
  ]);
306
303
  saveAttributes(this.#indicatorElements, ["style"]);
304
+ this.#contentElement && saveAttributes([this.#contentElement], ["style"]);
307
305
  saveAttributes(this.#panelElements, [
308
306
  "aria-controls",
309
307
  "aria-labelledby",
310
308
  "id",
311
309
  "role",
310
+ "style",
312
311
  "tabindex"
313
312
  ]);
314
313
  this.#eventController = new AbortController();
@@ -340,13 +339,20 @@ var Tabs = class _Tabs {
340
339
  });
341
340
  this.#indicatorElements.forEach((indicator) => {
342
341
  indicator.closest(this.#settings.selector.list)?.style.setProperty("position", "relative");
343
- const { style } = indicator;
344
- style.setProperty("display", "block");
345
- style.setProperty("position", "absolute");
342
+ const { style: style2 } = indicator;
343
+ style2.setProperty("display", "block");
344
+ style2.setProperty("position", "absolute");
346
345
  this.#indicators.push(new TabsIndicator(indicator, this.#settings));
347
346
  });
347
+ if (!this.#contentElement) {
348
+ return;
349
+ }
350
+ const { style } = this.#contentElement;
351
+ style.setProperty("align-items", "start");
352
+ style.setProperty("display", "grid");
348
353
  this.#panelElements.forEach((panel) => {
349
354
  panel.setAttribute("role", "tabpanel");
355
+ panel.style.setProperty("grid-area", "1 / 1");
350
356
  !panel.hasAttribute("hidden") && !this.#hasFocusable(panel) && panel.setAttribute("tabindex", "0");
351
357
  panel.addEventListener("beforematch", this.#onPanelBeforeMatch, {
352
358
  signal
@@ -384,17 +390,11 @@ var Tabs = class _Tabs {
384
390
  this.#isAvoidedTab(tab) && tab.blur();
385
391
  };
386
392
  #onContentAnimationFinish() {
387
- ["block-size", "overflow", "position"].forEach((name) => {
393
+ ["block-size", "overflow"].forEach((name) => {
388
394
  this.#contentElement?.style.removeProperty(name);
389
395
  });
390
396
  this.#panelElements.forEach((panel) => {
391
- [
392
- "content-visibility",
393
- "display",
394
- "inline-size",
395
- "opacity",
396
- "position"
397
- ].forEach((name) => {
397
+ ["content-visibility", "opacity"].forEach((name) => {
398
398
  panel.style.removeProperty(name);
399
399
  });
400
400
  });
@@ -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.5
524
+ * @version 2.0.7
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.5",
3
+ "version": "2.0.7",
4
4
  "description": "WAI-ARIA compliant tabs pattern implementation in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -44,15 +44,14 @@
44
44
  "devDependencies": {
45
45
  "bun-types": "latest",
46
46
  "tsup": "^8.0.0",
47
- "typescript": "^5.6.0",
48
- "utility-types": "^3.11.0"
47
+ "typescript": "^5.6.0"
49
48
  },
50
49
  "engines": {
51
50
  "node": ">=18"
52
51
  },
53
52
  "dependencies": {
54
- "@y14e/attributes-utils": "^1.1.2",
53
+ "@y14e/attributes-utils": "^1.1.3",
55
54
  "@y14e/button": "^1.0.6",
56
- "@y14e/roving-tabindex": "^3.1.2"
55
+ "@y14e/roving-tabindex": "^3.1.9"
57
56
  }
58
57
  }