@conscience-technology/ctds 0.0.0-stage → 0.1.1

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 (289) hide show
  1. package/README.md +128 -2
  2. package/assets/components/AppFrame/AppFrame.module.css +177 -0
  3. package/assets/components/AppFrame/AppFrame.tsx +93 -0
  4. package/assets/components/AppFrame/index.ts +6 -0
  5. package/assets/components/AttachmentChip/AttachmentChip.module.css +71 -0
  6. package/assets/components/AttachmentChip/AttachmentChip.tsx +74 -0
  7. package/assets/components/AttachmentChip/index.ts +2 -0
  8. package/assets/components/AttachmentThumb/AttachmentThumb.module.css +107 -0
  9. package/assets/components/AttachmentThumb/AttachmentThumb.tsx +91 -0
  10. package/assets/components/AttachmentThumb/index.ts +2 -0
  11. package/assets/components/Avatar/Avatar.module.css +167 -0
  12. package/assets/components/Avatar/Avatar.tsx +228 -0
  13. package/assets/components/Avatar/index.ts +2 -0
  14. package/assets/components/AvatarUpload/AvatarUpload.module.css +130 -0
  15. package/assets/components/AvatarUpload/AvatarUpload.tsx +139 -0
  16. package/assets/components/AvatarUpload/index.ts +2 -0
  17. package/assets/components/Badge/Badge.module.css +76 -0
  18. package/assets/components/Badge/Badge.tsx +68 -0
  19. package/assets/components/Badge/index.ts +2 -0
  20. package/assets/components/Breadcrumb/Breadcrumb.module.css +213 -0
  21. package/assets/components/Breadcrumb/Breadcrumb.tsx +279 -0
  22. package/assets/components/Breadcrumb/index.ts +8 -0
  23. package/assets/components/Button/Button.module.css +216 -0
  24. package/assets/components/Button/Button.tsx +149 -0
  25. package/assets/components/Button/index.ts +2 -0
  26. package/assets/components/Callout/Callout.module.css +146 -0
  27. package/assets/components/Callout/Callout.tsx +138 -0
  28. package/assets/components/Callout/index.ts +2 -0
  29. package/assets/components/ChatInput/ChatInput.module.css +254 -0
  30. package/assets/components/ChatInput/ChatInput.tsx +322 -0
  31. package/assets/components/ChatInput/ModelSelector.tsx +40 -0
  32. package/assets/components/ChatInput/SendButton.tsx +41 -0
  33. package/assets/components/ChatInput/index.ts +10 -0
  34. package/assets/components/Checkbox/Checkbox.module.css +66 -0
  35. package/assets/components/Checkbox/Checkbox.tsx +36 -0
  36. package/assets/components/Checkbox/index.ts +2 -0
  37. package/assets/components/Chip/Chip.module.css +128 -0
  38. package/assets/components/Chip/Chip.tsx +103 -0
  39. package/assets/components/Chip/index.ts +2 -0
  40. package/assets/components/ChoiceCard/ChoiceCard.module.css +142 -0
  41. package/assets/components/ChoiceCard/ChoiceCard.tsx +132 -0
  42. package/assets/components/ChoiceCard/index.ts +2 -0
  43. package/assets/components/ContextMenu/ContextMenu.module.css +102 -0
  44. package/assets/components/ContextMenu/ContextMenu.tsx +392 -0
  45. package/assets/components/ContextMenu/index.ts +9 -0
  46. package/assets/components/DatePicker/Calendar.tsx +234 -0
  47. package/assets/components/DatePicker/DESIGN_NOTES.md +106 -0
  48. package/assets/components/DatePicker/DESIGN_NOTES_TIME.md +125 -0
  49. package/assets/components/DatePicker/DatePicker.module.css +295 -0
  50. package/assets/components/DatePicker/DatePicker.tsx +387 -0
  51. package/assets/components/DatePicker/TimeSelector.tsx +69 -0
  52. package/assets/components/DatePicker/index.ts +8 -0
  53. package/assets/components/DatePicker/presets.ts +80 -0
  54. package/assets/components/DatePicker/utils.ts +148 -0
  55. package/assets/components/Disclosure/Disclosure.module.css +73 -0
  56. package/assets/components/Disclosure/Disclosure.tsx +129 -0
  57. package/assets/components/Disclosure/index.ts +6 -0
  58. package/assets/components/Drawer/Drawer.module.css +257 -0
  59. package/assets/components/Drawer/Drawer.tsx +126 -0
  60. package/assets/components/Drawer/index.ts +7 -0
  61. package/assets/components/EmptyState/EmptyState.module.css +102 -0
  62. package/assets/components/EmptyState/EmptyState.tsx +80 -0
  63. package/assets/components/EmptyState/index.ts +2 -0
  64. package/assets/components/FileIcon/FileIcon.module.css +66 -0
  65. package/assets/components/FileIcon/FileIcon.tsx +84 -0
  66. package/assets/components/FileIcon/fileExtMap.ts +112 -0
  67. package/assets/components/FileIcon/index.ts +9 -0
  68. package/assets/components/FilterButton/FilterButton.module.css +130 -0
  69. package/assets/components/FilterButton/FilterButton.tsx +94 -0
  70. package/assets/components/FilterButton/index.ts +2 -0
  71. package/assets/components/GalleryItem/GalleryItem.module.css +220 -0
  72. package/assets/components/GalleryItem/GalleryItem.tsx +163 -0
  73. package/assets/components/GalleryItem/index.ts +7 -0
  74. package/assets/components/Icon/Icon.tsx +616 -0
  75. package/assets/components/Icon/context.tsx +39 -0
  76. package/assets/components/Icon/index.ts +4 -0
  77. package/assets/components/IconButton/IconButton.module.css +109 -0
  78. package/assets/components/IconButton/IconButton.tsx +110 -0
  79. package/assets/components/IconButton/index.ts +2 -0
  80. package/assets/components/Input/Input.module.css +338 -0
  81. package/assets/components/Input/Input.tsx +371 -0
  82. package/assets/components/Input/index.ts +2 -0
  83. package/assets/components/ListItem/ListItem.module.css +318 -0
  84. package/assets/components/ListItem/ListItem.tsx +262 -0
  85. package/assets/components/ListItem/index.ts +9 -0
  86. package/assets/components/MenuItem/MenuItem.module.css +437 -0
  87. package/assets/components/MenuItem/MenuItem.tsx +529 -0
  88. package/assets/components/MenuItem/index.ts +8 -0
  89. package/assets/components/MetricCard/MetricCard.module.css +153 -0
  90. package/assets/components/MetricCard/MetricCard.tsx +140 -0
  91. package/assets/components/MetricCard/index.ts +2 -0
  92. package/assets/components/Modal/Modal.module.css +175 -0
  93. package/assets/components/Modal/Modal.tsx +98 -0
  94. package/assets/components/Modal/index.ts +2 -0
  95. package/assets/components/Onboarding/DocsIndex.tsx +82 -0
  96. package/assets/components/Onboarding/LayoutBuilder.tsx +160 -0
  97. package/assets/components/Onboarding/Onboarding.module.css +1394 -0
  98. package/assets/components/Onboarding/OnboardingAxisPanel.tsx +515 -0
  99. package/assets/components/Onboarding/OnboardingPage.tsx +1193 -0
  100. package/assets/components/Onboarding/PresetsGallery.tsx +65 -0
  101. package/assets/components/Onboarding/actions.ts +250 -0
  102. package/assets/components/Onboarding/index.ts +8 -0
  103. package/assets/components/Onboarding/palette.css +40 -0
  104. package/assets/components/Onboarding/wizardData.ts +265 -0
  105. package/assets/components/Pagination/Pagination.module.css +82 -0
  106. package/assets/components/Pagination/Pagination.tsx +248 -0
  107. package/assets/components/Pagination/index.ts +6 -0
  108. package/assets/components/ProgressBar/ProgressBar.module.css +64 -0
  109. package/assets/components/ProgressBar/ProgressBar.tsx +54 -0
  110. package/assets/components/ProgressBar/index.ts +2 -0
  111. package/assets/components/QuotationBar/QuotationBar.module.css +61 -0
  112. package/assets/components/QuotationBar/QuotationBar.tsx +48 -0
  113. package/assets/components/QuotationBar/index.ts +2 -0
  114. package/assets/components/Radio/Radio.module.css +63 -0
  115. package/assets/components/Radio/Radio.tsx +33 -0
  116. package/assets/components/Radio/index.ts +2 -0
  117. package/assets/components/Select/Select.module.css +151 -0
  118. package/assets/components/Select/Select.tsx +425 -0
  119. package/assets/components/Select/index.ts +10 -0
  120. package/assets/components/SelectableCard/SelectableCard.module.css +177 -0
  121. package/assets/components/SelectableCard/SelectableCard.tsx +83 -0
  122. package/assets/components/SelectableCard/index.ts +2 -0
  123. package/assets/components/Shortcut/Shortcut.module.css +56 -0
  124. package/assets/components/Shortcut/Shortcut.tsx +156 -0
  125. package/assets/components/Shortcut/index.ts +2 -0
  126. package/assets/components/Sidebar/Sidebar.module.css +242 -0
  127. package/assets/components/Sidebar/Sidebar.tsx +264 -0
  128. package/assets/components/Sidebar/index.ts +7 -0
  129. package/assets/components/SidebarSplit/SidebarSplit.module.css +126 -0
  130. package/assets/components/SidebarSplit/SidebarSplit.tsx +222 -0
  131. package/assets/components/SidebarSplit/index.ts +6 -0
  132. package/assets/components/Slider/Slider.module.css +120 -0
  133. package/assets/components/Slider/Slider.tsx +88 -0
  134. package/assets/components/Slider/index.ts +2 -0
  135. package/assets/components/SplitButton/SplitButton.module.css +190 -0
  136. package/assets/components/SplitButton/SplitButton.tsx +145 -0
  137. package/assets/components/SplitButton/index.ts +6 -0
  138. package/assets/components/Stepper/Stepper.module.css +182 -0
  139. package/assets/components/Stepper/Stepper.tsx +185 -0
  140. package/assets/components/Stepper/index.ts +2 -0
  141. package/assets/components/Switch/Switch.module.css +116 -0
  142. package/assets/components/Switch/Switch.tsx +58 -0
  143. package/assets/components/Switch/index.ts +2 -0
  144. package/assets/components/TableCell/TableCell.module.css +137 -0
  145. package/assets/components/TableCell/TableCellAvatar.tsx +42 -0
  146. package/assets/components/TableCell/TableCellBadge.tsx +23 -0
  147. package/assets/components/TableCell/TableCellIcon.tsx +39 -0
  148. package/assets/components/TableCell/TableCellImage.tsx +49 -0
  149. package/assets/components/TableCell/TableCellLink.tsx +33 -0
  150. package/assets/components/TableCell/TableCellMeter.tsx +55 -0
  151. package/assets/components/TableCell/TableCellNumber.tsx +43 -0
  152. package/assets/components/TableCell/TableCellText.tsx +30 -0
  153. package/assets/components/TableCell/index.ts +23 -0
  154. package/assets/components/TableHeader/TableHeader.module.css +287 -0
  155. package/assets/components/TableHeader/TableHeader.tsx +590 -0
  156. package/assets/components/TableHeader/index.ts +9 -0
  157. package/assets/components/TableRow/TableRow.module.css +290 -0
  158. package/assets/components/TableRow/TableRow.tsx +253 -0
  159. package/assets/components/TableRow/index.ts +8 -0
  160. package/assets/components/TableRowEdit/TableRowEdit.module.css +126 -0
  161. package/assets/components/TableRowEdit/TableRowEdit.tsx +247 -0
  162. package/assets/components/TableRowEdit/index.ts +2 -0
  163. package/assets/components/TableRowSelect/TableRowSelect.module.css +23 -0
  164. package/assets/components/TableRowSelect/TableRowSelect.tsx +175 -0
  165. package/assets/components/TableRowSelect/index.ts +2 -0
  166. package/assets/components/Tabs/Tabs.module.css +234 -0
  167. package/assets/components/Tabs/Tabs.tsx +426 -0
  168. package/assets/components/Tabs/index.ts +9 -0
  169. package/assets/components/Textarea/Textarea.module.css +318 -0
  170. package/assets/components/Textarea/Textarea.tsx +426 -0
  171. package/assets/components/Textarea/index.ts +7 -0
  172. package/assets/components/ThemeController.tsx +271 -0
  173. package/assets/components/TimePicker/TimePicker.module.css +317 -0
  174. package/assets/components/TimePicker/TimePicker.tsx +821 -0
  175. package/assets/components/TimePicker/index.ts +8 -0
  176. package/assets/components/TimePicker/utils.ts +115 -0
  177. package/assets/components/Toast/Toast.module.css +264 -0
  178. package/assets/components/Toast/Toast.tsx +243 -0
  179. package/assets/components/Toast/index.ts +15 -0
  180. package/assets/components/Toolbar/Toolbar.module.css +72 -0
  181. package/assets/components/Toolbar/Toolbar.tsx +75 -0
  182. package/assets/components/Toolbar/index.ts +2 -0
  183. package/assets/components/Tooltip/Tooltip.module.css +42 -0
  184. package/assets/components/Tooltip/Tooltip.tsx +332 -0
  185. package/assets/components/Tooltip/index.ts +2 -0
  186. package/assets/components/Topbar/Topbar.module.css +26 -0
  187. package/assets/components/Topbar/Topbar.tsx +47 -0
  188. package/assets/components/Topbar/index.ts +2 -0
  189. package/assets/components/_cn.ts +3 -0
  190. package/assets/components/_color.ts +48 -0
  191. package/assets/components/_data.ts +659 -0
  192. package/assets/components/_utils.css +19 -0
  193. package/assets/components/axisOptions.ts +24 -0
  194. package/assets/components/tokens.css +742 -0
  195. package/assets/prompts/GUIDE.md +251 -0
  196. package/assets/prompts/OVERRIDE.md +170 -0
  197. package/assets/prompts/PRINCIPLES.md +130 -0
  198. package/assets/prompts/axes/density.md +38 -0
  199. package/assets/prompts/axes/font.md +36 -0
  200. package/assets/prompts/axes/hue.md +36 -0
  201. package/assets/prompts/axes/icon.md +48 -0
  202. package/assets/prompts/axes/mode.md +50 -0
  203. package/assets/prompts/axes/motion.md +77 -0
  204. package/assets/prompts/axes/palette.md +35 -0
  205. package/assets/prompts/axes/shape.md +33 -0
  206. package/assets/prompts/axes/voice.md +54 -0
  207. package/assets/prompts/components/README.md +84 -0
  208. package/assets/prompts/components/app-frame.md +94 -0
  209. package/assets/prompts/components/attachment-chip.md +46 -0
  210. package/assets/prompts/components/attachment-thumb.md +49 -0
  211. package/assets/prompts/components/avatar.md +86 -0
  212. package/assets/prompts/components/badge.md +104 -0
  213. package/assets/prompts/components/breadcrumb.md +77 -0
  214. package/assets/prompts/components/button.md +99 -0
  215. package/assets/prompts/components/callout.md +81 -0
  216. package/assets/prompts/components/chat-input.md +84 -0
  217. package/assets/prompts/components/checkbox.md +46 -0
  218. package/assets/prompts/components/chip.md +84 -0
  219. package/assets/prompts/components/choice-card.md +127 -0
  220. package/assets/prompts/components/context-menu.md +145 -0
  221. package/assets/prompts/components/date-picker.md +104 -0
  222. package/assets/prompts/components/drawer.md +152 -0
  223. package/assets/prompts/components/empty-state.md +69 -0
  224. package/assets/prompts/components/file-icon.md +73 -0
  225. package/assets/prompts/components/filter-button.md +42 -0
  226. package/assets/prompts/components/form-field.md +74 -0
  227. package/assets/prompts/components/gallery-item.md +158 -0
  228. package/assets/prompts/components/icon-button.md +82 -0
  229. package/assets/prompts/components/icon.md +68 -0
  230. package/assets/prompts/components/input.md +95 -0
  231. package/assets/prompts/components/list-item.md +235 -0
  232. package/assets/prompts/components/menu-item.md +234 -0
  233. package/assets/prompts/components/metric-card.md +132 -0
  234. package/assets/prompts/components/modal.md +131 -0
  235. package/assets/prompts/components/pagination.md +92 -0
  236. package/assets/prompts/components/progress-bar.md +61 -0
  237. package/assets/prompts/components/quotation-bar.md +39 -0
  238. package/assets/prompts/components/radio.md +41 -0
  239. package/assets/prompts/components/select.md +104 -0
  240. package/assets/prompts/components/selectable-card.md +67 -0
  241. package/assets/prompts/components/shortcut.md +76 -0
  242. package/assets/prompts/components/sidebar.md +107 -0
  243. package/assets/prompts/components/slider.md +89 -0
  244. package/assets/prompts/components/split-button.md +71 -0
  245. package/assets/prompts/components/stepper.md +93 -0
  246. package/assets/prompts/components/switch.md +86 -0
  247. package/assets/prompts/components/table-cell.md +87 -0
  248. package/assets/prompts/components/table-header.md +157 -0
  249. package/assets/prompts/components/table-row-edit.md +129 -0
  250. package/assets/prompts/components/table-row-select.md +82 -0
  251. package/assets/prompts/components/table-row.md +156 -0
  252. package/assets/prompts/components/tabs.md +122 -0
  253. package/assets/prompts/components/textarea.md +105 -0
  254. package/assets/prompts/components/toast.md +149 -0
  255. package/assets/prompts/components/tooltip.md +71 -0
  256. package/assets/prompts/components/topbar.md +148 -0
  257. package/assets/prompts/primitives/emerge.md +43 -0
  258. package/assets/prompts/primitives/fade.md +31 -0
  259. package/assets/prompts/primitives/scale.md +32 -0
  260. package/assets/prompts/primitives/scroll.md +75 -0
  261. package/assets/prompts/primitives/slide.md +31 -0
  262. package/assets/prompts/themes/_SCHEMA.md +135 -0
  263. package/assets/prompts/themes/_TEMPLATE.md +73 -0
  264. package/assets/prompts/themes/expressive.md +118 -0
  265. package/assets/prompts/themes/pure.md +87 -0
  266. package/assets/prompts/themes/spare.md +73 -0
  267. package/assets/prompts/tokens/breakpoint.md +29 -0
  268. package/assets/prompts/tokens/color.md +78 -0
  269. package/assets/prompts/tokens/radius.md +33 -0
  270. package/assets/prompts/tokens/shadow.md +35 -0
  271. package/assets/prompts/tokens/spacing.md +86 -0
  272. package/assets/prompts/tokens/typography.md +76 -0
  273. package/assets/prompts/tokens/z-index.md +35 -0
  274. package/assets/public/expressive.png +0 -0
  275. package/assets/public/pure.png +0 -0
  276. package/assets/public/spare.png +0 -0
  277. package/assets/skill/SKILL.md +36 -0
  278. package/bin/ctds.js +76 -0
  279. package/package.json +35 -4
  280. package/src/commands/init.js +215 -0
  281. package/src/commands/update.js +275 -0
  282. package/src/utils/assets.js +78 -0
  283. package/src/utils/deps.js +51 -0
  284. package/src/utils/detect.js +47 -0
  285. package/src/utils/diff.js +52 -0
  286. package/src/utils/hash.js +16 -0
  287. package/src/utils/log.js +41 -0
  288. package/src/utils/meta.js +73 -0
  289. package/src/utils/prompt.js +28 -0
@@ -0,0 +1,104 @@
1
+ # Badge
2
+
3
+ ### 원칙
4
+ 카운트·상태 라벨을 담는 최소 컴포넌트. 메뉴 아이템 옆 언리드 수, 사이드바 nav 옆 "new", 버튼 위 알림 카운트, 리스트 행의 상태 태그가 모두 이 컴포넌트를 공유한다. 콘텐츠(숫자/짧은 문자열)를 감싸는 얇은 껍데기 역할이라 아이콘·모션·인터랙션은 안 담는다 — 아이콘이 필요하면 [[components/chip]] 또는 [[components/tag]]를 검토.
5
+
6
+ 크기는 폰트/컨트롤 위계에 종속되어 [[axes/density]]에 반응. **variant 규칙**: `solid`는 알림/언리드 강조 전용이라 `--primary`만, `inverse`는 어두운 표면(선택된 FilterButton 등) 위 라벨 전용이라 `--bg`+`--fg`만 — 둘 다 status와 조합 금지. `soft`는 기본 `--primary` 기반이며 `status` prop으로 `--success` · `--warning` · `--destructive` · `--info`에 매핑. 라운드는 `shape` prop — 기본 `square`는 sm/md 공통 `--radius-xs`(Shape 축이 커도 md가 pill로 보이지 않도록 sm에 고정), 완전 pill이 필요하면 `shape="pill"`로 `--radius-full`.
7
+
8
+ ### Do
9
+ - **수치는 우측 슬롯**: `MenuItem`, 리스트 행, 카드 헤더의 trailing 위치에 넣는다. 언리드 수·미확인 수·중요 태그 위계.
10
+ - **콘텐츠 폭 그대로 흐르는 사각 라벨**: 정원·pill 아님. `--radius-xs`로 조여진 사각 캡슐(sm/md 공통). 1글자든 여러 글자든 텍스트 크기에 붙어 자연스럽게 늘어남.
11
+ - **뜻이 명확한 문자열만**: `new`, `beta`, `12` 처럼 짧고 자명한 콘텐츠. 3~4글자를 넘기지 않는다.
12
+ - **size는 붙는 컴포넌트에 맞춘다**: `MenuItem` `md` 옆이면 `sm`, `MenuItem` `lg`나 큰 카드 옆이면 `md`. 라벨 폰트 위계보다 커지지 않게.
13
+ - **variant는 강조 위계로 선택**: 지금 반드시 봐야 하는 알림·언리드는 `solid`(primary만), 그 외 모든 라벨(온화한 강조·상태·카운트)은 `soft`.
14
+ - **status는 soft 전용**: 성공/경고/삭제/정보 뜻이 정확할 때만 `soft`에 status를 얹는다. 브랜드 톤을 "예쁘게" 쓰려고 status를 남용하지 않는다.
15
+
16
+ ### Don't
17
+ - 문장이나 아이콘을 넣지 않는다 — 그건 [[components/chip]] · [[components/tag]] · [[components/callout]]의 몫.
18
+ - 상호작용(클릭·hover 툴팁 등)을 붙이지 않는다. Badge는 순수 시각 요소.
19
+ - **`solid` + `status` 조합 금지**: solid는 primary만 사용. 상태색을 채운 solid 라벨이 필요하면 [[components/chip]]/[[components/tag]] 검토. (런타임에서 status를 무시하고 dev warning.)
20
+ - 색을 hex/tailwind 클래스로 직접 지정하지 않는다. 성공·경고·삭제·정보 외의 색상 슬롯이 필요하면 임의로 만들지 말고 [[components/chip]] · [[components/tag]] 검토.
21
+ - `--primary-fg` 같은 존재하지 않는 토큰을 쓰지 않는다. solid 위 텍스트는 `--bg` (Button primary와 동일 규칙).
22
+
23
+ ### Fallback
24
+ size 애매하면 `sm`, variant 애매하면 `soft`. `solid`는 "지금 봐야 하는 알림"임이 확실할 때만.
25
+
26
+ ### 관련
27
+ - [[components/menu-item]] · [[components/sidebar]] — 가장 흔한 사용처. trailing 슬롯 배지 카운트.
28
+ - [[components/button]] — solid 위 텍스트 색을 `--bg`로 두는 규칙 공유.
29
+ - [[components/chip]] · [[components/tag]] — 아이콘·상태 색·인터랙션이 필요하면 여기로.
30
+ - [[tokens/color]] — `--primary` · `--bg` · `--secondary-fg`
31
+ - [[axes/density]] — 폰트·min-height가 축에 반응
32
+
33
+ ### Props 시그니처
34
+ ```tsx
35
+ <Badge
36
+ size="sm | md" // default: sm
37
+ variant="solid | soft | inverse" // default: solid
38
+ status="success | warning | destructive | info" // optional — 상태 뜻이 정확할 때만
39
+ shape="square | pill" // default: square
40
+ >
41
+ {children} // 짧은 문자열/숫자
42
+ </Badge>
43
+ ```
44
+
45
+ ### 상태 매트릭스
46
+ `solid`는 primary만. `soft`는 status에 따라 상태 토큰으로 스왑된다.
47
+
48
+ | variant | 배경 | 텍스트 | 용도 |
49
+ |---|---|---|---|
50
+ | `solid` | `--primary` | `--bg` (Mode 반전) | 지금 봐야 하는 강조: 언리드, 알림 카운트 (**status 조합 불가**) |
51
+ | `soft` | `--primary` 8% 알파 | `--secondary-fg` (Palette=mono면 무채색) | 온화한 상태 라벨: "new", "beta" |
52
+ | `soft` + `success` / `warning` / `destructive` / `info` | 각 상태 토큰 8% 알파 | 각 상태 토큰 | 뜻이 명확한 상태 라벨 |
53
+ | `inverse` | `--bg` | `--fg` | **어두운 표면 위에서만 사용** — 선택된 FilterButton 안 카운트 등 (**status 조합 불가**) |
54
+
55
+ ### Size 가이드
56
+ 크기는 텍스트 line-height + padding으로 자연히 결정된다. `shape="square"`(기본)는 size별 radius로 조여진 사각 라벨, `shape="pill"`은 좌우 반원 캡. 1글자든 여러 글자든 콘텐츠 폭 그대로 흐른다.
57
+
58
+ | size | padding (v · h) | font-size | radius (square) | 언제 |
59
+ |---|---|---|---|---|
60
+ | `sm` | 2 · 4 | `--text-xs` | `--radius-xs` | MenuItem sm/md 옆, 리스트 · 사이드바 |
61
+ | `md` | 4 · 6 | `--label-sm-size` | `--radius-xs` | MenuItem lg 옆, 카드 헤더, 페이지 타이틀 |
62
+
63
+ `shape="pill"`이면 size와 무관하게 `--radius-full`. 라벨 성격이 &ldquo;메타/카테고리&rdquo;가 아니라 &ldquo;알림 카운트/도트&rdquo;에 가까울 때만 pill.
64
+
65
+ ### Solid vs Soft — 언제 뭘 쓰나
66
+ Badge의 위계는 **두 갈래**로 나뉜다. 헷갈리면 이 표를 먼저 본다.
67
+
68
+ | variant | 뜻 | 언제 쓰나 | 예시 라벨 |
69
+ |---|---|---|---|
70
+ | `solid` | **"지금 반드시 봐야 함"** — 시각적 알림 | 언리드 메시지 수, 미확인 알림, 처리 대기 카운트. 사용자가 방치하면 안 되는 것. | `3`, `12`, `99+` |
71
+ | `soft` | **"이 아이템의 속성/상태"** — 조용한 라벨 | 카테고리 태그, "new"·"beta" 배지, API 상태(성공/경고/삭제/정보). 정보성 표기. | `new`, `beta`, `draft`, `API` |
72
+
73
+ 한 화면에 `solid`가 너무 많이 보이면 안 된다 — "알림"이라는 뜻이 희석된다. Sidebar 100개 항목 중 언리드가 있는 3~4개만 `solid`, 나머지는 아예 배지 없음이 정상.
74
+
75
+ ### 조합 예시
76
+ ```tsx
77
+ // SOLID — 언리드 카운트 (알림)
78
+ <MenuItem
79
+ leadingActions={[<Icon name="chat" />]}
80
+ trailingActions={[<Badge variant="solid">3</Badge>]}
81
+ >#general</MenuItem>
82
+
83
+ <MenuItem
84
+ leadingActions={[<Icon name="bell" />]}
85
+ trailingActions={[<Badge variant="solid">12</Badge>]}
86
+ >알림</MenuItem>
87
+
88
+ // SOFT — 조용한 상태/카테고리 라벨
89
+ <MenuItem asChild active leadingActions={[<Icon name="star" />]}
90
+ trailingActions={[<Badge variant="soft">new</Badge>]}
91
+ >
92
+ <Link href="/whats-new">What&apos;s new</Link>
93
+ </MenuItem>
94
+
95
+ <div className="card-header">
96
+ <h3>Beta features <Badge size="md" variant="soft">beta</Badge></h3>
97
+ </div>
98
+
99
+ // SOFT + STATUS — 뜻이 명확한 상태 라벨
100
+ <Badge variant="soft" status="success">API</Badge>
101
+ <Badge variant="soft" status="info">draft</Badge>
102
+ <Badge variant="soft" status="warning">deprecated</Badge>
103
+ <Badge variant="soft" status="destructive">3</Badge>
104
+ ```
@@ -0,0 +1,77 @@
1
+ # Breadcrumb
2
+
3
+ ### 원칙
4
+ 현재 페이지가 계층 구조의 어디에 있는지 보여주고, **상위로 한 번에** 돌아가게 해주는 nav 컨트롤. 시각 무게는 최소 — [[components/button]] `size=xs · variant=ghost`와 같은 톤. 페이지 헤더 위 얇은 한 줄로만 존재하고, 자기 자신을 스캔 대상으로 만들지 않는다.
5
+
6
+ ### Do
7
+ - **깊이 3 이상**일 때만 쓴다 — 2단계면 상위 링크 하나로 충분하고, 브래드크럼은 노이즈가 된다.
8
+ - **마지막 항목은 `Breadcrumb.Current`** — 링크가 아닌 텍스트. `--fg-strong`로 자연스럽게 위계를 준다.
9
+ - **첫 항목은 워크스페이스/홈 아이콘** 하나까지 허용. 그 외 항목엔 아이콘 붙이지 않는다 (스캔 방해).
10
+ - **아이콘 단독 항목**: `Breadcrumb.Link`/`Current`에 `children` 없이 `leftIcon`만 넘기면 정사각 hit box 아이콘 버튼이 된다. `aria-label` 반드시 지정.
11
+ - **URL 계층이 그대로 라벨** — 사이트맵의 실제 위치를 그대로 반영. 계층에 없는 임의 카테고리를 만들어 붙이지 않는다.
12
+ - **모바일에서는 축약** — 첫 항목 + `Breadcrumb.Ellipsis` + 마지막 두 항목. 6개 이상이면 축약이 필수.
13
+ - **Next.js `<Link>` 등 라우터**는 `<Breadcrumb.Link asChild>`로 감싼다. 스타일 유지한 채 SPA 네비게이션 위임.
14
+ - **접근성**: 루트가 자동으로 `<nav aria-label="Breadcrumb">` + `<ol>`, 마지막 항목에 `aria-current="page"`를 붙인다. separator는 `aria-hidden`.
15
+
16
+ ### Don't
17
+ - **탭 전환용으로 쓰지 않는다** — 그건 [[components/tabs]]. Breadcrumb은 URL 자체가 바뀌는 계층 이동 전용.
18
+ - **마지막 항목을 링크로 만들지 않는다** — 자기 페이지를 다시 링크하면 새로고침 트리거가 되고 사용자를 헷갈리게 한다.
19
+ - **`Button size=xs`가 아닌 다른 사이즈**로 커스텀하지 않는다 — 페이지 헤더 위 최소 무게가 유일한 존재 이유.
20
+ - **활성 색을 `--primary`로 덮지 않는다** — 활성은 `--fg-strong`(무채). 브랜드 컬러를 여기 쓰면 CTA와 위계가 충돌.
21
+ - **아이콘 남발 금지** — 첫 항목 외에 아이콘 붙이면 라벨 스캔이 무너진다.
22
+ - **draggable/sortable 만들지 않는다** — 계층은 URL이 정한다. UI에서 조작할 대상이 아님.
23
+
24
+ ### Fallback
25
+ - 라우터 결정 애매하면 기본 `<a href>` 렌더. 프레임워크 붙일 때 `asChild`로 교체.
26
+ - 축약 위치 애매하면 첫 · 마지막 두 개 유지, 중간 전부 `Breadcrumb.Ellipsis`로 접기.
27
+ - 규칙대로 판단 불가한 경우 사용자에게 확인.
28
+
29
+ ### 관련
30
+ - [[components/button]] — Link 시각을 그대로 상속 (`size=xs · variant=ghost`)
31
+ - [[components/tabs]] — 페이지 안 콘텐츠 전환은 Breadcrumb이 아니라 Tabs
32
+ - [[components/sidebar]] — 계층의 "전체 뷰"는 Sidebar, "현재 위치 트레일"은 Breadcrumb
33
+ - [[axes/density]] — `--control-h-xs`가 Link 높이에 매핑
34
+ - [[axes/shape]] — `--radius-xs`가 Link hover 표면 radius에 매핑
35
+ - [[tokens/color]] — `--fg-muted`(Link) → `--fg-strong`(Current) 대비, `--hover`(hover 표면)
36
+
37
+ ### Props 시그니처
38
+ ```tsx
39
+ <Breadcrumb
40
+ aria-label="Breadcrumb" // default: "Breadcrumb"
41
+ separator={<Icon name="caret-right" />} // default: caret-right icon
42
+ >
43
+ <Breadcrumb.Link href="/" leftIcon={<Icon name="house" />}>Home</Breadcrumb.Link>
44
+ <Breadcrumb.Link asChild>
45
+ <Link href="/components">Components</Link>
46
+ </Breadcrumb.Link>
47
+ <Breadcrumb.Ellipsis />
48
+ <Breadcrumb.Current>Breadcrumb</Breadcrumb.Current>
49
+ </Breadcrumb>
50
+ ```
51
+
52
+ ### Variant 매트릭스
53
+ | variant | 용도 | 금지 조합 |
54
+ |---|---|---|
55
+ | `Breadcrumb.Link` | 상위 계층 링크. Button xs · ghost 톤. hover 시 `--hover` 표면. | 마지막 항목엔 쓰지 않음. |
56
+ | `Breadcrumb.Current` | 현재 페이지. `--fg-strong` 텍스트, hover 반응 없음. | `href`·`onClick` 붙이지 않음. |
57
+ | `Breadcrumb.Ellipsis` | 축약 트리거. 항상 클릭 가능. [[components/select]]와 동일한 팝오버 표면으로 숨긴 항목 리스트를 연다. | `items`에 5개 이상 넣지 않는다 — 그러면 축약이 아니라 실질적 서브메뉴가 됨. 정적(클릭 불가) 마커는 지원하지 않는다. |
58
+
59
+ ### 조합 예시
60
+ ```tsx
61
+ // 표준 — Next Link + 홈 아이콘 + 축약
62
+ <Breadcrumb aria-label="문서 경로">
63
+ <Breadcrumb.Link asChild leftIcon={<Icon name="house" />}>
64
+ <Link href="/">Home</Link>
65
+ </Breadcrumb.Link>
66
+ <Breadcrumb.Ellipsis
67
+ items={[
68
+ { label: "Components", href: "/components" },
69
+ { label: "Navigation", href: "/components/nav" },
70
+ ]}
71
+ />
72
+ <Breadcrumb.Link asChild>
73
+ <Link href="/components/nav">Navigation</Link>
74
+ </Breadcrumb.Link>
75
+ <Breadcrumb.Current>Breadcrumb</Breadcrumb.Current>
76
+ </Breadcrumb>
77
+ ```
@@ -0,0 +1,99 @@
1
+ # Button
2
+
3
+ ### 원칙
4
+ 텍스트 액션의 최소 단위. 클릭 시 무언가 **일어나는** 컨트롤 — 페이지 이동은 [[components/link]]. size는 [[axes/density]] 축과 연동되고, variant는 semantic 역할(강조 위계)만 담당한다.
5
+
6
+ ### Do
7
+ - **중요=`primary`, 서브=`outline`**이 기본 쌍이다. 모달 하단, 폼 하단, 페이지 액션 영역 등 "확정 + 취소/이전" 구조의 기본값. `secondary`는 primary tint가 섞인 색조 액션이 필요한 특별 맥락에서만 — 중립 서브 액션엔 `outline`이 먼저다.
8
+ - **버튼 사이 gap은 언제나 `space-1`(4px) 고정.** footer action 쌍, 툴바 액션 묶음, 폼 하단 등 어느 자리든 동일. `space-2` 이상 금지 — 두 버튼이 하나의 액션 묶음으로 묶여 읽히는 밀도를 유지.
9
+ - **기본은 `size="md"`**. 90% 이상의 경우 md. 다른 사이즈로 갈 명확한 이유가 있을 때만 바꾼다.
10
+ - **폼·컨트롤과 나란히 놓일 때는 그 컨트롤의 size와 맞춘다** — Input md 옆엔 Button md, Input sm 옆엔 Button sm. 미묘한 높이 차이가 정렬을 무너뜨린다.
11
+ - 한 화면에 `variant="primary"`는 **1개**. 페이지의 대표 액션만.
12
+ - **아이콘만 있는 버튼도 Button으로 처리** — label 없이 `leftIcon`만 넣으면 자동으로 정사각(width = height = `--control-h-*`), `leftIcon` + `rightIcon`(예: 아이콘 + `caret-down`)이면 텍스트 없이 좁은 대칭 패딩. 어느 쪽이든 `aria-label` 필수. 별도 [[components/icon-button]] 컴포넌트는 legacy — 신규 사용은 지양.
13
+ - **파괴적 액션은 위계로 2단 분리한다.**
14
+ - `destructive` — **강한 위계.** 확인 모달의 "정말 삭제하시겠습니까?" 최종 확인, 되돌릴 수 없는 결정적 순간. 평상시 옅은 빨강 배경 + 빨강 텍스트, hover 시 solid 빨강으로 전환되며 위험을 예고.
15
+ - `destructive-ghost` — **약한 위계.** 테이블 행/헤더의 삭제, 페이지에 그냥 노출된 삭제 버튼 등 일상적 목록 조작. 평상시 fg(검정) 텍스트로 눈에 띄지 않다가 hover 시에만 빨강 톤(8% 배경 + 빨강 텍스트)이 나타남.
16
+
17
+ ### Don't
18
+ - 한 화면에 primary 2개 이상 금지. 시각 위계 붕괴.
19
+ - 버튼 사이 gap에 `space-2`(8px) 이상 금지 — 반드시 `space-1`(4px).
20
+ - height를 CSS로 덮어쓰지 않는다. `size` prop 경유.
21
+ - 페이지 이동에 Button 쓰지 않는다 — 시맨틱은 `<a>`.
22
+ - disabled 색을 variant별로 다르게 덮어쓰지 않는다. **모든 variant는 disabled 시 회색 배경(`--bg-muted`) + 실버 텍스트(`--fg-disabled`) + 투명 보더로 통일** — "지금은 못 누른다"가 variant 위계보다 우선 읽혀야 한다.
23
+
24
+ ### Fallback
25
+ size 애매하면 `md`, variant 애매하면 서브 자리에선 `outline`·대표 자리에선 `primary`.
26
+
27
+ ### 관련
28
+ - [[components/split-button]] — 메인 액션 + 부가 옵션(caret) 2-part 버튼
29
+ - [[components/icon-button]] — legacy, 신규는 Button icon-only 사용
30
+ - [[components/input]] · [[components/select]] — 같은 화면에서 size 맞춤
31
+ - [[axes/density]] — `--control-h-*`가 size에 매핑
32
+ - [[axes/shape]] — radius가 Shape 축에 반응
33
+ - [[tokens/color]] — `--primary`, `--destructive` 등 variant 매핑
34
+
35
+ ### Props 시그니처
36
+ ```tsx
37
+ <Button
38
+ size="xs | sm | md | lg" // default: md
39
+ variant="primary | inverse | secondary | outline | ghost | destructive | destructive-ghost" // default: primary
40
+ leftIcon={ReactNode} rightIcon={ReactNode}
41
+ loading={boolean} disabled={boolean}
42
+ fullWidth={boolean}
43
+ asChild={boolean} // Radix Slot 패턴
44
+ />
45
+ ```
46
+
47
+ ### Variant 매트릭스
48
+ | variant | 용도 | 금지 조합 |
49
+ |---|---|---|
50
+ | `primary` | **중요 액션의 기본값.** 페이지 대표 액션(가입·제출·확인·다음) | 한 화면 2개 이상 금지 |
51
+ | `inverse` | 흑백 반전. Palette=mono에서 primary 대신 강조 | Hue와 무관 |
52
+ | `outline` | **서브 액션의 기본값.** 취소·이전 등 primary와 짝 이루는 중립 액션. 툴바·필터에도 사용 | — |
53
+ | `secondary` | primary tint가 섞인 색조 액션이 필요할 때만. 중립 서브엔 `outline`이 먼저 | — |
54
+ | `ghost` | 최소 시각 무게. 인라인·툴바. | — |
55
+ | `destructive` | **강한** 위험 위계 — 확인 모달의 최종 삭제 버튼, 되돌릴 수 없는 결정 | 목록·툴바의 일상 삭제엔 과함 → `destructive-ghost` 사용 |
56
+ | `destructive-ghost` | **약한** 위험 위계 — 테이블/페이지에 노출된 일상적 삭제 | 최종 확인 자리엔 부족 → `destructive` 사용 |
57
+
58
+ ### Size 가이드
59
+ | size | height | 언제 |
60
+ |---|---|---|
61
+ | `xs` | 24 | **거의 쓸 일 없음.** 극한 밀도가 정말 필요한 예외적 상황(인라인 태그 액션, 셀 내부 미니 컨트롤)에서만. 쓴다면 **`variant="ghost"` 강력 권장** — filled/outline은 이 크기에서 시각 무게가 과해 튀고 답답함. |
62
+ | `sm` | 32 | 밀도 높은 관리 UI, 툴바, 테이블 행 액션 |
63
+ | `md` | 36 | **기본.** 폼·모달·페이지 액션 대부분 |
64
+ | `lg` | 40 | 랜딩·온보딩의 대표 CTA. 손가락 hitbox 필요한 터치 |
65
+
66
+ > **`xs` 사용 전 재고**: 밀도가 부족하다고 느껴진다면 먼저 Density 축(`--space-scale`)을 조이는 게 옳다. 페이지에 `xs`가 튀어나온다면 대부분 `sm` + Density 축 조정으로 해결된다.
67
+
68
+ ### 조합 예시
69
+ ```tsx
70
+ // 폼 하단: outline(서브) + primary(중요) 나란히, Input과 같은 size
71
+ <div style={{ display: "flex", gap: "var(--space-1)" }}>
72
+ <Button variant="outline">취소</Button>
73
+ <Button variant="primary" leftIcon={<CheckIcon />}>저장</Button>
74
+ </div>
75
+
76
+ // 테이블 행 액션: sm ghost로 밀도 확보
77
+ <Button size="sm" variant="ghost" leftIcon={<PencilIcon />}>수정</Button>
78
+
79
+ // 테이블/페이지의 일상적 삭제: destructive-ghost (약한 위계, hover에만 빨강)
80
+ <Button size="sm" variant="destructive-ghost" leftIcon={<TrashIcon />}>삭제</Button>
81
+
82
+ // 확인 모달의 최종 삭제 버튼: destructive (강한 위계)
83
+ <Modal>
84
+ <p>정말 삭제하시겠습니까?</p>
85
+ <Button variant="outline" onClick={close}>취소</Button>
86
+ <Button variant="destructive" onClick={confirmDelete}>삭제</Button>
87
+ </Modal>
88
+
89
+ // 아이콘만: 정사각 (aria-label 필수)
90
+ <Button variant="ghost" aria-label="검색" leftIcon={<Icon name="search" />} />
91
+
92
+ // 아이콘 + caret: 드롭다운 트리거 (텍스트 없이 좁은 대칭 패딩)
93
+ <Button
94
+ variant="outline"
95
+ aria-label="사용자 메뉴"
96
+ leftIcon={<Icon name="user" />}
97
+ rightIcon={<Icon name="caret-down" />}
98
+ />
99
+ ```
@@ -0,0 +1,81 @@
1
+ # Callout
2
+
3
+ ### 원칙
4
+ 사이드바·리스트 끝·설정 패널의 여백에 상주하는 소형 안내 카드. 페이지 흐름을 끊지 않고 새 기능·이동 경로를 제시한다. hover가 없는 [[components/tooltip]], 휘발되는 Toast, 페이지 폭 전체를 덮는 [[components/banner]]와 구분된다.
5
+
6
+ ### Do
7
+ - 표면 강도는 `variant`, 강조 색은 `tone`으로 독립 제어한다.
8
+ - `dismissible=true`면 `onDismiss`와 함께 부모가 숨김 상태를 저장한다.
9
+ - `actions`는 [[components/button]] slot이다 — variant는 자유, size는 `xs`(기본) 또는 `sm`만.
10
+ - 액션 Button의 색은 `tone`을 따라간다 — solid/soft 버튼이면 같은 tone(warning엔 warning 버튼, destructive엔 destructive 버튼), 아니면 `ghost`/`outline` 중립. tone과 다른 색 solid 버튼으로 신호를 깨지 않는다.
11
+ - 좁은 컨테이너에선 `actionsPlacement="bottom"` 유지, `right`는 본문이 짧고 카드가 가로로 넓을 때만.
12
+ - `warning`/`destructive` tone은 `icon` 미지정 시 각각 `warning-circle`(주의) / `warning`(위험)이 자동. 다른 의미 아이콘이 필요할 때만 override한다.
13
+
14
+ ### Don't
15
+ - 페이지 폭 전역 경고에 쓰지 않는다 — [[components/banner]] 영역.
16
+ - 임시 피드백에 쓰지 않는다 — Toast를 쓴다.
17
+ - 본문을 4줄 넘게 채우지 않는다.
18
+ - `tone`을 임의 색상으로 확장하지 않는다.
19
+
20
+ ### Fallback
21
+ `variant` 애매하면 `fill`. `tone` 애매하면 `brand`. `actionsPlacement` 애매하면 `bottom`.
22
+
23
+ ### 관련
24
+ - [[components/banner]] — 페이지 폭 전면 경고. Callout은 국소 카드.
25
+ - [[components/button]] — actions 슬롯의 실제 요소이며 variant 규칙 원본.
26
+ - [[components/badge]] — title 옆 상태 라벨.
27
+ - [[axes/hue]] · [[axes/palette]] — tone별 강조 색을 스왑.
28
+
29
+ ### Props 시그니처
30
+ ```tsx
31
+ <Callout
32
+ title={ReactNode} // required
33
+ icon={IconName}
34
+ variant="fill | outline" // default: fill
35
+ tone="neutral | brand | success | warning | destructive" // default: brand
36
+ actions={ReactNode}
37
+ actionsPlacement="bottom | right" // default: bottom
38
+ dismissible={boolean} // default: false
39
+ onDismiss={() => void}
40
+ dismissLabel={string}
41
+ >{children}</Callout>
42
+ ```
43
+
44
+ ### Variant 매트릭스
45
+ variant × tone 축이 독립 조합. 표는 tone 기준으로 정렬, 각 tone에 variant 두 종을 보여준다.
46
+
47
+ | tone | fill | outline | 용도 |
48
+ |---|---|---|---|
49
+ | `neutral` | 회색 표면(`bg-subtle`) + `fg-muted` 아이콘 | 표면 투명 + `border` 경계 | 톤 없는 기본 안내·중립 컨텍스트 |
50
+ | `brand` | tone 8% tint 표면 + brand 아이콘·경계 | 표면 투명 + brand 경계 | 신기능·프로모션·마이그레이션 유도 |
51
+ | `success` | success 8% tint + success 아이콘·경계 | 표면 투명 + success 경계 | 완료·다음 스텝 제안 |
52
+ | `warning` | warning 8% tint + warning 아이콘·경계 | 표면 투명 + warning 경계 | 만료·용량 임박·설정 누락 |
53
+ | `destructive` | destructive 8% tint + destructive 아이콘·경계 | 표면 투명 + destructive 경계 | 삭제 예정·비가역 상태 |
54
+
55
+ **금지 조합**
56
+ tone이 톤 신호를 쥐고 있으므로, 그 안의 요소들(액션 버튼·아이콘)도 같은 신호를 유지해야 한다. 색이 어긋나면 사용자는 어느 쪽을 믿어야 할지 결정하지 못한다.
57
+
58
+ - `tone`과 다른 색상 CTA Button을 섞지 않는다 — `warning` 콜아웃 안에 `brand`(파랑) solid 버튼, `destructive` 콜아웃 안에 `success`(초록) 버튼처럼 신호가 어긋나는 조합은 금지. 액션 Button은 같은 tone의 색을 쓰거나(`solid`/`soft`), 색 신호를 비우는 `ghost`/`outline` 중립 버튼만 허용.
59
+ - `brand` tone 콜아웃에 `secondary` 톤 solid 버튼으로 메인 CTA를 두지 않는다 — 톤이 brand면 주 액션도 brand solid, 보조 액션만 ghost.
60
+ - `tone=success` + 파괴 액션(`destructive` Button) — 긍정 맥락 안의 비가역 액션은 사용자를 속인다.
61
+ - `tone=destructive` + `success` 아이콘(check 등) — 아이콘이 톤을 뒤집는다.
62
+ - `tone=warning` + `success` 아이콘, `tone=warning` + brand solid 버튼 등 톤↔요소 신호 역전 금지.
63
+ - 한 콜아웃 안에 서로 다른 tone의 solid 버튼 둘을 나란히 두지 않는다 — primary 1개 + 중립(ghost/outline) 1개 패턴만.
64
+
65
+ ### 조합 예시
66
+ ```tsx
67
+ <Callout
68
+ icon="stack"
69
+ title="Import Issues"
70
+ dismissible
71
+ onDismiss={() => setHidden(true)}
72
+ dismissLabel="Dismiss"
73
+ actions={
74
+ <Button variant="ghost" size="sm" rightIcon={<Icon name="arrow-right" />}>
75
+ Try Now
76
+ </Button>
77
+ }
78
+ >
79
+ Use our Migration Assistant to copy issues from another service.
80
+ </Callout>
81
+ ```
@@ -0,0 +1,84 @@
1
+ # Chat Input
2
+
3
+ ### 원칙
4
+ AI 채팅의 입력 영역. **첨부물 바 → 인용 바 → 입력 본문**(textarea 또는 input)의 세 층 구성. 모델 선택·전송·중지·파일첨부를 전부 담당. 하위 레이어 [[components/file-icon]]·[[components/attachment-thumb]]·[[components/attachment-chip]]·[[components/quotation-bar]]를 **조립**하는 상위 블록 — 자체 primitive 추가 금지.
5
+
6
+ ### Do
7
+ - Shape은 두 가지 — `multi`(기본, 긴 입력·오버레이 UI), `single`(토픽바·검색봉 느낌).
8
+ - Radius는 세 단계: `square`(--radius-xs) / `rounded`(--radius-sm) / `circular`(--radius-md). Shape 축 반응.
9
+ - `models` + `selectedModel` + `onSelectModel` 셋이 다 있을 때만 모델 selector 노출.
10
+ - 전송은 `Enter`로 — multi에선 `Shift+Enter`가 줄바꿈. 스트리밍 중엔 `Enter`나 send 클릭이 `onStop`을 호출.
11
+ - 첨부·인용은 전부 **외부 상태** — ChatInput은 표시·삭제 콜백만 중계. 업로드 로직·중복 체크는 소비처 책임.
12
+ - `onAttach`에 File[]이 들어옴. 소비처가 kind 판정(image/file)해서 attachments에 매핑.
13
+
14
+ ### Don't
15
+ - 첨부·인용·메시지 상태를 ChatInput 안에서 관리하지 않는다 — controlled 전용.
16
+ - radius prop을 수치로 받지 않는다 — `square | rounded | circular` 세 단계만. 실제 값은 Shape 축 토큰이 결정.
17
+ - 모델 선택 메뉴를 내부에서 열지 않는다 — 현재는 라벨 클릭 시 다음 모델로 토글만. 실제 ContextMenu는 소비처에서 조립 (ChatInput의 책임 과잉 방지).
18
+ - SingleLine에서 모델 라벨을 끝까지 노출하지 않는다 — 10자 넘으면 자동 compact(아이콘만).
19
+ - Send 버튼 색을 변경하지 않는다 — 비활성=`bg-subtle` / 활성·스트리밍=`primary`로 고정.
20
+
21
+ ### Fallback
22
+ shape 애매하면 `multi`, radius 애매하면 `rounded`. maxRows 애매하면 `8`.
23
+
24
+ ### 관련
25
+ - [[components/file-icon]] / [[components/attachment-thumb]] / [[components/attachment-chip]] / [[components/quotation-bar]] — 조립 요소
26
+ - [[components/message-bubble]] — 짝 컴포넌트 (후속)
27
+ - [[components/context-menu]] — 모델 선택 메뉴를 소비처에서 조립할 때
28
+
29
+ ### Props 시그니처
30
+ ```tsx
31
+ <ChatInput
32
+ shape="multi | single" // default: multi
33
+ radius="square | rounded | circular" // default: rounded
34
+
35
+ value={string}
36
+ onChange={(v) => void}
37
+
38
+ onSend={() => void} // canSend일 때만 호출
39
+ onStop={() => void} // isStreaming일 때 send 자리에 stop
40
+ isStreaming={boolean}
41
+
42
+ attachments={ChatAttachment[]} // image/file 섞어 전달
43
+ onRemoveAttachment={(id) => void}
44
+ onAttach={(files: File[]) => void}
45
+
46
+ quotation={{ text, onRemove? }}
47
+
48
+ models={{ id, label }[]}
49
+ selectedModel={string}
50
+ onSelectModel={(id) => void}
51
+
52
+ placeholder="Ask me anything…"
53
+ disabled={boolean}
54
+ maxRows={number} // multi 전용, default 8
55
+ />
56
+ ```
57
+
58
+ ### ChatAttachment 타입
59
+ ```tsx
60
+ type ChatAttachment =
61
+ | { id, kind: "image", src?, alt?, loading? }
62
+ | { id, kind: "file", filename }
63
+ ```
64
+ - `kind: "image"`에 `src` 없거나 `loading: true`면 AttachmentThumb이 placeholder/pulse 자동.
65
+ - `kind: "file"`은 AttachmentChip이 filename 확장자로 FileIcon을 자동 결정.
66
+
67
+ ### 레이아웃
68
+ - 외곽: hairline border, `var(--bg)`, radius=props
69
+ - focus-within에서 ring
70
+ - 내부 세로 gap: `--space-2`, padding: `--space-3`
71
+ - **MultiLine**: `attachments → quotation → [textarea / footer]` 세로
72
+ - **SingleLine**: `attachments → quotation → [attach · input · model · send]` 가로 한 줄
73
+ - Attach/Model/Send: footer 안에서 좌측(attach) 우측(model+send) 분리
74
+
75
+ ### 상태 매트릭스
76
+ | 상태 | 트리거 | 시각 |
77
+ |---|---|---|
78
+ | Normal | 빈 입력 | placeholder, send=`bg-subtle` |
79
+ | Active | 포커스 | focus-within ring |
80
+ | ActiveSendBtn | `value.trim() || attachments` | send=`primary` |
81
+ | FileUpload | `attachments.length > 0` | attachments 바 노출 |
82
+ | Quotation | `quotation != null` | quotation bar 노출 |
83
+ | Streaming | `isStreaming && onStop` | send 자리에 stop (square icon) |
84
+ | Disabled | `disabled` | opacity 0.5, pointer-events none |
@@ -0,0 +1,46 @@
1
+ # Checkbox
2
+
3
+ ### 원칙
4
+ 폼에서 **다중 선택**을 표시하는 최소 컨트롤. 시각 요소(`.indicator`)와 접근성(실제 `<input type="checkbox">`, visually-hidden)을 분리해 native 시맨틱을 유지한다.
5
+
6
+ 색은 [[tokens/color]]의 `--primary` 기반. 상태(성공/경고/삭제/정보)를 표시할 뜻이 정확하면 `status` prop으로 상태 토큰 스왑.
7
+
8
+ ### Do
9
+ - **다중 선택에만**: "여러 개 켤 수 있음"이 의미의 핵심. 하나만 켜지는 그룹은 [[components/radio]].
10
+ - **라벨과 세트로 렌더**: `<label>` 래퍼가 컨트롤 + 텍스트 hitbox를 확장. children이 없으면 별도 라벨 요소에 `htmlFor` 연결 필수.
11
+ - **indeterminate는 부모 노드에만**: 트리·리스트에서 자식 일부만 체크된 부모에 표시. 자식 자체를 indeterminate로 두지 않는다.
12
+ - **status는 뜻이 명확할 때만**: 예를 들어 "삭제 확인" 체크박스에 `destructive`. 브랜드 톤 대신 primary 그대로 두는 게 대부분 자연스럽다.
13
+
14
+ ### Don't
15
+ - native input을 완전히 없애지 않는다 — visually-hidden으로 감추되 DOM엔 남긴다(폼 제출·스크린리더).
16
+ - 커스텀 SVG를 직접 그려 넣지 않는다. indicator 안 마크는 [[components/icon]]의 `check` / `minus` 사용.
17
+ - Switch 대체로 쓰지 않는다. 체크박스는 &ldquo;선택 여부&rdquo;, Switch는 &ldquo;즉시 적용되는 on/off&rdquo;.
18
+
19
+ ### Fallback
20
+ status 애매하면 없음(=primary).
21
+
22
+ ### 관련
23
+ - [[components/radio]] — 단일 선택 버전. 시각·시맨틱은 형제.
24
+ - [[components/badge]] — status 4종 토큰을 공유.
25
+ - [[tokens/color]] — `--primary` · `--*-fg`
26
+
27
+ ### Props 시그니처
28
+ ```tsx
29
+ <Checkbox
30
+ status="success | warning | destructive | info" // optional
31
+ indeterminate={boolean} // 부모 노드 부분선택 표시
32
+ checked / defaultChecked / onChange / disabled ... // native input props
33
+ >
34
+ {children} // 라벨 (없어도 됨)
35
+ </Checkbox>
36
+ ```
37
+
38
+ ### 상태 매트릭스
39
+ | 상태 | 배경 | 테두리 | 마크 |
40
+ |---|---|---|---|
41
+ | unchecked | `--bg` | `--border-strong` | 없음 |
42
+ | hover | `--bg` | `--fg` | 없음 |
43
+ | checked | `--primary` | `--primary` | `--bg` (check) |
44
+ | indeterminate | `--primary` | `--primary` | `--bg` (minus) |
45
+ | checked + status | 각 상태 토큰 | 각 상태 토큰 | 각 `--*-fg` |
46
+ | disabled | 그대로 | 그대로 | opacity 0.5 |
@@ -0,0 +1,84 @@
1
+ # Chip
2
+
3
+ ### 원칙
4
+ **검색 필터·다중 선택의 "선택된 값" 요약 전용**. 사용자가 X로 제거할 수 있는 값 라벨만 Chip이다. 이메일 To 필드, 다중 태그 입력, 필터 결과 요약 — 전부 "선택을 되돌릴 수 있는 값" 자리. 그 외 모든 라벨(카테고리·상태·메타데이터)은 [[components/badge]]. 판정 기준은 **`onRemove` 유무**: 없으면 Badge다.
5
+
6
+ ### Do
7
+ - **검색 필터·다중 선택의 "선택된 값" 요약에만** 사용. `onRemove` + `removeLabel` 세트가 반드시 있어야 한다.
8
+ - 이메일 To, 멘션, 태그 입력 등 "값을 추가·제거하는 자리"에만.
9
+ - `leftIcon`은 값의 성격 힌트(국기·avatar 미니·색 스와치). 라벨 중복 금지.
10
+ - `size="sm"`은 밀도 높은 리스트(검색 필터 요약), `size="md"`는 폼 안 값(이메일 To).
11
+
12
+ ### Don't
13
+ - **카테고리·태그·메타데이터 라벨에 쓰지 않는다** — 그건 [[components/badge]] (`variant="soft"`). "아티클", "가이드", "new", "beta", "draft" 전부 Badge. 공주 영구 금지 룰.
14
+ - 카드/리스트 메타 라인에 쓰지 않는다 — meta 자리는 Badge 또는 inline muted 텍스트.
15
+ - `onRemove`가 없는 Chip은 만들지 않는다. 제거 불가능하면 그 자체로 Chip이 아니다.
16
+ - 상태 표시에 쓰지 않는다 — [[components/badge]] `variant="soft" status="..."`.
17
+ - 클릭 가능한 액션 버튼으로 쓰지 않는다 — [[components/button]] 또는 [[components/filter-button]].
18
+ - removeLabel을 생략하지 않는다 — 접근성 필수.
19
+ - `disabled` 상태에서 onRemove가 호출되지 않게 — 컴포넌트가 자동 처리하지만 상위에서 비즈니스 로직을 거르지 말 것.
20
+
21
+ ### Fallback
22
+ size 애매하면 `md`, variant 애매하면 `soft`.
23
+
24
+ ### 관련
25
+ - [[components/badge]] — 상태 표시(제거 불가). Chip과 짝 개념
26
+ - [[components/filter-button]] — 필터 선택 트리거. 선택 결과는 Chip으로 요약
27
+ - [[components/input]] — 이메일 To 등 입력 안 Chip 리스트
28
+ - [[components/icon]] — leftIcon·remove 아이콘
29
+ - [[axes/shape]] — radius가 Shape 축에 반응
30
+
31
+ ### Props 시그니처
32
+ ```tsx
33
+ <Chip
34
+ size="sm | md" // default: md
35
+ variant="soft | outline" // default: soft
36
+ leftIcon={ReactNode}
37
+ onRemove={(e) => void} // 있으면 X 버튼 노출
38
+ removeLabel="제거" // onRemove와 세트, aria-label
39
+ disabled={boolean}
40
+ >
41
+ 라벨 텍스트
42
+ </Chip>
43
+ ```
44
+
45
+ ### Variant 매트릭스
46
+ | variant | 시각 | 쓰임 |
47
+ |---|---|---|
48
+ | `soft` | primary 8% 배경 + primary 텍스트 | **기본** — 선택된 값 강조 |
49
+ | `outline` | 투명 배경 + border | 보수적 톤, 다중 Chip이 나열될 때 |
50
+
51
+ ### 상태 매트릭스
52
+ | 상태 | 시각 |
53
+ |---|---|
54
+ | default | variant 기본 |
55
+ | hover (remove 버튼) | X 배경 `--hover` |
56
+ | disabled | opacity 0.5, cursor not-allowed, X 비활성 |
57
+
58
+ ### 조합 예시
59
+ ```tsx
60
+ // 이메일 To 필드 — 입력 가능한 Chip 리스트
61
+ <div className="to-field">
62
+ {recipients.map((r) => (
63
+ <Chip key={r.id} leftIcon={<Avatar size="xs" name={r.name} />} onRemove={() => remove(r.id)}>
64
+ {r.email}
65
+ </Chip>
66
+ ))}
67
+ <input type="email" placeholder="주소 추가" />
68
+ </div>
69
+
70
+ // 필터 요약 — sm, outline
71
+ <div className="filters">
72
+ {activeFilters.map((f) => (
73
+ <Chip
74
+ key={f.id}
75
+ size="sm"
76
+ variant="outline"
77
+ leftIcon={f.swatch}
78
+ onRemove={() => clearFilter(f.id)}
79
+ >
80
+ {f.label}
81
+ </Chip>
82
+ ))}
83
+ </div>
84
+ ```