From 84f9547f91209f60b2ca980c1dd6fbcfa2bd4edd Mon Sep 17 00:00:00 2001 From: umsangdon Date: Mon, 26 Oct 2026 21:59:50 +0900 Subject: [PATCH] =?UTF-8?q?feat(A00):=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=ED=83=AD=20=EC=A4=84=20=EC=B1=84=EC=9B=80=20=EB=8F=84=EC=9A=B0?= =?UTF-8?q?=EB=AF=B8=20=E2=80=94=20=EB=B6=80=ED=92=88=20=ED=83=AD=EC=9D=84?= =?UTF-8?q?=20=EC=A4=84=20=EC=9A=94=EC=86=8C=20=EC=95=88=EC=97=90=20?= =?UTF-8?q?=EC=B1=84=EC=9B=80=20(PLAN=20553-3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 --- A00_Common/b_page_tabs.ts | 46 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 A00_Common/b_page_tabs.ts diff --git a/A00_Common/b_page_tabs.ts b/A00_Common/b_page_tabs.ts new file mode 100644 index 000000000..179ac8c5c --- /dev/null +++ b/A00_Common/b_page_tabs.ts @@ -0,0 +1,46 @@ +/* ============================================================================= + * b_page_tabs.ts + * 페이지 탭 줄 — 부품 「탭」(`ui_template_tabs`)을 이미 있는 줄 요소 안에 채움(553-3 · B08 · B09 · ☰ [설정]). + * + * 쓰기 = `fillTabs(줄, { tabs, value, onChange, kind: "pill", data: "b08Tab" })` — 칸마다 `data-` = 탭 열쇠 + * 줄 요소는 페이지가 정함(클래스 · 자리) · 칸 모양 · 크기 · 고름 표시는 부품 몫 · 누른 칸이 지금 칸이면 안 부름 + * 탭 이름이 바뀌면 다시 부르면 됨(줄을 통째로 다시 채움) + * ========================================================================== */ + +import type { UiSize } from "@ui/ui_template_button"; +import { createTabs, type TabItem } from "@ui/ui_template_tabs"; + +export interface PageTabsOptions { + tabs: TabItem[]; + value: string; + onChange: (key: string) => void; + /** line = 위 탭(밑줄) · pill = 보조 탭(작은 알약) */ + kind?: "line" | "pill"; + size?: UiSize; + /** 칸에 붙일 data 이름(camelCase · 예: b08Tab → data-b08-tab) */ + data: string; + /** 칸 풍선 */ + title?: (key: string) => string | undefined; +} + +export function fillTabs(host: HTMLElement, opts: PageTabsOptions): HTMLElement[] { + const tabs = createTabs({ + tabs: opts.tabs, + value: opts.value, + kind: opts.kind, + size: opts.size, + onChange: (key) => key !== opts.value && opts.onChange(key), + }); + const buttons = [...tabs.root.querySelectorAll("[data-tab]")]; + for (const button of buttons) { + const key = button.dataset.tab ?? ""; + button.dataset[opts.data] = key; + const title = opts.title?.(key); + if (title) button.title = title; + } + host.classList.add(...tabs.root.classList); + host.dataset.size = tabs.root.dataset.size ?? ""; + host.setAttribute("role", "tablist"); + host.replaceChildren(...tabs.root.childNodes); + return buttons; +}