/** * DTModal — Portal-based modal with beveled card content. * * CSS reference: bevels.css .dt-bevel-modal, .card, .mode-* */ import { useEffect, useCallback, type ReactNode, type CSSProperties } from 'react'; import { createPortal } from 'react-dom'; import type { DTVariant } from '@dangerousthings/tokens'; import { cx } from '../utils/cx'; import { getVariantClass } from '../utils/variantClasses'; interface DTModalProps { visible: boolean; onDismiss: () => void; title?: string; /** Color variant @default 'normal' */ variant?: DTVariant; children: ReactNode; /** Whether clicking backdrop dismisses @default true */ dismissable?: boolean; className?: string; style?: CSSProperties; } export function DTModal({ visible, onDismiss, title, variant = 'normal', children, dismissable = true, className, style, }: DTModalProps) { const handleKeyDown = useCallback( (e: KeyboardEvent) => { if (e.key === 'Escape' && dismissable) onDismiss(); }, [onDismiss, dismissable], ); useEffect(() => { if (visible) { document.addEventListener('keydown', handleKeyDown); return () => document.removeEventListener('keydown', handleKeyDown); } }, [visible, handleKeyDown]); if (!visible) return null; return createPortal(