@y14e/portal 1.0.0 → 1.0.2
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 +44 -18
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +44 -18
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -7,9 +7,18 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
7
7
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
8
8
|
container = document.body;
|
|
9
9
|
}
|
|
10
|
-
const { composed = false
|
|
10
|
+
const { composed = false } = options;
|
|
11
|
+
let { filter, include } = options;
|
|
12
|
+
if (filter && typeof filter !== "function") {
|
|
13
|
+
console.warn("Invalid filter function. Fallback: undefined.");
|
|
14
|
+
filter = void 0;
|
|
15
|
+
}
|
|
16
|
+
if (include && typeof include !== "function") {
|
|
17
|
+
console.warn("Invalid include function. Fallback: undefined.");
|
|
18
|
+
include = void 0;
|
|
19
|
+
}
|
|
11
20
|
const elements = [];
|
|
12
|
-
if (composed ||
|
|
21
|
+
if (composed || include) {
|
|
13
22
|
let traverse2 = function(node) {
|
|
14
23
|
if (node instanceof Element) {
|
|
15
24
|
if (isFocusable(node) || include?.(node)) {
|
|
@@ -38,7 +47,8 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
38
47
|
}
|
|
39
48
|
}
|
|
40
49
|
}
|
|
41
|
-
|
|
50
|
+
const unfiltered = normalizeRadioGroup(sortByTabIndex(elements));
|
|
51
|
+
return filter ? unfiltered.filter(filter) : unfiltered;
|
|
42
52
|
}
|
|
43
53
|
function getNextFocusable(container = document.body, options = {}) {
|
|
44
54
|
if (!(container instanceof Element)) {
|
|
@@ -81,22 +91,25 @@ function isFocusable(element) {
|
|
|
81
91
|
return true;
|
|
82
92
|
}
|
|
83
93
|
function getRelativeFocusable(container, offset, options) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
let anchor = options.anchor ?? getActiveElement();
|
|
95
|
+
const { composed = false, filter, include, wrap = false } = options;
|
|
96
|
+
if (!(anchor instanceof Element)) {
|
|
97
|
+
const active = getActiveElement();
|
|
98
|
+
if (active instanceof Element) {
|
|
99
|
+
console.warn("Invalid anchor element. Fallback: active element.");
|
|
100
|
+
anchor = active;
|
|
101
|
+
} else {
|
|
102
|
+
console.warn("Invalid anchor element");
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
95
105
|
}
|
|
96
|
-
if (!
|
|
106
|
+
if (!containsComposed(container, anchor)) {
|
|
107
|
+
console.warn("Mismatch elements");
|
|
97
108
|
return null;
|
|
98
109
|
}
|
|
99
|
-
|
|
110
|
+
const focusables = getFocusables(container, { composed, filter, include });
|
|
111
|
+
const { length } = focusables;
|
|
112
|
+
if (!length) {
|
|
100
113
|
return null;
|
|
101
114
|
}
|
|
102
115
|
const currentIndex = focusables.indexOf(anchor);
|
|
@@ -262,6 +275,9 @@ function createPortal(host, container = document.body) {
|
|
|
262
275
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
263
276
|
container = document.body;
|
|
264
277
|
}
|
|
278
|
+
if (!containsComposed2(container, host)) {
|
|
279
|
+
throw new Error("Mismatch elements");
|
|
280
|
+
}
|
|
265
281
|
const portal = new Portal(host, container);
|
|
266
282
|
return () => portal.destroy();
|
|
267
283
|
}
|
|
@@ -394,6 +410,16 @@ var Portal = class {
|
|
|
394
410
|
focusable && focus(focusable);
|
|
395
411
|
}
|
|
396
412
|
};
|
|
413
|
+
function containsComposed2(container, element) {
|
|
414
|
+
let current = element;
|
|
415
|
+
while (current) {
|
|
416
|
+
if (current === container) {
|
|
417
|
+
return true;
|
|
418
|
+
}
|
|
419
|
+
current = current instanceof ShadowRoot ? current.mode === "open" ? current.host : null : current.parentNode;
|
|
420
|
+
}
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
397
423
|
function focus(element) {
|
|
398
424
|
"focus" in element && typeof element.focus === "function" && element.focus();
|
|
399
425
|
}
|
|
@@ -409,7 +435,7 @@ function getActiveElement2() {
|
|
|
409
435
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
410
436
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
411
437
|
*
|
|
412
|
-
* @version 1.0.
|
|
438
|
+
* @version 1.0.2
|
|
413
439
|
* @author Yusuke Kamiyamane
|
|
414
440
|
* @license MIT
|
|
415
441
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -423,7 +449,7 @@ power-focusable/dist/index.js:
|
|
|
423
449
|
* High-precision focus management utility with full composed tree support.
|
|
424
450
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
425
451
|
*
|
|
426
|
-
* @version 4.1.
|
|
452
|
+
* @version 4.1.3
|
|
427
453
|
* @author Yusuke Kamiyamane
|
|
428
454
|
* @license MIT
|
|
429
455
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
4
4
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
5
5
|
*
|
|
6
|
-
* @version 1.0.
|
|
6
|
+
* @version 1.0.2
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
4
4
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
5
5
|
*
|
|
6
|
-
* @version 1.0.
|
|
6
|
+
* @version 1.0.2
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.js
CHANGED
|
@@ -5,9 +5,18 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
5
5
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
6
6
|
container = document.body;
|
|
7
7
|
}
|
|
8
|
-
const { composed = false
|
|
8
|
+
const { composed = false } = options;
|
|
9
|
+
let { filter, include } = options;
|
|
10
|
+
if (filter && typeof filter !== "function") {
|
|
11
|
+
console.warn("Invalid filter function. Fallback: undefined.");
|
|
12
|
+
filter = void 0;
|
|
13
|
+
}
|
|
14
|
+
if (include && typeof include !== "function") {
|
|
15
|
+
console.warn("Invalid include function. Fallback: undefined.");
|
|
16
|
+
include = void 0;
|
|
17
|
+
}
|
|
9
18
|
const elements = [];
|
|
10
|
-
if (composed ||
|
|
19
|
+
if (composed || include) {
|
|
11
20
|
let traverse2 = function(node) {
|
|
12
21
|
if (node instanceof Element) {
|
|
13
22
|
if (isFocusable(node) || include?.(node)) {
|
|
@@ -36,7 +45,8 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
36
45
|
}
|
|
37
46
|
}
|
|
38
47
|
}
|
|
39
|
-
|
|
48
|
+
const unfiltered = normalizeRadioGroup(sortByTabIndex(elements));
|
|
49
|
+
return filter ? unfiltered.filter(filter) : unfiltered;
|
|
40
50
|
}
|
|
41
51
|
function getNextFocusable(container = document.body, options = {}) {
|
|
42
52
|
if (!(container instanceof Element)) {
|
|
@@ -79,22 +89,25 @@ function isFocusable(element) {
|
|
|
79
89
|
return true;
|
|
80
90
|
}
|
|
81
91
|
function getRelativeFocusable(container, offset, options) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
let anchor = options.anchor ?? getActiveElement();
|
|
93
|
+
const { composed = false, filter, include, wrap = false } = options;
|
|
94
|
+
if (!(anchor instanceof Element)) {
|
|
95
|
+
const active = getActiveElement();
|
|
96
|
+
if (active instanceof Element) {
|
|
97
|
+
console.warn("Invalid anchor element. Fallback: active element.");
|
|
98
|
+
anchor = active;
|
|
99
|
+
} else {
|
|
100
|
+
console.warn("Invalid anchor element");
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
93
103
|
}
|
|
94
|
-
if (!
|
|
104
|
+
if (!containsComposed(container, anchor)) {
|
|
105
|
+
console.warn("Mismatch elements");
|
|
95
106
|
return null;
|
|
96
107
|
}
|
|
97
|
-
|
|
108
|
+
const focusables = getFocusables(container, { composed, filter, include });
|
|
109
|
+
const { length } = focusables;
|
|
110
|
+
if (!length) {
|
|
98
111
|
return null;
|
|
99
112
|
}
|
|
100
113
|
const currentIndex = focusables.indexOf(anchor);
|
|
@@ -260,6 +273,9 @@ function createPortal(host, container = document.body) {
|
|
|
260
273
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
261
274
|
container = document.body;
|
|
262
275
|
}
|
|
276
|
+
if (!containsComposed2(container, host)) {
|
|
277
|
+
throw new Error("Mismatch elements");
|
|
278
|
+
}
|
|
263
279
|
const portal = new Portal(host, container);
|
|
264
280
|
return () => portal.destroy();
|
|
265
281
|
}
|
|
@@ -392,6 +408,16 @@ var Portal = class {
|
|
|
392
408
|
focusable && focus(focusable);
|
|
393
409
|
}
|
|
394
410
|
};
|
|
411
|
+
function containsComposed2(container, element) {
|
|
412
|
+
let current = element;
|
|
413
|
+
while (current) {
|
|
414
|
+
if (current === container) {
|
|
415
|
+
return true;
|
|
416
|
+
}
|
|
417
|
+
current = current instanceof ShadowRoot ? current.mode === "open" ? current.host : null : current.parentNode;
|
|
418
|
+
}
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
395
421
|
function focus(element) {
|
|
396
422
|
"focus" in element && typeof element.focus === "function" && element.focus();
|
|
397
423
|
}
|
|
@@ -407,7 +433,7 @@ function getActiveElement2() {
|
|
|
407
433
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
408
434
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
409
435
|
*
|
|
410
|
-
* @version 1.0.
|
|
436
|
+
* @version 1.0.2
|
|
411
437
|
* @author Yusuke Kamiyamane
|
|
412
438
|
* @license MIT
|
|
413
439
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -421,7 +447,7 @@ power-focusable/dist/index.js:
|
|
|
421
447
|
* High-precision focus management utility with full composed tree support.
|
|
422
448
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
423
449
|
*
|
|
424
|
-
* @version 4.1.
|
|
450
|
+
* @version 4.1.3
|
|
425
451
|
* @author Yusuke Kamiyamane
|
|
426
452
|
* @license MIT
|
|
427
453
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y14e/portal",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Lightweight DOM portal (teleport) utility with fully focus management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"homepage": "https://github.com/y14e/portal#readme",
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"bun-types": "latest",
|
|
51
|
-
"power-focusable": "^4.1.
|
|
51
|
+
"power-focusable": "^4.1.3",
|
|
52
52
|
"tsup": "^8.0.0",
|
|
53
53
|
"typescript": "^5.6.0"
|
|
54
54
|
},
|