"use client"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@kandev/ui/dialog"; import { pluginModalManager, usePluginModals, type OpenPluginModal, } from "@/lib/plugins/modal-manager"; import type { PluginModalOptions } from "@/lib/plugins/types"; import { PluginErrorBoundary } from "./plugin-error-boundary"; /** Maps `PluginModalOptions.size` to the host's Dialog width classes. */ const SIZE_CLASSES: Record, string> = { sm: "sm:max-w-sm", md: "sm:max-w-xl", lg: "sm:max-w-3xl", xl: "sm:max-w-5xl", }; function preventWhenNotDismissible(dismissible: boolean) { return (event: Event) => { if (!dismissible) event.preventDefault(); }; } function PluginModalInstance({ modal }: { modal: OpenPluginModal }) { const { instanceId, pluginId, options } = modal; const dismissible = options.dismissible ?? true; const Content = options.content; const guardClose = preventWhenNotDismissible(dismissible); const handleOpenChange = (open: boolean) => { if (open || !dismissible) return; pluginModalManager.close(instanceId); }; return ( {/* `options.title` is supplied by the plugin author, so it is third-party data rather than host copy. */} {options.title && ( {options.title} )} ); } /** * Renders every open plugin modal (`host.openModal(...)`) in a `@kandev/ui` * `Dialog`, each isolated behind its own `PluginErrorBoundary`. Mounted once * at the app root, alongside ``. */ export function PluginModalHost() { const modals = usePluginModals(); if (modals.length === 0) return null; return ( <> {modals.map((modal) => ( ))} ); }