import { useT } from '@app/i18n' import { IconX as X } from '@tabler/icons-react' import { type ReactNode, useEffect, useId, useRef } from 'react' /** * Generic modal chrome (overlay + panel + Escape/outside-click close), shared * by feature areas that need layout the config-driven FormModal cannot express. */ export function Modal({ title, description, open, onClose, width = 'max-w-[620px]', children, footer, }: { title: string description?: string open: boolean onClose: () => void width?: string children: ReactNode footer?: ReactNode }) { const { t } = useT() const panel = useRef(null) const closeRef = useRef(onClose) const titleId = useId() useEffect(() => { closeRef.current = onClose }, [onClose]) useEffect(() => { if (!open) return const previousFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null const previousOverflow = document.body.style.overflow document.body.style.overflow = 'hidden' const frame = requestAnimationFrame(() => { const firstField = panel.current?.querySelector( 'input:not([disabled]), textarea:not([disabled]), select:not([disabled])', ) ;(firstField ?? panel.current)?.focus() }) const onKey = (event: KeyboardEvent) => { if (event.defaultPrevented) return if (event.key === 'Escape') { event.preventDefault() closeRef.current() } } window.addEventListener('keydown', onKey) return () => { cancelAnimationFrame(frame) document.body.style.overflow = previousOverflow window.removeEventListener('keydown', onKey) if (previousFocus?.isConnected) previousFocus.focus() } }, [open]) if (!open) return null return (
event.stopPropagation()} className={`flex max-h-[86vh] w-full flex-col rounded-xl border-2 border-shell-hairline bg-shell-surface p-5 shadow-xl ${width}`} >

{title}

{description ? (

{description}

) : null}
{children}
{footer ?
{footer}
: null}
) } export const dialogInputClass = 'h-10 w-full rounded-md border-2 border-shell-hairline bg-shell-field px-3 text-[13.5px] text-shell-ink outline-none transition-colors focus:border-shell-ink' export const dialogTextareaClass = 'w-full resize-y rounded-md border-2 border-shell-hairline bg-shell-field px-3 py-2 text-[13.5px] leading-6 outline-none transition-colors focus:border-shell-ink' export const dialogLabelClass = 'mb-1.5 block text-[12px] font-medium text-shell-ink'