import { useEffect, useState, type ReactNode } from "react"; import { createPortal } from "react-dom"; // A widget shell that can expand into a full-screen modal. To avoid mounting // the (stateful) body twice, the children render in exactly one place at a // time: inline normally, or inside the modal when expanded. The inline slot // shows a lightweight placeholder while expanded. export default function Widget(props: { title: string; sub?: ReactNode; headExtra?: ReactNode; className?: string; expandable?: boolean; children: ReactNode; }) { const [open, setOpen] = useState(false); useEffect(() => { function onKey(e: KeyboardEvent) { if (e.key === "Escape") setOpen(false); } document.addEventListener("keydown", onKey); return () => document.removeEventListener("keydown", onKey); }, []); const head = (inModal: boolean) => (
{props.title} {props.sub} {props.headExtra} {props.expandable !== false && ( )}
); return ( <>
{head(false)} {open ?
setOpen(true)}>Expanded — click to focus, Esc to close
: props.children}
{open && createPortal(
setOpen(false)}>
e.stopPropagation()}> {head(true)}
{props.children}
, document.body, )} ); }