mongoku
Version:
[](https://github.com/huggingface/Mongoku/actions/workflows/ci.yml)
50 lines (44 loc) • 1.2 kB
text/typescript
import { tick } from "svelte";
/**
* This action is used to create a portal for a given node.
*
* On the container:
* <div use:createPortal></div>
*
* On the target:
* <div use:portal></div>
*
* Or if you want to use a custom id:
* <div use:createPortal="custom-id"></div>
* <div use:portal="custom-id"></div>
*/
const portal_map = new Map<string, HTMLElement>();
export function createPortal(node: HTMLElement, id = "default") {
const key = `$$portal.${id}`;
if (portal_map.has(key)) {
throw `duplicate portal key "${id}"`;
} else {
portal_map.set(key, node);
}
return { destroy: portal_map.delete.bind(portal_map, key) };
}
function mount(node: HTMLElement, key: string) {
if (!portal_map.has(key)) {
throw `unknown portal ${key}`;
}
const host = portal_map.get(key)!;
host.insertBefore(node, null);
return () => host.contains(node) && host.removeChild(node);
}
export function portal(node: HTMLElement, id = "default") {
let destroy: (() => void) | undefined;
const key = `$$portal.${id}`;
if (!portal_map.has(key)) {
tick().then(() => {
destroy = mount(node, key);
});
} else {
destroy = mount(node, key);
}
return { destroy: () => destroy?.() };
}