@y14e/disclosure 2.1.4 → 2.2.0

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.
@@ -91,81 +91,105 @@ function resolveOptions(options) {
91
91
  }
92
92
 
93
93
  // node_modules/power-focusable/dist/index.js
94
+ function getComposedChildren(node) {
95
+ if (node instanceof ShadowRoot) {
96
+ return [...node.children];
97
+ }
98
+ if (!(node instanceof Element)) {
99
+ return [];
100
+ }
101
+ if (node instanceof HTMLSlotElement) {
102
+ const assigned = node.assignedElements({ flatten: true });
103
+ if (assigned.length) {
104
+ return assigned;
105
+ }
106
+ }
107
+ if (node instanceof HTMLElement && node.shadowRoot?.mode === "open") {
108
+ return [...node.shadowRoot.children];
109
+ }
110
+ return [...node.children];
111
+ }
94
112
  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
- var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX = FOCUSABLE_SELECTOR.replace(
96
- /(,\s*)?\[tabindex="-1"\]/g,
97
- ""
98
- );
99
- function getFocusables(container = document.body, options = {}) {
100
- if (!(container instanceof Element)) {
101
- console.warn("Invalid container element. Fallback: <body> element.");
102
- container = document.body;
113
+ var FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX = FOCUSABLE_SELECTOR.replace(/(,\s*)?\[tabindex="-1"\]/g, "");
114
+ function focusElement(element) {
115
+ "focus" in element && typeof element.focus === "function" && element.focus();
116
+ }
117
+ function getActiveElement() {
118
+ let current = document.activeElement;
119
+ while (current?.shadowRoot?.activeElement) {
120
+ current = current.shadowRoot.activeElement;
103
121
  }
104
- const {
105
- composed,
122
+ return current;
123
+ }
124
+ function getTabIndex(element) {
125
+ return "tabIndex" in element ? Number(element.tabIndex) : 0;
126
+ }
127
+ function isDisabled(element) {
128
+ return "disabled" in element && !!element.disabled;
129
+ }
130
+ function isFormControl(element) {
131
+ return ["BUTTON", "INPUT", "SELECT", "TEXTAREA"].includes(element.tagName);
132
+ }
133
+ function isInert(element) {
134
+ return "inert" in element && !!element.inert;
135
+ }
136
+ function isUngroupedRadio(element) {
137
+ return element.type === "radio" && !!element.name;
138
+ }
139
+ function resolveOptions2(options) {
140
+ let {
141
+ anchor = getActiveElement(),
142
+ composed = false,
106
143
  filter,
107
144
  include,
108
- skipNegativeTabIndexCheck,
109
- skipVisibilityCheck
110
- } = resolveOptions2(options);
111
- const candidates = [];
112
- if (!composed && !include) {
113
- for (const match of container.querySelectorAll(
114
- !skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR : FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX
115
- )) {
116
- match && isFocusable(match, {
117
- skipNegativeTabIndexCheck,
118
- skipVisibilityCheck
119
- }) && candidates.push(match);
145
+ skipNegativeTabIndexCheck = false,
146
+ skipVisibilityCheck = false,
147
+ wrap = false
148
+ } = options;
149
+ if (!(anchor instanceof Element)) {
150
+ const active = getActiveElement();
151
+ if (active instanceof Element) {
152
+ console.warn("Invalid anchor element. Fallback: active element.");
153
+ anchor = active;
120
154
  }
121
- } else {
122
- let traverse2 = function(node) {
123
- if (isFocusable(node, {
124
- skipNegativeTabIndexCheck,
125
- skipVisibilityCheck
126
- }) || include?.(node)) {
127
- candidates.push(node);
128
- }
129
- (!composed ? [...node.children] : getComposedChildren(node)).map(
130
- traverse2
131
- );
132
- };
133
- (!composed ? [...container.children] : getComposedChildren(container)).map(
134
- traverse2
135
- );
136
155
  }
137
- return normalizeRadioGroup(
138
- sortByTabIndex(!filter ? candidates : candidates.filter(filter))
139
- );
140
- }
141
- function isFocusable(element, options = {}) {
142
- if (!(element instanceof Element)) {
143
- console.warn("Invalid element");
144
- return false;
156
+ if (typeof composed !== "boolean") {
157
+ console.warn("Invalid composed option. Fallback: false.");
158
+ composed = false;
145
159
  }
146
- const { skipNegativeTabIndexCheck, skipVisibilityCheck } = resolveOptions2(options);
147
- if (element.hasAttribute("hidden") || isInert(element)) {
148
- return false;
160
+ if (filter !== void 0 && typeof filter !== "function") {
161
+ console.warn(
162
+ "Invalid filter function. Fallback: no filter function (undefined)."
163
+ );
164
+ filter = void 0;
149
165
  }
150
- if (!skipNegativeTabIndexCheck && getTabIndex(element) < 0) {
151
- return false;
166
+ if (include !== void 0 && typeof include !== "function") {
167
+ console.warn(
168
+ "Invalid include function. Fallback: no include function (undefined)."
169
+ );
170
+ include = void 0;
152
171
  }
153
- if (!element.matches(
154
- !skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR : FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX
155
- )) {
156
- return false;
172
+ if (typeof skipNegativeTabIndexCheck !== "boolean") {
173
+ console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
174
+ skipNegativeTabIndexCheck = false;
157
175
  }
158
- if (isDisabledDeep(element)) {
159
- return false;
176
+ if (typeof skipVisibilityCheck !== "boolean") {
177
+ console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
178
+ skipVisibilityCheck = false;
160
179
  }
161
- if (!skipVisibilityCheck && !element.checkVisibility({
162
- contentVisibilityAuto: true,
163
- opacityProperty: true,
164
- visibilityProperty: true
165
- })) {
166
- return false;
180
+ if (typeof wrap !== "boolean") {
181
+ console.warn("Invalid wrap option. Fallback: false.");
182
+ wrap = false;
167
183
  }
168
- return true;
184
+ return {
185
+ anchor,
186
+ composed,
187
+ filter,
188
+ include,
189
+ skipNegativeTabIndexCheck,
190
+ skipVisibilityCheck,
191
+ wrap
192
+ };
169
193
  }
170
194
  function isDisabledDeep(element) {
171
195
  let current = element;
@@ -247,107 +271,135 @@ function sortByTabIndex(elements) {
247
271
  }
248
272
  return ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b)).concat(natural);
249
273
  }
250
- function getComposedChildren(node) {
251
- if (node instanceof ShadowRoot) {
252
- return [...node.children];
253
- }
254
- if (!(node instanceof Element)) {
255
- return [];
274
+ function getFocusables(container = document.body, options = {}) {
275
+ if (!(container instanceof Element)) {
276
+ console.warn("Invalid container element. Fallback: <body> element.");
277
+ container = document.body;
256
278
  }
257
- if (node instanceof HTMLSlotElement) {
258
- const assigned = node.assignedElements({ flatten: true });
259
- if (assigned.length) {
260
- return assigned;
279
+ const {
280
+ composed,
281
+ filter,
282
+ include,
283
+ skipNegativeTabIndexCheck,
284
+ skipVisibilityCheck
285
+ } = resolveOptions2(options);
286
+ const candidates = [];
287
+ if (!composed && !include) {
288
+ for (const match of container.querySelectorAll(
289
+ !skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR : FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX
290
+ )) {
291
+ match && isFocusable(match, {
292
+ skipNegativeTabIndexCheck,
293
+ skipVisibilityCheck
294
+ }) && candidates.push(match);
261
295
  }
296
+ } else {
297
+ let traverse2 = function(node) {
298
+ if (isFocusable(node, {
299
+ skipNegativeTabIndexCheck,
300
+ skipVisibilityCheck
301
+ }) || include?.(node)) {
302
+ candidates.push(node);
303
+ }
304
+ (!composed ? [...node.children] : getComposedChildren(node)).map(
305
+ traverse2
306
+ );
307
+ };
308
+ (!composed ? [...container.children] : getComposedChildren(container)).map(
309
+ traverse2
310
+ );
262
311
  }
263
- if (node instanceof HTMLElement && node.shadowRoot?.mode === "open") {
264
- return [...node.shadowRoot.children];
265
- }
266
- return [...node.children];
267
- }
268
- function focusElement(element) {
269
- "focus" in element && typeof element.focus === "function" && element.focus();
312
+ return normalizeRadioGroup(
313
+ sortByTabIndex(!filter ? candidates : candidates.filter(filter))
314
+ );
270
315
  }
271
- function getActiveElement() {
272
- let current = document.activeElement;
273
- while (current?.shadowRoot?.activeElement) {
274
- current = current.shadowRoot.activeElement;
316
+ function isFocusable(element, options = {}) {
317
+ if (!(element instanceof Element)) {
318
+ console.warn("Invalid element");
319
+ return false;
275
320
  }
276
- return current;
277
- }
278
- function getTabIndex(element) {
279
- return "tabIndex" in element ? Number(element.tabIndex) : 0;
280
- }
281
- function isDisabled(element) {
282
- return "disabled" in element && !!element.disabled;
283
- }
284
- function isFormControl(element) {
285
- return ["BUTTON", "INPUT", "SELECT", "TEXTAREA"].includes(element.tagName);
286
- }
287
- function isInert(element) {
288
- return "inert" in element && !!element.inert;
289
- }
290
- function isUngroupedRadio(element) {
291
- return element.type === "radio" && !!element.name;
321
+ const { skipNegativeTabIndexCheck, skipVisibilityCheck } = resolveOptions2(options);
322
+ if (element.hasAttribute("hidden") || isInert(element)) {
323
+ return false;
324
+ }
325
+ if (!skipNegativeTabIndexCheck && getTabIndex(element) < 0) {
326
+ return false;
327
+ }
328
+ if (!element.matches(
329
+ !skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR : FOCUSABLE_SELECTOR_WITH_NEGATIVE_TABINDEX
330
+ )) {
331
+ return false;
332
+ }
333
+ if (isDisabledDeep(element)) {
334
+ return false;
335
+ }
336
+ if (!skipVisibilityCheck && !element.checkVisibility({
337
+ contentVisibilityAuto: true,
338
+ opacityProperty: true,
339
+ visibilityProperty: true
340
+ })) {
341
+ return false;
342
+ }
343
+ return true;
292
344
  }
293
- function resolveOptions2(options) {
345
+
346
+ // node_modules/@y14e/roving-tabindex/dist/index.js
347
+ var DIRECTIONS = ["both", "grid", "horizontal", "vertical"];
348
+ function resolveOptions3(options) {
294
349
  let {
295
- anchor = getActiveElement(),
296
- composed = false,
297
- filter,
298
- include,
299
- skipNegativeTabIndexCheck = false,
300
- skipVisibilityCheck = false,
350
+ direction = "both",
351
+ navigationOnly = false,
352
+ noMemory = false,
353
+ noStart = false,
354
+ selector = "",
355
+ typeahead = false,
301
356
  wrap = false
302
357
  } = options;
303
- if (!(anchor instanceof Element)) {
304
- const active = getActiveElement();
305
- if (active instanceof Element) {
306
- console.warn("Invalid anchor element. Fallback: active element.");
307
- anchor = active;
308
- }
358
+ if (typeof direction === "string") {
359
+ direction = direction.toLowerCase();
309
360
  }
310
- if (typeof composed !== "boolean") {
311
- console.warn("Invalid composed option. Fallback: false.");
312
- composed = false;
361
+ if (!DIRECTIONS.includes(direction)) {
362
+ console.warn("Invalid direction option. Fallback: 'both'.");
363
+ direction = "both";
313
364
  }
314
- if (filter !== void 0 && typeof filter !== "function") {
315
- console.warn(
316
- "Invalid filter function. Fallback: no filter function (undefined)."
317
- );
318
- filter = void 0;
365
+ if (typeof navigationOnly !== "boolean") {
366
+ console.warn("Invalid navigationOnly option. Fallback: false.");
367
+ navigationOnly = false;
319
368
  }
320
- if (include !== void 0 && typeof include !== "function") {
321
- console.warn(
322
- "Invalid include function. Fallback: no include function (undefined)."
323
- );
324
- include = void 0;
369
+ if (typeof noMemory !== "boolean") {
370
+ console.warn("Invalid noMemory option. Fallback: false.");
371
+ noMemory = false;
325
372
  }
326
- if (typeof skipNegativeTabIndexCheck !== "boolean") {
327
- console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
328
- skipNegativeTabIndexCheck = false;
373
+ if (typeof noStart !== "boolean") {
374
+ console.warn("Invalid noStart option. Fallback: false.");
375
+ noStart = false;
329
376
  }
330
- if (typeof skipVisibilityCheck !== "boolean") {
331
- console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
332
- skipVisibilityCheck = false;
377
+ if (selector !== "") {
378
+ try {
379
+ document.querySelector(selector);
380
+ } catch {
381
+ console.warn("Invalid selector. Fallback: no selector string.");
382
+ selector = "";
383
+ }
384
+ }
385
+ if (typeof typeahead !== "boolean") {
386
+ console.warn("Invalid typeahead option. Fallback: false.");
387
+ typeahead = false;
333
388
  }
334
389
  if (typeof wrap !== "boolean") {
335
390
  console.warn("Invalid wrap option. Fallback: false.");
336
391
  wrap = false;
337
392
  }
338
393
  return {
339
- anchor,
340
- composed,
341
- filter,
342
- include,
343
- skipNegativeTabIndexCheck,
344
- skipVisibilityCheck,
394
+ direction,
395
+ navigationOnly,
396
+ noMemory,
397
+ noStart,
398
+ selector,
399
+ typeahead,
345
400
  wrap
346
401
  };
347
402
  }
348
-
349
- // node_modules/@y14e/roving-tabindex/dist/index.js
350
- var DIRECTIONS = ["both", "grid", "horizontal", "vertical"];
351
403
  function createRovingTabIndex(container, options = {}) {
352
404
  if (!(container instanceof Element)) {
353
405
  console.warn("Invalid container element");
@@ -368,7 +420,7 @@ var RovingTabIndex = class _RovingTabIndex {
368
420
  #isDestroyed = false;
369
421
  constructor(container, options = {}) {
370
422
  this.#container = container;
371
- this.#settings = this.#resolveOptions(options);
423
+ this.#settings = resolveOptions3(options);
372
424
  this.#selectorFilter = this.#createSelectorFilter();
373
425
  this.#initialize();
374
426
  }
@@ -616,74 +668,54 @@ var RovingTabIndex = class _RovingTabIndex {
616
668
  }
617
669
  return result;
618
670
  }
619
- #resolveOptions(options) {
620
- let {
621
- direction = "both",
622
- navigationOnly = false,
623
- noMemory = false,
624
- noStart = false,
625
- selector = "",
626
- typeahead = false,
627
- wrap = false
628
- } = options;
629
- if (typeof direction === "string") {
630
- direction = direction.toLowerCase();
631
- }
632
- if (!DIRECTIONS.includes(direction)) {
633
- console.warn("Invalid direction option. Fallback: 'both'.");
634
- direction = "both";
635
- }
636
- if (typeof navigationOnly !== "boolean") {
637
- console.warn("Invalid navigationOnly option. Fallback: false.");
638
- navigationOnly = false;
639
- }
640
- if (typeof noMemory !== "boolean") {
641
- console.warn("Invalid noMemory option. Fallback: false.");
642
- noMemory = false;
643
- }
644
- if (typeof noStart !== "boolean") {
645
- console.warn("Invalid noStart option. Fallback: false.");
646
- noStart = false;
647
- }
648
- if (selector !== "") {
649
- try {
650
- document.querySelector(selector);
651
- } catch {
652
- console.warn("Invalid selector. Fallback: no selector string.");
653
- selector = "";
654
- }
655
- }
656
- if (typeof typeahead !== "boolean") {
657
- console.warn("Invalid typeahead option. Fallback: false.");
658
- typeahead = false;
659
- }
660
- if (typeof wrap !== "boolean") {
661
- console.warn("Invalid wrap option. Fallback: false.");
662
- wrap = false;
663
- }
664
- return {
665
- direction,
666
- navigationOnly,
667
- noMemory,
668
- noStart,
669
- selector,
670
- typeahead,
671
- wrap
672
- };
673
- }
674
671
  };
675
672
 
673
+ // src/defaults.ts
674
+ var defaults = {
675
+ animation: {
676
+ duration: 300,
677
+ easing: "ease"
678
+ },
679
+ collapsible: true
680
+ };
681
+
682
+ // src/options.ts
683
+ function resolveOptions4(defaults2, source) {
684
+ const merged = {
685
+ ...defaults2,
686
+ ...source,
687
+ animation: { ...defaults2.animation, ...source.animation ?? {} }
688
+ };
689
+ const mergedAnimation = merged.animation;
690
+ const duration = mergedAnimation.duration;
691
+ const defaultAnimation = defaults2.animation;
692
+ if (typeof duration !== "number" || Number.isNaN(duration)) {
693
+ const duration2 = defaultAnimation.duration;
694
+ console.warn(`Invalid animation duration. Fallback: ${duration2} (ms).`);
695
+ mergedAnimation.duration = duration2;
696
+ }
697
+ if (duration < 0) {
698
+ console.warn("Invalid animation duration. Fallback: 0 (ms).");
699
+ mergedAnimation.duration = 0;
700
+ }
701
+ if (!CSS.supports("animation-timing-function", mergedAnimation.easing)) {
702
+ const easing = defaultAnimation.easing;
703
+ console.warn(`Invalid animation easing. Fallback: '${easing}'.`);
704
+ mergedAnimation.easing = easing;
705
+ }
706
+ if (typeof merged.collapsible !== "boolean") {
707
+ const collapsible = defaults2.collapsible;
708
+ console.warn(`Invalid collapsible option. Fallback: ${collapsible}.`);
709
+ merged.collapsible = collapsible;
710
+ }
711
+ return merged;
712
+ }
713
+
676
714
  // src/index.ts
677
715
  var Disclosure = class _Disclosure {
678
716
  static defaults = {};
679
717
  #rootElement;
680
- #defaults = {
681
- animation: {
682
- duration: 300,
683
- easing: "ease"
684
- },
685
- collapsible: true
686
- };
718
+ #defaults = defaults;
687
719
  #settings;
688
720
  #detailsElements;
689
721
  #summaryElements;
@@ -703,8 +735,8 @@ var Disclosure = class _Disclosure {
703
735
  return;
704
736
  }
705
737
  this.#rootElement = root;
706
- this.#defaults = this.#resolveOptions(this.#defaults, _Disclosure.defaults);
707
- this.#settings = this.#resolveOptions(this.#defaults, options);
738
+ this.#defaults = resolveOptions4(this.#defaults, _Disclosure.defaults);
739
+ this.#settings = resolveOptions4(this.#defaults, options);
708
740
  matchMedia("(prefers-reduced-motion: reduce)").matches && Object.assign(this.#settings.animation, { duration: 0 });
709
741
  const NOT_NESTED = ":not(:scope summary + * *)";
710
742
  this.#detailsElements = [
@@ -927,37 +959,6 @@ var Disclosure = class _Disclosure {
927
959
  #isFocusable(element) {
928
960
  return element.tabIndex >= 0;
929
961
  }
930
- #resolveOptions(target, source) {
931
- const merged = {
932
- ...target,
933
- ...source,
934
- animation: { ...target.animation, ...source.animation ?? {} }
935
- };
936
- const mergedAnimation = merged.animation;
937
- const duration = mergedAnimation.duration;
938
- const defaults = this.#defaults;
939
- const defaultAnimation = defaults.animation;
940
- if (typeof duration !== "number" || Number.isNaN(duration)) {
941
- const duration2 = defaultAnimation.duration;
942
- console.warn(`Invalid animation duration. Fallback: ${duration2} (ms).`);
943
- mergedAnimation.duration = duration2;
944
- }
945
- if (duration < 0) {
946
- console.warn("Invalid animation duration. Fallback: 0 (ms).");
947
- mergedAnimation.duration = 0;
948
- }
949
- if (!CSS.supports("animation-timing-function", mergedAnimation.easing)) {
950
- const easing = defaultAnimation.easing;
951
- console.warn(`Invalid animation easing. Fallback: '${easing}'.`);
952
- mergedAnimation.easing = easing;
953
- }
954
- if (typeof merged.collapsible !== "boolean") {
955
- const collapsible = defaults.collapsible;
956
- console.warn(`Invalid collapsible option. Fallback: ${collapsible}.`);
957
- merged.collapsible = collapsible;
958
- }
959
- return merged;
960
- }
961
962
  async #waitAnimationsFinish() {
962
963
  const promises = [];
963
964
  for (const content of this.#contentElements) {