import { useState, useEffect } from 'react' import { createRoot } from 'react-dom/client' import { colors } from '../constants/theme' interface ThemeColors { bg: string border: string text: string hover: string selected: string textMuted: string } interface ModalProps { title?: string message: string type: 'alert' | 'prompt' | 'confirm' defaultValue?: string onConfirm: (value?: string) => void onCancel: () => void theme: ThemeColors } function Modal({ title, message, type, defaultValue = '', onConfirm, onCancel, theme }: ModalProps) { const [inputValue, setInputValue] = useState(defaultValue) // Focus input on mount useEffect(() => { if (type === 'prompt') { const input = document.getElementById('custom-modal-input') if (input) input.focus() } }, [type]) const handleConfirm = () => { onConfirm(type === 'prompt' ? inputValue : undefined) } return (
{title && (
{title}
)}
{message}
{type === 'prompt' && ( setInputValue(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') handleConfirm() if (e.key === 'Escape') onCancel() }} style={{ width: '100%', padding: '10px 12px', background: theme.hover, border: `1px solid ${theme.border}`, borderRadius: 6, color: theme.text, fontSize: 14, marginBottom: 20, outline: 'none', }} /> )}
{(type === 'prompt' || type === 'confirm') && ( )}
) } // Utility to mount the modal dynamically export function showModal(props: Omit): Promise { return new Promise((resolve) => { // Detect Theme let isDark = false try { const prefs = localStorage.getItem('tldraw_global_prefs') if (prefs) { const parsed = JSON.parse(prefs) if (parsed.colorScheme === 'dark') isDark = true } } catch (e) { } const theme: ThemeColors = { bg: isDark ? colors.panelBgDark : colors.panelBg, border: isDark ? colors.borderDark : colors.border, text: isDark ? colors.textDark : colors.text, hover: isDark ? colors.hoverDark : colors.hover, selected: colors.selected, textMuted: colors.textMuted } const div = document.createElement('div') document.body.appendChild(div) const root = createRoot(div) const cleanup = () => { root.unmount() document.body.removeChild(div) } const onConfirm = (value?: string) => { cleanup() resolve(props.type === 'prompt' ? value : true) } const onCancel = () => { cleanup() resolve(props.type === 'prompt' ? undefined : false) } root.render( ) }) }