@y14e/tabs 1.5.7 → 1.5.9
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 +4 -4
- package/dist/index.cjs +77 -96
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +77 -96
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,14 +10,14 @@ npm i @y14e/tabs
|
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
12
|
// npm
|
|
13
|
-
import Tabs from '@y14e/tabs@1.5.
|
|
13
|
+
import Tabs from '@y14e/tabs@1.5.9';
|
|
14
14
|
|
|
15
15
|
// CDNs
|
|
16
|
-
import Tabs from 'https://esm.sh/@y14e/tabs@1.5.
|
|
16
|
+
import Tabs from 'https://esm.sh/@y14e/tabs@1.5.9';
|
|
17
17
|
// or
|
|
18
|
-
import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@1.5.
|
|
18
|
+
import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@1.5.9/+esm';
|
|
19
19
|
// or
|
|
20
|
-
import Tabs from 'https://esm.unpkg.com/@y14e/tabs@1.5.
|
|
20
|
+
import Tabs from 'https://esm.unpkg.com/@y14e/tabs@1.5.9';
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## Usage
|
package/dist/index.cjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
// node_modules/@y14e/attributes-utils/dist/index.js
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var DEFAULT_PARSER = (value) => value.split(/\s+/);
|
|
5
|
+
var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
|
|
6
6
|
function addTokenToAttribute(element, attribute, token, options = {}) {
|
|
7
7
|
const {
|
|
8
8
|
caseInsensitive = false,
|
|
9
|
-
parse =
|
|
10
|
-
serialize =
|
|
9
|
+
parse = DEFAULT_PARSER,
|
|
10
|
+
serialize = DEFAULT_SERIALIZER
|
|
11
11
|
} = options;
|
|
12
12
|
const value = element.getAttribute(attribute)?.trim();
|
|
13
13
|
const tokens = value ? parse(value).filter(Boolean) : [];
|
|
@@ -17,11 +17,11 @@ function addTokenToAttribute(element, attribute, token, options = {}) {
|
|
|
17
17
|
tokens.push(token);
|
|
18
18
|
element.setAttribute(attribute, serialize(tokens));
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
} else {
|
|
21
|
+
const set = new Set(tokens);
|
|
22
|
+
set.add(token);
|
|
23
|
+
element.setAttribute(attribute, serialize([...set]));
|
|
21
24
|
}
|
|
22
|
-
const set = new Set(tokens);
|
|
23
|
-
set.add(token);
|
|
24
|
-
element.setAttribute(attribute, serialize([...set]));
|
|
25
25
|
}
|
|
26
26
|
var snapshots = /* @__PURE__ */ new WeakMap();
|
|
27
27
|
function restoreAttributes(elements) {
|
|
@@ -106,13 +106,13 @@ function getActiveElement() {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
// node_modules/@y14e/roving-tabindex/dist/index.js
|
|
109
|
-
var
|
|
110
|
-
var
|
|
109
|
+
var DEFAULT_PARSER2 = (value) => value.split(/\s+/);
|
|
110
|
+
var DEFAULT_SERIALIZER2 = (tokens) => tokens.join(" ");
|
|
111
111
|
function addTokenToAttribute2(element, attribute, token, options = {}) {
|
|
112
112
|
const {
|
|
113
113
|
caseInsensitive = false,
|
|
114
|
-
parse =
|
|
115
|
-
serialize =
|
|
114
|
+
parse = DEFAULT_PARSER2,
|
|
115
|
+
serialize = DEFAULT_SERIALIZER2
|
|
116
116
|
} = options;
|
|
117
117
|
const value = element.getAttribute(attribute)?.trim();
|
|
118
118
|
const tokens = value ? parse(value).filter(Boolean) : [];
|
|
@@ -122,11 +122,11 @@ function addTokenToAttribute2(element, attribute, token, options = {}) {
|
|
|
122
122
|
tokens.push(token);
|
|
123
123
|
element.setAttribute(attribute, serialize(tokens));
|
|
124
124
|
}
|
|
125
|
-
|
|
125
|
+
} else {
|
|
126
|
+
const set = new Set(tokens);
|
|
127
|
+
set.add(token);
|
|
128
|
+
element.setAttribute(attribute, serialize([...set]));
|
|
126
129
|
}
|
|
127
|
-
const set = new Set(tokens);
|
|
128
|
-
set.add(token);
|
|
129
|
-
element.setAttribute(attribute, serialize([...set]));
|
|
130
130
|
}
|
|
131
131
|
var snapshots2 = /* @__PURE__ */ new WeakMap();
|
|
132
132
|
function restoreAttributes2(elements) {
|
|
@@ -193,21 +193,16 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
193
193
|
const elements = [];
|
|
194
194
|
if (composed || include) {
|
|
195
195
|
let traverse2 = function(node) {
|
|
196
|
-
if (node instanceof Element) {
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
elements[elements.length] = node;
|
|
202
|
-
}
|
|
196
|
+
if (!(node instanceof Element)) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
|
|
200
|
+
elements[elements.length] = node;
|
|
203
201
|
}
|
|
204
202
|
const children = getComposedChildren(node);
|
|
205
203
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
206
204
|
const child = children[i];
|
|
207
|
-
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
210
|
-
traverse2(child);
|
|
205
|
+
child && traverse2(child);
|
|
211
206
|
}
|
|
212
207
|
};
|
|
213
208
|
traverse2(container);
|
|
@@ -215,10 +210,7 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
215
210
|
const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
|
|
216
211
|
for (let i = 0, l = candidates.length; i < l; i++) {
|
|
217
212
|
const candidate = candidates[i];
|
|
218
|
-
if (
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
|
-
if (isFocusable(candidate, {
|
|
213
|
+
if (candidate && isFocusable(candidate, {
|
|
222
214
|
skipNegativeTabIndexCheck,
|
|
223
215
|
skipVisibilityCheck
|
|
224
216
|
})) {
|
|
@@ -321,23 +313,19 @@ function normalizeRadioGroup(elements) {
|
|
|
321
313
|
for (const group of map.values()) {
|
|
322
314
|
placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
|
|
323
315
|
}
|
|
324
|
-
return elements.filter(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
return true;
|
|
329
|
-
});
|
|
316
|
+
return elements.filter(
|
|
317
|
+
(element) => isUngroupedRadio(element) ? placeholder.has(element) : true
|
|
318
|
+
);
|
|
330
319
|
}
|
|
331
320
|
function sortByTabIndex(elements) {
|
|
332
321
|
const ordered = [];
|
|
333
322
|
const natural = [];
|
|
334
323
|
for (let i = 0, l = elements.length; i < l; i++) {
|
|
335
324
|
const element = elements[i];
|
|
336
|
-
if (
|
|
337
|
-
|
|
325
|
+
if (element) {
|
|
326
|
+
const target = getTabIndex(element) > 0 ? ordered : natural;
|
|
327
|
+
target[target.length] = element;
|
|
338
328
|
}
|
|
339
|
-
const target = getTabIndex(element) > 0 ? ordered : natural;
|
|
340
|
-
target[target.length] = element;
|
|
341
329
|
}
|
|
342
330
|
ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
|
|
343
331
|
let count = 0;
|
|
@@ -436,7 +424,13 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
436
424
|
console.warn("Invalid wrap option. Fallback: false.");
|
|
437
425
|
wrap = false;
|
|
438
426
|
}
|
|
439
|
-
const settings = {
|
|
427
|
+
const settings = {
|
|
428
|
+
navigationOnly,
|
|
429
|
+
noMemory,
|
|
430
|
+
noStart,
|
|
431
|
+
typeahead,
|
|
432
|
+
wrap
|
|
433
|
+
};
|
|
440
434
|
direction && Object.assign(settings, { direction });
|
|
441
435
|
selector && Object.assign(settings, { selector });
|
|
442
436
|
const roving = new RovingTabIndex(container, settings);
|
|
@@ -488,11 +482,7 @@ var RovingTabIndex = class {
|
|
|
488
482
|
return;
|
|
489
483
|
}
|
|
490
484
|
const isFocusable22 = this.#focusables.has(target);
|
|
491
|
-
|
|
492
|
-
this.#update(null);
|
|
493
|
-
return;
|
|
494
|
-
}
|
|
495
|
-
isFocusable22 && this.#update(target);
|
|
485
|
+
this.#options.noMemory && !isFocusable22 ? this.#update(null) : isFocusable22 && this.#update(target);
|
|
496
486
|
};
|
|
497
487
|
#onKeyDown = (event) => {
|
|
498
488
|
if (!event.composedPath().includes(this.#container)) {
|
|
@@ -524,10 +514,8 @@ var RovingTabIndex = class {
|
|
|
524
514
|
return;
|
|
525
515
|
}
|
|
526
516
|
event.preventDefault();
|
|
527
|
-
event.stopPropagation();
|
|
528
517
|
const currentIndex = current.indexOf(active);
|
|
529
|
-
let
|
|
530
|
-
let newIndex = currentIndex;
|
|
518
|
+
let newIndex;
|
|
531
519
|
let target = current;
|
|
532
520
|
switch (key) {
|
|
533
521
|
case "End":
|
|
@@ -537,15 +525,17 @@ var RovingTabIndex = class {
|
|
|
537
525
|
newIndex = 0;
|
|
538
526
|
break;
|
|
539
527
|
case "ArrowLeft":
|
|
540
|
-
case "ArrowUp":
|
|
541
|
-
rawIndex = currentIndex - 1;
|
|
528
|
+
case "ArrowUp": {
|
|
529
|
+
const rawIndex = currentIndex - 1;
|
|
542
530
|
newIndex = wrap ? rawIndex : Math.max(rawIndex, 0);
|
|
543
531
|
break;
|
|
532
|
+
}
|
|
544
533
|
case "ArrowRight":
|
|
545
|
-
case "ArrowDown":
|
|
546
|
-
rawIndex = currentIndex + 1;
|
|
534
|
+
case "ArrowDown": {
|
|
535
|
+
const rawIndex = currentIndex + 1;
|
|
547
536
|
newIndex = wrap ? rawIndex % current.length : Math.min(rawIndex, current.length - 1);
|
|
548
537
|
break;
|
|
538
|
+
}
|
|
549
539
|
default: {
|
|
550
540
|
target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
|
|
551
541
|
const foundIndex = target.findIndex(
|
|
@@ -560,15 +550,14 @@ var RovingTabIndex = class {
|
|
|
560
550
|
#update(active) {
|
|
561
551
|
const current = new Set(this.#getFocusables());
|
|
562
552
|
for (const focusable of this.#focusables) {
|
|
563
|
-
if (current.has(focusable)) {
|
|
564
|
-
|
|
553
|
+
if (!current.has(focusable)) {
|
|
554
|
+
focusable.isConnected && restoreAttributes2([focusable]);
|
|
555
|
+
this.#focusables.delete(focusable);
|
|
556
|
+
this.#focusablesByFirstChar.forEach((focusables) => {
|
|
557
|
+
const index = focusables.indexOf(focusable);
|
|
558
|
+
index >= 0 && focusables.splice(index, 1);
|
|
559
|
+
});
|
|
565
560
|
}
|
|
566
|
-
focusable.isConnected && restoreAttributes2([focusable]);
|
|
567
|
-
this.#focusables.delete(focusable);
|
|
568
|
-
this.#focusablesByFirstChar.forEach((focusables) => {
|
|
569
|
-
const index = focusables.indexOf(focusable);
|
|
570
|
-
index >= 0 && focusables.splice(index, 1);
|
|
571
|
-
});
|
|
572
561
|
}
|
|
573
562
|
const { navigationOnly, noStart, typeahead } = this.#options;
|
|
574
563
|
for (const focusable of current) {
|
|
@@ -601,18 +590,17 @@ var RovingTabIndex = class {
|
|
|
601
590
|
this.#focusablesByFirstChar.set(key, focusables);
|
|
602
591
|
});
|
|
603
592
|
}
|
|
604
|
-
if (navigationOnly) {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
593
|
+
if (!navigationOnly) {
|
|
594
|
+
if (active && this.#focusables.has(active)) {
|
|
595
|
+
this.#focusables.forEach((focusable) => {
|
|
596
|
+
focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
|
|
597
|
+
});
|
|
598
|
+
} else {
|
|
599
|
+
[...this.#focusables].forEach((focusable, i) => {
|
|
600
|
+
focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
|
|
601
|
+
});
|
|
602
|
+
}
|
|
612
603
|
}
|
|
613
|
-
[...this.#focusables].forEach((focusable, i) => {
|
|
614
|
-
focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
|
|
615
|
-
});
|
|
616
604
|
}
|
|
617
605
|
#createSelectorFilter() {
|
|
618
606
|
const { selector } = this.#options;
|
|
@@ -677,7 +665,6 @@ var Tabs = class _Tabs {
|
|
|
677
665
|
#animationController = null;
|
|
678
666
|
#cleanupsRovingTabIndex = [];
|
|
679
667
|
#animation = null;
|
|
680
|
-
#animationId = 0;
|
|
681
668
|
#buttons = [];
|
|
682
669
|
#indicators = [];
|
|
683
670
|
#isDestroyed = false;
|
|
@@ -801,16 +788,12 @@ var Tabs = class _Tabs {
|
|
|
801
788
|
p.removeAttribute("hidden");
|
|
802
789
|
} else {
|
|
803
790
|
const tab2 = this.#tabElements[i];
|
|
804
|
-
|
|
805
|
-
return;
|
|
806
|
-
}
|
|
807
|
-
p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
|
|
791
|
+
tab2 && p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
|
|
808
792
|
}
|
|
809
793
|
});
|
|
810
|
-
const animationId = ++this.#animationId;
|
|
811
794
|
this.#animation?.cancel();
|
|
812
795
|
const { duration, easing } = this.#settings.animation.content;
|
|
813
|
-
|
|
796
|
+
const animation = this.#contentElement.animate(
|
|
814
797
|
{
|
|
815
798
|
blockSize: [
|
|
816
799
|
`${size}px`,
|
|
@@ -822,8 +805,9 @@ var Tabs = class _Tabs {
|
|
|
822
805
|
easing
|
|
823
806
|
}
|
|
824
807
|
);
|
|
808
|
+
this.#animation = animation;
|
|
825
809
|
const cleanup = () => {
|
|
826
|
-
if (
|
|
810
|
+
if (animation === this.#animation) {
|
|
827
811
|
this.#animation = null;
|
|
828
812
|
}
|
|
829
813
|
};
|
|
@@ -836,7 +820,7 @@ var Tabs = class _Tabs {
|
|
|
836
820
|
this.#animation.addEventListener(
|
|
837
821
|
"finish",
|
|
838
822
|
() => {
|
|
839
|
-
if (
|
|
823
|
+
if (this.#animation === animation) {
|
|
840
824
|
this.#onAnimationFinish();
|
|
841
825
|
cleanup();
|
|
842
826
|
}
|
|
@@ -854,7 +838,7 @@ var Tabs = class _Tabs {
|
|
|
854
838
|
const opacity = getComputedStyle(p).getPropertyValue("opacity");
|
|
855
839
|
binding.animation?.cancel();
|
|
856
840
|
const isSelected = p === panel;
|
|
857
|
-
const
|
|
841
|
+
const animation2 = p.animate(
|
|
858
842
|
{
|
|
859
843
|
opacity: fade ? isSelected ? [opacity, opacity, "1"] : [opacity, "0", "0"] : isSelected ? [opacity, "1"] : [opacity, "0"]
|
|
860
844
|
},
|
|
@@ -863,16 +847,16 @@ var Tabs = class _Tabs {
|
|
|
863
847
|
easing: "ease"
|
|
864
848
|
}
|
|
865
849
|
);
|
|
866
|
-
binding.animation =
|
|
850
|
+
binding.animation = animation2;
|
|
867
851
|
const cleanup2 = () => {
|
|
868
|
-
if (binding.animation ===
|
|
852
|
+
if (binding.animation === animation2) {
|
|
869
853
|
binding.animation = null;
|
|
870
854
|
}
|
|
871
855
|
};
|
|
872
856
|
this.#animationController = new AbortController();
|
|
873
857
|
const { signal: signal2 } = this.#animationController;
|
|
874
|
-
|
|
875
|
-
|
|
858
|
+
animation2.addEventListener("cancel", cleanup2, { once: true, signal: signal2 });
|
|
859
|
+
animation2.addEventListener("finish", cleanup2, { once: true, signal: signal2 });
|
|
876
860
|
});
|
|
877
861
|
}
|
|
878
862
|
async destroy(force = false) {
|
|
@@ -1029,10 +1013,7 @@ var Tabs = class _Tabs {
|
|
|
1029
1013
|
return;
|
|
1030
1014
|
}
|
|
1031
1015
|
const tab = this.#bindings.get(panel)?.tabs[0];
|
|
1032
|
-
|
|
1033
|
-
return;
|
|
1034
|
-
}
|
|
1035
|
-
this.activate(tab, true);
|
|
1016
|
+
tab && this.activate(tab, true);
|
|
1036
1017
|
};
|
|
1037
1018
|
#isAvoidedTab(tab) {
|
|
1038
1019
|
const binding = this.#bindings.get(tab);
|
|
@@ -1164,7 +1145,7 @@ function isFocusable2(element) {
|
|
|
1164
1145
|
* Tabs
|
|
1165
1146
|
* WAI-ARIA compliant tabs pattern implementation in TypeScript.
|
|
1166
1147
|
*
|
|
1167
|
-
* @version 1.5.
|
|
1148
|
+
* @version 1.5.9
|
|
1168
1149
|
* @author Yusuke Kamiyamane
|
|
1169
1150
|
* @license MIT
|
|
1170
1151
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1176,7 +1157,7 @@ function isFocusable2(element) {
|
|
|
1176
1157
|
(**
|
|
1177
1158
|
* Attributes Utils
|
|
1178
1159
|
*
|
|
1179
|
-
* @version 1.1.
|
|
1160
|
+
* @version 1.1.2
|
|
1180
1161
|
* @author Yusuke Kamiyamane
|
|
1181
1162
|
* @license MIT
|
|
1182
1163
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1200,7 +1181,7 @@ function isFocusable2(element) {
|
|
|
1200
1181
|
* Lightweight roving tabindex utility with fully focus management.
|
|
1201
1182
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
1202
1183
|
*
|
|
1203
|
-
* @version
|
|
1184
|
+
* @version 3.0.2
|
|
1204
1185
|
* @author Yusuke Kamiyamane
|
|
1205
1186
|
* @license MIT
|
|
1206
1187
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1212,7 +1193,7 @@ function isFocusable2(element) {
|
|
|
1212
1193
|
(**
|
|
1213
1194
|
* Attributes Utils
|
|
1214
1195
|
*
|
|
1215
|
-
* @version 1.1.
|
|
1196
|
+
* @version 1.1.2
|
|
1216
1197
|
* @author Yusuke Kamiyamane
|
|
1217
1198
|
* @license MIT
|
|
1218
1199
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1225,7 +1206,7 @@ function isFocusable2(element) {
|
|
|
1225
1206
|
* High-precision focus management utility with full composed tree support.
|
|
1226
1207
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
1227
1208
|
*
|
|
1228
|
-
* @version 4.3.
|
|
1209
|
+
* @version 4.3.3
|
|
1229
1210
|
* @author Yusuke Kamiyamane
|
|
1230
1211
|
* @license MIT
|
|
1231
1212
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// node_modules/@y14e/attributes-utils/dist/index.js
|
|
2
|
-
var
|
|
3
|
-
var
|
|
2
|
+
var DEFAULT_PARSER = (value) => value.split(/\s+/);
|
|
3
|
+
var DEFAULT_SERIALIZER = (tokens) => tokens.join(" ");
|
|
4
4
|
function addTokenToAttribute(element, attribute, token, options = {}) {
|
|
5
5
|
const {
|
|
6
6
|
caseInsensitive = false,
|
|
7
|
-
parse =
|
|
8
|
-
serialize =
|
|
7
|
+
parse = DEFAULT_PARSER,
|
|
8
|
+
serialize = DEFAULT_SERIALIZER
|
|
9
9
|
} = options;
|
|
10
10
|
const value = element.getAttribute(attribute)?.trim();
|
|
11
11
|
const tokens = value ? parse(value).filter(Boolean) : [];
|
|
@@ -15,11 +15,11 @@ function addTokenToAttribute(element, attribute, token, options = {}) {
|
|
|
15
15
|
tokens.push(token);
|
|
16
16
|
element.setAttribute(attribute, serialize(tokens));
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
} else {
|
|
19
|
+
const set = new Set(tokens);
|
|
20
|
+
set.add(token);
|
|
21
|
+
element.setAttribute(attribute, serialize([...set]));
|
|
19
22
|
}
|
|
20
|
-
const set = new Set(tokens);
|
|
21
|
-
set.add(token);
|
|
22
|
-
element.setAttribute(attribute, serialize([...set]));
|
|
23
23
|
}
|
|
24
24
|
var snapshots = /* @__PURE__ */ new WeakMap();
|
|
25
25
|
function restoreAttributes(elements) {
|
|
@@ -104,13 +104,13 @@ function getActiveElement() {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
// node_modules/@y14e/roving-tabindex/dist/index.js
|
|
107
|
-
var
|
|
108
|
-
var
|
|
107
|
+
var DEFAULT_PARSER2 = (value) => value.split(/\s+/);
|
|
108
|
+
var DEFAULT_SERIALIZER2 = (tokens) => tokens.join(" ");
|
|
109
109
|
function addTokenToAttribute2(element, attribute, token, options = {}) {
|
|
110
110
|
const {
|
|
111
111
|
caseInsensitive = false,
|
|
112
|
-
parse =
|
|
113
|
-
serialize =
|
|
112
|
+
parse = DEFAULT_PARSER2,
|
|
113
|
+
serialize = DEFAULT_SERIALIZER2
|
|
114
114
|
} = options;
|
|
115
115
|
const value = element.getAttribute(attribute)?.trim();
|
|
116
116
|
const tokens = value ? parse(value).filter(Boolean) : [];
|
|
@@ -120,11 +120,11 @@ function addTokenToAttribute2(element, attribute, token, options = {}) {
|
|
|
120
120
|
tokens.push(token);
|
|
121
121
|
element.setAttribute(attribute, serialize(tokens));
|
|
122
122
|
}
|
|
123
|
-
|
|
123
|
+
} else {
|
|
124
|
+
const set = new Set(tokens);
|
|
125
|
+
set.add(token);
|
|
126
|
+
element.setAttribute(attribute, serialize([...set]));
|
|
124
127
|
}
|
|
125
|
-
const set = new Set(tokens);
|
|
126
|
-
set.add(token);
|
|
127
|
-
element.setAttribute(attribute, serialize([...set]));
|
|
128
128
|
}
|
|
129
129
|
var snapshots2 = /* @__PURE__ */ new WeakMap();
|
|
130
130
|
function restoreAttributes2(elements) {
|
|
@@ -191,21 +191,16 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
191
191
|
const elements = [];
|
|
192
192
|
if (composed || include) {
|
|
193
193
|
let traverse2 = function(node) {
|
|
194
|
-
if (node instanceof Element) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
elements[elements.length] = node;
|
|
200
|
-
}
|
|
194
|
+
if (!(node instanceof Element)) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
|
|
198
|
+
elements[elements.length] = node;
|
|
201
199
|
}
|
|
202
200
|
const children = getComposedChildren(node);
|
|
203
201
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
204
202
|
const child = children[i];
|
|
205
|
-
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
traverse2(child);
|
|
203
|
+
child && traverse2(child);
|
|
209
204
|
}
|
|
210
205
|
};
|
|
211
206
|
traverse2(container);
|
|
@@ -213,10 +208,7 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
213
208
|
const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
|
|
214
209
|
for (let i = 0, l = candidates.length; i < l; i++) {
|
|
215
210
|
const candidate = candidates[i];
|
|
216
|
-
if (
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
if (isFocusable(candidate, {
|
|
211
|
+
if (candidate && isFocusable(candidate, {
|
|
220
212
|
skipNegativeTabIndexCheck,
|
|
221
213
|
skipVisibilityCheck
|
|
222
214
|
})) {
|
|
@@ -319,23 +311,19 @@ function normalizeRadioGroup(elements) {
|
|
|
319
311
|
for (const group of map.values()) {
|
|
320
312
|
placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
|
|
321
313
|
}
|
|
322
|
-
return elements.filter(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
326
|
-
return true;
|
|
327
|
-
});
|
|
314
|
+
return elements.filter(
|
|
315
|
+
(element) => isUngroupedRadio(element) ? placeholder.has(element) : true
|
|
316
|
+
);
|
|
328
317
|
}
|
|
329
318
|
function sortByTabIndex(elements) {
|
|
330
319
|
const ordered = [];
|
|
331
320
|
const natural = [];
|
|
332
321
|
for (let i = 0, l = elements.length; i < l; i++) {
|
|
333
322
|
const element = elements[i];
|
|
334
|
-
if (
|
|
335
|
-
|
|
323
|
+
if (element) {
|
|
324
|
+
const target = getTabIndex(element) > 0 ? ordered : natural;
|
|
325
|
+
target[target.length] = element;
|
|
336
326
|
}
|
|
337
|
-
const target = getTabIndex(element) > 0 ? ordered : natural;
|
|
338
|
-
target[target.length] = element;
|
|
339
327
|
}
|
|
340
328
|
ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
|
|
341
329
|
let count = 0;
|
|
@@ -434,7 +422,13 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
434
422
|
console.warn("Invalid wrap option. Fallback: false.");
|
|
435
423
|
wrap = false;
|
|
436
424
|
}
|
|
437
|
-
const settings = {
|
|
425
|
+
const settings = {
|
|
426
|
+
navigationOnly,
|
|
427
|
+
noMemory,
|
|
428
|
+
noStart,
|
|
429
|
+
typeahead,
|
|
430
|
+
wrap
|
|
431
|
+
};
|
|
438
432
|
direction && Object.assign(settings, { direction });
|
|
439
433
|
selector && Object.assign(settings, { selector });
|
|
440
434
|
const roving = new RovingTabIndex(container, settings);
|
|
@@ -486,11 +480,7 @@ var RovingTabIndex = class {
|
|
|
486
480
|
return;
|
|
487
481
|
}
|
|
488
482
|
const isFocusable22 = this.#focusables.has(target);
|
|
489
|
-
|
|
490
|
-
this.#update(null);
|
|
491
|
-
return;
|
|
492
|
-
}
|
|
493
|
-
isFocusable22 && this.#update(target);
|
|
483
|
+
this.#options.noMemory && !isFocusable22 ? this.#update(null) : isFocusable22 && this.#update(target);
|
|
494
484
|
};
|
|
495
485
|
#onKeyDown = (event) => {
|
|
496
486
|
if (!event.composedPath().includes(this.#container)) {
|
|
@@ -522,10 +512,8 @@ var RovingTabIndex = class {
|
|
|
522
512
|
return;
|
|
523
513
|
}
|
|
524
514
|
event.preventDefault();
|
|
525
|
-
event.stopPropagation();
|
|
526
515
|
const currentIndex = current.indexOf(active);
|
|
527
|
-
let
|
|
528
|
-
let newIndex = currentIndex;
|
|
516
|
+
let newIndex;
|
|
529
517
|
let target = current;
|
|
530
518
|
switch (key) {
|
|
531
519
|
case "End":
|
|
@@ -535,15 +523,17 @@ var RovingTabIndex = class {
|
|
|
535
523
|
newIndex = 0;
|
|
536
524
|
break;
|
|
537
525
|
case "ArrowLeft":
|
|
538
|
-
case "ArrowUp":
|
|
539
|
-
rawIndex = currentIndex - 1;
|
|
526
|
+
case "ArrowUp": {
|
|
527
|
+
const rawIndex = currentIndex - 1;
|
|
540
528
|
newIndex = wrap ? rawIndex : Math.max(rawIndex, 0);
|
|
541
529
|
break;
|
|
530
|
+
}
|
|
542
531
|
case "ArrowRight":
|
|
543
|
-
case "ArrowDown":
|
|
544
|
-
rawIndex = currentIndex + 1;
|
|
532
|
+
case "ArrowDown": {
|
|
533
|
+
const rawIndex = currentIndex + 1;
|
|
545
534
|
newIndex = wrap ? rawIndex % current.length : Math.min(rawIndex, current.length - 1);
|
|
546
535
|
break;
|
|
536
|
+
}
|
|
547
537
|
default: {
|
|
548
538
|
target = this.#focusablesByFirstChar.get(key.toUpperCase()) ?? [];
|
|
549
539
|
const foundIndex = target.findIndex(
|
|
@@ -558,15 +548,14 @@ var RovingTabIndex = class {
|
|
|
558
548
|
#update(active) {
|
|
559
549
|
const current = new Set(this.#getFocusables());
|
|
560
550
|
for (const focusable of this.#focusables) {
|
|
561
|
-
if (current.has(focusable)) {
|
|
562
|
-
|
|
551
|
+
if (!current.has(focusable)) {
|
|
552
|
+
focusable.isConnected && restoreAttributes2([focusable]);
|
|
553
|
+
this.#focusables.delete(focusable);
|
|
554
|
+
this.#focusablesByFirstChar.forEach((focusables) => {
|
|
555
|
+
const index = focusables.indexOf(focusable);
|
|
556
|
+
index >= 0 && focusables.splice(index, 1);
|
|
557
|
+
});
|
|
563
558
|
}
|
|
564
|
-
focusable.isConnected && restoreAttributes2([focusable]);
|
|
565
|
-
this.#focusables.delete(focusable);
|
|
566
|
-
this.#focusablesByFirstChar.forEach((focusables) => {
|
|
567
|
-
const index = focusables.indexOf(focusable);
|
|
568
|
-
index >= 0 && focusables.splice(index, 1);
|
|
569
|
-
});
|
|
570
559
|
}
|
|
571
560
|
const { navigationOnly, noStart, typeahead } = this.#options;
|
|
572
561
|
for (const focusable of current) {
|
|
@@ -599,18 +588,17 @@ var RovingTabIndex = class {
|
|
|
599
588
|
this.#focusablesByFirstChar.set(key, focusables);
|
|
600
589
|
});
|
|
601
590
|
}
|
|
602
|
-
if (navigationOnly) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
591
|
+
if (!navigationOnly) {
|
|
592
|
+
if (active && this.#focusables.has(active)) {
|
|
593
|
+
this.#focusables.forEach((focusable) => {
|
|
594
|
+
focusable.setAttribute("tabindex", focusable === active ? "0" : "-1");
|
|
595
|
+
});
|
|
596
|
+
} else {
|
|
597
|
+
[...this.#focusables].forEach((focusable, i) => {
|
|
598
|
+
focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
|
|
599
|
+
});
|
|
600
|
+
}
|
|
610
601
|
}
|
|
611
|
-
[...this.#focusables].forEach((focusable, i) => {
|
|
612
|
-
focusable.setAttribute("tabindex", i || noStart ? "-1" : "0");
|
|
613
|
-
});
|
|
614
602
|
}
|
|
615
603
|
#createSelectorFilter() {
|
|
616
604
|
const { selector } = this.#options;
|
|
@@ -675,7 +663,6 @@ var Tabs = class _Tabs {
|
|
|
675
663
|
#animationController = null;
|
|
676
664
|
#cleanupsRovingTabIndex = [];
|
|
677
665
|
#animation = null;
|
|
678
|
-
#animationId = 0;
|
|
679
666
|
#buttons = [];
|
|
680
667
|
#indicators = [];
|
|
681
668
|
#isDestroyed = false;
|
|
@@ -799,16 +786,12 @@ var Tabs = class _Tabs {
|
|
|
799
786
|
p.removeAttribute("hidden");
|
|
800
787
|
} else {
|
|
801
788
|
const tab2 = this.#tabElements[i];
|
|
802
|
-
|
|
803
|
-
return;
|
|
804
|
-
}
|
|
805
|
-
p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
|
|
789
|
+
tab2 && p.setAttribute("hidden", isFocusable2(tab2) ? "until-found" : "");
|
|
806
790
|
}
|
|
807
791
|
});
|
|
808
|
-
const animationId = ++this.#animationId;
|
|
809
792
|
this.#animation?.cancel();
|
|
810
793
|
const { duration, easing } = this.#settings.animation.content;
|
|
811
|
-
|
|
794
|
+
const animation = this.#contentElement.animate(
|
|
812
795
|
{
|
|
813
796
|
blockSize: [
|
|
814
797
|
`${size}px`,
|
|
@@ -820,8 +803,9 @@ var Tabs = class _Tabs {
|
|
|
820
803
|
easing
|
|
821
804
|
}
|
|
822
805
|
);
|
|
806
|
+
this.#animation = animation;
|
|
823
807
|
const cleanup = () => {
|
|
824
|
-
if (
|
|
808
|
+
if (animation === this.#animation) {
|
|
825
809
|
this.#animation = null;
|
|
826
810
|
}
|
|
827
811
|
};
|
|
@@ -834,7 +818,7 @@ var Tabs = class _Tabs {
|
|
|
834
818
|
this.#animation.addEventListener(
|
|
835
819
|
"finish",
|
|
836
820
|
() => {
|
|
837
|
-
if (
|
|
821
|
+
if (this.#animation === animation) {
|
|
838
822
|
this.#onAnimationFinish();
|
|
839
823
|
cleanup();
|
|
840
824
|
}
|
|
@@ -852,7 +836,7 @@ var Tabs = class _Tabs {
|
|
|
852
836
|
const opacity = getComputedStyle(p).getPropertyValue("opacity");
|
|
853
837
|
binding.animation?.cancel();
|
|
854
838
|
const isSelected = p === panel;
|
|
855
|
-
const
|
|
839
|
+
const animation2 = p.animate(
|
|
856
840
|
{
|
|
857
841
|
opacity: fade ? isSelected ? [opacity, opacity, "1"] : [opacity, "0", "0"] : isSelected ? [opacity, "1"] : [opacity, "0"]
|
|
858
842
|
},
|
|
@@ -861,16 +845,16 @@ var Tabs = class _Tabs {
|
|
|
861
845
|
easing: "ease"
|
|
862
846
|
}
|
|
863
847
|
);
|
|
864
|
-
binding.animation =
|
|
848
|
+
binding.animation = animation2;
|
|
865
849
|
const cleanup2 = () => {
|
|
866
|
-
if (binding.animation ===
|
|
850
|
+
if (binding.animation === animation2) {
|
|
867
851
|
binding.animation = null;
|
|
868
852
|
}
|
|
869
853
|
};
|
|
870
854
|
this.#animationController = new AbortController();
|
|
871
855
|
const { signal: signal2 } = this.#animationController;
|
|
872
|
-
|
|
873
|
-
|
|
856
|
+
animation2.addEventListener("cancel", cleanup2, { once: true, signal: signal2 });
|
|
857
|
+
animation2.addEventListener("finish", cleanup2, { once: true, signal: signal2 });
|
|
874
858
|
});
|
|
875
859
|
}
|
|
876
860
|
async destroy(force = false) {
|
|
@@ -1027,10 +1011,7 @@ var Tabs = class _Tabs {
|
|
|
1027
1011
|
return;
|
|
1028
1012
|
}
|
|
1029
1013
|
const tab = this.#bindings.get(panel)?.tabs[0];
|
|
1030
|
-
|
|
1031
|
-
return;
|
|
1032
|
-
}
|
|
1033
|
-
this.activate(tab, true);
|
|
1014
|
+
tab && this.activate(tab, true);
|
|
1034
1015
|
};
|
|
1035
1016
|
#isAvoidedTab(tab) {
|
|
1036
1017
|
const binding = this.#bindings.get(tab);
|
|
@@ -1162,7 +1143,7 @@ function isFocusable2(element) {
|
|
|
1162
1143
|
* Tabs
|
|
1163
1144
|
* WAI-ARIA compliant tabs pattern implementation in TypeScript.
|
|
1164
1145
|
*
|
|
1165
|
-
* @version 1.5.
|
|
1146
|
+
* @version 1.5.9
|
|
1166
1147
|
* @author Yusuke Kamiyamane
|
|
1167
1148
|
* @license MIT
|
|
1168
1149
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1174,7 +1155,7 @@ function isFocusable2(element) {
|
|
|
1174
1155
|
(**
|
|
1175
1156
|
* Attributes Utils
|
|
1176
1157
|
*
|
|
1177
|
-
* @version 1.1.
|
|
1158
|
+
* @version 1.1.2
|
|
1178
1159
|
* @author Yusuke Kamiyamane
|
|
1179
1160
|
* @license MIT
|
|
1180
1161
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1198,7 +1179,7 @@ function isFocusable2(element) {
|
|
|
1198
1179
|
* Lightweight roving tabindex utility with fully focus management.
|
|
1199
1180
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
1200
1181
|
*
|
|
1201
|
-
* @version
|
|
1182
|
+
* @version 3.0.2
|
|
1202
1183
|
* @author Yusuke Kamiyamane
|
|
1203
1184
|
* @license MIT
|
|
1204
1185
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1210,7 +1191,7 @@ function isFocusable2(element) {
|
|
|
1210
1191
|
(**
|
|
1211
1192
|
* Attributes Utils
|
|
1212
1193
|
*
|
|
1213
|
-
* @version 1.1.
|
|
1194
|
+
* @version 1.1.2
|
|
1214
1195
|
* @author Yusuke Kamiyamane
|
|
1215
1196
|
* @license MIT
|
|
1216
1197
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1223,7 +1204,7 @@ function isFocusable2(element) {
|
|
|
1223
1204
|
* High-precision focus management utility with full composed tree support.
|
|
1224
1205
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
1225
1206
|
*
|
|
1226
|
-
* @version 4.3.
|
|
1207
|
+
* @version 4.3.3
|
|
1227
1208
|
* @author Yusuke Kamiyamane
|
|
1228
1209
|
* @license MIT
|
|
1229
1210
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y14e/tabs",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.9",
|
|
4
4
|
"description": "WAI-ARIA compliant tabs pattern implementation in TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://github.com/y14e/tabs#readme",
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@y14e/attributes-utils": "^1.1.
|
|
45
|
+
"@y14e/attributes-utils": "^1.1.2",
|
|
46
46
|
"@y14e/button": "^1.0.0",
|
|
47
|
-
"@y14e/roving-tabindex": "^
|
|
47
|
+
"@y14e/roving-tabindex": "^3.0.2",
|
|
48
48
|
"bun-types": "latest",
|
|
49
49
|
"tsup": "^8.0.0",
|
|
50
50
|
"typescript": "^5.6.0",
|