import { useEffect, type ReactNode } from 'react'; import { createPortal } from 'react-dom'; import { X } from 'lucide-react'; import { cn } from '../../lib/cn'; export type ModalWidth = 'sm' | 'md' | 'lg' | 'xl'; export interface ModalProps { open: boolean; onClose: () => void; title?: ReactNode; subtitle?: ReactNode; /** @default "md" */ width?: ModalWidth; actions?: ReactNode; children?: ReactNode; } const WIDTH_CLASSES: Record = { sm: 'sm:w-[30vw]', md: 'sm:w-[50vw]', lg: 'sm:w-[70vw]', xl: 'sm:w-[90vw]', }; /** Portal modal host — backdrop, Esc / click-out close, scroll-locked body. */ export function Modal({ open, onClose, title, subtitle, width = 'md', actions, children }: ModalProps) { useEffect(() => { if (!open) return; const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; document.addEventListener('keydown', onKey); const prev = document.body.style.overflow; document.body.style.overflow = 'hidden'; return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = prev; }; }, [open, onClose]); if (!open) return null; return createPortal(
{ if (e.target === e.currentTarget) onClose(); }} >
{title &&

{title}

} {subtitle &&
{subtitle}
}
{actions &&
{actions}
}
{children}
, document.body, ); }