15 KiB
Public Runtime Theme Contract
계약 Source of Truth: packages/ui/src/theme/contract.ts. 모든 입력은 선택적이며 외부 override 가능. Component/derived 변수는 공개 입력이 아니다.
| Runtime JSON Token | CSS Token | Default | 의미 | 외부 override | 주요 영향 |
|---|---|---|---|---|---|
color.bg.content |
--hm-sem-bg-content |
#f5f0e5 |
콘텐츠 면 | Yes | gnb, lnb |
color.bg.surface |
--hm-sem-bg-surface |
#ffffff |
기본/카드/입력 면 | Yes | checkbox, radio, switch, slider, badge, table, input, select, button, gnb |
color.fg.primary |
--hm-sem-fg-primary |
#0a221d |
주요 텍스트 | Yes | calendar, pagination, badge, table, input, select, gnb |
color.fg.secondary |
--hm-sem-fg-secondary |
#6e6759 |
보조 텍스트 | Yes | calendar, pagination, badge, table, gnb |
color.fg.placeholder |
--hm-sem-fg-placeholder |
#999999 |
Placeholder | Yes | input, select |
color.action.primary |
--hm-sem-action-primary |
#123328 |
Strong / Primary ink | Yes | checkbox/radio hover, slider Hover/Drag halo, pagination current, badge default, button outline, navigation current ink |
color.action.cancel |
--hm-sem-action-cancel |
#6e6759 |
공개 취소 역할 | Yes | Button variant="cancel" + appearance="outline" |
color.action.destructive |
--hm-sem-action-destructive |
#d32f2f |
오류/위험 역할 | Yes | checkbox, radio, badge, input, button |
color.stroke.default |
--hm-sem-stroke-default |
#9a9284 |
기본 border | Yes | checkbox, radio, switch, badge |
color.stroke.input.default |
--hm-sem-stroke-input-default |
#dedbd2 |
입력/패널 divider border | Yes | table, input, select |
color.stroke.input.focus |
--hm-sem-stroke-input-focus |
#266651 |
공통 Focus border/ring | Yes | input, select, button, checkbox, calendar, slider Keyboard Focus halo 등; GNB/LNB는 contextual 예외 |
color.bg.brand.stop.0 |
--hm-sem-brand-bg-stop-0 |
#0a221d |
기존 gradient stop: color.bg.brand.stop.0 | Yes | Theme palette / adapter |
color.bg.brand.stop.12 |
--hm-sem-brand-bg-stop-12 |
#071e18 |
기존 gradient stop: color.bg.brand.stop.12 | Yes | Theme palette / adapter |
color.bg.brand.stop.42 |
--hm-sem-brand-bg-stop-42 |
#123328 |
기존 gradient stop: color.bg.brand.stop.42 | Yes | Theme palette / adapter |
color.bg.brand.stop.78 |
--hm-sem-brand-bg-stop-78 |
#266651 |
기존 gradient stop: color.bg.brand.stop.78 | Yes | Theme palette / adapter |
color.bg.brand.stop.100 |
--hm-sem-brand-bg-stop-100 |
#205241 |
기존 gradient stop: color.bg.brand.stop.100 | Yes | Theme palette / adapter |
surface.action.primary.stop.0 |
--hm-sem-action-surface-stop-0 |
#1f8265 |
기존 gradient stop: surface.action.primary.stop.0 | Yes | button, gnb |
surface.action.primary.stop.30 |
--hm-sem-action-surface-stop-30 |
#165c47 |
기존 gradient stop: surface.action.primary.stop.30 | Yes | button, gnb |
surface.action.primary.stop.65 |
--hm-sem-action-surface-stop-65 |
#114838 |
기존 gradient stop: surface.action.primary.stop.65 | Yes | button, gnb |
surface.action.primary.stop.100 |
--hm-sem-action-surface-stop-100 |
#08241c |
기존 gradient stop: surface.action.primary.stop.100 | Yes | button, gnb |
surface.action.primary.border.stop.0 |
--hm-sem-action-border-stop-0 |
#0a221d |
기존 gradient stop: surface.action.primary.border.stop.0 | Yes | button |
surface.action.primary.border.stop.50 |
--hm-sem-action-border-stop-50 |
#34daaa |
기존 gradient stop: surface.action.primary.border.stop.50 | Yes | button |
surface.action.primary.border.stop.100 |
--hm-sem-action-border-stop-100 |
#08241c |
기존 gradient stop: surface.action.primary.border.stop.100 | Yes | button |
radius.input.default |
--hm-radius-input |
4px |
Input/Select radius | Yes | input, select |
radius.container.default |
--hm-radius-container |
4px |
Container radius | Yes | Theme palette / adapter |
color.state.active |
--hm-sem-state-active |
#266651 |
Checked / Selected / ON fill | Yes | checkbox, radio, switch, slider, progress, calendar |
color.on.state.active |
--hm-sem-on-state-active |
#ffffff |
Active 위 텍스트/indicator | Yes | checkbox, calendar |
color.fg.inverse |
--hm-sem-on-action-primary |
#ffffff |
반전 텍스트 | Yes | pagination, badge, button, gnb, lnb |
color.bg.subtle |
--hm-sem-bg-subtle |
#f4f1ea |
은은한 면 | Yes | calendar, badge, table |
color.accent |
--hm-sem-accent |
#bddfd4 |
Soft Highlight 45%, Table 행 20% / Selected·Open surface 100% 원색 | Yes | select, combobox, menu item, table, calendar, pagination hover / toggle, menubar, navigation-menu trigger |
color.on.accent |
--hm-sem-on-accent |
#123328 |
Accent 위 텍스트; Primary와 독립 sibling | Yes | select, combobox, menu item, calendar, pagination hover, toggle, menubar, navigation-menu |
color.palette.green-light-4 |
--hm-sem-palette-green-light-4 |
#34daaa |
선택적 Theme 팔레트: green-light-4 | Yes | button |
color.palette.green-light-3 |
--hm-sem-palette-green-light-3 |
#249473 |
선택적 Theme 팔레트: green-light-3 | Yes | data-table Sort Direction Accent, tabs 장식, lnb gradient |
color.palette.green-light-2 |
--hm-sem-palette-green-light-2 |
#266651 |
선택적 Theme 팔레트: green-light-2 | Yes | checkbox, radio, switch, slider, progress, calendar, table, input, select, gnb, lnb |
color.palette.green-light-1 |
--hm-sem-palette-green-light-1 |
#205241 |
선택적 Theme 팔레트: green-light-1 | Yes | table, button, lnb |
color.palette.green-default |
--hm-sem-palette-green-default |
#123328 |
선택적 Theme 팔레트: green-default | Yes | checkbox, radio, slider, calendar, pagination, badge, select, button, gnb, lnb |
color.palette.green-dark-1 |
--hm-sem-palette-green-dark-1 |
#0a221d |
선택적 Theme 팔레트: green-dark-1 | Yes | calendar, pagination, badge, table, input, select, button, gnb |
color.palette.green-dark-2 |
--hm-sem-palette-green-dark-2 |
#071e18 |
선택적 Theme 팔레트: green-dark-2 | Yes | Theme palette / adapter |
color.palette.brown-light-2 |
--hm-sem-palette-brown-light-2 |
#897445 |
선택적 Theme 팔레트: brown-light-2 | Yes | button |
color.palette.brown-light-1 |
--hm-sem-palette-brown-light-1 |
#604f32 |
선택적 Theme 팔레트: brown-light-1 | Yes | button |
color.palette.brown-default |
--hm-sem-palette-brown-default |
#3e3523 |
선택적 Theme 팔레트: brown-default | Yes | button |
color.palette.brown-dark-1 |
--hm-sem-palette-brown-dark-1 |
#352d1d |
선택적 Theme 팔레트: brown-dark-1 | Yes | button |
color.palette.brown-light-4 |
--hm-sem-palette-brown-light-4 |
#ecd4a2 |
선택적 Theme 팔레트: brown-light-4 | Yes | Theme palette / adapter |
color.palette.orange-light-4 |
--hm-sem-palette-orange-light-4 |
#feba88 |
선택적 Theme 팔레트: orange-light-4 | Yes | button |
color.palette.orange-default |
--hm-sem-palette-orange-default |
#cc5200 |
선택적 Theme 팔레트: orange-default | Yes | button |
color.palette.warm-neutral-light |
--hm-sem-palette-warm-neutral-light |
#e0dace |
선택적 Theme 팔레트: warm-neutral-light | Yes | slider, progress |
color.palette.warm-neutral-mid |
--hm-sem-palette-warm-neutral-mid |
#9a9284 |
선택적 Theme 팔레트: warm-neutral-mid | Yes | checkbox, radio, switch, badge |
color.palette.warm-neutral-dark |
--hm-sem-palette-warm-neutral-dark |
#6e6759 |
선택적 Theme 팔레트: warm-neutral-dark | Yes | calendar, pagination, badge, table, gnb |
color.palette.beige-light |
--hm-sem-palette-beige-light |
#f5f0e5 |
선택적 Theme 팔레트: beige-light | Yes | gnb, lnb |
color.palette.red-danger |
--hm-sem-palette-red-danger |
#d32f2f |
선택적 Theme 팔레트: red-danger | Yes | checkbox, radio, badge, input, button |
color.palette.white |
--hm-sem-palette-white |
#ffffff |
선택적 Theme 팔레트: white | Yes | checkbox, radio, switch, slider, calendar, pagination, badge, table, input, select, button, gnb, lnb |
color.palette.black |
--hm-sem-palette-black |
#000000 |
선택적 Theme 팔레트: black | Yes | checkbox, switch, select, button, gnb, lnb |
color.palette.neutral-gray-500 |
--hm-sem-palette-neutral-gray-500 |
#999999 |
선택적 Theme 팔레트: neutral-gray-500 | Yes | input, select |
color.palette.green-tone-1 |
--hm-sem-palette-green-tone-1 |
#1f8265 |
선택적 Theme 팔레트: green-tone-1 | Yes | button, gnb |
color.palette.green-tone-2 |
--hm-sem-palette-green-tone-2 |
#165c47 |
선택적 Theme 팔레트: green-tone-2 | Yes | button, gnb |
color.palette.green-tone-3 |
--hm-sem-palette-green-tone-3 |
#114838 |
선택적 Theme 팔레트: green-tone-3 | Yes | button, gnb |
color.palette.green-tone-4 |
--hm-sem-palette-green-tone-4 |
#08241c |
선택적 Theme 팔레트: green-tone-4 | Yes | button, gnb |
color.palette.warm-neutral-pale |
--hm-sem-palette-warm-neutral-pale |
#dedbd2 |
선택적 Theme 팔레트: warm-neutral-pale | Yes | table, input, select |
color.palette.warm-neutral-secondary |
--hm-sem-palette-warm-neutral-secondary |
#ede8db |
선택적 Theme 팔레트: warm-neutral-secondary | Yes | Theme palette / adapter |
color.palette.warm-neutral-muted |
--hm-sem-palette-warm-neutral-muted |
#f4f1ea |
선택적 Theme 팔레트: warm-neutral-muted | Yes | calendar, badge, table |
color.palette.green-tint |
--hm-sem-palette-green-tint |
#bddfd4 |
선택적 Theme 팔레트: green-tint | Yes | calendar, pagination, table, select, gnb, lnb |
color.palette.yellow-accent |
--hm-sem-palette-yellow-accent |
#ffc600 |
선택적 Theme 팔레트: yellow-accent | Yes | lnb |
color.palette.brown-deep |
--hm-sem-palette-brown-deep |
#221d13 |
선택적 Theme 팔레트: brown-deep | Yes | button |
color.palette.brown-highlight |
--hm-sem-palette-brown-highlight |
#a98d53 |
선택적 Theme 팔레트: brown-highlight | Yes | button |
color.palette.orange-light |
--hm-sem-palette-orange-light |
#d35a00 |
선택적 Theme 팔레트: orange-light | Yes | button |
color.palette.orange-mid |
--hm-sem-palette-orange-mid |
#ce5600 |
선택적 Theme 팔레트: orange-mid | Yes | button |
color.palette.orange-dark |
--hm-sem-palette-orange-dark |
#b44b00 |
선택적 Theme 팔레트: orange-dark | Yes | button |
color.palette.orange-deep |
--hm-sem-palette-orange-deep |
#783402 |
선택적 Theme 팔레트: orange-deep | Yes | button |
color.palette.orange-border |
--hm-sem-palette-orange-border |
#bc4c00 |
선택적 Theme 팔레트: orange-border | Yes | button |
color.palette.orange-border-deep |
--hm-sem-palette-orange-border-deep |
#5e2902 |
선택적 Theme 팔레트: orange-border-deep | Yes | button |
color.palette.gray |
--hm-sem-palette-gray |
#767676 |
선택적 Theme 팔레트: gray | Yes | button |
color.palette.gray-dark |
--hm-sem-palette-gray-dark |
#5a5a5a |
선택적 Theme 팔레트: gray-dark | Yes | button |
color.palette.indicator |
--hm-sem-palette-indicator |
#2d2d2d |
선택적 Theme 팔레트: indicator | Yes | select |
총 73개. 기존 25개 + 핵심 역할 6개 + 선택적 팔레트 42개. 팔레트는 컴포넌트별 계약이 아니며 Primary / Active / Focus를 개별 지정하면 팔레트 alias보다 우선한다. Focus와 Active, Primary와 On Accent는 각각 sibling이며 서로 alias하지 않는다.
color.action.cancel의 공개 key·기본값은 보존한다. 2026-10-10 Gray 통일 요청에 따라 기본 Outline 취소 ink는 기존 Gray palette #767676을 사용한다. 기본값과 다른 명시적 취소 컬러 override는 내부 Button mapping에 전달하고 Reset 시 복원한다. 전체 Default preset을 주입해도 기본 Gray와 동일하다. Solid 취소는 기존 Gray mapping을 유지한다. Runtime Theme.
디자인팀 Runtime 운영 추가 결정 — 2026-10-06
기존 v1 입력 73개와 CSS property/type 계약을 유지한다. 공개 API isRuntimeTheme(unknown): value is RuntimeTheme를 제공한다. 이 사전 검증은 DOM을 변경하지 않는다. 기존 applyRuntimeTheme의 invalid 입력 시 reset 정책은 유지한다. 편집기는 사전 검증으로 invalid Import를 차단해 마지막 유효 Theme를 보존한다.
Default 컬러의 운영 원본은 themes/default.json(71개 컬러)이다. scripts/theme-defaults.mjs가 JSON과 컬러 literal 없는 alias/geometry template에서 package primitives.css, default.css, default-values.generated.ts를 생성한다. contract.ts의 defaultValue와 defaultRuntimeTheme는 생성 데이터를 읽는다. 2개 radius/geometry는 template에서 유지한다. CSS fallback/현재 색을 유지하고 세 가지 최종 명령의 pre hook에서 stale 생성 데이터를 검사한다. Theme-only 산출은 npm run build:themes로 분리한다.
Storybook Theme/Designer Playground/Editor는 17개 상위 컬러 역할과 JSON URL/파일 Preview를 제공하는 소비자다. Global decorator에서 resolveRuntimeTheme(theme, defaultJson) 후 Production applyRuntimeTheme(document.documentElement, theme) → CSS Custom Properties → 기존 Mapping으로 적용한다. JSON Export/Import는 동일 v1 계약이다. 컬러 artifact/편집기만 radius를 거부한다. Production API의 기존 radius/gradient 계약은 유지한다.
추가 Production API는 fetchRuntimeTheme(url, request?), resolveRuntimeTheme(theme, defaults?), loadRuntimeTheme(root,url,options?)다. fetch는 DOM과 분리되며 validation은 기존 isRuntimeTheme을 재사용한다. Loader 실패는 HM package fallback, partial은 같은 계약으로 교체/병합하며 superseded 요청은 새 Theme를 덮거나 reset하지 않는다. 회사 CDN URL은 하드코딩하지 않는다.
사용법: 디자인팀 Theme 가이드, Theme 운영/배포. 적용·fallback·scope 정책: Runtime Theme.
Dashboard 상태 색상 범위
Dashboard의 active / hold / done / issue 업무 상태 계약은 packages/ui/src/patterns/dashboard-status/contract.ts에서 ID·label·tone을 제공한다. 상태 변수 원본은 packages/ui/src/patterns/dashboard-status/dashboard-status.css이며 @hm-design/ui/dashboard-status.css로 배포한다. src/patterns/dashboard-status-contract.css는 기존 Story/HTML 경로의 호환 import다. Theme CSS 다음에 상태 CSS를 로드하고 --hm-dashboard-status-active|hold|done|issue를 화면 요소의 색상에 별도로 연결한다. 상태 CSS 자체는 Badge나 data-status를 자동으로 꾸미지 않는다. active/hold/issue는 기존 Story 색상을 보존하는 compatibility mapping이고 done은 :root 및 [data-hm-theme]에서 해당 scope의 기존 HM white token을 참조한다. 기존 HM Theme 및 Public Runtime Token/JSON 73개는 변경하지 않으며, 실제 Production 소비처가 반복되어 공통 색상 의미가 확정될 때만 Semantic Token 승격을 검토한다.