@y14e/disclosure 1.3.10 → 1.3.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
10
10
 
11
11
  ```ts
12
12
  // npm
13
- import Disclosure from '@y14e/disclosure@1.3.10';
13
+ import Disclosure from '@y14e/disclosure@1.3.12';
14
14
 
15
15
  // CDNs
16
- import Disclosure from 'https://esm.sh/@y14e/disclosure@1.3.10';
16
+ import Disclosure from 'https://esm.sh/@y14e/disclosure@1.3.12';
17
17
  // or
18
- import Disclosure from 'https://cdn.jsdelivr.net/npm/@y14e/disclosure@1.3.10/+esm';
18
+ import Disclosure from 'https://cdn.jsdelivr.net/npm/@y14e/disclosure@1.3.12/+esm';
19
19
  // or
20
- import Disclosure from 'https://esm.unpkg.com/@y14e/disclosure@1.3.10';
20
+ import Disclosure from 'https://esm.unpkg.com/@y14e/disclosure@1.3.12';
21
21
  ```
22
22
 
23
23
  ## Usage
package/dist/index.cjs CHANGED
@@ -28,13 +28,13 @@ function saveAttributes(elements, attributes) {
28
28
  }
29
29
 
30
30
  // node_modules/@y14e/roving-tabindex/dist/index.js
31
- var defaultParser = (value) => value.split(/\s+/);
32
- var defaultSerializer = (tokens) => tokens.join(" ");
31
+ var DEFAULT_PARSER = (value) => value.split(/\s+/);
32
+ var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
33
33
  function addTokenToAttribute(element, attribute, token, options = {}) {
34
34
  const {
35
35
  caseInsensitive = false,
36
- parse = defaultParser,
37
- serialize = defaultSerializer
36
+ parse = DEFAULT_PARSER,
37
+ serialize = DEFAULT_SERIALIZER
38
38
  } = options;
39
39
  const value = element.getAttribute(attribute)?.trim();
40
40
  const tokens = value ? parse(value).filter(Boolean) : [];
@@ -44,11 +44,11 @@ function addTokenToAttribute(element, attribute, token, options = {}) {
44
44
  tokens.push(token);
45
45
  element.setAttribute(attribute, serialize(tokens));
46
46
  }
47
- return;
47
+ } else {
48
+ const set = new Set(tokens);
49
+ set.add(token);
50
+ element.setAttribute(attribute, serialize([...set]));
48
51
  }
49
- const set = new Set(tokens);
50
- set.add(token);
51
- element.setAttribute(attribute, serialize([...set]));
52
52
  }
53
53
  var snapshots2 = /* @__PURE__ */ new WeakMap();
54
54
  function restoreAttributes2(elements) {
@@ -115,21 +115,16 @@ function getFocusables(container = document.body, options = {}) {
115
115
  const elements = [];
116
116
  if (composed || include) {
117
117
  let traverse2 = function(node) {
118
- if (node instanceof Element) {
119
- if (isFocusable(node, {
120
- skipNegativeTabIndexCheck,
121
- skipVisibilityCheck
122
- }) || include?.(node)) {
123
- elements[elements.length] = node;
124
- }
118
+ if (!(node instanceof Element)) {
119
+ return;
120
+ }
121
+ if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
122
+ elements[elements.length] = node;
125
123
  }
126
124
  const children = getComposedChildren(node);
127
125
  for (let i = 0, l = children.length; i < l; i++) {
128
126
  const child = children[i];
129
- if (!child) {
130
- continue;
131
- }
132
- traverse2(child);
127
+ child && traverse2(child);
133
128
  }
134
129
  };
135
130
  traverse2(container);
@@ -137,10 +132,7 @@ function getFocusables(container = document.body, options = {}) {
137
132
  const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
138
133
  for (let i = 0, l = candidates.length; i < l; i++) {
139
134
  const candidate = candidates[i];
140
- if (!(candidate instanceof Element)) {
141
- continue;
142
- }
143
- if (isFocusable(candidate, {
135
+ if (candidate && isFocusable(candidate, {
144
136
  skipNegativeTabIndexCheck,
145
137
  skipVisibilityCheck
146
138
  })) {
@@ -243,23 +235,19 @@ function normalizeRadioGroup(elements) {
243
235
  for (const group of map.values()) {
244
236
  placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
245
237
  }
246
- return elements.filter((element) => {
247
- if (isUngroupedRadio(element)) {
248
- return placeholder.has(element);
249
- }
250
- return true;
251
- });
238
+ return elements.filter(
239
+ (element) => isUngroupedRadio(element) ? placeholder.has(element) : true
240
+ );
252
241
  }
253
242
  function sortByTabIndex(elements) {
254
243
  const ordered = [];
255
244
  const natural = [];
256
245
  for (let i = 0, l = elements.length; i < l; i++) {
257
246
  const element = elements[i];
258
- if (!element) {
259
- continue;
247
+ if (element) {
248
+ const target = getTabIndex(element) > 0 ? ordered : natural;
249
+ target[target.length] = element;
260
250
  }
261
- const target = getTabIndex(element) > 0 ? ordered : natural;
262
- target[target.length] = element;
263
251
  }
264
252
  ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
265
253
  let count = 0;
@@ -412,15 +400,10 @@ var RovingTabIndex = class {
412
400
  }
413
401
  #onFocusIn = (event) => {
414
402
  const { target } = event;
415
- if (!(target instanceof Element)) {
416
- return;
403
+ if (target instanceof Element) {
404
+ const isFocusable22 = this.#focusables.has(target);
405
+ this.#options.noMemory && !isFocusable22 ? this.#update(null) : isFocusable22 && this.#update(target);
417
406
  }
418
- const isFocusable22 = this.#focusables.has(target);
419
- if (this.#options.noMemory && !isFocusable22) {
420
- this.#update(null);
421
- return;
422
- }
423
- isFocusable22 && this.#update(target);
424
407
  };
425
408
  #onKeyDown = (event) => {
426
409
  if (!event.composedPath().includes(this.#container)) {
@@ -453,8 +436,7 @@ var RovingTabIndex = class {
453
436
  }
454
437
  event.preventDefault();
455
438
  const currentIndex = current.indexOf(active);
456
- let rawIndex;
457
- let newIndex = currentIndex;
439
+ let newIndex;
458
440
  let target = current;
459
441
  switch (key) {
460
442
  case "End":
@@ -464,15 +446,17 @@ var RovingTabIndex = class {
464
446
  newIndex = 0;
465
447
  break;
466
448
  case "ArrowLeft":
467
- case "ArrowUp":
468
- rawIndex = currentIndex - 1;
449
+ case "ArrowUp": {
450
+ const rawIndex = currentIndex - 1;
469
451
  newIndex = wrap ? rawIndex : Math.max(rawIndex, 0);
470
452
  break;
453
+ }
471
454
  case "ArrowRight":
472
- case "ArrowDown":
473
- rawIndex = currentIndex + 1;
455
+ case "ArrowDown": {
456
+ const rawIndex = currentIndex + 1;
474
457
  newIndex = wrap ? rawIndex % current.length : Math.min(rawIndex, current.length - 1);
475
458
  break;
459
+ }
476
460
  default: {
477
461
  target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
478
462
  const foundIndex = target.findIndex(
@@ -487,15 +471,14 @@ var RovingTabIndex = class {
487
471
  #update(active) {
488
472
  const current = new Set(this.#getFocusables());
489
473
  for (const focusable of this.#focusables) {
490
- if (current.has(focusable)) {
491
- continue;
474
+ if (!current.has(focusable)) {
475
+ focusable.isConnected && restoreAttributes2([focusable]);
476
+ this.#focusables.delete(focusable);
477
+ this.#focusablesByFirstChar.forEach((focusables) => {
478
+ const index = focusables.indexOf(focusable);
479
+ index >= 0 && focusables.splice(index, 1);
480
+ });
492
481
  }
493
- focusable.isConnected && restoreAttributes2([focusable]);
494
- this.#focusables.delete(focusable);
495
- this.#focusablesByFirstChar.forEach((focusables) => {
496
- const index = focusables.indexOf(focusable);
497
- index >= 0 && focusables.splice(index, 1);
498
- });
499
482
  }
500
483
  const { navigationOnly, noStart, typeahead } = this.#options;
501
484
  for (const focusable of current) {
@@ -510,11 +493,11 @@ var RovingTabIndex = class {
510
493
  if (!typeahead) {
511
494
  continue;
512
495
  }
496
+ const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
513
497
  const value = focusable.ariaKeyShortcuts?.trim();
514
498
  const keys = new Set(
515
499
  value ? value.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
516
500
  );
517
- const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
518
501
  if (char) {
519
502
  keys.add(char);
520
503
  saveAttributes2([focusable], ["aria-keyshortcuts"]);
@@ -528,18 +511,17 @@ var RovingTabIndex = class {
528
511
  this.#focusablesByFirstChar.set(key, focusables);
529
512
  });
530
513
  }
531
- if (navigationOnly) {
532
- return;
533
- }
534
- if (active && this.#focusables.has(active)) {
535
- this.#focusables.forEach((focusable) => {
536
- focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
537
- });
538
- return;
514
+ if (!navigationOnly) {
515
+ if (active && this.#focusables.has(active)) {
516
+ this.#focusables.forEach((focusable) => {
517
+ focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
518
+ });
519
+ } else {
520
+ [...this.#focusables].forEach((focusable, i) => {
521
+ focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
522
+ });
523
+ }
539
524
  }
540
- [...this.#focusables].forEach((focusable, i) => {
541
- focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
542
- });
543
525
  }
544
526
  #createSelectorFilter() {
545
527
  const { selector } = this.#options;
@@ -628,13 +610,12 @@ var Disclosure = class _Disclosure {
628
610
  this.#detailsElements.forEach((details, i) => {
629
611
  const summary = this.#summaryElements[i];
630
612
  const content = this.#contentElements[i];
631
- if (!summary || !content) {
632
- return;
613
+ if (summary && content) {
614
+ const binding = createBinding(details, summary, content);
615
+ this.#bindings.set(details, binding);
616
+ this.#bindings.set(summary, binding);
617
+ this.#bindings.set(content, binding);
633
618
  }
634
- const binding = createBinding(details, summary, content);
635
- this.#bindings.set(details, binding);
636
- this.#bindings.set(summary, binding);
637
- this.#bindings.set(content, binding);
638
619
  });
639
620
  this.#initialize();
640
621
  }
@@ -642,11 +623,11 @@ var Disclosure = class _Disclosure {
642
623
  if (this.#isDestroyed) {
643
624
  return;
644
625
  }
645
- if (!(details instanceof HTMLDetailsElement) || !this.#bindings.has(details)) {
626
+ if (details instanceof HTMLDetailsElement && this.#bindings.has(details)) {
627
+ this.#toggle(details, false);
628
+ } else {
646
629
  console.warn("Invalid <details> element");
647
- return;
648
630
  }
649
- this.#toggle(details, false);
650
631
  }
651
632
  async destroy(force = false) {
652
633
  if (this.#isDestroyed) {
@@ -683,11 +664,11 @@ var Disclosure = class _Disclosure {
683
664
  if (this.#isDestroyed) {
684
665
  return;
685
666
  }
686
- if (!(details instanceof HTMLDetailsElement) || !this.#bindings.has(details)) {
667
+ if (details instanceof HTMLDetailsElement && this.#bindings.has(details)) {
668
+ this.#toggle(details, true);
669
+ } else {
687
670
  console.warn("Invalid <details> element");
688
- return;
689
671
  }
690
- this.#toggle(details, true);
691
672
  }
692
673
  #initialize() {
693
674
  saveAttributes(this.#summaryElements, [
@@ -732,11 +713,10 @@ var Disclosure = class _Disclosure {
732
713
  return;
733
714
  }
734
715
  const binding = this.#bindings.get(summary);
735
- if (!binding) {
736
- return;
716
+ if (binding) {
717
+ const { details } = binding;
718
+ this.#toggle(details, !details.hasAttribute("data-disclosure-open"));
737
719
  }
738
- const { details } = binding;
739
- this.#toggle(details, !details.hasAttribute("data-disclosure-open"));
740
720
  };
741
721
  #toggle(details, isOpen) {
742
722
  if (details.hasAttribute("data-disclosure-open") === isOpen) {
@@ -785,11 +765,10 @@ var Disclosure = class _Disclosure {
785
765
  animation.addEventListener(
786
766
  "finish",
787
767
  () => {
788
- if (binding?.animation !== animation) {
789
- return;
768
+ if (binding?.animation === animation) {
769
+ this.#onAnimationFinish(content);
770
+ cleanup();
790
771
  }
791
- this.#onAnimationFinish(content);
792
- cleanup();
793
772
  },
794
773
  { once: true, signal }
795
774
  );
@@ -835,17 +814,18 @@ function isFocusable2(element) {
835
814
  function waitAnimationFinish(animation) {
836
815
  if (["idle", "finished"].includes(animation.playState)) {
837
816
  return Promise.resolve();
817
+ } else {
818
+ return new Promise(
819
+ (resolve) => animation.addEventListener("finish", () => resolve(), { once: true })
820
+ );
838
821
  }
839
- return new Promise(
840
- (resolve) => animation.addEventListener("finish", () => resolve(), { once: true })
841
- );
842
822
  }
843
823
  /**
844
824
  * Disclosure
845
825
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
846
826
  * Using the <details> and <summary> element.
847
827
  *
848
- * @version 1.3.10
828
+ * @version 1.3.12
849
829
  * @author Yusuke Kamiyamane
850
830
  * @license MIT
851
831
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -857,7 +837,7 @@ function waitAnimationFinish(animation) {
857
837
  (**
858
838
  * Attributes Utils
859
839
  *
860
- * @version 1.1.1
840
+ * @version 1.1.2
861
841
  * @author Yusuke Kamiyamane
862
842
  * @license MIT
863
843
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -870,7 +850,7 @@ function waitAnimationFinish(animation) {
870
850
  * Lightweight roving tabindex utility with fully focus management.
871
851
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
872
852
  *
873
- * @version 3.0.0
853
+ * @version 3.0.4
874
854
  * @author Yusuke Kamiyamane
875
855
  * @license MIT
876
856
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -882,7 +862,7 @@ function waitAnimationFinish(animation) {
882
862
  (**
883
863
  * Attributes Utils
884
864
  *
885
- * @version 1.1.1
865
+ * @version 1.1.2
886
866
  * @author Yusuke Kamiyamane
887
867
  * @license MIT
888
868
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -895,7 +875,7 @@ function waitAnimationFinish(animation) {
895
875
  * High-precision focus management utility with full composed tree support.
896
876
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
897
877
  *
898
- * @version 4.3.2
878
+ * @version 4.3.3
899
879
  * @author Yusuke Kamiyamane
900
880
  * @license MIT
901
881
  * @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 1.3.10
6
+ * @version 1.3.12
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 1.3.10
6
+ * @version 1.3.12
7
7
  * @author Yusuke Kamiyamane
8
8
  * @license MIT
9
9
  * @copyright Copyright (c) Yusuke Kamiyamane
package/dist/index.js CHANGED
@@ -26,13 +26,13 @@ function saveAttributes(elements, attributes) {
26
26
  }
27
27
 
28
28
  // node_modules/@y14e/roving-tabindex/dist/index.js
29
- var defaultParser = (value) => value.split(/\s+/);
30
- var defaultSerializer = (tokens) => tokens.join(" ");
29
+ var DEFAULT_PARSER = (value) => value.split(/\s+/);
30
+ var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
31
31
  function addTokenToAttribute(element, attribute, token, options = {}) {
32
32
  const {
33
33
  caseInsensitive = false,
34
- parse = defaultParser,
35
- serialize = defaultSerializer
34
+ parse = DEFAULT_PARSER,
35
+ serialize = DEFAULT_SERIALIZER
36
36
  } = options;
37
37
  const value = element.getAttribute(attribute)?.trim();
38
38
  const tokens = value ? parse(value).filter(Boolean) : [];
@@ -42,11 +42,11 @@ function addTokenToAttribute(element, attribute, token, options = {}) {
42
42
  tokens.push(token);
43
43
  element.setAttribute(attribute, serialize(tokens));
44
44
  }
45
- return;
45
+ } else {
46
+ const set = new Set(tokens);
47
+ set.add(token);
48
+ element.setAttribute(attribute, serialize([...set]));
46
49
  }
47
- const set = new Set(tokens);
48
- set.add(token);
49
- element.setAttribute(attribute, serialize([...set]));
50
50
  }
51
51
  var snapshots2 = /* @__PURE__ */ new WeakMap();
52
52
  function restoreAttributes2(elements) {
@@ -113,21 +113,16 @@ function getFocusables(container = document.body, options = {}) {
113
113
  const elements = [];
114
114
  if (composed || include) {
115
115
  let traverse2 = function(node) {
116
- if (node instanceof Element) {
117
- if (isFocusable(node, {
118
- skipNegativeTabIndexCheck,
119
- skipVisibilityCheck
120
- }) || include?.(node)) {
121
- elements[elements.length] = node;
122
- }
116
+ if (!(node instanceof Element)) {
117
+ return;
118
+ }
119
+ if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
120
+ elements[elements.length] = node;
123
121
  }
124
122
  const children = getComposedChildren(node);
125
123
  for (let i = 0, l = children.length; i < l; i++) {
126
124
  const child = children[i];
127
- if (!child) {
128
- continue;
129
- }
130
- traverse2(child);
125
+ child && traverse2(child);
131
126
  }
132
127
  };
133
128
  traverse2(container);
@@ -135,10 +130,7 @@ function getFocusables(container = document.body, options = {}) {
135
130
  const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
136
131
  for (let i = 0, l = candidates.length; i < l; i++) {
137
132
  const candidate = candidates[i];
138
- if (!(candidate instanceof Element)) {
139
- continue;
140
- }
141
- if (isFocusable(candidate, {
133
+ if (candidate && isFocusable(candidate, {
142
134
  skipNegativeTabIndexCheck,
143
135
  skipVisibilityCheck
144
136
  })) {
@@ -241,23 +233,19 @@ function normalizeRadioGroup(elements) {
241
233
  for (const group of map.values()) {
242
234
  placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
243
235
  }
244
- return elements.filter((element) => {
245
- if (isUngroupedRadio(element)) {
246
- return placeholder.has(element);
247
- }
248
- return true;
249
- });
236
+ return elements.filter(
237
+ (element) => isUngroupedRadio(element) ? placeholder.has(element) : true
238
+ );
250
239
  }
251
240
  function sortByTabIndex(elements) {
252
241
  const ordered = [];
253
242
  const natural = [];
254
243
  for (let i = 0, l = elements.length; i < l; i++) {
255
244
  const element = elements[i];
256
- if (!element) {
257
- continue;
245
+ if (element) {
246
+ const target = getTabIndex(element) > 0 ? ordered : natural;
247
+ target[target.length] = element;
258
248
  }
259
- const target = getTabIndex(element) > 0 ? ordered : natural;
260
- target[target.length] = element;
261
249
  }
262
250
  ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
263
251
  let count = 0;
@@ -410,15 +398,10 @@ var RovingTabIndex = class {
410
398
  }
411
399
  #onFocusIn = (event) => {
412
400
  const { target } = event;
413
- if (!(target instanceof Element)) {
414
- return;
401
+ if (target instanceof Element) {
402
+ const isFocusable22 = this.#focusables.has(target);
403
+ this.#options.noMemory && !isFocusable22 ? this.#update(null) : isFocusable22 && this.#update(target);
415
404
  }
416
- const isFocusable22 = this.#focusables.has(target);
417
- if (this.#options.noMemory && !isFocusable22) {
418
- this.#update(null);
419
- return;
420
- }
421
- isFocusable22 && this.#update(target);
422
405
  };
423
406
  #onKeyDown = (event) => {
424
407
  if (!event.composedPath().includes(this.#container)) {
@@ -451,8 +434,7 @@ var RovingTabIndex = class {
451
434
  }
452
435
  event.preventDefault();
453
436
  const currentIndex = current.indexOf(active);
454
- let rawIndex;
455
- let newIndex = currentIndex;
437
+ let newIndex;
456
438
  let target = current;
457
439
  switch (key) {
458
440
  case "End":
@@ -462,15 +444,17 @@ var RovingTabIndex = class {
462
444
  newIndex = 0;
463
445
  break;
464
446
  case "ArrowLeft":
465
- case "ArrowUp":
466
- rawIndex = currentIndex - 1;
447
+ case "ArrowUp": {
448
+ const rawIndex = currentIndex - 1;
467
449
  newIndex = wrap ? rawIndex : Math.max(rawIndex, 0);
468
450
  break;
451
+ }
469
452
  case "ArrowRight":
470
- case "ArrowDown":
471
- rawIndex = currentIndex + 1;
453
+ case "ArrowDown": {
454
+ const rawIndex = currentIndex + 1;
472
455
  newIndex = wrap ? rawIndex % current.length : Math.min(rawIndex, current.length - 1);
473
456
  break;
457
+ }
474
458
  default: {
475
459
  target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
476
460
  const foundIndex = target.findIndex(
@@ -485,15 +469,14 @@ var RovingTabIndex = class {
485
469
  #update(active) {
486
470
  const current = new Set(this.#getFocusables());
487
471
  for (const focusable of this.#focusables) {
488
- if (current.has(focusable)) {
489
- continue;
472
+ if (!current.has(focusable)) {
473
+ focusable.isConnected && restoreAttributes2([focusable]);
474
+ this.#focusables.delete(focusable);
475
+ this.#focusablesByFirstChar.forEach((focusables) => {
476
+ const index = focusables.indexOf(focusable);
477
+ index >= 0 && focusables.splice(index, 1);
478
+ });
490
479
  }
491
- focusable.isConnected && restoreAttributes2([focusable]);
492
- this.#focusables.delete(focusable);
493
- this.#focusablesByFirstChar.forEach((focusables) => {
494
- const index = focusables.indexOf(focusable);
495
- index >= 0 && focusables.splice(index, 1);
496
- });
497
480
  }
498
481
  const { navigationOnly, noStart, typeahead } = this.#options;
499
482
  for (const focusable of current) {
@@ -508,11 +491,11 @@ var RovingTabIndex = class {
508
491
  if (!typeahead) {
509
492
  continue;
510
493
  }
494
+ const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
511
495
  const value = focusable.ariaKeyShortcuts?.trim();
512
496
  const keys = new Set(
513
497
  value ? value.split(/\s+/).filter((key) => /^\S$/i.test(key)).map((key) => key.toUpperCase()) : []
514
498
  );
515
- const char = focusable.textContent?.trim()?.at(0)?.toUpperCase();
516
499
  if (char) {
517
500
  keys.add(char);
518
501
  saveAttributes2([focusable], ["aria-keyshortcuts"]);
@@ -526,18 +509,17 @@ var RovingTabIndex = class {
526
509
  this.#focusablesByFirstChar.set(key, focusables);
527
510
  });
528
511
  }
529
- if (navigationOnly) {
530
- return;
531
- }
532
- if (active && this.#focusables.has(active)) {
533
- this.#focusables.forEach((focusable) => {
534
- focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
535
- });
536
- return;
512
+ if (!navigationOnly) {
513
+ if (active && this.#focusables.has(active)) {
514
+ this.#focusables.forEach((focusable) => {
515
+ focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
516
+ });
517
+ } else {
518
+ [...this.#focusables].forEach((focusable, i) => {
519
+ focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
520
+ });
521
+ }
537
522
  }
538
- [...this.#focusables].forEach((focusable, i) => {
539
- focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
540
- });
541
523
  }
542
524
  #createSelectorFilter() {
543
525
  const { selector } = this.#options;
@@ -626,13 +608,12 @@ var Disclosure = class _Disclosure {
626
608
  this.#detailsElements.forEach((details, i) => {
627
609
  const summary = this.#summaryElements[i];
628
610
  const content = this.#contentElements[i];
629
- if (!summary || !content) {
630
- return;
611
+ if (summary && content) {
612
+ const binding = createBinding(details, summary, content);
613
+ this.#bindings.set(details, binding);
614
+ this.#bindings.set(summary, binding);
615
+ this.#bindings.set(content, binding);
631
616
  }
632
- const binding = createBinding(details, summary, content);
633
- this.#bindings.set(details, binding);
634
- this.#bindings.set(summary, binding);
635
- this.#bindings.set(content, binding);
636
617
  });
637
618
  this.#initialize();
638
619
  }
@@ -640,11 +621,11 @@ var Disclosure = class _Disclosure {
640
621
  if (this.#isDestroyed) {
641
622
  return;
642
623
  }
643
- if (!(details instanceof HTMLDetailsElement) || !this.#bindings.has(details)) {
624
+ if (details instanceof HTMLDetailsElement && this.#bindings.has(details)) {
625
+ this.#toggle(details, false);
626
+ } else {
644
627
  console.warn("Invalid <details> element");
645
- return;
646
628
  }
647
- this.#toggle(details, false);
648
629
  }
649
630
  async destroy(force = false) {
650
631
  if (this.#isDestroyed) {
@@ -681,11 +662,11 @@ var Disclosure = class _Disclosure {
681
662
  if (this.#isDestroyed) {
682
663
  return;
683
664
  }
684
- if (!(details instanceof HTMLDetailsElement) || !this.#bindings.has(details)) {
665
+ if (details instanceof HTMLDetailsElement && this.#bindings.has(details)) {
666
+ this.#toggle(details, true);
667
+ } else {
685
668
  console.warn("Invalid <details> element");
686
- return;
687
669
  }
688
- this.#toggle(details, true);
689
670
  }
690
671
  #initialize() {
691
672
  saveAttributes(this.#summaryElements, [
@@ -730,11 +711,10 @@ var Disclosure = class _Disclosure {
730
711
  return;
731
712
  }
732
713
  const binding = this.#bindings.get(summary);
733
- if (!binding) {
734
- return;
714
+ if (binding) {
715
+ const { details } = binding;
716
+ this.#toggle(details, !details.hasAttribute("data-disclosure-open"));
735
717
  }
736
- const { details } = binding;
737
- this.#toggle(details, !details.hasAttribute("data-disclosure-open"));
738
718
  };
739
719
  #toggle(details, isOpen) {
740
720
  if (details.hasAttribute("data-disclosure-open") === isOpen) {
@@ -783,11 +763,10 @@ var Disclosure = class _Disclosure {
783
763
  animation.addEventListener(
784
764
  "finish",
785
765
  () => {
786
- if (binding?.animation !== animation) {
787
- return;
766
+ if (binding?.animation === animation) {
767
+ this.#onAnimationFinish(content);
768
+ cleanup();
788
769
  }
789
- this.#onAnimationFinish(content);
790
- cleanup();
791
770
  },
792
771
  { once: true, signal }
793
772
  );
@@ -833,17 +812,18 @@ function isFocusable2(element) {
833
812
  function waitAnimationFinish(animation) {
834
813
  if (["idle", "finished"].includes(animation.playState)) {
835
814
  return Promise.resolve();
815
+ } else {
816
+ return new Promise(
817
+ (resolve) => animation.addEventListener("finish", () => resolve(), { once: true })
818
+ );
836
819
  }
837
- return new Promise(
838
- (resolve) => animation.addEventListener("finish", () => resolve(), { once: true })
839
- );
840
820
  }
841
821
  /**
842
822
  * Disclosure
843
823
  * WAI-ARIA compliant disclosure pattern implementation in TypeScript.
844
824
  * Using the <details> and <summary> element.
845
825
  *
846
- * @version 1.3.10
826
+ * @version 1.3.12
847
827
  * @author Yusuke Kamiyamane
848
828
  * @license MIT
849
829
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -855,7 +835,7 @@ function waitAnimationFinish(animation) {
855
835
  (**
856
836
  * Attributes Utils
857
837
  *
858
- * @version 1.1.1
838
+ * @version 1.1.2
859
839
  * @author Yusuke Kamiyamane
860
840
  * @license MIT
861
841
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -868,7 +848,7 @@ function waitAnimationFinish(animation) {
868
848
  * Lightweight roving tabindex utility with fully focus management.
869
849
  * Designed for accessible menus, tabs, toolbars, and composite widgets.
870
850
  *
871
- * @version 3.0.0
851
+ * @version 3.0.4
872
852
  * @author Yusuke Kamiyamane
873
853
  * @license MIT
874
854
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -880,7 +860,7 @@ function waitAnimationFinish(animation) {
880
860
  (**
881
861
  * Attributes Utils
882
862
  *
883
- * @version 1.1.1
863
+ * @version 1.1.2
884
864
  * @author Yusuke Kamiyamane
885
865
  * @license MIT
886
866
  * @copyright Copyright (c) Yusuke Kamiyamane
@@ -893,7 +873,7 @@ function waitAnimationFinish(animation) {
893
873
  * High-precision focus management utility with full composed tree support.
894
874
  * Handles complex focus rules including tabindex ordering, radio groups, inert.
895
875
  *
896
- * @version 4.3.2
876
+ * @version 4.3.3
897
877
  * @author Yusuke Kamiyamane
898
878
  * @license MIT
899
879
  * @copyright Copyright (c) Yusuke Kamiyamane
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@y14e/disclosure",
3
- "version": "1.3.10",
3
+ "version": "1.3.12",
4
4
  "description": "WAI-ARIA compliant disclosure pattern implementation in TypeScript",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -43,8 +43,8 @@
43
43
  },
44
44
  "homepage": "https://github.com/y14e/disclosure#readme",
45
45
  "devDependencies": {
46
- "@y14e/attributes-utils": "^1.1.1",
47
- "@y14e/roving-tabindex": "^3.0.0",
46
+ "@y14e/attributes-utils": "^1.1.2",
47
+ "@y14e/roving-tabindex": "^3.0.4",
48
48
  "bun-types": "latest",
49
49
  "tsup": "^8.0.0",
50
50
  "typescript": "^5.6.0",