@iamfiro/design 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 (264) hide show
  1. package/AGENTS.md +81 -0
  2. package/README.md +15 -2
  3. package/agents/INDEX.md +156 -0
  4. package/agents/accordion/AGENTS.md +279 -0
  5. package/agents/action-bar/AGENTS.md +90 -0
  6. package/agents/alert/AGENTS.md +212 -0
  7. package/agents/alert-dialog/AGENTS.md +193 -0
  8. package/agents/app-shell/AGENTS.md +409 -0
  9. package/agents/area-chart/AGENTS.md +183 -0
  10. package/agents/aspect-ratio/AGENTS.md +143 -0
  11. package/agents/avatar/AGENTS.md +130 -0
  12. package/agents/badge/AGENTS.md +217 -0
  13. package/agents/bar-chart/AGENTS.md +386 -0
  14. package/agents/bar-list/AGENTS.md +223 -0
  15. package/agents/brand-icon/AGENTS.md +82 -0
  16. package/agents/breadcrumb/AGENTS.md +133 -0
  17. package/agents/button/AGENTS.md +195 -0
  18. package/agents/card/AGENTS.md +141 -0
  19. package/agents/card-frame/AGENTS.md +227 -0
  20. package/agents/chat-bubble/AGENTS.md +266 -0
  21. package/agents/chat-composer/AGENTS.md +251 -0
  22. package/agents/checkbox/AGENTS.md +113 -0
  23. package/agents/code-block/AGENTS.md +144 -0
  24. package/agents/color-dot/AGENTS.md +120 -0
  25. package/agents/color-picker/AGENTS.md +224 -0
  26. package/agents/colors/AGENTS.md +168 -0
  27. package/agents/combobox/AGENTS.md +218 -0
  28. package/agents/command-menu/AGENTS.md +169 -0
  29. package/agents/comment/AGENTS.md +206 -0
  30. package/agents/context-menu/AGENTS.md +303 -0
  31. package/agents/copy-button/AGENTS.md +84 -0
  32. package/agents/count-badge/AGENTS.md +115 -0
  33. package/agents/countdown/AGENTS.md +101 -0
  34. package/agents/data-grid/AGENTS.md +460 -0
  35. package/agents/date-picker/AGENTS.md +197 -0
  36. package/agents/delta/AGENTS.md +114 -0
  37. package/agents/description-list/AGENTS.md +251 -0
  38. package/agents/dialog/AGENTS.md +391 -0
  39. package/agents/drawer/AGENTS.md +471 -0
  40. package/agents/dropdown-menu/AGENTS.md +322 -0
  41. package/agents/dropzone/AGENTS.md +116 -0
  42. package/agents/elapsed/AGENTS.md +160 -0
  43. package/agents/empty-state/AGENTS.md +203 -0
  44. package/agents/file-chip/AGENTS.md +79 -0
  45. package/agents/file-icon/AGENTS.md +66 -0
  46. package/agents/file-upload/AGENTS.md +168 -0
  47. package/agents/filter-chips/AGENTS.md +167 -0
  48. package/agents/flag/AGENTS.md +67 -0
  49. package/agents/funnel-chart/AGENTS.md +131 -0
  50. package/agents/highlight/AGENTS.md +119 -0
  51. package/agents/hover-card/AGENTS.md +271 -0
  52. package/agents/icon-stack/AGENTS.md +120 -0
  53. package/agents/icon-tile/AGENTS.md +94 -0
  54. package/agents/inline-diff/AGENTS.md +211 -0
  55. package/agents/input/AGENTS.md +261 -0
  56. package/agents/kanban/AGENTS.md +352 -0
  57. package/agents/kbd/AGENTS.md +160 -0
  58. package/agents/layout/AGENTS.md +351 -0
  59. package/agents/line-chart/AGENTS.md +393 -0
  60. package/agents/link/AGENTS.md +53 -0
  61. package/agents/list/AGENTS.md +392 -0
  62. package/agents/marker/AGENTS.md +142 -0
  63. package/agents/masked-text/AGENTS.md +127 -0
  64. package/agents/menubar/AGENTS.md +276 -0
  65. package/agents/multi-select/AGENTS.md +159 -0
  66. package/agents/navigation-menu/AGENTS.md +315 -0
  67. package/agents/notice-stack/AGENTS.md +101 -0
  68. package/agents/number-stepper/AGENTS.md +96 -0
  69. package/agents/otp-input/AGENTS.md +162 -0
  70. package/agents/pagination/AGENTS.md +189 -0
  71. package/agents/phone-input/AGENTS.md +131 -0
  72. package/agents/pie-chart/AGENTS.md +243 -0
  73. package/agents/popover/AGENTS.md +190 -0
  74. package/agents/progress/AGENTS.md +273 -0
  75. package/agents/progress-tracker/AGENTS.md +305 -0
  76. package/agents/rating/AGENTS.md +165 -0
  77. package/agents/relative-time/AGENTS.md +103 -0
  78. package/agents/resizable/AGENTS.md +390 -0
  79. package/agents/scaled-preview/AGENTS.md +111 -0
  80. package/agents/scatter-chart/AGENTS.md +160 -0
  81. package/agents/scroll-area/AGENTS.md +271 -0
  82. package/agents/search-input/AGENTS.md +105 -0
  83. package/agents/segmented-control/AGENTS.md +153 -0
  84. package/agents/select/AGENTS.md +159 -0
  85. package/agents/selector-button/AGENTS.md +122 -0
  86. package/agents/sidebar/AGENTS.md +201 -0
  87. package/agents/skeleton/AGENTS.md +166 -0
  88. package/agents/slider/AGENTS.md +181 -0
  89. package/agents/spark-chart/AGENTS.md +257 -0
  90. package/agents/sparkbar/AGENTS.md +92 -0
  91. package/agents/spinner/AGENTS.md +123 -0
  92. package/agents/split-view/AGENTS.md +290 -0
  93. package/agents/stat/AGENTS.md +138 -0
  94. package/agents/status-icon/AGENTS.md +243 -0
  95. package/agents/step-list/AGENTS.md +313 -0
  96. package/agents/table/AGENTS.md +286 -0
  97. package/agents/tabs/AGENTS.md +305 -0
  98. package/agents/tag-input/AGENTS.md +246 -0
  99. package/agents/time-picker/AGENTS.md +228 -0
  100. package/agents/timeline/AGENTS.md +1018 -0
  101. package/agents/toast/AGENTS.md +266 -0
  102. package/agents/toggle-group/AGENTS.md +216 -0
  103. package/agents/toolbar/AGENTS.md +277 -0
  104. package/agents/tooltip/AGENTS.md +154 -0
  105. package/agents/tracker/AGENTS.md +158 -0
  106. package/agents/tree-diagram/AGENTS.md +260 -0
  107. package/agents/tree-view/AGENTS.md +329 -0
  108. package/agents/typography/AGENTS.md +396 -0
  109. package/lib/index.js +17914 -0
  110. package/lib/style.css +2 -0
  111. package/lib/types/components/Accordion/Accordion.d.ts +57 -0
  112. package/lib/types/components/ActionBar/ActionBar.d.ts +24 -0
  113. package/lib/types/components/Alert/Alert.d.ts +36 -0
  114. package/lib/types/components/AppShell/AppShell.d.ts +38 -0
  115. package/lib/types/components/AreaChart/AreaChart.d.ts +17 -0
  116. package/lib/types/components/BarChart/BarChart.d.ts +57 -0
  117. package/lib/types/components/BarList/BarList.d.ts +56 -0
  118. package/lib/types/components/Breadcrumb/Breadcrumb.d.ts +15 -0
  119. package/lib/types/components/Calendar/Calendar.d.ts +34 -0
  120. package/lib/types/components/Calendar/DatePicker.d.ts +45 -0
  121. package/lib/types/components/Calendar/date.d.ts +32 -0
  122. package/lib/types/components/Card/Card.d.ts +64 -0
  123. package/lib/types/components/CardFrame/CardFrame.d.ts +15 -0
  124. package/lib/types/components/Chart/ChartParts.d.ts +38 -0
  125. package/lib/types/components/Chart/chart.d.ts +46 -0
  126. package/lib/types/components/Chart/useChartInteraction.d.ts +39 -0
  127. package/lib/types/components/ChatBubble/ChatBubble.d.ts +61 -0
  128. package/lib/types/components/ChatBubble/formatChatTime.d.ts +2 -0
  129. package/lib/types/components/ChatComposer/ChatComposer.d.ts +42 -0
  130. package/lib/types/components/CodeBlock/CodeBlock.d.ts +18 -0
  131. package/lib/types/components/CodeBlock/highlight.d.ts +10 -0
  132. package/lib/types/components/ColorPicker/ColorPicker.d.ts +61 -0
  133. package/lib/types/components/ColorPicker/color.d.ts +48 -0
  134. package/lib/types/components/ColorPicker/presets.d.ts +7 -0
  135. package/lib/types/components/Combobox/Combobox.d.ts +48 -0
  136. package/lib/types/components/CommandMenu/CommandMenu.d.ts +51 -0
  137. package/lib/types/components/Comment/Comment.d.ts +45 -0
  138. package/lib/types/components/ContextMenu/ContextMenu.d.ts +40 -0
  139. package/lib/types/components/DataGrid/DataGrid.d.ts +43 -0
  140. package/lib/types/components/DataGrid/GridPopover.d.ts +43 -0
  141. package/lib/types/components/DataGrid/anchor.d.ts +5 -0
  142. package/lib/types/components/DataGrid/model.d.ts +61 -0
  143. package/lib/types/components/DataGrid/panels.d.ts +63 -0
  144. package/lib/types/components/DataGrid/typeMeta.d.ts +6 -0
  145. package/lib/types/components/DataGrid/types.d.ts +77 -0
  146. package/lib/types/components/DescriptionList/DescriptionList.d.ts +77 -0
  147. package/lib/types/components/Dialog/AlertDialog.d.ts +26 -0
  148. package/lib/types/components/Dialog/Dialog.d.ts +42 -0
  149. package/lib/types/components/Dialog/modal.d.ts +38 -0
  150. package/lib/types/components/Drawer/Drawer.d.ts +62 -0
  151. package/lib/types/components/DropdownMenu/DropdownMenu.d.ts +97 -0
  152. package/lib/types/components/DropdownMenu/menuCore.d.ts +23 -0
  153. package/lib/types/components/Dropzone/Dropzone.d.ts +30 -0
  154. package/lib/types/components/EmptyState/EmptyState.d.ts +26 -0
  155. package/lib/types/components/FileChip/FileChip.d.ts +32 -0
  156. package/lib/types/components/FileUpload/FileUpload.d.ts +52 -0
  157. package/lib/types/components/FilterChips/FilterChips.d.ts +37 -0
  158. package/lib/types/components/FunnelChart/FunnelChart.d.ts +38 -0
  159. package/lib/types/components/FunnelChart/funnel.d.ts +25 -0
  160. package/lib/types/components/Highlight/Highlight.d.ts +35 -0
  161. package/lib/types/components/HoverCard/HoverCard.d.ts +47 -0
  162. package/lib/types/components/InlineDiff/InlineDiff.d.ts +36 -0
  163. package/lib/types/components/InlineDiff/diff.d.ts +42 -0
  164. package/lib/types/components/InlineDiff/useDiffReview.d.ts +57 -0
  165. package/lib/types/components/Kanban/Kanban.d.ts +64 -0
  166. package/lib/types/components/Kanban/KanbanCard.d.ts +35 -0
  167. package/lib/types/components/Kanban/move.d.ts +25 -0
  168. package/lib/types/components/LineChart/LineChart.d.ts +85 -0
  169. package/lib/types/components/List/List.d.ts +62 -0
  170. package/lib/types/components/Listbox/Listbox.d.ts +60 -0
  171. package/lib/types/components/Marker/Marker.d.ts +28 -0
  172. package/lib/types/components/Menubar/Menubar.d.ts +50 -0
  173. package/lib/types/components/MultiSelect/MultiSelect.d.ts +38 -0
  174. package/lib/types/components/NavigationMenu/NavigationMenu.d.ts +101 -0
  175. package/lib/types/components/NoticeStack/NoticeStack.d.ts +41 -0
  176. package/lib/types/components/NumberStepper/NumberStepper.d.ts +32 -0
  177. package/lib/types/components/OtpInput/OtpInput.d.ts +31 -0
  178. package/lib/types/components/Pagination/Pagination.d.ts +54 -0
  179. package/lib/types/components/Pagination/paginationRange.d.ts +7 -0
  180. package/lib/types/components/PhoneInput/PhoneInput.d.ts +47 -0
  181. package/lib/types/components/PieChart/PieChart.d.ts +67 -0
  182. package/lib/types/components/PieChart/arc.d.ts +26 -0
  183. package/lib/types/components/PieChart/useArcTween.d.ts +15 -0
  184. package/lib/types/components/Popover/Popover.d.ts +28 -0
  185. package/lib/types/components/ProgressTracker/ProgressTracker.d.ts +64 -0
  186. package/lib/types/components/Rating/Rating.d.ts +42 -0
  187. package/lib/types/components/Resizable/Resizable.d.ts +50 -0
  188. package/lib/types/components/Resizable/layout.d.ts +31 -0
  189. package/lib/types/components/ScaledPreview/ScaledPreview.d.ts +38 -0
  190. package/lib/types/components/ScatterChart/ScatterChart.d.ts +81 -0
  191. package/lib/types/components/ScatterChart/scatter.d.ts +14 -0
  192. package/lib/types/components/ScrollArea/ScrollArea.d.ts +34 -0
  193. package/lib/types/components/Select/Select.d.ts +39 -0
  194. package/lib/types/components/Sidebar/Sidebar.d.ts +39 -0
  195. package/lib/types/components/Skeleton/Skeleton.d.ts +47 -0
  196. package/lib/types/components/Slider/Slider.d.ts +36 -0
  197. package/lib/types/components/SparkChart/SparkChart.d.ts +55 -0
  198. package/lib/types/components/SparkChart/spark.d.ts +16 -0
  199. package/lib/types/components/Sparkbar/Sparkbar.d.ts +39 -0
  200. package/lib/types/components/SplitView/SplitView.d.ts +31 -0
  201. package/lib/types/components/Stat/Stat.d.ts +58 -0
  202. package/lib/types/components/StepList/StepList.d.ts +61 -0
  203. package/lib/types/components/Table/Table.d.ts +39 -0
  204. package/lib/types/components/Tabs/Tabs.d.ts +47 -0
  205. package/lib/types/components/TagInput/TagInput.d.ts +46 -0
  206. package/lib/types/components/TimePicker/TimePicker.d.ts +43 -0
  207. package/lib/types/components/TimePicker/time.d.ts +15 -0
  208. package/lib/types/components/Timeline/Timeline.d.ts +154 -0
  209. package/lib/types/components/Timeline/scale.d.ts +22 -0
  210. package/lib/types/components/Toast/Toaster.d.ts +19 -0
  211. package/lib/types/components/Toast/index.d.ts +4 -0
  212. package/lib/types/components/Toast/store.d.ts +75 -0
  213. package/lib/types/components/ToggleGroup/ToggleGroup.d.ts +28 -0
  214. package/lib/types/components/Toolbar/Toolbar.d.ts +70 -0
  215. package/lib/types/components/Tracker/Tracker.d.ts +43 -0
  216. package/lib/types/components/TreeDiagram/TreeDiagram.d.ts +68 -0
  217. package/lib/types/components/TreeView/TreeView.d.ts +107 -0
  218. package/lib/types/components/index.d.ts +186 -0
  219. package/lib/types/hooks/index.d.ts +17 -0
  220. package/lib/types/hooks/timing.d.ts +29 -0
  221. package/lib/types/hooks/useControllableState.d.ts +5 -0
  222. package/lib/types/hooks/useCountdown.d.ts +19 -0
  223. package/lib/types/hooks/useDigitInput.d.ts +24 -0
  224. package/lib/types/hooks/useDismiss.d.ts +3 -0
  225. package/lib/types/hooks/useElapsed.d.ts +28 -0
  226. package/lib/types/hooks/useFloating.d.ts +21 -0
  227. package/lib/types/hooks/useFocusTrap.d.ts +7 -0
  228. package/lib/types/hooks/usePresence.d.ts +8 -0
  229. package/lib/types/hooks/usePressToOpen.d.ts +20 -0
  230. package/lib/types/hooks/useScrollLock.d.ts +2 -0
  231. package/lib/types/hooks/useSelection.d.ts +29 -0
  232. package/lib/types/index.d.ts +5 -0
  233. package/lib/types/primitives/AspectRatio.d.ts +14 -0
  234. package/lib/types/primitives/BrandIcon.d.ts +12 -0
  235. package/lib/types/primitives/ColorDot.d.ts +20 -0
  236. package/lib/types/primitives/CopyButton.d.ts +12 -0
  237. package/lib/types/primitives/CountBadge.d.ts +28 -0
  238. package/lib/types/primitives/Countdown.d.ts +21 -0
  239. package/lib/types/primitives/Delta.d.ts +33 -0
  240. package/lib/types/primitives/Elapsed.d.ts +23 -0
  241. package/lib/types/primitives/FileIcon.d.ts +17 -0
  242. package/lib/types/primitives/Flag.d.ts +15 -0
  243. package/lib/types/primitives/IconStack.d.ts +27 -0
  244. package/lib/types/primitives/IconTile.d.ts +24 -0
  245. package/lib/types/primitives/Kbd.d.ts +19 -0
  246. package/lib/types/primitives/Layout.d.ts +64 -0
  247. package/lib/types/primitives/Link.d.ts +12 -0
  248. package/lib/types/primitives/MaskedText.d.ts +28 -0
  249. package/lib/types/primitives/Progress.d.ts +52 -0
  250. package/lib/types/primitives/RelativeTime.d.ts +22 -0
  251. package/lib/types/primitives/SearchInput.d.ts +8 -0
  252. package/lib/types/primitives/SelectorButton.d.ts +23 -0
  253. package/lib/types/primitives/Spinner.d.ts +15 -0
  254. package/lib/types/primitives/StatusIcon.d.ts +40 -0
  255. package/lib/types/primitives/Swatch.d.ts +11 -0
  256. package/lib/types/primitives/Tooltip.d.ts +17 -0
  257. package/lib/types/primitives/Typography.d.ts +48 -0
  258. package/lib/types/primitives/formatCountdown.d.ts +2 -0
  259. package/lib/types/primitives/formatElapsed.d.ts +8 -0
  260. package/lib/types/primitives/formatRelativeTime.d.ts +16 -0
  261. package/lib/types/primitives/hotkey.d.ts +10 -0
  262. package/lib/types/primitives/index.d.ts +188 -0
  263. package/lib/types/primitives/maskValue.d.ts +24 -0
  264. package/package.json +54 -4
@@ -0,0 +1,84 @@
1
+ # CopyButton
2
+
3
+ > 버튼 & 링크 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ value를 클립보드에 복사하는 버튼. 복사되면 아이콘이 잠깐 체크로 바뀌어 결과를 바로 보여 줘요. 글자 없이 쓰면 아이콘 버튼 + 툴팁이 돼요.
6
+
7
+ ```tsx
8
+ import { CopyButton } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## API
12
+
13
+ ### CopyButton
14
+
15
+ Button의 variant · size · disabled 등도 그대로 받아요(onClick · icon · children 제외).
16
+
17
+ | prop | 타입 | 기본값 | 설명 |
18
+ | --- | --- | --- | --- |
19
+ | `value` (필수) | `string` | | 클립보드에 넣을 글자. |
20
+ | `label` | `string` | | 아이콘 옆 글자. 생략하면 아이콘 버튼 + 툴팁. |
21
+ | `copiedLabel` | `string` | `'복사했어요'` | 복사 직후(1.6초) 보이는 글자와 툴팁. |
22
+ | `onCopy` | `(value: string) => void` | | 복사에 성공했을 때. |
23
+ | `variant` | `ButtonVariant` | `'ghost'` | 버튼 스타일. |
24
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'sm'` | 버튼 크기. |
25
+
26
+ ## 예제
27
+
28
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
29
+
30
+ ### 기본
31
+
32
+ label이 없으면 아이콘만 보이고, 마우스를 올리면 "복사" 툴팁이 떠요.
33
+
34
+ ```tsx
35
+ import { CopyButton, Text } from '@iamfiro/design'
36
+
37
+ const API_KEY = 'pk_demo_7Gq2XvT9nR4w'
38
+
39
+ export default function Example() {
40
+ return (
41
+ <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
42
+ <Text variant="code">{API_KEY}</Text>
43
+ <CopyButton value={API_KEY} />
44
+ </div>
45
+ )
46
+ }
47
+ ```
48
+
49
+ ### 글자와 함께
50
+
51
+ label을 주면 글자가 붙고, 복사 직후에는 copiedLabel로 잠깐 바뀌어요.
52
+
53
+ ```tsx
54
+ import { CopyButton } from '@iamfiro/design'
55
+
56
+ export default function Example() {
57
+ return (
58
+ <div style={{ display: 'flex', flexWrap: 'wrap', alignItems: 'center', gap: 8 }}>
59
+ <CopyButton value="https://lumen.app/invite/8f2k1" label="초대 링크 복사" variant="secondary" size="md" />
60
+ <CopyButton value="npm install @lumen/ui" label="명령어 복사" copiedLabel="복사 완료" />
61
+ </div>
62
+ )
63
+ }
64
+ ```
65
+
66
+ ### 복사 후 알림
67
+
68
+ onCopy는 복사에 성공했을 때만 불려요. 토스트로 한 번 더 알려 줄 수 있어요.
69
+
70
+ ```tsx
71
+ import { CopyButton, toast } from '@iamfiro/design'
72
+
73
+ export default function Example() {
74
+ return (
75
+ <CopyButton
76
+ value="ORD-20261025-4821"
77
+ label="주문번호 복사"
78
+ variant="secondary"
79
+ size="md"
80
+ onCopy={() => toast.success('주문번호를 복사했어요')}
81
+ />
82
+ )
83
+ }
84
+ ```
@@ -0,0 +1,115 @@
1
+ # CountBadge
2
+
3
+ > 라벨 & 배지 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 섹션 제목 · 아이콘 옆에 붙는 작은 숫자 원. 기다리는 일, 읽지 않은 항목의 개수를 알려요. 숫자는 tabular라 흔들리지 않고, 두 자리 이상이면 둥근 캡슐로 늘어나요. 값이 바뀌면 배지가 살짝 튀고 새 숫자가 아래에서 올라와요. 글자가 있는 상태 라벨은 Badge, 탭 옆 개수는 Tabs의 count를 써요.
6
+
7
+ ```tsx
8
+ import { CountBadge } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 제목 · 아이콘 옆 개수 원은 `CountBadge`(tone · `max` "99+" · 바뀌면 튀기). 글자가 있는 상태 라벨은 `Badge`.
14
+ - 글 속 변경 내용(추적된 변경)은 `InlineDiff`: 삭제 = 빨간 취소선 + `--danger-soft`, 추가 = 초록 + `--success-soft`, 진짜 `<del>` · `<ins>` + 화면 읽기 "삭제" · "추가". 검토(수락 · 거절)는 `reviewable`, 툴바(남은 개수 `CountBadge variant="soft" tone="success"`, 이전 · 다음 `Button iconOnly`, 모두 거절 · 모두 수락)는 `useDiffReview` 상태를 함께 써서 조립한다. 검토 카드는 `CardFrame header`(회색 판 위 아이콘 + 문서 이름) 안에 `Card raised` — 회색 Box를 카드 안 제목줄로 넣으면 입력창처럼 보인다. 본문 줄 간격은 넉넉하게(위아래 줄의 색 배경이 닿지 않게). 모두 수락 · 거절은 확인 대신 `toast.undo`. 두 문자열 비교는 `diffWords`, 결과 글은 `applyDiffDecisions`.
15
+
16
+ ## API
17
+
18
+ ### CountBadge
19
+
20
+ | prop | 타입 | 기본값 | 설명 |
21
+ | --- | --- | --- | --- |
22
+ | `count` (필수) | `number` | | 보여 줄 숫자. |
23
+ | `max` | `number` | `99` | 넘으면 "99+"처럼 보여요. |
24
+ | `tone` | `'neutral' \| 'accent' \| 'success' \| 'warning' \| 'danger' \| 'info'` | `'accent'` | 색(Badge와 같아요). |
25
+ | `variant` | `'solid' \| 'soft'` | `'solid'` | solid: 채운 원 · soft: 연한 배경 + 색 숫자. |
26
+ | `size` | `'sm' \| 'md'` | `'md'` | sm 16px · md 18px 높이. |
27
+ | `showZero` | `boolean` | | 0일 때도 보여요(기본은 숨김). |
28
+ | `label` | `string` | | 숫자 대신 읽힐 이름("승인 대기 1건"). |
29
+ | `className / style` | `string / CSSProperties` | | 추가 클래스 · 스타일. |
30
+
31
+ ## 예제
32
+
33
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
34
+
35
+ ### 섹션 제목 옆
36
+
37
+ 버튼으로 개수를 바꿔 튀는 움직임을 확인해 보세요. label을 주면 화면 읽기 프로그램이 "승인 대기 1건"으로 읽어요.
38
+
39
+ ```tsx
40
+ import { useState } from 'react'
41
+ import { Minus, Plus } from 'lucide-react'
42
+ import { Button, CountBadge, Inline, Stack, Text } from '@iamfiro/design'
43
+
44
+ export default function Example() {
45
+ const [waiting, setWaiting] = useState(1)
46
+ return (
47
+ <Stack gap={4} style={{ width: 320 }}>
48
+ <Inline gap={2} wrap={false}>
49
+ <Text variant="heading-xs" as="h3">
50
+ 승인 대기
51
+ </Text>
52
+ <CountBadge count={waiting} tone="warning" label={`승인 대기 ${waiting}건`} />
53
+ </Inline>
54
+ <Text variant="body-sm" tone="secondary">
55
+ 숫자가 바뀌면 배지가 살짝 튀어 오르고 새 숫자가 아래에서 올라와요. 0이면 사라지고, 99를 넘으면 "99+"가 돼요.
56
+ </Text>
57
+ <Inline gap={2}>
58
+ <Button size="sm" icon={<Plus />} onClick={() => setWaiting((n) => n + 1)}>
59
+ 요청 추가
60
+ </Button>
61
+ <Button size="sm" variant="ghost" icon={<Minus />} disabled={waiting === 0} onClick={() => setWaiting((n) => Math.max(0, n - 1))}>
62
+ 하나 처리
63
+ </Button>
64
+ <Button size="sm" variant="ghost" onClick={() => setWaiting(120)}>
65
+ 120건
66
+ </Button>
67
+ </Inline>
68
+ </Stack>
69
+ )
70
+ }
71
+ ```
72
+
73
+ ### 색 · 모양 · 크기
74
+
75
+ Badge와 같은 tone. solid는 채운 원 + 흰 숫자, soft는 연한 상태색 + 색 숫자예요. sm 16 · md 18px, max를 넘으면 "99+".
76
+
77
+ ```tsx
78
+ import { CountBadge, Inline, Stack, Text, type Tone } from '@iamfiro/design'
79
+
80
+ const TONES: Tone[] = ['accent', 'neutral', 'success', 'warning', 'danger', 'info']
81
+
82
+ export default function Example() {
83
+ return (
84
+ <Stack gap={4}>
85
+ <Inline gap={3}>
86
+ {TONES.map((tone) => (
87
+ <CountBadge key={tone} tone={tone} count={3} />
88
+ ))}
89
+ <Text variant="caption" tone="tertiary">
90
+ solid
91
+ </Text>
92
+ </Inline>
93
+ <Inline gap={3}>
94
+ {TONES.map((tone) => (
95
+ <CountBadge key={tone} tone={tone} variant="soft" count={3} />
96
+ ))}
97
+ <Text variant="caption" tone="tertiary">
98
+ soft
99
+ </Text>
100
+ </Inline>
101
+ <Inline gap={3}>
102
+ <CountBadge size="sm" count={1} tone="warning" />
103
+ <CountBadge size="sm" count={24} />
104
+ <CountBadge count={8} />
105
+ <CountBadge count={128} tone="danger" />
106
+ <CountBadge count={1500} max={999} tone="neutral" />
107
+ <CountBadge count={0} showZero tone="neutral" variant="soft" />
108
+ <Text variant="caption" tone="tertiary">
109
+ sm · md · max · showZero
110
+ </Text>
111
+ </Inline>
112
+ </Stack>
113
+ )
114
+ }
115
+ ```
@@ -0,0 +1,101 @@
1
+ # Countdown
2
+
3
+ > 진행 표시 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 남은 시간을 "8초" · "1:05"처럼 글자로 보여 줘요. 글자라서 Badge · 캡션 · 버튼 어디에나 들어가고, 숫자는 tabular라 흔들리지 않아요. 렌더 중엔 시계를 읽지 않고 타이머 안에서 마감 시각과 비교해 밀리지 않아요. 직접 그리고 싶으면 useCountdown 훅을 써요. 시작한 뒤 지난 시간을 올려 세려면 Elapsed를 써요.
6
+
7
+ ```tsx
8
+ import { Countdown, formatCountdown, useCountdown } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 남은 시간("8초")은 `Countdown` / `useCountdown`(렌더 중 시계 읽기 금지). Badge 안엔 글자로 넣는다.
14
+
15
+ ## API
16
+
17
+ ### Countdown
18
+
19
+ | prop | 타입 | 기본값 | 설명 |
20
+ | --- | --- | --- | --- |
21
+ | `seconds` (필수) | `number` | | 몇 초부터 셀지. 값이 바뀌면 처음부터. |
22
+ | `running` | `boolean` | `true` | false면 그 자리에서 멈추고, true면 이어서 세요. |
23
+ | `onComplete` | `() => void` | | 0이 될 때 한 번. |
24
+ | `format` | `(remaining: number) => ReactNode` | `formatCountdown` | 남은 초를 글자로. 기본은 "8초" / "1:05" / "1:02:05". |
25
+ | `doneLabel` | `ReactNode` | | 0일 때 "0초" 대신 보일 글자. |
26
+ | `className / style` | `string / CSSProperties` | | span(role="timer")에 전달. |
27
+
28
+ ### useCountdown(seconds, options)
29
+
30
+ 반환값 { remaining, done, restart(seconds?) }.
31
+
32
+ | prop | 타입 | 기본값 | 설명 |
33
+ | --- | --- | --- | --- |
34
+ | `seconds` (필수) | `number` | | 시작 초. 바뀌면 처음부터 다시. |
35
+ | `options.running` | `boolean` | `true` | 멈춤 / 이어 세기. |
36
+ | `options.onComplete` | `() => void` | | 0이 될 때 한 번. |
37
+
38
+ ## 예제
39
+
40
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
41
+
42
+ ### Badge 안의 카운트다운
43
+
44
+ Badge는 그대로 두고 글자 자리에 Countdown을 넣어요. 0이 되면 onComplete로 상태를 바꿔요. 1분이 넘으면 "2:05" 형식.
45
+
46
+ ```tsx
47
+ import { useState } from 'react'
48
+ import { Badge, Button, Countdown, Inline } from '@iamfiro/design'
49
+
50
+ export default function Example() {
51
+ const [limited, setLimited] = useState(true)
52
+ return (
53
+ <Inline gap={3}>
54
+ {limited ? (
55
+ <Badge tone="warning" dot>
56
+ 요청 제한 · <Countdown seconds={8} onComplete={() => setLimited(false)} />
57
+ </Badge>
58
+ ) : (
59
+ <Badge tone="success" dot>
60
+ 다시 보낼 수 있어요
61
+ </Badge>
62
+ )}
63
+ <Badge>
64
+ 세션 만료까지 <Countdown seconds={125} />
65
+ </Badge>
66
+ <Button size="sm" variant="ghost" disabled={limited} onClick={() => setLimited(true)}>
67
+ 다시 제한 걸기
68
+ </Button>
69
+ </Inline>
70
+ )
71
+ }
72
+ ```
73
+
74
+ ### useCountdown
75
+
76
+ 남은 초(remaining) · done · restart()를 받아 막대와 색을 직접 그려요. seconds가 바뀌어도 처음부터 다시 세요.
77
+
78
+ ```tsx
79
+ import { RotateCcw } from 'lucide-react'
80
+ import { Button, Inline, Progress, Stack, Text, formatCountdown, useCountdown } from '@iamfiro/design'
81
+
82
+ const SECONDS = 30
83
+
84
+ export default function Example() {
85
+ const { remaining, done, restart } = useCountdown(SECONDS)
86
+ return (
87
+ <Stack gap={3} style={{ width: 320 }}>
88
+ <Inline justify="between" wrap={false}>
89
+ <Text variant="label-md">인증번호 유효 시간</Text>
90
+ <Text variant="label-md" tone={done ? 'danger' : remaining <= 10 ? 'warning' : 'secondary'} numeric>
91
+ {done ? '만료됨' : formatCountdown(remaining)}
92
+ </Text>
93
+ </Inline>
94
+ <Progress value={remaining} max={SECONDS} size="sm" tone={remaining <= 10 ? 'warning' : 'accent'} aria-label="남은 시간" />
95
+ <Button size="sm" icon={<RotateCcw />} onClick={() => restart()} disabled={!done}>
96
+ 인증번호 다시 받기
97
+ </Button>
98
+ </Stack>
99
+ )
100
+ }
101
+ ```