import { createContext, useContext, type ReactNode } from "react"; import { useShortcut, type KeyEventLike, type ShortcutOptions } from "../react/input"; export interface AlertContext { dialogId?: string; dismiss(): void; } export interface PromptContext extends AlertContext { resolve(value: T): void; } export interface DialogApi { alert(options: Record): Promise; prompt(options: Record): Promise; } interface DialogContextValue { dialog: DialogApi; isOpen: boolean; dialogId?: string; keyboardEnabled: boolean; } const DialogContext = createContext(null); export function DialogHostProvider({ dialog, isOpen, dialogId, keyboardEnabled = true, children, }: { dialog: DialogApi; isOpen: boolean; dialogId?: string; keyboardEnabled?: boolean; children: ReactNode; }) { return ( {children} ); } export function useDialog(): DialogApi { const context = useContext(DialogContext); if (!context) throw new Error("useDialog must be used inside DialogHostProvider"); return context.dialog; } /** The dialog API when a host is mounted; null in isolated renders such as tests. */ export function useOptionalDialog(): DialogApi | null { return useContext(DialogContext)?.dialog ?? null; } export function useDialogState(selector: (state: { isOpen: boolean }) => T): T { const context = useContext(DialogContext); if (!context) throw new Error("useDialogState must be used inside DialogHostProvider"); return selector({ isOpen: context.isOpen }); } export function useDialogKeyboard( handler: (event: KeyEventLike) => void, options?: ShortcutOptions | string, ): void { const context = useContext(DialogContext); const resolved = typeof options === "string" ? { scope: options } : options; useShortcut(handler, { ...resolved, enabled: (resolved?.enabled ?? true) && (context?.keyboardEnabled ?? true), scope: resolved?.scope ?? context?.dialogId, }); }