power-focusable 3.1.0 → 4.0.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/README.md +4 -4
- package/dist/index.cjs +10 -25
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +10 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,14 +35,14 @@ import { ... } 'https://unpkg.com/power-focusable/dist/index.js';
|
|
|
35
35
|
|
|
36
36
|
```ts
|
|
37
37
|
interface PowerFocusableOptions {
|
|
38
|
-
|
|
38
|
+
anchor?: Element | null; // default: document.activeElement
|
|
39
39
|
composed?: boolean; // default: false
|
|
40
40
|
filter?: (element: Element) => boolean; // default: () => true
|
|
41
41
|
wrap?: boolean; // default: false
|
|
42
42
|
}
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
### `
|
|
45
|
+
### `anchor`
|
|
46
46
|
|
|
47
47
|
Specifies the starting element.
|
|
48
48
|
|
|
@@ -109,7 +109,7 @@ getNextFocusable(container);
|
|
|
109
109
|
// container (optional): Element (default: <body>)
|
|
110
110
|
|
|
111
111
|
// Specifies the starting element
|
|
112
|
-
getNextFocusable(container, {
|
|
112
|
+
getNextFocusable(container, { anchor: document.querySelector('.button') });
|
|
113
113
|
|
|
114
114
|
// Traverses the composed tree (including shadow DOM; slower)
|
|
115
115
|
getNextFocusable(container, { composed: true });
|
|
@@ -132,7 +132,7 @@ getPreviousFocusable(container);
|
|
|
132
132
|
// container (optional): Element (default: <body>)
|
|
133
133
|
|
|
134
134
|
// Specifies the starting element
|
|
135
|
-
getPreviousFocusable(container, {
|
|
135
|
+
getPreviousFocusable(container, { anchor: document.querySelector('.button') });
|
|
136
136
|
|
|
137
137
|
// Traverses the composed tree (including shadow DOM; slower)
|
|
138
138
|
getPreviousFocusable(container, { composed: true });
|
package/dist/index.cjs
CHANGED
|
@@ -9,9 +9,7 @@ function createFocusTrap(container) {
|
|
|
9
9
|
focus(container);
|
|
10
10
|
if (getActiveElement() !== container) {
|
|
11
11
|
const first = getFocusables(container, { composed: true })[0];
|
|
12
|
-
|
|
13
|
-
focus(first);
|
|
14
|
-
}
|
|
12
|
+
first && focus(first);
|
|
15
13
|
}
|
|
16
14
|
function onKeyDown(event) {
|
|
17
15
|
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
@@ -121,9 +119,7 @@ function inertOutside(element) {
|
|
|
121
119
|
if (!(node instanceof Element)) {
|
|
122
120
|
return;
|
|
123
121
|
}
|
|
124
|
-
|
|
125
|
-
elements.push(node);
|
|
126
|
-
}
|
|
122
|
+
applyInert(node) && elements.push(node);
|
|
127
123
|
});
|
|
128
124
|
return () => {
|
|
129
125
|
elements.forEach((element2) => {
|
|
@@ -159,7 +155,7 @@ function isFocusable(element) {
|
|
|
159
155
|
}
|
|
160
156
|
function getRelativeFocusable(container, offset, options) {
|
|
161
157
|
const {
|
|
162
|
-
|
|
158
|
+
anchor = getActiveElement(),
|
|
163
159
|
composed = false,
|
|
164
160
|
filter = () => true,
|
|
165
161
|
wrap = false
|
|
@@ -169,13 +165,13 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
169
165
|
if (!length) {
|
|
170
166
|
return null;
|
|
171
167
|
}
|
|
172
|
-
if (!
|
|
168
|
+
if (!anchor || !containsComposed(container, anchor)) {
|
|
173
169
|
return null;
|
|
174
170
|
}
|
|
175
|
-
if (!(
|
|
171
|
+
if (!(anchor instanceof Element)) {
|
|
176
172
|
return null;
|
|
177
173
|
}
|
|
178
|
-
const currentIndex = focusables.indexOf(
|
|
174
|
+
const currentIndex = focusables.indexOf(anchor);
|
|
179
175
|
if (currentIndex === -1) {
|
|
180
176
|
return null;
|
|
181
177
|
}
|
|
@@ -335,9 +331,7 @@ function applyInert(element) {
|
|
|
335
331
|
}
|
|
336
332
|
const count = inertRefCounts.get(element) ?? 0;
|
|
337
333
|
inertRefCounts.set(element, count + 1);
|
|
338
|
-
|
|
339
|
-
setInert(element, true);
|
|
340
|
-
}
|
|
334
|
+
count === 0 && element.toggleAttribute("inert", true);
|
|
341
335
|
return true;
|
|
342
336
|
}
|
|
343
337
|
function restoreInert(element) {
|
|
@@ -347,15 +341,13 @@ function restoreInert(element) {
|
|
|
347
341
|
}
|
|
348
342
|
if (count === 1) {
|
|
349
343
|
inertRefCounts.delete(element);
|
|
350
|
-
|
|
344
|
+
element.toggleAttribute("inert", false);
|
|
351
345
|
return;
|
|
352
346
|
}
|
|
353
347
|
inertRefCounts.set(element, count - 1);
|
|
354
348
|
}
|
|
355
349
|
function focus(element) {
|
|
356
|
-
|
|
357
|
-
element.focus();
|
|
358
|
-
}
|
|
350
|
+
"focus" in element && typeof element.focus === "function" && element.focus();
|
|
359
351
|
}
|
|
360
352
|
function getActiveElement() {
|
|
361
353
|
let current = document.activeElement;
|
|
@@ -400,20 +392,13 @@ function isInert(element) {
|
|
|
400
392
|
function isUngroupedRadio(element) {
|
|
401
393
|
return element instanceof HTMLInputElement && element.type === "radio" && !!element.name;
|
|
402
394
|
}
|
|
403
|
-
function setInert(element, boolean) {
|
|
404
|
-
if (boolean) {
|
|
405
|
-
element.setAttribute("inert", "");
|
|
406
|
-
} else {
|
|
407
|
-
element.removeAttribute("inert");
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
395
|
/**
|
|
411
396
|
* Power Focusable
|
|
412
397
|
* High-precision focus management utility with full composed tree support.
|
|
413
398
|
* Handles complex focus rules including tabindex ordering, radio groups, inert,
|
|
414
399
|
* and shadow DOM.
|
|
415
400
|
*
|
|
416
|
-
* @version
|
|
401
|
+
* @version 4.0.0
|
|
417
402
|
* @author Yusuke Kamiyamane
|
|
418
403
|
* @license MIT
|
|
419
404
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
|
@@ -4,23 +4,23 @@
|
|
|
4
4
|
* Handles complex focus rules including tabindex ordering, radio groups, inert,
|
|
5
5
|
* and shadow DOM.
|
|
6
6
|
*
|
|
7
|
-
* @version
|
|
7
|
+
* @version 4.0.0
|
|
8
8
|
* @author Yusuke Kamiyamane
|
|
9
9
|
* @license MIT
|
|
10
10
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
11
11
|
* @see {@link https://github.com/y14e/power-focusable}
|
|
12
12
|
*/
|
|
13
13
|
interface PowerFocusableOptions {
|
|
14
|
-
readonly
|
|
14
|
+
readonly anchor?: Element | null;
|
|
15
15
|
readonly composed?: boolean;
|
|
16
16
|
readonly filter?: (element: Element) => boolean;
|
|
17
17
|
readonly wrap?: boolean;
|
|
18
18
|
}
|
|
19
19
|
declare function createFocusTrap(container: Element): () => void;
|
|
20
|
-
declare function getFocusables(container?: Element, options?: Omit<PowerFocusableOptions, '
|
|
20
|
+
declare function getFocusables(container?: Element, options?: Omit<PowerFocusableOptions, 'anchor' | 'wrap'>): Element[];
|
|
21
21
|
declare function getNextFocusable(container?: Element, options?: PowerFocusableOptions): Element | null;
|
|
22
22
|
declare function getPreviousFocusable(container?: Element, options?: PowerFocusableOptions): Element | null;
|
|
23
|
-
declare function hasFocusable(container?: Element, options?: Omit<PowerFocusableOptions, '
|
|
23
|
+
declare function hasFocusable(container?: Element, options?: Omit<PowerFocusableOptions, 'anchor' | 'wrap'>): boolean;
|
|
24
24
|
declare function inertOutside(element: Element): () => void;
|
|
25
25
|
declare function isFocusable(element: Element): boolean;
|
|
26
26
|
|
package/dist/index.d.ts
CHANGED
|
@@ -4,23 +4,23 @@
|
|
|
4
4
|
* Handles complex focus rules including tabindex ordering, radio groups, inert,
|
|
5
5
|
* and shadow DOM.
|
|
6
6
|
*
|
|
7
|
-
* @version
|
|
7
|
+
* @version 4.0.0
|
|
8
8
|
* @author Yusuke Kamiyamane
|
|
9
9
|
* @license MIT
|
|
10
10
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
11
11
|
* @see {@link https://github.com/y14e/power-focusable}
|
|
12
12
|
*/
|
|
13
13
|
interface PowerFocusableOptions {
|
|
14
|
-
readonly
|
|
14
|
+
readonly anchor?: Element | null;
|
|
15
15
|
readonly composed?: boolean;
|
|
16
16
|
readonly filter?: (element: Element) => boolean;
|
|
17
17
|
readonly wrap?: boolean;
|
|
18
18
|
}
|
|
19
19
|
declare function createFocusTrap(container: Element): () => void;
|
|
20
|
-
declare function getFocusables(container?: Element, options?: Omit<PowerFocusableOptions, '
|
|
20
|
+
declare function getFocusables(container?: Element, options?: Omit<PowerFocusableOptions, 'anchor' | 'wrap'>): Element[];
|
|
21
21
|
declare function getNextFocusable(container?: Element, options?: PowerFocusableOptions): Element | null;
|
|
22
22
|
declare function getPreviousFocusable(container?: Element, options?: PowerFocusableOptions): Element | null;
|
|
23
|
-
declare function hasFocusable(container?: Element, options?: Omit<PowerFocusableOptions, '
|
|
23
|
+
declare function hasFocusable(container?: Element, options?: Omit<PowerFocusableOptions, 'anchor' | 'wrap'>): boolean;
|
|
24
24
|
declare function inertOutside(element: Element): () => void;
|
|
25
25
|
declare function isFocusable(element: Element): boolean;
|
|
26
26
|
|
package/dist/index.js
CHANGED
|
@@ -7,9 +7,7 @@ function createFocusTrap(container) {
|
|
|
7
7
|
focus(container);
|
|
8
8
|
if (getActiveElement() !== container) {
|
|
9
9
|
const first = getFocusables(container, { composed: true })[0];
|
|
10
|
-
|
|
11
|
-
focus(first);
|
|
12
|
-
}
|
|
10
|
+
first && focus(first);
|
|
13
11
|
}
|
|
14
12
|
function onKeyDown(event) {
|
|
15
13
|
const { key, altKey, ctrlKey, metaKey, shiftKey } = event;
|
|
@@ -119,9 +117,7 @@ function inertOutside(element) {
|
|
|
119
117
|
if (!(node instanceof Element)) {
|
|
120
118
|
return;
|
|
121
119
|
}
|
|
122
|
-
|
|
123
|
-
elements.push(node);
|
|
124
|
-
}
|
|
120
|
+
applyInert(node) && elements.push(node);
|
|
125
121
|
});
|
|
126
122
|
return () => {
|
|
127
123
|
elements.forEach((element2) => {
|
|
@@ -157,7 +153,7 @@ function isFocusable(element) {
|
|
|
157
153
|
}
|
|
158
154
|
function getRelativeFocusable(container, offset, options) {
|
|
159
155
|
const {
|
|
160
|
-
|
|
156
|
+
anchor = getActiveElement(),
|
|
161
157
|
composed = false,
|
|
162
158
|
filter = () => true,
|
|
163
159
|
wrap = false
|
|
@@ -167,13 +163,13 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
167
163
|
if (!length) {
|
|
168
164
|
return null;
|
|
169
165
|
}
|
|
170
|
-
if (!
|
|
166
|
+
if (!anchor || !containsComposed(container, anchor)) {
|
|
171
167
|
return null;
|
|
172
168
|
}
|
|
173
|
-
if (!(
|
|
169
|
+
if (!(anchor instanceof Element)) {
|
|
174
170
|
return null;
|
|
175
171
|
}
|
|
176
|
-
const currentIndex = focusables.indexOf(
|
|
172
|
+
const currentIndex = focusables.indexOf(anchor);
|
|
177
173
|
if (currentIndex === -1) {
|
|
178
174
|
return null;
|
|
179
175
|
}
|
|
@@ -333,9 +329,7 @@ function applyInert(element) {
|
|
|
333
329
|
}
|
|
334
330
|
const count = inertRefCounts.get(element) ?? 0;
|
|
335
331
|
inertRefCounts.set(element, count + 1);
|
|
336
|
-
|
|
337
|
-
setInert(element, true);
|
|
338
|
-
}
|
|
332
|
+
count === 0 && element.toggleAttribute("inert", true);
|
|
339
333
|
return true;
|
|
340
334
|
}
|
|
341
335
|
function restoreInert(element) {
|
|
@@ -345,15 +339,13 @@ function restoreInert(element) {
|
|
|
345
339
|
}
|
|
346
340
|
if (count === 1) {
|
|
347
341
|
inertRefCounts.delete(element);
|
|
348
|
-
|
|
342
|
+
element.toggleAttribute("inert", false);
|
|
349
343
|
return;
|
|
350
344
|
}
|
|
351
345
|
inertRefCounts.set(element, count - 1);
|
|
352
346
|
}
|
|
353
347
|
function focus(element) {
|
|
354
|
-
|
|
355
|
-
element.focus();
|
|
356
|
-
}
|
|
348
|
+
"focus" in element && typeof element.focus === "function" && element.focus();
|
|
357
349
|
}
|
|
358
350
|
function getActiveElement() {
|
|
359
351
|
let current = document.activeElement;
|
|
@@ -398,20 +390,13 @@ function isInert(element) {
|
|
|
398
390
|
function isUngroupedRadio(element) {
|
|
399
391
|
return element instanceof HTMLInputElement && element.type === "radio" && !!element.name;
|
|
400
392
|
}
|
|
401
|
-
function setInert(element, boolean) {
|
|
402
|
-
if (boolean) {
|
|
403
|
-
element.setAttribute("inert", "");
|
|
404
|
-
} else {
|
|
405
|
-
element.removeAttribute("inert");
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
393
|
/**
|
|
409
394
|
* Power Focusable
|
|
410
395
|
* High-precision focus management utility with full composed tree support.
|
|
411
396
|
* Handles complex focus rules including tabindex ordering, radio groups, inert,
|
|
412
397
|
* and shadow DOM.
|
|
413
398
|
*
|
|
414
|
-
* @version
|
|
399
|
+
* @version 4.0.0
|
|
415
400
|
* @author Yusuke Kamiyamane
|
|
416
401
|
* @license MIT
|
|
417
402
|
* @copyright Copyright (c) Yusuke Kamiyamane
|