Files
Aislo/ui_template/ui_template_item_picker_ask.ts
T

85 lines
2.8 KiB
TypeScript

/* =============================================================================
* ui_template_item_picker_ask.ts
* 고르기 모달에서 글을 물을 때 쓰는 작은 입력 창(계획서 26-3b) — [개인에 저장](경로 · 이름) ·
* 나무 오른쪽 클릭 「새 항목」(이름 · 단위). 확인 = 넣은 글들 · 닫기 = null.
* [확인] = 머리 [닫기] 왼쪽 · [취소] 없음(머리 [닫기] = 취소 · 147-2).
* ========================================================================== */
import { createButton, createInputField, el } from "./ui_template_elements";
import { openModal } from "./ui_template_modal";
export interface AskField {
key: string;
label: string;
value?: string;
placeholder?: string;
/** 비우면 확인 안 됨 */
required?: boolean;
}
export interface AskOptions {
title: string;
/** 창 위 한 줄 설명 */
note?: string;
fields: AskField[];
okLabel: string;
closeLabel: string;
/** 빈 값 알림 — `{label}` 자리에 칸 이름 */
emptyText: string;
}
export function askFields(opts: AskOptions): Promise<Record<string, string> | null> {
return new Promise((resolve) => {
let done = false;
const finish = (value: Record<string, string> | null): void => {
if (done) return;
done = true;
resolve(value);
};
openModal({
title: opts.title,
closeLabel: opts.closeLabel,
dialogClass: "ui-item-ask",
backdropClass: "ui-item-ask__backdrop",
beforeClose: () => {
finish(null);
return true;
},
mount: (body, close, head) => {
const inputs = opts.fields.map((field) => ({
field,
input: createInputField({
label: field.label,
value: field.value ?? "",
placeholder: field.placeholder,
}),
}));
const submit = (): void => {
let bad = false;
for (const { field, input } of inputs) {
const empty = field.required && input.input.value.trim() === "";
input.setError(empty ? opts.emptyText.replace("{label}", field.label) : undefined);
bad ||= !!empty;
}
if (bad) return;
finish(
Object.fromEntries(
inputs.map(({ field, input }) => [field.key, input.input.value.trim()]),
),
);
close();
};
for (const { input } of inputs)
input.input.addEventListener("keydown", (event) => {
if (event.key === "Enter") submit();
});
body.append(
...(opts.note ? [el("p", { className: "ui-item-picker__where", text: opts.note })] : []),
...inputs.map(({ input }) => input.root),
);
head.append(createButton({ label: opts.okLabel, variant: "filled", onClick: submit }));
},
});
});
}