@y14e/accordion 2.0.14 → 2.0.16

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/accordion
10
10
 
11
11
  ```ts
12
12
  // npm
13
- import { Accordion } from "@y14e/accordion";
13
+ import { Accordion } from '@y14e/accordion';
14
14
 
15
15
  // CDNs
16
- import { Accordion } from "https://esm.sh/@y14e/accordion@2.0.14";
16
+ import { Accordion } from 'https://esm.sh/@y14e/accordion@2.0.16';
17
17
  // or
18
- import { Accordion } from "https://cdn.jsdelivr.net/npm/@y14e/accordion@2.0.14/+esm";
18
+ import { Accordion } from 'https://cdn.jsdelivr.net/npm/@y14e/accordion@2.0.16/+esm';
19
19
  // or
20
- import { Accordion } from "https://esm.unpkg.com/@y14e/accordion@2.0.14";
20
+ import { Accordion } from 'https://esm.unpkg.com/@y14e/accordion@2.0.16';
21
21
  ```
22
22
 
23
23
  ## Usage
@@ -51,15 +51,15 @@ interface AccordionOptions {
51
51
  Override the global default settings applied to all accordion instances.
52
52
 
53
53
  ```ts
54
- import { Accordion } from "@y14e/accordion";
54
+ import { Accordion } from '@y14e/accordion';
55
55
 
56
56
  Accordion.defaults = {
57
57
  animation: {
58
58
  duration: 1000,
59
59
  },
60
60
  selector: {
61
- content: ".content",
62
- trigger: ".trigger",
61
+ content: '.content',
62
+ trigger: '.trigger',
63
63
  },
64
64
  };
65
65
 
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  // node_modules/@y14e/attribute-utils/dist/index.js
4
- var DEFAULT_PARSER = (value) => value.split(/\s+/);
5
- var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
4
+ var DEFAULT_PARSER = (v) => v.split(/\s+/);
5
+ var DEFAULT_SERIALIZER = (t) => t.join(" ");
6
6
  function addAttributeToken(element, name, token, options = {}) {
7
7
  if (!isValid(element, name, token)) {
8
8
  return;
@@ -12,7 +12,7 @@ function addAttributeToken(element, name, token, options = {}) {
12
12
  const tokens = value ? parse(value).filter(Boolean) : [];
13
13
  if (caseInsensitive) {
14
14
  const lower = token.toLowerCase();
15
- if (tokens.every((token2) => token2.toLowerCase() !== lower)) {
15
+ if (tokens.every((t) => t.toLowerCase() !== lower)) {
16
16
  tokens.push(token);
17
17
  element.setAttribute(name, serialize(tokens));
18
18
  }
@@ -37,16 +37,16 @@ function restoreAttributes(element_or_elements) {
37
37
  }
38
38
  function saveAttributes(element_or_elements, name_or_names) {
39
39
  const names = Array.isArray(name_or_names) ? name_or_names : [name_or_names];
40
- (Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]).forEach((element) => {
40
+ for (const element of Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]) {
41
41
  let snapshot = snapshots.get(element);
42
42
  if (!snapshot) {
43
43
  snapshot = /* @__PURE__ */ new Map();
44
44
  snapshots.set(element, snapshot);
45
45
  }
46
- names.forEach((name) => {
46
+ for (const name of names) {
47
47
  snapshot.set(name, element.getAttribute(name));
48
- });
49
- });
48
+ }
49
+ }
50
50
  }
51
51
  function isValid(element, name, token) {
52
52
  if (!(element instanceof Element)) {
@@ -91,7 +91,7 @@ function resolveOptions(options) {
91
91
  }
92
92
 
93
93
  // node_modules/power-focusable/dist/index.js
94
- var FOCUSABLE_SELECTOR = `:is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])`;
94
+ var FOCUSABLE_SELECTOR = ':is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])';
95
95
  var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX = FOCUSABLE_SELECTOR.replace(
96
96
  /(,\s*)?\[tabindex="-1"\]/g,
97
97
  ""
@@ -115,31 +115,21 @@ function getFocusables(container = document.body, options = {}) {
115
115
  skipNegativeTabIndexCheck,
116
116
  skipVisibilityCheck
117
117
  }) || include?.(node)) {
118
- candidates[candidates.length] = node;
119
- }
120
- const children2 = composed ? getComposedChildren(node) : getChildren(node);
121
- for (let i = 0, l = children2.length; i < l; i++) {
122
- const child = children2[i];
123
- child && traverse2(child);
118
+ candidates.push(node);
124
119
  }
120
+ (composed ? getComposedChildren(node) : [...node.children]).map(traverse2);
125
121
  };
126
- const children = composed ? getComposedChildren(container) : getChildren(container);
127
- for (let i = 0, l = children.length; i < l; i++) {
128
- const child = children[i];
129
- child && traverse2(child);
130
- }
122
+ (composed ? getComposedChildren(container) : [...container.children]).map(
123
+ traverse2
124
+ );
131
125
  } else {
132
- const matches = container.querySelectorAll(
126
+ for (const match of container.querySelectorAll(
133
127
  skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX : FOCUSABLE_SELECTOR
134
- );
135
- for (let i = 0, l = matches.length; i < l; i++) {
136
- const matched = matches[i];
137
- if (matched && isFocusable(matched, {
128
+ )) {
129
+ match && isFocusable(match, {
138
130
  skipNegativeTabIndexCheck,
139
131
  skipVisibilityCheck
140
- })) {
141
- candidates[candidates.length] = matched;
142
- }
132
+ }) && candidates.push(match);
143
133
  }
144
134
  }
145
135
  return normalizeRadioGroup(
@@ -206,8 +196,7 @@ function isDisabledDeep(element) {
206
196
  }
207
197
  function normalizeRadioGroup(elements) {
208
198
  let map = null;
209
- for (let i = 0, l = elements.length; i < l; i++) {
210
- const element = elements[i];
199
+ for (const element of elements) {
211
200
  if (!(element instanceof HTMLInputElement)) {
212
201
  continue;
213
202
  }
@@ -218,31 +207,31 @@ function normalizeRadioGroup(elements) {
218
207
  map = /* @__PURE__ */ new Map();
219
208
  }
220
209
  const root = element.getRootNode();
221
- let value = map.get(root);
222
- if (!value) {
223
- value = /* @__PURE__ */ new Map();
224
- map.set(root, value);
225
- }
226
- let v = value.get(element.form);
227
- if (!v) {
228
- v = /* @__PURE__ */ new Map();
229
- value.set(element.form, v);
230
- }
231
- let vv = v.get(element.name);
232
- if (!vv) {
233
- vv = [];
234
- v.set(element.name, vv);
235
- }
236
- vv[vv.length] = element;
210
+ let groups = map.get(root);
211
+ if (!groups) {
212
+ groups = /* @__PURE__ */ new Map();
213
+ map.set(root, groups);
214
+ }
215
+ let group = groups.get(element.form);
216
+ if (!group) {
217
+ group = /* @__PURE__ */ new Map();
218
+ groups.set(element.form, group);
219
+ }
220
+ let radios = group.get(element.name);
221
+ if (!radios) {
222
+ radios = [];
223
+ group.set(element.name, radios);
224
+ }
225
+ radios.push(element);
237
226
  }
238
227
  if (!map) {
239
228
  return elements;
240
229
  }
241
230
  const placeholder = /* @__PURE__ */ new Set();
242
- for (const value of map.values()) {
243
- for (const v of value.values()) {
244
- for (const vv of v.values()) {
245
- const radio = vv.find((element) => element.checked) ?? vv[0];
231
+ for (const groups of map.values()) {
232
+ for (const group of groups.values()) {
233
+ for (const radios of group.values()) {
234
+ const radio = radios.find((r) => r.checked) ?? radios[0];
246
235
  radio && placeholder.add(radio);
247
236
  }
248
237
  }
@@ -257,27 +246,14 @@ function normalizeRadioGroup(elements) {
257
246
  function sortByTabIndex(elements) {
258
247
  const ordered = [];
259
248
  const natural = [];
260
- for (let i = 0, l = elements.length; i < l; i++) {
261
- const element = elements[i];
262
- if (element) {
263
- const target = getTabIndex(element) > 0 ? ordered : natural;
264
- target[target.length] = element;
265
- }
266
- }
267
- ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
268
- let count = 0;
269
- const sorted = new Array(ordered.length + natural.length);
270
- for (let i = 0, l = ordered.length; i < l; i++) {
271
- sorted[count++] = ordered[i];
249
+ for (const element of elements) {
250
+ (getTabIndex(element) > 0 ? ordered : natural).push(element);
272
251
  }
273
- for (let i = 0, l = natural.length; i < l; i++) {
274
- sorted[count++] = natural[i];
275
- }
276
- return sorted;
252
+ return ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b)).concat(natural);
277
253
  }
278
254
  function getComposedChildren(node) {
279
255
  if (node instanceof ShadowRoot) {
280
- return getChildren(node);
256
+ return [...node.children];
281
257
  }
282
258
  if (!(node instanceof Element)) {
283
259
  return [];
@@ -289,9 +265,9 @@ function getComposedChildren(node) {
289
265
  }
290
266
  }
291
267
  if (node instanceof HTMLElement && node.shadowRoot?.mode === "open") {
292
- return getChildren(node.shadowRoot);
268
+ return [...node.shadowRoot.children];
293
269
  }
294
- return getChildren(node);
270
+ return [...node.children];
295
271
  }
296
272
  function focusElement(element) {
297
273
  "focus" in element && typeof element.focus === "function" && element.focus();
@@ -303,13 +279,6 @@ function getActiveElement() {
303
279
  }
304
280
  return current;
305
281
  }
306
- function getChildren(node) {
307
- const elements = [];
308
- for (let child = node.firstElementChild; child; child = child.nextElementSibling) {
309
- elements[elements.length] = child;
310
- }
311
- return elements;
312
- }
313
282
  function getTabIndex(element) {
314
283
  return "tabIndex" in element ? Number(element.tabIndex) : 0;
315
284
  }
@@ -463,10 +432,10 @@ var RovingTabIndex = class _RovingTabIndex {
463
432
  this.#isDestroyed = true;
464
433
  this.#controller?.abort();
465
434
  this.#controller = null;
466
- this.#focusables.forEach((focusable) => {
435
+ for (const focusable of this.#focusables) {
467
436
  _RovingTabIndex.#initialized.delete(focusable);
468
437
  restoreAttributes(focusable);
469
- });
438
+ }
470
439
  this.#focusables.clear();
471
440
  this.#focusablesByFirstChar.clear();
472
441
  }
@@ -516,7 +485,7 @@ var RovingTabIndex = class _RovingTabIndex {
516
485
  }
517
486
  }
518
487
  const candidates = this.#getFocusables().filter(
519
- (focusable2) => this.#focusables.has(focusable2)
488
+ (f) => this.#focusables.has(f)
520
489
  );
521
490
  const active = getActiveElement();
522
491
  if (!(active instanceof Element)) {
@@ -553,11 +522,9 @@ var RovingTabIndex = class _RovingTabIndex {
553
522
  const focusablesByFirstChar = new Set(
554
523
  this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
555
524
  );
556
- focusables = candidates.filter(
557
- (candidate) => focusablesByFirstChar.has(candidate)
558
- );
525
+ focusables = candidates.filter((c) => focusablesByFirstChar.has(c));
559
526
  const afterIndex = focusables.findIndex(
560
- (focusable2) => candidates.indexOf(focusable2) > activeIndex
527
+ (f) => candidates.indexOf(f) > activeIndex
561
528
  );
562
529
  newIndex = afterIndex >= 0 ? afterIndex : 0;
563
530
  }
@@ -601,7 +568,7 @@ var RovingTabIndex = class _RovingTabIndex {
601
568
  const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
602
569
  const value = focusable.ariaKeyShortcuts?.trim();
603
570
  const keys = new Set(
604
- value ? value.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
571
+ value ? value.split(/\s+/).filter((k) => /^\S$/i.test(k)).map((k) => k.toUpperCase()) : []
605
572
  );
606
573
  if (char) {
607
574
  keys.add(char);
@@ -610,17 +577,17 @@ var RovingTabIndex = class _RovingTabIndex {
610
577
  caseInsensitive: true
611
578
  });
612
579
  }
613
- keys.forEach((key) => {
580
+ for (const key of keys) {
614
581
  const focusables = this.#focusablesByFirstChar.get(key) ?? [];
615
582
  focusables.push(focusable);
616
583
  this.#focusablesByFirstChar.set(key, focusables);
617
- });
584
+ }
618
585
  }
619
586
  if (!navigationOnly) {
620
587
  if (active && this.#focusables.has(active)) {
621
- this.#focusables.forEach((focusable) => {
588
+ for (const focusable of this.#focusables) {
622
589
  focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
623
- });
590
+ }
624
591
  } else {
625
592
  [...this.#focusables].forEach((focusable, i) => {
626
593
  focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
@@ -650,6 +617,7 @@ var RovingTabIndex = class _RovingTabIndex {
650
617
  typeahead = false,
651
618
  wrap = false
652
619
  } = options;
620
+ direction = direction.toLowerCase();
653
621
  if (!["both", "horizontal", "vertical"].includes(direction)) {
654
622
  console.warn("Invalid direction option. Fallback: 'both'.");
655
623
  direction = "both";
@@ -780,15 +748,15 @@ var Accordion = class _Accordion {
780
748
  this.#eventController = null;
781
749
  this.#cleanupRovingTabIndex?.();
782
750
  this.#cleanupRovingTabIndex = null;
783
- this.#buttons.forEach((button) => {
751
+ for (const button of this.#buttons) {
784
752
  button.destroy();
785
- });
753
+ }
786
754
  this.#buttons.length = 0;
787
755
  !force && await this.#waitAnimationsFinish();
788
- this.#contentElements.forEach((content) => {
756
+ for (const content of this.#contentElements) {
789
757
  force && this.#bindings.get(content)?.animation?.finish();
790
758
  this.#onContentAnimationFinish(content);
791
- });
759
+ }
792
760
  this.#animationController?.abort();
793
761
  this.#animationController = null;
794
762
  restoreAttributes([
@@ -873,9 +841,9 @@ var Accordion = class _Accordion {
873
841
  return;
874
842
  }
875
843
  trigger.ariaExpanded === "false" && content.setAttribute("hidden", "until-found");
876
- ["block-size", "overflow"].forEach((name) => {
844
+ for (const name of ["block-size", "overflow"]) {
877
845
  content.style.removeProperty(name);
878
- });
846
+ }
879
847
  }
880
848
  #onContentBeforeMatch = (event) => {
881
849
  const content = event.currentTarget;
@@ -892,7 +860,7 @@ var Accordion = class _Accordion {
892
860
  if (trigger.ariaExpanded === String(isExpand)) {
893
861
  return;
894
862
  }
895
- if (!isExpand && !isProgrammatic && !this.#settings.collapsible && this.#triggerElements.filter((trigger2) => trigger2.ariaExpanded === "true").length <= 1) {
863
+ if (!isExpand && !isProgrammatic && !this.#settings.collapsible && this.#triggerElements.filter((t) => t.ariaExpanded === "true").length <= 1) {
896
864
  return;
897
865
  }
898
866
  const name = trigger.getAttribute("data-accordion-name");
@@ -1002,10 +970,10 @@ var Accordion = class _Accordion {
1002
970
  }
1003
971
  async #waitAnimationsFinish() {
1004
972
  const promises = [];
1005
- this.#contentElements.forEach((content) => {
973
+ for (const content of this.#contentElements) {
1006
974
  const animation = this.#bindings.get(content)?.animation;
1007
975
  animation && promises.push(waitAnimationFinish(animation));
1008
- });
976
+ }
1009
977
  await Promise.allSettled(promises);
1010
978
  }
1011
979
  };
@@ -1018,7 +986,7 @@ function waitAnimationFinish(animation) {
1018
986
  * Accordion
1019
987
  * WAI-ARIA compliant accordion pattern implementation in TypeScript.
1020
988
  *
1021
- * @version 2.0.14
989
+ * @version 2.0.16
1022
990
  * @author Yusuke Kamiyamane
1023
991
  * @license MIT
1024
992
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1030,7 +998,7 @@ function waitAnimationFinish(animation) {
1030
998
  (**
1031
999
  * Attribute Utils
1032
1000
  *
1033
- * @version 2.0.8
1001
+ * @version 2.0.12
1034
1002
  * @author Yusuke Kamiyamane
1035
1003
  * @license MIT
1036
1004
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1043,7 +1011,7 @@ power-focusable/dist/index.js:
1043
1011
  * High-precision focus management utility with full composed tree support.
1044
1012
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1045
1013
  *
1046
- * @version 4.3.29
1014
+ * @version 4.3.33
1047
1015
  * @author Yusuke Kamiyamane
1048
1016
  * @license MIT
1049
1017
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1067,7 +1035,7 @@ power-focusable/dist/index.js:
1067
1035
  * Lightweight roving tabindex utility with fully focus management.
1068
1036
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1069
1037
  *
1070
- * @version 3.1.27
1038
+ * @version 3.1.31
1071
1039
  * @author Yusuke Kamiyamane
1072
1040
  * @license MIT
1073
1041
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1,6 +1,6 @@
1
1
  // node_modules/@y14e/attribute-utils/dist/index.js
2
- var DEFAULT_PARSER = (value) => value.split(/\s+/);
3
- var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
2
+ var DEFAULT_PARSER = (v) => v.split(/\s+/);
3
+ var DEFAULT_SERIALIZER = (t) => t.join(" ");
4
4
  function addAttributeToken(element, name, token, options = {}) {
5
5
  if (!isValid(element, name, token)) {
6
6
  return;
@@ -10,7 +10,7 @@ function addAttributeToken(element, name, token, options = {}) {
10
10
  const tokens = value ? parse(value).filter(Boolean) : [];
11
11
  if (caseInsensitive) {
12
12
  const lower = token.toLowerCase();
13
- if (tokens.every((token2) => token2.toLowerCase() !== lower)) {
13
+ if (tokens.every((t) => t.toLowerCase() !== lower)) {
14
14
  tokens.push(token);
15
15
  element.setAttribute(name, serialize(tokens));
16
16
  }
@@ -35,16 +35,16 @@ function restoreAttributes(element_or_elements) {
35
35
  }
36
36
  function saveAttributes(element_or_elements, name_or_names) {
37
37
  const names = Array.isArray(name_or_names) ? name_or_names : [name_or_names];
38
- (Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]).forEach((element) => {
38
+ for (const element of Array.isArray(element_or_elements) ? element_or_elements : [element_or_elements]) {
39
39
  let snapshot = snapshots.get(element);
40
40
  if (!snapshot) {
41
41
  snapshot = /* @__PURE__ */ new Map();
42
42
  snapshots.set(element, snapshot);
43
43
  }
44
- names.forEach((name) => {
44
+ for (const name of names) {
45
45
  snapshot.set(name, element.getAttribute(name));
46
- });
47
- });
46
+ }
47
+ }
48
48
  }
49
49
  function isValid(element, name, token) {
50
50
  if (!(element instanceof Element)) {
@@ -89,7 +89,7 @@ function resolveOptions(options) {
89
89
  }
90
90
 
91
91
  // node_modules/power-focusable/dist/index.js
92
- var FOCUSABLE_SELECTOR = `:is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])`;
92
+ var FOCUSABLE_SELECTOR = ':is(a[href], area[href], button, embed, iframe, input:not([type="hidden" i]), object, select, details > summary:first-of-type, textarea, [contenteditable]:not([contenteditable="false" i]), [controls], [tabindex]):not(:disabled, [hidden], [inert], [tabindex="-1"])';
93
93
  var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX = FOCUSABLE_SELECTOR.replace(
94
94
  /(,\s*)?\[tabindex="-1"\]/g,
95
95
  ""
@@ -113,31 +113,21 @@ function getFocusables(container = document.body, options = {}) {
113
113
  skipNegativeTabIndexCheck,
114
114
  skipVisibilityCheck
115
115
  }) || include?.(node)) {
116
- candidates[candidates.length] = node;
117
- }
118
- const children2 = composed ? getComposedChildren(node) : getChildren(node);
119
- for (let i = 0, l = children2.length; i < l; i++) {
120
- const child = children2[i];
121
- child && traverse2(child);
116
+ candidates.push(node);
122
117
  }
118
+ (composed ? getComposedChildren(node) : [...node.children]).map(traverse2);
123
119
  };
124
- const children = composed ? getComposedChildren(container) : getChildren(container);
125
- for (let i = 0, l = children.length; i < l; i++) {
126
- const child = children[i];
127
- child && traverse2(child);
128
- }
120
+ (composed ? getComposedChildren(container) : [...container.children]).map(
121
+ traverse2
122
+ );
129
123
  } else {
130
- const matches = container.querySelectorAll(
124
+ for (const match of container.querySelectorAll(
131
125
  skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX : FOCUSABLE_SELECTOR
132
- );
133
- for (let i = 0, l = matches.length; i < l; i++) {
134
- const matched = matches[i];
135
- if (matched && isFocusable(matched, {
126
+ )) {
127
+ match && isFocusable(match, {
136
128
  skipNegativeTabIndexCheck,
137
129
  skipVisibilityCheck
138
- })) {
139
- candidates[candidates.length] = matched;
140
- }
130
+ }) && candidates.push(match);
141
131
  }
142
132
  }
143
133
  return normalizeRadioGroup(
@@ -204,8 +194,7 @@ function isDisabledDeep(element) {
204
194
  }
205
195
  function normalizeRadioGroup(elements) {
206
196
  let map = null;
207
- for (let i = 0, l = elements.length; i < l; i++) {
208
- const element = elements[i];
197
+ for (const element of elements) {
209
198
  if (!(element instanceof HTMLInputElement)) {
210
199
  continue;
211
200
  }
@@ -216,31 +205,31 @@ function normalizeRadioGroup(elements) {
216
205
  map = /* @__PURE__ */ new Map();
217
206
  }
218
207
  const root = element.getRootNode();
219
- let value = map.get(root);
220
- if (!value) {
221
- value = /* @__PURE__ */ new Map();
222
- map.set(root, value);
223
- }
224
- let v = value.get(element.form);
225
- if (!v) {
226
- v = /* @__PURE__ */ new Map();
227
- value.set(element.form, v);
228
- }
229
- let vv = v.get(element.name);
230
- if (!vv) {
231
- vv = [];
232
- v.set(element.name, vv);
233
- }
234
- vv[vv.length] = element;
208
+ let groups = map.get(root);
209
+ if (!groups) {
210
+ groups = /* @__PURE__ */ new Map();
211
+ map.set(root, groups);
212
+ }
213
+ let group = groups.get(element.form);
214
+ if (!group) {
215
+ group = /* @__PURE__ */ new Map();
216
+ groups.set(element.form, group);
217
+ }
218
+ let radios = group.get(element.name);
219
+ if (!radios) {
220
+ radios = [];
221
+ group.set(element.name, radios);
222
+ }
223
+ radios.push(element);
235
224
  }
236
225
  if (!map) {
237
226
  return elements;
238
227
  }
239
228
  const placeholder = /* @__PURE__ */ new Set();
240
- for (const value of map.values()) {
241
- for (const v of value.values()) {
242
- for (const vv of v.values()) {
243
- const radio = vv.find((element) => element.checked) ?? vv[0];
229
+ for (const groups of map.values()) {
230
+ for (const group of groups.values()) {
231
+ for (const radios of group.values()) {
232
+ const radio = radios.find((r) => r.checked) ?? radios[0];
244
233
  radio && placeholder.add(radio);
245
234
  }
246
235
  }
@@ -255,27 +244,14 @@ function normalizeRadioGroup(elements) {
255
244
  function sortByTabIndex(elements) {
256
245
  const ordered = [];
257
246
  const natural = [];
258
- for (let i = 0, l = elements.length; i < l; i++) {
259
- const element = elements[i];
260
- if (element) {
261
- const target = getTabIndex(element) > 0 ? ordered : natural;
262
- target[target.length] = element;
263
- }
264
- }
265
- ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
266
- let count = 0;
267
- const sorted = new Array(ordered.length + natural.length);
268
- for (let i = 0, l = ordered.length; i < l; i++) {
269
- sorted[count++] = ordered[i];
247
+ for (const element of elements) {
248
+ (getTabIndex(element) > 0 ? ordered : natural).push(element);
270
249
  }
271
- for (let i = 0, l = natural.length; i < l; i++) {
272
- sorted[count++] = natural[i];
273
- }
274
- return sorted;
250
+ return ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b)).concat(natural);
275
251
  }
276
252
  function getComposedChildren(node) {
277
253
  if (node instanceof ShadowRoot) {
278
- return getChildren(node);
254
+ return [...node.children];
279
255
  }
280
256
  if (!(node instanceof Element)) {
281
257
  return [];
@@ -287,9 +263,9 @@ function getComposedChildren(node) {
287
263
  }
288
264
  }
289
265
  if (node instanceof HTMLElement && node.shadowRoot?.mode === "open") {
290
- return getChildren(node.shadowRoot);
266
+ return [...node.shadowRoot.children];
291
267
  }
292
- return getChildren(node);
268
+ return [...node.children];
293
269
  }
294
270
  function focusElement(element) {
295
271
  "focus" in element && typeof element.focus === "function" && element.focus();
@@ -301,13 +277,6 @@ function getActiveElement() {
301
277
  }
302
278
  return current;
303
279
  }
304
- function getChildren(node) {
305
- const elements = [];
306
- for (let child = node.firstElementChild; child; child = child.nextElementSibling) {
307
- elements[elements.length] = child;
308
- }
309
- return elements;
310
- }
311
280
  function getTabIndex(element) {
312
281
  return "tabIndex" in element ? Number(element.tabIndex) : 0;
313
282
  }
@@ -461,10 +430,10 @@ var RovingTabIndex = class _RovingTabIndex {
461
430
  this.#isDestroyed = true;
462
431
  this.#controller?.abort();
463
432
  this.#controller = null;
464
- this.#focusables.forEach((focusable) => {
433
+ for (const focusable of this.#focusables) {
465
434
  _RovingTabIndex.#initialized.delete(focusable);
466
435
  restoreAttributes(focusable);
467
- });
436
+ }
468
437
  this.#focusables.clear();
469
438
  this.#focusablesByFirstChar.clear();
470
439
  }
@@ -514,7 +483,7 @@ var RovingTabIndex = class _RovingTabIndex {
514
483
  }
515
484
  }
516
485
  const candidates = this.#getFocusables().filter(
517
- (focusable2) => this.#focusables.has(focusable2)
486
+ (f) => this.#focusables.has(f)
518
487
  );
519
488
  const active = getActiveElement();
520
489
  if (!(active instanceof Element)) {
@@ -551,11 +520,9 @@ var RovingTabIndex = class _RovingTabIndex {
551
520
  const focusablesByFirstChar = new Set(
552
521
  this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
553
522
  );
554
- focusables = candidates.filter(
555
- (candidate) => focusablesByFirstChar.has(candidate)
556
- );
523
+ focusables = candidates.filter((c) => focusablesByFirstChar.has(c));
557
524
  const afterIndex = focusables.findIndex(
558
- (focusable2) => candidates.indexOf(focusable2) > activeIndex
525
+ (f) => candidates.indexOf(f) > activeIndex
559
526
  );
560
527
  newIndex = afterIndex >= 0 ? afterIndex : 0;
561
528
  }
@@ -599,7 +566,7 @@ var RovingTabIndex = class _RovingTabIndex {
599
566
  const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
600
567
  const value = focusable.ariaKeyShortcuts?.trim();
601
568
  const keys = new Set(
602
- value ? value.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
569
+ value ? value.split(/\s+/).filter((k) => /^\S$/i.test(k)).map((k) => k.toUpperCase()) : []
603
570
  );
604
571
  if (char) {
605
572
  keys.add(char);
@@ -608,17 +575,17 @@ var RovingTabIndex = class _RovingTabIndex {
608
575
  caseInsensitive: true
609
576
  });
610
577
  }
611
- keys.forEach((key) => {
578
+ for (const key of keys) {
612
579
  const focusables = this.#focusablesByFirstChar.get(key) ?? [];
613
580
  focusables.push(focusable);
614
581
  this.#focusablesByFirstChar.set(key, focusables);
615
- });
582
+ }
616
583
  }
617
584
  if (!navigationOnly) {
618
585
  if (active && this.#focusables.has(active)) {
619
- this.#focusables.forEach((focusable) => {
586
+ for (const focusable of this.#focusables) {
620
587
  focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
621
- });
588
+ }
622
589
  } else {
623
590
  [...this.#focusables].forEach((focusable, i) => {
624
591
  focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
@@ -648,6 +615,7 @@ var RovingTabIndex = class _RovingTabIndex {
648
615
  typeahead = false,
649
616
  wrap = false
650
617
  } = options;
618
+ direction = direction.toLowerCase();
651
619
  if (!["both", "horizontal", "vertical"].includes(direction)) {
652
620
  console.warn("Invalid direction option. Fallback: 'both'.");
653
621
  direction = "both";
@@ -778,15 +746,15 @@ var Accordion = class _Accordion {
778
746
  this.#eventController = null;
779
747
  this.#cleanupRovingTabIndex?.();
780
748
  this.#cleanupRovingTabIndex = null;
781
- this.#buttons.forEach((button) => {
749
+ for (const button of this.#buttons) {
782
750
  button.destroy();
783
- });
751
+ }
784
752
  this.#buttons.length = 0;
785
753
  !force && await this.#waitAnimationsFinish();
786
- this.#contentElements.forEach((content) => {
754
+ for (const content of this.#contentElements) {
787
755
  force && this.#bindings.get(content)?.animation?.finish();
788
756
  this.#onContentAnimationFinish(content);
789
- });
757
+ }
790
758
  this.#animationController?.abort();
791
759
  this.#animationController = null;
792
760
  restoreAttributes([
@@ -871,9 +839,9 @@ var Accordion = class _Accordion {
871
839
  return;
872
840
  }
873
841
  trigger.ariaExpanded === "false" && content.setAttribute("hidden", "until-found");
874
- ["block-size", "overflow"].forEach((name) => {
842
+ for (const name of ["block-size", "overflow"]) {
875
843
  content.style.removeProperty(name);
876
- });
844
+ }
877
845
  }
878
846
  #onContentBeforeMatch = (event) => {
879
847
  const content = event.currentTarget;
@@ -890,7 +858,7 @@ var Accordion = class _Accordion {
890
858
  if (trigger.ariaExpanded === String(isExpand)) {
891
859
  return;
892
860
  }
893
- if (!isExpand && !isProgrammatic && !this.#settings.collapsible && this.#triggerElements.filter((trigger2) => trigger2.ariaExpanded === "true").length <= 1) {
861
+ if (!isExpand && !isProgrammatic && !this.#settings.collapsible && this.#triggerElements.filter((t) => t.ariaExpanded === "true").length <= 1) {
894
862
  return;
895
863
  }
896
864
  const name = trigger.getAttribute("data-accordion-name");
@@ -1000,10 +968,10 @@ var Accordion = class _Accordion {
1000
968
  }
1001
969
  async #waitAnimationsFinish() {
1002
970
  const promises = [];
1003
- this.#contentElements.forEach((content) => {
971
+ for (const content of this.#contentElements) {
1004
972
  const animation = this.#bindings.get(content)?.animation;
1005
973
  animation && promises.push(waitAnimationFinish(animation));
1006
- });
974
+ }
1007
975
  await Promise.allSettled(promises);
1008
976
  }
1009
977
  };
@@ -1016,7 +984,7 @@ function waitAnimationFinish(animation) {
1016
984
  * Accordion
1017
985
  * WAI-ARIA compliant accordion pattern implementation in TypeScript.
1018
986
  *
1019
- * @version 2.0.14
987
+ * @version 2.0.16
1020
988
  * @author Yusuke Kamiyamane
1021
989
  * @license MIT
1022
990
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1028,7 +996,7 @@ function waitAnimationFinish(animation) {
1028
996
  (**
1029
997
  * Attribute Utils
1030
998
  *
1031
- * @version 2.0.8
999
+ * @version 2.0.12
1032
1000
  * @author Yusuke Kamiyamane
1033
1001
  * @license MIT
1034
1002
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1041,7 +1009,7 @@ power-focusable/dist/index.js:
1041
1009
  * High-precision focus management utility with full composed tree support.
1042
1010
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
1043
1011
  *
1044
- * @version 4.3.29
1012
+ * @version 4.3.33
1045
1013
  * @author Yusuke Kamiyamane
1046
1014
  * @license MIT
1047
1015
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -1065,7 +1033,7 @@ power-focusable/dist/index.js:
1065
1033
  * Lightweight roving tabindex utility with fully focus management.
1066
1034
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
1067
1035
  *
1068
- * @version 3.1.27
1036
+ * @version 3.1.31
1069
1037
  * @author Yusuke Kamiyamane
1070
1038
  * @license MIT
1071
1039
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.cjs CHANGED
@@ -110,15 +110,15 @@ var Accordion = class _Accordion {
110
110
  this.#eventController = null;
111
111
  this.#cleanupRovingTabIndex?.();
112
112
  this.#cleanupRovingTabIndex = null;
113
- this.#buttons.forEach((button) => {
113
+ for (const button of this.#buttons) {
114
114
  button.destroy();
115
- });
115
+ }
116
116
  this.#buttons.length = 0;
117
117
  !force && await this.#waitAnimationsFinish();
118
- this.#contentElements.forEach((content) => {
118
+ for (const content of this.#contentElements) {
119
119
  force && this.#bindings.get(content)?.animation?.finish();
120
120
  this.#onContentAnimationFinish(content);
121
- });
121
+ }
122
122
  this.#animationController?.abort();
123
123
  this.#animationController = null;
124
124
  utils__namespace.restoreAttributes([
@@ -203,9 +203,9 @@ var Accordion = class _Accordion {
203
203
  return;
204
204
  }
205
205
  trigger.ariaExpanded === "false" && content.setAttribute("hidden", "until-found");
206
- ["block-size", "overflow"].forEach((name) => {
206
+ for (const name of ["block-size", "overflow"]) {
207
207
  content.style.removeProperty(name);
208
- });
208
+ }
209
209
  }
210
210
  #onContentBeforeMatch = (event) => {
211
211
  const content = event.currentTarget;
@@ -222,7 +222,7 @@ var Accordion = class _Accordion {
222
222
  if (trigger.ariaExpanded === String(isExpand)) {
223
223
  return;
224
224
  }
225
- if (!isExpand && !isProgrammatic && !this.#settings.collapsible && this.#triggerElements.filter((trigger2) => trigger2.ariaExpanded === "true").length <= 1) {
225
+ if (!isExpand && !isProgrammatic && !this.#settings.collapsible && this.#triggerElements.filter((t) => t.ariaExpanded === "true").length <= 1) {
226
226
  return;
227
227
  }
228
228
  const name = trigger.getAttribute("data-accordion-name");
@@ -332,10 +332,10 @@ var Accordion = class _Accordion {
332
332
  }
333
333
  async #waitAnimationsFinish() {
334
334
  const promises = [];
335
- this.#contentElements.forEach((content) => {
335
+ for (const content of this.#contentElements) {
336
336
  const animation = this.#bindings.get(content)?.animation;
337
337
  animation && promises.push(waitAnimationFinish(animation));
338
- });
338
+ }
339
339
  await Promise.allSettled(promises);
340
340
  }
341
341
  };
@@ -348,7 +348,7 @@ function waitAnimationFinish(animation) {
348
348
  * Accordion
349
349
  * WAI-ARIA compliant accordion pattern implementation in TypeScript.
350
350
  *
351
- * @version 2.0.14
351
+ * @version 2.0.16
352
352
  * @author Yusuke Kamiyamane
353
353
  * @license MIT
354
354
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.d.cts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Accordion
3
3
  * WAI-ARIA compliant accordion pattern implementation in TypeScript.
4
4
  *
5
- * @version 2.0.14
5
+ * @version 2.0.16
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
  * Accordion
3
3
  * WAI-ARIA compliant accordion pattern implementation in TypeScript.
4
4
  *
5
- * @version 2.0.14
5
+ * @version 2.0.16
6
6
  * @author Yusuke Kamiyamane
7
7
  * @license MIT
8
8
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -88,15 +88,15 @@ var Accordion = class _Accordion {
88
88
  this.#eventController = null;
89
89
  this.#cleanupRovingTabIndex?.();
90
90
  this.#cleanupRovingTabIndex = null;
91
- this.#buttons.forEach((button) => {
91
+ for (const button of this.#buttons) {
92
92
  button.destroy();
93
- });
93
+ }
94
94
  this.#buttons.length = 0;
95
95
  !force && await this.#waitAnimationsFinish();
96
- this.#contentElements.forEach((content) => {
96
+ for (const content of this.#contentElements) {
97
97
  force && this.#bindings.get(content)?.animation?.finish();
98
98
  this.#onContentAnimationFinish(content);
99
- });
99
+ }
100
100
  this.#animationController?.abort();
101
101
  this.#animationController = null;
102
102
  utils.restoreAttributes([
@@ -181,9 +181,9 @@ var Accordion = class _Accordion {
181
181
  return;
182
182
  }
183
183
  trigger.ariaExpanded === "false" && content.setAttribute("hidden", "until-found");
184
- ["block-size", "overflow"].forEach((name) => {
184
+ for (const name of ["block-size", "overflow"]) {
185
185
  content.style.removeProperty(name);
186
- });
186
+ }
187
187
  }
188
188
  #onContentBeforeMatch = (event) => {
189
189
  const content = event.currentTarget;
@@ -200,7 +200,7 @@ var Accordion = class _Accordion {
200
200
  if (trigger.ariaExpanded === String(isExpand)) {
201
201
  return;
202
202
  }
203
- if (!isExpand && !isProgrammatic && !this.#settings.collapsible && this.#triggerElements.filter((trigger2) => trigger2.ariaExpanded === "true").length <= 1) {
203
+ if (!isExpand && !isProgrammatic && !this.#settings.collapsible && this.#triggerElements.filter((t) => t.ariaExpanded === "true").length <= 1) {
204
204
  return;
205
205
  }
206
206
  const name = trigger.getAttribute("data-accordion-name");
@@ -310,10 +310,10 @@ var Accordion = class _Accordion {
310
310
  }
311
311
  async #waitAnimationsFinish() {
312
312
  const promises = [];
313
- this.#contentElements.forEach((content) => {
313
+ for (const content of this.#contentElements) {
314
314
  const animation = this.#bindings.get(content)?.animation;
315
315
  animation && promises.push(waitAnimationFinish(animation));
316
- });
316
+ }
317
317
  await Promise.allSettled(promises);
318
318
  }
319
319
  };
@@ -326,7 +326,7 @@ function waitAnimationFinish(animation) {
326
326
  * Accordion
327
327
  * WAI-ARIA compliant accordion pattern implementation in TypeScript.
328
328
  *
329
- * @version 2.0.14
329
+ * @version 2.0.16
330
330
  * @author Yusuke Kamiyamane
331
331
  * @license MIT
332
332
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/accordion",
3
- "version": "2.0.14",
3
+ "version": "2.0.16",
4
4
  "description": "WAI-ARIA compliant accordion pattern implementation in TypeScript",
5
5
  "keywords": [
6
6
  "a11y",
@@ -54,8 +54,8 @@
54
54
  "esbuild": true
55
55
  },
56
56
  "dependencies": {
57
- "@y14e/attribute-utils": "^2.0.8",
57
+ "@y14e/attribute-utils": "^2.0.12",
58
58
  "@y14e/button": "^1.0.8",
59
- "@y14e/roving-tabindex": "^3.1.27"
59
+ "@y14e/roving-tabindex": "^3.1.31"
60
60
  }
61
61
  }