@y14e/accordion 2.1.2 → 2.1.3
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 +3 -3
- package/dist/index.bundle.cjs +126 -57
- package/dist/index.bundle.js +126 -57
- package/dist/index.cjs +18 -15
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +18 -15
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -13,11 +13,11 @@ npm i @y14e/accordion
|
|
|
13
13
|
import { Accordion } from '@y14e/accordion';
|
|
14
14
|
|
|
15
15
|
// CDNs
|
|
16
|
-
import { Accordion } from 'https://esm.sh/@y14e/accordion@2.1.
|
|
16
|
+
import { Accordion } from 'https://esm.sh/@y14e/accordion@2.1.3';
|
|
17
17
|
// or
|
|
18
|
-
import { Accordion } from 'https://cdn.jsdelivr.net/npm/@y14e/accordion@2.1.
|
|
18
|
+
import { Accordion } from 'https://cdn.jsdelivr.net/npm/@y14e/accordion@2.1.3/+esm';
|
|
19
19
|
// or
|
|
20
|
-
import { Accordion } from 'https://esm.unpkg.com/@y14e/accordion@2.1.
|
|
20
|
+
import { Accordion } from 'https://esm.unpkg.com/@y14e/accordion@2.1.3';
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## Usage
|
package/dist/index.bundle.cjs
CHANGED
|
@@ -207,31 +207,25 @@ function normalizeRadioGroup(elements) {
|
|
|
207
207
|
map = /* @__PURE__ */ new Map();
|
|
208
208
|
}
|
|
209
209
|
const root = element.getRootNode();
|
|
210
|
-
|
|
210
|
+
const groups = map.get(root) ?? map.set(root, /* @__PURE__ */ new Map()).get(root);
|
|
211
211
|
if (!groups) {
|
|
212
|
-
|
|
213
|
-
map.set(root, groups);
|
|
214
|
-
}
|
|
215
|
-
let group = groups.get(element.form);
|
|
216
|
-
if (!group) {
|
|
217
|
-
group = /* @__PURE__ */ new Map();
|
|
218
|
-
groups.set(element.form, group);
|
|
212
|
+
continue;
|
|
219
213
|
}
|
|
220
|
-
|
|
214
|
+
const { form, name } = element;
|
|
215
|
+
const radios = groups.get(form) ?? groups.set(form, /* @__PURE__ */ new Map()).get(form);
|
|
221
216
|
if (!radios) {
|
|
222
|
-
|
|
223
|
-
group.set(element.name, radios);
|
|
217
|
+
continue;
|
|
224
218
|
}
|
|
225
|
-
radios.push(element);
|
|
219
|
+
(radios.get(name) ?? radios.set(name, []).get(name))?.push(element);
|
|
226
220
|
}
|
|
227
221
|
if (!map) {
|
|
228
222
|
return elements;
|
|
229
223
|
}
|
|
230
224
|
const placeholder = /* @__PURE__ */ new Set();
|
|
231
|
-
for (const
|
|
232
|
-
for (const
|
|
233
|
-
for (const
|
|
234
|
-
const radio =
|
|
225
|
+
for (const v of map.values()) {
|
|
226
|
+
for (const w of v.values()) {
|
|
227
|
+
for (const x of w.values()) {
|
|
228
|
+
const radio = x.find((r) => r.checked) ?? x[0];
|
|
235
229
|
radio && placeholder.add(radio);
|
|
236
230
|
}
|
|
237
231
|
}
|
|
@@ -407,8 +401,8 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
407
401
|
return () => {
|
|
408
402
|
};
|
|
409
403
|
}
|
|
410
|
-
const
|
|
411
|
-
return () =>
|
|
404
|
+
const rovingTabIndex = new RovingTabIndex(container, options);
|
|
405
|
+
return () => rovingTabIndex.destroy();
|
|
412
406
|
}
|
|
413
407
|
var RovingTabIndex = class _RovingTabIndex {
|
|
414
408
|
static #initialized = /* @__PURE__ */ new Set();
|
|
@@ -467,18 +461,19 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
467
461
|
if (!(event instanceof KeyboardEvent)) {
|
|
468
462
|
return;
|
|
469
463
|
}
|
|
464
|
+
const { direction, typeahead, wrap = false } = this.#settings;
|
|
465
|
+
const isGrid = direction === "grid";
|
|
470
466
|
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
471
|
-
if (
|
|
467
|
+
if (!(isGrid && ["End", "Home"].includes(key)) && ctrlKey || altKey || metaKey || shiftKey) {
|
|
472
468
|
return;
|
|
473
469
|
}
|
|
474
|
-
const { direction, typeahead, wrap } = this.#settings;
|
|
475
470
|
const isBoth = direction === "both";
|
|
476
471
|
const isHorizontal = direction === "horizontal";
|
|
477
472
|
if (![
|
|
478
473
|
"End",
|
|
479
474
|
"Home",
|
|
480
|
-
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
481
|
-
...isBoth ? ["ArrowRight", "ArrowDown"] : [`Arrow${isHorizontal ? "Right" : "Down"}`]
|
|
475
|
+
...isGrid || isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
476
|
+
...isGrid || isBoth ? ["ArrowRight", "ArrowDown"] : [`Arrow${isHorizontal ? "Right" : "Down"}`]
|
|
482
477
|
].includes(key)) {
|
|
483
478
|
if (!typeahead || !/^\S$/i.test(key) || !this.#focusablesByFirstChar.has(key.toUpperCase())) {
|
|
484
479
|
return;
|
|
@@ -497,39 +492,48 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
497
492
|
event.preventDefault();
|
|
498
493
|
let newIndex;
|
|
499
494
|
const activeIndex = candidates.indexOf(active);
|
|
500
|
-
let
|
|
495
|
+
let target = candidates;
|
|
501
496
|
switch (key) {
|
|
502
497
|
case "End":
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
newIndex = wrap ? rawIndex : Math.max(rawIndex, 0);
|
|
498
|
+
case "Home": {
|
|
499
|
+
const rawIndex = key === "End" ? -1 : 0;
|
|
500
|
+
if (isGrid && !ctrlKey) {
|
|
501
|
+
const cell = this.#getCellsOfActiveRow().at(rawIndex);
|
|
502
|
+
newIndex = cell ? candidates.indexOf(cell) : activeIndex;
|
|
503
|
+
} else {
|
|
504
|
+
newIndex = rawIndex;
|
|
505
|
+
}
|
|
512
506
|
break;
|
|
513
507
|
}
|
|
508
|
+
case "ArrowLeft":
|
|
509
|
+
case "ArrowUp":
|
|
514
510
|
case "ArrowRight":
|
|
515
511
|
case "ArrowDown": {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
512
|
+
if (["ArrowUp", "ArrowDown"].includes(key) && isGrid) {
|
|
513
|
+
const cell = this.#getNextCell(key, wrap);
|
|
514
|
+
newIndex = cell ? candidates.indexOf(cell) : activeIndex;
|
|
515
|
+
} else {
|
|
516
|
+
if (isGrid) {
|
|
517
|
+
target = this.#getCellsOfActiveRow();
|
|
518
|
+
}
|
|
519
|
+
const isPrevious = ["ArrowLeft", "ArrowUp"].includes(key);
|
|
520
|
+
const rawIndex = (isGrid ? target.indexOf(active) : activeIndex) + (isPrevious ? -1 : 1);
|
|
521
|
+
newIndex = isPrevious ? wrap ? rawIndex : Math.max(rawIndex, 0) : wrap ? rawIndex % target.length : Math.min(rawIndex, target.length - 1);
|
|
522
|
+
}
|
|
519
523
|
break;
|
|
520
524
|
}
|
|
521
525
|
default: {
|
|
522
526
|
const focusablesByFirstChar = new Set(
|
|
523
527
|
this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
|
|
524
528
|
);
|
|
525
|
-
|
|
526
|
-
const afterIndex =
|
|
529
|
+
target = candidates.filter((c) => focusablesByFirstChar.has(c));
|
|
530
|
+
const afterIndex = target.findIndex(
|
|
527
531
|
(f) => candidates.indexOf(f) > activeIndex
|
|
528
532
|
);
|
|
529
533
|
newIndex = afterIndex >= 0 ? afterIndex : 0;
|
|
530
534
|
}
|
|
531
535
|
}
|
|
532
|
-
const focusable =
|
|
536
|
+
const focusable = target.at(newIndex);
|
|
533
537
|
focusable && focusElement(focusable);
|
|
534
538
|
};
|
|
535
539
|
#update(active) {
|
|
@@ -599,6 +603,24 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
599
603
|
const { selector } = this.#settings;
|
|
600
604
|
return (element) => !selector || [...this.#container.querySelectorAll(selector)].includes(element);
|
|
601
605
|
}
|
|
606
|
+
#getCellCoords(cell) {
|
|
607
|
+
const { height, left, top, width } = cell.getBoundingClientRect();
|
|
608
|
+
return {
|
|
609
|
+
x: left + width / 2,
|
|
610
|
+
y: top + height / 2
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
#getCellsOfActiveRow() {
|
|
614
|
+
const active = getActiveElement();
|
|
615
|
+
if (!(active instanceof Element)) {
|
|
616
|
+
return [];
|
|
617
|
+
}
|
|
618
|
+
const activeRect = active.getBoundingClientRect();
|
|
619
|
+
return this.#getFocusables().filter((cell) => {
|
|
620
|
+
const cellRect = cell.getBoundingClientRect();
|
|
621
|
+
return cellRect.top < activeRect.bottom && cellRect.bottom > activeRect.top;
|
|
622
|
+
});
|
|
623
|
+
}
|
|
602
624
|
#getFocusables() {
|
|
603
625
|
return getFocusables(this.#container, {
|
|
604
626
|
composed: true,
|
|
@@ -607,6 +629,50 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
607
629
|
skipVisibilityCheck: true
|
|
608
630
|
});
|
|
609
631
|
}
|
|
632
|
+
#getNextCell(key, wrap) {
|
|
633
|
+
const cells = this.#getFocusables();
|
|
634
|
+
const active = getActiveElement();
|
|
635
|
+
if (!(active instanceof Element)) {
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
const activeCoords = this.#getCellCoords(active);
|
|
639
|
+
let min = Infinity;
|
|
640
|
+
let result = null;
|
|
641
|
+
for (const cell of cells) {
|
|
642
|
+
if (cell === active) {
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
645
|
+
const cellCoords = this.#getCellCoords(cell);
|
|
646
|
+
const distances = {
|
|
647
|
+
x: Math.abs(cellCoords.x - activeCoords.x),
|
|
648
|
+
y: Math.abs(cellCoords.y - activeCoords.y)
|
|
649
|
+
};
|
|
650
|
+
if (key === "ArrowUp" && cellCoords.y < activeCoords.y && distances.x < distances.y || key === "ArrowDown" && cellCoords.y > activeCoords.y && distances.x < distances.y) {
|
|
651
|
+
const distance = distances.x ** 2 + distances.y ** 2;
|
|
652
|
+
if (distance < min) {
|
|
653
|
+
min = distance;
|
|
654
|
+
result = cell;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
if (!result && wrap) {
|
|
659
|
+
let max = -Infinity;
|
|
660
|
+
for (const cell of cells) {
|
|
661
|
+
if (cell === active) {
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
const cellCoords = this.#getCellCoords(cell);
|
|
665
|
+
if (Math.abs(cellCoords.x - activeCoords.x) < cell.getBoundingClientRect().width / 2) {
|
|
666
|
+
const distance = key === "ArrowUp" ? cellCoords.y - activeCoords.y : activeCoords.y - cellCoords.y;
|
|
667
|
+
if (distance > max) {
|
|
668
|
+
max = distance;
|
|
669
|
+
result = cell;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
return result;
|
|
675
|
+
}
|
|
610
676
|
#resolveOptions(options) {
|
|
611
677
|
let {
|
|
612
678
|
direction = "both",
|
|
@@ -618,7 +684,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
618
684
|
wrap = false
|
|
619
685
|
} = options;
|
|
620
686
|
direction = direction.toLowerCase();
|
|
621
|
-
if (!["both", "horizontal", "vertical"].includes(direction)) {
|
|
687
|
+
if (!["both", "grid", "horizontal", "vertical"].includes(direction)) {
|
|
622
688
|
console.warn("Invalid direction option. Fallback: 'both'.");
|
|
623
689
|
direction = "both";
|
|
624
690
|
}
|
|
@@ -943,21 +1009,24 @@ var Accordion = class _Accordion {
|
|
|
943
1009
|
console.warn(`Invalid collapsible option. Fallback: ${collapsible}.`);
|
|
944
1010
|
merged.collapsible = collapsible;
|
|
945
1011
|
}
|
|
946
|
-
const
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
}
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1012
|
+
const selector = merged.selector;
|
|
1013
|
+
function resolveSelector(name, target2, source2) {
|
|
1014
|
+
try {
|
|
1015
|
+
document.querySelector(source2);
|
|
1016
|
+
return source2;
|
|
1017
|
+
} catch {
|
|
1018
|
+
console.warn(
|
|
1019
|
+
`Invalid ${name.replace(/[A-Z]/g, (c) => ` ${c.toLowerCase()}`)} selector. Fallback: '${target2}'.`
|
|
1020
|
+
);
|
|
1021
|
+
return target2;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
for (const name of ["content", "trigger"]) {
|
|
1025
|
+
selector[name] = resolveSelector(
|
|
1026
|
+
name,
|
|
1027
|
+
defaults.selector[name],
|
|
1028
|
+
selector[name]
|
|
1029
|
+
);
|
|
961
1030
|
}
|
|
962
1031
|
return merged;
|
|
963
1032
|
}
|
|
@@ -979,7 +1048,7 @@ function waitAnimationFinish(animation) {
|
|
|
979
1048
|
* Accordion
|
|
980
1049
|
* WAI-ARIA compliant accordion pattern implementation in TypeScript.
|
|
981
1050
|
*
|
|
982
|
-
* @version 2.1.
|
|
1051
|
+
* @version 2.1.3
|
|
983
1052
|
* @author Yusuke Kamiyamane
|
|
984
1053
|
* @license MIT
|
|
985
1054
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1004,7 +1073,7 @@ power-focusable/dist/index.js:
|
|
|
1004
1073
|
* High-precision focus management utility with full composed tree support.
|
|
1005
1074
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
1006
1075
|
*
|
|
1007
|
-
* @version 4.
|
|
1076
|
+
* @version 4.4.2
|
|
1008
1077
|
* @author Yusuke Kamiyamane
|
|
1009
1078
|
* @license MIT
|
|
1010
1079
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1028,7 +1097,7 @@ power-focusable/dist/index.js:
|
|
|
1028
1097
|
* Lightweight roving tabindex utility with fully focus management.
|
|
1029
1098
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
1030
1099
|
*
|
|
1031
|
-
* @version 3.1
|
|
1100
|
+
* @version 3.3.1
|
|
1032
1101
|
* @author Yusuke Kamiyamane
|
|
1033
1102
|
* @license MIT
|
|
1034
1103
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.bundle.js
CHANGED
|
@@ -205,31 +205,25 @@ function normalizeRadioGroup(elements) {
|
|
|
205
205
|
map = /* @__PURE__ */ new Map();
|
|
206
206
|
}
|
|
207
207
|
const root = element.getRootNode();
|
|
208
|
-
|
|
208
|
+
const groups = map.get(root) ?? map.set(root, /* @__PURE__ */ new Map()).get(root);
|
|
209
209
|
if (!groups) {
|
|
210
|
-
|
|
211
|
-
map.set(root, groups);
|
|
212
|
-
}
|
|
213
|
-
let group = groups.get(element.form);
|
|
214
|
-
if (!group) {
|
|
215
|
-
group = /* @__PURE__ */ new Map();
|
|
216
|
-
groups.set(element.form, group);
|
|
210
|
+
continue;
|
|
217
211
|
}
|
|
218
|
-
|
|
212
|
+
const { form, name } = element;
|
|
213
|
+
const radios = groups.get(form) ?? groups.set(form, /* @__PURE__ */ new Map()).get(form);
|
|
219
214
|
if (!radios) {
|
|
220
|
-
|
|
221
|
-
group.set(element.name, radios);
|
|
215
|
+
continue;
|
|
222
216
|
}
|
|
223
|
-
radios.push(element);
|
|
217
|
+
(radios.get(name) ?? radios.set(name, []).get(name))?.push(element);
|
|
224
218
|
}
|
|
225
219
|
if (!map) {
|
|
226
220
|
return elements;
|
|
227
221
|
}
|
|
228
222
|
const placeholder = /* @__PURE__ */ new Set();
|
|
229
|
-
for (const
|
|
230
|
-
for (const
|
|
231
|
-
for (const
|
|
232
|
-
const radio =
|
|
223
|
+
for (const v of map.values()) {
|
|
224
|
+
for (const w of v.values()) {
|
|
225
|
+
for (const x of w.values()) {
|
|
226
|
+
const radio = x.find((r) => r.checked) ?? x[0];
|
|
233
227
|
radio && placeholder.add(radio);
|
|
234
228
|
}
|
|
235
229
|
}
|
|
@@ -405,8 +399,8 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
405
399
|
return () => {
|
|
406
400
|
};
|
|
407
401
|
}
|
|
408
|
-
const
|
|
409
|
-
return () =>
|
|
402
|
+
const rovingTabIndex = new RovingTabIndex(container, options);
|
|
403
|
+
return () => rovingTabIndex.destroy();
|
|
410
404
|
}
|
|
411
405
|
var RovingTabIndex = class _RovingTabIndex {
|
|
412
406
|
static #initialized = /* @__PURE__ */ new Set();
|
|
@@ -465,18 +459,19 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
465
459
|
if (!(event instanceof KeyboardEvent)) {
|
|
466
460
|
return;
|
|
467
461
|
}
|
|
462
|
+
const { direction, typeahead, wrap = false } = this.#settings;
|
|
463
|
+
const isGrid = direction === "grid";
|
|
468
464
|
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
469
|
-
if (
|
|
465
|
+
if (!(isGrid && ["End", "Home"].includes(key)) && ctrlKey || altKey || metaKey || shiftKey) {
|
|
470
466
|
return;
|
|
471
467
|
}
|
|
472
|
-
const { direction, typeahead, wrap } = this.#settings;
|
|
473
468
|
const isBoth = direction === "both";
|
|
474
469
|
const isHorizontal = direction === "horizontal";
|
|
475
470
|
if (![
|
|
476
471
|
"End",
|
|
477
472
|
"Home",
|
|
478
|
-
...isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
479
|
-
...isBoth ? ["ArrowRight", "ArrowDown"] : [`Arrow${isHorizontal ? "Right" : "Down"}`]
|
|
473
|
+
...isGrid || isBoth ? ["ArrowLeft", "ArrowUp"] : [`Arrow${isHorizontal ? "Left" : "Up"}`],
|
|
474
|
+
...isGrid || isBoth ? ["ArrowRight", "ArrowDown"] : [`Arrow${isHorizontal ? "Right" : "Down"}`]
|
|
480
475
|
].includes(key)) {
|
|
481
476
|
if (!typeahead || !/^\S$/i.test(key) || !this.#focusablesByFirstChar.has(key.toUpperCase())) {
|
|
482
477
|
return;
|
|
@@ -495,39 +490,48 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
495
490
|
event.preventDefault();
|
|
496
491
|
let newIndex;
|
|
497
492
|
const activeIndex = candidates.indexOf(active);
|
|
498
|
-
let
|
|
493
|
+
let target = candidates;
|
|
499
494
|
switch (key) {
|
|
500
495
|
case "End":
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
newIndex = wrap ? rawIndex : Math.max(rawIndex, 0);
|
|
496
|
+
case "Home": {
|
|
497
|
+
const rawIndex = key === "End" ? -1 : 0;
|
|
498
|
+
if (isGrid && !ctrlKey) {
|
|
499
|
+
const cell = this.#getCellsOfActiveRow().at(rawIndex);
|
|
500
|
+
newIndex = cell ? candidates.indexOf(cell) : activeIndex;
|
|
501
|
+
} else {
|
|
502
|
+
newIndex = rawIndex;
|
|
503
|
+
}
|
|
510
504
|
break;
|
|
511
505
|
}
|
|
506
|
+
case "ArrowLeft":
|
|
507
|
+
case "ArrowUp":
|
|
512
508
|
case "ArrowRight":
|
|
513
509
|
case "ArrowDown": {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
510
|
+
if (["ArrowUp", "ArrowDown"].includes(key) && isGrid) {
|
|
511
|
+
const cell = this.#getNextCell(key, wrap);
|
|
512
|
+
newIndex = cell ? candidates.indexOf(cell) : activeIndex;
|
|
513
|
+
} else {
|
|
514
|
+
if (isGrid) {
|
|
515
|
+
target = this.#getCellsOfActiveRow();
|
|
516
|
+
}
|
|
517
|
+
const isPrevious = ["ArrowLeft", "ArrowUp"].includes(key);
|
|
518
|
+
const rawIndex = (isGrid ? target.indexOf(active) : activeIndex) + (isPrevious ? -1 : 1);
|
|
519
|
+
newIndex = isPrevious ? wrap ? rawIndex : Math.max(rawIndex, 0) : wrap ? rawIndex % target.length : Math.min(rawIndex, target.length - 1);
|
|
520
|
+
}
|
|
517
521
|
break;
|
|
518
522
|
}
|
|
519
523
|
default: {
|
|
520
524
|
const focusablesByFirstChar = new Set(
|
|
521
525
|
this.#focusablesByFirstChar.get(key.toUpperCase()) ?? []
|
|
522
526
|
);
|
|
523
|
-
|
|
524
|
-
const afterIndex =
|
|
527
|
+
target = candidates.filter((c) => focusablesByFirstChar.has(c));
|
|
528
|
+
const afterIndex = target.findIndex(
|
|
525
529
|
(f) => candidates.indexOf(f) > activeIndex
|
|
526
530
|
);
|
|
527
531
|
newIndex = afterIndex >= 0 ? afterIndex : 0;
|
|
528
532
|
}
|
|
529
533
|
}
|
|
530
|
-
const focusable =
|
|
534
|
+
const focusable = target.at(newIndex);
|
|
531
535
|
focusable && focusElement(focusable);
|
|
532
536
|
};
|
|
533
537
|
#update(active) {
|
|
@@ -597,6 +601,24 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
597
601
|
const { selector } = this.#settings;
|
|
598
602
|
return (element) => !selector || [...this.#container.querySelectorAll(selector)].includes(element);
|
|
599
603
|
}
|
|
604
|
+
#getCellCoords(cell) {
|
|
605
|
+
const { height, left, top, width } = cell.getBoundingClientRect();
|
|
606
|
+
return {
|
|
607
|
+
x: left + width / 2,
|
|
608
|
+
y: top + height / 2
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
#getCellsOfActiveRow() {
|
|
612
|
+
const active = getActiveElement();
|
|
613
|
+
if (!(active instanceof Element)) {
|
|
614
|
+
return [];
|
|
615
|
+
}
|
|
616
|
+
const activeRect = active.getBoundingClientRect();
|
|
617
|
+
return this.#getFocusables().filter((cell) => {
|
|
618
|
+
const cellRect = cell.getBoundingClientRect();
|
|
619
|
+
return cellRect.top < activeRect.bottom && cellRect.bottom > activeRect.top;
|
|
620
|
+
});
|
|
621
|
+
}
|
|
600
622
|
#getFocusables() {
|
|
601
623
|
return getFocusables(this.#container, {
|
|
602
624
|
composed: true,
|
|
@@ -605,6 +627,50 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
605
627
|
skipVisibilityCheck: true
|
|
606
628
|
});
|
|
607
629
|
}
|
|
630
|
+
#getNextCell(key, wrap) {
|
|
631
|
+
const cells = this.#getFocusables();
|
|
632
|
+
const active = getActiveElement();
|
|
633
|
+
if (!(active instanceof Element)) {
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
636
|
+
const activeCoords = this.#getCellCoords(active);
|
|
637
|
+
let min = Infinity;
|
|
638
|
+
let result = null;
|
|
639
|
+
for (const cell of cells) {
|
|
640
|
+
if (cell === active) {
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
const cellCoords = this.#getCellCoords(cell);
|
|
644
|
+
const distances = {
|
|
645
|
+
x: Math.abs(cellCoords.x - activeCoords.x),
|
|
646
|
+
y: Math.abs(cellCoords.y - activeCoords.y)
|
|
647
|
+
};
|
|
648
|
+
if (key === "ArrowUp" && cellCoords.y < activeCoords.y && distances.x < distances.y || key === "ArrowDown" && cellCoords.y > activeCoords.y && distances.x < distances.y) {
|
|
649
|
+
const distance = distances.x ** 2 + distances.y ** 2;
|
|
650
|
+
if (distance < min) {
|
|
651
|
+
min = distance;
|
|
652
|
+
result = cell;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (!result && wrap) {
|
|
657
|
+
let max = -Infinity;
|
|
658
|
+
for (const cell of cells) {
|
|
659
|
+
if (cell === active) {
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
const cellCoords = this.#getCellCoords(cell);
|
|
663
|
+
if (Math.abs(cellCoords.x - activeCoords.x) < cell.getBoundingClientRect().width / 2) {
|
|
664
|
+
const distance = key === "ArrowUp" ? cellCoords.y - activeCoords.y : activeCoords.y - cellCoords.y;
|
|
665
|
+
if (distance > max) {
|
|
666
|
+
max = distance;
|
|
667
|
+
result = cell;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
return result;
|
|
673
|
+
}
|
|
608
674
|
#resolveOptions(options) {
|
|
609
675
|
let {
|
|
610
676
|
direction = "both",
|
|
@@ -616,7 +682,7 @@ var RovingTabIndex = class _RovingTabIndex {
|
|
|
616
682
|
wrap = false
|
|
617
683
|
} = options;
|
|
618
684
|
direction = direction.toLowerCase();
|
|
619
|
-
if (!["both", "horizontal", "vertical"].includes(direction)) {
|
|
685
|
+
if (!["both", "grid", "horizontal", "vertical"].includes(direction)) {
|
|
620
686
|
console.warn("Invalid direction option. Fallback: 'both'.");
|
|
621
687
|
direction = "both";
|
|
622
688
|
}
|
|
@@ -941,21 +1007,24 @@ var Accordion = class _Accordion {
|
|
|
941
1007
|
console.warn(`Invalid collapsible option. Fallback: ${collapsible}.`);
|
|
942
1008
|
merged.collapsible = collapsible;
|
|
943
1009
|
}
|
|
944
|
-
const
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
1010
|
+
const selector = merged.selector;
|
|
1011
|
+
function resolveSelector(name, target2, source2) {
|
|
1012
|
+
try {
|
|
1013
|
+
document.querySelector(source2);
|
|
1014
|
+
return source2;
|
|
1015
|
+
} catch {
|
|
1016
|
+
console.warn(
|
|
1017
|
+
`Invalid ${name.replace(/[A-Z]/g, (c) => ` ${c.toLowerCase()}`)} selector. Fallback: '${target2}'.`
|
|
1018
|
+
);
|
|
1019
|
+
return target2;
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
for (const name of ["content", "trigger"]) {
|
|
1023
|
+
selector[name] = resolveSelector(
|
|
1024
|
+
name,
|
|
1025
|
+
defaults.selector[name],
|
|
1026
|
+
selector[name]
|
|
1027
|
+
);
|
|
959
1028
|
}
|
|
960
1029
|
return merged;
|
|
961
1030
|
}
|
|
@@ -977,7 +1046,7 @@ function waitAnimationFinish(animation) {
|
|
|
977
1046
|
* Accordion
|
|
978
1047
|
* WAI-ARIA compliant accordion pattern implementation in TypeScript.
|
|
979
1048
|
*
|
|
980
|
-
* @version 2.1.
|
|
1049
|
+
* @version 2.1.3
|
|
981
1050
|
* @author Yusuke Kamiyamane
|
|
982
1051
|
* @license MIT
|
|
983
1052
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1002,7 +1071,7 @@ power-focusable/dist/index.js:
|
|
|
1002
1071
|
* High-precision focus management utility with full composed tree support.
|
|
1003
1072
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
1004
1073
|
*
|
|
1005
|
-
* @version 4.
|
|
1074
|
+
* @version 4.4.2
|
|
1006
1075
|
* @author Yusuke Kamiyamane
|
|
1007
1076
|
* @license MIT
|
|
1008
1077
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1026,7 +1095,7 @@ power-focusable/dist/index.js:
|
|
|
1026
1095
|
* Lightweight roving tabindex utility with fully focus management.
|
|
1027
1096
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
1028
1097
|
*
|
|
1029
|
-
* @version 3.1
|
|
1098
|
+
* @version 3.3.1
|
|
1030
1099
|
* @author Yusuke Kamiyamane
|
|
1031
1100
|
* @license MIT
|
|
1032
1101
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.cjs
CHANGED
|
@@ -285,21 +285,24 @@ var Accordion = class _Accordion {
|
|
|
285
285
|
console.warn(`Invalid collapsible option. Fallback: ${collapsible}.`);
|
|
286
286
|
merged.collapsible = collapsible;
|
|
287
287
|
}
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
288
|
+
const selector = merged.selector;
|
|
289
|
+
function resolveSelector(name, target2, source2) {
|
|
290
|
+
try {
|
|
291
|
+
document.querySelector(source2);
|
|
292
|
+
return source2;
|
|
293
|
+
} catch {
|
|
294
|
+
console.warn(
|
|
295
|
+
`Invalid ${name.replace(/[A-Z]/g, (c) => ` ${c.toLowerCase()}`)} selector. Fallback: '${target2}'.`
|
|
296
|
+
);
|
|
297
|
+
return target2;
|
|
298
|
+
}
|
|
296
299
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
300
|
+
for (const name of ["content", "trigger"]) {
|
|
301
|
+
selector[name] = resolveSelector(
|
|
302
|
+
name,
|
|
303
|
+
defaults.selector[name],
|
|
304
|
+
selector[name]
|
|
305
|
+
);
|
|
303
306
|
}
|
|
304
307
|
return merged;
|
|
305
308
|
}
|
|
@@ -321,7 +324,7 @@ function waitAnimationFinish(animation) {
|
|
|
321
324
|
* Accordion
|
|
322
325
|
* WAI-ARIA compliant accordion pattern implementation in TypeScript.
|
|
323
326
|
*
|
|
324
|
-
* @version 2.1.
|
|
327
|
+
* @version 2.1.3
|
|
325
328
|
* @author Yusuke Kamiyamane
|
|
326
329
|
* @license MIT
|
|
327
330
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -283,21 +283,24 @@ var Accordion = class _Accordion {
|
|
|
283
283
|
console.warn(`Invalid collapsible option. Fallback: ${collapsible}.`);
|
|
284
284
|
merged.collapsible = collapsible;
|
|
285
285
|
}
|
|
286
|
-
const
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
286
|
+
const selector = merged.selector;
|
|
287
|
+
function resolveSelector(name, target2, source2) {
|
|
288
|
+
try {
|
|
289
|
+
document.querySelector(source2);
|
|
290
|
+
return source2;
|
|
291
|
+
} catch {
|
|
292
|
+
console.warn(
|
|
293
|
+
`Invalid ${name.replace(/[A-Z]/g, (c) => ` ${c.toLowerCase()}`)} selector. Fallback: '${target2}'.`
|
|
294
|
+
);
|
|
295
|
+
return target2;
|
|
296
|
+
}
|
|
294
297
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
298
|
+
for (const name of ["content", "trigger"]) {
|
|
299
|
+
selector[name] = resolveSelector(
|
|
300
|
+
name,
|
|
301
|
+
defaults.selector[name],
|
|
302
|
+
selector[name]
|
|
303
|
+
);
|
|
301
304
|
}
|
|
302
305
|
return merged;
|
|
303
306
|
}
|
|
@@ -319,7 +322,7 @@ function waitAnimationFinish(animation) {
|
|
|
319
322
|
* Accordion
|
|
320
323
|
* WAI-ARIA compliant accordion pattern implementation in TypeScript.
|
|
321
324
|
*
|
|
322
|
-
* @version 2.1.
|
|
325
|
+
* @version 2.1.3
|
|
323
326
|
* @author Yusuke Kamiyamane
|
|
324
327
|
* @license MIT
|
|
325
328
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y14e/accordion",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
4
4
|
"description": "WAI-ARIA compliant accordion pattern implementation in TypeScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"a11y",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@y14e/attribute-utils": "^2.0.12",
|
|
58
58
|
"@y14e/button": "^1.0.8",
|
|
59
|
-
"@y14e/roving-tabindex": "^3.1
|
|
59
|
+
"@y14e/roving-tabindex": "^3.3.1"
|
|
60
60
|
}
|
|
61
61
|
}
|