feat(org-chart): support external CSS themes and align documentation

This commit is contained in:
shkim4 committed 2026-10-13 22:43:21 +09:00
1 parent dcfa4e0895
commit 346c648c09
27 files changed
+1189 -75

No files matched your search

+130 -3
View File
@@ -4,6 +4,133 @@
빠른 시작은 아래 데이터 파일과 React 또는 Vanilla 진입점을 함께 복사한다. 예제는 Vite의 TypeScript 환경을 전제로 한다. 기본 예제는 제목·요약·툴바가 있는 Auto 화면이다. **Auto/Expanded Chart Only는 구현 및 기존 브라우저 검증이 완료됐으며**, 외부 UI 없이 삽입할 때는 [Chart Only 공개 API](#chart-only-공개-api-auto)를 사용한다. **Fixed Full Composition은 지원하지만 Fixed Chart Only는 미지원**이다.
## P11 외부 CSS 테마 (2026-10-13)
Core와 React는 같은 Shadow DOM CSS 정책을 사용한다. 공개 JS API·데이터 계약은 바뀌지 않는다. 외부 입력 `--hm-orgchart-*`는 호스트에서 상속되며, 내부 `resolved-*`/`current-*`는 실제 사용 요소에서 기본값을 계산한다. 회사색과 Fixed 부서색을 JS inline으로 덮어쓰지 않는다. 기본 파일만 연결하면 기존 회사색·카드·디자인을 유지한다.
### Shadow DOM 안에 외부 파일 연결
`stylesheetUrls.core`는 **기본 스타일 전체를 포함하는 한 개의 CSS URL**이다. 테마 변수만 있는 파일로 교체하면 기본 레이아웃이 누락된다. `engine`에는 기존 엔진 CSS URL을 유지한다. 일반 HTTP 서버에서는 공개 `style.css`를 복사한 경로로 import한다.
```css
/* /themes/external-theme.css — 기본 CSS를 먼저, 컬러 override를 뒤에 */
@import url('/assets/org-chart/style.css');
:host {
--hm-orgchart-bg-surface: #edf4ff;
--hm-orgchart-bg-content: #dce8f8;
--hm-orgchart-company-hanmac: #2457a7;
--hm-orgchart-company-saman: #385ca8;
--hm-orgchart-group-title-color: #fff4d6;
--hm-orgchart-card-background: #f4f8ff;
--hm-orgchart-card-border: #527aa9;
--hm-orgchart-expanded-line-color: #249a79;
}
```
Vite에서는 `@import '@hm-design/org-chart/style.css';`를 사용하고 CSS URL로 import한다. 실행 가능한 전체 예제는 [external-theme.css](../../examples/org-chart-react/external-theme.css), [React·Vanilla 소비 fixture](../../examples/org-chart-react/p11.tsx)다. `!important`가 필요하지 않다. `:host`에 선언한 값은 내부 기본값의 fallback보다 우선한다. 동일 속성의 CSS 규칙을 직접 재작성할 때는 보통의 specificity·source order가 적용된다.
React:
```tsx
import { OrgChart } from '@hm-design/org-chart-react';
import engineUrl from '@hm-design/org-chart/engine.css?url';
import externalThemeUrl from './external-theme.css?url';
<OrgChart dataSource={dataSource} layoutMode="auto"
stylesheetUrls={{ engine: engineUrl, core: externalThemeUrl }} />
```
Vanilla (공개 ESM을 서빙하는 환경):
```js
import { createOrgChart } from '/assets/org-chart/index.js';
const container = document.getElementById('chart');
if (!container) throw new Error('chart 요소가 없습니다.');
const chart = createOrgChart({
container, dataSource,
layoutMode: 'auto',
stylesheetUrls: {
engine: '/assets/org-chart/engine.css',
core: '/themes/external-theme.css',
},
});
await chart.mount();
```
### 호스트 HTML CSS 상속 방식
호스트에서 변수만 설정할 때는 기본 `stylesheetUrls.core`를 유지한다. 다음 파일을 호스트 HTML의 `<link rel="stylesheet">`로 연결하고, React의 `className="orgchart-custom-theme"` 또는 Vanilla 컨테이너의 같은 class를 사용한다.
```css
.orgchart-custom-theme {
--hm-orgchart-company-hanmac: #2457a7;
--hm-orgchart-company-saman: #385ca8;
--hm-orgchart-expanded-line-color: #249a79;
}
```
이 방식은 **Custom Property 상속만** Shadow DOM을 통과한다. 호스트의 `.hm-orgchart-employee { ... }` 같은 selector는 Shadow 내부 카드에 적용되지 않는다. 내부 selector를 수정해야 하면 `stylesheetUrls.core` 파일 안에 작성한다. 호스트 class를 제거하면 기본값이 즉시 복원된다. 외부 테마를 동시에 쓸 경우 Shadow 파일의 `:host`에 같은 입력을 선언하면 조상에서 상속된 값보다 우선한다. 소비자가 직접 inline으로 입력 변수를 설정하면 소비자 inline이 우선하므로 CSS 파일 운영 시 이를 제거한다.
### 공식 컬러 변수
아래 이름은 모두 `--hm-orgchart-` 접두사를 사용한다. `resolved-*`, `current-*`, `expanded-primary`, `expanded-card-primary`는 내부 계산 결과이므로 테마는 아래 공개 입력을 사용한다. 표에 없는 geometry API와 기존 table 변수는 그대로 유지한다.
| 입력 이름 (접두사 생략) | 적용 범위 / 기본값 정책 |
|---|---|
| `bg-surface`, `bg-content`, `bg-subtle`, `bg-brand` | 캔버스·내용·보조 배경·브랜드 배경. Fixed readOnly의 `bg-content` 미지정 기본값은 기존 `#F5F8FB` |
| `fg-primary`, `fg-secondary` | 일반 텍스트 / 보조 텍스트 |
| `stroke-default`, `stroke-input-default`, `stroke-input-focus` | 일반 Border / 입력 Border / Focus |
| `accent-color`, `on-accent`, `action-primary`, `on-action-primary` | 기존 공통 강조·액션 색 |
| `company-{id}` | Auto 회사 제목과 해당 직원의 소속 회사 강조선. 소속이 부모와 다르면 직원 소속색을 사용 |
| `company-{id}-secondary-{n}` | 기존 보조색 alias 입력. `{n}=1`은 hanmac/saman/jangheon-industry/jangheon/ptc/halla, `{n}=2`는 ptc만 있다. baron에는 보조색 입력이 없다. 현재 주요 제목·카드에는 primary만 사용 |
| `group-title-background`, `group-title-color` | Fixed·Auto 그룹 제목 배경(단색/gradient), 글자. 배경 미지정 시 부서/회사색 |
| `group-border` | Fixed 일반 조직 카드의 상단 Border. Auto에는 기본 그룹 외곽 Border가 없음 |
| `card-background`, `card-color`, `card-position-color`, `card-border`, `card-accent` | CSS 카드 배경·이름/텍스트·Fixed 직위·Border·강조선. Fixed 부서별 배경과 일반 fallback 카드의 텍스트 입력은 공통 값보다 우선한다. SVG/compact 카드의 HTML 이름은 공통 `card-color`를 사용한다. 직원 카드 Border는 공통 `card-border`가 부서 Border보다 우선하며 상단 강조선은 `card-accent`가 우선한다. SVG 이미지 내부 색은 바뀌지 않는다 |
| `leader-card-background`, `top-leader-card-background` | Auto 그룹장 / 대표자 카드의 별도 배경. 미지정 시 공통 카드 배경 |
| `card-hover-background`, `card-focus-color` | Auto 카드 Hover 배경 / Core 직원 버튼 Focus 색(Fixed에도 Focus 적용) |
| `expanded-line-color` | Auto CSS pseudo선과 SVG 조직·직원 연결선. 기존 기본 `#738399` |
| `fixed-line-color` | Fixed 엔진 연결선, Workdesk overlay의 실제 SVG path/arrowhead. PNG 화살표 제외 |
| `gradient`, `border`, `department-color` | 기존 Fixed 공통 부서 gradient·Border·제목 글자색 |
| `{department}-gradient`, `{department}-border`, `{department}-department-color`, `{department}-card-background`, `{department}-card-color` | Fixed 6개 부서별 override. 기존 측정 gradient·기본값 유지 |
| `status-title-background`, `status-title-color`, `status-title-border` | 파견·휴직 요약 제목의 공통 색. 기존 회색 gradient, readOnly 흰 글자 유지 |
| `status-card-gradient`, `status-card-border`, `status-card-color`, `status-position-color` | Fixed 파견·휴직 요약 카드의 공통 gradient·Border·이름·직위. 기존 회색 기본값 |
| `dispatched-title-background`, `on-leave-title-background` | 파견 / 휴직 제목의 독립 gradient, 공통보다 우선 |
| `dispatched-card-gradient`, `dispatched-card-border`, `dispatched-card-color` | 파견 카드 독립 입력. Fixed 요약·Auto 상태 직원 카드에 적용 |
| `on-leave-card-gradient`, `on-leave-card-border`, `on-leave-card-color` | 휴직 카드 독립 입력. Fixed 요약·Auto 상태 직원 카드에 적용 |
| `dialog-background`, `dialog-color`, `dialog-border` | Core native 팝업 배경·글자·Border |
| `dialog-close-color`, `dialog-close-hover-background`, `dialog-focus-color` | Core 닫기 버튼 기본·Hover·Focus. 미지정 시 기존 HM 호스트 값/기본 fallback |
회사 `{id}`와 기본색은 `hanmac #CB2E28`, `saman #F08300`, `jangheon-industry #4580A6`, `jangheon #1D418D`, `ptc #84338E`, `halla #0068B7`, `baron #0C367F`다. 등록된 ID와 기존 프리셋은 그대로다. Fixed `{department}`는 `business-management`, `business-planning`, `talent-growth`, `integrated-system`, `design-planning`, `solution-sales`다. 회사색 override로 Fixed 부서색을 바꾸지 않는다.
```css
:host {
--hm-orgchart-company-saman: #385ca8; /* Auto 회사 제목·소속 카드 강조선 */
--hm-orgchart-business-planning-gradient: linear-gradient(180deg, #385ca8, #23417f);
--hm-orgchart-business-planning-border: #385ca8; /* Fixed 부서: 별도 설정 */
--hm-orgchart-dispatched-card-gradient: linear-gradient(180deg, #e9f9f0, #a9d8bd);
--hm-orgchart-dispatched-card-border: #278857;
--hm-orgchart-on-leave-card-gradient: linear-gradient(180deg, #f7efff, #d6bbeb);
--hm-orgchart-dialog-background: #eef2ff;
--hm-orgchart-dialog-focus-color: #8958ba;
}
```
색상 입력에는 유효한 CSS color를 사용한다. `*-background`는 적용되는 CSS 속성에 맞는 배경 표현식을, `*-gradient`는 `linear-gradient(...)` 같은 CSS image 표현식을 사용한다(Fixed 요약 카드는 `background-image`에 적용). CSS 파일만으로 동작하며 소스를 수정하거나 JS 색상 설정을 추가할 필요가 없다. 그룹 공통 배경을 설정하면 회사별 제목 배경보다 우선하므로 회사별 배경을 유지하려면 공통 배경을 생략한다. 상태 카드도 Auto의 회사 강조선을 유지한다.
### 런타임 변경과 기본 테마 복원
호스트 변수 class/값을 바꾸면 이미 mount된 차트에 반영되며 데이터·Zoom·Pan을 재생성하지 않는다. 서버의 CSS 파일 값을 바꾼 뒤 기존 link는 브라우저 캐시에 따라 다시 요청되지 않을 수 있으므로 CSS link를 갱신하거나 새 URL로 mount한다. React는 `stylesheetUrls.core` URL 변경 시 기존 lifecycle로 remount한다. Vanilla는 기존 handle을 `destroy()`한 뒤 새 CSS URL로 `createOrgChart()`·`mount()`한다. 새 테마 변경 API는 추가하지 않았다.
복원은 호스트 테마 class/link/소비자 inline 입력을 제거하고 Core URL을 기본 `@hm-design/org-chart/style.css?url` 또는 `/assets/org-chart/style.css`로 되돌린다. 일부 값만 복원하려면 외부 파일의 해당 선언을 삭제한다. `resolved-*`에 `unset`을 주는 방식은 사용하지 않는다.
### HM Dialog와 Fixed 이미지 한계
React `/hm-dialog`의 `employeePopup="hm-dialog"`는 Shadow 밖의 HM React Dialog다. 위 `dialog-*` 변수는 Core 팝업에만 적용된다. HM Dialog에는 기존 `@hm-design/ui/theme.css`와 `@hm-design/ui/theme`의 `applyRuntimeTheme`/`resetRuntimeTheme`를 사용한다([Runtime Theme 가이드](../guidelines/runtime-theme.md)). Portal은 DOM 경계를 따르므로 차트 컨테이너에만 적용한 Scoped Theme는 body Portal로 전달되지 않는다. 같은 팔레트를 원하면 HM Global Runtime Theme 입력과 OrgChart CSS 입력에 각각 연결한다. 자동 동기화나 HM Dialog 디자인 변경은 하지 않는다.
Fixed에서 회사 로고 PNG, `cards/*.svg`의 대표자·6개 부서 직원/그룹장 카드 이미지, `workdesk/Group.svg`, `bg_sky.png`, `bg_main.png`, `Frame2@3x.png`, `1-8-4x-1@2x.png`, `team-arrow-*.png`는 이미지 내부 픽셀 색상을 CSS 변수로 바꿀 수 없다. 카드 바깥의 Focus, CSS 제목·파견/휴직·배경과 실제 inline SVG 연결 path는 변경할 수 있다. 카드 CSS 배경을 바꿔도 SVG 이미지의 불투명 영역은 그대로다. 자산 재작성·필터 착색·이미지 교체는 하지 않았다.
검증 범위·Guard 원본 상태는 [P11 결과 보고서](implementation-report-p11.md)를 참고한다.
## 1. 설치·패키지·실행 환경
- `@hm-design/org-chart@0.1.0`: 데이터 타입·Validator·JSON DataSource·집계·이동 함수·DOM 렌더러. React 없이 사용한다. 내부 엔진 의존성은 `orgchart@6.0.0`이며 소비자가 엔진을 직접 조작하지 않는다.
@@ -698,8 +825,8 @@ React 없이 생성해 달라는 명시적 요청은 이 가이드의 Vanilla Co
- 자연어→데이터 자동 생성 UI, CSV/XLSX 직접 import, 서버 저장·외부 API·CSV/PDF/이미지 export는 공개 사용 기능이 아니다.
- 임의 회사 프리셋 등록 setter·카드 교체·Compact·공개 collapse setter·React imperative ref는 없다. Chart Only는 Auto 전용 `presentationMode`로만 제공하며 Fixed Chart Only는 없다.
- 제공 데이터의 최대 인원/Depth·모든 브라우저·실제 모바일 터치/스크린리더·외부 fresh install을 이번 소스 분석으로 보장하지 않는다.
- 기존 P10 PARTIAL/Guard FAIL 10건의 원본 기록은 보존한다. 2026-10-13 Feature 통합 대상은 Chart Only·초기 Fit·직접 Wheel Zoom, GuardFix의 F3–F7 해결 5건, AI 생성 방식 사전 선택 정책이다. Cell 디자인·미리보기는 제외한다. 잔여 Guard FAIL 5건·NOT VERIFIED 9건을 유지하며 원본 `status/staticStatus FAIL`, `runtimeStatus NOT VERIFIED`를 제품 전체 PASS로 표현하지 않는다. 범위와 새 결과는 [최종 Feature 통합 보고서](final-integration-2026-10-13.md)를 따른다.
- [P10.3 GuardReview](guard-review-p10-3.md)는 별도 Worktree에서 작성한 원본 분석이다. 당시 FAIL 10건을 재현했고 제품·Guard 수정 없이 공유했다. 현재 Auto Chart Only는 위 공개 API로 지원하며 Fixed Chart Only, 외부 CSS 테마 표준화, Fixed SVG/PNG 테마화, 최종 디자인 승인, main Merge와 Docker 배포는 이번 통합 대상이 아니다.
- 기존 P10 PARTIAL/Guard FAIL 10건의 원본 기록은 보존한다. [P10 Feature 통합](final-integration-2026-10-13.md)은 Chart Only·초기 Fit·직접 Wheel Zoom, GuardFix의 F3–F7 해결 5건, AI 생성 방식 사전 선택 정책을 포함했고 당시 잔여 FAIL 5건·NOT VERIFIED 9건이었다. 이후 [P11](implementation-report-p11.md)의 동일 대상 실제 Guard는 `status/staticStatus PASS`, FAIL 0건이다. Guard `runtimeStatus NOT VERIFIED`와 제품 전체 미검증을 계속 구분한다. Cell 디자인·미리보기는 제외한다.
- [P10.3 GuardReview](guard-review-p10-3.md)는 별도 Worktree에서 당시 FAIL 10건을 재현한 원본 분석이다. 현재 Auto Chart Only와 P11 외부 CSS 테마는 지원한다. Fixed Chart Only·Fixed SVG/PNG 이미지 내부 테마화는 미지원이며, 최종 디자인 승인·main Merge·Docker 배포는 완료하지 않았다.
### 이 가이드 예제 검증 범위
@@ -725,4 +852,4 @@ React 없이 생성해 달라는 명시적 요청은 이 가이드의 Vanilla Co
- [데이터 타입](../../packages/org-chart/src/data/types.ts), [검증](../../packages/org-chart/src/data/validate.ts), [이동](../../packages/org-chart/src/data/moves.ts): 실제 Contract와 정책.
- [P10 보고서](implementation-report-p10.md): 기존 PARTIAL/Guard FAIL·별도 미검증 기록. 현재 기능의 근거는 보고서보다 이 가이드 기준 소스다.
원본 UsageGuide/P10.2의 문서 예제 검증 기록은 위에 보존했다. P10.7에서는 검증 기준 SHA·Gitea Commit 고정 절차·현재 Chart Only 지원 상태와 옵션 설명을 공개 소스와 대조했다. 새 전체 타입 검사·제품 테스트·빌드·브라우저 검사는 수행하지 않았다. 제품 코드·기존 디자인·Core 공개 API 변경 없음.
원본 UsageGuide/P10.2의 문서 예제 검증 기록은 위에 보존했다. P10.7에서는 검증 기준 SHA·Gitea Commit 고정 절차·현재 Chart Only 지원 상태와 옵션 설명을 공개 소스와 대조했으며 새 전체 타입 검사·제품 테스트·빌드·브라우저 검사는 수행하지 않았다. P11/P11.1의 후속 검증은 [P11 보고서](implementation-report-p11.md)와 [P11.1 정합성 검증](consistency-review-p11-1.md)을 따른다. P11.1은 공개 API·제품 스타일·Story 소스를 변경하지 않는다.