@conscience-technology/ctds 0.0.0-stage → 0.1.0

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 +241 -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,105 @@
1
+ # Textarea
2
+
3
+ ### 원칙
4
+ 다중 행 텍스트 입력. [[components/input]]과 **시각·width·label 규약 100% 공유** — 다른 점은 **높이 조절**뿐. `autoResize`로 내용에 맞춰 자동 성장(기본), 수동 모드엔 **커스텀 리사이즈 핸들**(브라우저 기본 그립 대신 bottom-center 캡슐). minRows / maxRows로 성장 한계 지정. `showCount`로 maxLength 카운터 노출.
5
+
6
+ ### Do
7
+ - 짧은 입력(한 줄)엔 [[components/input]], **긴 서술·메모·설명문**엔 Textarea.
8
+ - `autoResize=true`(기본): 내용 따라감. `maxRows`에 닿으면 세로 스크롤.
9
+ - 수동 리사이즈가 유용한 자리(에디터·댓글): `autoResize={false}` + `minRows`.
10
+ - maxLength가 있으면 `showCount`로 카운터 노출. 넘기면 `.countOver`로 destructive 톤.
11
+ - Input 옆 나란히 놓을 땐 size·variant 통일.
12
+
13
+ ### Don't
14
+ - 한 줄 입력에 쓰지 않는다 — [[components/input]].
15
+ - 브라우저 기본 `resize` 쓰지 않는다 (컴포넌트가 none으로 강제). 커스텀 핸들만.
16
+ - 높이를 CSS로 override 금지. autoResize 쓰거나 minRows/maxRows로.
17
+ - line-height 변경 금지. autoResize 계산이 깨짐.
18
+ - `showCount` 없이 maxLength만 걸고 끝내지 않는다 — 사용자가 왜 끊기는지 모름.
19
+
20
+ ### Fallback
21
+ size 애매하면 `md`, variant 애매하면 `outline`, autoResize 애매하면 `true`, rows 애매하면 `3`.
22
+
23
+ ### 관련
24
+ - [[components/input]] — 한 줄 입력, 모든 시각·width·label 규약 공유
25
+ - [[components/form-field]] — label·description·warning 자리
26
+ - [[axes/density]] — padding·font-size가 Density에 반응
27
+ - [[axes/shape]] — radius가 Shape 축에 반응
28
+
29
+ ### Props 시그니처
30
+ ```tsx
31
+ <Textarea
32
+ size="sm | md | lg" // default: md
33
+ variant="outline | filled | line" // default: outline
34
+ width="fill | md | lg | number" // default: "fill"
35
+ invalid={boolean} // warning 있으면 자동 true
36
+ label={ReactNode}
37
+ description={ReactNode}
38
+ warning={ReactNode}
39
+ autoResize={boolean} // default: true
40
+ minRows={number} // autoResize 하한. 기본 rows=3
41
+ maxRows={number} // autoResize 상한. 넘으면 스크롤
42
+ showCount={boolean} // default: false
43
+ rows={number} // default: 3
44
+ value={string} defaultValue={string}
45
+ onChange={(e) => void}
46
+ maxLength={number}
47
+ disabled={boolean}
48
+ readOnly={boolean}
49
+ required={boolean}
50
+ placeholder={string}
51
+ id={string}
52
+ />
53
+ ```
54
+
55
+ ### Variant · Size 매트릭스
56
+ Input과 동일. 자세히는 [[components/input]] 참고.
57
+
58
+ ### Mode 매트릭스
59
+ | 모드 | 조건 | 동작 |
60
+ |---|---|---|
61
+ | autoResize (기본) | `autoResize=true` | 내용 따라 성장, maxRows 도달 시 세로 스크롤, 커스텀 핸들 숨김 |
62
+ | manual | `autoResize=false` | minRows 높이 고정, 커스텀 핸들(bottom-center)로 드래그 리사이즈 |
63
+
64
+ ### 상태 매트릭스
65
+ | 상태 | 시각 |
66
+ |---|---|
67
+ | default | Input default |
68
+ | hover | border-strong |
69
+ | focus-visible | ring |
70
+ | disabled | opacity 0.5, cursor not-allowed |
71
+ | readOnly | bg-subtle 유지, cursor default |
72
+ | invalid / warning | border destructive, warning 메시지 노출 |
73
+ | count over (showCount + maxLength) | 카운터 destructive 톤 |
74
+
75
+ ### 조합 예시
76
+ ```tsx
77
+ // 기본 — autoResize + 카운터
78
+ <Textarea
79
+ label="메모"
80
+ description="최대 500자"
81
+ value={memo}
82
+ onChange={(e) => setMemo(e.target.value)}
83
+ maxLength={500}
84
+ showCount
85
+ />
86
+
87
+ // 매뉴얼 리사이즈 — 에디터 자리
88
+ <Textarea
89
+ label="본문"
90
+ autoResize={false}
91
+ minRows={10}
92
+ variant="filled"
93
+ />
94
+
95
+ // 경고 상태
96
+ <Textarea
97
+ label="피드백"
98
+ value={feedback}
99
+ onChange={(e) => setFeedback(e.target.value)}
100
+ warning={feedback.length < 10 ? "최소 10자 이상 입력하세요" : undefined}
101
+ />
102
+
103
+ // Line variant — 미니멀 폼
104
+ <Textarea variant="line" size="lg" label="소개" />
105
+ ```
@@ -0,0 +1,149 @@
1
+ # Toast
2
+
3
+ ### 원칙
4
+ 휘발성 피드백 — 사용자 액션의 결과를 짧게 알리고 자동으로 사라진다. 흐름을 끊지 않는다. [[components/callout]]은 상주 안내, [[components/banner]]는 페이지 폭 경고, Toast는 **일회성 결과 신호**.
5
+
6
+ ### Do
7
+ - `tone`은 **아이콘 색**에만 적용. 표면 색은 `surface`(`inverse` 기본 / `default`)가 담당.
8
+ - 비파괴 결과(저장·복사됨)엔 `tone="neutral"`, 성공 상태 전환엔 `success`, 설정 누락·용량 임박엔 `warning`, 삭제·실패엔 `destructive`.
9
+ - `tone` 미지정 시 아이콘 자동 매칭 — `neutral`→`info`, `success`→`check-circle`, `warning`→`warning-circle`, `destructive`→`warning`. 다른 의미 아이콘 필요할 때만 `icon` override. 아이콘 없는 Toast는 허용하지 않는다.
10
+ - `action` 1개 + 자동 close `×` 1개까지. `action` Button은 size `xs`·variant `ghost` 또는 `outline`만 — Toast 표면이 inverse일 때 solid 버튼은 신호 역전.
11
+ - 스택 최대 3개. 4번째가 들어오면 가장 오래된 1개를 자동 제거.
12
+ - `placement`는 `bottom-right`(데스크톱 생산성 도구) 또는 `top-center`(모바일·간결 앱) 둘 중 하나. 혼용 금지.
13
+ - `placement="top-center"`는 **단일 라인 강제** — Viewport가 title 1줄만 보여주고 `description`은 자동 숨김, 긴 title은 ellipsis. 2줄 이상 신호가 필요하면 `bottom-right` 또는 [[components/callout]].
14
+ - `duration` 기본 4000ms. 중요도 높으면 `6000`, action 포함 시 `6000` 권장. `destructive` + 사용자 결정 필요엔 `Infinity`(수동 close 전엔 유지).
15
+ - `role` 자동 — tone이 `destructive`면 `alert`(즉시 읽힘), 그 외엔 `status`(polite).
16
+ - Provider는 앱 루트 1곳에 `<ToastProvider>` + `<ToastViewport>` 배치. Viewport가 placement를 결정.
17
+
18
+ ### Don't
19
+ - Toast 표면색에 tone별 tint 금지 — 색은 아이콘·action 버튼에만.
20
+ - action Button 2개 이상 두지 않는다 — Toast 폭에서 신호 분산.
21
+ - action variant에 `primary`·`destructive` solid 금지 — inverse 표면에서 색 신호가 깨짐.
22
+ - 긴 본문(2줄 초과) 금지 — Toast는 1~2줄까지. 그 이상이면 [[components/callout]] 또는 [[components/banner]].
23
+ - `placement="top-center"`에 `description` 전달 금지 — Viewport가 숨긴다. multiline 신호 필요하면 placement부터 `bottom-right`로.
24
+ - 비동기 로딩 상태(spinner Toast)로 쓰지 않는다 — Toast는 완료 신호 전용.
25
+ - 플로팅이지만 `data-side` 기반 `.m-float` 유틸은 쓰지 않는다 — Toast는 placement별 slide-in 전용 애니.
26
+ - 영구 안내·설명·FAQ 유도에 쓰지 않는다 — [[components/callout]] 영역.
27
+
28
+ ### Fallback
29
+ `tone` 애매하면 `neutral`. `surface` 애매하면 `inverse`. `placement` 애매하면 `bottom-right`. `duration` 애매하면 `4000`.
30
+
31
+ ### 관련
32
+ - [[components/callout]] — 상주 안내 카드. Toast는 휘발.
33
+ - [[components/banner]] — 페이지 폭 전역 경고. Toast는 코너 소형.
34
+ - [[components/button]] — `action` 슬롯의 요소.
35
+ - [[axes/motion]] — placement별 slide-in·fade-out 파라미터 스왑.
36
+ - [[tokens/z-index]] — `z-toast` 레이어 (Modal 위, Tooltip 아래).
37
+
38
+ ### Props 시그니처
39
+ ```tsx
40
+ // Provider — 앱 루트 1곳
41
+ <ToastProvider duration={4000}>
42
+ {children}
43
+ <ToastViewport placement="bottom-right | top-center" /> // default: bottom-right
44
+ </ToastProvider>
45
+
46
+ // Toast — ToastProvider 자손에서 open 상태로 렌더
47
+ <Toast
48
+ open={boolean}
49
+ onOpenChange={(open: boolean) => void}
50
+ title={ReactNode} // required
51
+ description={ReactNode}
52
+ tone="neutral | success | warning | destructive" // default: neutral
53
+ surface="inverse | default" // default: inverse
54
+ icon={IconName} // tone별 자동 매칭 override
55
+ action={ReactNode} // Button size="xs" variant="ghost|outline"만
56
+ actionAltText={string} // required if action — 스크린리더 설명
57
+ dismissible={boolean} // default: true
58
+ dismissLabel={string}
59
+ duration={number | "Infinity"} // default: 4000
60
+ />
61
+
62
+ // Hook — 명령형 호출 (권장)
63
+ const { toast } = useToast();
64
+ toast({ title: "저장됨", tone: "success", duration: 3000 });
65
+ ```
66
+
67
+ ### Variant 매트릭스
68
+ Toast는 **5개 축의 독립 조합**이다. 축별로 결정 → 조합의 완성도는 아래 금지 조합만 피하면 보증.
69
+
70
+ **1. `placement` (Viewport 레벨, 앱당 1곳 지정)**
71
+
72
+ | 값 | 레이아웃 | description | 용도 |
73
+ |---|---|---|---|
74
+ | `bottom-right` (기본) | 우하단 → 위로 스택 | **허용** (2줄까지) | 데스크톱 생산성 도구 |
75
+ | `top-center` | 상단 중앙 → 아래로 스택 | **자동 숨김** (단일 라인 강제, title ellipsis) | 모바일·간결 앱 |
76
+
77
+ **2. `surface` (Toast별)**
78
+
79
+ | 값 | 표면 | 텍스트 | 용도 |
80
+ |---|---|---|---|
81
+ | `inverse` (기본) | `--fg`(라이트에선 검정) | `--bg`(라이트에선 흰색) | 주변 UI와 명확 분리. 생산성 도구 |
82
+ | `default` | `--bg` + `--shadow-lg` | `--fg` | Callout·Tooltip과 같은 톤. 가벼운 느낌 |
83
+
84
+ **3. `tone` (아이콘·action 색만 스왑. 표면 색은 영향 없음)**
85
+
86
+ | 값 | 아이콘 색 | 자동 아이콘 | 용도 |
87
+ |---|---|---|---|
88
+ | `neutral` (기본) | 중립(bg/fg-muted) | 없음 | 저장됨·복사됨 등 일반 완료 |
89
+ | `success` | `--success` | `check-circle` | 성공 전환(업로드 완료·결제 완료) |
90
+ | `warning` | `--warning` | `warning-circle` | 설정 누락·용량 임박 |
91
+ | `destructive` | `--destructive` | `warning` | 삭제·실패·롤백. `role="alert"` 자동 승격 |
92
+
93
+ **4. `dismissible` (우측 X 버튼)**
94
+
95
+ | 값 | 결과 | 용도 |
96
+ |---|---|---|
97
+ | `true` (기본) | 우측에 X IconButton | 대부분의 경우. `duration=Infinity`일 땐 **필수** |
98
+ | `false` | X 숨김 | duration 짧고(≤4000) action도 없는 순수 알림 전용 |
99
+
100
+ **5. `action` (Button 1개 slot)**
101
+
102
+ | action variant | 허용 조건 |
103
+ |---|---|
104
+ | `ghost` | 모든 tone·surface |
105
+ | `outline` | 모든 tone·surface |
106
+ | `primary`/`solid` | **금지** (아래 참조) |
107
+
108
+ **금지 조합**
109
+ - `surface=inverse` + action `primary`/`solid` — 반전 표면에서 solid는 색 신호 깨짐. `ghost`/`outline`만.
110
+ - `tone=destructive` + action `primary`(brand) — 파괴 맥락에 brand 색 신호 금지.
111
+ - `tone=success` + action `destructive` — 긍정 맥락에 비가역 액션 혼재 금지.
112
+ - `placement=top-center` + `description` 전달 — Viewport가 숨긴다. 2줄 신호 필요하면 bottom-right.
113
+ - `duration=Infinity` + `dismissible=false` — 사용자가 영원히 닫을 수 없음.
114
+ - action 2개 이상 — slot 1개로 제한.
115
+
116
+ ### 애니메이션
117
+ `.m-float` 쓰지 않는다 (data-side 기반이라 placement 스택 구조에 안 맞음). Toast 전용 keyframe을 컴포넌트 CSS에 두되, duration·easing은 **반드시 `--duration-*`/`--ease-*` 토큰 경유**.
118
+
119
+ 톤은 Sonner/Linear 계열 — **짧은 거리 slide + fade + 미세 scale**. 뷰포트 밖 전체 폭에서 밀고 들어오는 긴 slide는 쓰지 않는다 ("확 끼어드는" 인상). open은 공간에 '놓이는' 느낌, close는 '사라지는' 느낌.
120
+
121
+ - `placement=bottom-right` — open: `translateX(space-4)` + `scale(0.96)` + opacity 0 → 1. `--duration-slow` + `--ease-emphasized`.
122
+ - `placement=top-center` — open: `translateY(-space-4)` + `scale(0.96)` + opacity 0 → 1. 같은 토큰.
123
+ - close(dismiss) — placement 공통으로 `scale(1 → 0.96)` + opacity 1 → 0만. slide 없음. `--duration-base` + `--ease-in`.
124
+ - swipe dismiss는 `--radix-toast-swipe-move-x` 추적 → end 시 손가락이 민 방향으로 짧게 밀어내며 fade.
125
+ - `prefers-reduced-motion: reduce` — 모든 Toast 애니 즉시 완료.
126
+
127
+ ### 조합 예시
128
+ ```tsx
129
+ // 앱 루트
130
+ <ToastProvider>
131
+ <App />
132
+ <ToastViewport placement="bottom-right" />
133
+ </ToastProvider>
134
+
135
+ // 호출부
136
+ const { toast } = useToast();
137
+
138
+ toast({
139
+ title: "변경사항이 저장되었습니다",
140
+ tone: "success",
141
+ action: (
142
+ <Button size="xs" variant="outline" onClick={undo}>
143
+ 실행 취소
144
+ </Button>
145
+ ),
146
+ actionAltText: "방금 저장을 되돌리기",
147
+ duration: 6000,
148
+ });
149
+ ```
@@ -0,0 +1,71 @@
1
+ # Tooltip
2
+
3
+ ### 원칙
4
+ hover·focus 시 뜨는 **짧은 보조 설명**. Radix Tooltip 위에 얹은 compound. 라벨이 없는 [[components/icon-button]]의 의미 설명, 축약된 단어의 보충, 단축키 힌트에 사용. **클릭 액션은 담지 않는다** — 그건 [[components/popover]].
5
+
6
+ ### Do
7
+ - 라벨이 없는 아이콘 버튼엔 반드시 Tooltip + `aria-label` 둘 다.
8
+ - 내용은 **한 줄** 또는 **최대 두 줄** — Tooltip은 설명이 아니라 힌트.
9
+ - 단축키는 [[components/shortcut]]과 조합: `content={<>붙여넣기 <Shortcut>⌘V</Shortcut></>}`.
10
+ - `side`로 방향 지정 — 공간이 좁은 쪽은 자동 flip.
11
+ - `followMouse`는 긴 호버 요소(차트·툴바)에서만.
12
+
13
+ ### Don't
14
+ - 모바일/터치에선 Tooltip 금지 — hover가 없음. 중요한 정보는 Label·description으로.
15
+ - 액션 버튼이 담긴 Tooltip 금지 — [[components/popover]]로.
16
+ - content에 긴 문단 금지. 설명이 길면 Dialog 또는 Popover.
17
+ - hover 시 사라지는 중요 정보 금지 — WCAG 2.5.3 (호버 지속성) 위반.
18
+ - 커스텀 애니메이션 금지. `.m-float` 유틸이 전담.
19
+
20
+ ### Fallback
21
+ side 애매하면 `top`, align 애매하면 `center`, delayDuration 애매하면 Radix 기본(~700ms).
22
+
23
+ ### 관련
24
+ - [[components/icon-button]] — 가장 흔한 트리거 (aria-label 보충)
25
+ - [[components/shortcut]] — content 안쪽 단축키 힌트
26
+ - [[components/popover]] — 액션·입력이 담긴 자리 (Tooltip 대신)
27
+ - [[axes/motion]] — Content in/out은 `.m-float` 유틸
28
+
29
+ ### Props 시그니처
30
+ ```tsx
31
+ <Tooltip
32
+ content={ReactNode} // 한 줄 또는 Shortcut 조합
33
+ side="top | right | bottom | left" // default: top (자동 flip)
34
+ align="start | center | end" // default: center
35
+ sideOffset={number} // default: 6
36
+ arrowOffset={number} // 꼭지 중심 오프셋 (followMouse=true 시 무시)
37
+ followMouse={boolean} // 트리거 위 커서 추적
38
+ arrow={boolean} // default: true
39
+ delayDuration={number} // ms, default: Radix 기본
40
+ open={boolean}
41
+ onOpenChange={(open: boolean) => void}
42
+ >
43
+ {trigger} // 자동으로 asChild 처리
44
+ </Tooltip>
45
+ ```
46
+
47
+ ### Size · 색
48
+ Tooltip은 size prop 없음 — 콘텐츠에 맞춰 자동 폭 (최소 240px). 색은 Mode 반전 (라이트에선 다크 Tooltip, 다크에선 라이트) — `--tooltip-bg`·`--tooltip-fg` 토큰이 자동.
49
+
50
+ ### 조합 예시
51
+ ```tsx
52
+ // 아이콘 버튼 라벨 — 가장 흔한 자리
53
+ <Tooltip content="복사">
54
+ <IconButton icon={<Icon name="copy" />} aria-label="복사" />
55
+ </Tooltip>
56
+
57
+ // 단축키 힌트 — Shortcut 조합
58
+ <Tooltip content={<>붙여넣기 <Shortcut>⌘V</Shortcut></>}>
59
+ <IconButton icon={<Icon name="clipboard" />} aria-label="붙여넣기" />
60
+ </Tooltip>
61
+
62
+ // followMouse — 긴 요소 (툴바 레이블)
63
+ <Tooltip content="Timeline에서 이 시점을 선택" side="bottom" followMouse>
64
+ <div className="timeline-track">...</div>
65
+ </Tooltip>
66
+
67
+ // 축약어 보충
68
+ <Tooltip content="Operational Expenditure (운영비)" side="top">
69
+ <span className="metric-label">OPEX</span>
70
+ </Tooltip>
71
+ ```
@@ -0,0 +1,148 @@
1
+ # Topbar
2
+
3
+ ### 원칙
4
+ 앱 shell 최상단의 가로 bar — Breadcrumb·탐색·검색·알림·사용자 메뉴처럼 **"지금 어느 자리인지 + 공용 액션"**만 담는 chrome. 콘텐츠 자체(hero head, 큰 환영 메시지, 섹션 제목)는 Topbar의 자리가 아니라 **아래 body의 첫 블록 자리**다. Topbar는 세로 높이가 고정된 **얇은 축**이므로, 수직 리듬이 큰 요소를 끼우면 align이 깨지고 bar 자체가 "들뜬다".
5
+
6
+ ### Do
7
+ - Breadcrumb·검색 Input·알림 IconButton·avatar menu·탐색 Tabs처럼 **반복적으로 쓰이는 공용 액션만** 담는다.
8
+ - 세로는 `size` prop(`sm`/`md`)이 결정하는 한 줄만. 수직으로 쌓지 않는다.
9
+ - 좌/우 정렬은 `Topbar.Spacer`로. 가운데 그룹이 필요하면 중앙에 또 하나의 Spacer를 끼운다.
10
+ - 자체 chrome(bg/border/shadow)은 두지 않는다 — 표현은 상위 [[components/app-frame]] variant가 담당.
11
+ - 페이지의 "지금 어디" 신호는 **Breadcrumb**로. 큰 타이틀로 쓰고 싶으면 Topbar가 아니라 body 첫 블록.
12
+
13
+ ### Don't
14
+ - `h1`·큰 hero head·환영 메시지("good morning, …")·페이지 섹션 타이틀을 Topbar 안에 넣지 않는다 — Topbar는 **얇은 축**이고 큰 타이포가 들어가는 순간 `align-items` 전쟁이 벌어진다. 이걸 로컬 CSS로 때우는 순간(`align-items: flex-start`, `padding-bottom` override 등) Topbar의 "축" 약속이 깨지고, 아래 body와의 수직 리듬도 어긋난다. hero는 body의 첫 섹션으로 꺼낸다.
15
+ - 수직 스택(eyebrow + title 세로 두 줄 같은 조합)을 Topbar 안에 넣지 않는다. 수직 리듬은 body의 섹션 head에서.
16
+ - 알림·검색·Breadcrumb 외의 **콘텐츠**(KPI·요약·공지 문구)를 Topbar에 끼우지 않는다. 그건 body hero 섹션 또는 Callout의 자리.
17
+ - Topbar에 로컬 `padding`·`align-items`를 override해서 "큰 요소 끼운 걸 수습"하지 않는다 — 수습이 필요한 순간 그 요소가 Topbar의 자리가 아니라는 신호.
18
+ - 자체 bg/border/shadow 추가 금지 — AppFrame variant가 쥐고 있는 자리.
19
+ - 여러 줄 쌓거나 `size` 바깥의 세로 공간을 늘리지 않는다 — "얇은 축"이 Topbar의 약속.
20
+
21
+ ### Fallback
22
+ `size` 애매하면 `md`. 콘텐츠 밀도가 아주 낮은 랜딩/문서 shell이면 `sm`.
23
+ Breadcrumb 자리·공용 액션 자리 둘 다 비면 Topbar를 두지 않는다 — 빈 bar는 수직 공간만 먹는다.
24
+
25
+ ### 관련
26
+ - [[components/app-frame]] — Topbar를 품는 shell. bg/border/shadow 등 chrome 표현은 AppFrame variant가 쥔다.
27
+ - [[components/breadcrumb]] — Topbar 왼쪽의 "지금 어디" 신호. 큰 타이틀 대신 이걸로.
28
+ - [[components/sidebar]] — 가로축이 Topbar, 세로축이 Sidebar. 둘의 top baseline은 AppFrame이 맞춘다.
29
+ - [[components/callout]] — "지금 공지해야 할 큰 콘텐츠"가 생기면 Topbar가 아니라 body 첫 블록의 Callout.
30
+ - [[axes/density]] — size와 함께 세로 높이 리듬을 결정.
31
+ - [[tokens/spacing]] — 좌우 padding은 shell 토큰에 양보. Topbar가 자체로 쥐지 않는다.
32
+
33
+ ### Props 시그니처
34
+ ```tsx
35
+ <Topbar size="sm | md">
36
+ { /* 자유 슬롯: Breadcrumb, Input, IconButton, Topbar.Spacer, Avatar menu 등 */ }
37
+ </Topbar>
38
+
39
+ <Topbar.Spacer /> {/* 좌/우 정렬용 flex:1 빈 블록 */}
40
+ ```
41
+
42
+ ### Size 매트릭스
43
+
44
+ | size | 세로 높이 | 용도 |
45
+ |---|---|---|
46
+ | `sm` | 얇음 | 문서·랜딩·설정 shell. 액션 수 적을 때 |
47
+ | `md` | 기본 | 앱 콘솔. Breadcrumb + 공용 액션 2~3개 |
48
+
49
+ ### 금지 조합
50
+ - Topbar 안에 `h1`·`h2`·hero head 삽입 — "얇은 축" 약속 깨짐. body hero 섹션으로 꺼낸다.
51
+ - Topbar 안에 수직 스택(eyebrow + title 2줄) — 단일 줄 원칙 깨짐.
52
+ - 로컬 CSS로 `align-items: flex-start` + `padding-bottom` 늘려서 큰 타이포 수용 — 수습이 필요한 순간 그 요소가 자리가 아니라는 신호.
53
+ - 자체 bg/border/shadow 리터럴 추가 — AppFrame variant 영역 침범.
54
+ - Breadcrumb·공용 액션 없이 **콘텐츠 요약**만 넣기 — Callout·hero 섹션의 자리.
55
+ - MetricCard·Chip·Badge를 콘텐츠 신호로 Topbar에 끼우기 — body 섹션 안이 자리.
56
+
57
+ ### 조합 예시
58
+
59
+ Topbar는 **자유 슬롯 컨테이너**다. "page / detail / panel" 같은 variant를 따로 두지 않고, **같은 Topbar에 다른 children**을 넣어 역할을 바꾼다. 뒤로가기·close도 전용 컴포넌트가 아니라 `IconButton` + `Icon`을 slot에 꽂는 조립.
60
+
61
+ ```tsx
62
+ // 1) page — 운영 콘솔. Breadcrumb + 검색 + 알림
63
+ <Topbar size="md">
64
+ <Breadcrumb>
65
+ <Breadcrumb.Item href="/today">today</Breadcrumb.Item>
66
+ <Breadcrumb.Current>meetings</Breadcrumb.Current>
67
+ </Breadcrumb>
68
+ <Topbar.Spacer />
69
+ <Input
70
+ size="md"
71
+ variant="filled"
72
+ placeholder="search anything"
73
+ leftIcon={<Icon name="search" />}
74
+ rightAction={<Shortcut size="sm">⌘K</Shortcut>}
75
+ />
76
+ <IconButton icon={<Icon name="bell" />} size="md" variant="ghost" />
77
+ </Topbar>
78
+
79
+ // 2) detail — 뒤로가기 + Breadcrumb로 현재 위치 + overflow 액션
80
+ <Topbar size="md">
81
+ <IconButton
82
+ icon={<Icon name="caret-left" />}
83
+ size="md"
84
+ variant="ghost"
85
+ aria-label="back"
86
+ />
87
+ <Breadcrumb>
88
+ <Breadcrumb.Item href="/meetings">meetings</Breadcrumb.Item>
89
+ <Breadcrumb.Current>oct 5 standup</Breadcrumb.Current>
90
+ </Breadcrumb>
91
+ <Topbar.Spacer />
92
+ <IconButton
93
+ icon={<Icon name="dots-three" />}
94
+ size="md"
95
+ variant="ghost"
96
+ aria-label="more"
97
+ />
98
+ </Topbar>
99
+
100
+ // 3) panel — 사이드패널/드로어 내부. 더 얇게 + close
101
+ <Topbar size="sm">
102
+ <Breadcrumb>
103
+ <Breadcrumb.Current>filters</Breadcrumb.Current>
104
+ </Breadcrumb>
105
+ <Topbar.Spacer />
106
+ <IconButton
107
+ icon={<Icon name="x" />}
108
+ size="sm"
109
+ variant="ghost"
110
+ aria-label="close"
111
+ />
112
+ </Topbar>
113
+
114
+ // hero head는 Topbar가 아니라 body의 첫 블록
115
+ <main>
116
+ <Topbar size="md">{/* page topbar */}</Topbar>
117
+
118
+ <section className={hero}>
119
+ <span className={eyebrow}>thursday · october 2</span>
120
+ <h1 className={head}>good morning, 희영</h1>
121
+ </section>
122
+
123
+ { /* 이하 KPI, 섹션들 … */ }
124
+ </main>
125
+ ```
126
+
127
+ ### 역할별 slot 공식
128
+
129
+ | 역할 | leading slot | 가운데 | trailing slot | size |
130
+ |---|---|---|---|---|
131
+ | page | Breadcrumb | — | 검색 Input, 알림/avatar IconButton | `md` |
132
+ | detail | `IconButton icon="caret-left" variant="ghost"` + Breadcrumb | — | overflow/share 등 IconButton | `md` |
133
+ | panel (사이드패널·drawer) | Breadcrumb(단일 Current) | — | `IconButton icon="x" variant="ghost"` | `sm` |
134
+
135
+ - 뒤로가기는 **전용 컴포넌트가 아니라** `IconButton` + `Icon name="caret-left"`. `variant="ghost"` 고정, `aria-label="back"` 필수.
136
+ - 패널 close도 동일하게 `IconButton` + `Icon name="x"`, `aria-label="close"`.
137
+ - "지금 어디"는 어떤 역할이든 **항상 Breadcrumb**로. detail/panel이라고 `h1`·굵은 타이틀로 바꾸지 않는다 — "얇은 축" 약속은 역할과 무관하게 유지.
138
+ - panel은 콘텐츠 밀도가 낮으니 `size="sm"`이 기본. 더 얇아야 할 이유가 명확할 때만.
139
+ - bg/border/shadow는 **역할별로도 Topbar가 쥐지 않는다** — detail은 상위 AppFrame, panel은 Drawer/SidePanel shell이 쥔다.
140
+
141
+ ### 조립 — 상위 shell과의 공식
142
+ - 좌/우 padding은 **AppFrame variant 또는 콘텐츠 panel**이 쥔다. Topbar가 자체 padding으로 수평 정렬을 책임지지 않는다. 수평 baseline은 body와 반드시 동일해야 하며, Topbar가 혼자 다르게 쥐면 body와 어긋난다.
143
+ - 세로 top padding은 shell(또는 콘텐츠 panel)의 top padding과 동일하게. Sidebar의 top padding도 **같은 수치**로 맞춰야 좌·우 상단이 한 줄에 선다.
144
+ - Topbar와 아래 body 첫 섹션 사이 간격은 **Topbar의 bottom padding**이 아니라 **body의 top padding 또는 body gap**이 담당. Topbar는 "얇은 축"으로 끝나야 수직 리듬이 섹션 쪽으로 넘어간다.
145
+
146
+ ### Known Gaps
147
+ - Topbar는 반응형 breakpoints에서 "검색 Input → 아이콘으로 축약" 같은 전환을 자체적으로 하지 않는다. 상위 레이아웃이 반응형으로 children을 바꿔 넘긴다.
148
+ - Topbar 안 Breadcrumb의 **잘림/트렁케이션** 규칙은 [[components/breadcrumb]]이 담는다. Topbar는 "자리"만 제공.
@@ -0,0 +1,43 @@
1
+ # emerge
2
+
3
+ ### 원칙
4
+ 앵커(트리거)에서 자라나는 등장. slide + scale + fade가 하나로 묶인 프리미티브.
5
+ Radix의 `data-side` 자동 스왑과 결합해 방향이 자동 결정.
6
+
7
+ ### Do
8
+ - 앵커 기반 오버레이(Tooltip·Popover·DropdownMenu·ContextMenu·HoverCard) 등장에 사용.
9
+ - `transform-origin`은 Radix의 `--radix-{component}-content-transform-origin` 사용.
10
+ - 방향 클래스는 아래 [방향 매핑](#방향-매핑) 표를 따른다 (Radix `data-side` 자동 반영).
11
+
12
+ ### Don't
13
+ - 뷰포트 가장자리에서 오는 Drawer·Sheet·Toast에는 emerge 쓰지 않는다 (`slide-*` 사용).
14
+ - `transform-origin`을 직접 계산해 넣지 않는다. 반드시 Radix의 `--radix-{component}-content-transform-origin`을 참조 (앵커 위치 자동 반영).
15
+
16
+ ### Fallback
17
+ 앵커 기반 오버레이는 무조건 emerge. 방향은 Radix가 계산한 `data-side` 신뢰.
18
+
19
+ ### 관련
20
+ - [[axes/motion]] — duration·거리·scale amount를 스왑
21
+ - [[primitives/slide]] · [[primitives/scale]] — emerge의 구성 요소
22
+
23
+ ### 축별 스왑
24
+ | data-motion | 파라미터 |
25
+ |---|---|
26
+ | `bouncy` | duration 400ms · distance 1.3× · scale 0.94→1 |
27
+ | `standard` | duration 200ms · distance 1× · scale 0.96→1 |
28
+ | `calm` | duration 100ms · distance 0.7× · scale 0.98→1 |
29
+ | `none` | 즉시 (변화 없음) |
30
+
31
+ ### 겹침 규칙
32
+ - 자기 자신이 이미 slide + scale + fade 조합이라 다른 프리미티브와 겹치지 않는다.
33
+ - 다른 프리미티브(예: shake, pulse)는 emerge 등장 후 별개 이벤트로 실행 가능.
34
+
35
+ ### 방향 매핑
36
+ Radix의 `data-side`가 앵커 위치 반대 방향에서 등장하도록 자동 매핑된다.
37
+
38
+ | Radix `data-side` | emerge 방향 클래스 | 의미 |
39
+ |---|---|---|
40
+ | `top` | `m-emerge-from-bottom` | 아래에서 올라옴 |
41
+ | `bottom` | `m-emerge-from-top` | 위에서 내려옴 |
42
+ | `left` | `m-emerge-from-right` | 오른쪽에서 옴 |
43
+ | `right` | `m-emerge-from-left` | 왼쪽에서 옴 |
@@ -0,0 +1,31 @@
1
+ # fade
2
+
3
+ ### 원칙
4
+ opacity만 트랜지션. 위치·크기 변화 없음. 상태 전환의 가장 기본 프리미티브.
5
+
6
+ ### Do
7
+ - 요소의 표시/숨김, 상태 전환에 사용.
8
+ - 다른 프리미티브와 조합해 "fade + scale" 같은 오버레이 등장 표현.
9
+
10
+ ### Don't
11
+ - 공간 이동이 필요한 곳에는 fade만 쓰지 않는다.
12
+ - 반복(무한 loop)에 fade 쓰지 않는다 (`pulse` 사용).
13
+
14
+ ### Fallback
15
+ 가장 안전한 트랜지션. 상태 전환의 기본값.
16
+
17
+ ### 관련
18
+ - [[axes/motion]] — duration을 스왑
19
+ - [[primitives/scale]] · [[primitives/emerge]] — fade와 자주 조합
20
+
21
+ ### 축별 스왑
22
+ | data-motion | 파라미터 |
23
+ |---|---|
24
+ | `bouncy` | duration 400ms |
25
+ | `standard` | duration 200ms |
26
+ | `calm` | duration 100ms |
27
+ | `none` | duration 0ms (즉시) |
28
+
29
+ ### 겹침 규칙
30
+ - `scale`, `slide-*`, `emerge-*`와 조합 허용.
31
+ - 스스로 반복하지 않음 (단발성).
@@ -0,0 +1,32 @@
1
+ # scale
2
+
3
+ ### 원칙
4
+ 크기 변화(0.96 → 1). `transform-origin`을 앵커 쪽으로 두면 앵커에서 자라나는 느낌.
5
+ 강조 등장의 기본. fade와 조합해 사용.
6
+
7
+ ### Do
8
+ - Popover·Modal·Tooltip 등장 시 fade와 조합해 "안착" 느낌.
9
+ - `transform-origin`을 앵커 방향으로 명시. 오버레이는 Radix의 `--radix-*-content-transform-origin` 사용.
10
+
11
+ ### Don't
12
+ - 큰 스케일 변화(0.5 → 1) 금지 — 위압적. 0.9 ~ 1.0 범위 유지.
13
+ - 반복 스케일에 쓰지 않는다 (`pulse` 사용).
14
+ - 좁은 UI 안에서 여러 요소가 동시에 scale 등장하지 않는다.
15
+
16
+ ### Fallback
17
+ Popover/Modal/Tooltip은 이걸 사용. 나머지는 fade가 우선.
18
+
19
+ ### 관련
20
+ - [[axes/motion]] — duration과 scale amount를 스왑
21
+ - [[primitives/emerge]] — scale + slide + fade 조합의 표준 형태
22
+
23
+ ### 축별 스왑
24
+ | data-motion | 파라미터 |
25
+ |---|---|
26
+ | `bouncy` | duration 400ms · scale 0.94 → 1 |
27
+ | `standard` | duration 200ms · scale 0.96 → 1 |
28
+ | `calm` | duration 100ms · scale 0.98 → 1 |
29
+ | `none` | 즉시 scale 1 (변화 없음) |
30
+
31
+ ### 겹침 규칙
32
+ - `fade`와 조합 필수 (opacity 없이 scale만 하면 어색).
@@ -0,0 +1,75 @@
1
+ # scroll
2
+
3
+ ### 원칙
4
+ 스크롤이 있는 곳엔 **두 겹의 패딩 규약**을 지킨다.
5
+
6
+ 1. **바깥 컨테이너(스크롤 발생 요소)** 에는 패딩을 두지 않는다.
7
+ → 패딩이 있으면 스크롤 트랙이 콘텐츠 위로 겹치거나 잘려 보인다.
8
+ 2. **안쪽 트랙(items가 실제로 놓이는 자식)** 에 상하좌우 패딩을 준다.
9
+ → 스크롤 도중 첫/끝 item이 컨테이너 엣지에 딱 붙어 잘린 느낌을 없앤다.
10
+
11
+ 이 규약은 세로·가로·양방향 스크롤 모두에 동일하게 적용된다.
12
+
13
+ ### Do
14
+ - 스크롤 컨테이너에 `overflow: auto`를, 안쪽 children wrapper에 `padding: var(--space-*)`를.
15
+ - 스크롤 방향에 맞춰 최소 `--space-2` 이상의 패딩을 줘서 트랙 끝에서도 콘텐츠가 카드 벽에 붙지 않도록.
16
+ - 리스트/그리드형 스크롤은 items 간 gap과 별개로 **컨테이너-item 사이의 여백**을 반드시 확보.
17
+ - 채팅창처럼 하단이 항상 최신인 경우에도 안쪽 패딩으로 마지막 메시지가 잘리지 않게.
18
+
19
+ ### Don't
20
+ - 스크롤 컨테이너 자체에 `padding`을 걸지 않는다 → thumb이 콘텐츠와 겹쳐 보임.
21
+ - items에 `margin: first-child/last-child` 트릭으로 여백 흉내내지 않는다 → 정렬 깨지고 유지보수 어려움.
22
+ - `overflow: hidden` 위에 scrollTop을 JS로 조작하는 커스텀 스크롤은 접근성 무너짐. 반드시 네이티브 `overflow: auto`.
23
+
24
+ ### Fallback
25
+ 스크롤 필요 없는 경우엔 안쪽 트랙 패딩만으로도 무해. 그러니 규약을 컴포넌트 기본으로 두는 게 안전.
26
+
27
+ ### 관련
28
+ - [[axes/density]] — `--space-*` 스케일 스왑에 자동 반응
29
+ - [[tokens/spacing]] — 안쪽 패딩은 `--space-*` 경유
30
+ - 스크롤바 시각(색·두께·hover 노출)은 globals.css의 전역 정책이 담당. 컴포넌트가 별도로 스크롤바 스타일을 선언하지 않는다.
31
+
32
+ ### 정책 요약
33
+
34
+ | 요소 | overflow | padding |
35
+ |---|---|---|
36
+ | 바깥(스크롤) 컨테이너 | `auto` | 없음 |
37
+ | 안쪽(items) 트랙 | 없음 | `var(--space-2)` 이상 |
38
+
39
+ ### 스크롤바 시각 정책 (전역, globals.css)
40
+
41
+ - 평상시: thumb 투명 → 스크롤바 자리는 있지만 안 보임 (overlay)
42
+ - 부모 `:hover` 또는 `:focus-within`: thumb에 `--border-strong` 페이드 인
43
+ - thumb `:hover`: `--fg-muted`로 진해짐
44
+ - 두께: `--scrollbar-size` 토큰 (Density 축 영향 없음, 고정)
45
+ - macOS 방식(사용 중일 때만 얇게 노출) — Notion/Linear/Figma 스타일
46
+
47
+ ### 스크롤 페이드 (edge fade mask)
48
+
49
+ 스크롤로 잘려나가는 콘텐츠 경계를 부드럽게 처리. 사용자에게 "더 있음"을 암시하면서 카드 벽에 텍스트가 딱 붙는 느낌을 없앤다.
50
+
51
+ - 세로 스크롤 컨테이너: `class="scroll-fade-y"` 부착 (상하단 페이드)
52
+ - 가로 스크롤 컨테이너: `class="scroll-fade-x"` 부착 (좌우 페이드)
53
+ - 크기 토큰: `--scroll-fade-size` (기본 `--space-4`)
54
+ - 구현: `mask-image` linear-gradient. 컨테이너 안 콘텐츠 전체가 마스킹되므로 스크롤 페이드는 **실제 스크롤이 있는 컨테이너에만** 부착. 스크롤 없는 곳에 붙이면 가장자리 요소(아이콘·버튼)가 흐릿하게 잘려 보임.
55
+
56
+ **Do**: 세로 스크롤 리스트, 가로 스크롤 테이블/탭, 채팅 메시지 리스트 등 스크롤이 상수인 자리에 클래스 명시적 부착.
57
+
58
+ **Don't**: 스크롤 유무가 유동적인 컨테이너에 blanket 적용. 콘텐츠가 짧을 때는 마스크만 남고 실제 페이드 효과 없이 가장자리가 흐릿함.
59
+
60
+ ### 예시 (CSS 스케치)
61
+
62
+ ```css
63
+ .list { /* 바깥 스크롤 컨테이너 */
64
+ overflow-y: auto;
65
+ max-height: calc(var(--control-h-md) * 8);
66
+ /* padding 금지 */
67
+ }
68
+
69
+ .listTrack { /* 안쪽 items 래퍼 */
70
+ display: flex;
71
+ flex-direction: column;
72
+ gap: var(--space-0_5);
73
+ padding: var(--space-2);
74
+ }
75
+ ```