@iamfiro/design 0.0.0-stage → 0.3.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 (416) hide show
  1. package/AGENTS.md +82 -0
  2. package/README.md +15 -2
  3. package/agents/INDEX.md +157 -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/social-login-button/AGENTS.md +156 -0
  90. package/agents/spark-chart/AGENTS.md +257 -0
  91. package/agents/sparkbar/AGENTS.md +92 -0
  92. package/agents/spinner/AGENTS.md +123 -0
  93. package/agents/split-view/AGENTS.md +290 -0
  94. package/agents/stat/AGENTS.md +138 -0
  95. package/agents/status-icon/AGENTS.md +243 -0
  96. package/agents/step-list/AGENTS.md +313 -0
  97. package/agents/table/AGENTS.md +286 -0
  98. package/agents/tabs/AGENTS.md +305 -0
  99. package/agents/tag-input/AGENTS.md +246 -0
  100. package/agents/time-picker/AGENTS.md +228 -0
  101. package/agents/timeline/AGENTS.md +1018 -0
  102. package/agents/toast/AGENTS.md +266 -0
  103. package/agents/toggle-group/AGENTS.md +216 -0
  104. package/agents/toolbar/AGENTS.md +277 -0
  105. package/agents/tooltip/AGENTS.md +154 -0
  106. package/agents/tracker/AGENTS.md +158 -0
  107. package/agents/tree-diagram/AGENTS.md +260 -0
  108. package/agents/tree-view/AGENTS.md +329 -0
  109. package/agents/typography/AGENTS.md +396 -0
  110. package/lib/components/Accordion/Accordion2.js +135 -0
  111. package/lib/components/ActionBar/ActionBar2.js +65 -0
  112. package/lib/components/Alert/Alert2.js +131 -0
  113. package/lib/components/AppShell/AppShell2.js +94 -0
  114. package/lib/components/AreaChart/AreaChart.js +59 -0
  115. package/lib/components/BarChart/BarChart2.js +243 -0
  116. package/lib/components/BarList/BarList2.js +172 -0
  117. package/lib/components/Breadcrumb/Breadcrumb2.js +87 -0
  118. package/lib/components/Calendar/Calendar2.js +309 -0
  119. package/lib/components/Calendar/DatePicker2.js +229 -0
  120. package/lib/components/Calendar/date.js +121 -0
  121. package/lib/components/Card/Card2.js +104 -0
  122. package/lib/components/CardFrame/CardFrame2.js +72 -0
  123. package/lib/components/Chart/ChartParts.js +150 -0
  124. package/lib/components/Chart/chart2.js +96 -0
  125. package/lib/components/Chart/useChartInteraction.js +94 -0
  126. package/lib/components/ChatBubble/ChatBubble2.js +174 -0
  127. package/lib/components/ChatBubble/formatChatTime.js +53 -0
  128. package/lib/components/ChatComposer/ChatComposer2.js +153 -0
  129. package/lib/components/CodeBlock/CodeBlock2.js +93 -0
  130. package/lib/components/CodeBlock/highlight.js +114 -0
  131. package/lib/components/ColorPicker/ColorPicker2.js +610 -0
  132. package/lib/components/ColorPicker/color.js +180 -0
  133. package/lib/components/ColorPicker/presets.js +75 -0
  134. package/lib/components/Combobox/Combobox2.js +229 -0
  135. package/lib/components/CommandMenu/CommandMenu.js +267 -0
  136. package/lib/components/Comment/Comment2.js +134 -0
  137. package/lib/components/ContextMenu/ContextMenu2.js +168 -0
  138. package/lib/components/DataGrid/DataGrid2.js +1996 -0
  139. package/lib/components/DataGrid/GridPopover.js +154 -0
  140. package/lib/components/DataGrid/anchor.js +50 -0
  141. package/lib/components/DataGrid/model.js +558 -0
  142. package/lib/components/DataGrid/panels.js +703 -0
  143. package/lib/components/DataGrid/typeMeta.js +76 -0
  144. package/lib/components/DataGrid/types.js +54 -0
  145. package/lib/components/DescriptionList/DescriptionList2.js +180 -0
  146. package/lib/components/Dialog/AlertDialog.js +118 -0
  147. package/lib/components/Dialog/Dialog2.js +109 -0
  148. package/lib/components/Dialog/modal.js +92 -0
  149. package/lib/components/Drawer/Drawer2.js +244 -0
  150. package/lib/components/DropdownMenu/DropdownMenu2.js +394 -0
  151. package/lib/components/DropdownMenu/menuCore.js +63 -0
  152. package/lib/components/Dropzone/Dropzone2.js +144 -0
  153. package/lib/components/EmptyState/EmptyState2.js +72 -0
  154. package/lib/components/FileChip/FileChip2.js +118 -0
  155. package/lib/components/FileUpload/FileUpload.js +258 -0
  156. package/lib/components/FilterChips/FilterChips2.js +101 -0
  157. package/lib/components/FunnelChart/FunnelChart2.js +283 -0
  158. package/lib/components/FunnelChart/funnel.js +69 -0
  159. package/lib/components/Highlight/Highlight2.js +100 -0
  160. package/lib/components/HoverCard/HoverCard.js +134 -0
  161. package/lib/components/InlineDiff/InlineDiff2.js +215 -0
  162. package/lib/components/InlineDiff/diff.js +126 -0
  163. package/lib/components/InlineDiff/useDiffReview.js +109 -0
  164. package/lib/components/Kanban/Kanban2.js +691 -0
  165. package/lib/components/Kanban/KanbanCard.js +159 -0
  166. package/lib/components/Kanban/move.js +69 -0
  167. package/lib/components/LineChart/LineChart2.js +342 -0
  168. package/lib/components/List/List2.js +133 -0
  169. package/lib/components/Listbox/Listbox2.js +163 -0
  170. package/lib/components/Marker/Marker2.js +82 -0
  171. package/lib/components/Menubar/Menubar2.js +223 -0
  172. package/lib/components/MultiSelect/MultiSelect2.js +204 -0
  173. package/lib/components/NavigationMenu/NavigationMenu2.js +481 -0
  174. package/lib/components/NoticeStack/NoticeStack2.js +178 -0
  175. package/lib/components/NumberStepper/NumberStepper2.js +129 -0
  176. package/lib/components/OtpInput/OtpInput2.js +122 -0
  177. package/lib/components/Pagination/Pagination2.js +210 -0
  178. package/lib/components/Pagination/paginationRange.js +53 -0
  179. package/lib/components/PhoneInput/PhoneInput.js +175 -0
  180. package/lib/components/PieChart/PieChart2.js +246 -0
  181. package/lib/components/PieChart/arc.js +66 -0
  182. package/lib/components/PieChart/useArcTween.js +94 -0
  183. package/lib/components/Popover/Popover2.js +112 -0
  184. package/lib/components/ProgressTracker/ProgressTracker2.js +226 -0
  185. package/lib/components/Rating/Rating2.js +186 -0
  186. package/lib/components/Resizable/Resizable2.js +236 -0
  187. package/lib/components/Resizable/layout.js +115 -0
  188. package/lib/components/ScaledPreview/ScaledPreview2.js +100 -0
  189. package/lib/components/ScatterChart/ScatterChart2.js +356 -0
  190. package/lib/components/ScatterChart/scatter.js +83 -0
  191. package/lib/components/ScrollArea/ScrollArea2.js +218 -0
  192. package/lib/components/Select/Select2.js +153 -0
  193. package/lib/components/Sidebar/Sidebar2.js +127 -0
  194. package/lib/components/Skeleton/Skeleton2.js +91 -0
  195. package/lib/components/Slider/Slider2.js +142 -0
  196. package/lib/components/SocialLoginButton/SocialLoginButton.js +85 -0
  197. package/lib/components/SparkChart/SparkChart2.js +217 -0
  198. package/lib/components/SparkChart/spark.js +76 -0
  199. package/lib/components/Sparkbar/Sparkbar2.js +111 -0
  200. package/lib/components/SplitView/SplitView2.js +95 -0
  201. package/lib/components/Stat/Stat2.js +164 -0
  202. package/lib/components/StepList/StepList2.js +131 -0
  203. package/lib/components/Table/Table2.js +104 -0
  204. package/lib/components/Tabs/Tabs2.js +131 -0
  205. package/lib/components/TagInput/TagInput2.js +360 -0
  206. package/lib/components/TimePicker/TimePicker2.js +388 -0
  207. package/lib/components/TimePicker/time.js +83 -0
  208. package/lib/components/Timeline/Timeline2.js +369 -0
  209. package/lib/components/Timeline/scale.js +83 -0
  210. package/lib/components/Toast/Toaster.js +212 -0
  211. package/lib/components/Toast/store.js +129 -0
  212. package/lib/components/ToggleGroup/ToggleGroup2.js +125 -0
  213. package/lib/components/Toolbar/Toolbar2.js +281 -0
  214. package/lib/components/Tracker/Tracker2.js +172 -0
  215. package/lib/components/TreeDiagram/TreeDiagram2.js +223 -0
  216. package/lib/components/TreeView/TreeView2.js +284 -0
  217. package/lib/hooks/timing.js +55 -0
  218. package/lib/hooks/useControllableState.js +49 -0
  219. package/lib/hooks/useCountdown.js +80 -0
  220. package/lib/hooks/useDigitInput.js +105 -0
  221. package/lib/hooks/useDismiss.js +71 -0
  222. package/lib/hooks/useElapsed.js +83 -0
  223. package/lib/hooks/useFloating.js +70 -0
  224. package/lib/hooks/useFocusTrap.js +61 -0
  225. package/lib/hooks/usePresence.js +60 -0
  226. package/lib/hooks/usePressToOpen.js +69 -0
  227. package/lib/hooks/useScrollLock.js +70 -0
  228. package/lib/hooks/useSelection.js +68 -0
  229. package/lib/index.js +178 -0
  230. package/lib/primitives/AspectRatio2.js +80 -0
  231. package/lib/primitives/BrandIcon.js +245 -0
  232. package/lib/primitives/ColorDot2.js +70 -0
  233. package/lib/primitives/CopyButton2.js +85 -0
  234. package/lib/primitives/CountBadge2.js +78 -0
  235. package/lib/primitives/Countdown2.js +65 -0
  236. package/lib/primitives/Delta2.js +67 -0
  237. package/lib/primitives/Elapsed.js +62 -0
  238. package/lib/primitives/FileIcon2.js +125 -0
  239. package/lib/primitives/Flag2.js +263 -0
  240. package/lib/primitives/IconStack2.js +85 -0
  241. package/lib/primitives/IconTile2.js +68 -0
  242. package/lib/primitives/Kbd2.js +88 -0
  243. package/lib/primitives/Layout2.js +118 -0
  244. package/lib/primitives/Link2.js +53 -0
  245. package/lib/primitives/MaskedText2.js +120 -0
  246. package/lib/primitives/Progress2.js +137 -0
  247. package/lib/primitives/RelativeTime.js +84 -0
  248. package/lib/primitives/SearchInput2.js +84 -0
  249. package/lib/primitives/SelectorButton2.js +97 -0
  250. package/lib/primitives/Spinner2.js +98 -0
  251. package/lib/primitives/StatusIcon2.js +126 -0
  252. package/lib/primitives/Swatch2.js +79 -0
  253. package/lib/primitives/Tooltip2.js +132 -0
  254. package/lib/primitives/Typography2.js +97 -0
  255. package/lib/primitives/formatCountdown.js +51 -0
  256. package/lib/primitives/formatElapsed.js +66 -0
  257. package/lib/primitives/formatRelativeTime.js +64 -0
  258. package/lib/primitives/hotkey.js +94 -0
  259. package/lib/primitives/index.js +352 -0
  260. package/lib/primitives/maskValue.js +65 -0
  261. package/lib/style.css +2 -0
  262. package/lib/types/components/Accordion/Accordion.d.ts +57 -0
  263. package/lib/types/components/ActionBar/ActionBar.d.ts +24 -0
  264. package/lib/types/components/Alert/Alert.d.ts +36 -0
  265. package/lib/types/components/AppShell/AppShell.d.ts +38 -0
  266. package/lib/types/components/AreaChart/AreaChart.d.ts +17 -0
  267. package/lib/types/components/BarChart/BarChart.d.ts +57 -0
  268. package/lib/types/components/BarList/BarList.d.ts +56 -0
  269. package/lib/types/components/Breadcrumb/Breadcrumb.d.ts +15 -0
  270. package/lib/types/components/Calendar/Calendar.d.ts +34 -0
  271. package/lib/types/components/Calendar/DatePicker.d.ts +45 -0
  272. package/lib/types/components/Calendar/date.d.ts +32 -0
  273. package/lib/types/components/Card/Card.d.ts +64 -0
  274. package/lib/types/components/CardFrame/CardFrame.d.ts +15 -0
  275. package/lib/types/components/Chart/ChartParts.d.ts +38 -0
  276. package/lib/types/components/Chart/chart.d.ts +46 -0
  277. package/lib/types/components/Chart/useChartInteraction.d.ts +39 -0
  278. package/lib/types/components/ChatBubble/ChatBubble.d.ts +61 -0
  279. package/lib/types/components/ChatBubble/formatChatTime.d.ts +2 -0
  280. package/lib/types/components/ChatComposer/ChatComposer.d.ts +42 -0
  281. package/lib/types/components/CodeBlock/CodeBlock.d.ts +18 -0
  282. package/lib/types/components/CodeBlock/highlight.d.ts +10 -0
  283. package/lib/types/components/ColorPicker/ColorPicker.d.ts +61 -0
  284. package/lib/types/components/ColorPicker/color.d.ts +48 -0
  285. package/lib/types/components/ColorPicker/presets.d.ts +7 -0
  286. package/lib/types/components/Combobox/Combobox.d.ts +48 -0
  287. package/lib/types/components/CommandMenu/CommandMenu.d.ts +51 -0
  288. package/lib/types/components/Comment/Comment.d.ts +45 -0
  289. package/lib/types/components/ContextMenu/ContextMenu.d.ts +40 -0
  290. package/lib/types/components/DataGrid/DataGrid.d.ts +43 -0
  291. package/lib/types/components/DataGrid/GridPopover.d.ts +43 -0
  292. package/lib/types/components/DataGrid/anchor.d.ts +5 -0
  293. package/lib/types/components/DataGrid/model.d.ts +61 -0
  294. package/lib/types/components/DataGrid/panels.d.ts +63 -0
  295. package/lib/types/components/DataGrid/typeMeta.d.ts +6 -0
  296. package/lib/types/components/DataGrid/types.d.ts +77 -0
  297. package/lib/types/components/DescriptionList/DescriptionList.d.ts +77 -0
  298. package/lib/types/components/Dialog/AlertDialog.d.ts +26 -0
  299. package/lib/types/components/Dialog/Dialog.d.ts +42 -0
  300. package/lib/types/components/Dialog/modal.d.ts +38 -0
  301. package/lib/types/components/Drawer/Drawer.d.ts +62 -0
  302. package/lib/types/components/DropdownMenu/DropdownMenu.d.ts +97 -0
  303. package/lib/types/components/DropdownMenu/menuCore.d.ts +23 -0
  304. package/lib/types/components/Dropzone/Dropzone.d.ts +30 -0
  305. package/lib/types/components/EmptyState/EmptyState.d.ts +26 -0
  306. package/lib/types/components/FileChip/FileChip.d.ts +32 -0
  307. package/lib/types/components/FileUpload/FileUpload.d.ts +52 -0
  308. package/lib/types/components/FilterChips/FilterChips.d.ts +37 -0
  309. package/lib/types/components/FunnelChart/FunnelChart.d.ts +38 -0
  310. package/lib/types/components/FunnelChart/funnel.d.ts +25 -0
  311. package/lib/types/components/Highlight/Highlight.d.ts +35 -0
  312. package/lib/types/components/HoverCard/HoverCard.d.ts +47 -0
  313. package/lib/types/components/InlineDiff/InlineDiff.d.ts +36 -0
  314. package/lib/types/components/InlineDiff/diff.d.ts +42 -0
  315. package/lib/types/components/InlineDiff/useDiffReview.d.ts +57 -0
  316. package/lib/types/components/Kanban/Kanban.d.ts +64 -0
  317. package/lib/types/components/Kanban/KanbanCard.d.ts +35 -0
  318. package/lib/types/components/Kanban/move.d.ts +25 -0
  319. package/lib/types/components/LineChart/LineChart.d.ts +85 -0
  320. package/lib/types/components/List/List.d.ts +62 -0
  321. package/lib/types/components/Listbox/Listbox.d.ts +60 -0
  322. package/lib/types/components/Marker/Marker.d.ts +28 -0
  323. package/lib/types/components/Menubar/Menubar.d.ts +50 -0
  324. package/lib/types/components/MultiSelect/MultiSelect.d.ts +38 -0
  325. package/lib/types/components/NavigationMenu/NavigationMenu.d.ts +101 -0
  326. package/lib/types/components/NoticeStack/NoticeStack.d.ts +41 -0
  327. package/lib/types/components/NumberStepper/NumberStepper.d.ts +32 -0
  328. package/lib/types/components/OtpInput/OtpInput.d.ts +31 -0
  329. package/lib/types/components/Pagination/Pagination.d.ts +54 -0
  330. package/lib/types/components/Pagination/paginationRange.d.ts +7 -0
  331. package/lib/types/components/PhoneInput/PhoneInput.d.ts +47 -0
  332. package/lib/types/components/PieChart/PieChart.d.ts +67 -0
  333. package/lib/types/components/PieChart/arc.d.ts +26 -0
  334. package/lib/types/components/PieChart/useArcTween.d.ts +15 -0
  335. package/lib/types/components/Popover/Popover.d.ts +28 -0
  336. package/lib/types/components/ProgressTracker/ProgressTracker.d.ts +64 -0
  337. package/lib/types/components/Rating/Rating.d.ts +42 -0
  338. package/lib/types/components/Resizable/Resizable.d.ts +50 -0
  339. package/lib/types/components/Resizable/layout.d.ts +31 -0
  340. package/lib/types/components/ScaledPreview/ScaledPreview.d.ts +38 -0
  341. package/lib/types/components/ScatterChart/ScatterChart.d.ts +81 -0
  342. package/lib/types/components/ScatterChart/scatter.d.ts +14 -0
  343. package/lib/types/components/ScrollArea/ScrollArea.d.ts +34 -0
  344. package/lib/types/components/Select/Select.d.ts +39 -0
  345. package/lib/types/components/Sidebar/Sidebar.d.ts +39 -0
  346. package/lib/types/components/Skeleton/Skeleton.d.ts +47 -0
  347. package/lib/types/components/Slider/Slider.d.ts +36 -0
  348. package/lib/types/components/SocialLoginButton/SocialLoginButton.d.ts +10 -0
  349. package/lib/types/components/SparkChart/SparkChart.d.ts +55 -0
  350. package/lib/types/components/SparkChart/spark.d.ts +16 -0
  351. package/lib/types/components/Sparkbar/Sparkbar.d.ts +39 -0
  352. package/lib/types/components/SplitView/SplitView.d.ts +31 -0
  353. package/lib/types/components/Stat/Stat.d.ts +58 -0
  354. package/lib/types/components/StepList/StepList.d.ts +61 -0
  355. package/lib/types/components/Table/Table.d.ts +39 -0
  356. package/lib/types/components/Tabs/Tabs.d.ts +47 -0
  357. package/lib/types/components/TagInput/TagInput.d.ts +46 -0
  358. package/lib/types/components/TimePicker/TimePicker.d.ts +43 -0
  359. package/lib/types/components/TimePicker/time.d.ts +15 -0
  360. package/lib/types/components/Timeline/Timeline.d.ts +154 -0
  361. package/lib/types/components/Timeline/scale.d.ts +22 -0
  362. package/lib/types/components/Toast/Toaster.d.ts +19 -0
  363. package/lib/types/components/Toast/index.d.ts +4 -0
  364. package/lib/types/components/Toast/store.d.ts +75 -0
  365. package/lib/types/components/ToggleGroup/ToggleGroup.d.ts +28 -0
  366. package/lib/types/components/Toolbar/Toolbar.d.ts +70 -0
  367. package/lib/types/components/Tracker/Tracker.d.ts +43 -0
  368. package/lib/types/components/TreeDiagram/TreeDiagram.d.ts +68 -0
  369. package/lib/types/components/TreeView/TreeView.d.ts +107 -0
  370. package/lib/types/components/index.d.ts +188 -0
  371. package/lib/types/hooks/index.d.ts +17 -0
  372. package/lib/types/hooks/timing.d.ts +29 -0
  373. package/lib/types/hooks/useControllableState.d.ts +5 -0
  374. package/lib/types/hooks/useCountdown.d.ts +19 -0
  375. package/lib/types/hooks/useDigitInput.d.ts +24 -0
  376. package/lib/types/hooks/useDismiss.d.ts +3 -0
  377. package/lib/types/hooks/useElapsed.d.ts +28 -0
  378. package/lib/types/hooks/useFloating.d.ts +21 -0
  379. package/lib/types/hooks/useFocusTrap.d.ts +7 -0
  380. package/lib/types/hooks/usePresence.d.ts +8 -0
  381. package/lib/types/hooks/usePressToOpen.d.ts +20 -0
  382. package/lib/types/hooks/useScrollLock.d.ts +2 -0
  383. package/lib/types/hooks/useSelection.d.ts +29 -0
  384. package/lib/types/index.d.ts +5 -0
  385. package/lib/types/primitives/AspectRatio.d.ts +14 -0
  386. package/lib/types/primitives/BrandIcon.d.ts +12 -0
  387. package/lib/types/primitives/ColorDot.d.ts +20 -0
  388. package/lib/types/primitives/CopyButton.d.ts +12 -0
  389. package/lib/types/primitives/CountBadge.d.ts +28 -0
  390. package/lib/types/primitives/Countdown.d.ts +21 -0
  391. package/lib/types/primitives/Delta.d.ts +33 -0
  392. package/lib/types/primitives/Elapsed.d.ts +23 -0
  393. package/lib/types/primitives/FileIcon.d.ts +17 -0
  394. package/lib/types/primitives/Flag.d.ts +15 -0
  395. package/lib/types/primitives/IconStack.d.ts +27 -0
  396. package/lib/types/primitives/IconTile.d.ts +24 -0
  397. package/lib/types/primitives/Kbd.d.ts +19 -0
  398. package/lib/types/primitives/Layout.d.ts +64 -0
  399. package/lib/types/primitives/Link.d.ts +12 -0
  400. package/lib/types/primitives/MaskedText.d.ts +28 -0
  401. package/lib/types/primitives/Progress.d.ts +52 -0
  402. package/lib/types/primitives/RelativeTime.d.ts +22 -0
  403. package/lib/types/primitives/SearchInput.d.ts +8 -0
  404. package/lib/types/primitives/SelectorButton.d.ts +23 -0
  405. package/lib/types/primitives/Spinner.d.ts +15 -0
  406. package/lib/types/primitives/StatusIcon.d.ts +40 -0
  407. package/lib/types/primitives/Swatch.d.ts +11 -0
  408. package/lib/types/primitives/Tooltip.d.ts +17 -0
  409. package/lib/types/primitives/Typography.d.ts +48 -0
  410. package/lib/types/primitives/formatCountdown.d.ts +2 -0
  411. package/lib/types/primitives/formatElapsed.d.ts +8 -0
  412. package/lib/types/primitives/formatRelativeTime.d.ts +16 -0
  413. package/lib/types/primitives/hotkey.d.ts +10 -0
  414. package/lib/types/primitives/index.d.ts +188 -0
  415. package/lib/types/primitives/maskValue.d.ts +24 -0
  416. package/package.json +55 -4
@@ -0,0 +1,227 @@
1
+ # CardFrame
2
+
3
+ > 컨테이너 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 흰 Card를 옅은 회색 판으로 한 번 더 감싸는 틀. 카드는 내용 그대로 두고, 몇 단계인지 · 얼마나 진행됐는지 같은 맥락은 카드 바깥 회색 위의 header · footer 줄에 둬요. 회색 테두리 4px + 카드 모서리 16px = 바깥 모서리 20px라 모서리가 겹쳐 보이지 않아요.
6
+
7
+ ```tsx
8
+ import { CardFrame } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 카드를 회색 판으로 한 번 더 감싸고 맥락(몇 단계 · 어떤 도구 · 진행 상태)을 카드 바깥에 둘 땐 `CardFrame`(`header` 캡션 / `footer` 상태 줄, `--surface-active` 판 + 4px 테두리 + 바깥 모서리 20px로 카드 16px와 겹치지 않게). 카드 안쪽 아래 띠는 여전히 `CardFooter band`.
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
+ ### CardFrame
19
+
20
+ | prop | 타입 | 기본값 | 설명 |
21
+ | --- | --- | --- | --- |
22
+ | `header` | `ReactNode` | | 카드 위 회색 캡션 줄. 자식이 둘이면 양 끝으로 벌어져요. |
23
+ | `footer` | `ReactNode` | | 카드 아래 회색 상태 줄. 자식이 둘이면 양 끝으로 벌어져요. |
24
+ | `children` | `ReactNode` | | 보통 Card 하나. |
25
+
26
+ ## 예제
27
+
28
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
29
+
30
+ ### 아래 상태 줄
31
+
32
+ footer에 진행 상태와 경과 시간. 두 요소를 넣으면 양 끝으로 벌어져요. 안쪽은 Card + CardHeader + StepList 그대로예요.
33
+
34
+ ```tsx
35
+ import { ListChecks } from 'lucide-react'
36
+ import { Elapsed, Inline, StatusIcon, Text, formatElapsed, Card, CardBody, CardFrame, CardHeader, StepList, type StepListStep } from '@iamfiro/design'
37
+
38
+ const STEPS: StepListStep[] = [
39
+ {
40
+ id: 'pull',
41
+ status: 'done',
42
+ title: '3분기 매출 · 이탈률 가져오기',
43
+ description: (
44
+ <>
45
+ Stripe에서 7월 ~ 9월 <Text variant="code">stripe.query</Text>
46
+ </>
47
+ ),
48
+ meta: '2.1초',
49
+ },
50
+ {
51
+ id: 'read',
52
+ status: 'done',
53
+ title: '지난 분기 이사회 메모 읽기',
54
+ description: (
55
+ <>
56
+ 이사회에 익숙한 구성을 유지 <Text variant="code">search</Text>
57
+ </>
58
+ ),
59
+ meta: '2.5초',
60
+ },
61
+ {
62
+ id: 'draft',
63
+ status: 'active',
64
+ title: '메모 초안 고치기',
65
+ description: (
66
+ <>
67
+ 매출 · 이탈률 · 4분기 전망 <Text variant="code">docs.write</Text>
68
+ </>
69
+ ),
70
+ meta: <Elapsed initial={3} format={(s) => formatElapsed(s, 'text')} />,
71
+ },
72
+ {
73
+ id: 'send',
74
+ status: 'pending',
75
+ title: '김민지 님에게 초안 보내기',
76
+ description: (
77
+ <>
78
+ 먼저 승인이 필요해요 <Text variant="code">gmail.send</Text>
79
+ </>
80
+ ),
81
+ },
82
+ {
83
+ id: 'book',
84
+ status: 'pending',
85
+ title: '김민지 님과 검토 일정 잡기',
86
+ description: (
87
+ <>
88
+ 이사회 30분 전 <Text variant="code">calendar.create</Text>
89
+ </>
90
+ ),
91
+ },
92
+ ]
93
+
94
+ export default function Example() {
95
+ const done = STEPS.filter((s) => s.status === 'done').length
96
+ return (
97
+ <CardFrame
98
+ style={{ width: '100%', maxWidth: 560 }}
99
+ footer={
100
+ <>
101
+ <Inline gap={2} wrap={false}>
102
+ <StatusIcon status="active" size="sm" decorative />
103
+ <Text variant="label-sm" tone="secondary" numeric>
104
+ 실행 중 · {done + 1}/{STEPS.length}
105
+ </Text>
106
+ </Inline>
107
+ <Text variant="label-sm" tone="tertiary">
108
+ <Elapsed initial={5} />
109
+ </Text>
110
+ </>
111
+ }
112
+ >
113
+ <Card>
114
+ <CardHeader
115
+ eyebrow={
116
+ <Inline gap={1} wrap={false}>
117
+ <ListChecks size={14} aria-hidden />
118
+ 계획 · {STEPS.length}단계
119
+ </Inline>
120
+ }
121
+ title="3분기 이사회 보고 준비"
122
+ />
123
+ <CardBody>
124
+ <StepList steps={STEPS} marker="status-number" aria-label="이사회 보고 준비 단계" />
125
+ </CardBody>
126
+ </Card>
127
+ </CardFrame>
128
+ )
129
+ }
130
+ ```
131
+
132
+ ### 위 캡션
133
+
134
+ header에 어느 단계 · 어떤 도구인지 적고, 안쪽 카드엔 승인 내용(IconTile · Badge · DescriptionList soft · 버튼)만 둬요.
135
+
136
+ ```tsx
137
+ import { Mail } from 'lucide-react'
138
+ import { Badge, Button, IconTile, Text, Card, CardBody, CardFooter, CardFrame, CardHeader, DescriptionItem, DescriptionList, toast } from '@iamfiro/design'
139
+
140
+ export default function Example() {
141
+ return (
142
+ <CardFrame
143
+ style={{ width: '100%', maxWidth: 360 }}
144
+ header={
145
+ <Text variant="label-sm" tone="tertiary">
146
+ 4단계 · <Text variant="code">gmail.send</Text>
147
+ </Text>
148
+ }
149
+ >
150
+ <Card padding="sm">
151
+ <CardHeader
152
+ icon={
153
+ <IconTile>
154
+ <Mail />
155
+ </IconTile>
156
+ }
157
+ title="김민지 님에게 초안 보내기"
158
+ description="3분기 이사회 메모를 메일로 보내요."
159
+ actions={
160
+ <Badge tone="warning" dot size="sm">
161
+ 보통
162
+ </Badge>
163
+ }
164
+ />
165
+ <CardBody>
166
+ <DescriptionList layout="inline" align="start" variant="soft" labelStyle="muted" size="sm" aria-label="보낼 메일">
167
+ <DescriptionItem label="받는 사람">김민지 (CFO)</DescriptionItem>
168
+ <DescriptionItem label="제목">3분기 이사회 보고 – 초안</DescriptionItem>
169
+ <DescriptionItem label="첨부">이사회 메모 – 2026년 3분기</DescriptionItem>
170
+ </DescriptionList>
171
+ </CardBody>
172
+ <CardFooter>
173
+ <Button size="sm" variant="secondary" onClick={() => toast('발송을 거절했어요')}>
174
+ 거절
175
+ </Button>
176
+ <Button size="sm" variant="primary" onClick={() => toast.success('초안을 보냈어요')}>
177
+ 승인
178
+ </Button>
179
+ </CardFooter>
180
+ </Card>
181
+ </CardFrame>
182
+ )
183
+ }
184
+ ```
185
+
186
+ ### 위 · 아래 함께
187
+
188
+ header와 footer를 같이 쓸 수 있어요.
189
+
190
+ ```tsx
191
+ import { Sparkles } from 'lucide-react'
192
+ import { Badge, Inline, RelativeTime, Text, Card, CardBody, CardFrame } from '@iamfiro/design'
193
+
194
+ const SAVED_AT = new Date(Date.now() - 2 * 60_000)
195
+
196
+ export default function Example() {
197
+ return (
198
+ <CardFrame
199
+ style={{ width: '100%', maxWidth: 420 }}
200
+ header={
201
+ <>
202
+ <Inline gap={1} wrap={false}>
203
+ <Sparkles size={14} aria-hidden />
204
+ <Text variant="label-sm" tone="tertiary">
205
+ 이사회 메모 – 3분기 · 매출
206
+ </Text>
207
+ </Inline>
208
+ <Badge size="sm" tone="accent">
209
+ 제안 3개
210
+ </Badge>
211
+ </>
212
+ }
213
+ footer={
214
+ <Text variant="label-sm" tone="tertiary">
215
+ <RelativeTime date={SAVED_AT} /> 자동 저장됨
216
+ </Text>
217
+ }
218
+ >
219
+ <Card>
220
+ <CardBody>
221
+ 3분기 매출은 전 분기보다 12% 늘어난 48억 원이에요. 이탈률은 2.1%로 목표보다 낮게 유지됐고, 4분기에는 신규 요금제 효과로 성장이 이어질 것으로 보여요.
222
+ </CardBody>
223
+ </Card>
224
+ </CardFrame>
225
+ )
226
+ }
227
+ ```
@@ -0,0 +1,266 @@
1
+ # ChatBubble
2
+
3
+ > 대화 & 활동 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 채팅 메시지 한 개를 채워진 말풍선으로 보여 줘요. 상대 메시지는 왼쪽 회색, 내 메시지는 오른쪽 파랑. ChatBubbleGroup으로 한 사람이 이어 보낸 메시지를 묶으면 이웃한 모서리가 좁아져 한 줄기로 읽히고, 시간 · 읽음 표시는 마지막 말풍선 옆에만 붙어요. 보내는 중(pending)은 옅게, 실패하면 빨간 글자와 "다시 보내기"가 나타나요.
6
+
7
+ ```tsx
8
+ import { ChatBubble, ChatBubbleGroup } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 채팅(메신저형)은 `ChatBubble` + `ChatBubbleGroup`: 상대 = 왼쪽 회색(`--surface-active`), 나 = 오른쪽 파랑(`--accent`), 테두리 없이 채움만. 한 사람의 연속 메시지는 그룹으로 묶어 이웃한 모서리만 좁히고(`--r-lg` → `--r-xs`), 시간("오후 3:12", `formatChatTime`) · 읽음 체크는 마지막 말풍선 옆에만. 보내는 중 = 옅은 말풍선 + Spinner, 실패 = 빨간 글자 + "다시 보내기"(테두리 X). 새 메시지는 `appear`, 입력 중은 `typing`.
14
+
15
+ ## API
16
+
17
+ ### ChatBubble
18
+
19
+ | prop | 타입 | 기본값 | 설명 |
20
+ | --- | --- | --- | --- |
21
+ | `children` | `ReactNode` | | 메시지 내용. 줄바꿈이 그대로 보여요. |
22
+ | `side` | `'start' \| 'end'` | `그룹의 side 또는 'start'` | start = 상대(왼쪽), end = 나(오른쪽). |
23
+ | `tone` | `'neutral' \| 'accent' \| 'primary'` | `start → neutral, end → accent` | 말풍선 채움 색. |
24
+ | `time` | `Date \| string \| number` | | 보낸 시각. "오후 3:12"처럼 보이고, 올리면 전체 날짜가 나와요. 묶음의 마지막 말풍선에만 보여요. |
25
+ | `status` | `'sending' \| 'sent' \| 'read' \| 'failed'` | | 전송 상태. 보내는 중 · 실패는 묶음 위치와 상관없이 항상 보여요. |
26
+ | `onRetry` | `() => void` | | failed일 때 "다시 보내기" 버튼을 눌렀을 때. |
27
+ | `typing` | `boolean` | | 내용 대신 움직이는 점 세 개(입력 중). |
28
+ | `actions` | `ReactNode` | | 말풍선 옆 버튼(반응, 답장, 더 보기). hover · focus 때 나타나요. |
29
+ | `footer` | `ReactNode` | | 말풍선 아래(반응, 첨부, 링크 미리보기). |
30
+ | `appear` | `boolean` | | 마운트될 때 아래에서 떠오르기 — 방금 도착한 메시지에. |
31
+ | `position` | `'single' \| 'first' \| 'middle' \| 'last'` | | ChatBubbleGroup이 정해 줘요. 그룹 밖에서 쓸 때만 직접 넘겨요. |
32
+ | `className / style` | `string / CSSProperties` | | 바깥 요소에 전달. |
33
+
34
+ ### ChatBubbleGroup
35
+
36
+ ChatBubble.Group으로도 쓸 수 있어요. 시간 글자("오후 3:12")만 필요하면 formatChatTime(date).
37
+
38
+ | prop | 타입 | 기본값 | 설명 |
39
+ | --- | --- | --- | --- |
40
+ | `children` (필수) | `ReactNode` | | ChatBubble들(오래된 것부터). |
41
+ | `author` | `ReactNode` | | 보낸 사람. 시작 쪽에서 문자열이면 Avatar와 이름을 그려요. |
42
+ | `side` | `'start' \| 'end'` | `'start'` | 묶음 전체의 방향. |
43
+ | `avatar` | `ReactNode` | | 기본 아바타 대신. null이면 자리만 비워 두어 정렬을 유지해요. |
44
+ | `showName` | `boolean` | `side === 'start'` | 첫 말풍선 위의 이름. 1:1 대화에선 끄세요. |
45
+ | `avatarSize` | `number` | `28` | 아바타 크기(px). |
46
+ | `className / style` | `string / CSSProperties` | | 바깥 요소에 전달. |
47
+
48
+ ## 예제
49
+
50
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
51
+
52
+ ### 1:1 대화
53
+
54
+ Card 안에 ChatBubbleGroup · Marker(날짜) · ChatComposer를 조립했어요. 메시지를 보내면 보내는 중 → 전송됨 → 읽음으로 바뀌고, 상대가 입력 중(typing)이다가 답장해요. 새 메시지는 appear로 제 모서리에서 떠올라요.
55
+
56
+ ```tsx
57
+ import { useEffect, useRef, useState } from 'react'
58
+ import { Stack, Text, Card, CardBody, CardHeader, ChatBubble, ChatBubbleGroup, ChatComposer, Marker, type ChatBubbleStatus } from '@iamfiro/design'
59
+
60
+ const minutesAgo = (m: number) => new Date(Date.now() - m * 60_000)
61
+
62
+ interface Message {
63
+ id: string
64
+ side: 'start' | 'end'
65
+ text: string
66
+ time: Date
67
+ status?: ChatBubbleStatus
68
+ fresh?: boolean
69
+ }
70
+
71
+ const INITIAL: Message[] = [
72
+ { id: '1', side: 'start', text: '민지 씨, 내일 디자인 리뷰 몇 시였죠?', time: minutesAgo(14) },
73
+ { id: '2', side: 'start', text: '회의실 예약을 아직 안 해서요', time: minutesAgo(14) },
74
+ { id: '3', side: 'end', text: '오후 2시예요!', time: minutesAgo(12), status: 'read' },
75
+ { id: '4', side: 'end', text: '3층 큰 회의실로 잡아 주시면 좋겠어요', time: minutesAgo(12), status: 'read' },
76
+ ]
77
+
78
+ /** Consecutive messages from the same side become one group. */
79
+ function groupRuns(messages: Message[]) {
80
+ const runs: Message[][] = []
81
+ for (const m of messages) {
82
+ const run = runs[runs.length - 1]
83
+ if (run && run[0].side === m.side) run.push(m)
84
+ else runs.push([m])
85
+ }
86
+ return runs
87
+ }
88
+
89
+ export default function Example() {
90
+ const [messages, setMessages] = useState(INITIAL)
91
+ const [typing, setTyping] = useState(false)
92
+ const timers = useRef<number[]>([])
93
+
94
+ useEffect(() => () => timers.current.forEach((t) => window.clearTimeout(t)), [])
95
+
96
+ const later = (ms: number, fn: () => void) => timers.current.push(window.setTimeout(fn, ms))
97
+ const setStatus = (id: string, status: ChatBubbleStatus) => setMessages((prev) => prev.map((m) => (m.id === id ? { ...m, status } : m)))
98
+
99
+ const send = (text: string) => {
100
+ const id = String(Date.now())
101
+ setMessages((prev) => [...prev, { id, side: 'end', text, time: new Date(), status: 'sending', fresh: true }])
102
+ later(700, () => setStatus(id, 'sent'))
103
+ later(1600, () => {
104
+ setStatus(id, 'read')
105
+ setTyping(true)
106
+ })
107
+ later(3400, () => {
108
+ setTyping(false)
109
+ setMessages((prev) => [...prev, { id: `${id}-r`, side: 'start', text: '네, 확인했어요. 바로 예약할게요 👍', time: new Date(), fresh: true }])
110
+ })
111
+ }
112
+
113
+ const runs = groupRuns(messages)
114
+ const lastSide = runs[runs.length - 1][0].side
115
+
116
+ return (
117
+ <Card padding="sm" style={{ width: 400 }}>
118
+ <CardHeader title={<Text variant="label-md">이도현</Text>} />
119
+ <CardBody>
120
+ <Stack gap={4}>
121
+ <Stack gap={4} aria-live="polite">
122
+ <Marker>오늘</Marker>
123
+ {runs.map((run, i) => (
124
+ <ChatBubbleGroup key={run[0].id} side={run[0].side} author="이도현" showName={false}>
125
+ {run.map((m) => (
126
+ <ChatBubble key={m.id} time={m.time} status={m.status} appear={m.fresh}>
127
+ {m.text}
128
+ </ChatBubble>
129
+ ))}
130
+ {/* "입력 중" joins the other person's run when they spoke last. */}
131
+ {typing && i === runs.length - 1 && lastSide === 'start' && <ChatBubble key="typing" typing appear />}
132
+ </ChatBubbleGroup>
133
+ ))}
134
+ {typing && lastSide === 'end' && (
135
+ <ChatBubbleGroup author="이도현" showName={false}>
136
+ <ChatBubble typing appear />
137
+ </ChatBubbleGroup>
138
+ )}
139
+ </Stack>
140
+ <ChatComposer size="sm" placeholder="메시지 입력" aria-label="메시지" onSubmit={send} />
141
+ </Stack>
142
+ </CardBody>
143
+ </Card>
144
+ )
145
+ }
146
+ ```
147
+
148
+ ### 그룹 대화
149
+
150
+ 시작 쪽 그룹은 이름과 아바타를 보여 줘요. 아바타는 첫 말풍선 옆, 시간은 마지막 말풍선 옆에 붙어요.
151
+
152
+ ```tsx
153
+ import { Stack, ChatBubble, ChatBubbleGroup, Marker } from '@iamfiro/design'
154
+
155
+ const at = (h: number, m: number) => new Date(2026, 9, 25, h, m)
156
+
157
+ export default function Example() {
158
+ return (
159
+ <Stack gap={4} style={{ width: '100%', maxWidth: 420 }}>
160
+ <Marker>10월 25일 일요일</Marker>
161
+ <ChatBubbleGroup author="김민지">
162
+ <ChatBubble time={at(15, 2)}>배포 끝났어요 🎉</ChatBubble>
163
+ </ChatBubbleGroup>
164
+ <ChatBubbleGroup author="박서준">
165
+ <ChatBubble>수고하셨어요!</ChatBubble>
166
+ <ChatBubble>혹시 변경 로그도 올라갔나요?</ChatBubble>
167
+ <ChatBubble time={at(15, 4)}>고객 공지에 링크를 걸어야 해서요</ChatBubble>
168
+ </ChatBubbleGroup>
169
+ <ChatBubbleGroup side="end">
170
+ <ChatBubble>방금 올렸어요</ChatBubble>
171
+ <ChatBubble time={at(15, 5)} status="read">
172
+ docs/changelog 맨 위에 있어요
173
+ </ChatBubble>
174
+ </ChatBubbleGroup>
175
+ </Stack>
176
+ )
177
+ }
178
+ ```
179
+
180
+ ### 전송 상태
181
+
182
+ sending은 옅은 말풍선 + 스피너, sent는 체크, read는 파란 이중 체크. failed는 테두리 대신 빨간 글자와 다시 보내기 버튼이에요.
183
+
184
+ ```tsx
185
+ import { useEffect, useRef, useState } from 'react'
186
+ import { Stack, ChatBubble, ChatBubbleGroup, type ChatBubbleStatus } from '@iamfiro/design'
187
+
188
+ const NOW = new Date(2026, 9, 25, 16, 20)
189
+
190
+ export default function Example() {
191
+ const [status, setStatus] = useState<ChatBubbleStatus>('failed')
192
+ const timer = useRef(0)
193
+
194
+ useEffect(() => () => window.clearTimeout(timer.current), [])
195
+
196
+ const retry = () => {
197
+ setStatus('sending')
198
+ timer.current = window.setTimeout(() => setStatus('sent'), 1200)
199
+ }
200
+
201
+ return (
202
+ <Stack gap={4} style={{ width: '100%', maxWidth: 420 }}>
203
+ <ChatBubbleGroup side="end">
204
+ <ChatBubble time={NOW} status="read">
205
+ 읽음 — 파란 이중 체크
206
+ </ChatBubble>
207
+ </ChatBubbleGroup>
208
+ <ChatBubbleGroup side="end">
209
+ <ChatBubble time={NOW} status="sent">
210
+ 전송됨 — 회색 체크
211
+ </ChatBubble>
212
+ </ChatBubbleGroup>
213
+ <ChatBubbleGroup side="end">
214
+ <ChatBubble status="sending">보내는 중 — 옅은 말풍선</ChatBubble>
215
+ </ChatBubbleGroup>
216
+ <ChatBubbleGroup side="end">
217
+ <ChatBubble time={NOW} status={status} onRetry={retry}>
218
+ 네트워크가 끊겨서 못 보낸 메시지
219
+ </ChatBubble>
220
+ </ChatBubbleGroup>
221
+ </Stack>
222
+ )
223
+ }
224
+ ```
225
+
226
+ ### 색 · 액션 · 반응
227
+
228
+ tone(neutral · accent · primary), 마우스를 올리면 나타나는 actions, 말풍선 아래 footer(반응)를 보여 줘요.
229
+
230
+ ```tsx
231
+ import { useState } from 'react'
232
+ import { Reply, SmilePlus } from 'lucide-react'
233
+ import { Badge, Button, Stack, ChatBubble, ChatBubbleGroup } from '@iamfiro/design'
234
+
235
+ const NOW = new Date(2026, 9, 25, 9, 41)
236
+
237
+ export default function Example() {
238
+ const [liked, setLiked] = useState(false)
239
+
240
+ const actions = (
241
+ <>
242
+ <Button variant="ghost" size="sm" iconOnly icon={<SmilePlus />} aria-label="반응 남기기" onClick={() => setLiked((v) => !v)} />
243
+ <Button variant="ghost" size="sm" iconOnly icon={<Reply />} aria-label="답장" />
244
+ </>
245
+ )
246
+
247
+ return (
248
+ <Stack gap={4} style={{ width: '100%', maxWidth: 420 }}>
249
+ <ChatBubbleGroup author="이도현" showName={false}>
250
+ <ChatBubble time={NOW} actions={actions} footer={liked && <Badge>👍 1</Badge>}>
251
+ 올려 두면 반응 · 답장 버튼이 나타나요
252
+ </ChatBubble>
253
+ <ChatBubble typing />
254
+ </ChatBubbleGroup>
255
+ <ChatBubbleGroup side="end">
256
+ <ChatBubble time={NOW}>accent — 기본 내 메시지</ChatBubble>
257
+ </ChatBubbleGroup>
258
+ <ChatBubbleGroup side="end">
259
+ <ChatBubble tone="primary" time={NOW}>
260
+ primary — 검정 말풍선
261
+ </ChatBubble>
262
+ </ChatBubbleGroup>
263
+ </Stack>
264
+ )
265
+ }
266
+ ```