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.
164 lines
9.3 KiB
Markdown
164 lines
9.3 KiB
Markdown
# 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)를 참고한다.
|