@y14e/tabs 1.5.2 → 1.5.4
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 +39 -42
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +39 -42
- 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';
|
|
13
|
+
import Tabs from '@y14e/tabs@1.5.4';
|
|
14
14
|
|
|
15
15
|
// CDNs
|
|
16
|
-
import Tabs from 'https://esm.sh/@y14e/tabs'
|
|
16
|
+
import Tabs from 'https://esm.sh/@y14e/tabs@1.5.4';
|
|
17
17
|
// or
|
|
18
|
-
import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs/+esm';
|
|
18
|
+
import Tabs from 'https://cdn.jsdelivr.net/npm/@y14e/tabs@1.5.4/+esm';
|
|
19
19
|
// or
|
|
20
|
-
import Tabs from 'https://unpkg.com/@y14e/tabs
|
|
20
|
+
import Tabs from 'https://esm.unpkg.com/@y14e/tabs@1.5.4';
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## Usage
|
package/dist/index.cjs
CHANGED
|
@@ -414,7 +414,7 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
414
414
|
console.warn("Invalid navigationOnly option. Fallback: false.");
|
|
415
415
|
navigationOnly = false;
|
|
416
416
|
}
|
|
417
|
-
if (typeof selector !== "undefined" && typeof selector !== "string") {
|
|
417
|
+
if (typeof selector !== "undefined" && (typeof selector !== "string" || !selector.trim())) {
|
|
418
418
|
console.warn(
|
|
419
419
|
"Invalid selector. Fallback: all focusable elements (undefined)."
|
|
420
420
|
);
|
|
@@ -428,13 +428,14 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
428
428
|
console.warn("Invalid wrap option. Fallback: false.");
|
|
429
429
|
wrap = false;
|
|
430
430
|
}
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
431
|
+
const settings = { navigationOnly, typeahead, wrap };
|
|
432
|
+
if (direction) {
|
|
433
|
+
Object.assign(settings, { direction });
|
|
434
|
+
}
|
|
435
|
+
if (selector) {
|
|
436
|
+
Object.assign(settings, { selector });
|
|
437
|
+
}
|
|
438
|
+
const roving = new RovingTabIndex(container, settings);
|
|
438
439
|
return () => roving.destroy();
|
|
439
440
|
}
|
|
440
441
|
var RovingTabIndex = class {
|
|
@@ -476,8 +477,8 @@ var RovingTabIndex = class {
|
|
|
476
477
|
if (!event.composedPath().includes(this.#container)) {
|
|
477
478
|
return;
|
|
478
479
|
}
|
|
479
|
-
const { key, altKey, ctrlKey, metaKey } = event;
|
|
480
|
-
if (altKey || ctrlKey || metaKey) {
|
|
480
|
+
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
481
|
+
if (altKey || ctrlKey || metaKey || shiftKey) {
|
|
481
482
|
return;
|
|
482
483
|
}
|
|
483
484
|
const { direction, typeahead, wrap } = this.#options;
|
|
@@ -540,14 +541,7 @@ var RovingTabIndex = class {
|
|
|
540
541
|
focusElement(focusable);
|
|
541
542
|
};
|
|
542
543
|
#update(active) {
|
|
543
|
-
const current =
|
|
544
|
-
...this.#getFocusables(),
|
|
545
|
-
...getFocusables(this.#container, {
|
|
546
|
-
composed: true,
|
|
547
|
-
filter: this.#selectorFilter,
|
|
548
|
-
skipNegativeTabIndexCheck: !this.#options.navigationOnly
|
|
549
|
-
})
|
|
550
|
-
]);
|
|
544
|
+
const current = new Set(this.#getFocusables());
|
|
551
545
|
for (const focusable of this.#focusables) {
|
|
552
546
|
if (current.has(focusable)) {
|
|
553
547
|
continue;
|
|
@@ -915,19 +909,12 @@ var Tabs = class _Tabs {
|
|
|
915
909
|
this.#rootElement.removeAttribute("data-tabs-initialized");
|
|
916
910
|
}
|
|
917
911
|
#initialize() {
|
|
918
|
-
this.#eventController = new AbortController();
|
|
919
|
-
const { signal } = this.#eventController;
|
|
920
912
|
saveAttributes(this.#listElements, [
|
|
921
913
|
"aria-hidden",
|
|
922
914
|
"aria-orientation",
|
|
923
915
|
"role",
|
|
924
916
|
"style"
|
|
925
917
|
]);
|
|
926
|
-
this.#listElements.forEach((list, i) => {
|
|
927
|
-
this.#settings.avoidDuplicates && i && list.setAttribute("aria-hidden", "true");
|
|
928
|
-
this.#settings.vertical && list.setAttribute("aria-orientation", "vertical");
|
|
929
|
-
list.setAttribute("role", "tablist");
|
|
930
|
-
});
|
|
931
918
|
saveAttributes(this.#tabElements, [
|
|
932
919
|
"aria-controls",
|
|
933
920
|
"id",
|
|
@@ -935,16 +922,27 @@ var Tabs = class _Tabs {
|
|
|
935
922
|
"style",
|
|
936
923
|
"tabindex"
|
|
937
924
|
]);
|
|
925
|
+
saveAttributes(this.#indicatorElements, ["style"]);
|
|
926
|
+
saveAttributes(this.#panelElements, [
|
|
927
|
+
"aria-controls",
|
|
928
|
+
"aria-labelledby",
|
|
929
|
+
"id",
|
|
930
|
+
"role",
|
|
931
|
+
"tabindex"
|
|
932
|
+
]);
|
|
933
|
+
this.#eventController = new AbortController();
|
|
934
|
+
const { signal } = this.#eventController;
|
|
935
|
+
this.#listElements.forEach((list, i) => {
|
|
936
|
+
this.#settings.avoidDuplicates && i && list.setAttribute("aria-hidden", "true");
|
|
937
|
+
this.#settings.vertical && list.setAttribute("aria-orientation", "vertical");
|
|
938
|
+
list.setAttribute("role", "tablist");
|
|
939
|
+
});
|
|
938
940
|
this.#tabElements.forEach((tab, i) => {
|
|
939
941
|
const id = Math.random().toString(36).slice(-8);
|
|
940
942
|
const panel = this.#panelElements[i % this.#panelElements.length];
|
|
941
943
|
if (!panel) {
|
|
942
944
|
return;
|
|
943
945
|
}
|
|
944
|
-
i < this.#panelElements.length && saveAttributes(
|
|
945
|
-
[panel],
|
|
946
|
-
["aria-controls", "aria-labelledby", "id", "role", "tabindex"]
|
|
947
|
-
);
|
|
948
946
|
panel.id ||= `tabs-panel-${id}`;
|
|
949
947
|
addTokenToAttribute(tab, "aria-controls", panel.id);
|
|
950
948
|
!tab.hasAttribute("aria-selected") && tab.setAttribute("aria-selected", "false");
|
|
@@ -959,7 +957,6 @@ var Tabs = class _Tabs {
|
|
|
959
957
|
tab.addEventListener("focus", this.#onTabFocus, { signal });
|
|
960
958
|
this.#buttons.push(new Button(tab));
|
|
961
959
|
});
|
|
962
|
-
saveAttributes(this.#indicatorElements, ["style"]);
|
|
963
960
|
this.#indicatorElements.forEach((indicator) => {
|
|
964
961
|
indicator.closest(this.#settings.selector.list)?.style.setProperty("position", "relative");
|
|
965
962
|
const { style } = indicator;
|
|
@@ -974,14 +971,14 @@ var Tabs = class _Tabs {
|
|
|
974
971
|
signal
|
|
975
972
|
});
|
|
976
973
|
});
|
|
974
|
+
const options = { selector: this.#settings.selector.tab, wrap: true };
|
|
977
975
|
this.#listElements.forEach((list) => {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
direction:
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
);
|
|
976
|
+
if (list.ariaOrientation !== "undefined") {
|
|
977
|
+
Object.assign(options, {
|
|
978
|
+
direction: this.#settings.vertical ? "vertical" : "horizontal"
|
|
979
|
+
});
|
|
980
|
+
}
|
|
981
|
+
this.#cleanupsRovingTabIndex.push(createRovingTabIndex(list, options));
|
|
985
982
|
list.querySelectorAll(this.#settings.selector.tab).forEach((tab) => {
|
|
986
983
|
tab.setAttribute(
|
|
987
984
|
"tabindex",
|
|
@@ -1149,7 +1146,7 @@ function isFocusable2(element) {
|
|
|
1149
1146
|
* Tabs
|
|
1150
1147
|
* WAI-ARIA compliant tabs pattern implementation in TypeScript.
|
|
1151
1148
|
*
|
|
1152
|
-
* @version 1.5.
|
|
1149
|
+
* @version 1.5.4
|
|
1153
1150
|
* @author Yusuke Kamiyamane
|
|
1154
1151
|
* @license MIT
|
|
1155
1152
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1161,7 +1158,7 @@ function isFocusable2(element) {
|
|
|
1161
1158
|
(**
|
|
1162
1159
|
* Attributes Utils
|
|
1163
1160
|
*
|
|
1164
|
-
* @version 1.0
|
|
1161
|
+
* @version 1.1.0
|
|
1165
1162
|
* @author Yusuke Kamiyamane
|
|
1166
1163
|
* @license MIT
|
|
1167
1164
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1185,7 +1182,7 @@ function isFocusable2(element) {
|
|
|
1185
1182
|
* Lightweight roving tabindex utility with fully focus management.
|
|
1186
1183
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
1187
1184
|
*
|
|
1188
|
-
* @version 2.0.
|
|
1185
|
+
* @version 2.0.4
|
|
1189
1186
|
* @author Yusuke Kamiyamane
|
|
1190
1187
|
* @license MIT
|
|
1191
1188
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1197,7 +1194,7 @@ function isFocusable2(element) {
|
|
|
1197
1194
|
(**
|
|
1198
1195
|
* Attributes Utils
|
|
1199
1196
|
*
|
|
1200
|
-
* @version 1.0
|
|
1197
|
+
* @version 1.1.0
|
|
1201
1198
|
* @author Yusuke Kamiyamane
|
|
1202
1199
|
* @license MIT
|
|
1203
1200
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1210,7 +1207,7 @@ function isFocusable2(element) {
|
|
|
1210
1207
|
* High-precision focus management utility with full composed tree support.
|
|
1211
1208
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
1212
1209
|
*
|
|
1213
|
-
* @version 4.3.
|
|
1210
|
+
* @version 4.3.1
|
|
1214
1211
|
* @author Yusuke Kamiyamane
|
|
1215
1212
|
* @license MIT
|
|
1216
1213
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -412,7 +412,7 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
412
412
|
console.warn("Invalid navigationOnly option. Fallback: false.");
|
|
413
413
|
navigationOnly = false;
|
|
414
414
|
}
|
|
415
|
-
if (typeof selector !== "undefined" && typeof selector !== "string") {
|
|
415
|
+
if (typeof selector !== "undefined" && (typeof selector !== "string" || !selector.trim())) {
|
|
416
416
|
console.warn(
|
|
417
417
|
"Invalid selector. Fallback: all focusable elements (undefined)."
|
|
418
418
|
);
|
|
@@ -426,13 +426,14 @@ function createRovingTabIndex(container, options = {}) {
|
|
|
426
426
|
console.warn("Invalid wrap option. Fallback: false.");
|
|
427
427
|
wrap = false;
|
|
428
428
|
}
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
}
|
|
429
|
+
const settings = { navigationOnly, typeahead, wrap };
|
|
430
|
+
if (direction) {
|
|
431
|
+
Object.assign(settings, { direction });
|
|
432
|
+
}
|
|
433
|
+
if (selector) {
|
|
434
|
+
Object.assign(settings, { selector });
|
|
435
|
+
}
|
|
436
|
+
const roving = new RovingTabIndex(container, settings);
|
|
436
437
|
return () => roving.destroy();
|
|
437
438
|
}
|
|
438
439
|
var RovingTabIndex = class {
|
|
@@ -474,8 +475,8 @@ var RovingTabIndex = class {
|
|
|
474
475
|
if (!event.composedPath().includes(this.#container)) {
|
|
475
476
|
return;
|
|
476
477
|
}
|
|
477
|
-
const { key, altKey, ctrlKey, metaKey } = event;
|
|
478
|
-
if (altKey || ctrlKey || metaKey) {
|
|
478
|
+
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
479
|
+
if (altKey || ctrlKey || metaKey || shiftKey) {
|
|
479
480
|
return;
|
|
480
481
|
}
|
|
481
482
|
const { direction, typeahead, wrap } = this.#options;
|
|
@@ -538,14 +539,7 @@ var RovingTabIndex = class {
|
|
|
538
539
|
focusElement(focusable);
|
|
539
540
|
};
|
|
540
541
|
#update(active) {
|
|
541
|
-
const current =
|
|
542
|
-
...this.#getFocusables(),
|
|
543
|
-
...getFocusables(this.#container, {
|
|
544
|
-
composed: true,
|
|
545
|
-
filter: this.#selectorFilter,
|
|
546
|
-
skipNegativeTabIndexCheck: !this.#options.navigationOnly
|
|
547
|
-
})
|
|
548
|
-
]);
|
|
542
|
+
const current = new Set(this.#getFocusables());
|
|
549
543
|
for (const focusable of this.#focusables) {
|
|
550
544
|
if (current.has(focusable)) {
|
|
551
545
|
continue;
|
|
@@ -913,19 +907,12 @@ var Tabs = class _Tabs {
|
|
|
913
907
|
this.#rootElement.removeAttribute("data-tabs-initialized");
|
|
914
908
|
}
|
|
915
909
|
#initialize() {
|
|
916
|
-
this.#eventController = new AbortController();
|
|
917
|
-
const { signal } = this.#eventController;
|
|
918
910
|
saveAttributes(this.#listElements, [
|
|
919
911
|
"aria-hidden",
|
|
920
912
|
"aria-orientation",
|
|
921
913
|
"role",
|
|
922
914
|
"style"
|
|
923
915
|
]);
|
|
924
|
-
this.#listElements.forEach((list, i) => {
|
|
925
|
-
this.#settings.avoidDuplicates && i && list.setAttribute("aria-hidden", "true");
|
|
926
|
-
this.#settings.vertical && list.setAttribute("aria-orientation", "vertical");
|
|
927
|
-
list.setAttribute("role", "tablist");
|
|
928
|
-
});
|
|
929
916
|
saveAttributes(this.#tabElements, [
|
|
930
917
|
"aria-controls",
|
|
931
918
|
"id",
|
|
@@ -933,16 +920,27 @@ var Tabs = class _Tabs {
|
|
|
933
920
|
"style",
|
|
934
921
|
"tabindex"
|
|
935
922
|
]);
|
|
923
|
+
saveAttributes(this.#indicatorElements, ["style"]);
|
|
924
|
+
saveAttributes(this.#panelElements, [
|
|
925
|
+
"aria-controls",
|
|
926
|
+
"aria-labelledby",
|
|
927
|
+
"id",
|
|
928
|
+
"role",
|
|
929
|
+
"tabindex"
|
|
930
|
+
]);
|
|
931
|
+
this.#eventController = new AbortController();
|
|
932
|
+
const { signal } = this.#eventController;
|
|
933
|
+
this.#listElements.forEach((list, i) => {
|
|
934
|
+
this.#settings.avoidDuplicates && i && list.setAttribute("aria-hidden", "true");
|
|
935
|
+
this.#settings.vertical && list.setAttribute("aria-orientation", "vertical");
|
|
936
|
+
list.setAttribute("role", "tablist");
|
|
937
|
+
});
|
|
936
938
|
this.#tabElements.forEach((tab, i) => {
|
|
937
939
|
const id = Math.random().toString(36).slice(-8);
|
|
938
940
|
const panel = this.#panelElements[i % this.#panelElements.length];
|
|
939
941
|
if (!panel) {
|
|
940
942
|
return;
|
|
941
943
|
}
|
|
942
|
-
i < this.#panelElements.length && saveAttributes(
|
|
943
|
-
[panel],
|
|
944
|
-
["aria-controls", "aria-labelledby", "id", "role", "tabindex"]
|
|
945
|
-
);
|
|
946
944
|
panel.id ||= `tabs-panel-${id}`;
|
|
947
945
|
addTokenToAttribute(tab, "aria-controls", panel.id);
|
|
948
946
|
!tab.hasAttribute("aria-selected") && tab.setAttribute("aria-selected", "false");
|
|
@@ -957,7 +955,6 @@ var Tabs = class _Tabs {
|
|
|
957
955
|
tab.addEventListener("focus", this.#onTabFocus, { signal });
|
|
958
956
|
this.#buttons.push(new Button(tab));
|
|
959
957
|
});
|
|
960
|
-
saveAttributes(this.#indicatorElements, ["style"]);
|
|
961
958
|
this.#indicatorElements.forEach((indicator) => {
|
|
962
959
|
indicator.closest(this.#settings.selector.list)?.style.setProperty("position", "relative");
|
|
963
960
|
const { style } = indicator;
|
|
@@ -972,14 +969,14 @@ var Tabs = class _Tabs {
|
|
|
972
969
|
signal
|
|
973
970
|
});
|
|
974
971
|
});
|
|
972
|
+
const options = { selector: this.#settings.selector.tab, wrap: true };
|
|
975
973
|
this.#listElements.forEach((list) => {
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
direction:
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
);
|
|
974
|
+
if (list.ariaOrientation !== "undefined") {
|
|
975
|
+
Object.assign(options, {
|
|
976
|
+
direction: this.#settings.vertical ? "vertical" : "horizontal"
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
this.#cleanupsRovingTabIndex.push(createRovingTabIndex(list, options));
|
|
983
980
|
list.querySelectorAll(this.#settings.selector.tab).forEach((tab) => {
|
|
984
981
|
tab.setAttribute(
|
|
985
982
|
"tabindex",
|
|
@@ -1147,7 +1144,7 @@ function isFocusable2(element) {
|
|
|
1147
1144
|
* Tabs
|
|
1148
1145
|
* WAI-ARIA compliant tabs pattern implementation in TypeScript.
|
|
1149
1146
|
*
|
|
1150
|
-
* @version 1.5.
|
|
1147
|
+
* @version 1.5.4
|
|
1151
1148
|
* @author Yusuke Kamiyamane
|
|
1152
1149
|
* @license MIT
|
|
1153
1150
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1159,7 +1156,7 @@ function isFocusable2(element) {
|
|
|
1159
1156
|
(**
|
|
1160
1157
|
* Attributes Utils
|
|
1161
1158
|
*
|
|
1162
|
-
* @version 1.0
|
|
1159
|
+
* @version 1.1.0
|
|
1163
1160
|
* @author Yusuke Kamiyamane
|
|
1164
1161
|
* @license MIT
|
|
1165
1162
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1183,7 +1180,7 @@ function isFocusable2(element) {
|
|
|
1183
1180
|
* Lightweight roving tabindex utility with fully focus management.
|
|
1184
1181
|
* Designed for accessible menus, tabs, toolbars, and composite widgets.
|
|
1185
1182
|
*
|
|
1186
|
-
* @version 2.0.
|
|
1183
|
+
* @version 2.0.4
|
|
1187
1184
|
* @author Yusuke Kamiyamane
|
|
1188
1185
|
* @license MIT
|
|
1189
1186
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1195,7 +1192,7 @@ function isFocusable2(element) {
|
|
|
1195
1192
|
(**
|
|
1196
1193
|
* Attributes Utils
|
|
1197
1194
|
*
|
|
1198
|
-
* @version 1.0
|
|
1195
|
+
* @version 1.1.0
|
|
1199
1196
|
* @author Yusuke Kamiyamane
|
|
1200
1197
|
* @license MIT
|
|
1201
1198
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -1208,7 +1205,7 @@ function isFocusable2(element) {
|
|
|
1208
1205
|
* High-precision focus management utility with full composed tree support.
|
|
1209
1206
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
1210
1207
|
*
|
|
1211
|
-
* @version 4.3.
|
|
1208
|
+
* @version 4.3.1
|
|
1212
1209
|
* @author Yusuke Kamiyamane
|
|
1213
1210
|
* @license MIT
|
|
1214
1211
|
* @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.4",
|
|
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.0
|
|
45
|
+
"@y14e/attributes-utils": "^1.1.0",
|
|
46
46
|
"@y14e/button": "^1.0.0",
|
|
47
|
-
"@y14e/roving-tabindex": "^2.0.
|
|
47
|
+
"@y14e/roving-tabindex": "^2.0.4",
|
|
48
48
|
"bun-types": "latest",
|
|
49
49
|
"tsup": "^8.0.0",
|
|
50
50
|
"typescript": "^5.6.0",
|