@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,460 @@
1
+ # DataGrid
2
+
3
+ > 데이터 표시 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ Notion 데이터베이스처럼 타입이 있는 속성과 보기(정렬·필터·그룹·검색)를, Google Sheets·Numbers처럼 범위 선택·키보드 편집·복사/붙여넣기·채우기 핸들을 갖춘 표. 열은 끌어서 순서·너비를 바꾸고 고정·숨기기·타입 변경까지 머리글 메뉴에서 할 수 있어요. 모든 데이터 변경은 실행 취소(⌘/Ctrl+Z)할 수 있고, 행이 많으면 보이는 줄만 그려요. 단순히 보여 주기만 하는 표는 Table을 쓰세요.
6
+
7
+ ```tsx
8
+ import { DataGrid, type GridColumn, type GridRow } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## 디자인 규칙
12
+
13
+ - 표: 보여 주기만 하면 `Table`, 편집·정렬·필터·범위 선택이 필요하면 `DataGrid`. 셀 편집·키 입력·클립보드·한글 IME는 셀 위에 놓인 textarea 하나가 모두 받는다(조합 중에 포커스를 옮기면 한글이 깨진다).
14
+
15
+ ## API
16
+
17
+ ### DataGrid
18
+
19
+ | prop | 타입 | 기본값 | 설명 |
20
+ | --- | --- | --- | --- |
21
+ | `rows / defaultRows / onRowsChange` | `R[] / R[] / (rows) => void` | | 행 데이터(제어/비제어). 행마다 고유한 id가 있어야 해요. |
22
+ | `columns / defaultColumns / onColumnsChange` | `GridColumn<R>[]` | | 열 정의. 너비·순서·고정·숨김·타입 변경이 여기에 반영돼요. |
23
+ | `view / defaultView / onViewChange` | `GridView / Partial<GridView>` | | 정렬·필터·그룹·검색·행 높이 같은 보기 상태. |
24
+ | `selectedRowIds / onSelectedRowIdsChange` | `string[]` | | 체크된 행(일괄 작업 대상). |
25
+ | `createRow` | `(values) => R` | | 새 행을 만들 때. values에는 현재 필터·그룹에 맞는 값이 들어 있어요. |
26
+ | `onCellEdit` | `({ row, column, value, previous }) => void` | | 셀이 확정될 때마다(입력·붙여넣기·채우기·지우기). |
27
+ | `readOnly` | `boolean` | `false` | 데이터 변경 금지. 보기 조작과 복사는 돼요. |
28
+ | `columnEditing` | `boolean` | `true` | 사용자가 속성을 추가·이름 변경·타입 변경·삭제할 수 있는지. |
29
+ | `toolbar` | `boolean` | `true` | 검색·필터·정렬·그룹·속성·보기 설정·실행 취소·새로 만들기 막대. |
30
+ | `title / actions` | `ReactNode` | | 툴바 왼쪽 제목 / 오른쪽 끝에 붙일 버튼. |
31
+ | `footer` | `boolean` | `true` | 열마다 계산을 고르는 아래 줄. |
32
+ | `height` | `number \| string` | `520` | 스크롤 영역 최대 높이. |
33
+ | `emptyState` | `ReactNode` | | 보일 행이 없을 때 대신 보여 줄 내용. |
34
+
35
+ ### GridColumn
36
+
37
+ | prop | 타입 | 기본값 | 설명 |
38
+ | --- | --- | --- | --- |
39
+ | `key / name` (필수) | `string` | | 값을 읽고 쓰는 필드 / 머리글 이름. |
40
+ | `type` | `'text' \| 'number' \| 'select' \| 'multiSelect' \| 'checkbox' \| 'date' \| 'url'` | `'text'` | 표시·편집·정렬·필터·붙여넣기 해석이 타입을 따라요. |
41
+ | `width / minWidth` | `number` | `180 / 64` | 열 너비(px). 경계를 더블클릭하면 내용에 맞춰요. |
42
+ | `pinned / hidden / wrap` | `boolean` | | 왼쪽 고정 / 숨김 / 줄바꿈(켜면 행 가상화가 꺼져요). |
43
+ | `options / creatable` | `GridOption[] / boolean` | | 선택지({ label, tone }). 없는 값을 입력하면 새로 만들어요(creatable: false면 거절). |
44
+ | `format / decimals` | `'plain' \| 'comma' \| 'percent' \| 'won' \| 'usd'` | `'comma'` | 숫자 표시 형식. |
45
+ | `aggregate` | `GridAggregate` | | 아래 줄 계산('sum', 'avg', 'percentChecked', 'earliest' …). |
46
+ | `readOnly / locked` | `boolean` | | 셀 편집 금지 / 속성 삭제·타입 변경 금지. |
47
+ | `align` | `'start' \| 'center' \| 'end'` | | 정렬. 숫자는 기본이 오른쪽. |
48
+ | `render` | `(value, row) => ReactNode` | | 셀 모양을 직접 그릴 때. |
49
+ | `validate` | `(value, row) => string \| null` | | 메시지를 돌려주면 그 편집을 거절해요. |
50
+
51
+ ### 키보드
52
+
53
+ | prop | 타입 | 기본값 | 설명 |
54
+ | --- | --- | --- | --- |
55
+ | `↑ ↓ ← → · Tab` | `이동` | | Shift를 같이 누르면 범위 확장, ⌘/Ctrl은 끝까지. |
56
+ | `Enter · F2 · 더블클릭` | `편집` | | 바로 글자를 쳐도 편집이 시작돼요(한글 입력 포함). Enter 확정 후 아래로, Tab은 오른쪽, Esc 취소. |
57
+ | `Shift+Enter · Alt+Enter` | `줄바꿈` | | 텍스트 셀 안에서 새 줄. |
58
+ | `Delete · Backspace` | `지우기` | | 선택 범위의 값을 지워요. |
59
+ | `Space` | `체크` | | 체크박스 열에서 범위를 한꺼번에 토글. |
60
+ | `⌘/Ctrl + C · X · V` | `클립보드` | | TSV로 주고받아 Sheets·Excel·Numbers와 호환돼요. |
61
+ | `⌘/Ctrl + D` | `아래로 채우기` | | 범위의 첫 행 값을 아래로 복사(숫자는 이어서). |
62
+ | `⌘/Ctrl + A · Z · Shift+Z` | `전체 선택 · 실행 취소 · 다시 실행` | | |
63
+ | `Esc (끄는 중)` | `취소` | | 열 너비·순서, 행 순서, 채우기를 끄는 도중 Esc면 원래대로. |
64
+
65
+ ## 예제
66
+
67
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
68
+
69
+ ### 데이터베이스 (Notion)
70
+
71
+ 텍스트·숫자·선택·다중 선택·날짜·체크박스·URL 속성. 머리글의 ⌄ 메뉴(또는 우클릭)에서 이름·타입·정렬·필터·그룹·고정·줄바꿈·삽입·삭제를 하고, 맨 오른쪽 +로 속성을 추가해요. 행 왼쪽 손잡이로 순서를 바꾸고, 체크하면 아래에 일괄 작업 막대가 떠요. 맨 아래 칸을 누르면 합계·평균·체크 비율 같은 계산을 고를 수 있어요.
72
+
73
+ ```tsx
74
+ import { DataGrid, type GridColumn, type GridRow } from '@iamfiro/design'
75
+
76
+ interface Task extends GridRow {
77
+ title: string
78
+ status: string | null
79
+ owner: string | null
80
+ tags: string[]
81
+ due: string | null
82
+ budget: number | null
83
+ progress: number | null
84
+ done: boolean
85
+ link: string | null
86
+ }
87
+
88
+ const COLUMNS: GridColumn<Task>[] = [
89
+ { key: 'title', name: '작업', type: 'text', width: 240, pinned: true, aggregate: 'count', locked: true },
90
+ {
91
+ key: 'status',
92
+ name: '상태',
93
+ type: 'select',
94
+ width: 130,
95
+ options: [
96
+ { label: '시작 전', tone: 'neutral' },
97
+ { label: '진행 중', tone: 'info' },
98
+ { label: '검토', tone: 'warning' },
99
+ { label: '완료', tone: 'success' },
100
+ ],
101
+ },
102
+ {
103
+ key: 'owner',
104
+ name: '담당자',
105
+ type: 'select',
106
+ width: 120,
107
+ options: [{ label: '김민지' }, { label: '이도현' }, { label: '박서연' }, { label: '최준호' }],
108
+ },
109
+ {
110
+ key: 'tags',
111
+ name: '태그',
112
+ type: 'multiSelect',
113
+ width: 200,
114
+ options: [
115
+ { label: '디자인', tone: 'accent' },
116
+ { label: '개발', tone: 'info' },
117
+ { label: '마케팅', tone: 'warning' },
118
+ { label: '긴급', tone: 'danger' },
119
+ ],
120
+ },
121
+ { key: 'due', name: '마감일', type: 'date', width: 130, aggregate: 'earliest' },
122
+ { key: 'budget', name: '예산', type: 'number', format: 'won', width: 140, aggregate: 'sum' },
123
+ { key: 'progress', name: '진행률', type: 'number', format: 'percent', width: 110, aggregate: 'avg' },
124
+ { key: 'done', name: '완료', type: 'checkbox', width: 90, aggregate: 'percentChecked' },
125
+ { key: 'link', name: '문서', type: 'url', width: 200 },
126
+ ]
127
+
128
+ const ROWS: Task[] = [
129
+ { id: 't1', title: '랜딩 페이지 리뉴얼', status: '진행 중', owner: '김민지', tags: ['디자인', '마케팅'], due: '2026-11-03', budget: 4200000, progress: 0.6, done: false, link: 'figma.com/lumen-landing' },
130
+ { id: 't2', title: '결제 모듈 교체', status: '검토', owner: '이도현', tags: ['개발', '긴급'], due: '2026-10-28', budget: 8800000, progress: 0.9, done: false, link: 'github.com/lumen/pay' },
131
+ { id: 't3', title: '10월 뉴스레터', status: '완료', owner: '박서연', tags: ['마케팅'], due: '2026-10-20', budget: 600000, progress: 1, done: true, link: null },
132
+ { id: 't4', title: '디자인 토큰 정리', status: '진행 중', owner: '김민지', tags: ['디자인', '개발'], due: '2026-11-10', budget: 1500000, progress: 0.35, done: false, link: 'lumen.app/tokens' },
133
+ { id: 't5', title: '온보딩 인터뷰 5건', status: '시작 전', owner: '최준호', tags: ['디자인'], due: '2026-11-14', budget: 500000, progress: 0, done: false, link: null },
134
+ { id: 't6', title: '모바일 앱 2.0 QA', status: '진행 중', owner: '이도현', tags: ['개발'], due: '2026-11-07', budget: 3200000, progress: 0.45, done: false, link: null },
135
+ { id: 't7', title: '파트너 웨비나', status: '시작 전', owner: '박서연', tags: ['마케팅'], due: '2026-11-21', budget: 2000000, progress: 0.1, done: false, link: null },
136
+ { id: 't8', title: '접근성 감사', status: '완료', owner: '최준호', tags: ['디자인', '개발'], due: '2026-10-15', budget: 1200000, progress: 1, done: true, link: 'lumen.app/a11y' },
137
+ { id: 't9', title: '요금제 페이지 A/B 테스트', status: '검토', owner: '김민지', tags: ['마케팅', '긴급'], due: '2026-10-30', budget: 900000, progress: 0.8, done: false, link: null },
138
+ { id: 't10', title: '고객 지원 매크로 정비', status: '시작 전', owner: null, tags: [], due: null, budget: null, progress: null, done: false, link: null },
139
+ ]
140
+
141
+ export default function Example() {
142
+ return <DataGrid title="4분기 로드맵" defaultColumns={COLUMNS} defaultRows={ROWS} height={460} style={{ width: '100%' }} />
143
+ }
144
+ ```
145
+
146
+ ### 스프레드시트 (Sheets · Numbers)
147
+
148
+ 셀을 끌어 범위를 고르고, 선택 오른쪽 아래 점(채우기 핸들)을 끌면 1, 2 → 3, 4처럼 이어서 채워요. Sheets·Excel에서 복사한 범위를 그대로 붙여 넣을 수 있고, 범위를 넘으면 행이 새로 생겨요. 합계 열은 readOnly로 두고 onRowsChange에서 다시 계산해요.
149
+
150
+ ```tsx
151
+ import { useState } from 'react'
152
+ import { DataGrid, type GridColumn, type GridRow } from '@iamfiro/design'
153
+
154
+ interface Line extends GridRow {
155
+ item: string
156
+ oct: number | null
157
+ nov: number | null
158
+ dec: number | null
159
+ total: number
160
+ }
161
+
162
+ const MONTHS = ['oct', 'nov', 'dec'] as const
163
+
164
+ const COLUMNS: GridColumn<Line>[] = [
165
+ { key: 'item', name: '항목', width: 180, pinned: true },
166
+ { key: 'oct', name: '10월', type: 'number', format: 'comma', width: 120, aggregate: 'sum' },
167
+ { key: 'nov', name: '11월', type: 'number', format: 'comma', width: 120, aggregate: 'sum' },
168
+ { key: 'dec', name: '12월', type: 'number', format: 'comma', width: 120, aggregate: 'sum' },
169
+ { key: 'total', name: '합계', type: 'number', format: 'comma', width: 140, aggregate: 'sum', readOnly: true, locked: true },
170
+ ]
171
+
172
+ // 합계 열은 직접 고칠 수 없고, 월별 값이 바뀔 때마다 다시 계산해요.
173
+ const withTotal = (l: Line): Line => ({ ...l, total: MONTHS.reduce((s, m) => s + (l[m] ?? 0), 0) })
174
+
175
+ const START: Line[] = [
176
+ { id: 'l1', item: '클라우드 서버', oct: 1820000, nov: 1910000, dec: 2000000, total: 0 },
177
+ { id: 'l2', item: '디자인 툴 구독', oct: 360000, nov: 360000, dec: 360000, total: 0 },
178
+ { id: 'l3', item: '광고', oct: 2500000, nov: 3000000, dec: 3500000, total: 0 },
179
+ { id: 'l4', item: '외주 번역', oct: 800000, nov: null, dec: 450000, total: 0 },
180
+ { id: 'l5', item: '사무용품', oct: 120000, nov: 95000, dec: 130000, total: 0 },
181
+ ].map(withTotal)
182
+
183
+ export default function Example() {
184
+ const [rows, setRows] = useState(START)
185
+ return (
186
+ <DataGrid
187
+ title="4분기 비용"
188
+ rows={rows}
189
+ onRowsChange={(next) => setRows(next.map(withTotal))}
190
+ defaultColumns={COLUMNS}
191
+ defaultView={{ gridlines: true, density: 'compact' }}
192
+ createRow={(values) => withTotal({ id: crypto.randomUUID(), item: '', oct: null, nov: null, dec: null, total: 0, ...values })}
193
+ height={360}
194
+ style={{ width: '100%' }}
195
+ />
196
+ )
197
+ }
198
+ ```
199
+
200
+ ### 저장된 보기
201
+
202
+ view / onViewChange로 정렬·필터·그룹·접힘 상태를 밖에서 들고 있어요. 탭마다 다른 보기를 저장하고, 표에서 바꾼 내용도 그 탭에 남아요. 그룹 머리의 +로 그 그룹 값이 채워진 행을 만들어요.
203
+
204
+ ```tsx
205
+ import { useState } from 'react'
206
+ import { SegmentedControl, DEFAULT_GRID_VIEW, DataGrid, type GridColumn, type GridRow, type GridView } from '@iamfiro/design'
207
+
208
+ interface Ticket extends GridRow {
209
+ title: string
210
+ status: string
211
+ priority: string
212
+ owner: string
213
+ due: string
214
+ }
215
+
216
+ const COLUMNS: GridColumn<Ticket>[] = [
217
+ { key: 'title', name: '제목', width: 260 },
218
+ {
219
+ key: 'status',
220
+ name: '상태',
221
+ type: 'select',
222
+ width: 120,
223
+ options: [
224
+ { label: '접수', tone: 'neutral' },
225
+ { label: '처리 중', tone: 'info' },
226
+ { label: '해결', tone: 'success' },
227
+ ],
228
+ },
229
+ {
230
+ key: 'priority',
231
+ name: '우선순위',
232
+ type: 'select',
233
+ width: 110,
234
+ options: [
235
+ { label: '높음', tone: 'danger' },
236
+ { label: '보통', tone: 'warning' },
237
+ { label: '낮음', tone: 'neutral' },
238
+ ],
239
+ },
240
+ { key: 'owner', name: '담당자', type: 'select', width: 110, options: [{ label: '김민지' }, { label: '이도현' }, { label: '박서연' }] },
241
+ { key: 'due', name: '기한', type: 'date', width: 120 },
242
+ ]
243
+
244
+ const ROWS: Ticket[] = [
245
+ { id: 'k1', title: '로그인 후 빈 화면이 떠요', status: '처리 중', priority: '높음', owner: '이도현', due: '2026-10-26' },
246
+ { id: 'k2', title: '영수증 이메일이 늦게 와요', status: '접수', priority: '보통', owner: '박서연', due: '2026-10-29' },
247
+ { id: 'k3', title: '다크 모드 대비가 낮아요', status: '해결', priority: '낮음', owner: '김민지', due: '2026-10-21' },
248
+ { id: 'k4', title: 'CSV 내보내기 한글 깨짐', status: '처리 중', priority: '높음', owner: '김민지', due: '2026-10-27' },
249
+ { id: 'k5', title: '팀 초대 링크 만료 기간', status: '접수', priority: '낮음', owner: '이도현', due: '2026-11-04' },
250
+ { id: 'k6', title: '알림 설정이 저장되지 않아요', status: '처리 중', priority: '보통', owner: '박서연', due: '2026-10-31' },
251
+ ]
252
+
253
+ type ViewId = 'all' | 'open' | 'byOwner' | 'urgent'
254
+
255
+ // 탭마다 보기(정렬·필터·그룹)를 따로 저장해요. 표에서 바꾼 내용도 그 탭에 남아요.
256
+ const PRESETS: Record<ViewId, GridView> = {
257
+ all: { ...DEFAULT_GRID_VIEW },
258
+ open: { ...DEFAULT_GRID_VIEW, filters: [{ id: 'f1', key: 'status', op: 'isNot', value: '해결' }], sorts: [{ key: 'due', dir: 'asc' }] },
259
+ byOwner: { ...DEFAULT_GRID_VIEW, groupBy: 'owner' },
260
+ urgent: { ...DEFAULT_GRID_VIEW, groupBy: 'priority', collapsed: ['낮음'], sorts: [{ key: 'due', dir: 'asc' }] },
261
+ }
262
+
263
+ export default function Example() {
264
+ const [tab, setTab] = useState<ViewId>('open')
265
+ const [views, setViews] = useState(PRESETS)
266
+
267
+ return (
268
+ <div style={{ display: 'grid', gap: 12, width: '100%' }}>
269
+ <SegmentedControl
270
+ variant="underline"
271
+ value={tab}
272
+ onChange={setTab}
273
+ ariaLabel="저장된 보기"
274
+ options={[
275
+ { value: 'all', label: '전체' },
276
+ { value: 'open', label: '미해결' },
277
+ { value: 'byOwner', label: '담당자별' },
278
+ { value: 'urgent', label: '우선순위별' },
279
+ ]}
280
+ />
281
+ <DataGrid
282
+ toolbar
283
+ defaultColumns={COLUMNS}
284
+ defaultRows={ROWS}
285
+ view={views[tab]}
286
+ onViewChange={(view) => setViews((v) => ({ ...v, [tab]: view }))}
287
+ height={420}
288
+ aria-label="지원 티켓"
289
+ />
290
+ </div>
291
+ )
292
+ }
293
+ ```
294
+
295
+ ### 1만 행
296
+
297
+ 보이는 줄만 그려서 1만 행도 부드럽게 스크롤돼요. 검색·정렬·필터·하단 계산은 전체 행 기준이에요.
298
+
299
+ ```tsx
300
+ import { useMemo } from 'react'
301
+ import { DataGrid, type GridColumn, type GridRow } from '@iamfiro/design'
302
+
303
+ interface Order extends GridRow {
304
+ no: number
305
+ customer: string
306
+ region: string
307
+ amount: number
308
+ ordered: string
309
+ paid: boolean
310
+ }
311
+
312
+ const NAMES = ['김민지', '이도현', '박서연', '최준호', '정하은', '강지우', '윤서준', '한예린']
313
+ const REGIONS = ['서울', '부산', '대구', '인천', '광주', '대전']
314
+
315
+ const COLUMNS: GridColumn<Order>[] = [
316
+ { key: 'no', name: '주문 번호', type: 'number', format: 'plain', width: 120, readOnly: true, aggregate: 'count' },
317
+ { key: 'customer', name: '고객', width: 140 },
318
+ { key: 'region', name: '지역', type: 'select', width: 110, options: REGIONS.map((label) => ({ label })) },
319
+ { key: 'amount', name: '금액', type: 'number', format: 'won', width: 140, aggregate: 'sum' },
320
+ { key: 'ordered', name: '주문일', type: 'date', width: 130, aggregate: 'latest' },
321
+ { key: 'paid', name: '결제', type: 'checkbox', width: 90, aggregate: 'percentChecked' },
322
+ ]
323
+
324
+ /** 1만 행을 만들어요(같은 결과가 나오도록 간단한 의사 난수). */
325
+ function makeOrders(count: number): Order[] {
326
+ let seed = 7
327
+ const rand = () => (seed = (seed * 16807) % 2147483647) / 2147483647
328
+ return Array.from({ length: count }, (_, i) => {
329
+ const day = new Date(2026, 0, 1 + Math.floor(rand() * 298))
330
+ return {
331
+ id: `o${i}`,
332
+ no: 100001 + i,
333
+ customer: NAMES[Math.floor(rand() * NAMES.length)],
334
+ region: REGIONS[Math.floor(rand() * REGIONS.length)],
335
+ amount: Math.round(rand() * 400) * 1000 + 9000,
336
+ ordered: `${day.getFullYear()}-${String(day.getMonth() + 1).padStart(2, '0')}-${String(day.getDate()).padStart(2, '0')}`,
337
+ paid: rand() > 0.2,
338
+ }
339
+ })
340
+ }
341
+
342
+ export default function Example() {
343
+ const rows = useMemo(() => makeOrders(10000), [])
344
+ return <DataGrid title="주문 10,000건" defaultRows={rows} defaultColumns={COLUMNS} defaultView={{ density: 'compact' }} height={440} style={{ width: '100%' }} />
345
+ }
346
+ ```
347
+
348
+ ### 커스텀 셀 · 검증
349
+
350
+ render로 셀 모양을 바꾸고(편집은 type을 따라요), validate로 잘못된 값을 막아요(칸이 흔들리고 편집이 유지돼요). creatable: false인 선택 열은 새 선택지를 만들 수 없고, readOnly 열은 고칠 수 없어요. onCellEdit으로 모든 변경을 받아요.
351
+
352
+ ```tsx
353
+ import { Avatar, Text, DataGrid, toast, type GridColumn, type GridRow } from '@iamfiro/design'
354
+
355
+ interface Member extends GridRow {
356
+ name: string
357
+ email: string
358
+ role: string
359
+ seats: number
360
+ joined: string
361
+ }
362
+
363
+ const COLUMNS: GridColumn<Member>[] = [
364
+ {
365
+ key: 'name',
366
+ name: '이름',
367
+ width: 180,
368
+ // render는 보이는 모습만 바꿔요. 편집·복사·정렬은 여전히 type(텍스트)을 따라요.
369
+ render: (value) => (
370
+ <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
371
+ <Avatar name={String(value ?? '')} size={22} />
372
+ <Text variant="label-md">{String(value ?? '')}</Text>
373
+ </span>
374
+ ),
375
+ },
376
+ {
377
+ key: 'email',
378
+ name: '이메일',
379
+ width: 220,
380
+ validate: (v) => (v && !/^\S+@\S+\.\S+$/.test(String(v)) ? '이메일 형식이 아니에요' : null),
381
+ },
382
+ {
383
+ key: 'role',
384
+ name: '역할',
385
+ type: 'select',
386
+ width: 120,
387
+ creatable: false,
388
+ options: [
389
+ { label: '관리자', tone: 'accent' },
390
+ { label: '편집자', tone: 'success' },
391
+ { label: '뷰어', tone: 'neutral' },
392
+ ],
393
+ },
394
+ {
395
+ key: 'seats',
396
+ name: '좌석',
397
+ type: 'number',
398
+ format: 'plain',
399
+ width: 90,
400
+ validate: (v) => (typeof v === 'number' && (v < 1 || v > 50 || !Number.isInteger(v)) ? '1–50 사이 정수만 돼요' : null),
401
+ },
402
+ { key: 'joined', name: '가입일', type: 'date', width: 130, readOnly: true },
403
+ ]
404
+
405
+ const ROWS: Member[] = [
406
+ { id: 'm1', name: '김민지', email: 'minji@lumen.app', role: '관리자', seats: 12, joined: '2025-03-02' },
407
+ { id: 'm2', name: '이도현', email: 'dohyun@lumen.app', role: '편집자', seats: 4, joined: '2025-07-18' },
408
+ { id: 'm3', name: '박서연', email: 'seoyeon@lumen.app', role: '편집자', seats: 2, joined: '2026-01-09' },
409
+ { id: 'm4', name: '최준호', email: 'junho@lumen.app', role: '뷰어', seats: 1, joined: '2026-09-30' },
410
+ ]
411
+
412
+ export default function Example() {
413
+ return (
414
+ <DataGrid
415
+ title="멤버"
416
+ defaultColumns={COLUMNS}
417
+ defaultRows={ROWS}
418
+ columnEditing={false}
419
+ footer={false}
420
+ defaultView={{ rowNumbers: false }}
421
+ onCellEdit={({ row, column, value }) => toast.success(`${row.name} · ${column.name} → ${String(value ?? '비움')}`)}
422
+ height={320}
423
+ style={{ width: '100%' }}
424
+ />
425
+ )
426
+ }
427
+ ```
428
+
429
+ ### 읽기 전용
430
+
431
+ readOnly면 데이터는 바뀌지 않지만 선택·복사·정렬·너비 조절은 그대로 돼요. toolbar·footer를 끄면 작은 표로도 써요.
432
+
433
+ ```tsx
434
+ import { DataGrid, type GridColumn, type GridRow } from '@iamfiro/design'
435
+
436
+ interface Release extends GridRow {
437
+ version: string
438
+ date: string
439
+ changes: number
440
+ stable: boolean
441
+ }
442
+
443
+ const COLUMNS: GridColumn<Release>[] = [
444
+ { key: 'version', name: '버전', width: 120 },
445
+ { key: 'date', name: '배포일', type: 'date', width: 130 },
446
+ { key: 'changes', name: '변경', type: 'number', width: 100 },
447
+ { key: 'stable', name: '안정판', type: 'checkbox', width: 90 },
448
+ ]
449
+
450
+ const ROWS: Release[] = [
451
+ { id: 'v5', version: 'v2.4.0', date: '2026-10-21', changes: 38, stable: true },
452
+ { id: 'v4', version: 'v2.4.0-rc.2', date: '2026-10-14', changes: 12, stable: false },
453
+ { id: 'v3', version: 'v2.3.2', date: '2026-09-30', changes: 7, stable: true },
454
+ { id: 'v2', version: 'v2.3.1', date: '2026-09-18', changes: 4, stable: true },
455
+ ]
456
+
457
+ export default function Example() {
458
+ return <DataGrid readOnly toolbar={false} footer={false} defaultColumns={COLUMNS} defaultRows={ROWS} defaultView={{ rowNumbers: false }} style={{ width: 460 }} />
459
+ }
460
+ ```
@@ -0,0 +1,197 @@
1
+ # DatePicker · Calendar
2
+
3
+ > 선택 컨트롤 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
4
+
5
+ 날짜 입력. 입력창처럼 생긴 필드를 누르면 Popover 안에 달력이 열리고, 고르면 닫혀요. 화살표로 하루씩, PageUp/PageDown으로 한 달씩(Shift는 1년) 움직이고, 달을 넘기면 그 방향으로 미끄러져요. 위의 "2026년 10월"을 누르면 한 화면에서 연도(왼쪽 스크롤 목록)와 월(오른쪽)을 고를 수 있고, 월을 누르면 바로 그 달로 돌아와요. Esc는 날짜 화면으로 돌아가요. 기간 선택은 마우스를 올린 날까지 범위를 미리 보여줘요.
6
+
7
+ ```tsx
8
+ import { Calendar, DatePicker, DateRangePicker, type DateRange } from '@iamfiro/design'
9
+ ```
10
+
11
+ ## API
12
+
13
+ ### DatePicker
14
+
15
+ | prop | 타입 | 기본값 | 설명 |
16
+ | --- | --- | --- | --- |
17
+ | `value` | `Date \| null` | | 선택한 날짜(제어). |
18
+ | `defaultValue` | `Date \| null` | `null` | 처음 값(비제어). |
19
+ | `onValueChange` | `(date: Date \| null) => void` | | 고르거나 지울 때. |
20
+ | `formatValue` | `(date: Date) => string` | `"10월 25일"` | 필드에 쓰는 형식. |
21
+ | `placeholder` | `string` | `'날짜 입력 또는 선택'` | 비었을 때 문구. |
22
+ | `clearable` | `boolean` | `true` | × 지우기 버튼. |
23
+ | `min / max` | `Date` | | 고를 수 있는 처음·마지막 날. |
24
+ | `isDateDisabled` | `(date: Date) => boolean` | | 추가로 막을 날(공휴일, 주말…). |
25
+ | `weekStartsOn` | `0 \| 1` | `0` | 0 = 일요일 시작, 1 = 월요일 시작. |
26
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 필드 높이 36 / 44 / 52px. |
27
+ | `invalid / disabled` | `boolean` | | 오류 · 비활성. |
28
+ | `align` | `'start' \| 'end'` | `'start'` | 달력이 필드 어느 쪽에 맞춰 열릴지. |
29
+
30
+ ### DateRangePicker
31
+
32
+ DatePicker와 같은 props에 아래가 다르거나 추가돼요.
33
+
34
+ | prop | 타입 | 기본값 | 설명 |
35
+ | --- | --- | --- | --- |
36
+ | `value / defaultValue` | `DateRange` | | { from: Date \| null, to: Date \| null } |
37
+ | `onValueChange` | `(range: DateRange) => void` | | 시작·끝을 고를 때마다. 두 날짜가 다 고르면 닫혀요. |
38
+ | `presets` | `DatePreset[]` | `DEFAULT_DATE_PRESETS` | { label, range: () => DateRange }[]. []면 숨김. |
39
+
40
+ ### Calendar
41
+
42
+ | prop | 타입 | 기본값 | 설명 |
43
+ | --- | --- | --- | --- |
44
+ | `mode` | `'single' \| 'range'` | `'single'` | 하루 또는 기간. |
45
+ | `value / onValueChange` | `Date \| null · DateRange` | | mode에 맞는 값. |
46
+ | `defaultMonth` | `Date` | | 처음 보여줄 달. 생략하면 선택한 날 또는 오늘. |
47
+ | `min / max / isDateDisabled / weekStartsOn` | `…` | | DatePicker와 같아요. |
48
+ | `autoFocus` | `boolean` | | 처음에 선택한 날(또는 오늘)로 포커스. 팝오버 안에서 써요. |
49
+ | `showFooter` | `boolean` | `true` | 아래 줄("오늘" 버튼, 기간 선택 안내). |
50
+
51
+ ## 예제
52
+
53
+ 예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
54
+
55
+ ### 날짜 선택
56
+
57
+ 값이 올해면 연도는 생략해요("10월 25일"). ×로 지울 수 있어요.
58
+
59
+ ```tsx
60
+ import { useState } from 'react'
61
+ import { Stack, Text, DatePicker, formatDate } from '@iamfiro/design'
62
+
63
+ export default function Example() {
64
+ const [date, setDate] = useState<Date | null>(() => new Date())
65
+ return (
66
+ <Stack gap={2} style={{ width: 260 }}>
67
+ <DatePicker value={date} onValueChange={setDate} aria-label="마감일" />
68
+ <Text variant="caption" tone="tertiary">
69
+ 선택: {date ? formatDate(date, true) : '없음'}
70
+ </Text>
71
+ </Stack>
72
+ )
73
+ }
74
+ ```
75
+
76
+ ### 직접 입력
77
+
78
+ "10/25", "2026.10.25", "10월 25일", "내일"처럼 쳐도 돼요. 완전한 날짜가 되면 달력이 따라오고, Enter로 확정, ↓로 달력에 들어가요. 못 알아들으면 빨갛게 표시하고, 칸을 벗어나면 원래 값으로 돌아가요.
79
+
80
+ ```tsx
81
+ import { useState } from 'react'
82
+ import { Field, Stack, Text, DatePicker, formatDate } from '@iamfiro/design'
83
+
84
+ export default function Example() {
85
+ const [date, setDate] = useState<Date | null>(null)
86
+ return (
87
+ <Stack gap={2} style={{ width: 280 }}>
88
+ <Field label="출발일" htmlFor="depart" hint="예) 10/25 · 2026.10.25 · 10월 25일 · 내일">
89
+ <DatePicker id="depart" value={date} onValueChange={setDate} />
90
+ </Field>
91
+ <Text variant="caption" tone="tertiary">
92
+ 값: {date ? formatDate(date, true) : '없음'}
93
+ </Text>
94
+ </Stack>
95
+ )
96
+ }
97
+ ```
98
+
99
+ ### 기간 선택
100
+
101
+ 두 날짜를 차례로 누르거나, 왼쪽의 빠른 선택(오늘·최근 7일…)을 써요. presets로 바꾸거나 []로 숨겨요.
102
+
103
+ ```tsx
104
+ import { useState } from 'react'
105
+ import { Stack, Text, DateRangePicker, formatDate, type DateRange } from '@iamfiro/design'
106
+
107
+ export default function Example() {
108
+ const [range, setRange] = useState<DateRange>({ from: null, to: null })
109
+ const days = range.from && range.to ? Math.round((range.to.getTime() - range.from.getTime()) / 86400000) + 1 : 0
110
+ return (
111
+ <Stack gap={2} style={{ width: 300 }}>
112
+ <DateRangePicker value={range} onValueChange={setRange} aria-label="조회 기간" />
113
+ <Text variant="caption" tone="tertiary">
114
+ {range.from && range.to ? `${formatDate(range.from)} ~ ${formatDate(range.to)} · ${days}일` : '두 날짜를 고르거나 빠른 선택을 눌러 보세요'}
115
+ </Text>
116
+ </Stack>
117
+ )
118
+ }
119
+ ```
120
+
121
+ ### 선택 가능한 날짜 제한
122
+
123
+ min · max와 isDateDisabled로 지난 날짜와 주말을 막아요. 막힌 날은 취소선으로 보여요.
124
+
125
+ ```tsx
126
+ import { Field, DatePicker } from '@iamfiro/design'
127
+
128
+ const today = new Date()
129
+ const inThreeMonths = new Date(today.getFullYear(), today.getMonth() + 3, today.getDate())
130
+ const isWeekend = (d: Date) => d.getDay() === 0 || d.getDay() === 6
131
+
132
+ export default function Example() {
133
+ return (
134
+ <Field label="미팅 날짜 · 평일, 오늘부터 3개월 안" htmlFor="meeting-date">
135
+ <div style={{ width: 280 }}>
136
+ <DatePicker id="meeting-date" min={today} max={inThreeMonths} isDateDisabled={isWeekend} placeholder="평일을 고르세요" />
137
+ </div>
138
+ </Field>
139
+ )
140
+ }
141
+ ```
142
+
143
+ ### Calendar 단독
144
+
145
+ 팝오버 없이 화면에 바로 두는 달력. 일요일은 빨강, 토요일은 파랑 톤. 아래 "오늘"로 바로 이동하고, 월요일 시작(weekStartsOn={1})도 돼요.
146
+
147
+ ```tsx
148
+ import { useState } from 'react'
149
+ import { Card, CardBody, Calendar, Inline } from '@iamfiro/design'
150
+
151
+ export default function Example() {
152
+ const [date, setDate] = useState<Date | null>(() => new Date())
153
+ return (
154
+ <Inline gap={4} align="start">
155
+ <Card>
156
+ <CardBody>
157
+ <Calendar value={date} onValueChange={setDate} />
158
+ </CardBody>
159
+ </Card>
160
+ <Card>
161
+ <CardBody>
162
+ <Calendar value={date} onValueChange={setDate} weekStartsOn={1} />
163
+ </CardBody>
164
+ </Card>
165
+ </Inline>
166
+ )
167
+ }
168
+ ```
169
+
170
+ ### 크기와 상태
171
+
172
+ Field와 함께 쓰면 라벨이 연결돼요. size · invalid · disabled.
173
+
174
+ ```tsx
175
+ import { Field, Grid, DatePicker } from '@iamfiro/design'
176
+
177
+ const TODAY = new Date()
178
+
179
+ export default function Example() {
180
+ return (
181
+ <Grid columns={2} gap={4} style={{ width: 480 }}>
182
+ <Field label="작게 (sm)" htmlFor="dp-sm">
183
+ <DatePicker id="dp-sm" size="sm" defaultValue={TODAY} />
184
+ </Field>
185
+ <Field label="크게 (lg)" htmlFor="dp-lg">
186
+ <DatePicker id="dp-lg" size="lg" />
187
+ </Field>
188
+ <Field label="시작일" invalid hint="시작일을 골라 주세요." htmlFor="dp-err">
189
+ <DatePicker id="dp-err" invalid />
190
+ </Field>
191
+ <Field label="계약일" htmlFor="dp-off">
192
+ <DatePicker id="dp-off" defaultValue={new Date(2026, 0, 2)} disabled />
193
+ </Field>
194
+ </Grid>
195
+ )
196
+ }
197
+ ```