# 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(['hanmac', 'saman']); return <> ; } ``` 위 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는 없다. Auto 부모·자식 관계선과 직원 연결선은 전용 `--hm-orgchart-expanded-line-color` 변수(기본 `#738399`)를 공유한다. 카드의 중립 Border·회사별 Border 강조와 Fixed 연결선은 이 변수를 사용하지 않는다. 배경 또는 이 색상을 재정의할 때는 실제 합성 배경과 computed 표시색으로 비텍스트 대비 3:1 이상을 별도로 확인한다. 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)를 참고한다.