zdp-design-system 0.43.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/CHANGELOG.md +449 -0
  2. package/LICENSE +21 -0
  3. package/README.md +568 -0
  4. package/THIRD_PARTY_NOTICES.md +34 -0
  5. package/dist/code.ts +2 -0
  6. package/dist/combobox.ts +9 -0
  7. package/dist/command.ts +1 -0
  8. package/dist/components/Accordion.svelte +97 -0
  9. package/dist/components/Avatar.svelte +90 -0
  10. package/dist/components/Badge.svelte +61 -0
  11. package/dist/components/Breadcrumb.svelte +97 -0
  12. package/dist/components/Button.svelte +163 -0
  13. package/dist/components/Callout.svelte +81 -0
  14. package/dist/components/Card.svelte +151 -0
  15. package/dist/components/CardHeader.svelte +58 -0
  16. package/dist/components/Checkbox.svelte +135 -0
  17. package/dist/components/CodeBlock.svelte +247 -0
  18. package/dist/components/Combobox.svelte +552 -0
  19. package/dist/components/CommandField.svelte +230 -0
  20. package/dist/components/ConfirmAction.svelte +307 -0
  21. package/dist/components/Container.svelte +63 -0
  22. package/dist/components/Dialog.svelte +303 -0
  23. package/dist/components/Disclosure.svelte +176 -0
  24. package/dist/components/Divider.svelte +41 -0
  25. package/dist/components/EmptyState.svelte +79 -0
  26. package/dist/components/ErrorText.svelte +18 -0
  27. package/dist/components/Field.svelte +38 -0
  28. package/dist/components/Grid.svelte +76 -0
  29. package/dist/components/HelpText.svelte +17 -0
  30. package/dist/components/Icon.svelte +45 -0
  31. package/dist/components/IconButton.svelte +162 -0
  32. package/dist/components/IdentityChip.svelte +130 -0
  33. package/dist/components/Inline.svelte +85 -0
  34. package/dist/components/InlineCode.svelte +27 -0
  35. package/dist/components/Input.svelte +109 -0
  36. package/dist/components/Kbd.svelte +63 -0
  37. package/dist/components/KeyValue.svelte +73 -0
  38. package/dist/components/Label.svelte +43 -0
  39. package/dist/components/Link.svelte +70 -0
  40. package/dist/components/LocaleSwitcher.svelte +209 -0
  41. package/dist/components/Menu.svelte +491 -0
  42. package/dist/components/Page.svelte +36 -0
  43. package/dist/components/PageHeader.svelte +93 -0
  44. package/dist/components/Pagination.svelte +297 -0
  45. package/dist/components/Popover.svelte +208 -0
  46. package/dist/components/Progress.svelte +111 -0
  47. package/dist/components/Radio.svelte +132 -0
  48. package/dist/components/Section.svelte +52 -0
  49. package/dist/components/SegmentedControl.svelte +190 -0
  50. package/dist/components/Select.svelte +88 -0
  51. package/dist/components/ShareDock.svelte +304 -0
  52. package/dist/components/Sheet.svelte +332 -0
  53. package/dist/components/ShortcutHint.svelte +52 -0
  54. package/dist/components/Skeleton.svelte +82 -0
  55. package/dist/components/SkipLink.svelte +40 -0
  56. package/dist/components/SortHeader.svelte +138 -0
  57. package/dist/components/Spinner.svelte +82 -0
  58. package/dist/components/Stack.svelte +62 -0
  59. package/dist/components/StatusToast.svelte +133 -0
  60. package/dist/components/Surface.svelte +53 -0
  61. package/dist/components/Switch.svelte +152 -0
  62. package/dist/components/Table.svelte +94 -0
  63. package/dist/components/TableToolbar.svelte +195 -0
  64. package/dist/components/Tabs.svelte +205 -0
  65. package/dist/components/TermSheet.svelte +392 -0
  66. package/dist/components/TermTrigger.svelte +70 -0
  67. package/dist/components/TextScaleControl.svelte +219 -0
  68. package/dist/components/Textarea.svelte +106 -0
  69. package/dist/components/ThemeToggle.svelte +148 -0
  70. package/dist/components/Toast.svelte +180 -0
  71. package/dist/components/Toolbar.svelte +83 -0
  72. package/dist/components/Tooltip.svelte +199 -0
  73. package/dist/components/VisuallyHidden.svelte +18 -0
  74. package/dist/disclosure.ts +11 -0
  75. package/dist/focusable.ts +36 -0
  76. package/dist/identity.ts +5 -0
  77. package/dist/index.d.ts +106 -0
  78. package/dist/index.js +76 -0
  79. package/dist/index.ts +106 -0
  80. package/dist/menu.ts +12 -0
  81. package/dist/modal-layer.ts +108 -0
  82. package/dist/pagination.ts +10 -0
  83. package/dist/preferences.js +14 -0
  84. package/dist/preferences.ts +36 -0
  85. package/dist/progress.ts +4 -0
  86. package/dist/schemas/design-tokens.schema.json +119 -0
  87. package/dist/segmented.ts +8 -0
  88. package/dist/share.d.ts +48 -0
  89. package/dist/share.js +115 -0
  90. package/dist/share.ts +99 -0
  91. package/dist/sheet.ts +3 -0
  92. package/dist/shortcuts.js +125 -0
  93. package/dist/shortcuts.ts +153 -0
  94. package/dist/styles/brand-fonts.css +10 -0
  95. package/dist/styles/components.css +4686 -0
  96. package/dist/styles/expressive-fonts.css +2 -0
  97. package/dist/styles/index.css +2 -0
  98. package/dist/styles/locale-fonts.css +4 -0
  99. package/dist/styles/tokens.css +413 -0
  100. package/dist/table-tools.ts +10 -0
  101. package/dist/term.ts +16 -0
  102. package/dist/theme.ts +2 -0
  103. package/dist/toast.ts +14 -0
  104. package/dist/tokens/zdp.tokens.json +241 -0
  105. package/dist/tokens.js +122 -0
  106. package/dist/tokens.ts +123 -0
  107. package/docs/CONSUMER_CONTRACT.md +482 -0
  108. package/docs/EXTERNAL_UI_ADOPTION.md +141 -0
  109. package/docs/INTERACTIVE_PRIMITIVE_AUDIT.md +127 -0
  110. package/package.json +78 -0
package/README.md ADDED
@@ -0,0 +1,568 @@
1
+ # zdp-design-system
2
+
3
+ ZDP의 디자인 토큰, CSS, 아이콘, Svelte UI 컴포넌트 경계를 고정하는 저장소다.
4
+
5
+ 초기 목적은 `zdp-web-public`, `zdp-web-apps`, 제품 실험, 게임 소개 화면이 각자 다른 시각 언어를 만들지 않게 막는 것이다.
6
+
7
+ ## 현재 범위
8
+
9
+ - 색상, 간격, 타이포그래피, radius, elevation 같은 디자인 토큰
10
+ - 공통 CSS reset과 theme contract
11
+ - Svelte UI 컴포넌트 public surface
12
+ - 아이콘 사용 기준과 접근성 기본 규칙
13
+ - Storybook 또는 동등한 컴포넌트 검토 표면
14
+
15
+ ## 시각 방향
16
+
17
+ 기본 톤은 밝은 중세 유럽 마을 광장과 수채화 종이 질감이다. 토큰 값은 parchment, warm brass, muted sage, sunlit gold, umber, terracotta 계열을 쓰되, 토큰 이름은 `primary`, `surface`, `line`, `danger`처럼 역할 중심으로 유지한다.
18
+
19
+ ## Foundation 계약
20
+
21
+ 디자인 시스템은 각 제품의 번역, 라우팅, SEO, 페이지별 레이아웃을 소유하지 않는다. 대신 소비 표면이 깨지지 않도록 다음 공통 계약을 제공한다.
22
+ Default component text is English. 제품별 화면은 필요한 모든 user-facing label, placeholder, aria-label, empty text, toast dismissal text를 prop으로 넘겨 각 locale에 맞게 override한다.
23
+
24
+ - `type`: body, body small, page title, title, label, caption, control, data에 쓰는 기본 크기와 줄높이
25
+ - `breakpoint`: mobile, tablet, desktop, wide 기준 폭
26
+ - `control`: 버튼, 아이콘 버튼, 입력류가 공유할 높이, radius, border width, hit target, 선택 컨트롤 전용 mark, indicator, switch, scrollbar 크기
27
+ - `focus`: 키보드 사용자가 현재 위치를 놓치지 않도록 하는 sunlit focus highlight, dark text, dark line
28
+ - `selection`: 드래그로 선택한 텍스트가 브라우저 기본 파란색 대신 theme surface와 readable text로 보이게 하는 selection 색
29
+ - `brand`: `8ailors` 워드마크 같은 브랜드 표면에만 쓰는 Playwrite AU VIC Guides 기반 폰트 스택
30
+ - `i18n`: 긴 텍스트와 CJK/영문/힌디어 혼합 문장이 UI를 밀어내지 않게 하는 wrapping 및 언어별 폰트 기본값
31
+
32
+ ## 현재 제외
33
+
34
+ - 제품별 화면 구성
35
+ - 랜딩 페이지 문구
36
+ - 번역 문구, locale 라우팅, SEO hreflang/canonical
37
+ - 결제, 권한, 인증, 관리자 의사결정
38
+ - 앱 라우팅, API 호출, 데이터 저장
39
+ - 브랜드별 캠페인 실험
40
+
41
+ ## 운영 문서
42
+
43
+ - `service.yaml`
44
+ - `AGENTS.md`
45
+ - `CONTRIBUTING.md`
46
+ - `CHANGELOG.md`
47
+ - `docs/CONSUMER_CONTRACT.md`
48
+ - `docs/EXTERNAL_UI_ADOPTION.md`
49
+ - `docs/INTERACTIVE_PRIMITIVE_AUDIT.md`
50
+ - `THIRD_PARTY_NOTICES.md`
51
+
52
+ ## 외부 UI 흡수 기준
53
+
54
+ 외부 UI 라이브러리는 ZDP의 dependency source가 아니라 검증 source로 다룬다.
55
+ Bits UI와 shadcn-svelte는 Select, Combobox, Dialog, Popover, Menu, Command 같은 고난도 interactive primitive의 동작 명세와 접근성 테스트 후보로만 검토한다.
56
+ 내부 구현 의존성은 허용할 수 있지만 public API, CSS token, class, DOM 노출 정책은 ZDP가 소유하고 외부 타입이나 Tailwind/shadcn 구조가 package surface로 새면 실패다.
57
+ Skeleton, Flowbite Svelte, daisyUI는 패턴 카탈로그로만 보고 core primitive에 직접 유입하지 않는다.
58
+ Motion과 SmoothUI류는 marketing recipe로 격리하고 reduced motion 대체를 갖춘다.
59
+ Tailwind Plus와 Tailwind UI 계열은 파생/재배포 리스크 때문에 ZDP package 재료로 쓰지 않는다.
60
+ 외부 source를 참고, 포팅, 복사, 런타임 의존성으로 다루는 기준은 `docs/EXTERNAL_UI_ADOPTION.md`와 `THIRD_PARTY_NOTICES.md`를 따른다.
61
+ 현재 고난도 primitive의 위험도와 headless dependency 후보 전환 기준은 `docs/INTERACTIVE_PRIMITIVE_AUDIT.md`를 따른다.
62
+
63
+ ## Storybook 검토 기준
64
+
65
+ - Controls는 `Button`처럼 public props가 있는 컴포넌트의 라벨, 크기, 상태를 직접 바꿔보는 story에만 붙인다.
66
+ - Viewports는 ZDP Mobile, Tablet, Desktop, Wide 프리셋으로 mobile/tablet/desktop 폭을 확인한다.
67
+ - Accessibility addon은 CI 실패 게이트로 유지한다. 새 story는 a11y 위반을 남긴 채 merge하지 않는다.
68
+ - Interaction play는 `Tabs`, `Dialog`, `ConfirmAction`처럼 키보드와 상태 전이가 중요한 컴포넌트에 먼저 붙인다.
69
+ - Theme / Locale Stress story는 light/dark, ZDP Mobile 폭, 긴 한국어/영어/중국어/힌디어 문장, focus-visible 상태를 한 번에 확인한다.
70
+
71
+ ## 패키지 표면
72
+
73
+ 웹 소비 저장소는 공통 CSS 토큰을 먼저 불러온다.
74
+
75
+ ```ts
76
+ import 'zdp-design-system/styles.css';
77
+ ```
78
+
79
+ 10개국어 웹 표면에서 라틴/중국어/힌디어/일본어 웹폰트까지 명시 로드해야 하면 선택형 폰트 CSS를 추가로 불러온다. 한국어 Pretendard는 기본 `styles.css`에서 이미 로드한다.
80
+
81
+ ```ts
82
+ import 'zdp-design-system/styles.css';
83
+ import 'zdp-design-system/locale-fonts.css';
84
+ ```
85
+
86
+ 브랜드 워드마크를 렌더링하는 표면은 선택형 브랜드 폰트 CSS를 추가로 불러온다. 이 entry는 body나 일반 heading을 바꾸지 않고 `font.family.brand`, `.zdp-brand-lockup`, `.zdp-brand-wordmark`에 필요한 Playwrite AU VIC Guides font face만 제공한다. 워드마크 텍스트에는 `.zdp-brand-wordmark`를 직접 붙여 locale font override가 브랜드 스택을 덮지 않게 하고, 브랜드명이 너무 가늘게 보이지 않도록 `semibold` weight와 절제된 전용 크기를 쓴다.
87
+
88
+ ```ts
89
+ import 'zdp-design-system/styles.css';
90
+ import 'zdp-design-system/brand-fonts.css';
91
+ ```
92
+
93
+ 캠페인형 섹션 제목, 짧은 마케팅 문구, 장식적 안내처럼 표현력이 필요한 표면은 선택형 expressive font CSS를 추가로 불러온다. 이 entry는 일반 제품 UI를 바꾸지 않고 `font.family.expression*` 토큰에 필요한 Tangerine, Caesar Dressing, Google Sans, Merriweather, Fredericka the Great, Copse, Cabin, Libertinus Keyboard font face만 제공한다.
94
+
95
+ ```ts
96
+ import 'zdp-design-system/styles.css';
97
+ import 'zdp-design-system/expressive-fonts.css';
98
+ ```
99
+
100
+ 패키지 export는 `dist/` 산출물을 가리킨다. root runtime entry는 `dist/index.js`, type entry는 `dist/index.d.ts`다. 원천은 `src/lib`, `src/styles`, `tokens/zdp.tokens.json`, `src/lib/share.ts`이고 `bun run package:build`가 소비자용 `dist/` 표면을 다시 만든다. 소비 저장소와 문서 예시는 `zdp-design-system` public export만 쓰고 내부 `src/` 경로를 직접 import하지 않는다.
101
+
102
+ ## 소비 컴포넌트 계약
103
+
104
+ - Breadcrumb는 현재 위치 탐색을 `nav`로 표현하고, 제품 라우팅 판단은 소비 앱이 한다.
105
+ - Button과 IconButton은 `onclick` 실행 표면이며 권한, 저장, 네트워크 재시도 판단을 소유하지 않는다.
106
+ - 단축키 표기는 `ariaKeyShortcuts`와 실제 keydown 처리를 분리한다. Chrome과 브라우저가 기본 동작으로 가져가는 조합은 제품 단축키로 덮어쓰지 않는다. 소비 앱의 전역 단축키 dispatcher는 `shouldZdpIgnoreShortcutEvent`, `isZdpTextEntryTarget`, `isZdpBrowserReservedShortcut`, `zdpShortcutRecommendations` 같은 shortcut policy helper로 입력창, IME 조합, 브라우저 예약 조합을 먼저 걸러낸다.
107
+ - ConfirmAction은 중요한 액션 앞의 확인 흐름만 제공하고, 실제 삭제나 권한 검사는 소비 앱이 한다.
108
+ - Avatar와 IdentityChip은 사람, 팀, 계정의 짧은 식별 표면이다.
109
+ - CommandField는 검색 입력 primitive이며 shortcut keycap, `ariaKeyShortcuts`, `ariaAutocomplete`, result id 연결, 입력 keydown callback은 제공하되 실제 검색 로직, 결과 목록, command palette 실행은 소비 앱이 소유한다.
110
+ - Combobox는 검색 가능한 단일 선택 입력의 frame, listbox, keyboard navigation, disabled option skip, hidden submitted value만 제공한다. 실제 필터링, async search, command 실행, 권한 판단은 소비 앱이 계속 소유한다.
111
+ - InlineCode와 CodeBlock은 문서, 보안, 아키텍처 화면의 코드 표면이다.
112
+ - Icon은 장식용 glyph 기본값을 갖고, 의미 있는 아이콘은 소비 컴포넌트가 접근성 이름을 제공한다.
113
+ - Link는 일반 텍스트 링크이며 버튼처럼 보이는 destructive action으로 쓰지 않는다.
114
+ - ShareDock은 공유 도크와 아이콘 shape를 제공하고 URL 조립과 플랫폼 정책은 소비 앱이 정한다.
115
+ - Kbd와 ShortcutHint는 입력 힌트를 표시할 뿐, 단축키 실행을 등록하지 않는다. 화면에 보이는 힌트는 `/`, `?`, `Esc`, `Enter`, `ArrowUp/ArrowDown`, `Ctrl/⌘+Enter`처럼 자주 쓰고 맥락이 분명한 키만 남긴다. `ariaKeyShortcuts`는 실제 단축키가 소비 앱에서 구현된 control이나 CommandField에만 붙인다.
116
+ - LocaleSwitcher는 언어 선택 표면과 keyboard 이동만 제공하고 실제 message catalog, 라우팅, fallback locale, 저장소, `<html lang>` 반영은 소비 앱이 정한다.
117
+ - ThemeToggle은 light/dark 전환 버튼의 pressed 상태와 glyph만 제공하고 초기 테마, 저장소, 시스템 선호도 판단은 소비 앱이 정한다.
118
+ - TextScaleControl은 읽기 배율 선택 표면과 keyboard 이동만 제공하고 실제 문서 크기 반영, 저장소, 사용자 선호도 판단은 소비 앱이 정한다.
119
+ - Tooltip은 짧은 보조 설명만 맡고, Escape dismiss를 유지하며, 긴 안내나 상태 설명은 Popover, Disclosure, 문서 본문으로 보낸다.
120
+ - Accordion과 Disclosure는 접힌 안내와 점진적 정보 공개를 담당한다.
121
+ - SegmentedControl은 보기 방식이나 단일 모드 전환을 표현한다.
122
+ - SortHeader와 TableToolbar는 sortable column affordance, 선택 행 액션, 밀도 조절 같은 표 주변 도구를 맡는다.
123
+ - Popover와 Menu는 설정, 더보기, 필터, 계정 메뉴 표면을 제공하지만 메뉴 항목 권한 판단은 소비 앱이 한다.
124
+ - Sheet는 설정, 필터, 보조 흐름을 right, left, bottom edge panel로 열고, 저장, 권한, 데이터 fetch, 라우팅 판단은 소비 앱이 한다.
125
+ - Pagination은 목록 페이지 이동을 표현하고 데이터 범위 계산은 소비 앱이 한다.
126
+ - Progress, Spinner, Skeleton은 작업 진행, 대기, 자리 예약 상태를 보여주며 실제 작업 큐를 소유하지 않는다.
127
+ - Toast와 StatusToast는 저장, 동기화, 연결 같은 짧은 상태 피드백을 제공한다.
128
+ - `.zdp-combobox`, `.zdp-combobox__control`, `.zdp-combobox__input`, `.zdp-combobox__listbox`, `.zdp-combobox__option`은 검색 가능한 단일 선택의 정적 표면만 제공하고 option source, filtering, async loading은 소비처가 소유한다.
129
+ - Text selection의 기본값은 선택 가능이다. 조작 컴포넌트와 장식 요소만 선택을 막고, 드래그 중에는 `zdp-user-select-dragging` 같은 임시 상태로 제한한다.
130
+ - SkipLink는 키보드 반복 탐색을 줄이는 첫 번째 탈출구다.
131
+ - VisuallyHidden은 스크린리더에 필요한 텍스트를 시각적으로 숨길 때만 쓴다.
132
+ - Table, KeyValue, EmptyState는 업무 데이터, 용어-값, 비어 있는 상태를 표현한다.
133
+ - TermTrigger와 TermSheet는 용어 설명을 click-open sheet로 연결하며, TermTrigger는 sheet가 열린 동안에만 `aria-controls`를 연결한다. TermTrigger는 본문 안 의미 있는 단어이므로 hover에서 글자색을 바꾸지 않고 배경만 살짝 강조하며, 좌우 최소 padding과 focus token을 유지하고, 텍스트 선택을 막지 않는다. TermSheet root에는 stable `term_id`와 `data-zdp-ad-exclude`를 남긴다. TermSheet에는 광고 slot을 넣지 않는다.
134
+ - Dialog는 모달 레이어이며 닫기, scroll lock, focus trap, `describedBy`에 id 배열, `errorMessageId`로 `aria-errormessage` 연결을 명확히 한다.
135
+ - Checkbox와 Switch는 native input에 invalid 상태를 노출하고, Radio는 native radio role 제약 때문에 wrapper invalid styling과 `describedBy` 연결을 유지한다. Switch는 `describedBy` id 배열과 `errorMessageId`로 에러 설명을 연결한다.
136
+ - Page, Container, Section, PageHeader는 페이지 폭, 섹션 rhythm, 제목 구조를 정리한다.
137
+ - Flutter는 Svelte 컴포넌트를 직접 쓰지 않고 `tokens/zdp.tokens.json`과 필요한 platform adapter를 통해 시각 토큰만 소비한다.
138
+
139
+ Svelte 또는 Tauri(Svelte) 표면은 컴포넌트를 직접 가져온다.
140
+
141
+ ```svelte
142
+ <script lang="ts">
143
+ import {
144
+ Accordion,
145
+ Avatar,
146
+ Badge,
147
+ Breadcrumb,
148
+ Button,
149
+ Callout,
150
+ Checkbox,
151
+ CodeBlock,
152
+ Combobox,
153
+ CommandField,
154
+ ConfirmAction,
155
+ Container,
156
+ Dialog,
157
+ Disclosure,
158
+ Divider,
159
+ EmptyState,
160
+ Field,
161
+ Grid,
162
+ HelpText,
163
+ Icon,
164
+ Input,
165
+ IdentityChip,
166
+ Inline,
167
+ InlineCode,
168
+ Kbd,
169
+ KeyValue,
170
+ Label,
171
+ Link,
172
+ LocaleSwitcher,
173
+ Menu,
174
+ Page,
175
+ PageHeader,
176
+ Pagination,
177
+ Popover,
178
+ Progress,
179
+ SkipLink,
180
+ SegmentedControl,
181
+ Skeleton,
182
+ Stack,
183
+ SortHeader,
184
+ StatusToast,
185
+ Spinner,
186
+ Section,
187
+ ShareDock,
188
+ Sheet,
189
+ ShortcutHint,
190
+ Surface,
191
+ Switch,
192
+ Tabs,
193
+ Table,
194
+ TableToolbar,
195
+ TermSheet,
196
+ TermTrigger,
197
+ TextScaleControl,
198
+ ThemeToggle,
199
+ Tooltip,
200
+ Toast,
201
+ Toolbar,
202
+ VisuallyHidden
203
+ } from 'zdp-design-system';
204
+
205
+ let dialogOpen = false;
206
+ </script>
207
+
208
+ <Page labelledBy="design-system-title">
209
+ <SkipLink href="#content">본문으로 건너뛰기</SkipLink>
210
+ <Section spacing="lg">
211
+ <Container size="lg" padding="lg">
212
+ <PageHeader labelledBy="design-system-title">
213
+ <span slot="eyebrow">플랫폼</span>
214
+ <h1 id="design-system-title">디자인 시스템</h1>
215
+ <p slot="summary">공개 화면과 작업 화면이 같은 기준 위에서 움직입니다.</p>
216
+ </PageHeader>
217
+ </Container>
218
+ </Section>
219
+ <Container as="section" id="content" size="lg" padding="lg">
220
+ <Stack gap="md">
221
+ <Breadcrumb
222
+ ariaLabel="현재 위치"
223
+ items={[
224
+ { label: '홈 화면', href: '/' },
225
+ { label: '플랫폼', href: '/platform' },
226
+ { label: '디자인 시스템' }
227
+ ]}
228
+ />
229
+ <Badge tone="success">정상</Badge>
230
+ <IdentityChip
231
+ label="홍길동"
232
+ description="검토 담당"
233
+ initials="홍"
234
+ href="/people/hong"
235
+ />
236
+ <Avatar label="플랫폼 팀" initials="플" tone="primary" />
237
+ <Link href="/design">자세히 보기</Link>
238
+ <ShareDock
239
+ placement="inline"
240
+ ariaLabel="공유"
241
+ items={[
242
+ { id: 'copy', label: '링크 복사', icon: 'copy' },
243
+ { id: 'telegram', label: '텔레그램', icon: 'telegram', href: '/share' },
244
+ { id: 'x', label: 'X', icon: 'x', href: '/share' }
245
+ ]}
246
+ />
247
+ <Callout tone="info" semanticRole="note">
248
+ <strong>다음 단계가 준비됐습니다.</strong>
249
+ <p>필요한 입력을 확인한 뒤 저장하면 변경 내역에 남습니다.</p>
250
+ </Callout>
251
+ <Divider />
252
+ <Disclosure title="검토 기준" open headingLevel={2}>
253
+ <p>필요한 기준만 펼쳐서 확인합니다.</p>
254
+ </Disclosure>
255
+ <Accordion
256
+ ariaLabel="접힌 안내"
257
+ items={[
258
+ {
259
+ id: 'scope',
260
+ title: '범위',
261
+ content: '화면 흐름과 데이터 판단은 소비 앱에서 정합니다.',
262
+ open: true
263
+ },
264
+ {
265
+ id: 'owner',
266
+ title: '소유자',
267
+ content: '표시할 항목과 권한 판단은 제품 저장소가 연결합니다.'
268
+ }
269
+ ]}
270
+ />
271
+ <SegmentedControl
272
+ ariaLabel="보기 방식"
273
+ items={[
274
+ { id: 'list', label: '목록' },
275
+ { id: 'cards', label: '카드' },
276
+ { id: 'summary', label: '요약' }
277
+ ]}
278
+ selectedId="list"
279
+ />
280
+ <CommandField
281
+ label="빠른 이동"
282
+ labelVisible
283
+ placeholder="프로젝트, 문서, 설정 검색"
284
+ describedBy="command-field-help"
285
+ />
286
+ <HelpText id="command-field-help">이 화면에서 찾을 항목을 입력하세요.</HelpText>
287
+ <Combobox
288
+ name="owner"
289
+ label="담당"
290
+ labelVisible
291
+ placeholder="담당 팀 찾기"
292
+ options={[
293
+ { id: 'platform', value: 'platform', label: '플랫폼 운영' },
294
+ { id: 'security', value: 'security', label: '보안 검토' }
295
+ ]}
296
+ />
297
+ <p>배포 값은 <InlineCode text="readonly" /> 상태로 남깁니다.</p>
298
+ <CodeBlock
299
+ label="검토 규칙"
300
+ language="ts"
301
+ code={"const requiredEvidence = ['owner', 'budget', 'audit-log'];\nconst ready = requiredEvidence.every((item) => status[item] === 'ready');"}
302
+ />
303
+ <Divider />
304
+ <Grid columns="two" gap="md">
305
+ <Surface padding="lg">
306
+ <strong>공개 표면</strong>
307
+ <p>브랜드, 문서, 로드맵처럼 반복 확인하는 화면을 차분하게 묶습니다.</p>
308
+ </Surface>
309
+ <Surface padding="lg">
310
+ <strong>작업 표면</strong>
311
+ <p>설정, 입력, 검토 흐름은 같은 여백과 focus 규칙 위에 놓입니다.</p>
312
+ </Surface>
313
+ </Grid>
314
+ <Toolbar labelledBy="design-system-toolbar-title">
315
+ <strong id="design-system-toolbar-title">검토 흐름</strong>
316
+ <svelte:fragment slot="actions">
317
+ <Button variant="secondary">초안</Button>
318
+ <Button>검토 요청</Button>
319
+ </svelte:fragment>
320
+ </Toolbar>
321
+ <TableToolbar
322
+ title="점검 목록"
323
+ summary="권한과 감사 항목을 확인합니다."
324
+ selectedCount={2}
325
+ density="compact"
326
+ ariaLabel="점검 목록 도구"
327
+ >
328
+ <svelte:fragment slot="selection-actions">
329
+ <Button variant="secondary">선택 해제</Button>
330
+ </svelte:fragment>
331
+ <svelte:fragment slot="actions">
332
+ <Button>새로 고침</Button>
333
+ </svelte:fragment>
334
+ </TableToolbar>
335
+ <Table caption="보안 점검 목록" density="compact">
336
+ <thead>
337
+ <tr>
338
+ <th scope="col" aria-sort="ascending">
339
+ <SortHeader label="항목" direction="ascending" />
340
+ </th>
341
+ <th scope="col">
342
+ <SortHeader label="상태" direction="none" />
343
+ </th>
344
+ <th scope="col">다음 확인</th>
345
+ </tr>
346
+ </thead>
347
+ <tbody>
348
+ <tr>
349
+ <th scope="row">권한 분리</th>
350
+ <td>통과</td>
351
+ <td>분기 리뷰</td>
352
+ </tr>
353
+ </tbody>
354
+ </Table>
355
+ <Pagination
356
+ currentPage={2}
357
+ totalPages={8}
358
+ ariaLabel="점검 목록 페이지"
359
+ hrefForPage={(page) => `?page=${page}`}
360
+ />
361
+ <KeyValue columns="two">
362
+ <dt>소유 저장소</dt>
363
+ <dd>zdp-money-platform</dd>
364
+ <dt>승격 조건</dt>
365
+ <dd>예산, 소유자, 운영 증거 확인</dd>
366
+ </KeyValue>
367
+ <EmptyState labelledBy="empty-roadmap-title">
368
+ <h2 id="empty-roadmap-title">아직 공개할 변경이 없습니다.</h2>
369
+ <p>검토가 끝난 항목만 공개 로드맵에 올라갑니다.</p>
370
+ <svelte:fragment slot="actions">
371
+ <Button variant="secondary">초안 보기</Button>
372
+ </svelte:fragment>
373
+ </EmptyState>
374
+ <Tabs
375
+ idPrefix="project-tabs"
376
+ ariaLabel="프로젝트 섹션"
377
+ items={[
378
+ { id: 'overview', label: '개요' },
379
+ { id: 'history', label: '기록' }
380
+ ]}
381
+ selectedId="overview"
382
+ let:selectedId
383
+ >
384
+ <p>{selectedId === 'history' ? '변경 기록입니다.' : '프로젝트 개요입니다.'}</p>
385
+ </Tabs>
386
+ <Field required>
387
+ <Label forId="project-name">프로젝트</Label>
388
+ <Input id="project-name" name="project-name" describedBy="project-name-help" />
389
+ <HelpText id="project-name-help">공개 표기에 사용됩니다.</HelpText>
390
+ </Field>
391
+ <Field readonly>
392
+ <Label forId="project-id">고정 ID</Label>
393
+ <Input id="project-id" name="project-id" value="ZDP-2401" describedBy="project-id-help" readonly />
394
+ <HelpText id="project-id-help">이미 발급된 값은 그대로 둡니다.</HelpText>
395
+ </Field>
396
+ <Field invalid>
397
+ <Label forId="project-status">상태</Label>
398
+ <Input
399
+ id="project-status"
400
+ name="project-status"
401
+ describedBy={['project-status-help', 'project-status-error']}
402
+ errorMessageId="project-status-error"
403
+ invalid
404
+ />
405
+ <HelpText id="project-status-help">현재 작업 상태를 입력하세요.</HelpText>
406
+ <ErrorText id="project-status-error">다음 단계 전에 기준을 확인하세요.</ErrorText>
407
+ </Field>
408
+ <Checkbox name="release-updates" checked>업데이트 받기</Checkbox>
409
+ <Switch name="autosave" checked>자동 저장</Switch>
410
+ <Inline gap="sm">
411
+ <Button onclick={() => (dialogOpen = true)} ariaControls="project-dialog" ariaExpanded={dialogOpen}>저장</Button>
412
+ <Button variant="secondary">
413
+ <Icon size="sm">+</Icon>
414
+ <VisuallyHidden>새 항목 </VisuallyHidden>추가
415
+ </Button>
416
+ </Inline>
417
+ <Dialog
418
+ open={dialogOpen}
419
+ id="project-dialog"
420
+ labelledBy="project-dialog-title"
421
+ describedBy="project-dialog-desc"
422
+ onClose={() => (dialogOpen = false)}
423
+ >
424
+ <h2 slot="title" id="project-dialog-title">변경 내용을 저장할까요?</h2>
425
+ <p id="project-dialog-desc">저장하면 공개 표기에 바로 반영됩니다.</p>
426
+ <svelte:fragment slot="footer">
427
+ <Button variant="secondary" onclick={() => (dialogOpen = false)}>취소</Button>
428
+ <Button onclick={() => (dialogOpen = false)}>저장</Button>
429
+ </svelte:fragment>
430
+ </Dialog>
431
+ </Stack>
432
+ </Container>
433
+ </Page>
434
+ ```
435
+
436
+ Astro는 `styles.css`를 전역으로 불러오고, Svelte island가 필요한 부분에서 Svelte 컴포넌트를 소비한다. Flutter는 `tokens/zdp.tokens.json`을 Dart theme adapter 입력으로 쓴다.
437
+
438
+ 정적 HTML 소비처에서 쓸 수 있는 주요 utility class:
439
+
440
+ | 용도 | utility |
441
+ |---|---|
442
+ | 페이지 폭, 섹션 리듬, 헤더 | `.zdp-page` `.zdp-container` `.zdp-section` `.zdp-page-header` |
443
+ | 세로 흐름 | `.zdp-stack` `.zdp-stack--gap-*` |
444
+ | 가로 흐름 | `.zdp-inline` `.zdp-inline--gap-*` |
445
+ | 구분선 | `.zdp-divider` `.zdp-divider--horizontal` |
446
+ | 카드 그리드, 액션 묶음 | `.zdp-grid` `.zdp-toolbar` |
447
+ | 검색 / 명령 팔레트 입력 | `.zdp-command-field-shell` `.zdp-command-field` `.zdp-kbd` `.zdp-shortcut-hint` |
448
+ | 사람 / 팀 표기 | `.zdp-avatar` `.zdp-identity-chip` |
449
+ | 테마 전환 | `.zdp-theme-toggle` `.zdp-theme-toggle__icon` |
450
+ | 언어 선택 | `.zdp-locale-switcher` `.zdp-locale-switcher__item` |
451
+ | 글자 크기 선택 | `.zdp-text-scale-control` `.zdp-text-scale-control__item` |
452
+ | 보조 설명 | `.zdp-tooltip` `.zdp-tooltip__trigger` `.zdp-tooltip__content` |
453
+ | 접힌 안내 | `.zdp-disclosure` `.zdp-accordion` |
454
+ | 단일 선택 | `.zdp-segmented-control` |
455
+ | 팝오버 / 메뉴 | `.zdp-popover` `.zdp-menu` |
456
+ | 시트 / 드로어 | `.zdp-sheet` |
457
+ | 상태 알림 | `.zdp-toast` `.zdp-status-toast` |
458
+ | 로딩 / 진행 | `.zdp-progress` `.zdp-spinner` `.zdp-skeleton` |
459
+ | 아이콘 | `.zdp-icon` `.zdp-icon--sm|md` |
460
+ | 표 | `.zdp-table-wrap` `.zdp-table` `.zdp-sort-header` `.zdp-table-toolbar` |
461
+ | 페이지네이션 | `.zdp-pagination` |
462
+ | 용어/값 목록, 빈 상태 | `.zdp-key-value` `.zdp-empty-state` |
463
+ | 용어 설명 | `.zdp-term-trigger` `.zdp-term-sheet` |
464
+ | 공유 도크 | `.zdp-share-dock` `.zdp-share-action` `.zdp-share-icon` |
465
+ | 코드 | `.zdp-inline-code` `.zdp-code-block` |
466
+
467
+ Svelte island 없이 공유 아이콘 shape만 필요한 Astro 표면은 `zdp-design-system/share`에서 `zdpShareIcons`와 `ZdpShareIconName`을 가져온다. 플랫폼 브랜드 아이콘은 Simple Icons path를 유지하고 임의 outline glyph로 대체하지 않는다.
468
+
469
+ 소비처별 적용 순서와 금지 경계는 `docs/CONSUMER_CONTRACT.md`를 따른다. 내부 `src/` 경로 직접 import 금지.
470
+
471
+ ## Storybook
472
+
473
+ 디자인 피드백은 Storybook을 기준 표면으로 본다.
474
+
475
+ ```bash
476
+ bun install
477
+ bun run dev
478
+ ```
479
+
480
+ Storybook은 Svelte/Vite 기반이다.
481
+
482
+ - `Design System/Overview` — light/dark 테마, 색상, 타이포그래피, 버튼, 아이콘 버튼, form, surface 상태
483
+ - `Design System/Components/*` — 컴포넌트별 상태 확인 (Button, Data Display, Form Controls, Navigation, Feedback, Interaction)
484
+ - `Design System/QA/Theme Locale Stress` — 긴 다국어 문장, 좁은 모바일 폭, focus-visible 상태를 한 번에 확인하는 QA 표면
485
+
486
+ `bun run storybook`과 `bun run storybook:build`는 `bun run dev` / `bun run build`의 별칭이다.
487
+ 정적 HTML이 필요하면 `preview/index.html`을 브라우저에서 바로 열면 된다.
488
+
489
+ ## 정적 미리보기
490
+
491
+ 가벼운 확인은 로컬 정적 페이지에서 볼 수 있다.
492
+
493
+ ```text
494
+ preview/index.html
495
+ ```
496
+
497
+ 이 페이지는 `src/styles/index.css`를 직접 불러와 light/dark 테마, 색상, 타이포그래피, 버튼, 아이콘 버튼, form, surface 상태를 보여준다. 별도 개발 서버 없이 브라우저에서 열 수 있다.
498
+
499
+ ## 토큰 원칙
500
+
501
+ - 토큰 이름은 제품명이나 캠페인명이 아니라 역할을 기준으로 둔다.
502
+ - 색상, 간격, radius, typography, responsive, control, focus, selection, i18n, shadow, motion은 `tokens/zdp.tokens.json`이 원천이다.
503
+ - 색상 토큰은 `hex` fallback과 `oklch` 의도값을 함께 가진다.
504
+ - `src/styles/tokens.css`는 웹과 Tauri WebView가 쓰는 CSS 변수 표면이다.
505
+ - CSS는 hex를 먼저 선언하고 OKLCH 지원 브라우저에서만 `@supports`로 덮어쓴다.
506
+ - `styles.css`는 Pretendard Variable dynamic subset을 로드하고, sans/display stack은 `"Pretendard Variable", Pretendard`를 최우선으로 둔다.
507
+ - `brand-fonts.css`는 선택형 public export이며 `font.family.brand`와 `.zdp-brand-wordmark`가 쓰는 Playwrite AU VIC Guides를 로드한다. 일반 문서 제목, 제품 UI heading, 표, 본문에는 `brand` stack을 쓰지 않는다.
508
+ - `expressive-fonts.css`는 선택형 public export이며 `font.family.expressionScript`, `font.family.expressionInscription`, `font.family.expressionSketch`, `font.family.expressionEditorial`, `font.family.expressionSans`, `font.family.expressionKeyboard`가 쓰는 표현용 Google Fonts를 로드한다. 기본 앱 UI, 표, 긴 본문, 일반 Tooltip에는 자동 적용하지 않는다.
509
+ - `locale-fonts.css`는 선택형 public export이며 Manrope, Noto Sans SC, Noto Sans Devanagari, Noto Sans JP 웹폰트를 로드한다. 모든 소비 앱이 반드시 가져갈 필요는 없다.
510
+ - `:lang(en|es|fr|de|pt|id)`는 Manrope/Inter 라틴 스택, `:lang(ko)`는 Pretendard 한국어 스택, `:lang(zh)`는 Noto Sans SC/시스템 중국어 스택, `:lang(hi)`는 Noto Sans Devanagari/시스템 데바나가리 스택, `:lang(ja)`는 Noto Sans JP/시스템 일본어 스택으로 덮어쓴다.
511
+ - Flutter, native shell, 문서 생성기는 JSON 토큰의 hex 값을 기본 입력으로 쓰고 필요할 때 OKLCH를 별도 변환한다.
512
+
513
+ ## Flat UI 계약
514
+
515
+ 그림자, 그라데이션, 반짝임, 이동형 hover 장식을 쓰지 않는다. 깊이는 `surface` 색상 단계, 1px framed border, 타이포그래피, 여백으로 만든다.
516
+
517
+ **Shadow / Gradient**
518
+ - `shadow.focus`, `shadow.sm`, `shadow.md`는 `none`이다.
519
+ - core 토큰에 `gradient` 그룹을 만들지 않는다.
520
+
521
+ **Hover / Active**
522
+ - 버튼 hover/active는 배경색, 테두리색, 글자색만 바꾼다. 위치 이동·빛 반사 없음.
523
+ - Secondary Button과 ghost IconButton의 resting border는 `line-subtle`, hover/active는 `line-strong`.
524
+ - Focus는 `focus.surface` outline + `focus.line` border로 표시한다.
525
+
526
+ **Radius**
527
+ - controls (Button, Input 등): `0.375rem`
528
+ - 카드, 패널 등 큰 surface: `0.5rem` 상한. pill 형태 기본 금지.
529
+
530
+ **User select**
531
+ - 버튼, 아이콘, 페이지네이션 컨트롤, separator처럼 조작·장식 목적인 표면만 선택 막기.
532
+ - 카드 텍스트, 표 셀, 코드, toast 문장, 문서 본문, ID, 이메일, 날짜, 가격은 선택 가능 유지.
533
+ - 앱 root나 큰 컨테이너에 `user-select: none` 걸지 않는다. 보안 이유로 선택만 막는 것도 금지.
534
+ - drag surface는 drag start~end까지만 `.zdp-user-select-dragging`을 붙인다.
535
+
536
+ **색상**
537
+ - `success`, `warning`, `danger`는 상태 의미 기준. 모두 parchment/brass/umber 계열에서 채도를 낮춰 튀지 않게 유지.
538
+ - `focus.surface/text/line`은 접근성 기능색. 브랜드 장식색·hover 색으로 재사용 금지.
539
+ - `selection.surface/text`는 드래그 선택 전용. focus, hover, selected control과 이름 섞지 않기.
540
+
541
+ **폰트**
542
+ - 브랜드 워드마크(`font.family.brand`)는 로고·헤더 워드마크에만. 제품 UI heading·CTA에 쓰지 않는다.
543
+ - Expressive 폰트는 짧은 캠페인 문구나 장식 표면에만. 긴 본문, 표, form label에 쓰지 않는다.
544
+ - Button 라벨은 `medium` weight.
545
+
546
+ **Line height**
547
+ - 본문 기본 `1.6`. compact control과 섞지 않는다.
548
+
549
+ 컴포넌트별 세부 경계 규칙은 `CONTRIBUTING.md`를 따른다.
550
+
551
+ ## 검증
552
+
553
+ ```bash
554
+ bun run tokens:check
555
+ ```
556
+
557
+ `tokens:check`는 토큰 JSON, CSS 변수, public component export가 함께 맞는지 확인한다.
558
+ `tokens:generate`는 `tokens/zdp.tokens.json`에서 `zdpTokenNames`를 다시 만든다.
559
+ `share-icons:generate`는 `src/lib/share.ts`에서 소비자용 `share.js`와 `share.d.ts`를 다시 만든다.
560
+ 색상 토큰은 JSON의 `hex`와 `oklch` 값이 CSS fallback 및 OKLCH override에 모두 존재해야 통과한다.
561
+ `preview:check`는 정적 미리보기 페이지가 공통 스타일 entry와 핵심 토큰/컴포넌트 표면을 참조하는지 확인한다.
562
+ `storybook:check`는 Storybook 설정, scripts, devDependencies, overview story가 함께 유지되는지 확인한다.
563
+ `a11y:check`는 Storybook Accessibility addon이 `error` 게이트로 유지되는지 확인한다.
564
+ `package:build`는 `dist/` package surface를 생성한다.
565
+ `package:check`는 package export, files, sideEffects, Svelte 컴포넌트 compile 결과가 함께 맞는지 확인한다.
566
+ `publish:check`는 npm publish 전 package metadata, export target, files whitelist, generated dist entry, public docs, license, third-party notice가 함께 맞는지 확인한다.
567
+ `fixtures:check`는 소비자 Svelte/Vite fixture가 public package export만으로 build되는지 확인한다.
568
+ `preview:check`와 `storybook:check`는 shared CSS, Svelte 컴포넌트, Storybook, 정적 preview에 장식성 그림자, 그라데이션, 반짝임 pseudo-element, hover 이동 효과, 과한 pill radius가 다시 들어오지 않는지도 확인한다.
@@ -0,0 +1,34 @@
1
+ # Third Party Notices
2
+
3
+ This repository may review external UI libraries as behavior references, pattern catalogs, or implementation candidates.
4
+ External sources are not automatically copied into `zdp-design-system`.
5
+
6
+ ## Current Adapted Source
7
+
8
+ No third-party source code is currently copied or adapted into the package source.
9
+
10
+ ## Review Sources
11
+
12
+ The following projects may be reviewed as references under the rules in `docs/EXTERNAL_UI_ADOPTION.md`.
13
+ Reference review does not mean source code has been copied.
14
+
15
+ | Source | License | Allowed Use In ZDP |
16
+ | --- | --- | --- |
17
+ | shadcn-svelte | MIT | Behavior and accessibility reference for Svelte primitives. |
18
+ | Bits UI | MIT | Candidate internal headless implementation for high-risk interactive primitives. |
19
+ | Skeleton | MIT | Pattern catalog only; no direct core import. |
20
+ | Flowbite Svelte | MIT | Pattern catalog only; no direct core import. |
21
+ | daisyUI | MIT | CSS/pattern reference only; no Tailwind theme dependency in core. |
22
+ | Ark UI | MIT | Long-term multi-framework headless candidate. |
23
+ | Motion | MIT | Animation engine candidate for isolated marketing recipes. |
24
+ | SmoothUI | MIT | Marketing animation recipe reference only; source-derived code must be recorded separately. |
25
+
26
+ ## Prohibited Sources
27
+
28
+ Tailwind Plus and Tailwind UI source, templates, components, and derivative snippets are not used as source material for this package.
29
+ Their license terms are not a fit for a redistributable shared UI package, template, starter, or component library boundary.
30
+
31
+ ## Notice Rule
32
+
33
+ If any third-party source code is copied, ported, or meaningfully adapted later, update this file in the same change.
34
+ Record the source URL, license, component, adoption grade, and local files affected.
package/dist/code.ts ADDED
@@ -0,0 +1,2 @@
1
+ export type ZdpCodeBlockSize = 'sm' | 'md';
2
+ export type ZdpCodeBlockTone = 'default' | 'muted';
@@ -0,0 +1,9 @@
1
+ export type ZdpComboboxOption = {
2
+ readonly id: string;
3
+ readonly label: string;
4
+ readonly value: string;
5
+ readonly description?: string;
6
+ readonly disabled?: boolean;
7
+ };
8
+
9
+ export type ZdpComboboxSize = 'sm' | 'md';
@@ -0,0 +1 @@
1
+ export type ZdpCommandFieldSize = 'sm' | 'md';