Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PAdA5ThqmtVSsbzjusk1cJ
45 lines
1.6 KiB
TypeScript
45 lines
1.6 KiB
TypeScript
/* =============================================================================
|
|
* M01_MasterData_UI_LogicLab_Pill.ts
|
|
* 줄 모달의 알약 단추 — 쓰인 자료를 알약으로만 늘어놓고, 누른 것 하나만 펼침(다시 누르면 접힘)
|
|
* ========================================================================== */
|
|
|
|
import { el } from "@ui/ui_template_elements";
|
|
|
|
export interface Pill {
|
|
/** 알약 글 — 보기 「표 QF000421」 · 「인력 석공」 */
|
|
label: string;
|
|
/** 펼칠 때 그림 — 표처럼 읽어 와야 하면 Promise */
|
|
view: () => HTMLElement | Promise<HTMLElement>;
|
|
}
|
|
|
|
export function pillBar(pills: Pill[]): HTMLElement {
|
|
const stage = el("div", { className: "m01lab__pill-stage" });
|
|
const buttons: HTMLButtonElement[] = [];
|
|
let open = -1;
|
|
let turn = 0;
|
|
const show = async (i: number): Promise<void> => {
|
|
const mine = ++turn;
|
|
open = open === i ? -1 : i;
|
|
buttons.forEach((b, k) => {
|
|
b.setAttribute("aria-expanded", String(k === open));
|
|
b.classList.toggle("is-open", k === open);
|
|
});
|
|
if (open < 0) return stage.replaceChildren();
|
|
const view = await pills[open].view();
|
|
if (mine === turn) stage.replaceChildren(view); // 빨리 눌러도 마지막 것만
|
|
};
|
|
pills.forEach((p, i) => {
|
|
const b = el("button", {
|
|
className: "m01lab__pill",
|
|
text: p.label,
|
|
attrs: { type: "button", "aria-expanded": "false", "data-pill": p.label },
|
|
});
|
|
b.addEventListener("click", () => void show(i));
|
|
buttons.push(b);
|
|
});
|
|
return el("div", {
|
|
className: "m01lab__pills",
|
|
children: [el("div", { className: "m01lab__pill-row", children: buttons }), stage],
|
|
});
|
|
}
|