@y14e/portal 1.2.7 → 1.2.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 -7
- package/dist/index.cjs +86 -30
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +86 -30
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
Lightweight DOM portal (teleport) utility with fully focus management. Designed for accessible dialogs, menus, overlays, popovers.
|
|
4
4
|
|
|
5
|
-
> [!NOTE]
|
|
6
|
-
> Focus traversal works across portals using invisible sentinels and composed-tree-aware focus detection powered by [Power Focusable](https://github.com/y14e/power-focusable).
|
|
7
|
-
|
|
8
5
|
## Install
|
|
9
6
|
|
|
10
7
|
```bash
|
|
@@ -13,14 +10,14 @@ npm i @y14e/portal
|
|
|
13
10
|
|
|
14
11
|
```ts
|
|
15
12
|
// npm
|
|
16
|
-
import { createPortal } from '@y14e/portal';
|
|
13
|
+
import { createPortal } from '@y14e/portal@1.2.9';
|
|
17
14
|
|
|
18
15
|
// CDNs
|
|
19
|
-
import { createPortal } from 'https://esm.sh/@y14e/portal'
|
|
16
|
+
import { createPortal } from 'https://esm.sh/@y14e/portal@1.2.9';
|
|
20
17
|
// or
|
|
21
|
-
import { createPortal } from 'https://cdn.jsdelivr.net/npm/@y14e/portal/+esm';
|
|
18
|
+
import { createPortal } from 'https://cdn.jsdelivr.net/npm/@y14e/portal@1.2.9/+esm';
|
|
22
19
|
// or
|
|
23
|
-
import { createPortal } from 'https://unpkg.com/@y14e/portal
|
|
20
|
+
import { createPortal } from 'https://esm.unpkg.com/@y14e/portal@1.2.9';
|
|
24
21
|
```
|
|
25
22
|
|
|
26
23
|
## 📦 APIs
|
package/dist/index.cjs
CHANGED
|
@@ -34,24 +34,45 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
34
34
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
35
35
|
container = document.body;
|
|
36
36
|
}
|
|
37
|
-
let {
|
|
37
|
+
let {
|
|
38
|
+
composed = false,
|
|
39
|
+
filter,
|
|
40
|
+
include,
|
|
41
|
+
skipNegativeTabIndexCheck = false,
|
|
42
|
+
skipVisibilityCheck = false
|
|
43
|
+
} = options;
|
|
38
44
|
if (typeof composed !== "boolean") {
|
|
39
|
-
console.warn("Invalid composed. Fallback: false.");
|
|
45
|
+
console.warn("Invalid composed option. Fallback: false.");
|
|
40
46
|
composed = false;
|
|
41
47
|
}
|
|
42
48
|
if (typeof filter !== "undefined" && typeof filter !== "function") {
|
|
43
|
-
console.warn(
|
|
49
|
+
console.warn(
|
|
50
|
+
"Invalid filter function. Fallback: no filter function (undefined)."
|
|
51
|
+
);
|
|
44
52
|
filter = void 0;
|
|
45
53
|
}
|
|
46
54
|
if (typeof include !== "undefined" && typeof include !== "function") {
|
|
47
|
-
console.warn(
|
|
55
|
+
console.warn(
|
|
56
|
+
"Invalid include function. Fallback: no include function (undefined)."
|
|
57
|
+
);
|
|
48
58
|
include = void 0;
|
|
49
59
|
}
|
|
60
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
61
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
62
|
+
skipNegativeTabIndexCheck = false;
|
|
63
|
+
}
|
|
64
|
+
if (typeof skipVisibilityCheck !== "boolean") {
|
|
65
|
+
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
66
|
+
skipVisibilityCheck = false;
|
|
67
|
+
}
|
|
50
68
|
const elements = [];
|
|
51
69
|
if (composed || include) {
|
|
52
70
|
let traverse2 = function(node) {
|
|
53
71
|
if (node instanceof Element) {
|
|
54
|
-
if (isFocusable(node
|
|
72
|
+
if (isFocusable(node, {
|
|
73
|
+
skipNegativeTabIndexCheck,
|
|
74
|
+
skipVisibilityCheck
|
|
75
|
+
}) || include?.(node)) {
|
|
55
76
|
elements[elements.length] = node;
|
|
56
77
|
}
|
|
57
78
|
}
|
|
@@ -72,7 +93,10 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
72
93
|
if (!(candidate instanceof Element)) {
|
|
73
94
|
continue;
|
|
74
95
|
}
|
|
75
|
-
if (isFocusable(candidate
|
|
96
|
+
if (isFocusable(candidate, {
|
|
97
|
+
skipNegativeTabIndexCheck,
|
|
98
|
+
skipVisibilityCheck
|
|
99
|
+
})) {
|
|
76
100
|
elements[elements.length] = candidate;
|
|
77
101
|
}
|
|
78
102
|
}
|
|
@@ -86,24 +110,35 @@ function getNextFocusable(container = document.body, options = {}) {
|
|
|
86
110
|
function getPreviousFocusable(container = document.body, options = {}) {
|
|
87
111
|
return getRelativeFocusable(container, -1, options);
|
|
88
112
|
}
|
|
89
|
-
function isFocusable(element) {
|
|
113
|
+
function isFocusable(element, options = {}) {
|
|
90
114
|
if (!(element instanceof Element)) {
|
|
91
115
|
console.warn("Invalid element");
|
|
92
116
|
return false;
|
|
93
117
|
}
|
|
118
|
+
let { skipNegativeTabIndexCheck = false, skipVisibilityCheck = false } = options;
|
|
119
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
120
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
121
|
+
skipNegativeTabIndexCheck = false;
|
|
122
|
+
}
|
|
123
|
+
if (typeof skipVisibilityCheck !== "boolean") {
|
|
124
|
+
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
125
|
+
skipVisibilityCheck = false;
|
|
126
|
+
}
|
|
94
127
|
if (element.hasAttribute("hidden") || isInert(element)) {
|
|
95
128
|
return false;
|
|
96
129
|
}
|
|
97
|
-
if (getTabIndex(element) < 0) {
|
|
130
|
+
if (!skipNegativeTabIndexCheck && getTabIndex(element) < 0) {
|
|
98
131
|
return false;
|
|
99
132
|
}
|
|
100
|
-
if (!element.matches(
|
|
133
|
+
if (!element.matches(
|
|
134
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR.replace(/(,\s*)?\[tabindex="-1"\]/g, "") : FOCUSABLE_SELECTOR
|
|
135
|
+
)) {
|
|
101
136
|
return false;
|
|
102
137
|
}
|
|
103
138
|
if (isDisabledDeep(element)) {
|
|
104
139
|
return false;
|
|
105
140
|
}
|
|
106
|
-
if (!element.checkVisibility({
|
|
141
|
+
if (!skipVisibilityCheck && !element.checkVisibility({
|
|
107
142
|
contentVisibilityAuto: true,
|
|
108
143
|
opacityProperty: true,
|
|
109
144
|
visibilityProperty: true
|
|
@@ -122,6 +157,8 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
122
157
|
composed = false,
|
|
123
158
|
filter,
|
|
124
159
|
include,
|
|
160
|
+
skipNegativeTabIndexCheck = false,
|
|
161
|
+
skipVisibilityCheck = false,
|
|
125
162
|
wrap = false
|
|
126
163
|
} = options;
|
|
127
164
|
if (!(anchor instanceof Element)) {
|
|
@@ -139,22 +176,41 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
139
176
|
return null;
|
|
140
177
|
}
|
|
141
178
|
if (typeof composed !== "boolean") {
|
|
142
|
-
console.warn("Invalid composed. Fallback: false.");
|
|
179
|
+
console.warn("Invalid composed option. Fallback: false.");
|
|
143
180
|
composed = false;
|
|
144
181
|
}
|
|
145
182
|
if (typeof filter !== "undefined" && typeof filter !== "function") {
|
|
146
|
-
console.warn(
|
|
183
|
+
console.warn(
|
|
184
|
+
"Invalid filter function. Fallback: no filter function (undefined)."
|
|
185
|
+
);
|
|
147
186
|
filter = void 0;
|
|
148
187
|
}
|
|
149
188
|
if (typeof include !== "undefined" && typeof include !== "function") {
|
|
150
|
-
console.warn(
|
|
189
|
+
console.warn(
|
|
190
|
+
"Invalid include function. Fallback: no include function (undefined)."
|
|
191
|
+
);
|
|
151
192
|
include = void 0;
|
|
152
193
|
}
|
|
194
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
195
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
196
|
+
skipNegativeTabIndexCheck = false;
|
|
197
|
+
}
|
|
198
|
+
if (typeof skipVisibilityCheck !== "boolean") {
|
|
199
|
+
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
200
|
+
skipVisibilityCheck = false;
|
|
201
|
+
}
|
|
153
202
|
if (typeof wrap !== "boolean") {
|
|
154
|
-
console.warn("Invalid wrap. Fallback: false.");
|
|
203
|
+
console.warn("Invalid wrap option. Fallback: false.");
|
|
155
204
|
wrap = false;
|
|
156
205
|
}
|
|
157
|
-
const
|
|
206
|
+
const settings = { composed, skipNegativeTabIndexCheck, skipVisibilityCheck };
|
|
207
|
+
if (filter !== void 0) {
|
|
208
|
+
Object.assign(settings, { filter });
|
|
209
|
+
}
|
|
210
|
+
if (include !== void 0) {
|
|
211
|
+
Object.assign(settings, { include });
|
|
212
|
+
}
|
|
213
|
+
const focusables = getFocusables(container, settings);
|
|
158
214
|
const { length } = focusables;
|
|
159
215
|
if (!length) {
|
|
160
216
|
return null;
|
|
@@ -392,19 +448,21 @@ var Portal = class {
|
|
|
392
448
|
if (current === this.#entranceSentinel) {
|
|
393
449
|
if (this.#host.contains(before)) {
|
|
394
450
|
this.#moveFocus("previous");
|
|
395
|
-
|
|
396
|
-
this.#update();
|
|
397
|
-
const first = [...this.#focusables][0];
|
|
398
|
-
first && focusElement(first);
|
|
451
|
+
return;
|
|
399
452
|
}
|
|
400
|
-
|
|
453
|
+
this.#update();
|
|
454
|
+
const first = [...this.#focusables][0];
|
|
455
|
+
first && focusElement(first);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
if (current === this.#exitSentinel) {
|
|
401
459
|
if (this.#host.contains(before)) {
|
|
402
460
|
this.#moveFocus("next");
|
|
403
|
-
|
|
404
|
-
this.#update();
|
|
405
|
-
const last = [...this.#focusables].at(-1);
|
|
406
|
-
last && focusElement(last);
|
|
461
|
+
return;
|
|
407
462
|
}
|
|
463
|
+
this.#update();
|
|
464
|
+
const last = [...this.#focusables].at(-1);
|
|
465
|
+
last && focusElement(last);
|
|
408
466
|
}
|
|
409
467
|
};
|
|
410
468
|
#onKeyDown = (event) => {
|
|
@@ -443,9 +501,7 @@ var Portal = class {
|
|
|
443
501
|
if (current.has(focusable)) {
|
|
444
502
|
continue;
|
|
445
503
|
}
|
|
446
|
-
|
|
447
|
-
restoreAttributes([focusable]);
|
|
448
|
-
}
|
|
504
|
+
focusable.isConnected && restoreAttributes([focusable]);
|
|
449
505
|
this.#focusables.delete(focusable);
|
|
450
506
|
}
|
|
451
507
|
for (const focusable of current) {
|
|
@@ -510,7 +566,7 @@ function getActiveElement2() {
|
|
|
510
566
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
511
567
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
512
568
|
*
|
|
513
|
-
* @version 1.2.
|
|
569
|
+
* @version 1.2.9
|
|
514
570
|
* @author Yusuke Kamiyamane
|
|
515
571
|
* @license MIT
|
|
516
572
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -522,7 +578,7 @@ function getActiveElement2() {
|
|
|
522
578
|
(**
|
|
523
579
|
* Attributes Utils
|
|
524
580
|
*
|
|
525
|
-
* @version 1.0
|
|
581
|
+
* @version 1.1.0
|
|
526
582
|
* @author Yusuke Kamiyamane
|
|
527
583
|
* @license MIT
|
|
528
584
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -535,7 +591,7 @@ power-focusable/dist/index.js:
|
|
|
535
591
|
* High-precision focus management utility with full composed tree support.
|
|
536
592
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
537
593
|
*
|
|
538
|
-
* @version 4.1
|
|
594
|
+
* @version 4.3.1
|
|
539
595
|
* @author Yusuke Kamiyamane
|
|
540
596
|
* @license MIT
|
|
541
597
|
* @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.2.
|
|
6
|
+
* @version 1.2.9
|
|
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.2.
|
|
6
|
+
* @version 1.2.9
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.js
CHANGED
|
@@ -32,24 +32,45 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
32
32
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
33
33
|
container = document.body;
|
|
34
34
|
}
|
|
35
|
-
let {
|
|
35
|
+
let {
|
|
36
|
+
composed = false,
|
|
37
|
+
filter,
|
|
38
|
+
include,
|
|
39
|
+
skipNegativeTabIndexCheck = false,
|
|
40
|
+
skipVisibilityCheck = false
|
|
41
|
+
} = options;
|
|
36
42
|
if (typeof composed !== "boolean") {
|
|
37
|
-
console.warn("Invalid composed. Fallback: false.");
|
|
43
|
+
console.warn("Invalid composed option. Fallback: false.");
|
|
38
44
|
composed = false;
|
|
39
45
|
}
|
|
40
46
|
if (typeof filter !== "undefined" && typeof filter !== "function") {
|
|
41
|
-
console.warn(
|
|
47
|
+
console.warn(
|
|
48
|
+
"Invalid filter function. Fallback: no filter function (undefined)."
|
|
49
|
+
);
|
|
42
50
|
filter = void 0;
|
|
43
51
|
}
|
|
44
52
|
if (typeof include !== "undefined" && typeof include !== "function") {
|
|
45
|
-
console.warn(
|
|
53
|
+
console.warn(
|
|
54
|
+
"Invalid include function. Fallback: no include function (undefined)."
|
|
55
|
+
);
|
|
46
56
|
include = void 0;
|
|
47
57
|
}
|
|
58
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
59
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
60
|
+
skipNegativeTabIndexCheck = false;
|
|
61
|
+
}
|
|
62
|
+
if (typeof skipVisibilityCheck !== "boolean") {
|
|
63
|
+
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
64
|
+
skipVisibilityCheck = false;
|
|
65
|
+
}
|
|
48
66
|
const elements = [];
|
|
49
67
|
if (composed || include) {
|
|
50
68
|
let traverse2 = function(node) {
|
|
51
69
|
if (node instanceof Element) {
|
|
52
|
-
if (isFocusable(node
|
|
70
|
+
if (isFocusable(node, {
|
|
71
|
+
skipNegativeTabIndexCheck,
|
|
72
|
+
skipVisibilityCheck
|
|
73
|
+
}) || include?.(node)) {
|
|
53
74
|
elements[elements.length] = node;
|
|
54
75
|
}
|
|
55
76
|
}
|
|
@@ -70,7 +91,10 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
70
91
|
if (!(candidate instanceof Element)) {
|
|
71
92
|
continue;
|
|
72
93
|
}
|
|
73
|
-
if (isFocusable(candidate
|
|
94
|
+
if (isFocusable(candidate, {
|
|
95
|
+
skipNegativeTabIndexCheck,
|
|
96
|
+
skipVisibilityCheck
|
|
97
|
+
})) {
|
|
74
98
|
elements[elements.length] = candidate;
|
|
75
99
|
}
|
|
76
100
|
}
|
|
@@ -84,24 +108,35 @@ function getNextFocusable(container = document.body, options = {}) {
|
|
|
84
108
|
function getPreviousFocusable(container = document.body, options = {}) {
|
|
85
109
|
return getRelativeFocusable(container, -1, options);
|
|
86
110
|
}
|
|
87
|
-
function isFocusable(element) {
|
|
111
|
+
function isFocusable(element, options = {}) {
|
|
88
112
|
if (!(element instanceof Element)) {
|
|
89
113
|
console.warn("Invalid element");
|
|
90
114
|
return false;
|
|
91
115
|
}
|
|
116
|
+
let { skipNegativeTabIndexCheck = false, skipVisibilityCheck = false } = options;
|
|
117
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
118
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
119
|
+
skipNegativeTabIndexCheck = false;
|
|
120
|
+
}
|
|
121
|
+
if (typeof skipVisibilityCheck !== "boolean") {
|
|
122
|
+
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
123
|
+
skipVisibilityCheck = false;
|
|
124
|
+
}
|
|
92
125
|
if (element.hasAttribute("hidden") || isInert(element)) {
|
|
93
126
|
return false;
|
|
94
127
|
}
|
|
95
|
-
if (getTabIndex(element) < 0) {
|
|
128
|
+
if (!skipNegativeTabIndexCheck && getTabIndex(element) < 0) {
|
|
96
129
|
return false;
|
|
97
130
|
}
|
|
98
|
-
if (!element.matches(
|
|
131
|
+
if (!element.matches(
|
|
132
|
+
skipNegativeTabIndexCheck ? FOCUSABLE_SELECTOR.replace(/(,\s*)?\[tabindex="-1"\]/g, "") : FOCUSABLE_SELECTOR
|
|
133
|
+
)) {
|
|
99
134
|
return false;
|
|
100
135
|
}
|
|
101
136
|
if (isDisabledDeep(element)) {
|
|
102
137
|
return false;
|
|
103
138
|
}
|
|
104
|
-
if (!element.checkVisibility({
|
|
139
|
+
if (!skipVisibilityCheck && !element.checkVisibility({
|
|
105
140
|
contentVisibilityAuto: true,
|
|
106
141
|
opacityProperty: true,
|
|
107
142
|
visibilityProperty: true
|
|
@@ -120,6 +155,8 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
120
155
|
composed = false,
|
|
121
156
|
filter,
|
|
122
157
|
include,
|
|
158
|
+
skipNegativeTabIndexCheck = false,
|
|
159
|
+
skipVisibilityCheck = false,
|
|
123
160
|
wrap = false
|
|
124
161
|
} = options;
|
|
125
162
|
if (!(anchor instanceof Element)) {
|
|
@@ -137,22 +174,41 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
137
174
|
return null;
|
|
138
175
|
}
|
|
139
176
|
if (typeof composed !== "boolean") {
|
|
140
|
-
console.warn("Invalid composed. Fallback: false.");
|
|
177
|
+
console.warn("Invalid composed option. Fallback: false.");
|
|
141
178
|
composed = false;
|
|
142
179
|
}
|
|
143
180
|
if (typeof filter !== "undefined" && typeof filter !== "function") {
|
|
144
|
-
console.warn(
|
|
181
|
+
console.warn(
|
|
182
|
+
"Invalid filter function. Fallback: no filter function (undefined)."
|
|
183
|
+
);
|
|
145
184
|
filter = void 0;
|
|
146
185
|
}
|
|
147
186
|
if (typeof include !== "undefined" && typeof include !== "function") {
|
|
148
|
-
console.warn(
|
|
187
|
+
console.warn(
|
|
188
|
+
"Invalid include function. Fallback: no include function (undefined)."
|
|
189
|
+
);
|
|
149
190
|
include = void 0;
|
|
150
191
|
}
|
|
192
|
+
if (typeof skipNegativeTabIndexCheck !== "boolean") {
|
|
193
|
+
console.warn("Invalid skipNegativeTabIndexCheck option. Fallback: false.");
|
|
194
|
+
skipNegativeTabIndexCheck = false;
|
|
195
|
+
}
|
|
196
|
+
if (typeof skipVisibilityCheck !== "boolean") {
|
|
197
|
+
console.warn("Invalid skipVisibilityCheck option. Fallback: false.");
|
|
198
|
+
skipVisibilityCheck = false;
|
|
199
|
+
}
|
|
151
200
|
if (typeof wrap !== "boolean") {
|
|
152
|
-
console.warn("Invalid wrap. Fallback: false.");
|
|
201
|
+
console.warn("Invalid wrap option. Fallback: false.");
|
|
153
202
|
wrap = false;
|
|
154
203
|
}
|
|
155
|
-
const
|
|
204
|
+
const settings = { composed, skipNegativeTabIndexCheck, skipVisibilityCheck };
|
|
205
|
+
if (filter !== void 0) {
|
|
206
|
+
Object.assign(settings, { filter });
|
|
207
|
+
}
|
|
208
|
+
if (include !== void 0) {
|
|
209
|
+
Object.assign(settings, { include });
|
|
210
|
+
}
|
|
211
|
+
const focusables = getFocusables(container, settings);
|
|
156
212
|
const { length } = focusables;
|
|
157
213
|
if (!length) {
|
|
158
214
|
return null;
|
|
@@ -390,19 +446,21 @@ var Portal = class {
|
|
|
390
446
|
if (current === this.#entranceSentinel) {
|
|
391
447
|
if (this.#host.contains(before)) {
|
|
392
448
|
this.#moveFocus("previous");
|
|
393
|
-
|
|
394
|
-
this.#update();
|
|
395
|
-
const first = [...this.#focusables][0];
|
|
396
|
-
first && focusElement(first);
|
|
449
|
+
return;
|
|
397
450
|
}
|
|
398
|
-
|
|
451
|
+
this.#update();
|
|
452
|
+
const first = [...this.#focusables][0];
|
|
453
|
+
first && focusElement(first);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
if (current === this.#exitSentinel) {
|
|
399
457
|
if (this.#host.contains(before)) {
|
|
400
458
|
this.#moveFocus("next");
|
|
401
|
-
|
|
402
|
-
this.#update();
|
|
403
|
-
const last = [...this.#focusables].at(-1);
|
|
404
|
-
last && focusElement(last);
|
|
459
|
+
return;
|
|
405
460
|
}
|
|
461
|
+
this.#update();
|
|
462
|
+
const last = [...this.#focusables].at(-1);
|
|
463
|
+
last && focusElement(last);
|
|
406
464
|
}
|
|
407
465
|
};
|
|
408
466
|
#onKeyDown = (event) => {
|
|
@@ -441,9 +499,7 @@ var Portal = class {
|
|
|
441
499
|
if (current.has(focusable)) {
|
|
442
500
|
continue;
|
|
443
501
|
}
|
|
444
|
-
|
|
445
|
-
restoreAttributes([focusable]);
|
|
446
|
-
}
|
|
502
|
+
focusable.isConnected && restoreAttributes([focusable]);
|
|
447
503
|
this.#focusables.delete(focusable);
|
|
448
504
|
}
|
|
449
505
|
for (const focusable of current) {
|
|
@@ -508,7 +564,7 @@ function getActiveElement2() {
|
|
|
508
564
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
509
565
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
510
566
|
*
|
|
511
|
-
* @version 1.2.
|
|
567
|
+
* @version 1.2.9
|
|
512
568
|
* @author Yusuke Kamiyamane
|
|
513
569
|
* @license MIT
|
|
514
570
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -520,7 +576,7 @@ function getActiveElement2() {
|
|
|
520
576
|
(**
|
|
521
577
|
* Attributes Utils
|
|
522
578
|
*
|
|
523
|
-
* @version 1.0
|
|
579
|
+
* @version 1.1.0
|
|
524
580
|
* @author Yusuke Kamiyamane
|
|
525
581
|
* @license MIT
|
|
526
582
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -533,7 +589,7 @@ power-focusable/dist/index.js:
|
|
|
533
589
|
* High-precision focus management utility with full composed tree support.
|
|
534
590
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
535
591
|
*
|
|
536
|
-
* @version 4.1
|
|
592
|
+
* @version 4.3.1
|
|
537
593
|
* @author Yusuke Kamiyamane
|
|
538
594
|
* @license MIT
|
|
539
595
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@y14e/portal",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"description": "Lightweight DOM portal (teleport) utility with fully focus management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -47,9 +47,9 @@
|
|
|
47
47
|
},
|
|
48
48
|
"homepage": "https://github.com/y14e/portal#readme",
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@y14e/attributes-utils": "^1.0
|
|
50
|
+
"@y14e/attributes-utils": "^1.1.0",
|
|
51
51
|
"bun-types": "latest",
|
|
52
|
-
"power-focusable": "^4.1
|
|
52
|
+
"power-focusable": "^4.3.1",
|
|
53
53
|
"tsup": "^8.0.0",
|
|
54
54
|
"typescript": "^5.6.0"
|
|
55
55
|
},
|