/* ============================================================================= * ui_template_item_picker_table.ts * 항목 고르기 모달 상단 표(PLAN 224-1) — M02 「구조물 조합」 페이지 상단의 구조물집계표를 **같은 부품** * (`ui_template/sheet` `createSheet` · 줄 글 = `numberLabels` · 숨김 열 = `comboView`)으로 보임. * 보기 전용(`readOnly` · 고침은 M02 에서) · 보이는 층(+ 주인)의 표 · 고른 항목의 열이 밝게 골라짐(280-2). * 같은 층이면 표는 그대로 두고 열만 옮김 · 층이 바뀌면 그 층 표로 바뀜 · 표에서 열을 고르면 `onColumn`. * 표 부품 · 집계표 모듈은 처음 보일 때만 `import()`(B05 · B06 번들에 안 섞임). * ========================================================================== */ import { el } from "./ui_template_elements"; import { fetchStructureNumbersAt, readTemplate, } from "../M02_MasterTemplete/M02_MasterTemplete_Api_Fetch"; import type { PickerLayer } from "./ui_template_item_picker_data"; import { t } from "./ui_template_locale"; import type { SheetDoc, SheetHandle } from "./sheet/ui_template_sheet"; export interface ComboTable { root: HTMLElement; /** 보일 층(+ 주인) · 고를 열(빈 글 = 안 고름) — `null` 이면 표를 숨김 */ show: (at: { layer: PickerLayer; owner: string | null } | null, column: string) => void; destroy: () => void; } const failed = (error: unknown): string => t("M02_PickerTableFailed").replace( "{value}", error instanceof Error ? error.message : String(error), ); /** `onColumn` = 표에서 고른 열 id(누르기 · 방향키) */ export function createComboTable(onColumn: (colId: string) => void): ComboTable { const root = el("div", { className: "ui-item-picker__table", attrs: { hidden: "" } }); let seq = 0; let shownKey: string | null = null; let sheet: SheetHandle | null = null; /** 가장 나중에 고른 열 — 표를 읽는 사이에 바뀌면 읽은 뒤 이 열을 고름 */ let column = ""; const drop = (): void => { sheet?.destroy(); sheet = null; shownKey = null; }; async function paint( layer: PickerLayer, owner: string | null, key: string, mine: number, ): Promise { drop(); root.replaceChildren( el("p", { className: "ui-item-picker__hint", text: t("M02_PickerLoading") }), ); try { const [{ createSheet }, struct] = await Promise.all([ import("./sheet/ui_template_sheet"), import("../M02_MasterTemplete/M02_MasterTemplete_Structure"), ]); const [got, numbers] = await Promise.all([ readTemplate(layer, "table", struct.STRUCTURE_TABLE, null, owner), fetchStructureNumbersAt(layer, owner).catch(() => ({})), ]); if (mine !== seq) return; sheet = createSheet(root, struct.comboView(got.문서) as SheetDoc, { mode: "master", readOnly: true, lockHead: true, combo: {}, onSelect: (sel) => sel.colId && onColumn(sel.colId), ...struct.numberLabels(() => numbers), }); shownKey = key; sheet.selectColumn(column); } catch (error) { if (mine === seq) root.replaceChildren(el("p", { className: "ui-item-picker__hint", text: failed(error) })); } } return { root, show: (at, col) => { const mine = ++seq; root.hidden = !at; if (!at) return; column = col; const key = `${at.layer}|${at.owner ?? ""}`; if (sheet && key === shownKey) return sheet.selectColumn(column); void paint(at.layer, at.owner, key, mine); }, destroy: () => { seq += 1; drop(); }, }; }