@y14e/portal 1.0.3 → 1.0.5
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 +24 -19
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +24 -19
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -10,11 +10,11 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
10
10
|
const { composed = false } = options;
|
|
11
11
|
let { filter, include } = options;
|
|
12
12
|
if (filter && typeof filter !== "function") {
|
|
13
|
-
console.warn("Invalid filter function
|
|
13
|
+
console.warn("Invalid filter function");
|
|
14
14
|
filter = void 0;
|
|
15
15
|
}
|
|
16
16
|
if (include && typeof include !== "function") {
|
|
17
|
-
console.warn("Invalid include function
|
|
17
|
+
console.warn("Invalid include function");
|
|
18
18
|
include = void 0;
|
|
19
19
|
}
|
|
20
20
|
const elements = [];
|
|
@@ -104,7 +104,7 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
if (!containsComposed(container, anchor)) {
|
|
107
|
-
console.warn("
|
|
107
|
+
console.warn("Anchor (active) element not within container");
|
|
108
108
|
return null;
|
|
109
109
|
}
|
|
110
110
|
const focusables = getFocusables(container, { composed, filter, include });
|
|
@@ -269,14 +269,23 @@ function isUngroupedRadio(element) {
|
|
|
269
269
|
var VISUALLY_HIDDEN_CSS = `border: 0; clip: rect(0, 0, 0, 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; user-select: none; white-space: nowrap; width: 1px;`;
|
|
270
270
|
function createPortal(host, container = document.body) {
|
|
271
271
|
if (!(host instanceof Element)) {
|
|
272
|
-
|
|
272
|
+
console.warn("Invalid host element");
|
|
273
|
+
return () => {
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
if (host.hasAttribute("data-portaled")) {
|
|
277
|
+
console.warn("Already portaled");
|
|
278
|
+
return () => {
|
|
279
|
+
};
|
|
273
280
|
}
|
|
274
281
|
if (!(container instanceof Element)) {
|
|
275
282
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
276
283
|
container = document.body;
|
|
277
284
|
}
|
|
278
285
|
if (containsComposed2(host, container)) {
|
|
279
|
-
|
|
286
|
+
console.warn("Host element cannot contain the container element");
|
|
287
|
+
return () => {
|
|
288
|
+
};
|
|
280
289
|
}
|
|
281
290
|
const portal = new Portal(host, container);
|
|
282
291
|
return () => portal.destroy();
|
|
@@ -290,10 +299,6 @@ var Portal = class {
|
|
|
290
299
|
#controller = null;
|
|
291
300
|
#isDestroyed = false;
|
|
292
301
|
constructor(host, container) {
|
|
293
|
-
if (host.hasAttribute("data-portaled")) {
|
|
294
|
-
console.warn("Already portaled");
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
302
|
this.#host = host;
|
|
298
303
|
this.#container = container;
|
|
299
304
|
this.#entranceSentinel = this.#createSentinel();
|
|
@@ -351,17 +356,17 @@ var Portal = class {
|
|
|
351
356
|
}
|
|
352
357
|
if (current === this.#entranceSentinel) {
|
|
353
358
|
if (this.#host.contains(before)) {
|
|
354
|
-
this.#
|
|
359
|
+
this.#moveFocus("previous");
|
|
355
360
|
} else {
|
|
356
361
|
const first = this.#getFocusables()[0];
|
|
357
|
-
first &&
|
|
362
|
+
first && focusElement(first);
|
|
358
363
|
}
|
|
359
364
|
} else if (current === this.#exitSentinel) {
|
|
360
365
|
if (this.#host.contains(before)) {
|
|
361
|
-
this.#
|
|
366
|
+
this.#moveFocus("next");
|
|
362
367
|
} else {
|
|
363
368
|
const last = this.#getFocusables().at(-1);
|
|
364
|
-
last &&
|
|
369
|
+
last && focusElement(last);
|
|
365
370
|
}
|
|
366
371
|
}
|
|
367
372
|
};
|
|
@@ -387,7 +392,7 @@ var Portal = class {
|
|
|
387
392
|
event.preventDefault();
|
|
388
393
|
const focusable = this.#getFocusables()[index + (event.shiftKey ? -1 : 1)];
|
|
389
394
|
if (focusable) {
|
|
390
|
-
|
|
395
|
+
focusElement(focusable);
|
|
391
396
|
} else {
|
|
392
397
|
(event.shiftKey ? this.#entranceSentinel : this.#exitSentinel).focus();
|
|
393
398
|
}
|
|
@@ -406,13 +411,13 @@ var Portal = class {
|
|
|
406
411
|
include: (element) => this.#tabIndexes.has(element)
|
|
407
412
|
});
|
|
408
413
|
}
|
|
409
|
-
#
|
|
414
|
+
#moveFocus(direction) {
|
|
410
415
|
const options = {
|
|
411
416
|
anchor: direction === "previous" ? this.#entranceSentinel : this.#exitSentinel,
|
|
412
417
|
composed: true
|
|
413
418
|
};
|
|
414
419
|
const focusable = direction === "previous" ? getPreviousFocusable(document.body, options) : getNextFocusable(document.body, options);
|
|
415
|
-
focusable &&
|
|
420
|
+
focusable && focusElement(focusable);
|
|
416
421
|
}
|
|
417
422
|
};
|
|
418
423
|
function containsComposed2(container, element) {
|
|
@@ -425,7 +430,7 @@ function containsComposed2(container, element) {
|
|
|
425
430
|
}
|
|
426
431
|
return false;
|
|
427
432
|
}
|
|
428
|
-
function
|
|
433
|
+
function focusElement(element) {
|
|
429
434
|
"focus" in element && typeof element.focus === "function" && element.focus();
|
|
430
435
|
}
|
|
431
436
|
function getActiveElement2() {
|
|
@@ -440,7 +445,7 @@ function getActiveElement2() {
|
|
|
440
445
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
441
446
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
442
447
|
*
|
|
443
|
-
* @version 1.0.
|
|
448
|
+
* @version 1.0.5
|
|
444
449
|
* @author Yusuke Kamiyamane
|
|
445
450
|
* @license MIT
|
|
446
451
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -454,7 +459,7 @@ power-focusable/dist/index.js:
|
|
|
454
459
|
* High-precision focus management utility with full composed tree support.
|
|
455
460
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
456
461
|
*
|
|
457
|
-
* @version 4.1.
|
|
462
|
+
* @version 4.1.4
|
|
458
463
|
* @author Yusuke Kamiyamane
|
|
459
464
|
* @license MIT
|
|
460
465
|
* @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.5
|
|
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.5
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.js
CHANGED
|
@@ -8,11 +8,11 @@ function getFocusables(container = document.body, options = {}) {
|
|
|
8
8
|
const { composed = false } = options;
|
|
9
9
|
let { filter, include } = options;
|
|
10
10
|
if (filter && typeof filter !== "function") {
|
|
11
|
-
console.warn("Invalid filter function
|
|
11
|
+
console.warn("Invalid filter function");
|
|
12
12
|
filter = void 0;
|
|
13
13
|
}
|
|
14
14
|
if (include && typeof include !== "function") {
|
|
15
|
-
console.warn("Invalid include function
|
|
15
|
+
console.warn("Invalid include function");
|
|
16
16
|
include = void 0;
|
|
17
17
|
}
|
|
18
18
|
const elements = [];
|
|
@@ -102,7 +102,7 @@ function getRelativeFocusable(container, offset, options) {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
if (!containsComposed(container, anchor)) {
|
|
105
|
-
console.warn("
|
|
105
|
+
console.warn("Anchor (active) element not within container");
|
|
106
106
|
return null;
|
|
107
107
|
}
|
|
108
108
|
const focusables = getFocusables(container, { composed, filter, include });
|
|
@@ -267,14 +267,23 @@ function isUngroupedRadio(element) {
|
|
|
267
267
|
var VISUALLY_HIDDEN_CSS = `border: 0; clip: rect(0, 0, 0, 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; user-select: none; white-space: nowrap; width: 1px;`;
|
|
268
268
|
function createPortal(host, container = document.body) {
|
|
269
269
|
if (!(host instanceof Element)) {
|
|
270
|
-
|
|
270
|
+
console.warn("Invalid host element");
|
|
271
|
+
return () => {
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (host.hasAttribute("data-portaled")) {
|
|
275
|
+
console.warn("Already portaled");
|
|
276
|
+
return () => {
|
|
277
|
+
};
|
|
271
278
|
}
|
|
272
279
|
if (!(container instanceof Element)) {
|
|
273
280
|
console.warn("Invalid container element. Fallback: <body> element.");
|
|
274
281
|
container = document.body;
|
|
275
282
|
}
|
|
276
283
|
if (containsComposed2(host, container)) {
|
|
277
|
-
|
|
284
|
+
console.warn("Host element cannot contain the container element");
|
|
285
|
+
return () => {
|
|
286
|
+
};
|
|
278
287
|
}
|
|
279
288
|
const portal = new Portal(host, container);
|
|
280
289
|
return () => portal.destroy();
|
|
@@ -288,10 +297,6 @@ var Portal = class {
|
|
|
288
297
|
#controller = null;
|
|
289
298
|
#isDestroyed = false;
|
|
290
299
|
constructor(host, container) {
|
|
291
|
-
if (host.hasAttribute("data-portaled")) {
|
|
292
|
-
console.warn("Already portaled");
|
|
293
|
-
return;
|
|
294
|
-
}
|
|
295
300
|
this.#host = host;
|
|
296
301
|
this.#container = container;
|
|
297
302
|
this.#entranceSentinel = this.#createSentinel();
|
|
@@ -349,17 +354,17 @@ var Portal = class {
|
|
|
349
354
|
}
|
|
350
355
|
if (current === this.#entranceSentinel) {
|
|
351
356
|
if (this.#host.contains(before)) {
|
|
352
|
-
this.#
|
|
357
|
+
this.#moveFocus("previous");
|
|
353
358
|
} else {
|
|
354
359
|
const first = this.#getFocusables()[0];
|
|
355
|
-
first &&
|
|
360
|
+
first && focusElement(first);
|
|
356
361
|
}
|
|
357
362
|
} else if (current === this.#exitSentinel) {
|
|
358
363
|
if (this.#host.contains(before)) {
|
|
359
|
-
this.#
|
|
364
|
+
this.#moveFocus("next");
|
|
360
365
|
} else {
|
|
361
366
|
const last = this.#getFocusables().at(-1);
|
|
362
|
-
last &&
|
|
367
|
+
last && focusElement(last);
|
|
363
368
|
}
|
|
364
369
|
}
|
|
365
370
|
};
|
|
@@ -385,7 +390,7 @@ var Portal = class {
|
|
|
385
390
|
event.preventDefault();
|
|
386
391
|
const focusable = this.#getFocusables()[index + (event.shiftKey ? -1 : 1)];
|
|
387
392
|
if (focusable) {
|
|
388
|
-
|
|
393
|
+
focusElement(focusable);
|
|
389
394
|
} else {
|
|
390
395
|
(event.shiftKey ? this.#entranceSentinel : this.#exitSentinel).focus();
|
|
391
396
|
}
|
|
@@ -404,13 +409,13 @@ var Portal = class {
|
|
|
404
409
|
include: (element) => this.#tabIndexes.has(element)
|
|
405
410
|
});
|
|
406
411
|
}
|
|
407
|
-
#
|
|
412
|
+
#moveFocus(direction) {
|
|
408
413
|
const options = {
|
|
409
414
|
anchor: direction === "previous" ? this.#entranceSentinel : this.#exitSentinel,
|
|
410
415
|
composed: true
|
|
411
416
|
};
|
|
412
417
|
const focusable = direction === "previous" ? getPreviousFocusable(document.body, options) : getNextFocusable(document.body, options);
|
|
413
|
-
focusable &&
|
|
418
|
+
focusable && focusElement(focusable);
|
|
414
419
|
}
|
|
415
420
|
};
|
|
416
421
|
function containsComposed2(container, element) {
|
|
@@ -423,7 +428,7 @@ function containsComposed2(container, element) {
|
|
|
423
428
|
}
|
|
424
429
|
return false;
|
|
425
430
|
}
|
|
426
|
-
function
|
|
431
|
+
function focusElement(element) {
|
|
427
432
|
"focus" in element && typeof element.focus === "function" && element.focus();
|
|
428
433
|
}
|
|
429
434
|
function getActiveElement2() {
|
|
@@ -438,7 +443,7 @@ function getActiveElement2() {
|
|
|
438
443
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
439
444
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
440
445
|
*
|
|
441
|
-
* @version 1.0.
|
|
446
|
+
* @version 1.0.5
|
|
442
447
|
* @author Yusuke Kamiyamane
|
|
443
448
|
* @license MIT
|
|
444
449
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
@@ -452,7 +457,7 @@ power-focusable/dist/index.js:
|
|
|
452
457
|
* High-precision focus management utility with full composed tree support.
|
|
453
458
|
* Handles complex focus rules including tabindex ordering, radio groups, inert.
|
|
454
459
|
*
|
|
455
|
-
* @version 4.1.
|
|
460
|
+
* @version 4.1.4
|
|
456
461
|
* @author Yusuke Kamiyamane
|
|
457
462
|
* @license MIT
|
|
458
463
|
* @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.5",
|
|
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.4",
|
|
52
52
|
"tsup": "^8.0.0",
|
|
53
53
|
"typescript": "^5.6.0"
|
|
54
54
|
},
|