@y14e/portal 0.0.4 → 0.1.0
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 +3 -9
- package/dist/index.cjs +11 -21
- package/dist/index.d.cts +3 -7
- package/dist/index.d.ts +3 -7
- package/dist/index.js +11 -21
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -30,15 +30,9 @@ import { createPortal } from 'https://unpkg.com/@y14e/portal/dist/index.js';
|
|
|
30
30
|
Creates a portal and preserves keyboard focus order between the original DOM and the portal.
|
|
31
31
|
|
|
32
32
|
```ts
|
|
33
|
-
const
|
|
34
|
-
// =>
|
|
33
|
+
const cleanup = createPortal(source, target);
|
|
34
|
+
// => () => void
|
|
35
35
|
//
|
|
36
36
|
// source: Element
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
// Element
|
|
40
|
-
console.log(portal.element);
|
|
41
|
-
|
|
42
|
-
// Cleanup
|
|
43
|
-
portal.cleanup();
|
|
37
|
+
// target (optional): Element (default: <body>)
|
|
44
38
|
```
|
package/dist/index.cjs
CHANGED
|
@@ -254,35 +254,28 @@ function isUngroupedRadio(element) {
|
|
|
254
254
|
|
|
255
255
|
// src/index.ts
|
|
256
256
|
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;`;
|
|
257
|
-
function createPortal(source,
|
|
257
|
+
function createPortal(source, target = document.body) {
|
|
258
258
|
if (!(source instanceof Element)) {
|
|
259
259
|
throw new Error("Invalid source element");
|
|
260
260
|
}
|
|
261
|
-
if (!(
|
|
262
|
-
console.warn("Invalid
|
|
263
|
-
|
|
261
|
+
if (!(target instanceof Element)) {
|
|
262
|
+
console.warn("Invalid target element. Fallback: <body> element.");
|
|
263
|
+
target = document.body;
|
|
264
264
|
}
|
|
265
|
-
const portal = new Portal(source,
|
|
266
|
-
return
|
|
267
|
-
element: portal.getElement(),
|
|
268
|
-
cleanup: () => portal.destroy()
|
|
269
|
-
};
|
|
265
|
+
const portal = new Portal(source, target);
|
|
266
|
+
return () => portal.destroy();
|
|
270
267
|
}
|
|
271
268
|
var Portal = class {
|
|
272
269
|
#source;
|
|
273
|
-
#container;
|
|
274
270
|
#target;
|
|
275
271
|
#entranceSentinel;
|
|
276
272
|
#exitSentinel;
|
|
277
273
|
#tabIndexes = /* @__PURE__ */ new WeakMap();
|
|
278
274
|
#controller = null;
|
|
279
275
|
#isDestroyed = false;
|
|
280
|
-
constructor(source,
|
|
276
|
+
constructor(source, target) {
|
|
281
277
|
this.#source = source;
|
|
282
|
-
this.#
|
|
283
|
-
this.#target = document.createElement("div");
|
|
284
|
-
this.#target.setAttribute("data-portal", "");
|
|
285
|
-
this.#target.setAttribute("tabindex", "-1");
|
|
278
|
+
this.#target = target;
|
|
286
279
|
this.#entranceSentinel = this.#createSentinel();
|
|
287
280
|
this.#exitSentinel = this.#createSentinel();
|
|
288
281
|
this.#initialize();
|
|
@@ -306,18 +299,14 @@ var Portal = class {
|
|
|
306
299
|
}
|
|
307
300
|
});
|
|
308
301
|
this.#exitSentinel.after(this.#source);
|
|
309
|
-
this.#target.remove();
|
|
310
302
|
this.#entranceSentinel.remove();
|
|
311
303
|
this.#exitSentinel.remove();
|
|
312
|
-
|
|
313
|
-
getElement() {
|
|
314
|
-
return this.#target;
|
|
304
|
+
this.#source.removeAttribute("data-portal");
|
|
315
305
|
}
|
|
316
306
|
#initialize() {
|
|
317
307
|
this.#source.before(this.#entranceSentinel);
|
|
318
308
|
this.#entranceSentinel.after(this.#exitSentinel);
|
|
319
309
|
this.#target.append(this.#source);
|
|
320
|
-
this.#container.append(this.#target);
|
|
321
310
|
this.#getFocusables().forEach((focusable) => {
|
|
322
311
|
const index = focusable.getAttribute("tabindex")?.trim();
|
|
323
312
|
this.#tabIndexes.set(focusable, index === null ? null : Number(index));
|
|
@@ -333,6 +322,7 @@ var Portal = class {
|
|
|
333
322
|
capture: true,
|
|
334
323
|
signal
|
|
335
324
|
});
|
|
325
|
+
this.#source.setAttribute("data-portal", "");
|
|
336
326
|
}
|
|
337
327
|
#onFocusIn = (event) => {
|
|
338
328
|
const current = event.target;
|
|
@@ -420,7 +410,7 @@ function getActiveElement2() {
|
|
|
420
410
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
421
411
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
422
412
|
*
|
|
423
|
-
* @version 0.0
|
|
413
|
+
* @version 0.1.0
|
|
424
414
|
* @author Yusuke Kamiyamane
|
|
425
415
|
* @license MIT
|
|
426
416
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
package/dist/index.d.cts
CHANGED
|
@@ -3,21 +3,17 @@
|
|
|
3
3
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
4
4
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
5
5
|
*
|
|
6
|
-
* @version 0.0
|
|
6
|
+
* @version 0.1.0
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
10
10
|
* @see {@link https://github.com/y14e/portal}
|
|
11
11
|
*/
|
|
12
|
-
declare function createPortal(source: Element,
|
|
13
|
-
element: Element;
|
|
14
|
-
cleanup: () => void;
|
|
15
|
-
};
|
|
12
|
+
declare function createPortal(source: Element, target?: HTMLElement): () => void;
|
|
16
13
|
declare class Portal {
|
|
17
14
|
#private;
|
|
18
|
-
constructor(source: Element,
|
|
15
|
+
constructor(source: Element, target: Element);
|
|
19
16
|
destroy(): void;
|
|
20
|
-
getElement(): HTMLElement;
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
export { Portal, createPortal };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,21 +3,17 @@
|
|
|
3
3
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
4
4
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
5
5
|
*
|
|
6
|
-
* @version 0.0
|
|
6
|
+
* @version 0.1.0
|
|
7
7
|
* @author Yusuke Kamiyamane
|
|
8
8
|
* @license MIT
|
|
9
9
|
* @copyright Copyright (c) Yusuke Kamiyamane
|
|
10
10
|
* @see {@link https://github.com/y14e/portal}
|
|
11
11
|
*/
|
|
12
|
-
declare function createPortal(source: Element,
|
|
13
|
-
element: Element;
|
|
14
|
-
cleanup: () => void;
|
|
15
|
-
};
|
|
12
|
+
declare function createPortal(source: Element, target?: HTMLElement): () => void;
|
|
16
13
|
declare class Portal {
|
|
17
14
|
#private;
|
|
18
|
-
constructor(source: Element,
|
|
15
|
+
constructor(source: Element, target: Element);
|
|
19
16
|
destroy(): void;
|
|
20
|
-
getElement(): HTMLElement;
|
|
21
17
|
}
|
|
22
18
|
|
|
23
19
|
export { Portal, createPortal };
|
package/dist/index.js
CHANGED
|
@@ -252,35 +252,28 @@ function isUngroupedRadio(element) {
|
|
|
252
252
|
|
|
253
253
|
// src/index.ts
|
|
254
254
|
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;`;
|
|
255
|
-
function createPortal(source,
|
|
255
|
+
function createPortal(source, target = document.body) {
|
|
256
256
|
if (!(source instanceof Element)) {
|
|
257
257
|
throw new Error("Invalid source element");
|
|
258
258
|
}
|
|
259
|
-
if (!(
|
|
260
|
-
console.warn("Invalid
|
|
261
|
-
|
|
259
|
+
if (!(target instanceof Element)) {
|
|
260
|
+
console.warn("Invalid target element. Fallback: <body> element.");
|
|
261
|
+
target = document.body;
|
|
262
262
|
}
|
|
263
|
-
const portal = new Portal(source,
|
|
264
|
-
return
|
|
265
|
-
element: portal.getElement(),
|
|
266
|
-
cleanup: () => portal.destroy()
|
|
267
|
-
};
|
|
263
|
+
const portal = new Portal(source, target);
|
|
264
|
+
return () => portal.destroy();
|
|
268
265
|
}
|
|
269
266
|
var Portal = class {
|
|
270
267
|
#source;
|
|
271
|
-
#container;
|
|
272
268
|
#target;
|
|
273
269
|
#entranceSentinel;
|
|
274
270
|
#exitSentinel;
|
|
275
271
|
#tabIndexes = /* @__PURE__ */ new WeakMap();
|
|
276
272
|
#controller = null;
|
|
277
273
|
#isDestroyed = false;
|
|
278
|
-
constructor(source,
|
|
274
|
+
constructor(source, target) {
|
|
279
275
|
this.#source = source;
|
|
280
|
-
this.#
|
|
281
|
-
this.#target = document.createElement("div");
|
|
282
|
-
this.#target.setAttribute("data-portal", "");
|
|
283
|
-
this.#target.setAttribute("tabindex", "-1");
|
|
276
|
+
this.#target = target;
|
|
284
277
|
this.#entranceSentinel = this.#createSentinel();
|
|
285
278
|
this.#exitSentinel = this.#createSentinel();
|
|
286
279
|
this.#initialize();
|
|
@@ -304,18 +297,14 @@ var Portal = class {
|
|
|
304
297
|
}
|
|
305
298
|
});
|
|
306
299
|
this.#exitSentinel.after(this.#source);
|
|
307
|
-
this.#target.remove();
|
|
308
300
|
this.#entranceSentinel.remove();
|
|
309
301
|
this.#exitSentinel.remove();
|
|
310
|
-
|
|
311
|
-
getElement() {
|
|
312
|
-
return this.#target;
|
|
302
|
+
this.#source.removeAttribute("data-portal");
|
|
313
303
|
}
|
|
314
304
|
#initialize() {
|
|
315
305
|
this.#source.before(this.#entranceSentinel);
|
|
316
306
|
this.#entranceSentinel.after(this.#exitSentinel);
|
|
317
307
|
this.#target.append(this.#source);
|
|
318
|
-
this.#container.append(this.#target);
|
|
319
308
|
this.#getFocusables().forEach((focusable) => {
|
|
320
309
|
const index = focusable.getAttribute("tabindex")?.trim();
|
|
321
310
|
this.#tabIndexes.set(focusable, index === null ? null : Number(index));
|
|
@@ -331,6 +320,7 @@ var Portal = class {
|
|
|
331
320
|
capture: true,
|
|
332
321
|
signal
|
|
333
322
|
});
|
|
323
|
+
this.#source.setAttribute("data-portal", "");
|
|
334
324
|
}
|
|
335
325
|
#onFocusIn = (event) => {
|
|
336
326
|
const current = event.target;
|
|
@@ -418,7 +408,7 @@ function getActiveElement2() {
|
|
|
418
408
|
* Lightweight DOM portal (teleport) utility with fully focus management.
|
|
419
409
|
* Designed for accessible dialogs, menus, overlays, popovers.
|
|
420
410
|
*
|
|
421
|
-
* @version 0.0
|
|
411
|
+
* @version 0.1.0
|
|
422
412
|
* @author Yusuke Kamiyamane
|
|
423
413
|
* @license MIT
|
|
424
414
|
* @copyright Copyright (c) Yusuke Kamiyamane
|