/* ============================================================================= * B06_Section_UI_Cross_Panel_Base.ts * 구조물 조정 오버레이 창 **공용 부품**(2026-08-25 사용자: 세월교·BOX암거 창을 * 기슭막이 창(`_Cross_Structure_Panel.ts`)과 같은 템플릿으로 일원화). * * 템플릿 규약: * · 머리줄(`__head`) = 제목 + ✕ 닫기. * · 항목 행 = 1행 이름 라벨 + 2행 값 조작(2026-08-22 확정 2행 구조). * · **십자(D-pad)·9키 조작 세트는 항상 창 맨 아래**(2026-08-24·08-25 사용자). * · 키보드 방향키 = 십자 버튼(2026-08-23) — 셀렉트·입력 포커스 중엔 양보. * ========================================================================== */ /** 조작 버튼 하나 — 클릭이 카드 선택·팬으로 번지지 않게 막는다. */ export function makeButton(label: string, title: string, onClick: () => void): HTMLButtonElement { const button = document.createElement("button"); button.type = "button"; button.className = "b06-structure-panel__btn"; button.textContent = label; button.title = title; button.addEventListener("click", (event) => { // 카드 선택·팬으로 번지면 도면이 다시 그려져 맞춰 둔 배율이 날아간다. event.stopPropagation(); onClick(); }); return button; } /** 항목 행 — 1행 이름 라벨 + 2행 값 조작. */ export function makeRow(labelText: string): { row: HTMLElement; controls: HTMLElement } { const row = document.createElement("div"); row.className = "b06-structure-panel__struct"; const label = document.createElement("span"); label.className = "b06-structure-panel__label"; label.textContent = labelText; const controls = document.createElement("div"); controls.className = "b06-structure-panel__controls"; row.append(label, controls); return { row, controls }; } /** D-pad 슬롯 버튼 — 방향키 바인딩이 슬롯 클래스로 버튼을 찾는다. */ export function dpadButton( label: string, slot: "up" | "down" | "left" | "right" | "reset" | "equal", title: string, onClick: () => void, ): HTMLButtonElement { const button = makeButton(label, title, onClick); button.classList.add(`b06-structure-panel__btn--${slot}`); return button; } /** 창 뼈대 — root(.b06-structure-panel, 숨김 시작) + 머리줄(제목·닫기). */ export function buildPanelShell(onClose: () => void): { root: HTMLElement; head: HTMLElement; title: HTMLSpanElement; } { const root = document.createElement("div"); root.className = "b06-structure-panel is-hidden"; root.addEventListener("click", (event) => event.stopPropagation()); const title = document.createElement("span"); title.className = "b06-structure-panel__title"; const closeButton = makeButton("✕", "닫기", onClose); closeButton.classList.add("b06-structure-panel__close"); const head = document.createElement("div"); head.className = "b06-structure-panel__head"; head.append(title, closeButton); root.append(head); return { root, head, title }; } const ARROW_SLOT: Record = { ArrowUp: "up", ArrowDown: "down", ArrowLeft: "left", ArrowRight: "right", }; /** * 키보드 방향키 = 십자 버튼. `containers` 중 숨겨지지 않은 첫 행의 슬롯 버튼을 * 누른다. 창이 숨겨지면 리스너를 떼고, 카드가 통째로 사라지면 스스로 해제한다. * 반환: show/hide 때 부를 (attach)와 (detach). */ export function bindArrowKeys( root: HTMLElement, containers: () => HTMLElement[], ): { attach: () => void; detach: () => void } { const onArrowKey = (event: KeyboardEvent): void => { if (!root.isConnected) { document.removeEventListener("keydown", onArrowKey); return; } const slot = ARROW_SLOT[event.key]; if (!slot || root.classList.contains("is-hidden")) return; const focus = event.target as HTMLElement | null; if (focus && (focus.tagName === "SELECT" || focus.tagName === "INPUT")) return; for (const container of containers()) { if (container.classList.contains("is-hidden")) continue; const button = container.querySelector( `.b06-structure-panel__btn--${slot}`, ); if (button) { event.preventDefault(); button.click(); return; } } }; return { attach: () => document.addEventListener("keydown", onArrowKey), detach: () => document.removeEventListener("keydown", onArrowKey), }; }