크라우니 오피스 마인드맵 punch #1 — 노드 트리 상태화 + 텍스트 편집 영속화
개요
마인드맵(ModuleMap) 모듈은 노드 트리(
const data)가 renderVals() 내부 로컬 const 라 편집 대상 모델이 없었다(실 state={sel,open,layout} 3개뿐, 슬라이드보다 한 겹 얕음). 이를
state.nodes(flat 트리 모델)로 승격(hoist)하고 노드 라벨을 contentEditable→모델 writeback 으로 영속화했다. 앱 번들 무수정(런타임 몽키패치), crownyBridge.js 신규 §21 installMapBridge(§20 슬라이드 대칭).
무엇을 했는지
- 한선씨 정본
bundle/office/bridge/마인드맵모델.한선 — flat nodes{id|parentId|label} 스키마·라벨 writeback·노드찾기·DFS 순회플랫·자식조회·시드·빈트리. hanseonc_high 컴파일 + crownyc run 자체시험 20/20 PASS(노드편집·트리순회·노드별독립·레이아웃보존·빈트리).
- crownyBridge.js §21 installMapBridge:
1. 노드 트리 상태화 — 로컬 const data 를 state.nodes(flat 트리)로 hoist(seedNodes, open→collapsed 이전으로 b0/b1/b2 하드코딩 함정 해소).
2. renderVals 몽키패치(
__crownyMapPatched 가드) — 원본 style 문자열·방사형 삼각함수·3레이아웃 wrap 규칙 1:1 보존, 데이터 소스만 모델로 교체(로컬 const 완전 대체).
3. DOM-fixup 폴링(150ms) — 현재 보이는 레이아웃의 노드 라벨을 contentEditable span 으로 승격 + input/blur writeback. 요소↔id 매핑은 원본 renderVals 와 동일 모델 순회 순서(구조 walk / 방사형 DFS zip).
4. 라벨 span mousedown/click stopPropagation — 편집 캐럿 배치 중 상위 위임 select 재렌더가 포커스를 뺏지 않게(노드 padding 클릭=선택 유지).
5. fiber walk(findMapLogic) — state 마커 {sel:string,open,layout} 로 마인드맵 인스턴스 식별(slides 없음).
실측(CDP :9333 headless Chrome, before/after)
- BEFORE: state.nodes 11노드 모델 구동(로컬 const 아님), DFS 순회 파리티, b0c2 DOM contentEditable=true.
- EDIT(실 DOM): b0c2 "노드 접기"→"★편집★" 모델 반영, b0c1 "멀티 커서" 불변(노드별 독립).
- AFTER: 방사형/트리/우측맵 3레이아웃 모두 b0c2 DOM="★편집★" + 뷰 반영 + 형제 유지(레이아웃 전환 후 편집 유지).
- 무회귀: chevron 접기 클릭→"접힘" 배지 표시, 편집값 모델 유지(엣지·접기 실작동 무회귀).
- 문서 회귀 27/27 PASS(회귀실행.sh — 시트/슬라이드/문서 무영향, 마인드맵은 신규 §21).
- ./CrownyAI(dist) 3초 생존 OK.
관련 파일
- /Users/ef/crownybrowser/bundle/office/bridge/마인드맵모델.한선 (한선씨 정본 20/20)
- /Users/ef/crownybrowser/bundle/office/bridge/crownyBridge.js §21 installMapBridge (dist 동기화)
- /Users/ef/crownybrowser/spec/마인드맵기능-판정표.md (punch #1)
잔여 이슈(후속 punch)
- 루트 노드는 템플릿 리터럴("기능<br>브레인스토밍")이라 편집 제외(선택 유지) — 필요시 DOM 구동 후속.
- punch #2~9: 노드 추가/삭제(Tab/Enter/componentDidMount 키보드)·이동/재부모·접기 레이아웃 통일(방사형/트리)·줌팬·색·아웃라인/슬라이드 내보내기.