@y14e/portal 1.2.14 → 1.2.15
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 +33 -47
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +33 -47
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,14 +10,14 @@ npm i @y14e/portal
|
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
12
|
// npm
|
|
13
|
-
import { createPortal } from '@y14e/portal@1.2.
|
|
13
|
+
import { createPortal } from '@y14e/portal@1.2.15';
|
|
14
14
|
|
|
15
15
|
// CDNs
|
|
16
|
-
import { createPortal } from 'https://esm.sh/@y14e/portal@1.2.
|
|
16
|
+
import { createPortal } from 'https://esm.sh/@y14e/portal@1.2.15';
|
|
17
17
|
// or
|
|
18
|
-
import { createPortal } from 'https://cdn.jsdelivr.net/npm/@y14e/portal@1.2.
|
|
18
|
+
import { createPortal } from 'https://cdn.jsdelivr.net/npm/@y14e/portal@1.2.15/+esm';
|
|
19
19
|
// or
|
|
20
|
-
import { createPortal } from 'https://esm.unpkg.com/@y14e/portal@1.2.
|
|
20
|
+
import { createPortal } from 'https://esm.unpkg.com/@y14e/portal@1.2.15';
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## 📦 APIs
|
package/dist/index.cjs
CHANGED
|
@@ -68,21 +68,16 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
68
68
|
const elements = [];
|
|
69
69
|
if (composed || include) {
|
|
70
70
|
let traverse2 = function(node) {
|
|
71
|
-
if (node instanceof Element) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
elements[elements.length] = node;
|
|
77
|
-
}
|
|
71
|
+
if (!(node instanceof Element)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
|
|
75
|
+
elements[elements.length] = node;
|
|
78
76
|
}
|
|
79
77
|
const children = getComposedChildren(node);
|
|
80
78
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
81
79
|
const child = children[i];
|
|
82
|
-
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
traverse2(child);
|
|
80
|
+
child && traverse2(child);
|
|
86
81
|
}
|
|
87
82
|
};
|
|
88
83
|
traverse2(container);
|
|
@@ -90,10 +85,7 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
90
85
|
const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
|
|
91
86
|
for (let i = 0, l = candidates.length; i < l; i++) {
|
|
92
87
|
const candidate = candidates[i];
|
|
93
|
-
if (
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (isFocusable(candidate, {
|
|
88
|
+
if (candidate && isFocusable(candidate, {
|
|
97
89
|
skipNegativeTabIndexCheck,
|
|
98
90
|
skipVisibilityCheck
|
|
99
91
|
})) {
|
|
@@ -280,23 +272,19 @@ function normalizeRadioGroup(elements) {
|
|
|
280
272
|
for (const group of map.values()) {
|
|
281
273
|
placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
|
|
282
274
|
}
|
|
283
|
-
return elements.filter(
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
}
|
|
287
|
-
return true;
|
|
288
|
-
});
|
|
275
|
+
return elements.filter(
|
|
276
|
+
(element) => isUngroupedRadio(element) ? placeholder.has(element) : true
|
|
277
|
+
);
|
|
289
278
|
}
|
|
290
279
|
function sortByTabIndex(elements) {
|
|
291
280
|
const ordered = [];
|
|
292
281
|
const natural = [];
|
|
293
282
|
for (let i = 0, l = elements.length; i < l; i++) {
|
|
294
283
|
const element = elements[i];
|
|
295
|
-
if (
|
|
296
|
-
|
|
284
|
+
if (element) {
|
|
285
|
+
const target = getTabIndex(element) > 0 ? ordered : natural;
|
|
286
|
+
target[target.length] = element;
|
|
297
287
|
}
|
|
298
|
-
const target = getTabIndex(element) > 0 ? ordered : natural;
|
|
299
|
-
target[target.length] = element;
|
|
300
288
|
}
|
|
301
289
|
ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
|
|
302
290
|
let count = 0;
|
|
@@ -314,8 +302,9 @@ function containsComposed(container, element) {
|
|
|
314
302
|
while (current) {
|
|
315
303
|
if (current === container) {
|
|
316
304
|
return true;
|
|
305
|
+
} else {
|
|
306
|
+
current = current instanceof ShadowRoot ? current.mode === "open" ? current.host : null : current.parentNode;
|
|
317
307
|
}
|
|
318
|
-
current = current instanceof ShadowRoot ? current.mode === "open" ? current.host : null : current.parentNode;
|
|
319
308
|
}
|
|
320
309
|
return false;
|
|
321
310
|
}
|
|
@@ -501,18 +490,17 @@ var Portal = class {
|
|
|
501
490
|
}
|
|
502
491
|
this.#update();
|
|
503
492
|
const focusables = this.#getFocusables();
|
|
504
|
-
if (
|
|
493
|
+
if (focusables.length) {
|
|
494
|
+
const index = focusables.indexOf(active);
|
|
495
|
+
if (index !== -1) {
|
|
496
|
+
event.preventDefault();
|
|
497
|
+
const focusable = focusables[index + (shiftKey ? -1 : 1)];
|
|
498
|
+
focusable ? focusElement(focusable) : this.#focusSentinel(shiftKey);
|
|
499
|
+
}
|
|
500
|
+
} else {
|
|
505
501
|
event.preventDefault();
|
|
506
502
|
this.#moveFocus(shiftKey ? "previous" : "next");
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
const index = focusables.indexOf(active);
|
|
510
|
-
if (index === -1) {
|
|
511
|
-
return;
|
|
512
503
|
}
|
|
513
|
-
event.preventDefault();
|
|
514
|
-
const focusable = focusables[index + (shiftKey ? -1 : 1)];
|
|
515
|
-
focusable ? focusElement(focusable) : this.#focusSentinel(shiftKey);
|
|
516
504
|
};
|
|
517
505
|
#update() {
|
|
518
506
|
const current = /* @__PURE__ */ new Set([
|
|
@@ -520,19 +508,17 @@ var Portal = class {
|
|
|
520
508
|
...getFocusables(this.#host, { composed: true })
|
|
521
509
|
]);
|
|
522
510
|
for (const focusable of this.#focusables) {
|
|
523
|
-
if (current.has(focusable)) {
|
|
524
|
-
|
|
511
|
+
if (!current.has(focusable)) {
|
|
512
|
+
focusable.isConnected && restoreAttributes([focusable]);
|
|
513
|
+
this.#focusables.delete(focusable);
|
|
525
514
|
}
|
|
526
|
-
focusable.isConnected && restoreAttributes([focusable]);
|
|
527
|
-
this.#focusables.delete(focusable);
|
|
528
515
|
}
|
|
529
516
|
for (const focusable of current) {
|
|
530
|
-
if (this.#focusables.has(focusable)) {
|
|
531
|
-
|
|
517
|
+
if (!this.#focusables.has(focusable)) {
|
|
518
|
+
this.#focusables.add(focusable);
|
|
519
|
+
saveAttributes([focusable], ["tabindex"]);
|
|
520
|
+
focusable.setAttribute("tabindex", "-1");
|
|
532
521
|
}
|
|
533
|
-
this.#focusables.add(focusable);
|
|
534
|
-
saveAttributes([focusable], ["tabindex"]);
|
|
535
|
-
focusable.setAttribute("tabindex", "-1");
|
|
536
522
|
}
|
|
537
523
|
}
|
|
538
524
|
#createSentinel() {
|
|
@@ -589,7 +575,7 @@ function getActiveElement2() {
|
|
|
589
575
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
590
576
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
591
577
|
*
|
|
592
|
-
* @version 1.2.
|
|
578
|
+
* @version 1.2.15
|
|
593
579
|
* @author Yusuke Kamiyamane
|
|
594
580
|
* @license MIT
|
|
595
581
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -601,7 +587,7 @@ function getActiveElement2() {
|
|
|
601
587
|
(**
|
|
602
588
|
* Attributes Utils
|
|
603
589
|
*
|
|
604
|
-
* @version 1.1.
|
|
590
|
+
* @version 1.1.2
|
|
605
591
|
* @author Yusuke Kamiyamane
|
|
606
592
|
* @license MIT
|
|
607
593
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -614,7 +600,7 @@ power-focusable/dist/index.js:
|
|
|
614
600
|
* High-precision focus management utility with full composed tree support.
|
|
615
601
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
616
602
|
*
|
|
617
|
-
* @version 4.3.
|
|
603
|
+
* @version 4.3.3
|
|
618
604
|
* @author Yusuke Kamiyamane
|
|
619
605
|
* @license MIT
|
|
620
606
|
* @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.15
|
|
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.15
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.js
CHANGED
|
@@ -66,21 +66,16 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
66
66
|
const elements = [];
|
|
67
67
|
if (composed || include) {
|
|
68
68
|
let traverse2 = function(node) {
|
|
69
|
-
if (node instanceof Element) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
elements[elements.length] = node;
|
|
75
|
-
}
|
|
69
|
+
if (!(node instanceof Element)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (isFocusable(node, { skipNegativeTabIndexCheck, skipVisibilityCheck }) || include?.(node)) {
|
|
73
|
+
elements[elements.length] = node;
|
|
76
74
|
}
|
|
77
75
|
const children = getComposedChildren(node);
|
|
78
76
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
79
77
|
const child = children[i];
|
|
80
|
-
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
traverse2(child);
|
|
78
|
+
child && traverse2(child);
|
|
84
79
|
}
|
|
85
80
|
};
|
|
86
81
|
traverse2(container);
|
|
@@ -88,10 +83,7 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
88
83
|
const candidates = container.querySelectorAll(FOCUSABLE_SELECTOR);
|
|
89
84
|
for (let i = 0, l = candidates.length; i < l; i++) {
|
|
90
85
|
const candidate = candidates[i];
|
|
91
|
-
if (
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
if (isFocusable(candidate, {
|
|
86
|
+
if (candidate && isFocusable(candidate, {
|
|
95
87
|
skipNegativeTabIndexCheck,
|
|
96
88
|
skipVisibilityCheck
|
|
97
89
|
})) {
|
|
@@ -278,23 +270,19 @@ function normalizeRadioGroup(elements) {
|
|
|
278
270
|
for (const group of map.values()) {
|
|
279
271
|
placeholder.add(group.find((radio) => radio.checked) ?? group[0]);
|
|
280
272
|
}
|
|
281
|
-
return elements.filter(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
return true;
|
|
286
|
-
});
|
|
273
|
+
return elements.filter(
|
|
274
|
+
(element) => isUngroupedRadio(element) ? placeholder.has(element) : true
|
|
275
|
+
);
|
|
287
276
|
}
|
|
288
277
|
function sortByTabIndex(elements) {
|
|
289
278
|
const ordered = [];
|
|
290
279
|
const natural = [];
|
|
291
280
|
for (let i = 0, l = elements.length; i < l; i++) {
|
|
292
281
|
const element = elements[i];
|
|
293
|
-
if (
|
|
294
|
-
|
|
282
|
+
if (element) {
|
|
283
|
+
const target = getTabIndex(element) > 0 ? ordered : natural;
|
|
284
|
+
target[target.length] = element;
|
|
295
285
|
}
|
|
296
|
-
const target = getTabIndex(element) > 0 ? ordered : natural;
|
|
297
|
-
target[target.length] = element;
|
|
298
286
|
}
|
|
299
287
|
ordered.sort((a, b) => getTabIndex(a) - getTabIndex(b));
|
|
300
288
|
let count = 0;
|
|
@@ -312,8 +300,9 @@ function containsComposed(container, element) {
|
|
|
312
300
|
while (current) {
|
|
313
301
|
if (current === container) {
|
|
314
302
|
return true;
|
|
303
|
+
} else {
|
|
304
|
+
current = current instanceof ShadowRoot ? current.mode === "open" ? current.host : null : current.parentNode;
|
|
315
305
|
}
|
|
316
|
-
current = current instanceof ShadowRoot ? current.mode === "open" ? current.host : null : current.parentNode;
|
|
317
306
|
}
|
|
318
307
|
return false;
|
|
319
308
|
}
|
|
@@ -499,18 +488,17 @@ var Portal = class {
|
|
|
499
488
|
}
|
|
500
489
|
this.#update();
|
|
501
490
|
const focusables = this.#getFocusables();
|
|
502
|
-
if (
|
|
491
|
+
if (focusables.length) {
|
|
492
|
+
const index = focusables.indexOf(active);
|
|
493
|
+
if (index !== -1) {
|
|
494
|
+
event.preventDefault();
|
|
495
|
+
const focusable = focusables[index + (shiftKey ? -1 : 1)];
|
|
496
|
+
focusable ? focusElement(focusable) : this.#focusSentinel(shiftKey);
|
|
497
|
+
}
|
|
498
|
+
} else {
|
|
503
499
|
event.preventDefault();
|
|
504
500
|
this.#moveFocus(shiftKey ? "previous" : "next");
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
const index = focusables.indexOf(active);
|
|
508
|
-
if (index === -1) {
|
|
509
|
-
return;
|
|
510
501
|
}
|
|
511
|
-
event.preventDefault();
|
|
512
|
-
const focusable = focusables[index + (shiftKey ? -1 : 1)];
|
|
513
|
-
focusable ? focusElement(focusable) : this.#focusSentinel(shiftKey);
|
|
514
502
|
};
|
|
515
503
|
#update() {
|
|
516
504
|
const current = /* @__PURE__ */ new Set([
|
|
@@ -518,19 +506,17 @@ var Portal = class {
|
|
|
518
506
|
...getFocusables(this.#host, { composed: true })
|
|
519
507
|
]);
|
|
520
508
|
for (const focusable of this.#focusables) {
|
|
521
|
-
if (current.has(focusable)) {
|
|
522
|
-
|
|
509
|
+
if (!current.has(focusable)) {
|
|
510
|
+
focusable.isConnected && restoreAttributes([focusable]);
|
|
511
|
+
this.#focusables.delete(focusable);
|
|
523
512
|
}
|
|
524
|
-
focusable.isConnected && restoreAttributes([focusable]);
|
|
525
|
-
this.#focusables.delete(focusable);
|
|
526
513
|
}
|
|
527
514
|
for (const focusable of current) {
|
|
528
|
-
if (this.#focusables.has(focusable)) {
|
|
529
|
-
|
|
515
|
+
if (!this.#focusables.has(focusable)) {
|
|
516
|
+
this.#focusables.add(focusable);
|
|
517
|
+
saveAttributes([focusable], ["tabindex"]);
|
|
518
|
+
focusable.setAttribute("tabindex", "-1");
|
|
530
519
|
}
|
|
531
|
-
this.#focusables.add(focusable);
|
|
532
|
-
saveAttributes([focusable], ["tabindex"]);
|
|
533
|
-
focusable.setAttribute("tabindex", "-1");
|
|
534
520
|
}
|
|
535
521
|
}
|
|
536
522
|
#createSentinel() {
|
|
@@ -587,7 +573,7 @@ function getActiveElement2() {
|
|
|
587
573
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
588
574
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
589
575
|
*
|
|
590
|
-
* @version 1.2.
|
|
576
|
+
* @version 1.2.15
|
|
591
577
|
* @author Yusuke Kamiyamane
|
|
592
578
|
* @license MIT
|
|
593
579
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -599,7 +585,7 @@ function getActiveElement2() {
|
|
|
599
585
|
(**
|
|
600
586
|
* Attributes Utils
|
|
601
587
|
*
|
|
602
|
-
* @version 1.1.
|
|
588
|
+
* @version 1.1.2
|
|
603
589
|
* @author Yusuke Kamiyamane
|
|
604
590
|
* @license MIT
|
|
605
591
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -612,7 +598,7 @@ power-focusable/dist/index.js:
|
|
|
612
598
|
* High-precision focus management utility with full composed tree support.
|
|
613
599
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
614
600
|
*
|
|
615
|
-
* @version 4.3.
|
|
601
|
+
* @version 4.3.3
|
|
616
602
|
* @author Yusuke Kamiyamane
|
|
617
603
|
* @license MIT
|
|
618
604
|
* @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.15",
|
|
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.1.
|
|
50
|
+
"@y14e/attributes-utils": "^1.1.2",
|
|
51
51
|
"bun-types": "latest",
|
|
52
|
-
"power-focusable": "^4.3.
|
|
52
|
+
"power-focusable": "^4.3.3",
|
|
53
53
|
"tsup": "^8.0.0",
|
|
54
54
|
"typescript": "^5.6.0"
|
|
55
55
|
},
|