"use client"; import { useEffect, useId, type ReactNode } from "react"; import { IconButton } from "@/components/ui/icon-button"; interface ModalProps { title: string; children: ReactNode; footer?: ReactNode; /** scrim 클릭·ESC·닫기 버튼에서 호출된다. 실제로 마운트 해제할지는 호출부(feature) 책임. */ onClose: () => void; } /** * 조회/입력 팝업 셸(scrim + 패널). 열림 여부는 호출부가 마운트/언마운트로 제어한다. * alert.tsx(확인 다이얼로그)와 달리 폼 필드를 담는 용도라 ESC 키·scrim 클릭·닫기 버튼에서 * onClose를 호출하는 상호작용을 자체적으로 가진다 — 그래서 이 컴포넌트만 'use client'. * 포커스 트랩은 다루지 않는다(호출부 책임). */ export function Modal({ title, children, footer, onClose }: ModalProps) { const titleId = useId(); useEffect(() => { function handleKeyDown(event: KeyboardEvent) { if (event.key === "Escape") { onClose(); } } document.addEventListener("keydown", handleKeyDown); return () => { document.removeEventListener("keydown", handleKeyDown); }; }, [onClose]); return (