/* ============================================================================= * ui_template_modal.ts * 공용 모달 겉틀 — 배경 · 제목줄 · 닫기 · Esc · 포커스. 몸은 `mount` 가 채움. * M01 · M02 가 함께 씀 — `dialogClass` · `backdropClass` 로 화면별 겉모양을 덧붙임. * ========================================================================== */ import "./ui_template_modal.css"; import { createButton, el } from "./ui_template_elements"; export interface ModalOptions { title: string; closeLabel: string; mount: (body: HTMLElement, close: () => void) => void; dialogClass?: string; backdropClass?: string; } export function openModal(opts: ModalOptions): { close: () => void } { const body = el("div", { className: "ui-modal__body" }); const close = (): void => backdrop.remove(); const dialog = el("div", { className: `ui-modal ${opts.dialogClass ?? ""}`.trim(), attrs: { role: "dialog", "aria-label": opts.title }, children: [ el("div", { className: "ui-modal__top", children: [ el("h3", { text: opts.title }), createButton({ label: opts.closeLabel, variant: "ghost", onClick: close }), ], }), body, ], }); const backdrop = el("div", { className: `ui-modal__backdrop ${opts.backdropClass ?? ""}`.trim(), children: [dialog], }); backdrop.addEventListener("click", (ev) => ev.target === backdrop && close()); backdrop.addEventListener("keydown", (ev) => ev.key === "Escape" && close()); opts.mount(body, close); document.body.append(backdrop); dialog.tabIndex = -1; dialog.focus(); return { close }; }