@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,261 @@
1
+ # Input
2
+
3
+ > 텍스트 입력 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 글자를 입력받는 기본 입력창과 Field · Textarea · NativeSelect. 포커스되면 연한 파란 테두리와 링이 바깥 칸에만 생기고, 오류는 빨간 테두리, 비활성은 회색 배경으로 구분해요.
6
+
7
+ ```tsx
8
+ import { Field, Input, Textarea, NativeSelect } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 다른 표면 안에 들어간 입력(ChatComposer의 글 칸)은 `Textarea bare`: **모든 상태(hover·focus·disabled)에서** 자체 테두리·배경·여백이 없어야 한다. 테두리·링·비활성 회색은 바깥 표면(`.ds-control`) 하나만 그린다. 상태별 리셋을 빠뜨리면 비활성일 때 안쪽 칸이 따로 보인다.
14
+
15
+ ## API
16
+
17
+ ### Input
18
+
19
+ 나머지 props는 안쪽 <input>에 전달돼요. ref도 <input>을 가리켜요.
20
+
21
+ | prop | 타입 | 기본값 | 설명 |
22
+ | --- | --- | --- | --- |
23
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 높이 36 / 44 / 52px. |
24
+ | `leading` | `ReactNode` | | 입력 앞 아이콘이나 글자. |
25
+ | `trailing` | `ReactNode` | | 입력 뒤 아이콘이나 글자. |
26
+ | `invalid` | `boolean` | | 오류 표시(빨간 테두리 + aria-invalid). |
27
+ | `disabled` | `boolean` | | 비활성(회색 배경, 금지 커서). |
28
+ | `bare` | `boolean` | | 테두리 · 배경 · 포커스 링 · 모서리 · 좌우 여백 없이(모든 상태). 명령 팔레트처럼 바깥 표면이 모양을 그릴 때. SearchInput에도 그대로 전달돼요. |
29
+ | `wrapperClassName` | `string` | | 바깥 칸(.ds-input)에 붙일 클래스. className은 <input>에 붙어요. |
30
+ | `wrapperStyle` | `CSSProperties` | | 바깥 칸 스타일. 너비 조절 등에 써요. |
31
+
32
+ ### Field
33
+
34
+ 라벨 · 입력 · 도움말을 세로로 묶어요.
35
+
36
+ | prop | 타입 | 기본값 | 설명 |
37
+ | --- | --- | --- | --- |
38
+ | `label` | `ReactNode` | | 라벨. |
39
+ | `hint` | `ReactNode` | | 아래 도움말. invalid면 오류 문구로 보여요. |
40
+ | `invalid` | `boolean` | | 도움말을 빨간색으로. |
41
+ | `htmlFor` | `string` | | 라벨과 연결할 입력의 id. |
42
+ | `children` (필수) | `ReactNode` | | 입력 요소. |
43
+
44
+ ### Textarea
45
+
46
+ <textarea>의 props를 그대로 받아요. 최소 높이 104px, 세로로만 늘릴 수 있어요. 오류는 aria-invalid.
47
+
48
+ | prop | 타입 | 기본값 | 설명 |
49
+ | --- | --- | --- | --- |
50
+ | `rows` | `number` | | 보이는 줄 수. |
51
+ | `autoResize` | `boolean` | | 글에 맞춰 높이가 자라요(한 줄에서 시작, 손잡이 없음). |
52
+ | `maxRows` | `number` | | autoResize일 때 최대 줄 수. 넘으면 스크롤. |
53
+ | `bare` | `boolean` | | 테두리 · 배경 · 여백 없이. 바깥 표면이 포커스를 그릴 때. |
54
+ | `aria-invalid` | `boolean` | | 오류 표시. |
55
+ | `disabled` | `boolean` | | 비활성. |
56
+
57
+ ### NativeSelect
58
+
59
+ <select>의 props를 그대로 받고 <option>을 children으로 넣어요. style은 바깥 칸에 적용돼요.
60
+
61
+ | prop | 타입 | 기본값 | 설명 |
62
+ | --- | --- | --- | --- |
63
+ | `children` (필수) | `ReactNode` | | <option> 목록. |
64
+ | `value / defaultValue` | `string` | | 선택값. |
65
+ | `onChange` | `(e: ChangeEvent<HTMLSelectElement>) => void` | | 값이 바뀔 때. |
66
+ | `disabled` | `boolean` | | 비활성. |
67
+ | `style` | `CSSProperties` | | 바깥 칸 스타일. |
68
+
69
+ ## 예제
70
+
71
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
72
+
73
+ ### 기본
74
+
75
+ Field로 감싸면 라벨과 도움말이 붙어요. htmlFor와 Input의 id를 맞추면 라벨을 눌러 포커스할 수 있어요.
76
+
77
+ ```tsx
78
+ import { Mail } from 'lucide-react'
79
+ import { Field, Input } from '@iamfiro/design'
80
+
81
+ export default function Example() {
82
+ return (
83
+ <div style={{ width: 320 }}>
84
+ <Field label="이메일" hint="이메일은 외부에 공유되지 않아요." htmlFor="signup-email">
85
+ <Input id="signup-email" type="email" placeholder="you@company.com" leading={<Mail />} />
86
+ </Field>
87
+ </div>
88
+ )
89
+ }
90
+ ```
91
+
92
+ ### 앞뒤 요소
93
+
94
+ leading · trailing에는 아이콘이나 짧은 글자(단위, 도메인)를 넣어요. 포커스되면 아이콘 색이 조금 진해져요.
95
+
96
+ ```tsx
97
+ import { useState } from 'react'
98
+ import { Link, Search } from 'lucide-react'
99
+ import { Field, Input, useDigitInput } from '@iamfiro/design'
100
+
101
+ const won = (digits: string) => (digits ? Number(digits).toLocaleString('ko-KR') : '')
102
+
103
+ export default function Example() {
104
+ const [budget, setBudget] = useState('1200000')
105
+ // Only digits get in; the commas follow as you type.
106
+ const budgetInput = useDigitInput({ digits: budget, onDigitsChange: setBudget, format: won, maxDigits: 12 })
107
+
108
+ return (
109
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 260px)', gap: 16 }}>
110
+ <Field label="워크스페이스 주소" htmlFor="ws-url">
111
+ <Input id="ws-url" leading={<Link />} trailing=".lumen.app" defaultValue="acme" />
112
+ </Field>
113
+ <Field label="월 예산" htmlFor="budget">
114
+ <Input id="budget" {...budgetInput} trailing="원" placeholder="0" style={{ textAlign: 'right' }} />
115
+ </Field>
116
+ <Field label="프로젝트 찾기" htmlFor="project-search">
117
+ <Input id="project-search" leading={<Search />} placeholder="이름으로 검색" />
118
+ </Field>
119
+ <Field label="웹사이트" htmlFor="website">
120
+ <Input id="website" leading="https://" placeholder="example.com" />
121
+ </Field>
122
+ </div>
123
+ )
124
+ }
125
+ ```
126
+
127
+ ### 크기와 상태
128
+
129
+ size는 높이 36 / 44 / 52px. Field와 Input 모두에 invalid를 주면 도움말도 빨갛게 바뀌어요.
130
+
131
+ ```tsx
132
+ import { Field, Input } from '@iamfiro/design'
133
+
134
+ export default function Example() {
135
+ return (
136
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 220px)', gap: 16 }}>
137
+ <Field label="작게 (sm)" htmlFor="name-sm">
138
+ <Input id="name-sm" size="sm" placeholder="높이 36px" />
139
+ </Field>
140
+ <Field label="기본 (md)" htmlFor="name-md">
141
+ <Input id="name-md" placeholder="높이 44px" />
142
+ </Field>
143
+ <Field label="크게 (lg)" htmlFor="name-lg">
144
+ <Input id="name-lg" size="lg" placeholder="높이 52px" />
145
+ </Field>
146
+ <Field label="워크스페이스 이름" invalid hint="이미 사용 중인 이름이에요." htmlFor="ws-name">
147
+ <Input id="ws-name" defaultValue="acme" invalid />
148
+ </Field>
149
+ <Field label="프로젝트 ID" hint="만든 뒤에는 바꿀 수 없어요." htmlFor="project-id">
150
+ <Input id="project-id" defaultValue="lumen-web" disabled />
151
+ </Field>
152
+ </div>
153
+ )
154
+ }
155
+ ```
156
+
157
+ ### 다른 표면 안의 입력 (bare)
158
+
159
+ bare면 테두리 · 배경 · 포커스 링 · 좌우 여백이 어떤 상태에서도 없어요. 명령 팔레트 검색 줄처럼 바깥 표면(Card)이 모양을 그리고, 좌우 여백도 바깥에서 정해요. 높이와 글자 크기는 size를 따라요.
160
+
161
+ ```tsx
162
+ import { useState } from 'react'
163
+ import { FileText, Search, Settings, Users } from 'lucide-react'
164
+ import { Box, IconTile, Input, Kbd, Separator, Card, List, ListItem } from '@iamfiro/design'
165
+
166
+ const items = [
167
+ { title: '10월 회의록', description: '문서 · 김민지', icon: <FileText /> },
168
+ { title: '팀원 관리', description: '설정 · 워크스페이스', icon: <Users /> },
169
+ { title: '알림 설정', description: '설정 · 내 계정', icon: <Settings /> },
170
+ ]
171
+
172
+ export default function Example() {
173
+ const [query, setQuery] = useState('')
174
+ const shown = items.filter((item) => item.title.includes(query.trim()))
175
+
176
+ return (
177
+ <Card padding="sm" style={{ maxWidth: 440 }}>
178
+ <Box paddingX={3}>
179
+ <Input
180
+ bare
181
+ size="lg"
182
+ type="search"
183
+ aria-label="명령 검색"
184
+ placeholder="무엇을 찾고 있나요?"
185
+ leading={<Search />}
186
+ trailing={<Kbd keys={['esc']} />}
187
+ value={query}
188
+ onChange={(e) => setQuery(e.target.value)}
189
+ />
190
+ </Box>
191
+ <Separator spacing={1} />
192
+ <List aria-label="검색 결과">
193
+ {shown.map((item) => (
194
+ <ListItem
195
+ key={item.title}
196
+ title={item.title}
197
+ description={item.description}
198
+ leading={<IconTile tone="surface">{item.icon}</IconTile>}
199
+ onClick={() => {}}
200
+ />
201
+ ))}
202
+ </List>
203
+ </Card>
204
+ )
205
+ }
206
+ ```
207
+
208
+ ### Textarea · NativeSelect
209
+
210
+ 여러 줄 입력과 브라우저 기본 select. Textarea의 오류는 aria-invalid로 표시해요. 검색·아이콘이 필요하면 Select를 쓰세요.
211
+
212
+ ```tsx
213
+ import { Field, NativeSelect, Textarea } from '@iamfiro/design'
214
+
215
+ export default function Example() {
216
+ return (
217
+ <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 280px)', gap: 16, alignItems: 'start' }}>
218
+ <div style={{ display: 'grid', gap: 16 }}>
219
+ <Field label="리전" htmlFor="region">
220
+ <NativeSelect id="region" defaultValue="icn">
221
+ <option value="icn">서울 (icn1)</option>
222
+ <option value="nrt">도쿄 (nrt1)</option>
223
+ <option value="sfo">샌프란시스코 (sfo1)</option>
224
+ </NativeSelect>
225
+ </Field>
226
+ <Field label="요금제" hint="관리자만 바꿀 수 있어요." htmlFor="plan">
227
+ <NativeSelect id="plan" defaultValue="team" disabled>
228
+ <option value="team">팀</option>
229
+ </NativeSelect>
230
+ </Field>
231
+ </div>
232
+ <div style={{ display: 'grid', gap: 16 }}>
233
+ <Field label="메모" htmlFor="memo">
234
+ <Textarea id="memo" placeholder="내용을 입력하세요" rows={3} />
235
+ </Field>
236
+ <Field label="취소 사유" invalid hint="10자 이상 입력해 주세요." htmlFor="reason">
237
+ <Textarea id="reason" defaultValue="일정 변경" aria-invalid />
238
+ </Field>
239
+ </div>
240
+ </div>
241
+ )
242
+ }
243
+ ```
244
+
245
+ ### Textarea 자동 높이
246
+
247
+ autoResize면 한 줄에서 시작해 글에 맞춰 자라고, maxRows를 넘으면 스크롤돼요. bare는 테두리·여백을 없애 다른 표면 안에 넣을 때 써요(ChatComposer).
248
+
249
+ ```tsx
250
+ import { Field, Textarea } from '@iamfiro/design'
251
+
252
+ export default function Example() {
253
+ return (
254
+ <div style={{ width: 360 }}>
255
+ <Field label="코멘트" hint="5줄까지 늘어나고, 그 뒤로는 스크롤돼요." htmlFor="comment">
256
+ <Textarea id="comment" autoResize maxRows={5} placeholder="여러 줄을 입력해 보세요" />
257
+ </Field>
258
+ </div>
259
+ )
260
+ }
261
+ ```
@@ -0,0 +1,352 @@
1
+ # Kanban
2
+
3
+ > 데이터 표시 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 열 사이로 카드를 끌어 옮기는 보드. 끌기 시작하면 카드 사본이 포인터를 따라오고, 놓일 자리에 빈칸이 열리며 다른 카드가 비켜서요. 놓는 순간 확정되고 사본이 제자리로 날아가 앉아요. Esc를 누르거나 받지 않는 열에서 놓으면 원래 자리로 돌아가요. 키보드(스페이스로 들고 화살표로 옮기기)와 터치(길게 눌러 끌기)도 같은 흐름이고, 모든 위치 변화는 이전 자리에서 미끄러지듯 움직여요.
6
+
7
+ ```tsx
8
+ import { KanbanBoard, KanbanCard, moveKanbanItem } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 열 사이로 카드를 옮기는 보드는 `KanbanBoard`(회색 레인 위 흰 카드, 기본 카드 면은 `KanbanCard`). 끌기 = 포인터를 따라오는 사본 + 놓일 자리 빈칸, 놓을 때 확정(`onValueChange`)하고 사본이 제자리로 날아가 앉는다. Esc · 거절 = 원래 자리로. 거절 이유는 `canMove`가 문자열로 돌려주면 열 안에 보인다. 진행 한도는 열 `limit`(차면 주황 · 넘으면 빨강, `limitMode="block"`이면 받지 않음). 키보드는 스페이스로 들고 화살표로 옮기기, 터치는 `TIMING.longPress`. 위치 변화는 모두 FLIP(offset 기준으로 재서 진행 중 transform에 흔들리지 않게).
14
+
15
+ ## API
16
+
17
+ ### KanbanBoard
18
+
19
+ | prop | 타입 | 기본값 | 설명 |
20
+ | --- | --- | --- | --- |
21
+ | `columns` (필수) | `KanbanColumn[]` | | { id, title, label?, description?, color?, limit?, limitMode? } 목록. 순서대로 왼쪽부터. |
22
+ | `value / defaultValue` | `Record<columnId, T[]>` | | 열마다 카드 목록(제어/비제어). T는 { id } 이상. |
23
+ | `onValueChange` | `(next, move) => void` | | 놓는 순간 한 번. move = { item, from, to }(index는 옮긴 카드를 뺀 기준). 끄는 동안의 미리보기에선 부르지 않아요. |
24
+ | `canMove` | `(move) => boolean \| string` | | 다른 열로 옮겨도 되는지. 문자열이면 거절 이유로 열 안에 보여요. 같은 열 안 순서 바꾸기는 언제나 허용. |
25
+ | `renderCard` | `(item, { dragging, lifted }) => ReactNode` | `<KanbanCard {...item} />` | 카드 면. dragging = 포인터를 따라오는 사본, lifted = 키보드로 들린 카드. |
26
+ | `onCardOpen` | `(item) => void` | | 클릭 또는 Enter. 끌기 뒤의 클릭은 무시해요. |
27
+ | `onCardAdd` | `(columnId, title) => void` | | 주면 열 아래 "카드 추가". Enter = 추가(칸은 열린 채), Shift+Enter = 줄바꿈, Esc = 닫기. 한글 조합 중 Enter는 무시. |
28
+ | `columnActions` | `(column) => ReactNode` | | 열 머리 오른쪽 버튼 · 메뉴. |
29
+ | `getItemLabel` | `(item) => string` | `item.title` | 안내 문구에 쓰는 카드 이름. |
30
+ | `columnWidth` | `number` | `288` | 열 폭(px). |
31
+ | `emptyLabel` | `ReactNode` | `'비어 있어요'` | 빈 열 문구. |
32
+ | `aria-label` | `string` | `'칸반 보드'` | 보드 이름. |
33
+
34
+ ### KanbanColumn
35
+
36
+ | prop | 타입 | 기본값 | 설명 |
37
+ | --- | --- | --- | --- |
38
+ | `limit` | `number` | | 진행 한도(WIP). 머리에 "2/3"으로, 차면 주황 · 넘으면 빨강. |
39
+ | `limitMode` | `'warn' \| 'block'` | `'warn'` | block이면 한도가 찬 열은 다른 열의 카드를 받지 않아요. |
40
+ | `color` | `string` | | 제목 앞 점 색. CSS 변수 이름('--chart-1') 또는 색. |
41
+ | `description` | `ReactNode` | | 제목 아래 회색 한 줄. |
42
+ | `label` | `string` | | title이 문자열이 아닐 때 안내 문구에 쓸 이름. |
43
+
44
+ ### KanbanCard
45
+
46
+ 기본 카드 면. Card · Stack · Inline · Text · Badge 조립.
47
+
48
+ | prop | 타입 | 기본값 | 설명 |
49
+ | --- | --- | --- | --- |
50
+ | `title` (필수) | `ReactNode` | | 최대 3줄. |
51
+ | `description` | `ReactNode` | | 회색 두 줄 요약. |
52
+ | `labels` | `{ label, tone? }[]` | | 제목 위 작은 Badge. |
53
+ | `assignees` | `string[]` | | 담당자 이름, 오른쪽 아래 겹친 Avatar(최대 3). |
54
+ | `due / dueTone` | `ReactNode / 'default' \| 'warning' \| 'danger'` | | 마감일. 임박 주황 · 지남 빨강. |
55
+ | `checklist` | `{ done, total }` | | 체크리스트 진행. 다 하면 초록. |
56
+ | `comments / attachments` | `number` | | 댓글 · 첨부 수. |
57
+ | `meta` | `ReactNode` | | 아래 줄에 덧붙일 것. |
58
+ | `dragging` | `boolean` | | 끌리는 사본(raised). |
59
+
60
+ ### moveKanbanItem
61
+
62
+ (value, id, to) => value. 보드 밖(서버 응답 · 실시간 동기화)에서 같은 규칙으로 카드를 옮길 때.
63
+
64
+ ## 예제
65
+
66
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
67
+
68
+ ### 프로젝트 보드
69
+
70
+ 카드를 끌어 열 사이로 옮겨 보세요. 옮기면 "실행 취소" 토스트가 떠요(⌘/Ctrl+Z). 열 아래 "카드 추가"는 Enter로 추가하고 칸이 열린 채 남아 연달아 쓸 수 있어요. 진행 중 열은 한도 3개 — 차면 주황, 넘으면 빨강이에요. 가장자리로 끌면 보드가 스크롤돼요.
71
+
72
+ ```tsx
73
+ import { useState } from 'react'
74
+ import { MoreHorizontal } from 'lucide-react'
75
+ import { Button, DropdownMenu, DropdownMenuItem, KanbanBoard, toast, type KanbanCardProps, type KanbanColumn, type KanbanValue } from '@iamfiro/design'
76
+
77
+ type Task = KanbanCardProps & { id: string }
78
+
79
+ const COLUMNS: KanbanColumn[] = [
80
+ { id: 'todo', title: '할 일', color: '--n6' },
81
+ { id: 'doing', title: '진행 중', color: '--chart-1', limit: 3 },
82
+ { id: 'review', title: '검토', color: '--chart-4' },
83
+ { id: 'done', title: '완료', color: '--success' },
84
+ ]
85
+
86
+ const INITIAL: KanbanValue<Task> = {
87
+ todo: [
88
+ { id: 't1', title: '온보딩 이메일 문구 다듬기', labels: [{ label: '콘텐츠' }], assignees: ['김민지'], due: '10월 30일' },
89
+ {
90
+ id: 't2',
91
+ title: '요금제 페이지 비교표 추가',
92
+ description: '연간 결제 할인율과 팀 요금제 차이를 한눈에 보여 주기',
93
+ labels: [{ label: '웹', tone: 'info' }],
94
+ comments: 2,
95
+ },
96
+ { id: 't3', title: '접근성 감사 결과 정리', assignees: ['박서연', '이도현'], checklist: { done: 0, total: 6 } },
97
+ ],
98
+ doing: [
99
+ {
100
+ id: 'd1',
101
+ title: '결제 실패 재시도 로직',
102
+ labels: [{ label: '버그', tone: 'danger' }],
103
+ assignees: ['이도현'],
104
+ due: '오늘',
105
+ dueTone: 'warning',
106
+ checklist: { done: 3, total: 5 },
107
+ },
108
+ { id: 'd2', title: '대시보드 차트 다크 모드', labels: [{ label: '디자인', tone: 'accent' }], assignees: ['정하늘', '김민지'], attachments: 3 },
109
+ ],
110
+ review: [
111
+ {
112
+ id: 'r1',
113
+ title: 'Kanban 컴포넌트 docs 페이지',
114
+ description: '예제 4개와 API 표',
115
+ labels: [{ label: '디자인 시스템', tone: 'accent' }],
116
+ assignees: ['최유진'],
117
+ comments: 5,
118
+ checklist: { done: 4, total: 4 },
119
+ },
120
+ ],
121
+ done: [
122
+ { id: 'f1', title: '로그인 화면 리뉴얼', assignees: ['박서연'], due: '10월 21일', comments: 12 },
123
+ { id: 'f2', title: '알림 설정 API 연결', labels: [{ label: '백엔드', tone: 'success' }], assignees: ['이도현'] },
124
+ ],
125
+ }
126
+
127
+ let nextId = 1
128
+
129
+ export default function Example() {
130
+ const [board, setBoard] = useState(INITIAL)
131
+
132
+ return (
133
+ <div style={{ width: '100%', height: 560 }}>
134
+ <KanbanBoard
135
+ columns={COLUMNS}
136
+ value={board}
137
+ style={{ height: '100%' }}
138
+ onValueChange={(next, move) => {
139
+ const before = board
140
+ setBoard(next)
141
+ if (move.from.columnId === move.to.columnId) return
142
+ const to = COLUMNS.find((c) => c.id === move.to.columnId)?.title
143
+ toast.undo(`‘${move.item.title}’ → ${to}`, { onUndo: () => setBoard(before) })
144
+ }}
145
+ onCardOpen={(task) => toast(`‘${task.title}’ 열기`)}
146
+ onCardAdd={(columnId, title) => setBoard((b) => ({ ...b, [columnId]: [...(b[columnId] ?? []), { id: `new-${nextId++}`, title }] }))}
147
+ columnActions={(col) => (
148
+ <DropdownMenu
149
+ align="end"
150
+ aria-label={`${col.title} 메뉴`}
151
+ trigger={<Button iconOnly variant="ghost" size="sm" icon={<MoreHorizontal />} aria-label="열 메뉴" />}
152
+ >
153
+ <DropdownMenuItem onSelect={() => setBoard((b) => ({ ...b, [col.id]: [...(b[col.id] ?? [])].reverse() }))}>순서 뒤집기</DropdownMenuItem>
154
+ <DropdownMenuItem
155
+ danger
156
+ onSelect={() => {
157
+ const before = board
158
+ setBoard((b) => ({ ...b, [col.id]: [] }))
159
+ toast.undo(`${col.title} 열을 비웠어요`, { onUndo: () => setBoard(before) })
160
+ }}
161
+ >
162
+ 모두 지우기
163
+ </DropdownMenuItem>
164
+ </DropdownMenu>
165
+ )}
166
+ />
167
+ </div>
168
+ )
169
+ }
170
+ ```
171
+
172
+ ### 옮기기 규칙 · 한도
173
+
174
+ canMove가 문자열을 돌려주면 그 열 위에서 이유가 보이고, 놓으면 원래 자리로 돌아가요. limitMode='block'인 열은 한도가 차면 다른 열의 카드를 받지 않아요. 키보드로 옮길 땐 받지 않는 열을 건너뛰어요.
175
+
176
+ ```tsx
177
+ import { useState } from 'react'
178
+ import { KanbanBoard, type KanbanCardProps, type KanbanColumn, type KanbanValue } from '@iamfiro/design'
179
+
180
+ type Ticket = KanbanCardProps & { id: string; blocked?: boolean }
181
+
182
+ const COLUMNS: KanbanColumn[] = [
183
+ { id: 'backlog', title: '백로그', color: '--n6' },
184
+ { id: 'doing', title: '개발', color: '--chart-1', limit: 2, limitMode: 'block' },
185
+ { id: 'qa', title: 'QA', color: '--chart-4' },
186
+ { id: 'released', title: '배포됨', color: '--success', description: 'QA를 거친 카드만' },
187
+ ]
188
+
189
+ const INITIAL: KanbanValue<Ticket> = {
190
+ backlog: [
191
+ { id: 'b1', title: '검색 결과 하이라이트', labels: [{ label: 'P2' }] },
192
+ { id: 'b2', title: '외부 API 키 교체', labels: [{ label: '막힘', tone: 'danger' }], description: '선행 작업: 비밀 저장소 이전', blocked: true },
193
+ { id: 'b3', title: 'CSV 내보내기 인코딩', labels: [{ label: 'P1', tone: 'warning' }] },
194
+ ],
195
+ doing: [
196
+ { id: 'd1', title: '세션 만료 안내', assignees: ['이도현'] },
197
+ { id: 'd2', title: '이미지 지연 로딩', assignees: ['정하늘'] },
198
+ ],
199
+ qa: [{ id: 'q1', title: '모바일 탭바 겹침', assignees: ['박서연'], checklist: { done: 2, total: 3 } }],
200
+ released: [],
201
+ }
202
+
203
+ export default function Example() {
204
+ const [board, setBoard] = useState(INITIAL)
205
+
206
+ return (
207
+ <div style={{ width: '100%', height: 440 }}>
208
+ <KanbanBoard
209
+ columns={COLUMNS}
210
+ value={board}
211
+ onValueChange={setBoard}
212
+ style={{ height: '100%' }}
213
+ columnWidth={260}
214
+ canMove={({ item, from, to }) => {
215
+ if (item.blocked && to.columnId !== 'backlog') return '선행 작업이 끝나야 시작할 수 있어요'
216
+ if (to.columnId === 'released' && from.columnId !== 'qa') return 'QA를 먼저 거쳐야 해요'
217
+ return true
218
+ }}
219
+ />
220
+ </div>
221
+ )
222
+ }
223
+ ```
224
+
225
+ ### 키보드로 옮기기
226
+
227
+ 카드에 포커스하고 스페이스로 들어 올린 뒤 ←/→로 열, ↑/↓로 순서를 바꾸고 스페이스나 Enter로 놓아요. Esc는 원래 자리로. 들지 않았을 땐 화살표가 카드 사이를 오가고(빈 열은 건너뜀), Enter는 onCardOpen을 불러요. 단계마다 화면 읽기 프로그램에 위치를 알려 줘요.
228
+
229
+ ```tsx
230
+ import { useState } from 'react'
231
+ import { Inline, Kbd, Stack, Text, KanbanBoard, toast, type KanbanCardProps, type KanbanColumn, type KanbanValue } from '@iamfiro/design'
232
+
233
+ type Idea = KanbanCardProps & { id: string }
234
+
235
+ const COLUMNS: KanbanColumn[] = [
236
+ { id: 'idea', title: '아이디어' },
237
+ { id: 'plan', title: '기획' },
238
+ { id: 'make', title: '제작' },
239
+ ]
240
+
241
+ const INITIAL: KanbanValue<Idea> = {
242
+ idea: [
243
+ { id: 'a', title: '사용자 인터뷰 질문지' },
244
+ { id: 'b', title: '경쟁 서비스 가입 흐름 비교' },
245
+ ],
246
+ plan: [{ id: 'c', title: '3분기 로드맵 초안' }],
247
+ make: [],
248
+ }
249
+
250
+ const KEYS: Array<[string, string]> = [
251
+ ['space', '들기 · 놓기'],
252
+ ['left', '앞 열'],
253
+ ['right', '뒤 열'],
254
+ ['up', '위로'],
255
+ ['down', '아래로'],
256
+ ['esc', '취소'],
257
+ ]
258
+
259
+ export default function Example() {
260
+ const [board, setBoard] = useState(INITIAL)
261
+ return (
262
+ <Stack gap={4} style={{ width: '100%' }}>
263
+ <Inline gap={4}>
264
+ {KEYS.map(([key, label]) => (
265
+ <Inline key={key} gap={2}>
266
+ <Kbd keys={[key]} size="sm" />
267
+ <Text variant="caption" tone="secondary">
268
+ {label}
269
+ </Text>
270
+ </Inline>
271
+ ))}
272
+ </Inline>
273
+ <KanbanBoard
274
+ columns={COLUMNS}
275
+ value={board}
276
+ onValueChange={setBoard}
277
+ columnWidth={240}
278
+ onCardOpen={(item) => toast(`‘${item.title}’ 열기`)}
279
+ aria-label="아이디어 보드"
280
+ />
281
+ </Stack>
282
+ )
283
+ }
284
+ ```
285
+
286
+ ### 카드 직접 그리기
287
+
288
+ renderCard로 카드 면을 바꿔요. 여기선 채용 파이프라인 — Card · Avatar · Text로 조립했어요. 상태(dragging)를 받아 끌리는 사본만 raised로 띄워요.
289
+
290
+ ```tsx
291
+ import { useState } from 'react'
292
+ import { Avatar, Inline, Stack, Text, Card, CardBody, KanbanBoard, type KanbanColumn, type KanbanValue } from '@iamfiro/design'
293
+
294
+ interface Candidate {
295
+ id: string
296
+ name: string
297
+ role: string
298
+ applied: string
299
+ }
300
+
301
+ const COLUMNS: KanbanColumn[] = [
302
+ { id: 'applied', title: '지원', color: '--chart-2' },
303
+ { id: 'screen', title: '서류 통과', color: '--chart-1' },
304
+ { id: 'interview', title: '면접', color: '--chart-4' },
305
+ { id: 'offer', title: '제안', color: '--success' },
306
+ ]
307
+
308
+ const INITIAL: KanbanValue<Candidate> = {
309
+ applied: [
310
+ { id: 'c1', name: '김민지', role: '프로덕트 디자이너', applied: '2일 전' },
311
+ { id: 'c2', name: '한지우', role: '프런트엔드 엔지니어', applied: '3일 전' },
312
+ { id: 'c3', name: '오세훈', role: '데이터 분석가', applied: '5일 전' },
313
+ ],
314
+ screen: [{ id: 'c4', name: '이도현', role: '백엔드 엔지니어', applied: '1주 전' }],
315
+ interview: [{ id: 'c5', name: '박서연', role: '프로덕트 매니저', applied: '2주 전' }],
316
+ offer: [],
317
+ }
318
+
319
+ export default function Example() {
320
+ const [board, setBoard] = useState(INITIAL)
321
+ return (
322
+ <div style={{ width: '100%' }}>
323
+ <KanbanBoard
324
+ columns={COLUMNS}
325
+ value={board}
326
+ onValueChange={setBoard}
327
+ columnWidth={232}
328
+ getItemLabel={(c) => c.name}
329
+ emptyLabel="아직 없어요"
330
+ aria-label="채용 파이프라인"
331
+ renderCard={(c, { dragging }) => (
332
+ <Card variant={dragging ? 'raised' : 'default'} padding="sm">
333
+ <CardBody>
334
+ <Inline gap={3} wrap={false}>
335
+ <Avatar name={c.name} size={32} tooltip={false} />
336
+ <Stack gap={0} style={{ minWidth: 0 }}>
337
+ <Text variant="label-md" weight="medium" truncate>
338
+ {c.name}
339
+ </Text>
340
+ <Text variant="caption" tone="tertiary" truncate>
341
+ {c.role} · {c.applied}
342
+ </Text>
343
+ </Stack>
344
+ </Inline>
345
+ </CardBody>
346
+ </Card>
347
+ )}
348
+ />
349
+ </div>
350
+ )
351
+ }
352
+ ```