@y14e/disclosure-css 2.0.10 → 2.0.12

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/disclosure-css
10
10
 
11
11
  ```ts
12
12
  // npm
13
- import { Disclosure } from "@y14e/disclosure-css";
13
+ import { Disclosure } from '@y14e/disclosure-css';
14
14
 
15
15
  // CDNs
16
- import { Disclosure } from "https://esm.sh/@y14e/disclosure-css@2.0.10";
16
+ import { Disclosure } from 'https://esm.sh/@y14e/disclosure-css@2.0.12';
17
17
  // or
18
- import { Disclosure } from "https://cdn.jsdelivr.net/npm/@y14e/disclosure-css@2.0.10/+esm";
18
+ import { Disclosure } from 'https://cdn.jsdelivr.net/npm/@y14e/disclosure-css@2.0.12/+esm';
19
19
  // or
20
- import { Disclosure } from "https://esm.unpkg.com/@y14e/disclosure-css@2.0.10";
20
+ import { Disclosure } from 'https://esm.unpkg.com/@y14e/disclosure-css@2.0.12';
21
21
  ```
22
22
 
23
23
  ## Usage
@@ -43,7 +43,7 @@ interface DisclosureOptions {
43
43
  Override the global default settings applied to all disclosure instances.
44
44
 
45
45
  ```ts
46
- import { Disclosure } from "@y14e/disclosure-css";
46
+ import { Disclosure } from '@y14e/disclosure-css';
47
47
 
48
48
  Disclosure.defaults = {
49
49
  collapsible: false,
@@ -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);
210
+ let groups = map.get(root);
211
+ if (!groups) {
212
+ groups = /* @__PURE__ */ new Map();
213
+ map.set(root, groups);
225
214
  }
226
- let v = value.get(element.form);
227
- if (!v) {
228
- v = /* @__PURE__ */ new Map();
229
- value.set(element.form, v);
215
+ let group = groups.get(element.form);
216
+ if (!group) {
217
+ group = /* @__PURE__ */ new Map();
218
+ groups.set(element.form, group);
230
219
  }
231
- let vv = v.get(element.name);
232
- if (!vv) {
233
- vv = [];
234
- v.set(element.name, vv);
220
+ let radios = group.get(element.name);
221
+ if (!radios) {
222
+ radios = [];
223
+ group.set(element.name, radios);
235
224
  }
236
- vv[vv.length] = element;
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
  }
@@ -414,10 +383,10 @@ var RovingTabIndex = class _RovingTabIndex {
414
383
  this.#isDestroyed = true;
415
384
  this.#controller?.abort();
416
385
  this.#controller = null;
417
- this.#focusables.forEach((focusable) => {
386
+ for (const focusable of this.#focusables) {
418
387
  _RovingTabIndex.#initialized.delete(focusable);
419
388
  restoreAttributes(focusable);
420
- });
389
+ }
421
390
  this.#focusables.clear();
422
391
  this.#focusablesByFirstChar.clear();
423
392
  }
@@ -467,7 +436,7 @@ var RovingTabIndex = class _RovingTabIndex {
467
436
  }
468
437
  }
469
438
  const candidates = this.#getFocusables().filter(
470
- (focusable2) => this.#focusables.has(focusable2)
439
+ (f) => this.#focusables.has(f)
471
440
  );
472
441
  const active = getActiveElement();
473
442
  if (!(active instanceof Element)) {
@@ -504,11 +473,9 @@ var RovingTabIndex = class _RovingTabIndex {
504
473
  const focusablesByFirstChar = new Set(
505
474
  this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
506
475
  );
507
- focusables = candidates.filter(
508
- (candidate) => focusablesByFirstChar.has(candidate)
509
- );
476
+ focusables = candidates.filter((c) => focusablesByFirstChar.has(c));
510
477
  const afterIndex = focusables.findIndex(
511
- (focusable2) => candidates.indexOf(focusable2) > activeIndex
478
+ (f) => candidates.indexOf(f) > activeIndex
512
479
  );
513
480
  newIndex = afterIndex >= 0 ? afterIndex : 0;
514
481
  }
@@ -552,7 +519,7 @@ var RovingTabIndex = class _RovingTabIndex {
552
519
  const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
553
520
  const value = focusable.ariaKeyShortcuts?.trim();
554
521
  const keys = new Set(
555
- value ? value.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
522
+ value ? value.split(/\s+/).filter((k) => /^\S$/i.test(k)).map((k) => k.toUpperCase()) : []
556
523
  );
557
524
  if (char) {
558
525
  keys.add(char);
@@ -561,17 +528,17 @@ var RovingTabIndex = class _RovingTabIndex {
561
528
  caseInsensitive: true
562
529
  });
563
530
  }
564
- keys.forEach((key) => {
531
+ for (const key of keys) {
565
532
  const focusables = this.#focusablesByFirstChar.get(key) ?? [];
566
533
  focusables.push(focusable);
567
534
  this.#focusablesByFirstChar.set(key, focusables);
568
- });
535
+ }
569
536
  }
570
537
  if (!navigationOnly) {
571
538
  if (active && this.#focusables.has(active)) {
572
- this.#focusables.forEach((focusable) => {
539
+ for (const focusable of this.#focusables) {
573
540
  focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
574
- });
541
+ }
575
542
  } else {
576
543
  [...this.#focusables].forEach((focusable, i) => {
577
544
  focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
@@ -601,6 +568,7 @@ var RovingTabIndex = class _RovingTabIndex {
601
568
  typeahead = false,
602
569
  wrap = false
603
570
  } = options;
571
+ direction = direction.toLowerCase();
604
572
  if (!["both", "horizontal", "vertical"].includes(direction)) {
605
573
  console.warn("Invalid direction option. Fallback: 'both'.");
606
574
  direction = "both";
@@ -753,14 +721,14 @@ var Disclosure = class _Disclosure {
753
721
  ]);
754
722
  this.#controller = new AbortController();
755
723
  const { signal } = this.#controller;
756
- this.#summaryElements.forEach((summary) => {
724
+ for (const summary of this.#summaryElements) {
757
725
  if (!this.#isFocusable(summary)) {
758
726
  summary.setAttribute("aria-disabled", "true");
759
727
  summary.setAttribute("tabindex", "-1");
760
728
  summary.style.setProperty("pointer-events", "none");
761
729
  }
762
730
  summary.addEventListener("click", this.#onSummaryClick, { signal });
763
- });
731
+ }
764
732
  this.#cleanupRovingTabIndex = createRovingTabIndex(this.#rootElement, {
765
733
  direction: "vertical",
766
734
  navigationOnly: true,
@@ -786,7 +754,7 @@ var Disclosure = class _Disclosure {
786
754
  if (details.open === isExpand) {
787
755
  return;
788
756
  }
789
- if (!isExpand && !this.#settings.collapsible && this.#detailsElements.filter((details2) => details2.open).length <= 1) {
757
+ if (!isExpand && !this.#settings.collapsible && this.#detailsElements.filter((d) => d.open).length <= 1) {
790
758
  return;
791
759
  }
792
760
  details.open = isExpand;
@@ -812,7 +780,7 @@ var Disclosure = class _Disclosure {
812
780
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
813
781
  * Using the <details> and <summary> element.
814
782
  *
815
- * @version 2.0.10
783
+ * @version 2.0.11
816
784
  * @author Yusuke Kamiyamane
817
785
  * @license MIT
818
786
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -824,7 +792,7 @@ var Disclosure = class _Disclosure {
824
792
  (**
825
793
  * Attribute Utils
826
794
  *
827
- * @version 2.0.8
795
+ * @version 2.0.12
828
796
  * @author Yusuke Kamiyamane
829
797
  * @license MIT
830
798
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -837,7 +805,7 @@ power-focusable/dist/index.js:
837
805
  * High-precision focus management utility with full composed tree support.
838
806
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
839
807
  *
840
- * @version 4.3.29
808
+ * @version 4.3.33
841
809
  * @author Yusuke Kamiyamane
842
810
  * @license MIT
843
811
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -850,7 +818,7 @@ power-focusable/dist/index.js:
850
818
  * Lightweight roving tabindex utility with fully focus management.
851
819
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
852
820
  *
853
- * @version 3.1.27
821
+ * @version 3.1.31
854
822
  * @author Yusuke Kamiyamane
855
823
  * @license MIT
856
824
  * @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);
208
+ let groups = map.get(root);
209
+ if (!groups) {
210
+ groups = /* @__PURE__ */ new Map();
211
+ map.set(root, groups);
223
212
  }
224
- let v = value.get(element.form);
225
- if (!v) {
226
- v = /* @__PURE__ */ new Map();
227
- value.set(element.form, v);
213
+ let group = groups.get(element.form);
214
+ if (!group) {
215
+ group = /* @__PURE__ */ new Map();
216
+ groups.set(element.form, group);
228
217
  }
229
- let vv = v.get(element.name);
230
- if (!vv) {
231
- vv = [];
232
- v.set(element.name, vv);
218
+ let radios = group.get(element.name);
219
+ if (!radios) {
220
+ radios = [];
221
+ group.set(element.name, radios);
233
222
  }
234
- vv[vv.length] = element;
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
  }
@@ -412,10 +381,10 @@ var RovingTabIndex = class _RovingTabIndex {
412
381
  this.#isDestroyed = true;
413
382
  this.#controller?.abort();
414
383
  this.#controller = null;
415
- this.#focusables.forEach((focusable) => {
384
+ for (const focusable of this.#focusables) {
416
385
  _RovingTabIndex.#initialized.delete(focusable);
417
386
  restoreAttributes(focusable);
418
- });
387
+ }
419
388
  this.#focusables.clear();
420
389
  this.#focusablesByFirstChar.clear();
421
390
  }
@@ -465,7 +434,7 @@ var RovingTabIndex = class _RovingTabIndex {
465
434
  }
466
435
  }
467
436
  const candidates = this.#getFocusables().filter(
468
- (focusable2) => this.#focusables.has(focusable2)
437
+ (f) => this.#focusables.has(f)
469
438
  );
470
439
  const active = getActiveElement();
471
440
  if (!(active instanceof Element)) {
@@ -502,11 +471,9 @@ var RovingTabIndex = class _RovingTabIndex {
502
471
  const focusablesByFirstChar = new Set(
503
472
  this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
504
473
  );
505
- focusables = candidates.filter(
506
- (candidate) => focusablesByFirstChar.has(candidate)
507
- );
474
+ focusables = candidates.filter((c) => focusablesByFirstChar.has(c));
508
475
  const afterIndex = focusables.findIndex(
509
- (focusable2) => candidates.indexOf(focusable2) > activeIndex
476
+ (f) => candidates.indexOf(f) > activeIndex
510
477
  );
511
478
  newIndex = afterIndex >= 0 ? afterIndex : 0;
512
479
  }
@@ -550,7 +517,7 @@ var RovingTabIndex = class _RovingTabIndex {
550
517
  const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
551
518
  const value = focusable.ariaKeyShortcuts?.trim();
552
519
  const keys = new Set(
553
- value ? value.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
520
+ value ? value.split(/\s+/).filter((k) => /^\S$/i.test(k)).map((k) => k.toUpperCase()) : []
554
521
  );
555
522
  if (char) {
556
523
  keys.add(char);
@@ -559,17 +526,17 @@ var RovingTabIndex = class _RovingTabIndex {
559
526
  caseInsensitive: true
560
527
  });
561
528
  }
562
- keys.forEach((key) => {
529
+ for (const key of keys) {
563
530
  const focusables = this.#focusablesByFirstChar.get(key) ?? [];
564
531
  focusables.push(focusable);
565
532
  this.#focusablesByFirstChar.set(key, focusables);
566
- });
533
+ }
567
534
  }
568
535
  if (!navigationOnly) {
569
536
  if (active && this.#focusables.has(active)) {
570
- this.#focusables.forEach((focusable) => {
537
+ for (const focusable of this.#focusables) {
571
538
  focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
572
- });
539
+ }
573
540
  } else {
574
541
  [...this.#focusables].forEach((focusable, i) => {
575
542
  focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
@@ -599,6 +566,7 @@ var RovingTabIndex = class _RovingTabIndex {
599
566
  typeahead = false,
600
567
  wrap = false
601
568
  } = options;
569
+ direction = direction.toLowerCase();
602
570
  if (!["both", "horizontal", "vertical"].includes(direction)) {
603
571
  console.warn("Invalid direction option. Fallback: 'both'.");
604
572
  direction = "both";
@@ -751,14 +719,14 @@ var Disclosure = class _Disclosure {
751
719
  ]);
752
720
  this.#controller = new AbortController();
753
721
  const { signal } = this.#controller;
754
- this.#summaryElements.forEach((summary) => {
722
+ for (const summary of this.#summaryElements) {
755
723
  if (!this.#isFocusable(summary)) {
756
724
  summary.setAttribute("aria-disabled", "true");
757
725
  summary.setAttribute("tabindex", "-1");
758
726
  summary.style.setProperty("pointer-events", "none");
759
727
  }
760
728
  summary.addEventListener("click", this.#onSummaryClick, { signal });
761
- });
729
+ }
762
730
  this.#cleanupRovingTabIndex = createRovingTabIndex(this.#rootElement, {
763
731
  direction: "vertical",
764
732
  navigationOnly: true,
@@ -784,7 +752,7 @@ var Disclosure = class _Disclosure {
784
752
  if (details.open === isExpand) {
785
753
  return;
786
754
  }
787
- if (!isExpand && !this.#settings.collapsible && this.#detailsElements.filter((details2) => details2.open).length <= 1) {
755
+ if (!isExpand && !this.#settings.collapsible && this.#detailsElements.filter((d) => d.open).length <= 1) {
788
756
  return;
789
757
  }
790
758
  details.open = isExpand;
@@ -810,7 +778,7 @@ var Disclosure = class _Disclosure {
810
778
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
811
779
  * Using the <details> and <summary> element.
812
780
  *
813
- * @version 2.0.10
781
+ * @version 2.0.11
814
782
  * @author Yusuke Kamiyamane
815
783
  * @license MIT
816
784
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -822,7 +790,7 @@ var Disclosure = class _Disclosure {
822
790
  (**
823
791
  * Attribute Utils
824
792
  *
825
- * @version 2.0.8
793
+ * @version 2.0.12
826
794
  * @author Yusuke Kamiyamane
827
795
  * @license MIT
828
796
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -835,7 +803,7 @@ power-focusable/dist/index.js:
835
803
  * High-precision focus management utility with full composed tree support.
836
804
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
837
805
  *
838
- * @version 4.3.29
806
+ * @version 4.3.33
839
807
  * @author Yusuke Kamiyamane
840
808
  * @license MIT
841
809
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -848,7 +816,7 @@ power-focusable/dist/index.js:
848
816
  * Lightweight roving tabindex utility with fully focus management.
849
817
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
850
818
  *
851
- * @version 3.1.27
819
+ * @version 3.1.31
852
820
  * @author Yusuke Kamiyamane
853
821
  * @license MIT
854
822
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.cjs CHANGED
@@ -131,14 +131,14 @@ var Disclosure = class _Disclosure {
131
131
  ]);
132
132
  this.#controller = new AbortController();
133
133
  const { signal } = this.#controller;
134
- this.#summaryElements.forEach((summary) => {
134
+ for (const summary of this.#summaryElements) {
135
135
  if (!this.#isFocusable(summary)) {
136
136
  summary.setAttribute("aria-disabled", "true");
137
137
  summary.setAttribute("tabindex", "-1");
138
138
  summary.style.setProperty("pointer-events", "none");
139
139
  }
140
140
  summary.addEventListener("click", this.#onSummaryClick, { signal });
141
- });
141
+ }
142
142
  this.#cleanupRovingTabIndex = rovingTabindex.createRovingTabIndex(this.#rootElement, {
143
143
  direction: "vertical",
144
144
  navigationOnly: true,
@@ -164,7 +164,7 @@ var Disclosure = class _Disclosure {
164
164
  if (details.open === isExpand) {
165
165
  return;
166
166
  }
167
- if (!isExpand && !this.#settings.collapsible && this.#detailsElements.filter((details2) => details2.open).length <= 1) {
167
+ if (!isExpand && !this.#settings.collapsible && this.#detailsElements.filter((d) => d.open).length <= 1) {
168
168
  return;
169
169
  }
170
170
  details.open = isExpand;
@@ -190,7 +190,7 @@ var Disclosure = class _Disclosure {
190
190
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
191
191
  * Using the <details> and <summary> element.
192
192
  *
193
- * @version 2.0.10
193
+ * @version 2.0.11
194
194
  * @author Yusuke Kamiyamane
195
195
  * @license MIT
196
196
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.d.cts CHANGED
@@ -3,7 +3,7 @@
3
3
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
4
4
  * Using the <details> and <summary> element.
5
5
  *
6
- * @version 2.0.10
6
+ * @version 2.0.11
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
4
4
  * Using the <details> and <summary> element.
5
5
  *
6
- * @version 2.0.10
6
+ * @version 2.0.11
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -109,14 +109,14 @@ var Disclosure = class _Disclosure {
109
109
  ]);
110
110
  this.#controller = new AbortController();
111
111
  const { signal } = this.#controller;
112
- this.#summaryElements.forEach((summary) => {
112
+ for (const summary of this.#summaryElements) {
113
113
  if (!this.#isFocusable(summary)) {
114
114
  summary.setAttribute("aria-disabled", "true");
115
115
  summary.setAttribute("tabindex", "-1");
116
116
  summary.style.setProperty("pointer-events", "none");
117
117
  }
118
118
  summary.addEventListener("click", this.#onSummaryClick, { signal });
119
- });
119
+ }
120
120
  this.#cleanupRovingTabIndex = createRovingTabIndex(this.#rootElement, {
121
121
  direction: "vertical",
122
122
  navigationOnly: true,
@@ -142,7 +142,7 @@ var Disclosure = class _Disclosure {
142
142
  if (details.open === isExpand) {
143
143
  return;
144
144
  }
145
- if (!isExpand && !this.#settings.collapsible && this.#detailsElements.filter((details2) => details2.open).length <= 1) {
145
+ if (!isExpand && !this.#settings.collapsible && this.#detailsElements.filter((d) => d.open).length <= 1) {
146
146
  return;
147
147
  }
148
148
  details.open = isExpand;
@@ -168,7 +168,7 @@ var Disclosure = class _Disclosure {
168
168
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
169
169
  * Using the <details> and <summary> element.
170
170
  *
171
- * @version 2.0.10
171
+ * @version 2.0.11
172
172
  * @author Yusuke Kamiyamane
173
173
  * @license MIT
174
174
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,11 +1,27 @@
1
1
  {
2
2
  "name": "@y14e/disclosure-css",
3
- "version": "2.0.10",
3
+ "version": "2.0.12",
4
4
  "description": "WAI-ARIA compliant disclosure pattern implementation in TypeScript",
5
+ "keywords": [
6
+ "a11y",
7
+ "accessibility",
8
+ "disclosure",
9
+ "collapsible",
10
+ "component",
11
+ "typescript",
12
+ "utility"
13
+ ],
14
+ "homepage": "https://github.com/y14e/disclosure-css#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/y14e/disclosure-css/issues"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/y14e/disclosure-css.git"
21
+ },
22
+ "license": "MIT",
23
+ "author": "Yusuke Kamiyamane",
5
24
  "type": "module",
6
- "main": "./dist/index.cjs",
7
- "module": "./dist/index.js",
8
- "types": "./dist/index.d.ts",
9
25
  "exports": {
10
26
  ".": {
11
27
  "types": "./dist/index.d.ts",
@@ -13,6 +29,9 @@
13
29
  "require": "./dist/index.cjs"
14
30
  }
15
31
  },
32
+ "main": "./dist/index.cjs",
33
+ "module": "./dist/index.js",
34
+ "types": "./dist/index.d.ts",
16
35
  "files": [
17
36
  "dist",
18
37
  "LICENSE",
@@ -20,28 +39,9 @@
20
39
  ],
21
40
  "scripts": {
22
41
  "build": "tsup",
23
- "prepublishOnly": "npm run build",
24
- "lint": "tsc --noEmit"
25
- },
26
- "keywords": [
27
- "a11y",
28
- "accessibility",
29
- "disclosure",
30
- "collapsible",
31
- "component",
32
- "typescript",
33
- "utility"
34
- ],
35
- "author": "Yusuke Kamiyamane",
36
- "license": "MIT",
37
- "repository": {
38
- "type": "git",
39
- "url": "git+https://github.com/y14e/disclosure-css.git"
42
+ "lint": "tsc --noEmit",
43
+ "prepublishOnly": "npm run build"
40
44
  },
41
- "bugs": {
42
- "url": "https://github.com/y14e/disclosure-css/issues"
43
- },
44
- "homepage": "https://github.com/y14e/disclosure-css#readme",
45
45
  "devDependencies": {
46
46
  "bun-types": "latest",
47
47
  "tsup": "^8.0.0",
@@ -54,7 +54,7 @@
54
54
  "esbuild": true
55
55
  },
56
56
  "dependencies": {
57
- "@y14e/attribute-utils": "^2.0.8",
58
- "@y14e/roving-tabindex": "^3.1.27"
57
+ "@y14e/attribute-utils": "^2.0.12",
58
+ "@y14e/roving-tabindex": "^3.1.31"
59
59
  }
60
60
  }