docs(org-chart): finalize expanded chart accessibility and usage

Document the shared Vanilla/React Auto API, company selection, styling ownership and preserved card design. Preserve P5-2/P5-3 and P5-4 implementation reports and their historical verification boundaries.
This commit is contained in:
shkim4 committed 2026-10-12 22:00:10 +09:00
1 parent 064517ec46
commit d2b76e7664
5 files changed
+482 -19

No files matched your search

+163
View File
@@ -0,0 +1,163 @@
# Expanded OrgChart 사용 및 스타일 — P5-4
2026-10-12 사용자 변경 요구사항으로 **현재 확장형 카드 외형과 크기를 유지**한다.
`Group 3391.svg`, `Group 1171288761.svg` 검색·재현·용도 배정은 이번 완료 조건에서 제외한다.
이 결정은 이전 P5-1B/P5-2/P5-3 검증 보고의 당시 미검증 기록을 변경하지 않는다.
Fixed의 승인 SVG·1920×914.5 구성·컬러·팝업은 기존 정책을 유지한다.
## Vanilla JS와 JSON Source
아래는 Vite를 사용하는 호스트의 공개 API 예시다. 순수 HTML 배포에서는 공개 CSS·ESM
산출물을 호스트가 제공하고 URL을 지정한다. 실행 가능한 HTML은
`examples/org-chart/expanded.html`과 `expanded-app.js`를 참고한다.
```js
import { createOrgChart, JsonOrgChartDataSource, getCompanyColorPreset } from '@hm-design/org-chart';
import engineCssUrl from '@hm-design/org-chart/engine.css?url';
import coreCssUrl from '@hm-design/org-chart/style.css?url';
import dataset from './data-expanded-small.json'; // 기존 20명 가상 JSON을 호스트에 복사
const chart = createOrgChart({
container: document.getElementById('chart'),
dataSource: new JsonOrgChartDataSource(dataset),
stylesheetUrls: { engine: engineCssUrl, core: coreCssUrl },
layoutMode: 'auto', // 'fixed' 또는 생략은 기존 Workdesk
displayMode: 'readOnly',
selectedCompanyIds: ['hanmac'], // 단일 회사
companyTopNodes: { hanmac: { title: '회장', display: 'card' } },
employeeConnections: { 'hanmac-office-0': 'left' },
zoom: { min: 0.05, max: 3, step: 1.2 },
});
await chart.mount();
await chart.setSelectedCompanies(['hanmac', 'saman']); // 복수 회사
await chart.setSelectedCompanies(); // 전체
await chart.setSelectedCompanies([]); // 명시적 빈 선택
chart.zoomTo(1); // 배율만 변경; 100% 도구 버튼은 이동 위치도 복원
chart.panBy(40, 0);
chart.fitToView();
console.log(chart.getViewportState(), getCompanyColorPreset('hanmac')?.primary);
// 호스트가 더 이상 컴포넌트를 사용하지 않을 때 chart.destroy()
```
`JsonOrgChartDataSource`는 인라인 JSON 또는 호스트가 제공하는 HTTP(S)/상대 URL을 받는다.
URL을 사용할 경우 `new JsonOrgChartDataSource('./data-expanded-large.json')`처럼 지정한다.
file:// Fetch는 지원하지 않는다. 이번 작업에 외부 API·서버·DB 구현은 추가하지 않았다.
현재 JSON 예시는 Small 20명/3회사, Medium 100명/5회사, Large 300명/7회사다.
## React
```tsx
import { useState } from 'react';
import { OrgChart } from '@hm-design/org-chart-react';
import { JsonOrgChartDataSource } from '@hm-design/org-chart';
import engineUrl from '@hm-design/org-chart/engine.css?url';
import coreUrl from '@hm-design/org-chart/style.css?url';
import dataset from './data-expanded-small.json';
const source = new JsonOrgChartDataSource(dataset);
const stylesheets = { engine: engineUrl, core: coreUrl };
const topNodes = { hanmac: { title: '회장', display: 'card' as const } };
const connections = { 'hanmac-office-0': 'left' as const };
export function ExpandedExample() {
const [selected, setSelected] = useState<string[] | undefined>(['hanmac', 'saman']);
return <>
<button type="button" onClick={() => setSelected(undefined)}>전체 회사</button>
<OrgChart dataSource={source} stylesheetUrls={stylesheets} layoutMode="auto"
displayMode="readOnly" selectedCompanyIds={selected}
companyTopNodes={topNodes} employeeConnections={connections} />
</>;
}
```
위 native 버튼은 React 계약만 설명하는 최소 예시다. HM 화면에서는 실제 기존
`Button`, `Checkbox`, `Label`, `Select`를 조합한다. Expanded Story가 그 사용 예다.
Source·옵션 객체를 안정적으로 유지한다. Core 생성 옵션(모드·TopNode·연결 방향·Zoom 설정)을
변경하면 React는 handle을 다시 생성한다. Vanilla는 새 handle을 생성한다.
회사 선택은 기존 setter/React prop으로 변경하며 원본 JSON과 parentId를 수정하지 않는다.
React에는 별도 레이아웃 알고리즘이나 imperative ref API가 없다.
## 테마·최상위 노드·연결 방향
회사 Root의 `Organization.companyId`가 자손에게 상속된다. 회사별 독립 Root와 기존
Employee 관계를 유지한다. `companyId` 생성 옵션은 기존 JSON의 회사 판별 fallback이며,
다중 회사 전체를 한 색으로 바꾸는 설정이 아니다.
| ID | 회사 | 메인 컬러 |
|---|---|---|
| hanmac | 한맥기술 | #CB2E28 |
| saman | 삼안 | #F08300 |
| jangheon-industry | 장헌산업 | #4580A6 |
| jangheon | 장헌 | #1D418D |
| ptc | 피티씨 | #84338E |
| halla | 한라산업개발 | #0068B7 |
| baron | 바론컨설턴트 | #0C367F |
표의 값은 기존 `getCompanyColorPreset(companyId)`에서 조회한다. 카드에 중복 하드코딩하지 않는다.
타이틀은 조직 회사, 카드 강조색은 알려진 직원 affiliation(미등록 시 조직 회사)의 프리셋을 쓴다.
삼안·장헌산업 타이틀은 기존 짙은 중립 텍스트 정책을 유지한다.
`companyTopNodes`는 `employeeId`, `title`, `name`, `profileImage`, `organizationName`,
`display: 'card' | 'titleOnly' | 'hidden'`을 지원한다. 생략 시 Root의 leaderId를 사용하며,
employeeId는 그 Root에 소속된 기존 직원이어야 한다. null은 최상위 카드 배정을 제거한다.
표시 override는 원본 identity·팝업 데이터·callback·관계를 바꾸지 않는다.
`employeeConnections`의 지원 값은 `top | left | right`다. Depth를 기준으로 정하지 않는다.
직원 연결선의 실제 도착점과 같은 면에만 회사 Border를 표시하며, 조직장은 타이틀 아래
상단 연결을 사용한다. 다른 면은 중립, 강조는 inset이라 외형 크기가 변하지 않는다.
연결 없는 카드에 임의로 accent를 붙이는 별도 `none` API는 없다. 현재 Auto presenter의
렌더링된 카드는 모두 타이틀 또는 이전 카드/분기 rail과 연결된다.
## 접기·펼치기와 직원 팝업
그룹 타이틀 전체 native button은 click·Enter·Space로 접기/펼치기하며 `aria-expanded`와
표시 기호를 갱신한다. 조직장은 유지하고 일반 직원·자손을 숨기며 형제 상태는 독립이다.
부모 재확장 시 유효한 하위 상태를 유지한다. 하위 직원/조직 없는 타이틀은 disabled다.
그룹 링크는 별도 아이콘으로 페이지 이동과 토글 동작을 분리한다.
공개 프로그래밍 방식 collapse setter는 제공하지 않는다.
직원 카드는 click·Enter·Space로 공통 직원 정보 dialog를 연다. dialog는 변환 forest 밖의
native top layer에 표시되므로 Zoom과 Stage overflow의 영향을 받지 않는다.
ESC/닫기 버튼과 focus trap·카드 focus 복귀를 제공한다.
`onEmployeeClick(employee, context)` 지정 시 기본 팝업 대신 callback을 호출하며
호스트가 dialog 접근성·닫기·focus 복귀를 책임진다.
P5-4는 Tab으로 화면 밖 카드·타이틀에 도달하면 **배율을 유지하고 Pan으로 표시**한다.
드래그 직후 포인터 click만 억제하고 이후 Enter/Space 활성화는 허용한다.
실제 스크린리더 음성·실제 모바일 터치는 별도 검증 대상이다.
## 카드 CSS 관리
현재 기본 카드 크기는 일반 직원 width 114px/min-height 54px, 조직장·최상위
width 154px/min-height 72px이며 사진은 36×36px
비원형 슬롯이다. 직위/이름 10/13px, Noto Sans KR, padding 8px, 기본 border 1px,
inset accent 3px를 유지한다. 3글자 한글 이름은 `홍 길 동`처럼 표시하며 직위 공백은
표시 계층에서만 제거한다. 긴 가상 이름이 두 줄이면 일반 직원의 실측 높이는 67px로
자연 확장된다(기존 동작). 실제 profileImage를 우선하고 없음/실패는 기존 공통 사람 SVG다.
Card geometry는 `packages/org-chart/src/styles/org-chart-expanded.css`에 Auto 전용으로 관리한다.
원본 Fixed CSS·SVG·Theme는 수정하지 않는다. `layoutConfig`·카드 교체 API는 없다.
Core는 Shadow DOM을 사용하므로 일반 호스트 CSS selector는 내부 카드에 닿지 않는다.
향후 별도 디자인 변경이 승인된다면 호스트가 공개 Core CSS 뒤에 다음 override를 결합한
CSS 자산을 만들고 그 URL을 `stylesheetUrls.core`로 제공할 수 있다(이번에는 적용하지 않음).
`--hm-orgchart-expanded-*` 중 내부 선언이 있는 변수는 호스트 div에 설정하면 덮어써질 수
있으므로 **Shadow DOM에 로드되는 CSS의 `.hm-orgchart-expanded`에서 재정의**한다.
```css
/* 공개 Core CSS 다음에 결합하는 Auto 전용 예시. 임의 신규 API가 아니다. */
.hm-orgchart-expanded {
--hm-orgchart-expanded-card-width: 114px;
--hm-orgchart-expanded-card-height: 54px;
--hm-orgchart-expanded-leader-width: 154px;
--hm-orgchart-expanded-leader-height: 72px;
--hm-orgchart-expanded-card-accent-width: 3px;
--hm-orgchart-expanded-photo-size: 36px;
}
```
크기 변경 시 기존 ResizeObserver가 article의 실측 높이와 실제 endpoint를 재계산한다.
향후 변경에는 Fit·형제/하위 트리 겹침·텍스트 overflow를 다시 확인해야 한다.
이번 P5-4는 기본 geometry를 바꾸지 않으며 대용량 성능의 과거 수치를 재측정하지 않는다.
검증 범위와 실행 URL·캡처는 [P5-4 보고서](implementation-report-p5-4.md)를 참고한다.
@@ -0,0 +1,103 @@
# HMDesign OrgChart P5-2 + P5-3 구현 보고
RESULT: **PARTIAL** — 요청된 기능 구현·변경 범위 검증은 PASS. 참고 SVG 두 개의 원본 일치와 최종 카드 디자인 승인, 물리적 터치·스크린리더 검증은 NOT VERIFIED.
## 작업 환경 및 시간
- 실제 폴더: `D:\디자인시스템\HMDesign-orgchart-package`
- 브랜치: `feature/orgchart-package`
- HEAD: `a92913d6bcc950dacc6fdf21cf3b0843ee79416d` (시작/완료 동일)
- origin: `https://gitea.hmac.kr/b25027/HMDesign.git`
- P5-1B 채팅 완료 상태와 미커밋 변경을 확인한 뒤 확장. 시작 시 변경 12파일·신규 검증 스크립트 1개를 보존. 시작 diff는 `test-results/org-chart-p5-23/p5-1b-before.patch`, 비교 dist는 같은 폴더의 `baseline-dist`.
- 작업 범위: BOTH — 공통 Core·HTML·React와 요청된 기존 Expanded Story. 운영 프로젝트·main 수정 없음. 신규 페이지 Navigation 없음(임베드 조직도 컴포넌트).
- Started At: 2026-10-12 19:27:14 KST
- Completed At: 2026-10-12 19:52:30 KST
- Actual Duration: 25분 16초
- Estimated Duration: 60–90분 (확인 10분 / 구현 35–55분 / 검증 15–25분)
- Variance: 최초 예상 하한보다 34분 44초, 상한보다 64분 44초 빠르게 완료.
## 기능 결과
| 항목 | 결과·근거 |
|---|---|
| 회사 전체·단일·복수·해제 | PASS. 독립 Root Forest를 가로 배치. undefined=전체, []=빈 상태. 원본 직원 수 불변, 선택 인원 별도 표시. |
| 회사 ID·계층 | PASS. 선택적 `Organization.companyId`, 부모 상속, 다른 회사 부모·자식 연결 오류. 기존 JSON은 알려진 Root leader affiliation 또는 기존 companyId fallback. |
| 회사별 최상위 | PASS. 기존 Root·Employee 그대로 사용. 직위·이름·조직명 override, card/titleOnly/hidden, employeeId/null. 예시는 회장·사업총괄·본부장 등과 최상위 직원 없는 바론. 이미지 URL 검증과 표시 경로 지원; 별도 프로필 이미지 변경의 시각 검증은 NOT VERIFIED. |
| 그룹 타이틀 | PASS. 전체 타이틀 native button, Enter/Space, aria-expanded, 빈 그룹 disabled. 조직장 유지·직원/하위 조직 숨김. 부모 재확장·회사 재선택 시 유효한 자식 상태 보존. 별도 링크 아이콘으로 이동. |
| 재귀 자동 배치 | PASS. dabeng 6.0.0 Forest 유지. 형제 가로 배치, 자신의 부모 아래 자식, 동일 Depth 높이 예약. Small 0–2, Medium 0–3, Large 0–4 Depth. 카드 겹침 0, 실제 DOM parentId 일치. |
| Zoom/Pan/Fit | PASS. 기본 5–300%, 설정 min/max/step. 확대/축소/100%/Fit, 현재 배율. Ctrl/Command+휠, 드래그, 방향키. 일반 휠에는 preventDefault하지 않음. 직원 카드 드래그 팝업 억제. 합성 touch PointerEvent 경로 PASS; 물리적 터치는 NOT VERIFIED. |
| 회사 테마 | PASS. 기존 7개 ID·메인 색상 모두 정확. P5-0 파일 변경 없음. 보조색 변수 보존. 삼안·장헌산업 제목은 대비를 위해 중립 짙은 텍스트. |
| 직원 Border | PASS. 직원 회사 affiliation의 기존 preset(미등록 affiliation은 조직 회사)을 CSS 변수로 참조. 실제 SVG endpoint와 top/left/right 면 일치, 나머지 중립. 3방향 실제 예시 모두 확인. inset accent 두께 변수로 외형 크기 보존. |
| 확장형 카드 | PASS(기능). 공통 비원형 사람 아이콘, 실제 이름·직위, Noto Sans KR, 홍길동→홍 길 동. Auto 전용 Width/Height/Padding/Border/Radius/사진/Font/간격 변수. 승인 SVG 재현은 NOT VERIFIED. |
| 직원 정보 팝업 | PASS. 공통 Core dialog, 변환 Forest 밖, focus·Escape 복귀. 표시 override에도 원본 직원 identity·callback 데이터 유지. |
| Fixture | PASS. Small 20명·3회사, Medium 100명·5회사, Large 300명·7회사. 고유 Employee ID, 유효 parentId·leader membership, 중복 없는 조직장 집계. 고정 JSON·결정적 생성 스크립트. 실제 개인정보 없음. |
| HTML·React | PASS. 실제 HTML 예시와 StrictMode React Story의 ID·직위·이름·크기·회사·색·방향 일치. 필터 로직은 Story가 아닌 Core. DataSource 계약 유지, API/DB 구현 없음. |
| Fixed | PASS. P5-1B 시작 dist와 현재 dist의 카드 좌표·크기·SVG·이름·직위·색 정확 비교 및 공통 팝업 최소 회귀. Fixed CSS·SVG·Full Composition Story 변경 없음. |
| Storybook | PASS. 사용자 메뉴 4개 유지. Expanded 하나에 20/100/300명·회사 체크박스·전체/해제 및 공통 확대 도구. |
## 실제 사용 요소·선택 근거
React Story는 공개 `@hm-design/ui`의 Button, Checkbox, Label, Select/Trigger/Value/Content/Item을 실제 렌더링한다. Label은 실제 control ID와 연결한다. FilterBar를 검토했으며 이번 도구는 검색·조회 조건이 아니라 Fixture 전환과 즉시 회사 표시 상태이므로 기존 Pattern의 목록 검색 구조를 강제하지 않았다. 체크박스 복수 선택과 Select를 직접 조합한다.
공통 Core는 React 의존성 없는 명시적 HTML Runtime adapter다. 그룹·Zoom native button과 HTML 예시의 native select/checkbox/label은 이 계약의 접근성 요소이며 HM React UI 모방이 아니다. Core·Wrapper·DataSource 역할을 유지한다.
## 성능 측정
Windows 로컬 Headless Chrome, 1440×1000, 실제 300명 JSON. 아래는 측정치이며 임의 성능 기준에 따른 PASS 판정이 아니다.
| 처리 | 실측 |
|---|---:|
| Small 최초 mount (모듈·CSS + 2 animation frames) | 93.3ms |
| Medium 최초 mount (동일 방식) | 93.9ms |
| Large 최초 mount (동일 방식) | 195.6ms |
| 300명 그룹 접기 (native click + 2 frames, 두 측정) | 222.7 / 281.9ms |
| 자동화 Enter/Space 접기·펼치기 (조작·focus·프레임 대기 포함) | 317.9–656.8ms |
| 300명→단일 회사 선택 + 재배치 2 frames | 42.0ms |
| Zoom + 60회 panBy + 1 frame (두 측정) | 20.5 / 0.9ms |
대용량 전체 DOM 누락·중복·카드 겹침 없음. 위 pan 일괄 호출은 실기기 프레임율/FPS를 뜻하지 않는다. 최초 mount 수치에는 초기 스크립트 경로 비용이 포함되며 다운로드 성능 인증이 아니다. 별도 가상화·엔진 교체·신규 라이브러리 설치 없음.
## 변경 범위 검증
- Core typecheck PASS; Core ESM/IIFE 및 선언 build PASS.
- React Wrapper typecheck·선언/ESM build PASS; 앱/Story TypeScript 검사 PASS.
- Expanded Story만 소비하는 독립 React bootstrap의 Vite production build PASS. 500kB 초과 chunk 경고 있음(기존 Core 이미지 자산 포함); 빌드 오류 아님. 결과: `test-results/org-chart-p5-23/react-build/dist/index.html`.
- 영향 범위 단위 테스트 **7/7 PASS**. Node 20의 globSync 부재로 최초 실행 불가였으며, 제공된 Node 런타임으로 정상 실행. 기존 전체 테스트를 반복하지 않음.
- 브라우저 **96/96 PASS**, 신규 console/runtime error 0. 실행기 선택자 오류를 수정하고 미완료 범위만 이어서 확인. 390/768/1280/1440px 가로 넘침·핵심 도구 확인.
- `git diff --check` PASS. 원래 CRLF 전환 안내는 공백 오류와 구분.
- 원본 Guard: PARTIAL/STORYBOOK profile, staticStatus **PASS**, 원본 status **PASS**, issues 0. Runtime은 자체 수행하지 않으므로 **NOT VERIFIED**.
- CSS 원본 styleEvidence: STATIC **PASS**, RUNTIME **NOT VERIFIED**, DESIGN_INTENT **NOT VERIFIED**, FINAL **NOT VERIFIED**.
- 별도 browser/runtime 증거 연결: fingerprint 일치 linked=true. 결합 status와 styleVerification은 **NOT VERIFIED** 유지. STORYBOOK profile에는 Production `--result` bootstrap 판정이 없으며 최종 디자인 승인·개별 CSS 적용 전 상태 검증도 미완료. 직접 실행된 React 브라우저 결과 PASS와 혼동하지 않음.
- Guard는 Story host 소비 범위이며 Core 내부의 모든 CSS를 승인하는 검사가 아니다. Core 연결 방향·색상·좌표는 별도 브라우저 근거에 기록.
- P5-1B 879/879 PASS 기록 보존. 과거 전체 회귀·기존 미검증 결과를 새 결과로 덮어쓰지 않음.
자동 승인 검토는 `0.0.0.0` Storybook 실행을 LAN 노출 위험으로 거부했다. `127.0.0.1`로만 바인딩한 안전한 실행은 승인·검증됐으며, 초기 sandbox 서버는 종료했다. 기능·작업에 남은 승인 차단 없음.
## 실행 URL·캡처·원시 근거
- [Expanded OrgChart](http://127.0.0.1:6054/?path=/story/orgchart--expanded-org-chart)
- [HTML 예시](http://127.0.0.1:4189/expanded.html)
- `test-results/org-chart-p5-23/browser.json`, `guard.json`, `runtime.json`, `combined.json`
- `storybook-large-1440.png`: 7회사·300명 Fit 전체 화면.
- `storybook-small-hanmac-100.png`: 한맥기술·100%·상단/좌측/우측 Border와 연결선.
- `storybook-{390,768,1280,1440}.png`: 반응형 실제 React 화면.
- `html-{small,medium,large}-fit.png`, `fixed-1440.png`: HTML Fixture 및 최소 Fixed 회귀.
## 이번 추가·수정 파일
기존 P5-1B 변경 전체를 이번 변경으로 주장하지 않는다. P5-1B의 `data-expanded.json`, `expanded-layout.test.ts`, `verify-p5-1b.mjs`는 그대로 보존했다.
- Core: `packages/org-chart/src/core/{index,types,render,employee-card,expanded-content,expanded-layout}.ts`; 신규 `expanded-company.ts`, `expanded-company.test.ts`, `expanded-viewport.ts`.
- 데이터 계약: `packages/org-chart/src/data/{types,validate}.ts`, `packages/org-chart/src/index.ts`, `docs/org-chart/data-contract.md`.
- 스타일: `packages/org-chart/src/styles/org-chart-expanded.css`.
- React: `packages/org-chart-react/src/OrgChart.tsx`.
- Story: `src/org-chart/org-chart-expanded.stories.tsx`, `org-chart-stories.css`.
- HTML/Fixture: `examples/org-chart/prepare.mjs`; 신규 `expanded.html`, `expanded-app.js`, `expanded.css`, `create-expanded-fixtures.mjs`, `data-expanded-small.json`, `data-expanded-medium.json`, `data-expanded-large.json`, `verify-p5-23.mjs`.
- 문서: `packages/org-chart/README.md`, `packages/org-chart-react/README.md`, 이 보고서.
- generated dist·검증 JSON·스크린샷·비교본은 기존 gitignore의 test-results/dist 경로. 소스 Stage 없음.
## 남은 미검증·Git 상태
참고 `Group 3391.svg`, `Group 1171288761.svg`의 원본 구조·최종 디자인 일치, 물리적 터치, 스크린리더 음성, 다른 브라우저·운영 소비자, 전체 heap/GC 회수, 전체 과거 회귀는 NOT VERIFIED. 최상위 profileImage 변경의 별도 시각 검증도 NOT VERIFIED. 기존 미검증을 기능 PASS로 제거하지 않았다.
**Commit·Push·Merge·Stage 미진행. Reset/Rebase/Force Push/Clean 미진행. main·운영 프로젝트·Fixed SVG/CSS 미수정. P5-4 미시작.**
@@ -0,0 +1,123 @@
# HMDesign OrgChart P5-4 완료 보고
RESULT: **PASS — 변경된 P5-4 요구사항의 구현·변경 영향 범위.**
전체 접근성 인증·실기기·모든 CSS 의도 검증은 **PARTIAL / NOT VERIFIED**이며 아래에 구분한다.
## 확정 범위와 환경
- 실제 작업 폴더: `D:\디자인시스템\HMDesign-orgchart-package`
- 브랜치: `feature/orgchart-package`
- 시작/완료 HEAD: `a92913d6bcc950dacc6fdf21cf3b0843ee79416d`
- origin: `https://gitea.hmac.kr/b25027/HMDesign.git`
- 범위: BOTH — 기존 Vanilla/React 공통 Core와 Expanded Story의 안내·문서 보완.
- 사용자 후속 확정: 현재 Expanded 카드 외형·크기·사진·직위·이름 구조를 유지한다.
`Group 3391.svg`, `Group 1171288761.svg`는 검색·적용·용도 배정 대상에서 제외하며,
SVG 미확보는 완료 차단 사유가 아니다. SVG 역할을 추정하지 않았다.
- 기존 P5-1B 879/879 및 P5-2·3 96/96·단위 7/7 기록은 과거 근거로 보존한다.
이번 결과는 그 전체 검사를 다시 실행했다는 의미가 아니다.
## 구현과 보존 결과
| 항목 | P5-4 결과 |
|---|---|
| 카드 외형·크기 | PASS. 시작 dist와 Small 20명의 카드 size/photo/font/color/border 정확 비교 일치. 기본 일반 직원 width 114/min-height 54px, 긴 가상 이름 실측 114×67px. 조직장·최상위 width 154/min-height 72px. 변경 전후 동일. |
| 사진·직위·이름 | PASS. 비원형 36×36 슬롯·공통 사람 SVG·Noto Sans KR computed family·직위 10px/이름 13px 유지. 표시용 직위 공백만 제거, raw 데이터 불변·원문 aria-label 제공. 가상 SVG profile URL override와 error-event placeholder 복귀 확인. 실제 사람 사진은 미사용. |
| 그룹 타이틀 | PASS. 기존 전체 버튼·상태 기호·aria-expanded·키보드 Focus·별도 링크 유지. 활성 타이틀 및 링크에 Hover 배경 피드백 추가. Enter 접힘·Space 펼침·rerender 후 focus 복귀 확인. |
| 회사 컬러·Border | PASS. 기존 7개 preset·회사 ID 불변. top/left/right 실제 endpoint 오차 1px 미만, 강조 한 면·나머지 중립·외형 크기 유지. 연결 없는 카드용 `none`은 지원 API가 아니며 별도 PASS 처리하지 않음. |
| 자동 배치·연결선 | PASS. 기존 dabeng 재귀 엔진·실측 ResizeObserver 유지. Medium/Large 직원 중복·누락·카드 겹침 없음, DOM 부모 관계와 부모 아래 자식 확인. 엔진 재작성·간격/색/크기 재작업 없음. |
| 다중 회사 | PASS. Large에서 두 회사 독립 Root 및 단일 선택 확인. 원본 JSON 및 source 인원 불변. 전체/해제·자식 collapse state 보존 등 변경 없는 상세 동작은 P5-2·3 근거 재사용. |
| Zoom/Pan/Fit | PASS. 기존 도구와 배율 범위 유지. 새 Tab focus가 화면 밖 카드/타이틀에 도달하면 배율 유지·Pan으로 노출, hidden scrollLeft/Top 0 확인. 실제 mouse Pan 및 Medium/Large Fit에 전체 카드 포함 확인. |
| 드래그·키보드 | PASS. 드래그의 pointer click 억제가 다음 Enter/Space 활성화를 막지 않도록 수정. 이후 Space 직원 팝업 활성화 확인. 기존 Pan 알고리즘 재구현 없음. |
| 직원 팝업 | PASS. 직원 이름·직위의 의미 있는 카드 이름, dialog 제목·닫기 이름, forest 밖·transform 없음, focus 내부·ESC 복귀 확인. 기존 공통 native dialog 재사용. |
| 20/100/300명 | PASS. 기존 JSON 그대로 사용. Medium/Large HTML의 고유 인원·전체 Fit, React Small 및 Large 300명 선택·겹침 없음 확인. 새 fixture·실제 개인정보 없음. |
| HTML/React | PASS. Small의 카드 identity·size·photo·표시 텍스트·font-size·중립 border 동일. 실제 Story와 production React bootstrap 모두 같은 Core 실행. 별도 React 엔진 없음. |
| Fixed | PASS(최소 회귀). 시작 dist와 카드 좌표·size·SVG asset·직위·이름·컬러·사진 정확 일치. Auto 토글 0, 공통 팝업 최소 회귀 확인. Fixed CSS·SVG·Full Composition Story 미수정. |
| Storybook | PASS. 사용자용 4개 메뉴 유지. 기존 internal Story는 사용자 메뉴 집계에서 제외. 안내의 SVG 미확보 문구 제거·P5-4 접근성 이름 갱신. 신규 Story 없음. |
## 접근성·검증 범위
- 실제 키보드 자동화: 그룹 Focus outline·Enter/Space·직원 Space·Tab으로 화면 밖 요소 표시·ESC/Focus 복귀 **PASS**.
- DOM/ARIA: 타이틀 이름·펼침 상태·카드 직원 정보 이름·dialog 제목·닫기 버튼·React 회사 Checkbox 및 데이터 Select 이름 **PASS**.
- 터치: Chrome mobile/hasTouch 에뮬레이션의 title tap, CDP touch Pan, card tap 팝업·닫기 **PASS**. 실제 모바일 기기는 **NOT VERIFIED**.
- 실제 스크린리더 발화, 다른 브라우저 엔진·운영 소비자, 전체 과거 회귀, 종합 자동 접근성 audit는 **NOT VERIFIED**.
- Noto는 computed family 및 기존 host font-face 로딩 확인이다. 실제 font glyph의 CDP 재측정은 하지 않았으며 P3.1 검증 기록을 보존한다.
- 390/768/1280/1440px: 실제 React 문서 가로 overflow 없음·카드 20명 유지·hidden viewport scroll 0 **PASS**.
문서 및 viewport scrollHeight/clientHeight 원시 값은 `browser.json`에 보존한다.
- 100%에서 큰 조직도가 viewport 밖으로 이어지는 것은 기존 Pan 탐색 동작이며, 전체 표시 여부는 Fit 상태에서 판정했다.
- 기존 조직 ID는 dataset·ARIA 동작 대상에 유지된다. 이번 화면은 개발용 조직 ID 텍스트를 표시하지 않으므로 ID 한 줄 표시 검사는 NOT APPLICABLE.
- 빈 그룹 disabled는 기존 구현을 유지했다. disabled/readOnly의 모든 입력 조합 재검사는 NOT VERIFIED.
기존 실제 React UI는 `@hm-design/ui` Button/Checkbox/Label/Select를 사용한다.
이 작업은 fixture/즉시 회사 표시 도구이며 FilterBar 목록 검색 구조를 추가할 필요가 없어
P5-2·3의 미사용 근거를 유지한다. 페이지 Navigation 없는 임베드 컴포넌트이며 신규 Navigation 없음.
Core native button/dialog는 명시적 Vanilla adapter 계약이다.
## 최종 통합 검증
- Core Typecheck 및 ESM/IIFE·선언 Build **PASS**.
- React Wrapper Typecheck·선언/ESM Build 및 앱/Story TypeScript **PASS**.
- 기존 Expanded Story를 소비하는 별도 production React Build **PASS**.
기존 이미지 자산에 의한 500kB 초과 chunk 경고는 유지하며 빌드 오류와 구분한다.
- 변경 영향 브라우저 **46/46 PASS**, 마지막 세 실행 경로 console/runtime errors **0**.
초기 검사 runner 오류(부모 중심 범위의 잘못된 제한·검증 URL data scheme·internal Story 집계·자산 라우팅·favicon 404)를 수정했다.
초기 실패 JSON을 보존하고 성공 25개→45개를 재사용하여 실패·미완료만 확인했다.
제품 코드 FAIL을 숨기거나 과거 Guard 결과를 바꾸지 않았다.
- 기존 단위 7/7 및 과거 전체 브라우저 suite는 **재실행하지 않음**. DOM 동작 변경은 위 통합 브라우저로 검증.
- `git diff --check` **PASS**. CRLF 전환 안내는 공백 오류가 아니다.
- Guard는 변경한 Expanded 소비 Story에 PARTIAL/STORYBOOK profile로 **1회** 실행.
원본 `status=PASS`, `staticStatus=PASS`, issues=0, `runtimeStatus=NOT VERIFIED`.
- 원본 styleEvidence: STATIC **PASS** / RUNTIME **NOT VERIFIED** / DESIGN_INTENT **NOT VERIFIED** / FINAL **NOT VERIFIED**.
- 별도 Runtime 증거 fingerprint 연결 `linked=true`; 결합 status **NOT VERIFIED**.
결합 styleVerification도 STATIC **PASS**, 나머지 세 항목 **NOT VERIFIED** 유지.
Storybook profile에는 Production `--result` 증명이 없고 전체 host CSS 의도 검증을 수행하지 않는다.
실제 production React 빌드·브라우저 PASS와 Guard 자동 판정을 구분한다.
- 현재 카드 유지의 사용자 확정은 모든 소비 CSS·외부 입력 상태의 포괄적 승인으로 확대하지 않는다.
- 카드 geometry·엔진이 동일하므로 성능을 재측정하지 않았다. 이전 195.6ms/42ms는 다른 작업의 조건부 기록으로 보존한다.
## 실행 화면·캡처·문서
- [Expanded OrgChart](http://127.0.0.1:6054/?path=/story/orgchart--expanded-org-chart)
- [Vanilla HTML 예시](http://127.0.0.1:4189/expanded.html)
- production React: `test-results/org-chart-p5-4/react-build/dist/index.html` (브라우저 검증 중 로컬 서버로 실행, file:// 직접 실행용 아님).
- `storybook-large.png`: 기존 7회사·300명 전체 Expanded 화면.
- `cards-100-percent.png`: 카드·상단/좌측 강조 연결선 100% 탐색 화면.
- `group-collapsed.png` / `group-expanded.png`: 동일 그룹 접힘·펼침 비교.
- `two-companies.png`: 2회사 독립 Root.
- `html-large-fit.png` / `html-medium-fit.png`: 300/100명 HTML Fit.
- `storybook-{390,768,1280,1440}.png`: 4개 폭 실제 React 화면.
- `touch-emulation.png`, `fixed-1440.png`: 터치 에뮬레이션·Fixed 최소 회귀.
- 캡처와 원시 근거는 모두 `test-results/org-chart-p5-4/`. 실제 직원 개인정보 없음.
- [사용 예제 및 스타일 관리](expanded-usage.md): Fixed/Auto, 컬러, 단일/복수 회사,
collapse, Zoom/Pan, JSON Source, popup, Shadow DOM CSS 변수 및 연결 방향을 실제 공개 API로 설명.
없는 collapse setter·layoutConfig·React imperative ref를 지원한다고 문서화하지 않음.
## 이번 실제 변경 파일
시작 시 미커밋 32개 파일을 snapshot/hash로 기록했다. 아래 기존 파일 7개만 이번에 추가 보완했으며,
나머지 25개는 시작 hash와 정확히 일치한다. 기존 미커밋 변경을 이번 신규 구현으로 주장하지 않는다.
1. `packages/org-chart/src/core/employee-card.ts` — Auto 직위 표시·원문 접근성 이름.
2. `packages/org-chart/src/core/expanded-viewport.ts` — 화면 밖 focus 표시·drag 이후 keyboard click·frame cleanup.
3. `packages/org-chart/src/core/expanded-content.ts` — current presentation 상태.
4. `packages/org-chart/src/styles/org-chart-expanded.css` — Auto title/link Hover·radius 상속, 기준 주석.
5. `src/org-chart/org-chart-expanded.stories.tsx` — P5-4 이름·SVG 안내 제거.
6. `packages/org-chart/README.md` — 현재 카드 기준·접근성·문서 링크.
7. `packages/org-chart-react/README.md` — 동일 기준·공통 Core 보완 설명.
8. 신규 `docs/org-chart/expanded-usage.md` — 사용·스타일·지원 경계.
9. 신규 `examples/org-chart/verify-p5-4.mjs` — 변경 영향 검증 runner.
10. 신규 이 보고서.
과거 보고·fixture·공개 타입/API·회사 preset·자동 레이아웃 엔진·Fixed 자산은 이번에 변경하지 않았다.
검증 산출물·시작 patch/dist/hash는 기존 ignored `test-results`에 저장했다.
**Stage·Commit·Push·Merge·PR 미진행.** 시작/완료 HEAD 동일, staged diff 없음.
Reset·Rebase·Force Push·Clean 없음. 운영 main·다른 프로젝트 수정 없음.
## 작업 시간 (Asia/Seoul)
- Started At: 2026-10-12 21:23:35 KST
- Completed At: 2026-10-12 21:41:32 KST
- Actual Duration: 17분 57초
- Estimated Duration: 최초 45–60분 (자료 확인 10분 / 구현 20–30분 / 검증·보고 15–20분)
- Variance: 예상 하한보다 27분 03초, 상한보다 42분 03초 짧음.
- 시간 차이는 사용자 확정으로 SVG 재작업이 제외되고 기존 PASS를 재사용한 결과다.
+11 -4
View File
@@ -44,8 +44,15 @@ Named runtime export: `OrgChart`. Type exports: `OrgChartProps` and the Core's p
- Required `dataSource`: the same Core `OrgChartDataSource` interface, `load(options?: { signal?: AbortSignal }): Promise<unknown>`.
- Required `stylesheetUrls`: `{ engine: string; core: string }`, the exact Core asset contract.
- Optional `displayMode`: `'interactive'` (default) or `'readOnly'`, passed to the Core composition. Changing it recreates the Core handle.
- Optional `layoutMode`: `'fixed'` (default) or `'auto'`, independent of `displayMode`. Auto is the P5-1A initial-group preview; automatic recursive layout, collapse and Zoom/Pan remain deferred. Changing it recreates the same Core handle.
- Optional `companyId`: existing Expanded company preset ID (default `hanmac`). Changing it recreates the handle; Fixed ignores company colors. Unknown Auto IDs report a Core construction lifecycle error. All seven IDs and preview limits are documented in the [Core README](../org-chart/README.md#layout-boundary-p5-1a).
- Optional `layoutMode`: `'fixed'` (default) or `'auto'`, independent of `displayMode`. Auto renders company forests, collapse and Zoom/Pan/Fit. P5-4 retains the current Expanded card presentation by user decision; external SVG matching is no longer required. Changing mode recreates the Core handle.
See [Expanded usage and styling](../../docs/org-chart/expanded-usage.md) for company
selection, top nodes, JSON sources, popup ownership and Auto-only CSS examples.
Keyboard focus reveals offscreen controls at the current Zoom; group-title Hover
feedback and drag/keyboard activation are implemented in the shared Core.
- Optional `companyId`: legacy Auto fallback company preset (default `hanmac`). Explicit/inherited organization company identity takes priority; Fixed ignores company colors. Changing it recreates the handle. See [Core README](../org-chart/README.md#layout-boundary-p5-2--p5-3).
- Optional `selectedCompanyIds`: undefined selects all, [] selects none. Changes call Core selection on the existing instance, preserving per-company collapse state and source counts.
- Optional `companyTopNodes`, `employeeConnections`, `zoom`: immutable Core configuration maps/range. Identity changes recreate the handle; memoize these objects. Names, positions and profile overrides affect only Auto presentation, not callback data.
- Optional `organizationLinks`: existing organization-ID-to-URL map, applied only to original 1Depth titles. Missing/blank values retain plain titles. Core validates HTTP(S)/relative URLs and rejects invalid URLs, other schemes and credentials. Treat the map as immutable and memoize it; a new map recreates the handle.
- Optional `onEmployeeClick(employee, context)`: host-owned information UI, replacing the Core's built-in popup. `context` contains the existing `organization`, `affiliation`, focusable `trigger` card and `originalEvent`. It works in both modes and receives untouched Employee data.
- Optional `aggregationPolicy`: the Core's `ApprovedAggregationPolicy`.
@@ -79,7 +86,7 @@ Changing callback identity updates the latest committed callback without reload
Cleanup invalidates the wrapper generation, unsubscribes, calls Core's terminal `destroy()` and clears its handle reference. React Strict Mode's setup → cleanup → setup uses a fresh handle. Old generations cannot deliver state/lifecycle callbacks to the new instance; superseded operation rejection handlers are also ignored. Cleanup runs before replacement, leaving at most one active Core per wrapper container. The wrapper does not repeat engine disposal or DOM removal itself.
Core regeneration resets expansion/scroll state according to the existing Core contract. Source errors can recover by replacing the source; Core validation/summary/node behavior remains identical to Vanilla. Invalid runtime Props that prevent Core construction are lifecycle usage errors: fix them and remount the component (for example by changing its React key). No rendered fallback silently replaces an invalid configuration.
Auto retains valid organization collapse state on source/selection updates, fits reloads/selection and restores toggle focus. Fixed retains its previous regeneration policy. Source errors can recover by replacing the source; Core validation/summary/node behavior remains identical to Vanilla. Invalid runtime Props that prevent Core construction are lifecycle usage errors: fix them and remount the component (for example by changing its React key). No rendered fallback silently replaces an invalid configuration.
Committed callback publication, Core ownership and source updates use layout effects in that order. Cleanup/reload runs synchronously with React commit, so a pending old response cannot notify in a gap before passive cleanup. Server rendering produces only the outer container; SSR/hydration remains outside the verified scope.
@@ -94,4 +101,4 @@ npm run typecheck --workspace @hm-design/org-chart-react
npm run build --workspace @hm-design/org-chart-react
```
Storybook is one React host, not proof of every consumer deployment. This adapter does not add pan/zoom, advanced mobile reflow, additional relation overlays or reserved Core presentation sections. SSR/hydration, full screen reader behavior, complete heap/GC recovery, Theme-less rendering, Workdesk reference visual approval and production consumers require their own evidence. Public ESM import without a DOM does not establish SSR/hydration support. Consult the final integration report for the actual typecheck/build/browser/consumer results.
Storybook is one React host, not proof of every consumer deployment. The adapter delegates Auto Pan/Zoom to Core; it adds no alternate layout, additional relation overlays or API client. SSR/hydration, full screen reader behavior, physical touch, complete heap/GC recovery, Theme-less rendering, Workdesk reference visual approval and production consumers require their own evidence. Public ESM import without a DOM does not establish SSR/hydration support. Consult the final integration report for the actual typecheck/build/browser/consumer results.
+82 -15
View File
@@ -24,25 +24,61 @@ chart.destroy();
## Organization links and employee information (P3)
### Layout boundary (P5-1A)
### Layout boundary (P5-2 / P5-3)
`layoutMode?: 'fixed' | 'auto'` is independent of `displayMode`. The default
`'fixed'` keeps the existing Workdesk composition and its display-mode behavior.
`'auto'` currently selects the **P5-1A initial preview**, showing the representative
and immediate organization groups from the validated hierarchy. Descendants stay
in the dataset and statistics but are not placed in this preview. Automatic
recursive placement/recalculation/collision prevention belongs to P5-1B;
collapse controls and Zoom/Pan remain deferred. No preview readiness state claims
those later features are complete.
`'auto'` renders the complete validated hierarchy through dabeng 6.0.0.
Root and same-parent siblings remain in their real hierarchy; the engine allocates
recursive subtree widths. The Auto-only presenter reserves the tallest content
height at each depth and observes article resizing so variable staff counts and
font loading keep child rows and connectors aligned. Update/reload regenerate the
same layout and dispose old observers. Auto has a transformed forest, initial Fit,
5–300% configurable Zoom, Ctrl/Command wheel Zoom, pointer Pan and keyboard Pan.
Ordinary wheel scrolling remains with the page. Dialogs stay outside the forest.
Use `companyId` with Auto to select an existing company preset (default `hanmac`).
Set optional `Organization.companyId` on company roots; descendants inherit it.
Child company changes are rejected instead of mixing independent trees.
Legacy roots resolve from a known leader affiliation, then the `companyId` fallback
(default `hanmac`). `companyId` is no longer a global recoloring selector.
The seven IDs are `hanmac`, `saman`, `jangheon-industry`, `jangheon`, `ptc`, `halla`,
and `baron`. Main colors style only Expanded group headers; indexed secondary
and `baron`. Main colors style Expanded group headers and card accents; indexed secondary
variables come from that same preset. Fixed ignores this option and preserves
its organization gradients. Unknown Auto IDs reject construction with `TypeError`.
The preview reuses approved Workdesk card presentation, the same data/engine and
employee dialog; it has an independent wrapper without Fixed coordinates or scaling.
Choose `displayMode: 'readOnly'` for the matching read-only popup name policy.
The Auto presenter shares photo/position/name and employee dialog behavior without
Fixed SVG cards, coordinates or scaling. Group title DOM carries the organization
ID; the full title is a native toggle with aria-expanded and disabled empty groups.
Separate link icons preserve page navigation. Child collapse state survives parent
collapse and company reselection. Auto uses actual Employee names/positions;
three-character Korean names display with spaces; position whitespace is removed
only for display, preserving raw data. P5-4 retains the current Expanded cards
by user decision; the two external SVG references are no longer required.
Auto geometry variables live under
`.hm-orgchart-expanded`; there is no new public `layoutConfig` API.
The existing employee popup still uses its displayMode policy and receives raw data.
P5-4 adds group-title Hover feedback and reveals offscreen keyboard-focused cards
without changing Zoom. Drag click suppression does not block Enter/Space activation.
See [Expanded usage and styling](../../docs/org-chart/expanded-usage.md) for complete
Vanilla/React examples, Shadow DOM CSS ownership and verification boundaries.
`selectedCompanyIds` / `setSelectedCompanies(ids?)` filter the view: undefined
means all, [] means empty. Summary raw counts always describe the unmodified source;
the Auto selection label reports selected company/employee counts separately.
`getSelectedCompanies`, `zoomTo`, `panBy`, `fitToView`, `getViewportState` expose
view operations. Selection requires a mounted Auto handle; Fixed rejects it.
`companyTopNodes` maps company IDs to optional employeeId, title, name, profileImage,
organizationName and display (`card`, `titleOnly`, `hidden`). An explicit employee
must belong to that company's root; null removes top-card assignment. Overrides
affect presentation only, preserving employee IDs, popup data and parentId.
`employeeConnections` maps organization IDs to top/left/right staff routes (default
top). Leaders connect from their title above. SVG paths use actual article/card
coordinates; each endpoint shares its direction with the corresponding single-side
border accent. Employee preset follows its known affiliation, otherwise its tree.
All remaining borders are neutral; an inset accent width variable preserves size.
Width/height/padding/radius/photo/font/spacing variables are scoped to Auto.
```js
const chart = createOrgChart({
@@ -50,12 +86,43 @@ const chart = createOrgChart({
layoutMode: 'auto',
displayMode: 'readOnly',
companyId: 'hanmac',
selectedCompanyIds: ['hanmac', 'saman'],
companyTopNodes: { hanmac: { title: '회장', display: 'card' } },
employeeConnections: { 'hanmac-office-0': 'left' },
});
```
Options are captured at construction: create a new handle to change the layout or
company. Standalone Tree/Summary factories keep their existing rendering paths.
company/top-node/connection/zoom configuration. Selection uses its own setter.
Standalone Tree/Summary factories keep their existing rendering paths.
`examples/org-chart/data-expanded-{small,medium,large}.json` contain exactly
20/100/300 unique virtual employees and 3/5/7 companies. Run
`node examples/org-chart/create-expanded-fixtures.mjs` to reproduce them.
After build/prepare, open `http://127.0.0.1:4178/expanded.html`.
Expanded OrgChart is one of the same four public Stories; it offers fixture and
company controls without filtering JSON in the Story. Native Core controls are
the explicit framework-independent HTML adapter, not imitations of HM React UI.
### Historical P5-1B verification and local runtime
Core/React builds and Typechecks pass. Focused browser evidence covers the
complete four-depth hierarchy, unequal employee counts, updates/reload, all seven
company presets, shared HTML/React cards and popup focus, viewport overflow, and
minimal Fixed baseline regression. Evidence is generated under
`test-results/org-chart-p5-1b`; the authored runner is
`examples/org-chart/verify-p5-1b.mjs`. Its baseline must be copied from a known
pre-change build before rebuilding. The runner uses configurable
`ORGCHART_STORY_ORIGIN`, `ORGCHART_PLAYWRIGHT_MODULE`, and `ORGCHART_CHROME`.
Do not assume another PC's localhost or generated dist exists.
Use npm with `package-lock.json`; a fresh install uses `npm ci`. The existing
package test runner imports Node's `globSync`, so use a runtime providing that API, such as the verified Node 24,
for focused unit tests. This PC's Node 20.20.1 built the packages successfully;
the installed Codex Node 24.19.0 ran the unit tests without changing the runner.
Final reference SVG design, collapse/Zoom/Pan, real screen-reader speech/touch and
historical full regression suites are not verified by this phase.
### P3.2 follow-up: representative badges
@@ -93,7 +160,7 @@ Omit `onEmployeeClick` to use the default popup. Vanilla options are captured at
`mount(container)` also accepts the container at mount time. Constructing a handle and importing the ESM facade require no DOM. Mount requires a connected HTMLElement. One handle owns one container, preserving host siblings. Duplicate mount and update/reload before mount or after destroy reject with a usage error. Data/Source failures become structured `error` states and resolve the operation. Destroy is synchronous, idempotent and terminal; use a new handle to mount again. `subscribe(listener)` returns an unsubscribe function; `getState()` returns the immutable current state. Consumer callback errors do not break the Core.
`update` captures its input immediately and preserves the current Source. `reload(source?)` optionally replaces it. The last started operation wins; earlier requests are aborted, and stale responses cannot commit. Call completion means the operation was applied, superseded, or produced a controlled error, rather than that every image/font finished loading. Regeneration resets expand/scroll state; removed keyboard focus moves to the scroll region.
`update` captures its input immediately and preserves the current Source. `reload(source?)` optionally replaces it. The last started operation wins; earlier requests are aborted, and stale responses cannot commit. Call completion means the operation was applied, superseded, or produced a controlled error, rather than that every image/font finished loading. Fixed keeps its prior regeneration policy. Auto preserves valid organization collapse IDs and transform state on toggles; reload/selection fits the new visible forest. Removed toggle focus is restored to the same organization, with viewport fallback.
## Data contract
@@ -130,4 +197,4 @@ Open `http://127.0.0.1:4178/index.html` for bundled ESM + external JSON. Open `e
`npm run test:org-chart-browser` expects Playwright supplied by the verification environment. If not installed locally, set `ORGCHART_PLAYWRIGHT_MODULE` to its absolute `index.mjs`/`index.js` and optionally `ORGCHART_CHROME` to a Chrome executable. Production has no browser-test dependency. Evidence is written under `test-results/org-chart-browser/`.
The React wrapper owns only ref/effect lifecycle, source/props updates and cleanup, including forwarding the additive P3 lookup options; HTML and React render the same Core. Standalone `createOrgChartTree`, `createPositionSummary`, `createAffiliationSummary` and `createStatusSummary` factories are exported at the package root and return the existing `OrgChartHandle`. The three public OrgChart Stories are Logo · Personnel Summary, Department Colors and Full Composition. Original verification Stories and independent component Stories remain available under the excluded `internal` tag.
The React wrapper owns only ref/effect lifecycle, source/props updates and cleanup, including forwarding lookup and Auto view options; HTML and React render the same Core. Standalone `createOrgChartTree`, `createPositionSummary`, `createAffiliationSummary` and `createStatusSummary` factories are exported at the package root and return the existing `OrgChartHandle`. The four public OrgChart Stories are Logo · Personnel Summary, Department Colors, Full Composition and Expanded OrgChart. Original verification Stories and independent component Stories remain available under the excluded `internal` tag.