/* ============================================================================= * ui_template_leave_dialog.ts * 저장 안 한 고침이 있을 때 넘어가기 전 물음 — 단추 셋: [취소] [버리고 넘어감] [저장 후 넘어감](주 단추). * 기본 초점 = 취소 · Esc = 취소 · 저장이 실패하거나 고침이 남으면 머묾. * 몸은 공용 확인 창(`showConfirmDialog`)과 같은 틀(.ui-confirm). * ========================================================================== */ import { createButton, el } from "./ui_template_elements"; import { t as L } from "./ui_template_locale"; export type LeaveChoice = "save" | "discard" | "cancel"; /** 3단추 물음 — 닫기 · Esc = "cancel" */ export function askLeave(message: string): Promise { return new Promise((resolve) => { const overlay = el("div", { className: "ui-confirm" }); const panel = el("div", { className: "ui-confirm__panel" }); const actions = el("div", { className: "ui-confirm__actions" }); const back = document.activeElement as HTMLElement | null; // 닫힐 때 초점을 돌려놓을 자리 const done = (choice: LeaveChoice): void => { overlay.remove(); if (back?.isConnected && back !== document.body) back.focus({ preventScroll: true }); resolve(choice); }; const cancel = createButton({ label: L("M02_TreeCancel"), variant: "ghost", onClick: () => done("cancel"), }); actions.append( cancel, createButton({ label: L("M02_TreeDiscardGo"), variant: "danger", onClick: () => done("discard"), }), createButton({ label: L("M02_TreeSaveGo"), variant: "filled", onClick: () => done("save"), }), ); overlay.addEventListener("keydown", (ev) => { if (ev.key !== "Escape") return; ev.stopPropagation(); // 뒤 창 · 페이지 Esc 까지 닫지 않음 done("cancel"); }); panel.append(el("p", { className: "ui-confirm__message", text: message }), actions); overlay.append(panel); document.body.append(overlay); cancel.focus(); // 창에 초점 — 뒤 칸에 글이 들어가지 않고 Esc 가 먹음 }); } export interface LeaveHooks { /** 저장 한 번 — 실패는 던지거나 `stillDirty` 로 알림(알림 글은 저장 길이 띄움) */ save: () => Promise; /** 저장 뒤에도 고침이 남았나 — 남으면 머묾 */ stillDirty: () => boolean; /** [버리고 넘어감] 때 */ discard?: () => void | Promise; } /** * 물음 → 고름대로 처리. 넘어가도 되면 "saved" | "discarded", 머물면 "stay". * 저장 실패(던짐) · 저장 뒤 고침 남음 · 취소 = "stay". */ export async function leaveOrStay( message: string, hooks: LeaveHooks, ): Promise<"saved" | "discarded" | "stay"> { const choice = await askLeave(message); if (choice === "cancel") return "stay"; if (choice === "discard") { await hooks.discard?.(); return "discarded"; } try { await hooks.save(); } catch { return "stay"; } return hooks.stillDirty() ? "stay" : "saved"; }