39 lines
1.0 KiB
TypeScript
39 lines
1.0 KiB
TypeScript
import { useEffect, useState } from "preact/hooks";
|
|
import { createPortal } from "preact/compat";
|
|
import type { ComponentChildren } from "preact";
|
|
|
|
type PortalProps = {
|
|
into?: string | HTMLElement;
|
|
children: ComponentChildren;
|
|
};
|
|
|
|
export function Portal({ into = "body", children }: PortalProps) {
|
|
const [host, setHost] = useState<HTMLElement | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (typeof document === "undefined") return;
|
|
|
|
let target: HTMLElement | null = null;
|
|
if (typeof into === "string") {
|
|
target = into === "body" ? document.body : document.querySelector(into);
|
|
} else {
|
|
target = into;
|
|
}
|
|
|
|
if (!target) target = document.body;
|
|
|
|
const wrapper = document.createElement("div");
|
|
wrapper.className = "preact-portal-root";
|
|
target.appendChild(wrapper);
|
|
setHost(wrapper);
|
|
|
|
return () => {
|
|
if (wrapper.parentNode) wrapper.parentNode.removeChild(wrapper);
|
|
setHost(null);
|
|
};
|
|
}, [into]);
|
|
|
|
if (!host) return null;
|
|
return createPortal(children, host);
|
|
}
|