import { createContext, createRoot, createSignal, getOwner, type Owner, type ParentProps, runWithOwner, useContext, type JSX, } from "solid-js" import { Dialog as Kobalte } from "@kobalte/core/dialog" type DialogElement = () => JSX.Element type Active = { id: string node: JSX.Element dispose: () => void owner: Owner onClose?: () => void } const Context = createContext>() function init() { const [active, setActive] = createSignal() const close = () => { const current = active() if (!current) return current.onClose?.() current.dispose() setActive(undefined) } const show = (element: DialogElement, owner: Owner, onClose?: () => void) => { close() const id = Math.random().toString(36).slice(2) let dispose: (() => void) | undefined const node = runWithOwner(owner, () => createRoot((d) => { dispose = d return ( { if (open) return close() }} > {element()} ) }), ) if (!dispose) return setActive({ id, node, dispose, owner, onClose }) } return { get active() { return active() }, close, show, } } export function DialogProvider(props: ParentProps) { const ctx = init() return ( {props.children}
{ctx.active?.node}
) } export function useDialog() { const ctx = useContext(Context) const owner = getOwner() if (!owner) { throw new Error("useDialog must be used within a DialogProvider") } if (!ctx) { throw new Error("useDialog must be used within a DialogProvider") } return { get active() { return ctx.active }, show(element: DialogElement, onClose?: () => void) { const base = ctx.active?.owner ?? owner ctx.show(element, base, onClose) }, close() { ctx.close() }, } }