@lessonkit/accessibility 1.3.0 → 1.4.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.
- package/dist/index.cjs +34 -5
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +34 -5
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -93,7 +93,23 @@ function focusFirst(container) {
|
|
|
93
93
|
}
|
|
94
94
|
function getFocusableElements(container) {
|
|
95
95
|
const candidates = Array.from(container.querySelectorAll(FOCUSABLE_SELECTORS));
|
|
96
|
-
return candidates.filter(
|
|
96
|
+
return candidates.filter(
|
|
97
|
+
(n) => isHTMLElement(n) && !n.hasAttribute("disabled") && isVisibleFocusable(n)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
function isVisibleFocusable(el) {
|
|
101
|
+
if (el.closest("[inert], [aria-hidden='true']")) return false;
|
|
102
|
+
if (typeof el.checkVisibility === "function") {
|
|
103
|
+
try {
|
|
104
|
+
return el.checkVisibility();
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (typeof window !== "undefined" && typeof window.getComputedStyle === "function") {
|
|
109
|
+
const style = window.getComputedStyle(el);
|
|
110
|
+
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
111
|
+
}
|
|
112
|
+
return true;
|
|
97
113
|
}
|
|
98
114
|
function trapFocus(container, opts) {
|
|
99
115
|
const restoreFocus = opts?.restoreFocus ?? true;
|
|
@@ -180,28 +196,41 @@ function createRovingTabIndex(opts) {
|
|
|
180
196
|
const loop = opts.loop ?? true;
|
|
181
197
|
const orientation = opts.orientation ?? "both";
|
|
182
198
|
let activeIndex = clampIndex(opts.initialIndex ?? 0, itemCount);
|
|
199
|
+
const focusActiveItem = () => {
|
|
200
|
+
if (!opts.getId || typeof document === "undefined") return;
|
|
201
|
+
const id = opts.getId(activeIndex);
|
|
202
|
+
if (!id) return;
|
|
203
|
+
document.getElementById(id)?.focus();
|
|
204
|
+
};
|
|
205
|
+
const notifyActiveChange = () => {
|
|
206
|
+
opts.onActiveIndexChange?.(activeIndex);
|
|
207
|
+
};
|
|
183
208
|
const setActiveIndex = (next) => {
|
|
184
209
|
activeIndex = clampIndex(next, itemCount);
|
|
210
|
+
notifyActiveChange();
|
|
211
|
+
focusActiveItem();
|
|
185
212
|
};
|
|
186
213
|
const move = (delta) => {
|
|
187
214
|
if (!itemCount) return;
|
|
188
215
|
const next = activeIndex + delta;
|
|
189
216
|
if (loop) {
|
|
190
217
|
activeIndex = (next % itemCount + itemCount) % itemCount;
|
|
191
|
-
|
|
218
|
+
} else {
|
|
219
|
+
activeIndex = clampIndex(next, itemCount);
|
|
192
220
|
}
|
|
193
|
-
|
|
221
|
+
notifyActiveChange();
|
|
222
|
+
focusActiveItem();
|
|
194
223
|
};
|
|
195
224
|
const onKeyDown = (e) => {
|
|
196
225
|
if (!itemCount) return;
|
|
197
226
|
switch (e.key) {
|
|
198
227
|
case "Home":
|
|
199
228
|
e.preventDefault();
|
|
200
|
-
|
|
229
|
+
setActiveIndex(0);
|
|
201
230
|
return;
|
|
202
231
|
case "End":
|
|
203
232
|
e.preventDefault();
|
|
204
|
-
|
|
233
|
+
setActiveIndex(itemCount - 1);
|
|
205
234
|
return;
|
|
206
235
|
case "ArrowLeft":
|
|
207
236
|
if (orientation === "vertical") return;
|
package/dist/index.d.cts
CHANGED
|
@@ -23,6 +23,8 @@ type RovingTabIndexOptions = {
|
|
|
23
23
|
orientation?: "horizontal" | "vertical" | "both";
|
|
24
24
|
loop?: boolean;
|
|
25
25
|
initialIndex?: number;
|
|
26
|
+
/** Called when the active index changes so consumers can re-render. */
|
|
27
|
+
onActiveIndexChange?: (index: number) => void;
|
|
26
28
|
};
|
|
27
29
|
/** Screen-reader-only styles (no external CSS required). */
|
|
28
30
|
declare const visuallyHiddenStyle: VisuallyHiddenStyle;
|
package/dist/index.d.ts
CHANGED
|
@@ -23,6 +23,8 @@ type RovingTabIndexOptions = {
|
|
|
23
23
|
orientation?: "horizontal" | "vertical" | "both";
|
|
24
24
|
loop?: boolean;
|
|
25
25
|
initialIndex?: number;
|
|
26
|
+
/** Called when the active index changes so consumers can re-render. */
|
|
27
|
+
onActiveIndexChange?: (index: number) => void;
|
|
26
28
|
};
|
|
27
29
|
/** Screen-reader-only styles (no external CSS required). */
|
|
28
30
|
declare const visuallyHiddenStyle: VisuallyHiddenStyle;
|
package/dist/index.js
CHANGED
|
@@ -60,7 +60,23 @@ function focusFirst(container) {
|
|
|
60
60
|
}
|
|
61
61
|
function getFocusableElements(container) {
|
|
62
62
|
const candidates = Array.from(container.querySelectorAll(FOCUSABLE_SELECTORS));
|
|
63
|
-
return candidates.filter(
|
|
63
|
+
return candidates.filter(
|
|
64
|
+
(n) => isHTMLElement(n) && !n.hasAttribute("disabled") && isVisibleFocusable(n)
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
function isVisibleFocusable(el) {
|
|
68
|
+
if (el.closest("[inert], [aria-hidden='true']")) return false;
|
|
69
|
+
if (typeof el.checkVisibility === "function") {
|
|
70
|
+
try {
|
|
71
|
+
return el.checkVisibility();
|
|
72
|
+
} catch {
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (typeof window !== "undefined" && typeof window.getComputedStyle === "function") {
|
|
76
|
+
const style = window.getComputedStyle(el);
|
|
77
|
+
if (style.display === "none" || style.visibility === "hidden") return false;
|
|
78
|
+
}
|
|
79
|
+
return true;
|
|
64
80
|
}
|
|
65
81
|
function trapFocus(container, opts) {
|
|
66
82
|
const restoreFocus = opts?.restoreFocus ?? true;
|
|
@@ -147,28 +163,41 @@ function createRovingTabIndex(opts) {
|
|
|
147
163
|
const loop = opts.loop ?? true;
|
|
148
164
|
const orientation = opts.orientation ?? "both";
|
|
149
165
|
let activeIndex = clampIndex(opts.initialIndex ?? 0, itemCount);
|
|
166
|
+
const focusActiveItem = () => {
|
|
167
|
+
if (!opts.getId || typeof document === "undefined") return;
|
|
168
|
+
const id = opts.getId(activeIndex);
|
|
169
|
+
if (!id) return;
|
|
170
|
+
document.getElementById(id)?.focus();
|
|
171
|
+
};
|
|
172
|
+
const notifyActiveChange = () => {
|
|
173
|
+
opts.onActiveIndexChange?.(activeIndex);
|
|
174
|
+
};
|
|
150
175
|
const setActiveIndex = (next) => {
|
|
151
176
|
activeIndex = clampIndex(next, itemCount);
|
|
177
|
+
notifyActiveChange();
|
|
178
|
+
focusActiveItem();
|
|
152
179
|
};
|
|
153
180
|
const move = (delta) => {
|
|
154
181
|
if (!itemCount) return;
|
|
155
182
|
const next = activeIndex + delta;
|
|
156
183
|
if (loop) {
|
|
157
184
|
activeIndex = (next % itemCount + itemCount) % itemCount;
|
|
158
|
-
|
|
185
|
+
} else {
|
|
186
|
+
activeIndex = clampIndex(next, itemCount);
|
|
159
187
|
}
|
|
160
|
-
|
|
188
|
+
notifyActiveChange();
|
|
189
|
+
focusActiveItem();
|
|
161
190
|
};
|
|
162
191
|
const onKeyDown = (e) => {
|
|
163
192
|
if (!itemCount) return;
|
|
164
193
|
switch (e.key) {
|
|
165
194
|
case "Home":
|
|
166
195
|
e.preventDefault();
|
|
167
|
-
|
|
196
|
+
setActiveIndex(0);
|
|
168
197
|
return;
|
|
169
198
|
case "End":
|
|
170
199
|
e.preventDefault();
|
|
171
|
-
|
|
200
|
+
setActiveIndex(itemCount - 1);
|
|
172
201
|
return;
|
|
173
202
|
case "ArrowLeft":
|
|
174
203
|
if (orientation === "vertical") return;
|