@y14e/tabs 2.0.3 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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@2.0.3';
13
+ import Tabs from '@y14e/tabs@2.0.4';
14
14
 
15
15
  // CDNs
16
- import Tabs from 'https://esm.sh/@y14e/tabs@2.0.3';
16
+ import Tabs from 'https://esm.sh/@y14e/tabs@2.0.4';
17
17
  // or
18
- import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@2.0.3/+esm';
18
+ import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@2.0.4/+esm';
19
19
  // or
20
- import Tabs from 'https://esm.unpkg.com/@y14e/tabs@2.0.3';
20
+ import Tabs from 'https://esm.unpkg.com/@y14e/tabs@2.0.4';
21
21
  ```
22
22
 
23
23
  ## Usage
@@ -343,8 +343,14 @@ function createRovingTabIndex(container, options = {}) {
343
343
  return () => {
344
344
  };
345
345
  }
346
- const roving = new RovingTabIndex(container, options);
347
- return () => roving.destroy();
346
+ try {
347
+ const roving = new RovingTabIndex(container, options);
348
+ return () => roving.destroy();
349
+ } catch (error) {
350
+ error instanceof Error && console.warn(error.message || error);
351
+ return () => {
352
+ };
353
+ }
348
354
  }
349
355
  var RovingTabIndex = class _RovingTabIndex {
350
356
  static #initialized = /* @__PURE__ */ new Set();
@@ -420,28 +426,28 @@ var RovingTabIndex = class _RovingTabIndex {
420
426
  this.#focusablesByFirstChar.clear();
421
427
  }
422
428
  #initialize() {
423
- this.#update(document.activeElement);
429
+ this.#update(getActiveElement());
424
430
  if (!(this.#container instanceof HTMLElement)) {
425
431
  return;
426
432
  }
427
433
  this.#controller = new AbortController();
428
434
  const { signal } = this.#controller;
429
- this.#container.addEventListener("focusin", this.#onFocusIn, {
430
- capture: true,
431
- signal
432
- });
433
- this.#container.addEventListener("keydown", this.#onKeyDown, {
434
- capture: true,
435
- signal
436
- });
435
+ document.addEventListener("focusin", this.#onFocusIn, { signal });
436
+ this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, { signal });
437
+ this.#container.addEventListener("keydown", this.#onKeyDown, { signal });
437
438
  }
438
439
  #onFocusIn = (event) => {
439
440
  const { target } = event;
440
441
  if (!(target instanceof Element)) {
441
442
  return;
442
443
  }
443
- const isFocusable3 = this.#focusables.has(target);
444
- this.#settings.noMemory && !isFocusable3 ? this.#update(null) : isFocusable3 && this.#update(target);
444
+ const isFocusable2 = this.#focusables.has(target);
445
+ this.#settings.noMemory && !isFocusable2 ? this.#update() : isFocusable2 && this.#update(target);
446
+ };
447
+ #onFocusOut = (event) => {
448
+ if (!event.relatedTarget) {
449
+ this.#update();
450
+ }
445
451
  };
446
452
  #onKeyDown = (event) => {
447
453
  const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
@@ -684,7 +690,7 @@ var Tabs = class _Tabs {
684
690
  if (!panel) {
685
691
  return;
686
692
  }
687
- const binding = createBinding(tabsByIndex, panel);
693
+ const binding = this.#createBinding(tabsByIndex, panel);
688
694
  this.#bindings.set(tab, binding);
689
695
  i < length && this.#bindings.set(panel, binding);
690
696
  });
@@ -731,14 +737,14 @@ var Tabs = class _Tabs {
731
737
  }
732
738
  style2.setProperty("inline-size", "100%");
733
739
  style2.setProperty("position", "absolute");
734
- p === panel && !hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
740
+ p === panel && !this.#hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
735
741
  });
736
742
  this.#panelElements.forEach((p, i) => {
737
743
  if (p === panel) {
738
744
  p.removeAttribute("hidden");
739
745
  } else {
740
746
  const tab2 = this.#tabElements[i];
741
- tab2 && p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
747
+ tab2 && p.setAttribute("hidden", this.#isFocusable(tab2) ? "until-found" : "");
742
748
  }
743
749
  });
744
750
  this.#animation?.cancel();
@@ -771,7 +777,7 @@ var Tabs = class _Tabs {
771
777
  "finish",
772
778
  () => {
773
779
  if (this.#animation === animation) {
774
- this.#onAnimationFinish();
780
+ this.#onContentAnimationFinish();
775
781
  cleanup();
776
782
  }
777
783
  },
@@ -848,7 +854,7 @@ var Tabs = class _Tabs {
848
854
  this.#panelElements.forEach((panel) => {
849
855
  this.#bindings.get(panel)?.animation?.cancel();
850
856
  });
851
- this.#onAnimationFinish();
857
+ this.#onContentAnimationFinish();
852
858
  this.#animationController?.abort();
853
859
  this.#animationController = null;
854
860
  restoreAttributes([
@@ -906,7 +912,7 @@ var Tabs = class _Tabs {
906
912
  tab.id ||= `tabs-tab-${id}`;
907
913
  }
908
914
  tab.setAttribute("role", "tab");
909
- !isFocusable2(tab) && tab.style.setProperty("pointer-events", "none");
915
+ !this.#isFocusable(tab) && tab.style.setProperty("pointer-events", "none");
910
916
  addTokenToAttribute(panel, "aria-labelledby", tab.id);
911
917
  tab.addEventListener("click", this.#onTabClick, { signal });
912
918
  tab.addEventListener("focus", this.#onTabFocus, { signal });
@@ -921,7 +927,7 @@ var Tabs = class _Tabs {
921
927
  });
922
928
  this.#panelElements.forEach((panel) => {
923
929
  panel.setAttribute("role", "tabpanel");
924
- !panel.hasAttribute("hidden") && !hasFocusable(panel) && panel.setAttribute("tabindex", "0");
930
+ !panel.hasAttribute("hidden") && !this.#hasFocusable(panel) && panel.setAttribute("tabindex", "0");
925
931
  panel.addEventListener("beforematch", this.#onPanelBeforeMatch, {
926
932
  signal
927
933
  });
@@ -957,6 +963,23 @@ var Tabs = class _Tabs {
957
963
  !this.#settings.manual && tab.click();
958
964
  this.#isAvoidedTab(tab) && tab.blur();
959
965
  };
966
+ #onContentAnimationFinish() {
967
+ ["block-size", "overflow", "position"].forEach((name) => {
968
+ this.#contentElement?.style.removeProperty(name);
969
+ });
970
+ this.#panelElements.forEach((panel) => {
971
+ [
972
+ "content-visibility",
973
+ "display",
974
+ "inline-size",
975
+ "opacity",
976
+ "position"
977
+ ].forEach((name) => {
978
+ panel.style.removeProperty(name);
979
+ });
980
+ });
981
+ this.#rootElement.removeAttribute("data-tabs-animating");
982
+ }
960
983
  #onPanelBeforeMatch = (event) => {
961
984
  const panel = event.currentTarget;
962
985
  if (!(panel instanceof HTMLElement)) {
@@ -965,6 +988,16 @@ var Tabs = class _Tabs {
965
988
  const tab = this.#bindings.get(panel)?.tabs[0];
966
989
  tab && this.activate(tab, true);
967
990
  };
991
+ #createBinding(tabs, panel) {
992
+ return { tabs, panel, animation: null };
993
+ }
994
+ #hasFocusable(container) {
995
+ return !![
996
+ ...container.querySelectorAll(
997
+ `: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"])`
998
+ )
999
+ ].filter((element) => element.checkVisibility()).length;
1000
+ }
968
1001
  #isAvoidedTab(tab) {
969
1002
  const binding = this.#bindings.get(tab);
970
1003
  if (!binding) {
@@ -972,6 +1005,9 @@ var Tabs = class _Tabs {
972
1005
  }
973
1006
  return this.#settings.avoidDuplicates && binding.tabs.indexOf(tab) > 0;
974
1007
  }
1008
+ #isFocusable(element) {
1009
+ return !element.hasAttribute("disabled");
1010
+ }
975
1011
  #mergeOptions(target, source) {
976
1012
  return {
977
1013
  ...target,
@@ -992,23 +1028,6 @@ var Tabs = class _Tabs {
992
1028
  }
993
1029
  };
994
1030
  }
995
- #onAnimationFinish() {
996
- ["block-size", "overflow", "position"].forEach((name) => {
997
- this.#contentElement?.style.removeProperty(name);
998
- });
999
- this.#panelElements.forEach((panel) => {
1000
- [
1001
- "content-visibility",
1002
- "display",
1003
- "inline-size",
1004
- "opacity",
1005
- "position"
1006
- ].forEach((name) => {
1007
- panel.style.removeProperty(name);
1008
- });
1009
- });
1010
- this.#rootElement.removeAttribute("data-tabs-animating");
1011
- }
1012
1031
  };
1013
1032
  var TabsIndicator = class {
1014
1033
  #rootElement;
@@ -1078,24 +1097,11 @@ var TabsIndicator = class {
1078
1097
  this.#listElement = null;
1079
1098
  }
1080
1099
  };
1081
- function createBinding(tabs, panel) {
1082
- return { tabs, panel, animation: null };
1083
- }
1084
- function hasFocusable(container) {
1085
- return !![
1086
- ...container.querySelectorAll(
1087
- `: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"])`
1088
- )
1089
- ].filter((element) => element.checkVisibility()).length;
1090
- }
1091
- function isFocusable2(element) {
1092
- return !element.hasAttribute("disabled");
1093
- }
1094
1100
  /**
1095
1101
  * Tabs
1096
1102
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
1097
1103
  *
1098
- * @version 2.0.3
1104
+ * @version 2.0.4
1099
1105
  * @author Yusuke Kamiyamane
1100
1106
  * @license MIT
1101
1107
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1120,7 +1126,7 @@ power-focusable/dist/index.js:
1120
1126
  * High-precision focus management utility with full composed tree support.
1121
1127
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1122
1128
  *
1123
- * @version 4.3.3
1129
+ * @version 4.3.5
1124
1130
  * @author Yusuke Kamiyamane
1125
1131
  * @license MIT
1126
1132
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1144,7 +1150,7 @@ power-focusable/dist/index.js:
1144
1150
  * Lightweight roving tabindex utility with fully focus management.
1145
1151
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1146
1152
  *
1147
- * @version 3.0.12
1153
+ * @version 3.1.2
1148
1154
  * @author Yusuke Kamiyamane
1149
1155
  * @license MIT
1150
1156
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -341,8 +341,14 @@ function createRovingTabIndex(container, options = {}) {
341
341
  return () => {
342
342
  };
343
343
  }
344
- const roving = new RovingTabIndex(container, options);
345
- return () => roving.destroy();
344
+ try {
345
+ const roving = new RovingTabIndex(container, options);
346
+ return () => roving.destroy();
347
+ } catch (error) {
348
+ error instanceof Error && console.warn(error.message || error);
349
+ return () => {
350
+ };
351
+ }
346
352
  }
347
353
  var RovingTabIndex = class _RovingTabIndex {
348
354
  static #initialized = /* @__PURE__ */ new Set();
@@ -418,28 +424,28 @@ var RovingTabIndex = class _RovingTabIndex {
418
424
  this.#focusablesByFirstChar.clear();
419
425
  }
420
426
  #initialize() {
421
- this.#update(document.activeElement);
427
+ this.#update(getActiveElement());
422
428
  if (!(this.#container instanceof HTMLElement)) {
423
429
  return;
424
430
  }
425
431
  this.#controller = new AbortController();
426
432
  const { signal } = this.#controller;
427
- this.#container.addEventListener("focusin", this.#onFocusIn, {
428
- capture: true,
429
- signal
430
- });
431
- this.#container.addEventListener("keydown", this.#onKeyDown, {
432
- capture: true,
433
- signal
434
- });
433
+ document.addEventListener("focusin", this.#onFocusIn, { signal });
434
+ this.#settings.noMemory && document.addEventListener("focusout", this.#onFocusOut, { signal });
435
+ this.#container.addEventListener("keydown", this.#onKeyDown, { signal });
435
436
  }
436
437
  #onFocusIn = (event) => {
437
438
  const { target } = event;
438
439
  if (!(target instanceof Element)) {
439
440
  return;
440
441
  }
441
- const isFocusable3 = this.#focusables.has(target);
442
- this.#settings.noMemory && !isFocusable3 ? this.#update(null) : isFocusable3 && this.#update(target);
442
+ const isFocusable2 = this.#focusables.has(target);
443
+ this.#settings.noMemory && !isFocusable2 ? this.#update() : isFocusable2 && this.#update(target);
444
+ };
445
+ #onFocusOut = (event) => {
446
+ if (!event.relatedTarget) {
447
+ this.#update();
448
+ }
443
449
  };
444
450
  #onKeyDown = (event) => {
445
451
  const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
@@ -682,7 +688,7 @@ var Tabs = class _Tabs {
682
688
  if (!panel) {
683
689
  return;
684
690
  }
685
- const binding = createBinding(tabsByIndex, panel);
691
+ const binding = this.#createBinding(tabsByIndex, panel);
686
692
  this.#bindings.set(tab, binding);
687
693
  i < length && this.#bindings.set(panel, binding);
688
694
  });
@@ -729,14 +735,14 @@ var Tabs = class _Tabs {
729
735
  }
730
736
  style2.setProperty("inline-size", "100%");
731
737
  style2.setProperty("position", "absolute");
732
- p === panel && !hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
738
+ p === panel && !this.#hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
733
739
  });
734
740
  this.#panelElements.forEach((p, i) => {
735
741
  if (p === panel) {
736
742
  p.removeAttribute("hidden");
737
743
  } else {
738
744
  const tab2 = this.#tabElements[i];
739
- tab2 && p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
745
+ tab2 && p.setAttribute("hidden", this.#isFocusable(tab2) ? "until-found" : "");
740
746
  }
741
747
  });
742
748
  this.#animation?.cancel();
@@ -769,7 +775,7 @@ var Tabs = class _Tabs {
769
775
  "finish",
770
776
  () => {
771
777
  if (this.#animation === animation) {
772
- this.#onAnimationFinish();
778
+ this.#onContentAnimationFinish();
773
779
  cleanup();
774
780
  }
775
781
  },
@@ -846,7 +852,7 @@ var Tabs = class _Tabs {
846
852
  this.#panelElements.forEach((panel) => {
847
853
  this.#bindings.get(panel)?.animation?.cancel();
848
854
  });
849
- this.#onAnimationFinish();
855
+ this.#onContentAnimationFinish();
850
856
  this.#animationController?.abort();
851
857
  this.#animationController = null;
852
858
  restoreAttributes([
@@ -904,7 +910,7 @@ var Tabs = class _Tabs {
904
910
  tab.id ||= `tabs-tab-${id}`;
905
911
  }
906
912
  tab.setAttribute("role", "tab");
907
- !isFocusable2(tab) && tab.style.setProperty("pointer-events", "none");
913
+ !this.#isFocusable(tab) && tab.style.setProperty("pointer-events", "none");
908
914
  addTokenToAttribute(panel, "aria-labelledby", tab.id);
909
915
  tab.addEventListener("click", this.#onTabClick, { signal });
910
916
  tab.addEventListener("focus", this.#onTabFocus, { signal });
@@ -919,7 +925,7 @@ var Tabs = class _Tabs {
919
925
  });
920
926
  this.#panelElements.forEach((panel) => {
921
927
  panel.setAttribute("role", "tabpanel");
922
- !panel.hasAttribute("hidden") && !hasFocusable(panel) && panel.setAttribute("tabindex", "0");
928
+ !panel.hasAttribute("hidden") && !this.#hasFocusable(panel) && panel.setAttribute("tabindex", "0");
923
929
  panel.addEventListener("beforematch", this.#onPanelBeforeMatch, {
924
930
  signal
925
931
  });
@@ -955,6 +961,23 @@ var Tabs = class _Tabs {
955
961
  !this.#settings.manual && tab.click();
956
962
  this.#isAvoidedTab(tab) && tab.blur();
957
963
  };
964
+ #onContentAnimationFinish() {
965
+ ["block-size", "overflow", "position"].forEach((name) => {
966
+ this.#contentElement?.style.removeProperty(name);
967
+ });
968
+ this.#panelElements.forEach((panel) => {
969
+ [
970
+ "content-visibility",
971
+ "display",
972
+ "inline-size",
973
+ "opacity",
974
+ "position"
975
+ ].forEach((name) => {
976
+ panel.style.removeProperty(name);
977
+ });
978
+ });
979
+ this.#rootElement.removeAttribute("data-tabs-animating");
980
+ }
958
981
  #onPanelBeforeMatch = (event) => {
959
982
  const panel = event.currentTarget;
960
983
  if (!(panel instanceof HTMLElement)) {
@@ -963,6 +986,16 @@ var Tabs = class _Tabs {
963
986
  const tab = this.#bindings.get(panel)?.tabs[0];
964
987
  tab && this.activate(tab, true);
965
988
  };
989
+ #createBinding(tabs, panel) {
990
+ return { tabs, panel, animation: null };
991
+ }
992
+ #hasFocusable(container) {
993
+ return !![
994
+ ...container.querySelectorAll(
995
+ `: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"])`
996
+ )
997
+ ].filter((element) => element.checkVisibility()).length;
998
+ }
966
999
  #isAvoidedTab(tab) {
967
1000
  const binding = this.#bindings.get(tab);
968
1001
  if (!binding) {
@@ -970,6 +1003,9 @@ var Tabs = class _Tabs {
970
1003
  }
971
1004
  return this.#settings.avoidDuplicates && binding.tabs.indexOf(tab) > 0;
972
1005
  }
1006
+ #isFocusable(element) {
1007
+ return !element.hasAttribute("disabled");
1008
+ }
973
1009
  #mergeOptions(target, source) {
974
1010
  return {
975
1011
  ...target,
@@ -990,23 +1026,6 @@ var Tabs = class _Tabs {
990
1026
  }
991
1027
  };
992
1028
  }
993
- #onAnimationFinish() {
994
- ["block-size", "overflow", "position"].forEach((name) => {
995
- this.#contentElement?.style.removeProperty(name);
996
- });
997
- this.#panelElements.forEach((panel) => {
998
- [
999
- "content-visibility",
1000
- "display",
1001
- "inline-size",
1002
- "opacity",
1003
- "position"
1004
- ].forEach((name) => {
1005
- panel.style.removeProperty(name);
1006
- });
1007
- });
1008
- this.#rootElement.removeAttribute("data-tabs-animating");
1009
- }
1010
1029
  };
1011
1030
  var TabsIndicator = class {
1012
1031
  #rootElement;
@@ -1076,24 +1095,11 @@ var TabsIndicator = class {
1076
1095
  this.#listElement = null;
1077
1096
  }
1078
1097
  };
1079
- function createBinding(tabs, panel) {
1080
- return { tabs, panel, animation: null };
1081
- }
1082
- function hasFocusable(container) {
1083
- return !![
1084
- ...container.querySelectorAll(
1085
- `: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"])`
1086
- )
1087
- ].filter((element) => element.checkVisibility()).length;
1088
- }
1089
- function isFocusable2(element) {
1090
- return !element.hasAttribute("disabled");
1091
- }
1092
1098
  /**
1093
1099
  * Tabs
1094
1100
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
1095
1101
  *
1096
- * @version 2.0.3
1102
+ * @version 2.0.4
1097
1103
  * @author Yusuke Kamiyamane
1098
1104
  * @license MIT
1099
1105
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1118,7 +1124,7 @@ power-focusable/dist/index.js:
1118
1124
  * High-precision focus management utility with full composed tree support.
1119
1125
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1120
1126
  *
1121
- * @version 4.3.3
1127
+ * @version 4.3.5
1122
1128
  * @author Yusuke Kamiyamane
1123
1129
  * @license MIT
1124
1130
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1142,7 +1148,7 @@ power-focusable/dist/index.js:
1142
1148
  * Lightweight roving tabindex utility with fully focus management.
1143
1149
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1144
1150
  *
1145
- * @version 3.0.12
1151
+ * @version 3.1.2
1146
1152
  * @author Yusuke Kamiyamane
1147
1153
  * @license MIT
1148
1154
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.cjs CHANGED
@@ -116,7 +116,7 @@ var Tabs = class _Tabs {
116
116
  if (!panel) {
117
117
  return;
118
118
  }
119
- const binding = createBinding(tabsByIndex, panel);
119
+ const binding = this.#createBinding(tabsByIndex, panel);
120
120
  this.#bindings.set(tab, binding);
121
121
  i < length && this.#bindings.set(panel, binding);
122
122
  });
@@ -163,14 +163,14 @@ var Tabs = class _Tabs {
163
163
  }
164
164
  style2.setProperty("inline-size", "100%");
165
165
  style2.setProperty("position", "absolute");
166
- p === panel && !hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
166
+ p === panel && !this.#hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
167
167
  });
168
168
  this.#panelElements.forEach((p, i) => {
169
169
  if (p === panel) {
170
170
  p.removeAttribute("hidden");
171
171
  } else {
172
172
  const tab2 = this.#tabElements[i];
173
- tab2 && p.setAttribute("hidden", isFocusable(tab2) ? "until-found" : "");
173
+ tab2 && p.setAttribute("hidden", this.#isFocusable(tab2) ? "until-found" : "");
174
174
  }
175
175
  });
176
176
  this.#animation?.cancel();
@@ -203,7 +203,7 @@ var Tabs = class _Tabs {
203
203
  "finish",
204
204
  () => {
205
205
  if (this.#animation === animation) {
206
- this.#onAnimationFinish();
206
+ this.#onContentAnimationFinish();
207
207
  cleanup();
208
208
  }
209
209
  },
@@ -280,7 +280,7 @@ var Tabs = class _Tabs {
280
280
  this.#panelElements.forEach((panel) => {
281
281
  this.#bindings.get(panel)?.animation?.cancel();
282
282
  });
283
- this.#onAnimationFinish();
283
+ this.#onContentAnimationFinish();
284
284
  this.#animationController?.abort();
285
285
  this.#animationController = null;
286
286
  attributesUtils.restoreAttributes([
@@ -338,7 +338,7 @@ var Tabs = class _Tabs {
338
338
  tab.id ||= `tabs-tab-${id}`;
339
339
  }
340
340
  tab.setAttribute("role", "tab");
341
- !isFocusable(tab) && tab.style.setProperty("pointer-events", "none");
341
+ !this.#isFocusable(tab) && tab.style.setProperty("pointer-events", "none");
342
342
  attributesUtils.addTokenToAttribute(panel, "aria-labelledby", tab.id);
343
343
  tab.addEventListener("click", this.#onTabClick, { signal });
344
344
  tab.addEventListener("focus", this.#onTabFocus, { signal });
@@ -353,7 +353,7 @@ var Tabs = class _Tabs {
353
353
  });
354
354
  this.#panelElements.forEach((panel) => {
355
355
  panel.setAttribute("role", "tabpanel");
356
- !panel.hasAttribute("hidden") && !hasFocusable(panel) && panel.setAttribute("tabindex", "0");
356
+ !panel.hasAttribute("hidden") && !this.#hasFocusable(panel) && panel.setAttribute("tabindex", "0");
357
357
  panel.addEventListener("beforematch", this.#onPanelBeforeMatch, {
358
358
  signal
359
359
  });
@@ -389,6 +389,23 @@ var Tabs = class _Tabs {
389
389
  !this.#settings.manual && tab.click();
390
390
  this.#isAvoidedTab(tab) && tab.blur();
391
391
  };
392
+ #onContentAnimationFinish() {
393
+ ["block-size", "overflow", "position"].forEach((name) => {
394
+ this.#contentElement?.style.removeProperty(name);
395
+ });
396
+ this.#panelElements.forEach((panel) => {
397
+ [
398
+ "content-visibility",
399
+ "display",
400
+ "inline-size",
401
+ "opacity",
402
+ "position"
403
+ ].forEach((name) => {
404
+ panel.style.removeProperty(name);
405
+ });
406
+ });
407
+ this.#rootElement.removeAttribute("data-tabs-animating");
408
+ }
392
409
  #onPanelBeforeMatch = (event) => {
393
410
  const panel = event.currentTarget;
394
411
  if (!(panel instanceof HTMLElement)) {
@@ -397,6 +414,16 @@ var Tabs = class _Tabs {
397
414
  const tab = this.#bindings.get(panel)?.tabs[0];
398
415
  tab && this.activate(tab, true);
399
416
  };
417
+ #createBinding(tabs, panel) {
418
+ return { tabs, panel, animation: null };
419
+ }
420
+ #hasFocusable(container) {
421
+ return !![
422
+ ...container.querySelectorAll(
423
+ `: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"])`
424
+ )
425
+ ].filter((element) => element.checkVisibility()).length;
426
+ }
400
427
  #isAvoidedTab(tab) {
401
428
  const binding = this.#bindings.get(tab);
402
429
  if (!binding) {
@@ -404,6 +431,9 @@ var Tabs = class _Tabs {
404
431
  }
405
432
  return this.#settings.avoidDuplicates && binding.tabs.indexOf(tab) > 0;
406
433
  }
434
+ #isFocusable(element) {
435
+ return !element.hasAttribute("disabled");
436
+ }
407
437
  #mergeOptions(target, source) {
408
438
  return {
409
439
  ...target,
@@ -424,23 +454,6 @@ var Tabs = class _Tabs {
424
454
  }
425
455
  };
426
456
  }
427
- #onAnimationFinish() {
428
- ["block-size", "overflow", "position"].forEach((name) => {
429
- this.#contentElement?.style.removeProperty(name);
430
- });
431
- this.#panelElements.forEach((panel) => {
432
- [
433
- "content-visibility",
434
- "display",
435
- "inline-size",
436
- "opacity",
437
- "position"
438
- ].forEach((name) => {
439
- panel.style.removeProperty(name);
440
- });
441
- });
442
- this.#rootElement.removeAttribute("data-tabs-animating");
443
- }
444
457
  };
445
458
  var TabsIndicator = class {
446
459
  #rootElement;
@@ -510,24 +523,11 @@ var TabsIndicator = class {
510
523
  this.#listElement = null;
511
524
  }
512
525
  };
513
- function createBinding(tabs, panel) {
514
- return { tabs, panel, animation: null };
515
- }
516
- function hasFocusable(container) {
517
- return !![
518
- ...container.querySelectorAll(
519
- `: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"])`
520
- )
521
- ].filter((element) => element.checkVisibility()).length;
522
- }
523
- function isFocusable(element) {
524
- return !element.hasAttribute("disabled");
525
- }
526
526
  /**
527
527
  * Tabs
528
528
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
529
529
  *
530
- * @version 2.0.3
530
+ * @version 2.0.4
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.3
5
+ * @version 2.0.4
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.3
5
+ * @version 2.0.4
6
6
  * @author Yusuke Kamiyamane
7
7
  * @license MIT
8
8
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -110,7 +110,7 @@ var Tabs = class _Tabs {
110
110
  if (!panel) {
111
111
  return;
112
112
  }
113
- const binding = createBinding(tabsByIndex, panel);
113
+ const binding = this.#createBinding(tabsByIndex, panel);
114
114
  this.#bindings.set(tab, binding);
115
115
  i < length && this.#bindings.set(panel, binding);
116
116
  });
@@ -157,14 +157,14 @@ var Tabs = class _Tabs {
157
157
  }
158
158
  style2.setProperty("inline-size", "100%");
159
159
  style2.setProperty("position", "absolute");
160
- p === panel && !hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
160
+ p === panel && !this.#hasFocusable(p) ? p.setAttribute("tabindex", "0") : p.removeAttribute("tabindex");
161
161
  });
162
162
  this.#panelElements.forEach((p, i) => {
163
163
  if (p === panel) {
164
164
  p.removeAttribute("hidden");
165
165
  } else {
166
166
  const tab2 = this.#tabElements[i];
167
- tab2 && p.setAttribute("hidden", isFocusable(tab2) ? "until-found" : "");
167
+ tab2 && p.setAttribute("hidden", this.#isFocusable(tab2) ? "until-found" : "");
168
168
  }
169
169
  });
170
170
  this.#animation?.cancel();
@@ -197,7 +197,7 @@ var Tabs = class _Tabs {
197
197
  "finish",
198
198
  () => {
199
199
  if (this.#animation === animation) {
200
- this.#onAnimationFinish();
200
+ this.#onContentAnimationFinish();
201
201
  cleanup();
202
202
  }
203
203
  },
@@ -274,7 +274,7 @@ var Tabs = class _Tabs {
274
274
  this.#panelElements.forEach((panel) => {
275
275
  this.#bindings.get(panel)?.animation?.cancel();
276
276
  });
277
- this.#onAnimationFinish();
277
+ this.#onContentAnimationFinish();
278
278
  this.#animationController?.abort();
279
279
  this.#animationController = null;
280
280
  restoreAttributes([
@@ -332,7 +332,7 @@ var Tabs = class _Tabs {
332
332
  tab.id ||= `tabs-tab-${id}`;
333
333
  }
334
334
  tab.setAttribute("role", "tab");
335
- !isFocusable(tab) && tab.style.setProperty("pointer-events", "none");
335
+ !this.#isFocusable(tab) && tab.style.setProperty("pointer-events", "none");
336
336
  addTokenToAttribute(panel, "aria-labelledby", tab.id);
337
337
  tab.addEventListener("click", this.#onTabClick, { signal });
338
338
  tab.addEventListener("focus", this.#onTabFocus, { signal });
@@ -347,7 +347,7 @@ var Tabs = class _Tabs {
347
347
  });
348
348
  this.#panelElements.forEach((panel) => {
349
349
  panel.setAttribute("role", "tabpanel");
350
- !panel.hasAttribute("hidden") && !hasFocusable(panel) && panel.setAttribute("tabindex", "0");
350
+ !panel.hasAttribute("hidden") && !this.#hasFocusable(panel) && panel.setAttribute("tabindex", "0");
351
351
  panel.addEventListener("beforematch", this.#onPanelBeforeMatch, {
352
352
  signal
353
353
  });
@@ -383,6 +383,23 @@ var Tabs = class _Tabs {
383
383
  !this.#settings.manual && tab.click();
384
384
  this.#isAvoidedTab(tab) && tab.blur();
385
385
  };
386
+ #onContentAnimationFinish() {
387
+ ["block-size", "overflow", "position"].forEach((name) => {
388
+ this.#contentElement?.style.removeProperty(name);
389
+ });
390
+ this.#panelElements.forEach((panel) => {
391
+ [
392
+ "content-visibility",
393
+ "display",
394
+ "inline-size",
395
+ "opacity",
396
+ "position"
397
+ ].forEach((name) => {
398
+ panel.style.removeProperty(name);
399
+ });
400
+ });
401
+ this.#rootElement.removeAttribute("data-tabs-animating");
402
+ }
386
403
  #onPanelBeforeMatch = (event) => {
387
404
  const panel = event.currentTarget;
388
405
  if (!(panel instanceof HTMLElement)) {
@@ -391,6 +408,16 @@ var Tabs = class _Tabs {
391
408
  const tab = this.#bindings.get(panel)?.tabs[0];
392
409
  tab && this.activate(tab, true);
393
410
  };
411
+ #createBinding(tabs, panel) {
412
+ return { tabs, panel, animation: null };
413
+ }
414
+ #hasFocusable(container) {
415
+ return !![
416
+ ...container.querySelectorAll(
417
+ `: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"])`
418
+ )
419
+ ].filter((element) => element.checkVisibility()).length;
420
+ }
394
421
  #isAvoidedTab(tab) {
395
422
  const binding = this.#bindings.get(tab);
396
423
  if (!binding) {
@@ -398,6 +425,9 @@ var Tabs = class _Tabs {
398
425
  }
399
426
  return this.#settings.avoidDuplicates && binding.tabs.indexOf(tab) > 0;
400
427
  }
428
+ #isFocusable(element) {
429
+ return !element.hasAttribute("disabled");
430
+ }
401
431
  #mergeOptions(target, source) {
402
432
  return {
403
433
  ...target,
@@ -418,23 +448,6 @@ var Tabs = class _Tabs {
418
448
  }
419
449
  };
420
450
  }
421
- #onAnimationFinish() {
422
- ["block-size", "overflow", "position"].forEach((name) => {
423
- this.#contentElement?.style.removeProperty(name);
424
- });
425
- this.#panelElements.forEach((panel) => {
426
- [
427
- "content-visibility",
428
- "display",
429
- "inline-size",
430
- "opacity",
431
- "position"
432
- ].forEach((name) => {
433
- panel.style.removeProperty(name);
434
- });
435
- });
436
- this.#rootElement.removeAttribute("data-tabs-animating");
437
- }
438
451
  };
439
452
  var TabsIndicator = class {
440
453
  #rootElement;
@@ -504,24 +517,11 @@ var TabsIndicator = class {
504
517
  this.#listElement = null;
505
518
  }
506
519
  };
507
- function createBinding(tabs, panel) {
508
- return { tabs, panel, animation: null };
509
- }
510
- function hasFocusable(container) {
511
- return !![
512
- ...container.querySelectorAll(
513
- `: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"])`
514
- )
515
- ].filter((element) => element.checkVisibility()).length;
516
- }
517
- function isFocusable(element) {
518
- return !element.hasAttribute("disabled");
519
- }
520
520
  /**
521
521
  * Tabs
522
522
  * WAI-ARIA compliant tabs pattern implementation in TypeScript.
523
523
  *
524
- * @version 2.0.3
524
+ * @version 2.0.4
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.3",
3
+ "version": "2.0.4",
4
4
  "description": "WAI-ARIA compliant tabs pattern implementation in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -53,6 +53,6 @@
53
53
  "dependencies": {
54
54
  "@y14e/attributes-utils": "^1.1.2",
55
55
  "@y14e/button": "^1.0.6",
56
- "@y14e/roving-tabindex": "^3.0.12"
56
+ "@y14e/roving-tabindex": "^3.1.2"
57
57
  }
58
58
  }