diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel.ts b/B05_Profile/B05_Profile_UI_Structures_Panel.ts index fabeafe0..3516d813 100644 --- a/B05_Profile/B05_Profile_UI_Structures_Panel.ts +++ b/B05_Profile/B05_Profile_UI_Structures_Panel.ts @@ -158,7 +158,8 @@ export function createStructuresSection(callbacks: StructuresCallbacks): Structu } let types: StructureType[] = []; - let structures: StructureInstance[] = []; + // 배열 자체를 바꾸지 않는다(조각들이 참조로 들고 있음) — 내용만 갈아끼운다. + const structures: StructureInstance[] = []; let pipeFacilities: PipeFacilityItem[] = []; let editingId: string | null = null; /** 목록에서 고른 계곡 통과 시설(누가거리 키). 삭제 버튼이 이쪽으로 동작한다. */ @@ -171,7 +172,7 @@ export function createStructuresSection(callbacks: StructuresCallbacks): Structu * 순간(또는 폼에 위치를 실어 연 순간)에만 true. 옵션 활성화 시점도 임시 배치와 * 같은 이 순간이다(2026-08-18 사용자 지시). */ let positionConfirmed = false; - let optionInputs: Array<{ + const optionInputs: Array<{ key: string; required: boolean; input: HTMLInputElement | HTMLSelectElement; @@ -290,7 +291,9 @@ export function createStructuresSection(callbacks: StructuresCallbacks): Structu * 몫이라 그리지 않는다(B05 = 유무·종류·위치 단계, 2026-08-17 사용자 확정). */ function renderOptionFields(values: Record = {}): void { const type = currentType(); - optionInputs = []; + // 여기도 배열을 갈아끼우지 않는다 — 조각들이 참조로 받아 두므로 새 배열로 + // 바꾸면 옛 칸 목록을 읽어 저장값이 어긋난다(2026-09-04). + optionInputs.length = 0; optionRow.replaceChildren(); // 서브폼이 담당하는 타입(계곡 통과 시설·독립 기슭막이)은 여기서 그리지 않는다. const visible = type && !facilityFormKind(type) ? type.options.filter(isB05Option) : []; @@ -537,7 +540,10 @@ export function createStructuresSection(callbacks: StructuresCallbacks): Structu setStructures(next) { // 서버 정본 주입 — onChange를 울리지 않는다. 울리면 Page가 다시 저장을 걸어 // 저장→재조회→주입→저장의 무한 고리가 된다(변경 알림은 사용자 조작에서만). - structures = next.map((entry) => ({ ...entry })); + // 배열을 **갈아끼우지 않고 안을 채운다** — 저장·배선 조각(`_Commit`·`_Events`)이 + // 이 배열을 참조로 받아 두므로, 새 배열로 바꾸면 그쪽이 옛 배열을 고쳐 + // 목록에 반영되지 않는다(2026-09-04 실측: 저장 전 항목 [삭제]가 안 먹던 원인). + structures.splice(0, structures.length, ...next.map((entry) => ({ ...entry }))); // 실시간 반영으로 되돌아온 목록이면 폼을 닫지 않는다 — 고치던 칸이 사라진다. if (applyingLive) renderList(); else {