@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,260 @@
1
+ # TreeDiagram
2
+
3
+ > 데이터 표시 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 조직도 · 작업 분해처럼 위계를 상자와 연결선으로 그려요. 루트 아래 자식이 한 줄로 놓이고, 깊은 단계는 부모 아래 들여쓴 목록으로 매달 수 있어요. 연결선은 실제 노드 상자를 재서 그리기 때문에 상자 크기가 바뀌거나 접고 펼 때도 따라가요. 노드 모양은 renderNode로 직접(보통 Card) 그리고, 넓어지면 가로로 스크롤돼요.
6
+
7
+ ```tsx
8
+ import { TreeDiagram, TreeDiagramToggle } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 위계(부모 → 자식): 들여쓴 행이면 `TreeView`(WAI-ARIA tree, roving tabindex, typeahead는 `TIMING.typeahead`), 상자 + 연결선이면 `TreeDiagram`(노드는 `renderNode`로 Card 조립, 접기 토글은 `state.toggle`).
14
+
15
+ ## API
16
+
17
+ ### TreeDiagram
18
+
19
+ | prop | 타입 | 기본값 | 설명 |
20
+ | --- | --- | --- | --- |
21
+ | `items` (필수) | `TreeDiagramNode<T>[]` | | 루트 노드(보통 하나). 여러 개면 나란히 놓여요. |
22
+ | `renderNode` (필수) | `(node, state: TreeDiagramNodeState) => ReactNode` | | 노드 상자. 보통 Card + Avatar · Text · Badge와 state.toggle. |
23
+ | `collapsed / defaultCollapsed` | `string[]` | | 접힌 노드 id(제어 / 비제어). |
24
+ | `onCollapsedChange` | `(ids: string[]) => void` | | 접힘이 바뀔 때. |
25
+ | `indentFrom` | `number` | | 이 깊이 이상인 노드는 하위를 들여쓴 목록으로(0 = 루트). 노드의 childLayout이 우선해요. |
26
+ | `gap` | `Space` | `4` | 한 줄에 놓인 형제 사이 간격. 들여쓴 목록은 그 절반. |
27
+ | `levelGap` | `Space` | `8` | 부모와 아래 줄 사이 세로 간격. |
28
+ | `indent` | `Space` | `8` | 들여쓴 목록이 부모보다 오른쪽으로 들어가는 폭. |
29
+ | `nodeWidth` | `number \| string` | | 모든 노드 상자의 고정 폭. 줄이 반듯해져요. |
30
+ | `aria-label` | `string` | | 다이어그램의 접근성 이름. |
31
+ | `className / style` | `string / CSSProperties` | | 스크롤되는 바깥 요소에 전달. |
32
+
33
+ ### TreeDiagramNode<T>
34
+
35
+ | prop | 타입 | 기본값 | 설명 |
36
+ | --- | --- | --- | --- |
37
+ | `id` (필수) | `string` | | 다이어그램 전체에서 고유. |
38
+ | `data` | `T` | | renderNode에서 쓸 값. |
39
+ | `children` | `TreeDiagramNode<T>[]` | | 하위 노드. |
40
+ | `childLayout` | `'row' \| 'indented'` | | 하위 배치. row: 한 단계 아래 한 줄로(가로 연결선) · indented: 아래로 들여쓴 목록(왼쪽 꺾은 연결선). indented 노드의 하위도 기본으로 indented. |
41
+
42
+ ### TreeDiagramNodeState
43
+
44
+ renderNode의 두 번째 인자.
45
+
46
+ | prop | 타입 | 기본값 | 설명 |
47
+ | --- | --- | --- | --- |
48
+ | `depth` | `number` | | 깊이(루트 0). |
49
+ | `childCount` | `number` | | 직계 하위 수. |
50
+ | `collapsed / setCollapsed` | `boolean / (next: boolean) => void` | | 이 노드의 접힘 상태와 변경 함수. |
51
+ | `toggle` | `ReactNode` | | 이 노드에 연결된 "3 ⌄" 토글. 하위가 없으면 null. |
52
+ | `childLayout` | `'row' \| 'indented'` | | 이 노드의 하위 배치. |
53
+
54
+ ### TreeDiagramToggle
55
+
56
+ 하위 수 + 셰브런. state.toggle로 충분하지 않을 때 직접 배치해요. 눌러도 감싼 카드의 클릭으로 번지지 않아요.
57
+
58
+ | prop | 타입 | 기본값 | 설명 |
59
+ | --- | --- | --- | --- |
60
+ | `count` (필수) | `number` | | 하위 수. |
61
+ | `collapsed` (필수) | `boolean` | | 접힘 상태(셰브런 방향 · aria-expanded). |
62
+ | `onToggle` (필수) | `() => void` | | 눌렀을 때. |
63
+ | `aria-controls / aria-label` | `string` | | 접히는 영역 id / 접근성 이름(기본 "하위 3개 접기"). |
64
+
65
+ ## 예제
66
+
67
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
68
+
69
+ ### 조직도
70
+
71
+ 대표 아래 팀장이 한 줄로, indentFrom={1}로 팀원은 팀장 아래 목록으로 매달려요. state.toggle("3 ⌄")을 CardHeader actions에 넣으면 하위를 접고 펴요. defaultCollapsed로 처음부터 접어 둘 수 있어요.
72
+
73
+ ```tsx
74
+ import { Avatar, Inline, Stack, Text, Card, CardHeader, TreeDiagram, type TreeDiagramNode } from '@iamfiro/design'
75
+
76
+ interface Person {
77
+ name: string
78
+ role: string
79
+ }
80
+
81
+ const p = (id: string, name: string, role: string, children?: TreeDiagramNode<Person>[]): TreeDiagramNode<Person> => ({ id, data: { name, role }, children })
82
+
83
+ const ORG = [
84
+ p('ceo', '최유진', '대표', [
85
+ p('design', '김민지', '디자인 팀장', [p('d1', '박서연', '프로덕트 디자이너'), p('d2', '정하늘', 'UX 리서처'), p('d3', '윤채원', '브랜드 디자이너')]),
86
+ p('dev', '이도현', '개발 팀장', [p('e1', '한지우', '프론트엔드 개발'), p('e2', '오세훈', '백엔드 개발')]),
87
+ p('biz', '장예린', '사업 팀장', [p('b1', '강태오', '영업'), p('b2', '서지민', '마케팅'), p('b3', '문가은', '고객 지원')]),
88
+ ]),
89
+ ]
90
+
91
+ export default function Example() {
92
+ return (
93
+ <TreeDiagram
94
+ aria-label="조직도"
95
+ items={ORG}
96
+ indentFrom={1}
97
+ nodeWidth={220}
98
+ defaultCollapsed={['biz']}
99
+ renderNode={(node, state) => (
100
+ <Card padding="sm">
101
+ <CardHeader actions={state.toggle}>
102
+ <Inline gap={3} wrap={false}>
103
+ <Avatar name={node.data?.name ?? ''} size={32} />
104
+ <Stack gap={0} style={{ minWidth: 0 }}>
105
+ <Text variant="label-md" truncate>
106
+ {node.data?.name}
107
+ </Text>
108
+ <Text variant="caption" tone="tertiary" truncate>
109
+ {node.data?.role}
110
+ </Text>
111
+ </Stack>
112
+ </Inline>
113
+ </CardHeader>
114
+ </Card>
115
+ )}
116
+ />
117
+ )
118
+ }
119
+ ```
120
+
121
+ ### 작업 분해 (제어)
122
+
123
+ collapsed / onCollapsedChange로 제어해 모두 펼치기 · 단계만 보기 버튼을 만들었어요. 상태는 Badge, 깊이에 따라 제목 크기를 바꿨어요.
124
+
125
+ ```tsx
126
+ import { useState } from 'react'
127
+ import { Badge, Button, Inline, Stack, Text, type Tone, Card, CardHeader, TreeDiagram, type TreeDiagramNode } from '@iamfiro/design'
128
+
129
+ interface Task {
130
+ title: string
131
+ owner: string
132
+ status: '완료' | '진행 중' | '대기'
133
+ }
134
+
135
+ const TONE: Record<Task['status'], Tone> = { 완료: 'success', '진행 중': 'accent', 대기: 'neutral' }
136
+
137
+ const t = (id: string, title: string, owner: string, status: Task['status'], children?: TreeDiagramNode<Task>[]): TreeDiagramNode<Task> => ({
138
+ id,
139
+ data: { title, owner, status },
140
+ children,
141
+ })
142
+
143
+ const PROJECT = [
144
+ t('app', '모바일 앱 리뉴얼', '김민지', '진행 중', [
145
+ t('plan', '기획', '최유진', '완료', [t('plan-1', '요구사항 정리', '최유진', '완료'), t('plan-2', '경쟁 서비스 분석', '장예린', '완료')]),
146
+ t('design', '디자인', '박서연', '진행 중', [t('design-1', '와이어프레임', '박서연', '완료'), t('design-2', '시각 디자인', '윤채원', '진행 중'), t('design-3', '사용성 테스트', '정하늘', '대기')]),
147
+ t('build', '개발', '이도현', '대기', [t('build-1', '화면 개발', '한지우', '대기'), t('build-2', 'API 연동', '오세훈', '대기')]),
148
+ ]),
149
+ ]
150
+
151
+ const PARENTS = ['app', 'plan', 'design', 'build']
152
+
153
+ export default function Example() {
154
+ const [collapsed, setCollapsed] = useState<string[]>(['plan'])
155
+ return (
156
+ <Stack gap={3}>
157
+ <Inline justify="between">
158
+ <Text variant="label-md">작업 분해</Text>
159
+ <Inline gap={1}>
160
+ <Button variant="ghost" size="sm" onClick={() => setCollapsed([])}>
161
+ 모두 펼치기
162
+ </Button>
163
+ <Button variant="ghost" size="sm" onClick={() => setCollapsed(PARENTS.slice(1))}>
164
+ 단계만 보기
165
+ </Button>
166
+ </Inline>
167
+ </Inline>
168
+ <TreeDiagram
169
+ aria-label="모바일 앱 리뉴얼 작업 분해"
170
+ items={PROJECT}
171
+ collapsed={collapsed}
172
+ onCollapsedChange={setCollapsed}
173
+ indentFrom={1}
174
+ nodeWidth={200}
175
+ renderNode={(node, state) => {
176
+ const task = node.data
177
+ if (!task) return null
178
+ return (
179
+ <Card padding="sm">
180
+ <CardHeader actions={state.toggle}>
181
+ <Stack gap={1}>
182
+ <Text variant={state.depth === 0 ? 'heading-xs' : 'label-md'} truncate>
183
+ {task.title}
184
+ </Text>
185
+ <Inline gap={2} wrap={false}>
186
+ <Badge tone={TONE[task.status]} dot>
187
+ {task.status}
188
+ </Badge>
189
+ <Text variant="caption" tone="tertiary" truncate>
190
+ {task.owner}
191
+ </Text>
192
+ </Inline>
193
+ </Stack>
194
+ </CardHeader>
195
+ </Card>
196
+ )
197
+ }}
198
+ />
199
+ </Stack>
200
+ )
201
+ }
202
+ ```
203
+
204
+ ### 노드별 배치 · 크기 변화
205
+
206
+ childLayout: 'indented'를 준 노드만 하위를 목록으로 매달아요. 페이지를 추가하면 상자와 연결선이 함께 자라요.
207
+
208
+ ```tsx
209
+ import { useState } from 'react'
210
+ import { Plus } from 'lucide-react'
211
+ import { Button, Stack, Text, Card, CardHeader, TreeDiagram, type TreeDiagramNode } from '@iamfiro/design'
212
+
213
+ interface Page {
214
+ title: string
215
+ path: string
216
+ }
217
+
218
+ const page = (id: string, title: string, path: string, children?: TreeDiagramNode<Page>[]): TreeDiagramNode<Page> => ({ id, data: { title, path }, children })
219
+
220
+ const EXTRA = ['공지사항', '이용 안내', '환불 정책', '제휴 문의']
221
+
222
+ export default function Example() {
223
+ const [added, setAdded] = useState(0)
224
+ const support = [page('faq', '자주 묻는 질문', '/support/faq'), ...EXTRA.slice(0, added).map((title, i) => page(`extra-${i}`, title, `/support/${i + 1}`))]
225
+ const site = [
226
+ page('home', '홈', '/', [
227
+ page('products', '제품', '/products', [page('new', '신제품', '/products/new'), page('best', '인기 상품', '/products/best')]),
228
+ // This one hangs its pages as a list, the others stay in rows.
229
+ { ...page('support', '고객 지원', '/support', support), childLayout: 'indented' as const },
230
+ page('about', '회사 소개', '/about', [page('team', '팀', '/about/team'), page('careers', '채용', '/about/careers')]),
231
+ ]),
232
+ ]
233
+ return (
234
+ <Stack gap={3} align="start">
235
+ <Button size="sm" icon={<Plus />} disabled={added === EXTRA.length} onClick={() => setAdded((n) => n + 1)}>
236
+ 고객 지원에 페이지 추가
237
+ </Button>
238
+ <TreeDiagram
239
+ aria-label="사이트맵"
240
+ items={site}
241
+ gap={3}
242
+ levelGap={6}
243
+ style={{ alignSelf: 'stretch' }}
244
+ renderNode={(node, state) => (
245
+ <Card padding="sm" style={{ minWidth: 140 }}>
246
+ <CardHeader actions={state.toggle}>
247
+ <Stack gap={0}>
248
+ <Text variant="label-md">{node.data?.title}</Text>
249
+ <Text variant="code" tone="tertiary">
250
+ {node.data?.path}
251
+ </Text>
252
+ </Stack>
253
+ </CardHeader>
254
+ </Card>
255
+ )}
256
+ />
257
+ </Stack>
258
+ )
259
+ }
260
+ ```
@@ -0,0 +1,329 @@
1
+ # TreeView
2
+
3
+ > 내비게이션 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 단계별로 들여쓴 행을 접고 펴는 트리. 폴더 · 파일, 작업 분해, 사이트맵처럼 위아래 관계가 있는 행에 써요. 행 모양은 List와 같고(앞 아이콘 · 굵은 이름 · 잘리는 회색 설명 · 뒤 자리), 하위 항목은 실제 높이만큼 부드럽게 펼쳐져요. 행 높이가 고정이라 옆에 일정 막대 같은 것을 행 단위로 맞춰 그릴 수 있어요.
6
+
7
+ ```tsx
8
+ import { TreeItem, TreeView, flattenTree, TREE_ROW_HEIGHT } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 위계(부모 → 자식): 들여쓴 행이면 `TreeView`(WAI-ARIA tree, roving tabindex, typeahead는 `TIMING.typeahead`), 상자 + 연결선이면 `TreeDiagram`(노드는 `renderNode`로 Card 조립, 접기 토글은 `state.toggle`).
14
+
15
+ ## API
16
+
17
+ ### TreeView
18
+
19
+ 키보드: ↑ ↓ 이동 · → 펼치기 / 첫 하위로 · ← 접기 / 부모로 · Home / End · Enter / Space 선택 · * 형제 모두 펼치기 · 글자 입력으로 이동(typeahead). 탭 순서에는 한 행만 들어가요(roving tabindex).
20
+
21
+ | prop | 타입 | 기본값 | 설명 |
22
+ | --- | --- | --- | --- |
23
+ | `items` | `TreeNode<T>[]` | | 데이터로 그릴 노드. 없으면 children의 TreeItem을 읽어요. |
24
+ | `children` | `ReactNode` | | items 대신 중첩한 TreeItem. |
25
+ | `expanded / defaultExpanded` | `string[]` | | 펼친 노드 id(제어 / 비제어). |
26
+ | `onExpandedChange` | `(ids: string[]) => void` | | 펼침이 바뀔 때. |
27
+ | `selected / defaultSelected` | `string \| null` | | 선택한 노드 id(제어 / 비제어). null = 제어 중, 선택 없음. |
28
+ | `onSelectedChange` | `(id: string \| null) => void` | | 선택이 바뀔 때. |
29
+ | `selectionMode` | `'single' \| 'none'` | `'single'` | none이면 선택 없이 펼치고 접기만 해요. |
30
+ | `expandOnClick` | `boolean` | `selectionMode === 'none'` | 부모 행을 누르면 펼침도 바꿔요(파일 탐색기). 아니면 셰브런으로만. |
31
+ | `onAction` | `(node: TreeNode<T>) => void` | | 행을 누르거나 Enter / Space를 눌렀을 때. |
32
+ | `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | 행 높이 32 / 40 / 48. |
33
+ | `rowHeight` | `number` | | density의 행 높이를 덮어써요(px). |
34
+ | `indent` | `Space` | `6` | 단계마다 들여쓰는 폭(4px 단위). 기본 24px이면 하위 셰브런이 부모 아이콘 아래 와요. |
35
+ | `guides` | `boolean` | | 열린 부모 아래 옅은 세로 안내선. |
36
+ | `animated` | `boolean` | `true` | 하위 항목 접고 펴기 애니메이션. 옆 차트가 행 위치를 바로 따라가야 하면 끄세요. |
37
+ | `renderItem` | `(node, state: TreeItemState) => ReactNode` | | 이름 + 설명 자리를 직접 그려요. leading / trailing은 노드 값 그대로. |
38
+ | `onVisibleChange` | `(rows: TreeRow<T>[]) => void` | | 보이는 행이 바뀔 때마다 순서대로(펼침 · 접힘 · 데이터 변경). |
39
+ | `aria-label / aria-labelledby` | `string` | | 트리의 접근성 이름. |
40
+ | `className / style` | `string / CSSProperties` | | 바깥 ul에 전달. |
41
+
42
+ ### TreeNode<T> · TreeItem
43
+
44
+ items의 노드 모양. TreeItem은 같은 props(+ 중첩 children)를 JSX로 받아요.
45
+
46
+ | prop | 타입 | 기본값 | 설명 |
47
+ | --- | --- | --- | --- |
48
+ | `id` (필수) | `string` | | 트리 전체에서 고유. |
49
+ | `label` (필수) | `ReactNode` | | 굵은 이름. |
50
+ | `description` | `ReactNode` | | 이름 뒤 회색 글자. 자리가 모자라면 먼저 잘려요. |
51
+ | `leading` | `ReactNode` | | 이름 앞 아이콘 · 아바타 · 파일 아이콘. |
52
+ | `trailing` | `ReactNode` | | 오른쪽: 기간, 개수, Spinner 등. |
53
+ | `disabled` | `boolean` | | 흐리게. 포커스는 되지만 선택 · 펼침은 안 돼요. |
54
+ | `textValue` | `string` | | label이 문자열이 아닐 때 typeahead가 읽을 글자. |
55
+ | `children` | `TreeNode<T>[]` | | 하위 노드. |
56
+ | `data` | `T` | | renderItem · 콜백에서 다시 꺼내 쓸 값. |
57
+
58
+ ### flattenTree · TreeRow · TREE_ROW_HEIGHT
59
+
60
+ flattenTree(items, expanded)는 보이는 행을 위에서부터 돌려줘요. TREE_ROW_HEIGHT는 density별 행 높이 { compact: 32, default: 40, comfortable: 48 }.
61
+
62
+ | prop | 타입 | 기본값 | 설명 |
63
+ | --- | --- | --- | --- |
64
+ | `id / node` | `string / TreeNode<T>` | | 행의 노드. |
65
+ | `index` | `number` | | 보이는 목록에서의 위치(0부터). × 행 높이 = 행의 top. |
66
+ | `depth` | `number` | | 단계(맨 위 0). |
67
+ | `parentId` | `string \| null` | | 부모 id. |
68
+ | `hasChildren / expanded` | `boolean` | | 하위가 있는지 / 펼쳐져 있는지. |
69
+ | `posinset / setsize` | `number` | | 형제 중 순서(1부터) / 형제 수. |
70
+
71
+ ## 예제
72
+
73
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
74
+
75
+ ### 파일 탐색기
76
+
77
+ expandOnClick으로 폴더 행을 누르면 펼쳐져요. guides는 열린 폴더 아래 옅은 세로선을 그려요. 펼침과 선택을 모두 제어(expanded · selected)해 폴더 아이콘을 바꿨어요.
78
+
79
+ ```tsx
80
+ import { useState } from 'react'
81
+ import { Folder, FolderOpen } from 'lucide-react'
82
+ import { FileIcon, Stack, Text, TreeView, type TreeNode } from '@iamfiro/design'
83
+
84
+ const file = (id: string, name: string, meta: string): TreeNode => ({ id, label: name, leading: <FileIcon name={name} size={16} />, trailing: meta })
85
+
86
+ const ITEMS: TreeNode[] = [
87
+ {
88
+ id: 'design',
89
+ label: '디자인',
90
+ children: [
91
+ file('design/landing', '랜딩 페이지 시안.png', '5.1MB'),
92
+ file('design/guide', '브랜드 가이드.pdf', '12MB'),
93
+ {
94
+ id: 'design/icons',
95
+ label: '아이콘',
96
+ children: [file('design/icons/set', '아이콘 세트.zip', '3.2MB'), file('design/icons/note', '사용 규칙.docx', '84KB')],
97
+ },
98
+ ],
99
+ },
100
+ {
101
+ id: 'plan',
102
+ label: '기획',
103
+ children: [file('plan/q4', '4분기 로드맵.pptx', '8.4MB'), file('plan/research', '사용자 인터뷰 정리.docx', '220KB')],
104
+ },
105
+ {
106
+ id: 'finance',
107
+ label: '재무',
108
+ children: [file('finance/sales', '10월 매출 정리.xlsx', '860KB'), file('finance/budget', '2027 예산안.xlsx', '1.1MB')],
109
+ },
110
+ file('readme', '폴더 안내.txt', '2KB'),
111
+ ]
112
+
113
+ // Open folders show an open-folder icon.
114
+ const withFolderIcons = (nodes: TreeNode[], open: string[]): TreeNode[] =>
115
+ nodes.map((n) => (n.children ? { ...n, leading: open.includes(n.id) ? <FolderOpen /> : <Folder />, children: withFolderIcons(n.children, open) } : n))
116
+
117
+ export default function Example() {
118
+ const [expanded, setExpanded] = useState<string[]>(['design'])
119
+ const [selected, setSelected] = useState<string | null>('design/landing')
120
+ return (
121
+ <Stack gap={3} style={{ width: 420 }}>
122
+ <TreeView
123
+ aria-label="공유 폴더"
124
+ items={withFolderIcons(ITEMS, expanded)}
125
+ expanded={expanded}
126
+ onExpandedChange={setExpanded}
127
+ selected={selected}
128
+ onSelectedChange={setSelected}
129
+ expandOnClick
130
+ guides
131
+ />
132
+ <Text variant="caption" tone="tertiary">
133
+ 선택: {selected ?? '없음'}
134
+ </Text>
135
+ </Stack>
136
+ )
137
+ }
138
+ ```
139
+
140
+ ### 작업 분해
141
+
142
+ trailing에 기간이나 Spinner, description에 잘리는 설명. 아직 시작하지 않은 작업은 disabled로 흐리게 — 포커스는 가지만 선택 · 펼침은 안 돼요.
143
+
144
+ ```tsx
145
+ import { CircleCheck, CircleDashed, CircleDot } from 'lucide-react'
146
+ import { Spinner, TreeView, type TreeNode } from '@iamfiro/design'
147
+
148
+ const done = <CircleCheck color="var(--success)" />
149
+ const doing = <CircleDot color="var(--accent)" />
150
+ const todo = <CircleDashed />
151
+
152
+ const ITEMS: TreeNode[] = [
153
+ {
154
+ id: 'launch',
155
+ label: '신규 서비스 출시',
156
+ description: '10월 1일 – 11월 7일',
157
+ leading: doing,
158
+ trailing: '38일',
159
+ children: [
160
+ {
161
+ id: 'research',
162
+ label: '사용자 조사',
163
+ description: '인터뷰 12명, 설문 340건 분석',
164
+ leading: done,
165
+ trailing: '6일',
166
+ children: [
167
+ { id: 'interview', label: '심층 인터뷰', description: '김민지 · 박서연', leading: done, trailing: '4일' },
168
+ { id: 'survey', label: '설문 분석', description: '응답 340건, 주요 불편 5가지 정리', leading: done, trailing: '2일' },
169
+ ],
170
+ },
171
+ {
172
+ id: 'design',
173
+ label: '디자인',
174
+ description: '와이어프레임부터 최종 시안까지',
175
+ leading: doing,
176
+ trailing: '12일',
177
+ children: [
178
+ { id: 'wire', label: '와이어프레임', description: '핵심 화면 8개', leading: done, trailing: '3일' },
179
+ { id: 'visual', label: '시각 디자인', description: '디자인 시스템 컴포넌트로 조립 중', leading: doing, trailing: <Spinner size={14} label="진행 중" /> },
180
+ ],
181
+ },
182
+ {
183
+ id: 'build',
184
+ label: '개발',
185
+ description: '디자인 확정 후 시작',
186
+ leading: todo,
187
+ trailing: '14일',
188
+ disabled: true,
189
+ children: [
190
+ { id: 'front', label: '프론트엔드', leading: todo, trailing: '9일', disabled: true },
191
+ { id: 'back', label: '백엔드 API', leading: todo, trailing: '5일', disabled: true },
192
+ ],
193
+ },
194
+ { id: 'qa', label: 'QA · 출시', description: '11월 4일부터', leading: todo, trailing: '4일', disabled: true },
195
+ ],
196
+ },
197
+ ]
198
+
199
+ export default function Example() {
200
+ return <TreeView aria-label="출시 작업" items={ITEMS} defaultExpanded={['launch', 'design']} defaultSelected="visual" style={{ width: 520 }} />
201
+ }
202
+ ```
203
+
204
+ ### TreeItem으로 쓰기 · 모두 펼치기
205
+
206
+ items 대신 TreeItem을 중첩해 JSX로 적을 수 있어요. selectionMode="none"이면 행을 눌러 펼치고 접기만 해요.
207
+
208
+ ```tsx
209
+ import { useState } from 'react'
210
+ import { FileText, House, Settings, ShoppingBag, Users } from 'lucide-react'
211
+ import { Button, Inline, Stack, Text, TreeItem, TreeView } from '@iamfiro/design'
212
+
213
+ const PARENTS = ['home', 'products', 'about', 'support']
214
+
215
+ export default function Example() {
216
+ const [expanded, setExpanded] = useState<string[]>(['home'])
217
+ const allOpen = expanded.length === PARENTS.length
218
+ return (
219
+ <Stack gap={3} style={{ width: 440 }}>
220
+ <Inline justify="between">
221
+ <Text variant="label-md">사이트맵</Text>
222
+ <Button variant="ghost" size="sm" onClick={() => setExpanded(allOpen ? [] : PARENTS)}>
223
+ {allOpen ? '모두 접기' : '모두 펼치기'}
224
+ </Button>
225
+ </Inline>
226
+ <TreeView aria-label="사이트맵" expanded={expanded} onExpandedChange={setExpanded} selectionMode="none" density="compact">
227
+ <TreeItem id="home" label="홈" description="/" leading={<House />}>
228
+ <TreeItem id="products" label="제품" description="/products" leading={<ShoppingBag />}>
229
+ <TreeItem id="products/new" label="신제품" description="/products/new" leading={<FileText />} />
230
+ <TreeItem id="products/best" label="인기 상품" description="/products/best" leading={<FileText />} />
231
+ <TreeItem id="products/sale" label="할인 행사" description="/products/sale · 11월 1일 공개" leading={<FileText />} disabled />
232
+ </TreeItem>
233
+ <TreeItem id="about" label="회사 소개" description="/about" leading={<Users />}>
234
+ <TreeItem id="about/team" label="팀" description="/about/team" leading={<FileText />} />
235
+ <TreeItem id="about/careers" label="채용" description="/about/careers" leading={<FileText />} />
236
+ </TreeItem>
237
+ <TreeItem id="support" label="고객 지원" description="/support" leading={<Settings />}>
238
+ <TreeItem id="support/faq" label="자주 묻는 질문" description="/support/faq" leading={<FileText />} />
239
+ <TreeItem id="support/contact" label="문의하기" description="/support/contact" leading={<FileText />} />
240
+ </TreeItem>
241
+ </TreeItem>
242
+ </TreeView>
243
+ </Stack>
244
+ )
245
+ }
246
+ ```
247
+
248
+ ### 밀도
249
+
250
+ density로 행 높이를 compact(32) · default(40) · comfortable(48) 중에 골라요. 행 좌우 여백은 List와 같아요.
251
+
252
+ ```tsx
253
+ import { useState } from 'react'
254
+ import { Avatar, SegmentedControl, Stack, TreeView, type TreeDensity, type TreeNode } from '@iamfiro/design'
255
+
256
+ const person = (id: string, name: string, role: string, children?: TreeNode[]): TreeNode => ({
257
+ id,
258
+ label: name,
259
+ description: role,
260
+ leading: <Avatar name={name} size={20} />,
261
+ children,
262
+ })
263
+
264
+ const ITEMS = [
265
+ person('ceo', '최유진', '대표', [
266
+ person('lead-1', '김민지', '디자인 팀장', [person('m-1', '박서연', '프로덕트 디자이너'), person('m-2', '정하늘', 'UX 리서처')]),
267
+ person('lead-2', '이도현', '개발 팀장', [person('m-3', '한지우', '프론트엔드'), person('m-4', '오세훈', '백엔드')]),
268
+ ]),
269
+ ]
270
+
271
+ export default function Example() {
272
+ const [density, setDensity] = useState<TreeDensity>('default')
273
+ return (
274
+ <Stack gap={4} align="start" style={{ width: 420 }}>
275
+ <SegmentedControl
276
+ ariaLabel="행 높이"
277
+ value={density}
278
+ onChange={setDensity}
279
+ options={[
280
+ { value: 'compact', label: 'compact' },
281
+ { value: 'default', label: 'default' },
282
+ { value: 'comfortable', label: 'comfortable' },
283
+ ]}
284
+ />
285
+ <TreeView aria-label="조직" items={ITEMS} density={density} defaultExpanded={['ceo', 'lead-1']} guides style={{ alignSelf: 'stretch' }} />
286
+ </Stack>
287
+ )
288
+ }
289
+ ```
290
+
291
+ ### 보이는 행 (옆에 차트 맞추기)
292
+
293
+ onVisibleChange는 보이는 행을 순서대로 알려 줘요. 행 높이(TREE_ROW_HEIGHT 또는 rowHeight) × index가 그 행의 위치예요. 데이터만 있을 땐 flattenTree(items, expanded)로 같은 목록을 얻어요.
294
+
295
+ ```tsx
296
+ import { useState } from 'react'
297
+ import { Stack, Text, TREE_ROW_HEIGHT, TreeView, type TreeNode, type TreeRow } from '@iamfiro/design'
298
+
299
+ const ITEMS: TreeNode[] = [
300
+ {
301
+ id: 'web',
302
+ label: '웹사이트 개편',
303
+ trailing: '21일',
304
+ children: [
305
+ { id: 'web/ia', label: '정보 구조 정리', trailing: '3일' },
306
+ { id: 'web/design', label: '화면 디자인', trailing: '8일', children: [{ id: 'web/design/main', label: '메인', trailing: '3일' }, { id: 'web/design/sub', label: '하위 페이지', trailing: '5일' }] },
307
+ { id: 'web/dev', label: '개발', trailing: '10일' },
308
+ ],
309
+ },
310
+ { id: 'app', label: '앱 업데이트', trailing: '9일', children: [{ id: 'app/push', label: '알림 설정 개선', trailing: '4일' }, { id: 'app/login', label: '간편 로그인', trailing: '5일' }] },
311
+ ]
312
+
313
+ export default function Example() {
314
+ const [rows, setRows] = useState<TreeRow[]>([])
315
+ const h = TREE_ROW_HEIGHT.default
316
+ return (
317
+ <Stack gap={3} style={{ width: 460 }}>
318
+ {/* animated={false}: rows move at once, so whatever is drawn beside them can follow without lagging. */}
319
+ <TreeView aria-label="프로젝트 일정" items={ITEMS} defaultExpanded={['web']} animated={false} onVisibleChange={setRows} />
320
+ <Text variant="caption" tone="tertiary" numeric>
321
+ 보이는 행 {rows.length}개 · 행 높이 {h}px · 전체 {rows.length * h}px
322
+ </Text>
323
+ <Text variant="caption" tone="tertiary" numeric>
324
+ {rows.map((r) => `${r.index * h}px ${'·'.repeat(r.depth)}${typeof r.node.label === 'string' ? r.node.label : r.id}`).join(' / ')}
325
+ </Text>
326
+ </Stack>
327
+ )
328
+ }
329
+ ```