Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
72 lines
2.7 KiB
TypeScript
72 lines
2.7 KiB
TypeScript
/* =============================================================================
|
|
* B09_Estimation_UI_TabBar.ts
|
|
* B09 탭 줄 두 층(PLAN 181-1) — 위 탭(md) · 아래 탭(sm) · B08 수량산출 페이지 꼴.
|
|
*
|
|
* 위 탭 = `TAB_GROUPS`(`…_UI_Tabs`) · 아래 탭 하나뿐인 위 탭 = 보이지 않는 sm 단추 한 줄(높이만 채움)
|
|
* 위 탭 누름 = 그 묶음에서 마지막으로 본 아래 탭(이 화면 안 Map · 저장 안 함) · 없으면 첫 아래 탭
|
|
* 탭 이동은 `draw(탭)` — 이동이 묶음을 넘어도 위 탭이 따라 켜짐
|
|
* ========================================================================== */
|
|
|
|
import { createButton } from "@ui/ui_template_elements";
|
|
import { groupOf, tabName, TAB_GROUPS, type TabId } from "./B09_Estimation_UI_Tabs";
|
|
|
|
export interface TabBars {
|
|
top: HTMLElement;
|
|
sub: HTMLElement;
|
|
/** 이 탭이 켜진 꼴로 두 줄을 다시 그림 */
|
|
draw: (tab: TabId) => void;
|
|
}
|
|
|
|
function tabButton(label: string, on: boolean, size: "sm" | undefined, pick: () => void) {
|
|
const button = createButton({
|
|
label,
|
|
variant: on ? "filled" : "ghost",
|
|
...(size ? { size } : {}),
|
|
onClick: () => !on && pick(),
|
|
});
|
|
button.setAttribute("role", "tab");
|
|
button.setAttribute("aria-selected", String(on));
|
|
return button;
|
|
}
|
|
|
|
export function createTabBars(onPick: (tab: TabId) => void): TabBars {
|
|
const top = document.createElement("div");
|
|
top.className = "b09-estimation__tabs";
|
|
top.setAttribute("role", "tablist");
|
|
const sub = document.createElement("div");
|
|
sub.className = "b09-estimation__tabs";
|
|
const lastSeen = new Map<TabId, TabId>();
|
|
|
|
const draw = (tab: TabId): void => {
|
|
const [, picked] = groupOf(tab);
|
|
lastSeen.set(picked[0], tab);
|
|
top.replaceChildren(
|
|
...TAB_GROUPS.map(([label, tabs]) => {
|
|
const button = tabButton(label, tabs === picked, undefined, () =>
|
|
onPick(lastSeen.get(tabs[0]) ?? tabs[0]),
|
|
);
|
|
button.dataset.b09Group = tabs[0];
|
|
if (tabs.length === 1) button.dataset.b09Tab = tabs[0];
|
|
return button;
|
|
}),
|
|
);
|
|
const single = picked.length === 1;
|
|
sub.classList.toggle("b09-estimation__tabs--blank", single);
|
|
sub.setAttribute("role", single ? "presentation" : "tablist");
|
|
sub.setAttribute("aria-hidden", String(single));
|
|
if (single) {
|
|
const ghost = createButton({ label: tabName(picked[0]), variant: "ghost", size: "sm" });
|
|
ghost.tabIndex = -1;
|
|
return void sub.replaceChildren(ghost);
|
|
}
|
|
sub.replaceChildren(
|
|
...picked.map((id) => {
|
|
const button = tabButton(tabName(id), id === tab, "sm", () => onPick(id));
|
|
button.dataset.b09Tab = id;
|
|
return button;
|
|
}),
|
|
);
|
|
};
|
|
return { top, sub, draw };
|
|
}
|