@y14e/disclosure-css 2.0.9 → 2.0.11

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.9";
16
+ import { Disclosure } from 'https://esm.sh/@y14e/disclosure-css@2.0.11';
17
17
  // or
18
- import { Disclosure } from "https://cdn.jsdelivr.net/npm/@y14e/disclosure-css@2.0.9/+esm";
18
+ import { Disclosure } from 'https://cdn.jsdelivr.net/npm/@y14e/disclosure-css@2.0.11/+esm';
19
19
  // or
20
- import { Disclosure } from "https://esm.unpkg.com/@y14e/disclosure-css@2.0.9";
20
+ import { Disclosure } from 'https://esm.unpkg.com/@y14e/disclosure-css@2.0.11';
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,
@@ -37,24 +37,26 @@ 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)) {
53
53
  console.warn("Invalid element");
54
54
  return false;
55
55
  }
56
- if (!element.hasAttribute(name)) {
57
- console.warn("Invalid attribute name");
56
+ try {
57
+ document.createElement("div").setAttribute(name, "");
58
+ } catch {
59
+ console.warn(`Invalid attribute name: '${name}'`);
58
60
  return false;
59
61
  }
60
62
  if (typeof token !== "string" || !token.trim()) {
@@ -89,7 +91,7 @@ function resolveOptions(options) {
89
91
  }
90
92
 
91
93
  // 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"])`;
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"])';
93
95
  var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX = FOCUSABLE_SELECTOR.replace(
94
96
  /(,\s*)?\[tabindex="-1"\]/g,
95
97
  ""
@@ -99,37 +101,13 @@ function getFocusables(container = document.body, options = {}) {
99
101
  console.warn("Invalid container element. Fallback: <body> element.");
100
102
  container = document.body;
101
103
  }
102
- let {
103
- composed = false,
104
+ const {
105
+ composed,
104
106
  filter,
105
107
  include,
106
- skipNegativeTabIndexCheck = false,
107
- skipVisibilityCheck = false
108
- } = options;
109
- if (typeof composed !== "boolean") {
110
- console.warn("Invalid composed option. Fallback: false.");
111
- composed = false;
112
- }
113
- if (typeof filter !== "undefined" && typeof filter !== "function") {
114
- console.warn(
115
- "Invalid filter function. Fallback: no filter function (undefined)."
116
- );
117
- filter = void 0;
118
- }
119
- if (typeof include !== "undefined" && typeof include !== "function") {
120
- console.warn(
121
- "Invalid include function. Fallback: no include function (undefined)."
122
- );
123
- include = void 0;
124
- }
125
- if (typeof skipNegativeTabIndexCheck !== "boolean") {
126
- console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
127
- skipNegativeTabIndexCheck = false;
128
- }
129
- if (typeof skipVisibilityCheck !== "boolean") {
130
- console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
131
- skipVisibilityCheck = false;
132
- }
108
+ skipNegativeTabIndexCheck,
109
+ skipVisibilityCheck
110
+ } = resolveOptions2(options);
133
111
  const candidates = [];
134
112
  if (composed || include) {
135
113
  let traverse2 = function(node) {
@@ -139,29 +117,19 @@ function getFocusables(container = document.body, options = {}) {
139
117
  }) || include?.(node)) {
140
118
  candidates[candidates.length] = node;
141
119
  }
142
- const children2 = composed ? getComposedChildren(node) : getChildren(node);
143
- for (let i = 0, l = children2.length; i < l; i++) {
144
- const child = children2[i];
145
- child && traverse2(child);
146
- }
120
+ (composed ? getComposedChildren(node) : getChildren(node)).map(traverse2);
147
121
  };
148
- const children = composed ? getComposedChildren(container) : getChildren(container);
149
- for (let i = 0, l = children.length; i < l; i++) {
150
- const child = children[i];
151
- child && traverse2(child);
152
- }
122
+ (composed ? getComposedChildren(container) : getChildren(container)).map(
123
+ traverse2
124
+ );
153
125
  } else {
154
- const matches = container.querySelectorAll(
126
+ for (const match of container.querySelectorAll(
155
127
  skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX : FOCUSABLE_SELECTOR
156
- );
157
- for (let i = 0, l = matches.length; i < l; i++) {
158
- const matched = matches[i];
159
- if (matched && isFocusable(matched, {
128
+ )) {
129
+ match && isFocusable(match, {
160
130
  skipNegativeTabIndexCheck,
161
131
  skipVisibilityCheck
162
- })) {
163
- candidates[candidates.length] = matched;
164
- }
132
+ }) && candidates.push(match);
165
133
  }
166
134
  }
167
135
  return normalizeRadioGroup(
@@ -173,15 +141,7 @@ function isFocusable(element, options = {}) {
173
141
  console.warn("Invalid element");
174
142
  return false;
175
143
  }
176
- let { skipNegativeTabIndexCheck = false, skipVisibilityCheck = false } = options;
177
- if (typeof skipNegativeTabIndexCheck !== "boolean") {
178
- console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
179
- skipNegativeTabIndexCheck = false;
180
- }
181
- if (typeof skipVisibilityCheck !== "boolean") {
182
- console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
183
- skipVisibilityCheck = false;
184
- }
144
+ const { skipNegativeTabIndexCheck, skipVisibilityCheck } = resolveOptions2(options);
185
145
  if (element.hasAttribute("hidden") || isInert(element)) {
186
146
  return false;
187
147
  }
@@ -236,8 +196,7 @@ function isDisabledDeep(element) {
236
196
  }
237
197
  function normalizeRadioGroup(elements) {
238
198
  let map = null;
239
- for (let i = 0, l = elements.length; i < l; i++) {
240
- const element = elements[i];
199
+ for (const element of elements) {
241
200
  if (!(element instanceof HTMLInputElement)) {
242
201
  continue;
243
202
  }
@@ -287,23 +246,10 @@ function normalizeRadioGroup(elements) {
287
246
  function sortByTabIndex(elements) {
288
247
  const ordered = [];
289
248
  const natural = [];
290
- for (let i = 0, l = elements.length; i < l; i++) {
291
- const element = elements[i];
292
- if (element) {
293
- const target = getTabIndex(element) > 0 ? ordered : natural;
294
- target[target.length] = element;
295
- }
249
+ for (const element of elements) {
250
+ (getTabIndex(element) > 0 ? ordered : natural).push(element);
296
251
  }
297
- ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
298
- let count = 0;
299
- const sorted = new Array(ordered.length + natural.length);
300
- for (let i = 0, l = ordered.length; i < l; i++) {
301
- sorted[count++] = ordered[i];
302
- }
303
- for (let i = 0, l = natural.length; i < l; i++) {
304
- sorted[count++] = natural[i];
305
- }
306
- return sorted;
252
+ return ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b)).concat(natural);
307
253
  }
308
254
  function getComposedChildren(node) {
309
255
  if (node instanceof ShadowRoot) {
@@ -356,6 +302,61 @@ function isInert(element) {
356
302
  function isUngroupedRadio(element) {
357
303
  return element.type === "radio" && !!element.name;
358
304
  }
305
+ function resolveOptions2(options) {
306
+ let {
307
+ anchor = getActiveElement(),
308
+ composed = false,
309
+ filter,
310
+ include,
311
+ skipNegativeTabIndexCheck = false,
312
+ skipVisibilityCheck = false,
313
+ wrap = false
314
+ } = options;
315
+ if (!(anchor instanceof Element)) {
316
+ const active = getActiveElement();
317
+ if (active instanceof Element) {
318
+ console.warn("Invalid anchor element. Fallback: active element.");
319
+ anchor = active;
320
+ }
321
+ }
322
+ if (typeof composed !== "boolean") {
323
+ console.warn("Invalid composed option. Fallback: false.");
324
+ composed = false;
325
+ }
326
+ if (filter !== void 0 && typeof filter !== "function") {
327
+ console.warn(
328
+ "Invalid filter function. Fallback: no filter function (undefined)."
329
+ );
330
+ filter = void 0;
331
+ }
332
+ if (include !== void 0 && typeof include !== "function") {
333
+ console.warn(
334
+ "Invalid include function. Fallback: no include function (undefined)."
335
+ );
336
+ include = void 0;
337
+ }
338
+ if (typeof skipNegativeTabIndexCheck !== "boolean") {
339
+ console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
340
+ skipNegativeTabIndexCheck = false;
341
+ }
342
+ if (typeof skipVisibilityCheck !== "boolean") {
343
+ console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
344
+ skipVisibilityCheck = false;
345
+ }
346
+ if (typeof wrap !== "boolean") {
347
+ console.warn("Invalid wrap option. Fallback: false.");
348
+ wrap = false;
349
+ }
350
+ return {
351
+ anchor,
352
+ composed,
353
+ filter,
354
+ include,
355
+ skipNegativeTabIndexCheck,
356
+ skipVisibilityCheck,
357
+ wrap
358
+ };
359
+ }
359
360
 
360
361
  // node_modules/@y14e/roving-tabindex/dist/index.js
361
362
  function createRovingTabIndex(container, options = {}) {
@@ -378,56 +379,7 @@ var RovingTabIndex = class _RovingTabIndex {
378
379
  #isDestroyed = false;
379
380
  constructor(container, options = {}) {
380
381
  this.#container = container;
381
- let {
382
- direction = "both",
383
- navigationOnly = false,
384
- noMemory = false,
385
- noStart = false,
386
- selector = "",
387
- typeahead = false,
388
- wrap = false
389
- } = options;
390
- if (!["both", "horizontal", "vertical"].includes(direction)) {
391
- console.warn("Invalid direction option. Fallback: 'both'.");
392
- direction = "both";
393
- }
394
- if (typeof navigationOnly !== "boolean") {
395
- console.warn("Invalid navigationOnly option. Fallback: false.");
396
- navigationOnly = false;
397
- }
398
- if (typeof noMemory !== "boolean") {
399
- console.warn("Invalid noMemory option. Fallback: false.");
400
- noMemory = false;
401
- }
402
- if (typeof noStart !== "boolean") {
403
- console.warn("Invalid noStart option. Fallback: false.");
404
- noStart = false;
405
- }
406
- if (selector !== "") {
407
- try {
408
- document.querySelector(selector);
409
- } catch {
410
- console.warn("Invalid selector. Fallback: no selector string.");
411
- selector = "";
412
- }
413
- }
414
- if (typeof typeahead !== "boolean") {
415
- console.warn("Invalid typeahead option. Fallback: false.");
416
- typeahead = false;
417
- }
418
- if (typeof wrap !== "boolean") {
419
- console.warn("Invalid wrap option. Fallback: false.");
420
- wrap = false;
421
- }
422
- this.#settings = {
423
- direction,
424
- navigationOnly,
425
- noMemory,
426
- noStart,
427
- selector,
428
- typeahead,
429
- wrap
430
- };
382
+ this.#settings = this.#resolveOptions(options);
431
383
  this.#selectorFilter = this.#createSelectorFilter();
432
384
  this.#initialize();
433
385
  }
@@ -438,10 +390,10 @@ var RovingTabIndex = class _RovingTabIndex {
438
390
  this.#isDestroyed = true;
439
391
  this.#controller?.abort();
440
392
  this.#controller = null;
441
- this.#focusables.forEach((focusable) => {
393
+ for (const focusable of this.#focusables) {
442
394
  _RovingTabIndex.#initialized.delete(focusable);
443
395
  restoreAttributes(focusable);
444
- });
396
+ }
445
397
  this.#focusables.clear();
446
398
  this.#focusablesByFirstChar.clear();
447
399
  }
@@ -585,17 +537,17 @@ var RovingTabIndex = class _RovingTabIndex {
585
537
  caseInsensitive: true
586
538
  });
587
539
  }
588
- keys.forEach((key) => {
540
+ for (const key of keys) {
589
541
  const focusables = this.#focusablesByFirstChar.get(key) ?? [];
590
542
  focusables.push(focusable);
591
543
  this.#focusablesByFirstChar.set(key, focusables);
592
- });
544
+ }
593
545
  }
594
546
  if (!navigationOnly) {
595
547
  if (active && this.#focusables.has(active)) {
596
- this.#focusables.forEach((focusable) => {
548
+ for (const focusable of this.#focusables) {
597
549
  focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
598
- });
550
+ }
599
551
  } else {
600
552
  [...this.#focusables].forEach((focusable, i) => {
601
553
  focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
@@ -615,6 +567,59 @@ var RovingTabIndex = class _RovingTabIndex {
615
567
  skipVisibilityCheck: true
616
568
  });
617
569
  }
570
+ #resolveOptions(options) {
571
+ let {
572
+ direction = "both",
573
+ navigationOnly = false,
574
+ noMemory = false,
575
+ noStart = false,
576
+ selector = "",
577
+ typeahead = false,
578
+ wrap = false
579
+ } = options;
580
+ direction = direction.toLowerCase();
581
+ if (!["both", "horizontal", "vertical"].includes(direction)) {
582
+ console.warn("Invalid direction option. Fallback: 'both'.");
583
+ direction = "both";
584
+ }
585
+ if (typeof navigationOnly !== "boolean") {
586
+ console.warn("Invalid navigationOnly option. Fallback: false.");
587
+ navigationOnly = false;
588
+ }
589
+ if (typeof noMemory !== "boolean") {
590
+ console.warn("Invalid noMemory option. Fallback: false.");
591
+ noMemory = false;
592
+ }
593
+ if (typeof noStart !== "boolean") {
594
+ console.warn("Invalid noStart option. Fallback: false.");
595
+ noStart = false;
596
+ }
597
+ if (selector !== "") {
598
+ try {
599
+ document.querySelector(selector);
600
+ } catch {
601
+ console.warn("Invalid selector. Fallback: no selector string.");
602
+ selector = "";
603
+ }
604
+ }
605
+ if (typeof typeahead !== "boolean") {
606
+ console.warn("Invalid typeahead option. Fallback: false.");
607
+ typeahead = false;
608
+ }
609
+ if (typeof wrap !== "boolean") {
610
+ console.warn("Invalid wrap option. Fallback: false.");
611
+ wrap = false;
612
+ }
613
+ return {
614
+ direction,
615
+ navigationOnly,
616
+ noMemory,
617
+ noStart,
618
+ selector,
619
+ typeahead,
620
+ wrap
621
+ };
622
+ }
618
623
  };
619
624
 
620
625
  // src/index.ts
@@ -725,14 +730,14 @@ var Disclosure = class _Disclosure {
725
730
  ]);
726
731
  this.#controller = new AbortController();
727
732
  const { signal } = this.#controller;
728
- this.#summaryElements.forEach((summary) => {
733
+ for (const summary of this.#summaryElements) {
729
734
  if (!this.#isFocusable(summary)) {
730
735
  summary.setAttribute("aria-disabled", "true");
731
736
  summary.setAttribute("tabindex", "-1");
732
737
  summary.style.setProperty("pointer-events", "none");
733
738
  }
734
739
  summary.addEventListener("click", this.#onSummaryClick, { signal });
735
- });
740
+ }
736
741
  this.#cleanupRovingTabIndex = createRovingTabIndex(this.#rootElement, {
737
742
  direction: "vertical",
738
743
  navigationOnly: true,
@@ -784,7 +789,7 @@ var Disclosure = class _Disclosure {
784
789
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
785
790
  * Using the <details> and <summary> element.
786
791
  *
787
- * @version 2.0.9
792
+ * @version 2.0.11
788
793
  * @author Yusuke Kamiyamane
789
794
  * @license MIT
790
795
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -796,7 +801,7 @@ var Disclosure = class _Disclosure {
796
801
  (**
797
802
  * Attribute Utils
798
803
  *
799
- * @version 2.0.6
804
+ * @version 2.0.10
800
805
  * @author Yusuke Kamiyamane
801
806
  * @license MIT
802
807
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -809,7 +814,7 @@ power-focusable/dist/index.js:
809
814
  * High-precision focus management utility with full composed tree support.
810
815
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
811
816
  *
812
- * @version 4.3.28
817
+ * @version 4.3.30
813
818
  * @author Yusuke Kamiyamane
814
819
  * @license MIT
815
820
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -822,7 +827,7 @@ power-focusable/dist/index.js:
822
827
  * Lightweight roving tabindex utility with fully focus management.
823
828
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
824
829
  *
825
- * @version 3.1.25
830
+ * @version 3.1.28
826
831
  * @author Yusuke Kamiyamane
827
832
  * @license MIT
828
833
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -35,24 +35,26 @@ 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)) {
51
51
  console.warn("Invalid element");
52
52
  return false;
53
53
  }
54
- if (!element.hasAttribute(name)) {
55
- console.warn("Invalid attribute name");
54
+ try {
55
+ document.createElement("div").setAttribute(name, "");
56
+ } catch {
57
+ console.warn(`Invalid attribute name: '${name}'`);
56
58
  return false;
57
59
  }
58
60
  if (typeof token !== "string" || !token.trim()) {
@@ -87,7 +89,7 @@ function resolveOptions(options) {
87
89
  }
88
90
 
89
91
  // node_modules/power-focusable/dist/index.js
90
- 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"])';
91
93
  var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX = FOCUSABLE_SELECTOR.replace(
92
94
  /(,\s*)?\[tabindex="-1"\]/g,
93
95
  ""
@@ -97,37 +99,13 @@ function getFocusables(container = document.body, options = {}) {
97
99
  console.warn("Invalid container element. Fallback: <body> element.");
98
100
  container = document.body;
99
101
  }
100
- let {
101
- composed = false,
102
+ const {
103
+ composed,
102
104
  filter,
103
105
  include,
104
- skipNegativeTabIndexCheck = false,
105
- skipVisibilityCheck = false
106
- } = options;
107
- if (typeof composed !== "boolean") {
108
- console.warn("Invalid composed option. Fallback: false.");
109
- composed = false;
110
- }
111
- if (typeof filter !== "undefined" && typeof filter !== "function") {
112
- console.warn(
113
- "Invalid filter function. Fallback: no filter function (undefined)."
114
- );
115
- filter = void 0;
116
- }
117
- if (typeof include !== "undefined" && typeof include !== "function") {
118
- console.warn(
119
- "Invalid include function. Fallback: no include function (undefined)."
120
- );
121
- include = void 0;
122
- }
123
- if (typeof skipNegativeTabIndexCheck !== "boolean") {
124
- console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
125
- skipNegativeTabIndexCheck = false;
126
- }
127
- if (typeof skipVisibilityCheck !== "boolean") {
128
- console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
129
- skipVisibilityCheck = false;
130
- }
106
+ skipNegativeTabIndexCheck,
107
+ skipVisibilityCheck
108
+ } = resolveOptions2(options);
131
109
  const candidates = [];
132
110
  if (composed || include) {
133
111
  let traverse2 = function(node) {
@@ -137,29 +115,19 @@ function getFocusables(container = document.body, options = {}) {
137
115
  }) || include?.(node)) {
138
116
  candidates[candidates.length] = node;
139
117
  }
140
- const children2 = composed ? getComposedChildren(node) : getChildren(node);
141
- for (let i = 0, l = children2.length; i < l; i++) {
142
- const child = children2[i];
143
- child && traverse2(child);
144
- }
118
+ (composed ? getComposedChildren(node) : getChildren(node)).map(traverse2);
145
119
  };
146
- const children = composed ? getComposedChildren(container) : getChildren(container);
147
- for (let i = 0, l = children.length; i < l; i++) {
148
- const child = children[i];
149
- child && traverse2(child);
150
- }
120
+ (composed ? getComposedChildren(container) : getChildren(container)).map(
121
+ traverse2
122
+ );
151
123
  } else {
152
- const matches = container.querySelectorAll(
124
+ for (const match of container.querySelectorAll(
153
125
  skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX : FOCUSABLE_SELECTOR
154
- );
155
- for (let i = 0, l = matches.length; i < l; i++) {
156
- const matched = matches[i];
157
- if (matched && isFocusable(matched, {
126
+ )) {
127
+ match && isFocusable(match, {
158
128
  skipNegativeTabIndexCheck,
159
129
  skipVisibilityCheck
160
- })) {
161
- candidates[candidates.length] = matched;
162
- }
130
+ }) && candidates.push(match);
163
131
  }
164
132
  }
165
133
  return normalizeRadioGroup(
@@ -171,15 +139,7 @@ function isFocusable(element, options = {}) {
171
139
  console.warn("Invalid element");
172
140
  return false;
173
141
  }
174
- let { skipNegativeTabIndexCheck = false, skipVisibilityCheck = false } = options;
175
- if (typeof skipNegativeTabIndexCheck !== "boolean") {
176
- console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
177
- skipNegativeTabIndexCheck = false;
178
- }
179
- if (typeof skipVisibilityCheck !== "boolean") {
180
- console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
181
- skipVisibilityCheck = false;
182
- }
142
+ const { skipNegativeTabIndexCheck, skipVisibilityCheck } = resolveOptions2(options);
183
143
  if (element.hasAttribute("hidden") || isInert(element)) {
184
144
  return false;
185
145
  }
@@ -234,8 +194,7 @@ function isDisabledDeep(element) {
234
194
  }
235
195
  function normalizeRadioGroup(elements) {
236
196
  let map = null;
237
- for (let i = 0, l = elements.length; i < l; i++) {
238
- const element = elements[i];
197
+ for (const element of elements) {
239
198
  if (!(element instanceof HTMLInputElement)) {
240
199
  continue;
241
200
  }
@@ -285,23 +244,10 @@ function normalizeRadioGroup(elements) {
285
244
  function sortByTabIndex(elements) {
286
245
  const ordered = [];
287
246
  const natural = [];
288
- for (let i = 0, l = elements.length; i < l; i++) {
289
- const element = elements[i];
290
- if (element) {
291
- const target = getTabIndex(element) > 0 ? ordered : natural;
292
- target[target.length] = element;
293
- }
247
+ for (const element of elements) {
248
+ (getTabIndex(element) > 0 ? ordered : natural).push(element);
294
249
  }
295
- ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
296
- let count = 0;
297
- const sorted = new Array(ordered.length + natural.length);
298
- for (let i = 0, l = ordered.length; i < l; i++) {
299
- sorted[count++] = ordered[i];
300
- }
301
- for (let i = 0, l = natural.length; i < l; i++) {
302
- sorted[count++] = natural[i];
303
- }
304
- return sorted;
250
+ return ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b)).concat(natural);
305
251
  }
306
252
  function getComposedChildren(node) {
307
253
  if (node instanceof ShadowRoot) {
@@ -354,6 +300,61 @@ function isInert(element) {
354
300
  function isUngroupedRadio(element) {
355
301
  return element.type === "radio" && !!element.name;
356
302
  }
303
+ function resolveOptions2(options) {
304
+ let {
305
+ anchor = getActiveElement(),
306
+ composed = false,
307
+ filter,
308
+ include,
309
+ skipNegativeTabIndexCheck = false,
310
+ skipVisibilityCheck = false,
311
+ wrap = false
312
+ } = options;
313
+ if (!(anchor instanceof Element)) {
314
+ const active = getActiveElement();
315
+ if (active instanceof Element) {
316
+ console.warn("Invalid anchor element. Fallback: active element.");
317
+ anchor = active;
318
+ }
319
+ }
320
+ if (typeof composed !== "boolean") {
321
+ console.warn("Invalid composed option. Fallback: false.");
322
+ composed = false;
323
+ }
324
+ if (filter !== void 0 && typeof filter !== "function") {
325
+ console.warn(
326
+ "Invalid filter function. Fallback: no filter function (undefined)."
327
+ );
328
+ filter = void 0;
329
+ }
330
+ if (include !== void 0 && typeof include !== "function") {
331
+ console.warn(
332
+ "Invalid include function. Fallback: no include function (undefined)."
333
+ );
334
+ include = void 0;
335
+ }
336
+ if (typeof skipNegativeTabIndexCheck !== "boolean") {
337
+ console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
338
+ skipNegativeTabIndexCheck = false;
339
+ }
340
+ if (typeof skipVisibilityCheck !== "boolean") {
341
+ console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
342
+ skipVisibilityCheck = false;
343
+ }
344
+ if (typeof wrap !== "boolean") {
345
+ console.warn("Invalid wrap option. Fallback: false.");
346
+ wrap = false;
347
+ }
348
+ return {
349
+ anchor,
350
+ composed,
351
+ filter,
352
+ include,
353
+ skipNegativeTabIndexCheck,
354
+ skipVisibilityCheck,
355
+ wrap
356
+ };
357
+ }
357
358
 
358
359
  // node_modules/@y14e/roving-tabindex/dist/index.js
359
360
  function createRovingTabIndex(container, options = {}) {
@@ -376,56 +377,7 @@ var RovingTabIndex = class _RovingTabIndex {
376
377
  #isDestroyed = false;
377
378
  constructor(container, options = {}) {
378
379
  this.#container = container;
379
- let {
380
- direction = "both",
381
- navigationOnly = false,
382
- noMemory = false,
383
- noStart = false,
384
- selector = "",
385
- typeahead = false,
386
- wrap = false
387
- } = options;
388
- if (!["both", "horizontal", "vertical"].includes(direction)) {
389
- console.warn("Invalid direction option. Fallback: 'both'.");
390
- direction = "both";
391
- }
392
- if (typeof navigationOnly !== "boolean") {
393
- console.warn("Invalid navigationOnly option. Fallback: false.");
394
- navigationOnly = false;
395
- }
396
- if (typeof noMemory !== "boolean") {
397
- console.warn("Invalid noMemory option. Fallback: false.");
398
- noMemory = false;
399
- }
400
- if (typeof noStart !== "boolean") {
401
- console.warn("Invalid noStart option. Fallback: false.");
402
- noStart = false;
403
- }
404
- if (selector !== "") {
405
- try {
406
- document.querySelector(selector);
407
- } catch {
408
- console.warn("Invalid selector. Fallback: no selector string.");
409
- selector = "";
410
- }
411
- }
412
- if (typeof typeahead !== "boolean") {
413
- console.warn("Invalid typeahead option. Fallback: false.");
414
- typeahead = false;
415
- }
416
- if (typeof wrap !== "boolean") {
417
- console.warn("Invalid wrap option. Fallback: false.");
418
- wrap = false;
419
- }
420
- this.#settings = {
421
- direction,
422
- navigationOnly,
423
- noMemory,
424
- noStart,
425
- selector,
426
- typeahead,
427
- wrap
428
- };
380
+ this.#settings = this.#resolveOptions(options);
429
381
  this.#selectorFilter = this.#createSelectorFilter();
430
382
  this.#initialize();
431
383
  }
@@ -436,10 +388,10 @@ var RovingTabIndex = class _RovingTabIndex {
436
388
  this.#isDestroyed = true;
437
389
  this.#controller?.abort();
438
390
  this.#controller = null;
439
- this.#focusables.forEach((focusable) => {
391
+ for (const focusable of this.#focusables) {
440
392
  _RovingTabIndex.#initialized.delete(focusable);
441
393
  restoreAttributes(focusable);
442
- });
394
+ }
443
395
  this.#focusables.clear();
444
396
  this.#focusablesByFirstChar.clear();
445
397
  }
@@ -583,17 +535,17 @@ var RovingTabIndex = class _RovingTabIndex {
583
535
  caseInsensitive: true
584
536
  });
585
537
  }
586
- keys.forEach((key) => {
538
+ for (const key of keys) {
587
539
  const focusables = this.#focusablesByFirstChar.get(key) ?? [];
588
540
  focusables.push(focusable);
589
541
  this.#focusablesByFirstChar.set(key, focusables);
590
- });
542
+ }
591
543
  }
592
544
  if (!navigationOnly) {
593
545
  if (active && this.#focusables.has(active)) {
594
- this.#focusables.forEach((focusable) => {
546
+ for (const focusable of this.#focusables) {
595
547
  focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
596
- });
548
+ }
597
549
  } else {
598
550
  [...this.#focusables].forEach((focusable, i) => {
599
551
  focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
@@ -613,6 +565,59 @@ var RovingTabIndex = class _RovingTabIndex {
613
565
  skipVisibilityCheck: true
614
566
  });
615
567
  }
568
+ #resolveOptions(options) {
569
+ let {
570
+ direction = "both",
571
+ navigationOnly = false,
572
+ noMemory = false,
573
+ noStart = false,
574
+ selector = "",
575
+ typeahead = false,
576
+ wrap = false
577
+ } = options;
578
+ direction = direction.toLowerCase();
579
+ if (!["both", "horizontal", "vertical"].includes(direction)) {
580
+ console.warn("Invalid direction option. Fallback: 'both'.");
581
+ direction = "both";
582
+ }
583
+ if (typeof navigationOnly !== "boolean") {
584
+ console.warn("Invalid navigationOnly option. Fallback: false.");
585
+ navigationOnly = false;
586
+ }
587
+ if (typeof noMemory !== "boolean") {
588
+ console.warn("Invalid noMemory option. Fallback: false.");
589
+ noMemory = false;
590
+ }
591
+ if (typeof noStart !== "boolean") {
592
+ console.warn("Invalid noStart option. Fallback: false.");
593
+ noStart = false;
594
+ }
595
+ if (selector !== "") {
596
+ try {
597
+ document.querySelector(selector);
598
+ } catch {
599
+ console.warn("Invalid selector. Fallback: no selector string.");
600
+ selector = "";
601
+ }
602
+ }
603
+ if (typeof typeahead !== "boolean") {
604
+ console.warn("Invalid typeahead option. Fallback: false.");
605
+ typeahead = false;
606
+ }
607
+ if (typeof wrap !== "boolean") {
608
+ console.warn("Invalid wrap option. Fallback: false.");
609
+ wrap = false;
610
+ }
611
+ return {
612
+ direction,
613
+ navigationOnly,
614
+ noMemory,
615
+ noStart,
616
+ selector,
617
+ typeahead,
618
+ wrap
619
+ };
620
+ }
616
621
  };
617
622
 
618
623
  // src/index.ts
@@ -723,14 +728,14 @@ var Disclosure = class _Disclosure {
723
728
  ]);
724
729
  this.#controller = new AbortController();
725
730
  const { signal } = this.#controller;
726
- this.#summaryElements.forEach((summary) => {
731
+ for (const summary of this.#summaryElements) {
727
732
  if (!this.#isFocusable(summary)) {
728
733
  summary.setAttribute("aria-disabled", "true");
729
734
  summary.setAttribute("tabindex", "-1");
730
735
  summary.style.setProperty("pointer-events", "none");
731
736
  }
732
737
  summary.addEventListener("click", this.#onSummaryClick, { signal });
733
- });
738
+ }
734
739
  this.#cleanupRovingTabIndex = createRovingTabIndex(this.#rootElement, {
735
740
  direction: "vertical",
736
741
  navigationOnly: true,
@@ -782,7 +787,7 @@ var Disclosure = class _Disclosure {
782
787
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
783
788
  * Using the <details> and <summary> element.
784
789
  *
785
- * @version 2.0.9
790
+ * @version 2.0.11
786
791
  * @author Yusuke Kamiyamane
787
792
  * @license MIT
788
793
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -794,7 +799,7 @@ var Disclosure = class _Disclosure {
794
799
  (**
795
800
  * Attribute Utils
796
801
  *
797
- * @version 2.0.6
802
+ * @version 2.0.10
798
803
  * @author Yusuke Kamiyamane
799
804
  * @license MIT
800
805
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -807,7 +812,7 @@ power-focusable/dist/index.js:
807
812
  * High-precision focus management utility with full composed tree support.
808
813
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
809
814
  *
810
- * @version 4.3.28
815
+ * @version 4.3.30
811
816
  * @author Yusuke Kamiyamane
812
817
  * @license MIT
813
818
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -820,7 +825,7 @@ power-focusable/dist/index.js:
820
825
  * Lightweight roving tabindex utility with fully focus management.
821
826
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
822
827
  *
823
- * @version 3.1.25
828
+ * @version 3.1.28
824
829
  * @author Yusuke Kamiyamane
825
830
  * @license MIT
826
831
  * @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,
@@ -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.9
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.9
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.9
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,
@@ -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.9
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.9",
3
+ "version": "2.0.11",
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.6",
58
- "@y14e/roving-tabindex": "^3.1.25"
57
+ "@y14e/attribute-utils": "^2.0.10",
58
+ "@y14e/roving-tabindex": "^3.1.28"
59
59
  }
60
60
  }