@y14e/portal 1.2.14 → 1.2.16
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 +34 -51
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +34 -51
- 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.16';
|
|
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.16';
|
|
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.16/+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.16';
|
|
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
|
}
|
|
@@ -466,9 +455,7 @@ var Portal = class {
|
|
|
466
455
|
});
|
|
467
456
|
next && focusElement(next);
|
|
468
457
|
}
|
|
469
|
-
|
|
470
|
-
}
|
|
471
|
-
if (current === this.#exitSentinel) {
|
|
458
|
+
} else if (current === this.#exitSentinel) {
|
|
472
459
|
if (this.#host.contains(before)) {
|
|
473
460
|
this.#moveFocus("next");
|
|
474
461
|
return;
|
|
@@ -484,7 +471,6 @@ var Portal = class {
|
|
|
484
471
|
});
|
|
485
472
|
previous && focusElement(previous);
|
|
486
473
|
}
|
|
487
|
-
return;
|
|
488
474
|
}
|
|
489
475
|
};
|
|
490
476
|
#onKeyDown = (event) => {
|
|
@@ -501,18 +487,17 @@ var Portal = class {
|
|
|
501
487
|
}
|
|
502
488
|
this.#update();
|
|
503
489
|
const focusables = this.#getFocusables();
|
|
504
|
-
if (
|
|
490
|
+
if (focusables.length) {
|
|
491
|
+
const index = focusables.indexOf(active);
|
|
492
|
+
if (index !== -1) {
|
|
493
|
+
event.preventDefault();
|
|
494
|
+
const focusable = focusables[index + (shiftKey ? -1 : 1)];
|
|
495
|
+
focusable ? focusElement(focusable) : this.#focusSentinel(shiftKey);
|
|
496
|
+
}
|
|
497
|
+
} else {
|
|
505
498
|
event.preventDefault();
|
|
506
499
|
this.#moveFocus(shiftKey ? "previous" : "next");
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
const index = focusables.indexOf(active);
|
|
510
|
-
if (index === -1) {
|
|
511
|
-
return;
|
|
512
500
|
}
|
|
513
|
-
event.preventDefault();
|
|
514
|
-
const focusable = focusables[index + (shiftKey ? -1 : 1)];
|
|
515
|
-
focusable ? focusElement(focusable) : this.#focusSentinel(shiftKey);
|
|
516
501
|
};
|
|
517
502
|
#update() {
|
|
518
503
|
const current = /* @__PURE__ */ new Set([
|
|
@@ -520,19 +505,17 @@ var Portal = class {
|
|
|
520
505
|
...getFocusables(this.#host, { composed: true })
|
|
521
506
|
]);
|
|
522
507
|
for (const focusable of this.#focusables) {
|
|
523
|
-
if (current.has(focusable)) {
|
|
524
|
-
|
|
508
|
+
if (!current.has(focusable)) {
|
|
509
|
+
focusable.isConnected && restoreAttributes([focusable]);
|
|
510
|
+
this.#focusables.delete(focusable);
|
|
525
511
|
}
|
|
526
|
-
focusable.isConnected && restoreAttributes([focusable]);
|
|
527
|
-
this.#focusables.delete(focusable);
|
|
528
512
|
}
|
|
529
513
|
for (const focusable of current) {
|
|
530
|
-
if (this.#focusables.has(focusable)) {
|
|
531
|
-
|
|
514
|
+
if (!this.#focusables.has(focusable)) {
|
|
515
|
+
this.#focusables.add(focusable);
|
|
516
|
+
saveAttributes([focusable], ["tabindex"]);
|
|
517
|
+
focusable.setAttribute("tabindex", "-1");
|
|
532
518
|
}
|
|
533
|
-
this.#focusables.add(focusable);
|
|
534
|
-
saveAttributes([focusable], ["tabindex"]);
|
|
535
|
-
focusable.setAttribute("tabindex", "-1");
|
|
536
519
|
}
|
|
537
520
|
}
|
|
538
521
|
#createSentinel() {
|
|
@@ -589,7 +572,7 @@ function getActiveElement2() {
|
|
|
589
572
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
590
573
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
591
574
|
*
|
|
592
|
-
* @version 1.2.
|
|
575
|
+
* @version 1.2.16
|
|
593
576
|
* @author Yusuke Kamiyamane
|
|
594
577
|
* @license MIT
|
|
595
578
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -601,7 +584,7 @@ function getActiveElement2() {
|
|
|
601
584
|
(**
|
|
602
585
|
* Attributes Utils
|
|
603
586
|
*
|
|
604
|
-
* @version 1.1.
|
|
587
|
+
* @version 1.1.2
|
|
605
588
|
* @author Yusuke Kamiyamane
|
|
606
589
|
* @license MIT
|
|
607
590
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -614,7 +597,7 @@ power-focusable/dist/index.js:
|
|
|
614
597
|
* High-precision focus management utility with full composed tree support.
|
|
615
598
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
616
599
|
*
|
|
617
|
-
* @version 4.3.
|
|
600
|
+
* @version 4.3.3
|
|
618
601
|
* @author Yusuke Kamiyamane
|
|
619
602
|
* @license MIT
|
|
620
603
|
* @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.16
|
|
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.16
|
|
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
|
}
|
|
@@ -464,9 +453,7 @@ var Portal = class {
|
|
|
464
453
|
});
|
|
465
454
|
next && focusElement(next);
|
|
466
455
|
}
|
|
467
|
-
|
|
468
|
-
}
|
|
469
|
-
if (current === this.#exitSentinel) {
|
|
456
|
+
} else if (current === this.#exitSentinel) {
|
|
470
457
|
if (this.#host.contains(before)) {
|
|
471
458
|
this.#moveFocus("next");
|
|
472
459
|
return;
|
|
@@ -482,7 +469,6 @@ var Portal = class {
|
|
|
482
469
|
});
|
|
483
470
|
previous && focusElement(previous);
|
|
484
471
|
}
|
|
485
|
-
return;
|
|
486
472
|
}
|
|
487
473
|
};
|
|
488
474
|
#onKeyDown = (event) => {
|
|
@@ -499,18 +485,17 @@ var Portal = class {
|
|
|
499
485
|
}
|
|
500
486
|
this.#update();
|
|
501
487
|
const focusables = this.#getFocusables();
|
|
502
|
-
if (
|
|
488
|
+
if (focusables.length) {
|
|
489
|
+
const index = focusables.indexOf(active);
|
|
490
|
+
if (index !== -1) {
|
|
491
|
+
event.preventDefault();
|
|
492
|
+
const focusable = focusables[index + (shiftKey ? -1 : 1)];
|
|
493
|
+
focusable ? focusElement(focusable) : this.#focusSentinel(shiftKey);
|
|
494
|
+
}
|
|
495
|
+
} else {
|
|
503
496
|
event.preventDefault();
|
|
504
497
|
this.#moveFocus(shiftKey ? "previous" : "next");
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
const index = focusables.indexOf(active);
|
|
508
|
-
if (index === -1) {
|
|
509
|
-
return;
|
|
510
498
|
}
|
|
511
|
-
event.preventDefault();
|
|
512
|
-
const focusable = focusables[index + (shiftKey ? -1 : 1)];
|
|
513
|
-
focusable ? focusElement(focusable) : this.#focusSentinel(shiftKey);
|
|
514
499
|
};
|
|
515
500
|
#update() {
|
|
516
501
|
const current = /* @__PURE__ */ new Set([
|
|
@@ -518,19 +503,17 @@ var Portal = class {
|
|
|
518
503
|
...getFocusables(this.#host, { composed: true })
|
|
519
504
|
]);
|
|
520
505
|
for (const focusable of this.#focusables) {
|
|
521
|
-
if (current.has(focusable)) {
|
|
522
|
-
|
|
506
|
+
if (!current.has(focusable)) {
|
|
507
|
+
focusable.isConnected && restoreAttributes([focusable]);
|
|
508
|
+
this.#focusables.delete(focusable);
|
|
523
509
|
}
|
|
524
|
-
focusable.isConnected && restoreAttributes([focusable]);
|
|
525
|
-
this.#focusables.delete(focusable);
|
|
526
510
|
}
|
|
527
511
|
for (const focusable of current) {
|
|
528
|
-
if (this.#focusables.has(focusable)) {
|
|
529
|
-
|
|
512
|
+
if (!this.#focusables.has(focusable)) {
|
|
513
|
+
this.#focusables.add(focusable);
|
|
514
|
+
saveAttributes([focusable], ["tabindex"]);
|
|
515
|
+
focusable.setAttribute("tabindex", "-1");
|
|
530
516
|
}
|
|
531
|
-
this.#focusables.add(focusable);
|
|
532
|
-
saveAttributes([focusable], ["tabindex"]);
|
|
533
|
-
focusable.setAttribute("tabindex", "-1");
|
|
534
517
|
}
|
|
535
518
|
}
|
|
536
519
|
#createSentinel() {
|
|
@@ -587,7 +570,7 @@ function getActiveElement2() {
|
|
|
587
570
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
588
571
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
589
572
|
*
|
|
590
|
-
* @version 1.2.
|
|
573
|
+
* @version 1.2.16
|
|
591
574
|
* @author Yusuke Kamiyamane
|
|
592
575
|
* @license MIT
|
|
593
576
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -599,7 +582,7 @@ function getActiveElement2() {
|
|
|
599
582
|
(**
|
|
600
583
|
* Attributes Utils
|
|
601
584
|
*
|
|
602
|
-
* @version 1.1.
|
|
585
|
+
* @version 1.1.2
|
|
603
586
|
* @author Yusuke Kamiyamane
|
|
604
587
|
* @license MIT
|
|
605
588
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -612,7 +595,7 @@ power-focusable/dist/index.js:
|
|
|
612
595
|
* High-precision focus management utility with full composed tree support.
|
|
613
596
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
614
597
|
*
|
|
615
|
-
* @version 4.3.
|
|
598
|
+
* @version 4.3.3
|
|
616
599
|
* @author Yusuke Kamiyamane
|
|
617
600
|
* @license MIT
|
|
618
601
|
* @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.16",
|
|
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
|
},
|