- 조정창 방향키 듣기가 창이 숨은 보기에 있으면 넘김(Cross_Panel_Base · Cross_Structure_Panel 한 줄씩) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BU9gbNE3aWFUvE61pS2WGt
116 lines
4.6 KiB
TypeScript
116 lines
4.6 KiB
TypeScript
/* =============================================================================
|
|
* 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<string, string> = {
|
|
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];
|
|
// 보기가 숨었으면(한 페이지 두 보기 · 계획서 24-3a) 다른 보기의 방향키를 먹지 않는다.
|
|
if (!slot || root.classList.contains("is-hidden") || !root.getClientRects().length) 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<HTMLButtonElement>(
|
|
`.b06-structure-panel__btn--${slot}`,
|
|
);
|
|
if (button) {
|
|
event.preventDefault();
|
|
button.click();
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
return {
|
|
attach: () => document.addEventListener("keydown", onArrowKey),
|
|
detach: () => document.removeEventListener("keydown", onArrowKey),
|
|
};
|
|
}
|