UNPKG

portal-vue

Version:

> A Portal Component for Vue 3, to render DOM outside of a component, anywhere in the document.

76 lines (63 loc) 1.81 kB
import { reactive, readonly } from 'vue' import type { Name, Transport, TransportCloser, TransportInput, TransportsHub, Wormhole, } from './types' import { inBrowser, stableSort } from './utils' export function createWormhole(asReadonly = true): Wormhole { const transports: TransportsHub = reactive(new Map()) function open(transport: TransportInput) { if (!inBrowser) return const { to, from, content, order = Infinity } = transport if (!to || !from || !content) return if (!transports.has(to)) { transports.set(to, new Map()) } const transportsForTarget = transports.get(to)! const newTransport = { to, from, content, order, } as Transport transportsForTarget.set(from, newTransport) } function close(transport: TransportCloser) { const { to, from } = transport if (!to || !from) return const transportsForTarget = transports.get(to) if (!transportsForTarget) { return } transportsForTarget.delete(from) if (!transportsForTarget.size) { transports.delete(to) } } function getContentForTarget(target: Name, returnAll?: boolean) { const transportsForTarget = transports.get(target) if (!transportsForTarget) return [] const content = Array.from(transportsForTarget?.values() || []) if (!returnAll) { // return Transport that was added last return [content.pop()] as Transport[] } // return all Transports, sorted by their order property return stableSort( content, (a: Transport, b: Transport) => a.order - b.order ) } const wh: Wormhole = { open, close, transports, getContentForTarget, } return asReadonly ? (readonly(wh) as Wormhole) : wh } export const wormhole = createWormhole()