- 지운 구조물 열의 도번 8자리를 조합 장부 지운번호에 남겨 새 열이 다시 안 받음(다음 저장에서도) - 공용 창 틀: 몸의 첫 입력 칸에 커서(붙기 전 focus 가 안 먹던 것) - 좌측 새로 · 본떠 만들기 이름 창에서 Enter = 만들기 - 표: 바인딩 · 계산 열은 손 입력 열 단추 꺼짐(켜도 프로젝트에서 잠김) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011vX53nJGC8ucBRFJns2n7B
48 lines
1.8 KiB
TypeScript
48 lines
1.8 KiB
TypeScript
/* =============================================================================
|
|
* 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;
|
|
// 몸의 첫 입력 칸에 커서 — mount 안의 focus() 는 붙기 전이라 안 먹음
|
|
(body.querySelector<HTMLElement>("input, textarea, select") ?? dialog).focus();
|
|
return { close };
|
|
}
|