@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.
- package/AGENTS.md +82 -0
- package/README.md +15 -2
- package/agents/INDEX.md +157 -0
- package/agents/accordion/AGENTS.md +279 -0
- package/agents/action-bar/AGENTS.md +90 -0
- package/agents/alert/AGENTS.md +212 -0
- package/agents/alert-dialog/AGENTS.md +193 -0
- package/agents/app-shell/AGENTS.md +409 -0
- package/agents/area-chart/AGENTS.md +183 -0
- package/agents/aspect-ratio/AGENTS.md +143 -0
- package/agents/avatar/AGENTS.md +130 -0
- package/agents/badge/AGENTS.md +217 -0
- package/agents/bar-chart/AGENTS.md +386 -0
- package/agents/bar-list/AGENTS.md +223 -0
- package/agents/brand-icon/AGENTS.md +82 -0
- package/agents/breadcrumb/AGENTS.md +133 -0
- package/agents/button/AGENTS.md +195 -0
- package/agents/card/AGENTS.md +141 -0
- package/agents/card-frame/AGENTS.md +227 -0
- package/agents/chat-bubble/AGENTS.md +266 -0
- package/agents/chat-composer/AGENTS.md +251 -0
- package/agents/checkbox/AGENTS.md +113 -0
- package/agents/code-block/AGENTS.md +144 -0
- package/agents/color-dot/AGENTS.md +120 -0
- package/agents/color-picker/AGENTS.md +224 -0
- package/agents/colors/AGENTS.md +168 -0
- package/agents/combobox/AGENTS.md +218 -0
- package/agents/command-menu/AGENTS.md +169 -0
- package/agents/comment/AGENTS.md +206 -0
- package/agents/context-menu/AGENTS.md +303 -0
- package/agents/copy-button/AGENTS.md +84 -0
- package/agents/count-badge/AGENTS.md +115 -0
- package/agents/countdown/AGENTS.md +101 -0
- package/agents/data-grid/AGENTS.md +460 -0
- package/agents/date-picker/AGENTS.md +197 -0
- package/agents/delta/AGENTS.md +114 -0
- package/agents/description-list/AGENTS.md +251 -0
- package/agents/dialog/AGENTS.md +391 -0
- package/agents/drawer/AGENTS.md +471 -0
- package/agents/dropdown-menu/AGENTS.md +322 -0
- package/agents/dropzone/AGENTS.md +116 -0
- package/agents/elapsed/AGENTS.md +160 -0
- package/agents/empty-state/AGENTS.md +203 -0
- package/agents/file-chip/AGENTS.md +79 -0
- package/agents/file-icon/AGENTS.md +66 -0
- package/agents/file-upload/AGENTS.md +168 -0
- package/agents/filter-chips/AGENTS.md +167 -0
- package/agents/flag/AGENTS.md +67 -0
- package/agents/funnel-chart/AGENTS.md +131 -0
- package/agents/highlight/AGENTS.md +119 -0
- package/agents/hover-card/AGENTS.md +271 -0
- package/agents/icon-stack/AGENTS.md +120 -0
- package/agents/icon-tile/AGENTS.md +94 -0
- package/agents/inline-diff/AGENTS.md +211 -0
- package/agents/input/AGENTS.md +261 -0
- package/agents/kanban/AGENTS.md +352 -0
- package/agents/kbd/AGENTS.md +160 -0
- package/agents/layout/AGENTS.md +351 -0
- package/agents/line-chart/AGENTS.md +393 -0
- package/agents/link/AGENTS.md +53 -0
- package/agents/list/AGENTS.md +392 -0
- package/agents/marker/AGENTS.md +142 -0
- package/agents/masked-text/AGENTS.md +127 -0
- package/agents/menubar/AGENTS.md +276 -0
- package/agents/multi-select/AGENTS.md +159 -0
- package/agents/navigation-menu/AGENTS.md +315 -0
- package/agents/notice-stack/AGENTS.md +101 -0
- package/agents/number-stepper/AGENTS.md +96 -0
- package/agents/otp-input/AGENTS.md +162 -0
- package/agents/pagination/AGENTS.md +189 -0
- package/agents/phone-input/AGENTS.md +131 -0
- package/agents/pie-chart/AGENTS.md +243 -0
- package/agents/popover/AGENTS.md +190 -0
- package/agents/progress/AGENTS.md +273 -0
- package/agents/progress-tracker/AGENTS.md +305 -0
- package/agents/rating/AGENTS.md +165 -0
- package/agents/relative-time/AGENTS.md +103 -0
- package/agents/resizable/AGENTS.md +390 -0
- package/agents/scaled-preview/AGENTS.md +111 -0
- package/agents/scatter-chart/AGENTS.md +160 -0
- package/agents/scroll-area/AGENTS.md +271 -0
- package/agents/search-input/AGENTS.md +105 -0
- package/agents/segmented-control/AGENTS.md +153 -0
- package/agents/select/AGENTS.md +159 -0
- package/agents/selector-button/AGENTS.md +122 -0
- package/agents/sidebar/AGENTS.md +201 -0
- package/agents/skeleton/AGENTS.md +166 -0
- package/agents/slider/AGENTS.md +181 -0
- package/agents/social-login-button/AGENTS.md +156 -0
- package/agents/spark-chart/AGENTS.md +257 -0
- package/agents/sparkbar/AGENTS.md +92 -0
- package/agents/spinner/AGENTS.md +123 -0
- package/agents/split-view/AGENTS.md +290 -0
- package/agents/stat/AGENTS.md +138 -0
- package/agents/status-icon/AGENTS.md +243 -0
- package/agents/step-list/AGENTS.md +313 -0
- package/agents/table/AGENTS.md +286 -0
- package/agents/tabs/AGENTS.md +305 -0
- package/agents/tag-input/AGENTS.md +246 -0
- package/agents/time-picker/AGENTS.md +228 -0
- package/agents/timeline/AGENTS.md +1018 -0
- package/agents/toast/AGENTS.md +266 -0
- package/agents/toggle-group/AGENTS.md +216 -0
- package/agents/toolbar/AGENTS.md +277 -0
- package/agents/tooltip/AGENTS.md +154 -0
- package/agents/tracker/AGENTS.md +158 -0
- package/agents/tree-diagram/AGENTS.md +260 -0
- package/agents/tree-view/AGENTS.md +329 -0
- package/agents/typography/AGENTS.md +396 -0
- package/lib/components/Accordion/Accordion2.js +135 -0
- package/lib/components/ActionBar/ActionBar2.js +65 -0
- package/lib/components/Alert/Alert2.js +131 -0
- package/lib/components/AppShell/AppShell2.js +94 -0
- package/lib/components/AreaChart/AreaChart.js +59 -0
- package/lib/components/BarChart/BarChart2.js +243 -0
- package/lib/components/BarList/BarList2.js +172 -0
- package/lib/components/Breadcrumb/Breadcrumb2.js +87 -0
- package/lib/components/Calendar/Calendar2.js +309 -0
- package/lib/components/Calendar/DatePicker2.js +229 -0
- package/lib/components/Calendar/date.js +121 -0
- package/lib/components/Card/Card2.js +104 -0
- package/lib/components/CardFrame/CardFrame2.js +72 -0
- package/lib/components/Chart/ChartParts.js +150 -0
- package/lib/components/Chart/chart2.js +96 -0
- package/lib/components/Chart/useChartInteraction.js +94 -0
- package/lib/components/ChatBubble/ChatBubble2.js +174 -0
- package/lib/components/ChatBubble/formatChatTime.js +53 -0
- package/lib/components/ChatComposer/ChatComposer2.js +153 -0
- package/lib/components/CodeBlock/CodeBlock2.js +93 -0
- package/lib/components/CodeBlock/highlight.js +114 -0
- package/lib/components/ColorPicker/ColorPicker2.js +610 -0
- package/lib/components/ColorPicker/color.js +180 -0
- package/lib/components/ColorPicker/presets.js +75 -0
- package/lib/components/Combobox/Combobox2.js +229 -0
- package/lib/components/CommandMenu/CommandMenu.js +267 -0
- package/lib/components/Comment/Comment2.js +134 -0
- package/lib/components/ContextMenu/ContextMenu2.js +168 -0
- package/lib/components/DataGrid/DataGrid2.js +1996 -0
- package/lib/components/DataGrid/GridPopover.js +154 -0
- package/lib/components/DataGrid/anchor.js +50 -0
- package/lib/components/DataGrid/model.js +558 -0
- package/lib/components/DataGrid/panels.js +703 -0
- package/lib/components/DataGrid/typeMeta.js +76 -0
- package/lib/components/DataGrid/types.js +54 -0
- package/lib/components/DescriptionList/DescriptionList2.js +180 -0
- package/lib/components/Dialog/AlertDialog.js +118 -0
- package/lib/components/Dialog/Dialog2.js +109 -0
- package/lib/components/Dialog/modal.js +92 -0
- package/lib/components/Drawer/Drawer2.js +244 -0
- package/lib/components/DropdownMenu/DropdownMenu2.js +394 -0
- package/lib/components/DropdownMenu/menuCore.js +63 -0
- package/lib/components/Dropzone/Dropzone2.js +144 -0
- package/lib/components/EmptyState/EmptyState2.js +72 -0
- package/lib/components/FileChip/FileChip2.js +118 -0
- package/lib/components/FileUpload/FileUpload.js +258 -0
- package/lib/components/FilterChips/FilterChips2.js +101 -0
- package/lib/components/FunnelChart/FunnelChart2.js +283 -0
- package/lib/components/FunnelChart/funnel.js +69 -0
- package/lib/components/Highlight/Highlight2.js +100 -0
- package/lib/components/HoverCard/HoverCard.js +134 -0
- package/lib/components/InlineDiff/InlineDiff2.js +215 -0
- package/lib/components/InlineDiff/diff.js +126 -0
- package/lib/components/InlineDiff/useDiffReview.js +109 -0
- package/lib/components/Kanban/Kanban2.js +691 -0
- package/lib/components/Kanban/KanbanCard.js +159 -0
- package/lib/components/Kanban/move.js +69 -0
- package/lib/components/LineChart/LineChart2.js +342 -0
- package/lib/components/List/List2.js +133 -0
- package/lib/components/Listbox/Listbox2.js +163 -0
- package/lib/components/Marker/Marker2.js +82 -0
- package/lib/components/Menubar/Menubar2.js +223 -0
- package/lib/components/MultiSelect/MultiSelect2.js +204 -0
- package/lib/components/NavigationMenu/NavigationMenu2.js +481 -0
- package/lib/components/NoticeStack/NoticeStack2.js +178 -0
- package/lib/components/NumberStepper/NumberStepper2.js +129 -0
- package/lib/components/OtpInput/OtpInput2.js +122 -0
- package/lib/components/Pagination/Pagination2.js +210 -0
- package/lib/components/Pagination/paginationRange.js +53 -0
- package/lib/components/PhoneInput/PhoneInput.js +175 -0
- package/lib/components/PieChart/PieChart2.js +246 -0
- package/lib/components/PieChart/arc.js +66 -0
- package/lib/components/PieChart/useArcTween.js +94 -0
- package/lib/components/Popover/Popover2.js +112 -0
- package/lib/components/ProgressTracker/ProgressTracker2.js +226 -0
- package/lib/components/Rating/Rating2.js +186 -0
- package/lib/components/Resizable/Resizable2.js +236 -0
- package/lib/components/Resizable/layout.js +115 -0
- package/lib/components/ScaledPreview/ScaledPreview2.js +100 -0
- package/lib/components/ScatterChart/ScatterChart2.js +356 -0
- package/lib/components/ScatterChart/scatter.js +83 -0
- package/lib/components/ScrollArea/ScrollArea2.js +218 -0
- package/lib/components/Select/Select2.js +153 -0
- package/lib/components/Sidebar/Sidebar2.js +127 -0
- package/lib/components/Skeleton/Skeleton2.js +91 -0
- package/lib/components/Slider/Slider2.js +142 -0
- package/lib/components/SocialLoginButton/SocialLoginButton.js +85 -0
- package/lib/components/SparkChart/SparkChart2.js +217 -0
- package/lib/components/SparkChart/spark.js +76 -0
- package/lib/components/Sparkbar/Sparkbar2.js +111 -0
- package/lib/components/SplitView/SplitView2.js +95 -0
- package/lib/components/Stat/Stat2.js +164 -0
- package/lib/components/StepList/StepList2.js +131 -0
- package/lib/components/Table/Table2.js +104 -0
- package/lib/components/Tabs/Tabs2.js +131 -0
- package/lib/components/TagInput/TagInput2.js +360 -0
- package/lib/components/TimePicker/TimePicker2.js +388 -0
- package/lib/components/TimePicker/time.js +83 -0
- package/lib/components/Timeline/Timeline2.js +369 -0
- package/lib/components/Timeline/scale.js +83 -0
- package/lib/components/Toast/Toaster.js +212 -0
- package/lib/components/Toast/store.js +129 -0
- package/lib/components/ToggleGroup/ToggleGroup2.js +125 -0
- package/lib/components/Toolbar/Toolbar2.js +281 -0
- package/lib/components/Tracker/Tracker2.js +172 -0
- package/lib/components/TreeDiagram/TreeDiagram2.js +223 -0
- package/lib/components/TreeView/TreeView2.js +284 -0
- package/lib/hooks/timing.js +55 -0
- package/lib/hooks/useControllableState.js +49 -0
- package/lib/hooks/useCountdown.js +80 -0
- package/lib/hooks/useDigitInput.js +105 -0
- package/lib/hooks/useDismiss.js +71 -0
- package/lib/hooks/useElapsed.js +83 -0
- package/lib/hooks/useFloating.js +70 -0
- package/lib/hooks/useFocusTrap.js +61 -0
- package/lib/hooks/usePresence.js +60 -0
- package/lib/hooks/usePressToOpen.js +69 -0
- package/lib/hooks/useScrollLock.js +70 -0
- package/lib/hooks/useSelection.js +68 -0
- package/lib/index.js +178 -0
- package/lib/primitives/AspectRatio2.js +80 -0
- package/lib/primitives/BrandIcon.js +245 -0
- package/lib/primitives/ColorDot2.js +70 -0
- package/lib/primitives/CopyButton2.js +85 -0
- package/lib/primitives/CountBadge2.js +78 -0
- package/lib/primitives/Countdown2.js +65 -0
- package/lib/primitives/Delta2.js +67 -0
- package/lib/primitives/Elapsed.js +62 -0
- package/lib/primitives/FileIcon2.js +125 -0
- package/lib/primitives/Flag2.js +263 -0
- package/lib/primitives/IconStack2.js +85 -0
- package/lib/primitives/IconTile2.js +68 -0
- package/lib/primitives/Kbd2.js +88 -0
- package/lib/primitives/Layout2.js +118 -0
- package/lib/primitives/Link2.js +53 -0
- package/lib/primitives/MaskedText2.js +120 -0
- package/lib/primitives/Progress2.js +137 -0
- package/lib/primitives/RelativeTime.js +84 -0
- package/lib/primitives/SearchInput2.js +84 -0
- package/lib/primitives/SelectorButton2.js +97 -0
- package/lib/primitives/Spinner2.js +98 -0
- package/lib/primitives/StatusIcon2.js +126 -0
- package/lib/primitives/Swatch2.js +79 -0
- package/lib/primitives/Tooltip2.js +132 -0
- package/lib/primitives/Typography2.js +97 -0
- package/lib/primitives/formatCountdown.js +51 -0
- package/lib/primitives/formatElapsed.js +66 -0
- package/lib/primitives/formatRelativeTime.js +64 -0
- package/lib/primitives/hotkey.js +94 -0
- package/lib/primitives/index.js +352 -0
- package/lib/primitives/maskValue.js +65 -0
- package/lib/style.css +2 -0
- package/lib/types/components/Accordion/Accordion.d.ts +57 -0
- package/lib/types/components/ActionBar/ActionBar.d.ts +24 -0
- package/lib/types/components/Alert/Alert.d.ts +36 -0
- package/lib/types/components/AppShell/AppShell.d.ts +38 -0
- package/lib/types/components/AreaChart/AreaChart.d.ts +17 -0
- package/lib/types/components/BarChart/BarChart.d.ts +57 -0
- package/lib/types/components/BarList/BarList.d.ts +56 -0
- package/lib/types/components/Breadcrumb/Breadcrumb.d.ts +15 -0
- package/lib/types/components/Calendar/Calendar.d.ts +34 -0
- package/lib/types/components/Calendar/DatePicker.d.ts +45 -0
- package/lib/types/components/Calendar/date.d.ts +32 -0
- package/lib/types/components/Card/Card.d.ts +64 -0
- package/lib/types/components/CardFrame/CardFrame.d.ts +15 -0
- package/lib/types/components/Chart/ChartParts.d.ts +38 -0
- package/lib/types/components/Chart/chart.d.ts +46 -0
- package/lib/types/components/Chart/useChartInteraction.d.ts +39 -0
- package/lib/types/components/ChatBubble/ChatBubble.d.ts +61 -0
- package/lib/types/components/ChatBubble/formatChatTime.d.ts +2 -0
- package/lib/types/components/ChatComposer/ChatComposer.d.ts +42 -0
- package/lib/types/components/CodeBlock/CodeBlock.d.ts +18 -0
- package/lib/types/components/CodeBlock/highlight.d.ts +10 -0
- package/lib/types/components/ColorPicker/ColorPicker.d.ts +61 -0
- package/lib/types/components/ColorPicker/color.d.ts +48 -0
- package/lib/types/components/ColorPicker/presets.d.ts +7 -0
- package/lib/types/components/Combobox/Combobox.d.ts +48 -0
- package/lib/types/components/CommandMenu/CommandMenu.d.ts +51 -0
- package/lib/types/components/Comment/Comment.d.ts +45 -0
- package/lib/types/components/ContextMenu/ContextMenu.d.ts +40 -0
- package/lib/types/components/DataGrid/DataGrid.d.ts +43 -0
- package/lib/types/components/DataGrid/GridPopover.d.ts +43 -0
- package/lib/types/components/DataGrid/anchor.d.ts +5 -0
- package/lib/types/components/DataGrid/model.d.ts +61 -0
- package/lib/types/components/DataGrid/panels.d.ts +63 -0
- package/lib/types/components/DataGrid/typeMeta.d.ts +6 -0
- package/lib/types/components/DataGrid/types.d.ts +77 -0
- package/lib/types/components/DescriptionList/DescriptionList.d.ts +77 -0
- package/lib/types/components/Dialog/AlertDialog.d.ts +26 -0
- package/lib/types/components/Dialog/Dialog.d.ts +42 -0
- package/lib/types/components/Dialog/modal.d.ts +38 -0
- package/lib/types/components/Drawer/Drawer.d.ts +62 -0
- package/lib/types/components/DropdownMenu/DropdownMenu.d.ts +97 -0
- package/lib/types/components/DropdownMenu/menuCore.d.ts +23 -0
- package/lib/types/components/Dropzone/Dropzone.d.ts +30 -0
- package/lib/types/components/EmptyState/EmptyState.d.ts +26 -0
- package/lib/types/components/FileChip/FileChip.d.ts +32 -0
- package/lib/types/components/FileUpload/FileUpload.d.ts +52 -0
- package/lib/types/components/FilterChips/FilterChips.d.ts +37 -0
- package/lib/types/components/FunnelChart/FunnelChart.d.ts +38 -0
- package/lib/types/components/FunnelChart/funnel.d.ts +25 -0
- package/lib/types/components/Highlight/Highlight.d.ts +35 -0
- package/lib/types/components/HoverCard/HoverCard.d.ts +47 -0
- package/lib/types/components/InlineDiff/InlineDiff.d.ts +36 -0
- package/lib/types/components/InlineDiff/diff.d.ts +42 -0
- package/lib/types/components/InlineDiff/useDiffReview.d.ts +57 -0
- package/lib/types/components/Kanban/Kanban.d.ts +64 -0
- package/lib/types/components/Kanban/KanbanCard.d.ts +35 -0
- package/lib/types/components/Kanban/move.d.ts +25 -0
- package/lib/types/components/LineChart/LineChart.d.ts +85 -0
- package/lib/types/components/List/List.d.ts +62 -0
- package/lib/types/components/Listbox/Listbox.d.ts +60 -0
- package/lib/types/components/Marker/Marker.d.ts +28 -0
- package/lib/types/components/Menubar/Menubar.d.ts +50 -0
- package/lib/types/components/MultiSelect/MultiSelect.d.ts +38 -0
- package/lib/types/components/NavigationMenu/NavigationMenu.d.ts +101 -0
- package/lib/types/components/NoticeStack/NoticeStack.d.ts +41 -0
- package/lib/types/components/NumberStepper/NumberStepper.d.ts +32 -0
- package/lib/types/components/OtpInput/OtpInput.d.ts +31 -0
- package/lib/types/components/Pagination/Pagination.d.ts +54 -0
- package/lib/types/components/Pagination/paginationRange.d.ts +7 -0
- package/lib/types/components/PhoneInput/PhoneInput.d.ts +47 -0
- package/lib/types/components/PieChart/PieChart.d.ts +67 -0
- package/lib/types/components/PieChart/arc.d.ts +26 -0
- package/lib/types/components/PieChart/useArcTween.d.ts +15 -0
- package/lib/types/components/Popover/Popover.d.ts +28 -0
- package/lib/types/components/ProgressTracker/ProgressTracker.d.ts +64 -0
- package/lib/types/components/Rating/Rating.d.ts +42 -0
- package/lib/types/components/Resizable/Resizable.d.ts +50 -0
- package/lib/types/components/Resizable/layout.d.ts +31 -0
- package/lib/types/components/ScaledPreview/ScaledPreview.d.ts +38 -0
- package/lib/types/components/ScatterChart/ScatterChart.d.ts +81 -0
- package/lib/types/components/ScatterChart/scatter.d.ts +14 -0
- package/lib/types/components/ScrollArea/ScrollArea.d.ts +34 -0
- package/lib/types/components/Select/Select.d.ts +39 -0
- package/lib/types/components/Sidebar/Sidebar.d.ts +39 -0
- package/lib/types/components/Skeleton/Skeleton.d.ts +47 -0
- package/lib/types/components/Slider/Slider.d.ts +36 -0
- package/lib/types/components/SocialLoginButton/SocialLoginButton.d.ts +10 -0
- package/lib/types/components/SparkChart/SparkChart.d.ts +55 -0
- package/lib/types/components/SparkChart/spark.d.ts +16 -0
- package/lib/types/components/Sparkbar/Sparkbar.d.ts +39 -0
- package/lib/types/components/SplitView/SplitView.d.ts +31 -0
- package/lib/types/components/Stat/Stat.d.ts +58 -0
- package/lib/types/components/StepList/StepList.d.ts +61 -0
- package/lib/types/components/Table/Table.d.ts +39 -0
- package/lib/types/components/Tabs/Tabs.d.ts +47 -0
- package/lib/types/components/TagInput/TagInput.d.ts +46 -0
- package/lib/types/components/TimePicker/TimePicker.d.ts +43 -0
- package/lib/types/components/TimePicker/time.d.ts +15 -0
- package/lib/types/components/Timeline/Timeline.d.ts +154 -0
- package/lib/types/components/Timeline/scale.d.ts +22 -0
- package/lib/types/components/Toast/Toaster.d.ts +19 -0
- package/lib/types/components/Toast/index.d.ts +4 -0
- package/lib/types/components/Toast/store.d.ts +75 -0
- package/lib/types/components/ToggleGroup/ToggleGroup.d.ts +28 -0
- package/lib/types/components/Toolbar/Toolbar.d.ts +70 -0
- package/lib/types/components/Tracker/Tracker.d.ts +43 -0
- package/lib/types/components/TreeDiagram/TreeDiagram.d.ts +68 -0
- package/lib/types/components/TreeView/TreeView.d.ts +107 -0
- package/lib/types/components/index.d.ts +188 -0
- package/lib/types/hooks/index.d.ts +17 -0
- package/lib/types/hooks/timing.d.ts +29 -0
- package/lib/types/hooks/useControllableState.d.ts +5 -0
- package/lib/types/hooks/useCountdown.d.ts +19 -0
- package/lib/types/hooks/useDigitInput.d.ts +24 -0
- package/lib/types/hooks/useDismiss.d.ts +3 -0
- package/lib/types/hooks/useElapsed.d.ts +28 -0
- package/lib/types/hooks/useFloating.d.ts +21 -0
- package/lib/types/hooks/useFocusTrap.d.ts +7 -0
- package/lib/types/hooks/usePresence.d.ts +8 -0
- package/lib/types/hooks/usePressToOpen.d.ts +20 -0
- package/lib/types/hooks/useScrollLock.d.ts +2 -0
- package/lib/types/hooks/useSelection.d.ts +29 -0
- package/lib/types/index.d.ts +5 -0
- package/lib/types/primitives/AspectRatio.d.ts +14 -0
- package/lib/types/primitives/BrandIcon.d.ts +12 -0
- package/lib/types/primitives/ColorDot.d.ts +20 -0
- package/lib/types/primitives/CopyButton.d.ts +12 -0
- package/lib/types/primitives/CountBadge.d.ts +28 -0
- package/lib/types/primitives/Countdown.d.ts +21 -0
- package/lib/types/primitives/Delta.d.ts +33 -0
- package/lib/types/primitives/Elapsed.d.ts +23 -0
- package/lib/types/primitives/FileIcon.d.ts +17 -0
- package/lib/types/primitives/Flag.d.ts +15 -0
- package/lib/types/primitives/IconStack.d.ts +27 -0
- package/lib/types/primitives/IconTile.d.ts +24 -0
- package/lib/types/primitives/Kbd.d.ts +19 -0
- package/lib/types/primitives/Layout.d.ts +64 -0
- package/lib/types/primitives/Link.d.ts +12 -0
- package/lib/types/primitives/MaskedText.d.ts +28 -0
- package/lib/types/primitives/Progress.d.ts +52 -0
- package/lib/types/primitives/RelativeTime.d.ts +22 -0
- package/lib/types/primitives/SearchInput.d.ts +8 -0
- package/lib/types/primitives/SelectorButton.d.ts +23 -0
- package/lib/types/primitives/Spinner.d.ts +15 -0
- package/lib/types/primitives/StatusIcon.d.ts +40 -0
- package/lib/types/primitives/Swatch.d.ts +11 -0
- package/lib/types/primitives/Tooltip.d.ts +17 -0
- package/lib/types/primitives/Typography.d.ts +48 -0
- package/lib/types/primitives/formatCountdown.d.ts +2 -0
- package/lib/types/primitives/formatElapsed.d.ts +8 -0
- package/lib/types/primitives/formatRelativeTime.d.ts +16 -0
- package/lib/types/primitives/hotkey.d.ts +10 -0
- package/lib/types/primitives/index.d.ts +188 -0
- package/lib/types/primitives/maskValue.d.ts +24 -0
- package/package.json +55 -4
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
# StepList
|
|
2
|
+
|
|
3
|
+
> 진행 표시 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
|
|
4
|
+
|
|
5
|
+
단계를 세로로 이어 보여 주는 읽기 전용 타임라인. 단계마다 왼쪽에 상태 마커(StatusIcon 또는 번호 원)가 있고 가는 연결선으로 이어져요. 제목 오른쪽엔 걸린 시간 같은 meta, 아래엔 회색 설명과 접는 줄 · 경고 줄 같은 내용을 넣어요. 상태가 바뀌면 마커가 자연스럽게 넘어가고, connector="progress"면 끝난 구간의 선이 아래로 차올라요. 사용자가 직접 체크하는 목록은 ProgressTracker를 써요.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { StepList, StepListItem } from '@iamfiro/design'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 디자인 규칙
|
|
12
|
+
|
|
13
|
+
- 읽기 전용 단계 타임라인(계획 · 활동 기록 · 승인 흐름)은 `StepList`(`ol`, 마커 + 연결선, `meta` 시간, 아래 내용엔 Collapsible inline). 번호 원은 `StatusIcon number`(`persistNumber`면 모든 상태에서 번호). 사용자가 체크하는 목록은 `ProgressTracker`. 카드 아래 상태 띠는 `CardFooter band`.
|
|
14
|
+
|
|
15
|
+
## API
|
|
16
|
+
|
|
17
|
+
### StepList
|
|
18
|
+
|
|
19
|
+
<ol>로 그려지고 진행 중(active) 단계엔 aria-current="step"이 붙어요.
|
|
20
|
+
|
|
21
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `steps` | `StepListStep[]` | | 단계 데이터. 대신 StepListItem을 children으로 조립해도 돼요. |
|
|
24
|
+
| `marker` | `'status' \| 'number' \| 'status-number'` | `'status'` | status: StatusIcon · number: 모든 단계에 번호(테두리가 상태 색) · status-number: StatusIcon인데 대기 단계만 번호. |
|
|
25
|
+
| `connector` | `'default' \| 'progress' \| 'none'` | `'default'` | default: 회색 선 · progress: 끝난 단계 아래 구간이 파랗게 차올라요 · none: 선 없음. |
|
|
26
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 마커 16 · 18 · 22px와 제목 · 설명 글자 크기. |
|
|
27
|
+
| `density` | `'compact' \| 'default' \| 'comfortable'` | `'default'` | 단계 사이 간격 12 · 20 · 32px. |
|
|
28
|
+
| `start` | `number` | `1` | 번호 마커의 첫 번호. |
|
|
29
|
+
| `aria-label` | `string` | | 목록 이름. |
|
|
30
|
+
| `className / style` | `string / CSSProperties` | | <ol>에 전달. |
|
|
31
|
+
|
|
32
|
+
### StepListStep / StepListItem
|
|
33
|
+
|
|
34
|
+
steps 배열의 항목(id 필수)과 StepListItem의 props는 같아요.
|
|
35
|
+
|
|
36
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
37
|
+
| --- | --- | --- | --- |
|
|
38
|
+
| `id` (필수) | `string` | | steps 배열에서만. key로 쓰여요. |
|
|
39
|
+
| `status` (필수) | `'done' \| 'active' \| 'pending' \| 'error' \| 'warning'` | | 단계 상태. |
|
|
40
|
+
| `title` (필수) | `ReactNode` | | 제목. |
|
|
41
|
+
| `description` | `ReactNode` | | 제목 아래 회색 글. Text variant="code" 칩을 함께 넣을 수 있어요. |
|
|
42
|
+
| `meta` | `ReactNode` | | 제목 줄 오른쪽 끝(걸린 시간 "1.9초", Elapsed). |
|
|
43
|
+
| `children` | `ReactNode` | | 설명 아래 내용(Collapsible inline, 경고 줄, FileChip). |
|
|
44
|
+
| `marker` | `'status' \| 'number' \| 'status-number' \| ReactNode` | | 이 단계만 다른 마커. 노드를 넘기면 그대로 그려요. |
|
|
45
|
+
| `number` | `number \| string` | | 번호 마커의 숫자. 기본은 순서(start부터). |
|
|
46
|
+
| `progress` | `number` | | active일 때 0–100. 링이 돌지 않고 그만큼 채워져요. |
|
|
47
|
+
|
|
48
|
+
## 예제
|
|
49
|
+
|
|
50
|
+
예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
|
|
51
|
+
|
|
52
|
+
### 계획 카드
|
|
53
|
+
|
|
54
|
+
Card + CardHeader(eyebrow 오버라인) + StepList + CardFooter band. marker="status-number"라 대기 단계는 번호, 진행 중은 파란 링, 완료는 회색 체크예요. 진행 중 단계와 아래 띠의 경과 시간은 Elapsed로 계속 올라가요.
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
import { ListChecks } from 'lucide-react'
|
|
58
|
+
import { Elapsed, Inline, StatusIcon, Text, formatElapsed, Card, CardBody, CardFooter, CardHeader, StepList, type StepListStep } from '@iamfiro/design'
|
|
59
|
+
|
|
60
|
+
const STEPS: StepListStep[] = [
|
|
61
|
+
{
|
|
62
|
+
id: 'collect',
|
|
63
|
+
status: 'done',
|
|
64
|
+
title: '분기 실적 자료 모으기',
|
|
65
|
+
description: (
|
|
66
|
+
<>
|
|
67
|
+
재무팀 공유 폴더에서 <Text variant="code">q3-actuals.xlsx</Text> 불러옴
|
|
68
|
+
</>
|
|
69
|
+
),
|
|
70
|
+
meta: '1.9초',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: 'compare',
|
|
74
|
+
status: 'done',
|
|
75
|
+
title: '계획 대비 실적 비교',
|
|
76
|
+
description: (
|
|
77
|
+
<>
|
|
78
|
+
부서별 차이를 <Text variant="code">variance</Text> 시트로 정리
|
|
79
|
+
</>
|
|
80
|
+
),
|
|
81
|
+
meta: '42초',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
id: 'charts',
|
|
85
|
+
status: 'done',
|
|
86
|
+
title: '핵심 지표 차트 만들기',
|
|
87
|
+
description: '매출 · 영업이익 · 현금흐름 차트 3개',
|
|
88
|
+
meta: '3분 12초',
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'draft',
|
|
92
|
+
status: 'active',
|
|
93
|
+
title: '보고서 초안 작성',
|
|
94
|
+
description: (
|
|
95
|
+
<>
|
|
96
|
+
<Text variant="code">board-update-q3.docx</Text>에 요약과 차트를 넣는 중
|
|
97
|
+
</>
|
|
98
|
+
),
|
|
99
|
+
// The running step keeps its own timer.
|
|
100
|
+
meta: <Elapsed initial={1052} format={(s) => formatElapsed(s, 'text')} />,
|
|
101
|
+
},
|
|
102
|
+
{ id: 'review', status: 'pending', title: '검토 요청 보내기', description: '김민지 팀장에게 검토 요청' },
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
export default function Example() {
|
|
106
|
+
const done = STEPS.filter((s) => s.status === 'done').length
|
|
107
|
+
return (
|
|
108
|
+
<Card style={{ width: '100%', maxWidth: 480 }}>
|
|
109
|
+
<CardHeader
|
|
110
|
+
eyebrow={
|
|
111
|
+
<Inline gap={1} wrap={false}>
|
|
112
|
+
<ListChecks size={14} aria-hidden />
|
|
113
|
+
계획 · {STEPS.length}단계
|
|
114
|
+
</Inline>
|
|
115
|
+
}
|
|
116
|
+
title="3분기 이사회 보고서 준비"
|
|
117
|
+
/>
|
|
118
|
+
<CardBody>
|
|
119
|
+
<StepList steps={STEPS} marker="status-number" aria-label="보고서 준비 단계" />
|
|
120
|
+
</CardBody>
|
|
121
|
+
<CardFooter band align="between">
|
|
122
|
+
<Inline gap={2} wrap={false}>
|
|
123
|
+
<StatusIcon status="active" size="sm" decorative />
|
|
124
|
+
<Text variant="label-sm" tone="secondary" numeric>
|
|
125
|
+
실행 중 · {done + 1}/{STEPS.length}
|
|
126
|
+
</Text>
|
|
127
|
+
</Inline>
|
|
128
|
+
<Text variant="label-sm" tone="tertiary">
|
|
129
|
+
<Elapsed initial={1060} />
|
|
130
|
+
</Text>
|
|
131
|
+
</CardFooter>
|
|
132
|
+
</Card>
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 활동 기록
|
|
138
|
+
|
|
139
|
+
StepListItem을 직접 조립해요. marker="number"는 모든 단계에 번호를 두고 테두리 색만 상태를 따라가요. 내용 자리엔 IconStack 타일을 단 Collapsible variant="inline"과 주황 경고 줄을 넣었어요. 마지막 단계처럼 marker에 노드를 넘기면 원하는 아이콘을 써요.
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import type { ReactNode } from 'react'
|
|
143
|
+
import { FileSearch, ListChecks, Server, ShieldCheck, TestTube } from 'lucide-react'
|
|
144
|
+
import { IconStack, IconTile, Inline, Stack, Text, Collapsible, StepList, StepListItem } from '@iamfiro/design'
|
|
145
|
+
|
|
146
|
+
const tile = (key: string, icon: ReactNode) => (
|
|
147
|
+
<IconTile key={key} size={18}>
|
|
148
|
+
{icon}
|
|
149
|
+
</IconTile>
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
export default function Example() {
|
|
153
|
+
return (
|
|
154
|
+
<Stack gap={3} style={{ width: '100%', maxWidth: 480 }}>
|
|
155
|
+
<Text as="h3" variant="heading-xs">
|
|
156
|
+
활동
|
|
157
|
+
</Text>
|
|
158
|
+
<StepList marker="number" aria-label="배포 활동">
|
|
159
|
+
<StepListItem status="done" title="배포 설정 확인">
|
|
160
|
+
<Collapsible
|
|
161
|
+
variant="inline"
|
|
162
|
+
icon={
|
|
163
|
+
<IconStack
|
|
164
|
+
shape="square"
|
|
165
|
+
size={18}
|
|
166
|
+
overlap={4}
|
|
167
|
+
icons={[tile('config', <FileSearch size={11} />), tile('security', <ShieldCheck size={11} />)]}
|
|
168
|
+
label="설정 검사, 보안 검사"
|
|
169
|
+
/>
|
|
170
|
+
}
|
|
171
|
+
label="검사 2개 · 1.2초"
|
|
172
|
+
>
|
|
173
|
+
<Text variant="body-sm" tone="secondary">
|
|
174
|
+
환경 변수 14개, 보안 정책 3개 모두 통과
|
|
175
|
+
</Text>
|
|
176
|
+
</Collapsible>
|
|
177
|
+
</StepListItem>
|
|
178
|
+
<StepListItem status="done" title="테스트 실행">
|
|
179
|
+
<Collapsible
|
|
180
|
+
variant="inline"
|
|
181
|
+
icon={<IconStack shape="square" size={18} icons={[tile('unit', <TestTube size={11} />)]} label="단위 테스트" />}
|
|
182
|
+
label="테스트 묶음 1개 · 2분 4초"
|
|
183
|
+
>
|
|
184
|
+
<Text variant="body-sm" tone="secondary">
|
|
185
|
+
812개 통과 · 건너뜀 3개
|
|
186
|
+
</Text>
|
|
187
|
+
</Collapsible>
|
|
188
|
+
</StepListItem>
|
|
189
|
+
<StepListItem status="done" title="스테이징 서버에 배포" description="v2.14.0 · 서버 4대" />
|
|
190
|
+
<StepListItem status="warning" title="운영 서버에 배포">
|
|
191
|
+
<Inline gap={1} wrap={false}>
|
|
192
|
+
<Text as="span" tone="warning" style={{ display: 'inline-flex' }}>
|
|
193
|
+
<ListChecks size={14} aria-hidden />
|
|
194
|
+
</Text>
|
|
195
|
+
<Text variant="label-sm" tone="warning">
|
|
196
|
+
승인을 기다리고 있어요
|
|
197
|
+
</Text>
|
|
198
|
+
</Inline>
|
|
199
|
+
</StepListItem>
|
|
200
|
+
<StepListItem
|
|
201
|
+
status="pending"
|
|
202
|
+
title="배포 후 모니터링"
|
|
203
|
+
description="마커는 직접 넣을 수도 있어요"
|
|
204
|
+
marker={
|
|
205
|
+
<IconTile size={18} round>
|
|
206
|
+
<Server size={11} />
|
|
207
|
+
</IconTile>
|
|
208
|
+
}
|
|
209
|
+
/>
|
|
210
|
+
</StepList>
|
|
211
|
+
</Stack>
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 상태 변화
|
|
217
|
+
|
|
218
|
+
"다음 단계"를 누르면 마커가 링 → 체크로 넘어가고, connector="progress"의 파란 선이 다음 단계까지 위에서 아래로 차올라요.
|
|
219
|
+
|
|
220
|
+
```tsx
|
|
221
|
+
import { useState } from 'react'
|
|
222
|
+
import { RotateCcw } from 'lucide-react'
|
|
223
|
+
import { Button, Inline, Stack, StepList, type StepListStatus, type StepListStep } from '@iamfiro/design'
|
|
224
|
+
|
|
225
|
+
const TITLES = ['코드 가져오기', '빌드', '테스트', '이미지 올리기', '배포']
|
|
226
|
+
|
|
227
|
+
export default function Example() {
|
|
228
|
+
// How many steps are finished; the one after them is running.
|
|
229
|
+
const [done, setDone] = useState(1)
|
|
230
|
+
const steps: StepListStep[] = TITLES.map((title, i) => {
|
|
231
|
+
const status: StepListStatus = i < done ? 'done' : i === done ? 'active' : 'pending'
|
|
232
|
+
return { id: title, status, title, meta: i < done ? `${(i + 1) * 7}초` : undefined }
|
|
233
|
+
})
|
|
234
|
+
return (
|
|
235
|
+
<Stack gap={4} style={{ width: '100%', maxWidth: 360 }}>
|
|
236
|
+
<StepList steps={steps} connector="progress" marker="status-number" density="compact" aria-label="배포 파이프라인" />
|
|
237
|
+
<Inline gap={2}>
|
|
238
|
+
<Button size="sm" variant="primary" disabled={done >= TITLES.length} onClick={() => setDone((d) => d + 1)}>
|
|
239
|
+
다음 단계
|
|
240
|
+
</Button>
|
|
241
|
+
<Button size="sm" variant="ghost" icon={<RotateCcw />} onClick={() => setDone(0)}>
|
|
242
|
+
처음부터
|
|
243
|
+
</Button>
|
|
244
|
+
</Inline>
|
|
245
|
+
</Stack>
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### 상태
|
|
251
|
+
|
|
252
|
+
done · active · pending · error · warning. 기본 marker="status"는 대기를 회색 점선 원으로 그려요.
|
|
253
|
+
|
|
254
|
+
```tsx
|
|
255
|
+
import { Text, StepList, type StepListStep } from '@iamfiro/design'
|
|
256
|
+
|
|
257
|
+
const STEPS: StepListStep[] = [
|
|
258
|
+
{ id: 'submit', status: 'done', title: '휴가 신청서 제출', description: '이도현 · 10월 25일 오전 9:30' },
|
|
259
|
+
{ id: 'lead', status: 'done', title: '팀장 승인', description: '김민지', meta: '12분' },
|
|
260
|
+
{
|
|
261
|
+
id: 'hr',
|
|
262
|
+
status: 'error',
|
|
263
|
+
title: '인사팀 확인',
|
|
264
|
+
description: (
|
|
265
|
+
<>
|
|
266
|
+
남은 연차가 부족해요 · <Text variant="code">잔여 1.5일</Text>
|
|
267
|
+
</>
|
|
268
|
+
),
|
|
269
|
+
meta: '3분',
|
|
270
|
+
},
|
|
271
|
+
{ id: 'fix', status: 'warning', title: '신청 기간 수정', description: '3일 → 1.5일로 바꿔 주세요' },
|
|
272
|
+
{ id: 'final', status: 'pending', title: '최종 승인' },
|
|
273
|
+
]
|
|
274
|
+
|
|
275
|
+
export default function Example() {
|
|
276
|
+
return <StepList steps={STEPS} aria-label="휴가 승인 단계" style={{ width: '100%', maxWidth: 400 }} />
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 크기 · 밀도
|
|
281
|
+
|
|
282
|
+
size는 마커와 글자 크기(sm 16 · md 18 · lg 22px), density는 단계 사이 간격(compact 12 · default 20 · comfortable 32px)이에요.
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
import { Grid, Stack, Text, StepList, type StepListDensity, type StepListSize, type StepListStep } from '@iamfiro/design'
|
|
286
|
+
|
|
287
|
+
const STEPS: StepListStep[] = [
|
|
288
|
+
{ id: 'quote', status: 'done', title: '견적 요청', meta: '2분' },
|
|
289
|
+
{ id: 'review', status: 'active', title: '견적서 검토' },
|
|
290
|
+
{ id: 'sign', status: 'pending', title: '계약서 서명' },
|
|
291
|
+
]
|
|
292
|
+
|
|
293
|
+
const VARIANTS: Array<{ size: StepListSize; density: StepListDensity }> = [
|
|
294
|
+
{ size: 'sm', density: 'compact' },
|
|
295
|
+
{ size: 'md', density: 'default' },
|
|
296
|
+
{ size: 'lg', density: 'comfortable' },
|
|
297
|
+
]
|
|
298
|
+
|
|
299
|
+
export default function Example() {
|
|
300
|
+
return (
|
|
301
|
+
<Grid minItemWidth={160} gap={6} style={{ width: '100%' }}>
|
|
302
|
+
{VARIANTS.map(({ size, density }) => (
|
|
303
|
+
<Stack key={size} gap={3}>
|
|
304
|
+
<Text variant="overline">
|
|
305
|
+
{size} · {density}
|
|
306
|
+
</Text>
|
|
307
|
+
<StepList steps={STEPS} size={size} density={density} marker="number" aria-label={`${size} 크기`} />
|
|
308
|
+
</Stack>
|
|
309
|
+
))}
|
|
310
|
+
</Grid>
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
```
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# Table
|
|
2
|
+
|
|
3
|
+
> 데이터 표시 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
|
|
4
|
+
|
|
5
|
+
격자선 없는 데이터 표. 머리글은 작은 회색 글씨로, 행은 선 대신 옅은 채움으로 구분해요. 열마다 render로 셀을 직접 그리고, 숫자 열은 자릿수가 맞게 정렬해요. 가로로 넘치면 표만 스크롤돼요.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Table, type TableColumn } from '@iamfiro/design'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 디자인 규칙
|
|
12
|
+
|
|
13
|
+
- 차트에서 한 칸을 고르는 화면(피벗)은 `BarChart selected` + `Table selectedKey`를 같은 상태로 묶는다. 고르지 않은 칸은 옅은 색, 고른 칸의 x축 아이콘(`xIcon`)은 흰 칩으로 펼친다. 임계치·이상 구간은 `LineChart referenceLines` · `bands`, 실시간 데이터는 `streaming`(모양 변형 대신 한 칸 미끄러짐) + `endDot="pulse"`.
|
|
14
|
+
- 표: 보여 주기만 하면 `Table`, 편집·정렬·필터·범위 선택이 필요하면 `DataGrid`. 셀 편집·키 입력·클립보드·한글 IME는 셀 위에 놓인 textarea 하나가 모두 받는다(조합 중에 포커스를 옮기면 한글이 깨진다).
|
|
15
|
+
|
|
16
|
+
## API
|
|
17
|
+
|
|
18
|
+
### Table
|
|
19
|
+
|
|
20
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `columns` (필수) | `TableColumn<Row>[]` | | 열 정의. |
|
|
23
|
+
| `rows` (필수) | `Row[]` | | 데이터 행. |
|
|
24
|
+
| `rowKey` | `(row, index) => string \| number` | | 행마다 고유한 key. 생략하면 index. |
|
|
25
|
+
| `density` | `'default' \| 'compact'` | `'default'` | 행 높이. |
|
|
26
|
+
| `striped` | `boolean` | `true` | 행을 번갈아 채워 구분해요. |
|
|
27
|
+
| `headerVariant` | `'label' \| 'overline'` | `'label'` | 머리글 모양. overline은 작은 대문자. |
|
|
28
|
+
| `selectedKey` | `string \| number \| null` | | rowKey가 같은 행을 옅은 회색으로 채워요. |
|
|
29
|
+
| `onRowClick` | `(row, index) => void` | | 행을 누를 때(클릭 · Enter/Space). 주면 hover 채움과 포커스가 생겨요. |
|
|
30
|
+
| `empty` | `ReactNode` | | 행이 없을 때 보여 줄 내용. |
|
|
31
|
+
| `caption` | `ReactNode` | | 표 위 작은 제목. |
|
|
32
|
+
| `className / style` | `string / CSSProperties` | | 스크롤 래퍼에 적용돼요. |
|
|
33
|
+
|
|
34
|
+
### TableColumn
|
|
35
|
+
|
|
36
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
37
|
+
| --- | --- | --- | --- |
|
|
38
|
+
| `key` (필수) | `string` | | 열 id. render가 없으면 row[key]를 보여 줘요. |
|
|
39
|
+
| `header` (필수) | `ReactNode` | | 머리글. |
|
|
40
|
+
| `headerLeading` | `ReactNode` | | 머리글 앞 요소(시리즈 열의 ColorDot). |
|
|
41
|
+
| `render` | `(row, index) => ReactNode` | | 셀 내용을 직접 그릴 때. |
|
|
42
|
+
| `leading` | `(row, index) => ReactNode` | | 셀 내용 앞 요소(첫 열 아이콘). |
|
|
43
|
+
| `width` | `number \| string` | | 열 너비. |
|
|
44
|
+
| `align` | `'start' \| 'center' \| 'end'` | `numeric ? 'end' : 'start'` | 머리글과 셀 정렬. |
|
|
45
|
+
| `numeric` | `boolean` | | 숫자 열. 자릿수가 맞는 tabular 숫자에 기본 오른쪽 정렬. |
|
|
46
|
+
|
|
47
|
+
## 예제
|
|
48
|
+
|
|
49
|
+
예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
|
|
50
|
+
|
|
51
|
+
### 기본
|
|
52
|
+
|
|
53
|
+
columns와 rows를 넘겨요. render가 없으면 row[key]를 그대로 보여 주고, numeric 열은 tabular 숫자로, align="end"면 오른쪽 정렬돼요.
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
import { Avatar, Badge, Text, type Tone, Table, type TableColumn } from '@iamfiro/design'
|
|
57
|
+
|
|
58
|
+
interface Member {
|
|
59
|
+
id: string
|
|
60
|
+
name: string
|
|
61
|
+
email: string
|
|
62
|
+
role: string
|
|
63
|
+
status: 'active' | 'invited' | 'suspended'
|
|
64
|
+
lastSeen: string
|
|
65
|
+
storage: number
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const MEMBERS: Member[] = [
|
|
69
|
+
{ id: 'u1', name: '김민지', email: 'minji@lumen.app', role: '관리자', status: 'active', lastSeen: '2분 전', storage: 12.4 },
|
|
70
|
+
{ id: 'u2', name: '이도현', email: 'dohyun@lumen.app', role: '편집자', status: 'active', lastSeen: '1시간 전', storage: 8.15 },
|
|
71
|
+
{ id: 'u3', name: '박서연', email: 'seoyeon@lumen.app', role: '편집자', status: 'invited', lastSeen: '—', storage: 0 },
|
|
72
|
+
{ id: 'u4', name: '최준호', email: 'junho@lumen.app', role: '뷰어', status: 'suspended', lastSeen: '10월 3일', storage: 1.02 },
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
const STATUS: Record<Member['status'], { label: string; tone: Tone }> = {
|
|
76
|
+
active: { label: '활성', tone: 'success' },
|
|
77
|
+
invited: { label: '초대됨', tone: 'info' },
|
|
78
|
+
suspended: { label: '정지', tone: 'danger' },
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const COLUMNS: TableColumn<Member>[] = [
|
|
82
|
+
{
|
|
83
|
+
key: 'name',
|
|
84
|
+
header: '멤버',
|
|
85
|
+
render: (m) => (
|
|
86
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
|
|
87
|
+
<Avatar name={m.name} />
|
|
88
|
+
<div>
|
|
89
|
+
<Text variant="label-md" as="div">
|
|
90
|
+
{m.name}
|
|
91
|
+
</Text>
|
|
92
|
+
<Text variant="caption" tone="tertiary" as="div">
|
|
93
|
+
{m.email}
|
|
94
|
+
</Text>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
),
|
|
98
|
+
},
|
|
99
|
+
{ key: 'role', header: '역할' },
|
|
100
|
+
{
|
|
101
|
+
key: 'status',
|
|
102
|
+
header: '상태',
|
|
103
|
+
render: (m) => (
|
|
104
|
+
<Badge tone={STATUS[m.status].tone} dot>
|
|
105
|
+
{STATUS[m.status].label}
|
|
106
|
+
</Badge>
|
|
107
|
+
),
|
|
108
|
+
},
|
|
109
|
+
{ key: 'lastSeen', header: '최근 활동' },
|
|
110
|
+
{ key: 'storage', header: '사용량', align: 'end', numeric: true, render: (m) => `${m.storage.toFixed(2)} GB` },
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
export default function Example() {
|
|
114
|
+
return <Table caption="멤버 4명" columns={COLUMNS} rows={MEMBERS} rowKey={(m) => m.id} style={{ width: 640 }} />
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 간격 · 줄무늬
|
|
119
|
+
|
|
120
|
+
density="compact"는 행 높이를 줄여요. striped를 끄면 행 구분 채움이 사라져요.
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
import { useState } from 'react'
|
|
124
|
+
import { SegmentedControl, Switch, Table, type TableColumn } from '@iamfiro/design'
|
|
125
|
+
|
|
126
|
+
interface Invoice {
|
|
127
|
+
id: string
|
|
128
|
+
date: string
|
|
129
|
+
plan: string
|
|
130
|
+
seats: number
|
|
131
|
+
amount: number
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const INVOICES: Invoice[] = [
|
|
135
|
+
{ id: 'INV-2610', date: '10월 1일', plan: '팀', seats: 12, amount: 180000 },
|
|
136
|
+
{ id: 'INV-2609', date: '9월 1일', plan: '팀', seats: 10, amount: 150000 },
|
|
137
|
+
{ id: 'INV-2608', date: '8월 1일', plan: '팀', seats: 10, amount: 150000 },
|
|
138
|
+
{ id: 'INV-2607', date: '7월 1일', plan: '스타터', seats: 4, amount: 36000 },
|
|
139
|
+
{ id: 'INV-2606', date: '6월 1일', plan: '스타터', seats: 3, amount: 27000 },
|
|
140
|
+
]
|
|
141
|
+
|
|
142
|
+
const COLUMNS: TableColumn<Invoice>[] = [
|
|
143
|
+
{ key: 'id', header: '청구서' },
|
|
144
|
+
{ key: 'date', header: '발행일' },
|
|
145
|
+
{ key: 'plan', header: '플랜' },
|
|
146
|
+
{ key: 'seats', header: '좌석', align: 'end', numeric: true },
|
|
147
|
+
{ key: 'amount', header: '금액', align: 'end', numeric: true, render: (r) => `${r.amount.toLocaleString('ko-KR')}원` },
|
|
148
|
+
]
|
|
149
|
+
|
|
150
|
+
export default function Example() {
|
|
151
|
+
const [density, setDensity] = useState<'default' | 'compact'>('default')
|
|
152
|
+
const [striped, setStriped] = useState(true)
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<div style={{ display: 'grid', gap: 16, width: 560 }}>
|
|
156
|
+
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
|
157
|
+
<SegmentedControl
|
|
158
|
+
value={density}
|
|
159
|
+
onChange={setDensity}
|
|
160
|
+
ariaLabel="행 간격"
|
|
161
|
+
options={[
|
|
162
|
+
{ value: 'default', label: '기본' },
|
|
163
|
+
{ value: 'compact', label: '촘촘하게' },
|
|
164
|
+
]}
|
|
165
|
+
/>
|
|
166
|
+
<Switch label="줄무늬" checked={striped} onChange={(e) => setStriped(e.target.checked)} />
|
|
167
|
+
</div>
|
|
168
|
+
<Table columns={COLUMNS} rows={INVOICES} rowKey={(r) => r.id} density={density} striped={striped} />
|
|
169
|
+
</div>
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### 빈 상태
|
|
175
|
+
|
|
176
|
+
행이 없으면 empty에 넣은 내용(보통 EmptyState)을 표 너비 전체에 보여 줘요.
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
import { useState } from 'react'
|
|
180
|
+
import { SearchX } from 'lucide-react'
|
|
181
|
+
import { Button, SearchInput, EmptyState, Table, type TableColumn } from '@iamfiro/design'
|
|
182
|
+
|
|
183
|
+
interface Project {
|
|
184
|
+
name: string
|
|
185
|
+
owner: string
|
|
186
|
+
updated: string
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const PROJECTS: Project[] = [
|
|
190
|
+
{ name: '웹사이트 리뉴얼', owner: '김민지', updated: '2분 전' },
|
|
191
|
+
{ name: '모바일 앱 2.0', owner: '이도현', updated: '어제' },
|
|
192
|
+
{ name: '디자인 시스템', owner: '박서연', updated: '10월 21일' },
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
const COLUMNS: TableColumn<Project>[] = [
|
|
196
|
+
{ key: 'name', header: '프로젝트' },
|
|
197
|
+
{ key: 'owner', header: '담당자' },
|
|
198
|
+
{ key: 'updated', header: '수정', align: 'end' },
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
export default function Example() {
|
|
202
|
+
const [query, setQuery] = useState('결제')
|
|
203
|
+
const rows = PROJECTS.filter((p) => p.name.includes(query.trim()))
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<div style={{ display: 'grid', gap: 16, width: 520 }}>
|
|
207
|
+
<SearchInput size="sm" placeholder="프로젝트 검색" value={query} onChange={(e) => setQuery(e.target.value)} aria-label="프로젝트 검색" />
|
|
208
|
+
<Table
|
|
209
|
+
columns={COLUMNS}
|
|
210
|
+
rows={rows}
|
|
211
|
+
rowKey={(p) => p.name}
|
|
212
|
+
empty={
|
|
213
|
+
<EmptyState
|
|
214
|
+
size="sm"
|
|
215
|
+
icon={<SearchX />}
|
|
216
|
+
title="검색 결과가 없어요"
|
|
217
|
+
description={`‘${query}’와 일치하는 프로젝트가 없어요.`}
|
|
218
|
+
actions={
|
|
219
|
+
<Button size="sm" onClick={() => setQuery('')}>
|
|
220
|
+
검색어 지우기
|
|
221
|
+
</Button>
|
|
222
|
+
}
|
|
223
|
+
/>
|
|
224
|
+
}
|
|
225
|
+
/>
|
|
226
|
+
</div>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### 행 선택 · 오버라인 머리글
|
|
232
|
+
|
|
233
|
+
onRowClick을 주면 행에 hover 채움이 생기고 Tab · Enter/Space로도 눌러요. selectedKey와 같은 행은 옅은 회색으로 채워요. headerVariant="overline"은 작은 대문자 머리글, headerLeading은 머리글 앞 ColorDot, leading은 첫 열 아이콘이에요. numeric 열은 오른쪽 정렬 + tabular 숫자예요. 차트와 연동하는 예는 BarChart의 "표와 연동"을 보세요.
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
import { useState, type ReactNode } from 'react'
|
|
237
|
+
import { CreditCard, Globe, Search, Server, Smartphone } from 'lucide-react'
|
|
238
|
+
import { Table, type TableColumn, ColorDot, Stack, Text } from '@iamfiro/design'
|
|
239
|
+
|
|
240
|
+
interface Service {
|
|
241
|
+
id: string
|
|
242
|
+
name: string
|
|
243
|
+
icon: ReactNode
|
|
244
|
+
success: number
|
|
245
|
+
rollback: number
|
|
246
|
+
failed: number
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const SERVICES: Service[] = [
|
|
250
|
+
{ id: 'web', name: '웹', icon: <Globe size={16} color="var(--text-3)" />, success: 42, rollback: 3, failed: 2 },
|
|
251
|
+
{ id: 'mobile', name: '모바일', icon: <Smartphone size={16} color="var(--text-3)" />, success: 18, rollback: 1, failed: 1 },
|
|
252
|
+
{ id: 'api', name: 'API', icon: <Server size={16} color="var(--text-3)" />, success: 57, rollback: 5, failed: 4 },
|
|
253
|
+
{ id: 'billing', name: '결제', icon: <CreditCard size={16} color="var(--text-3)" />, success: 12, rollback: 2, failed: 0 },
|
|
254
|
+
{ id: 'search', name: '검색', icon: <Search size={16} color="var(--text-3)" />, success: 25, rollback: 0, failed: 1 },
|
|
255
|
+
]
|
|
256
|
+
|
|
257
|
+
const COLUMNS: TableColumn<Service>[] = [
|
|
258
|
+
{ key: 'name', header: '서비스', leading: (s) => s.icon },
|
|
259
|
+
{ key: 'total', header: '배포', numeric: true, render: (s) => s.success + s.rollback + s.failed },
|
|
260
|
+
{ key: 'success', header: '성공', headerLeading: <ColorDot color="--chart-3" />, numeric: true },
|
|
261
|
+
{ key: 'rollback', header: '롤백', headerLeading: <ColorDot color="--warning" />, numeric: true },
|
|
262
|
+
{ key: 'failed', header: '실패', headerLeading: <ColorDot color="--danger" />, numeric: true },
|
|
263
|
+
]
|
|
264
|
+
|
|
265
|
+
export default function Example() {
|
|
266
|
+
const [selected, setSelected] = useState<string | null>('api')
|
|
267
|
+
const service = SERVICES.find((s) => s.id === selected)
|
|
268
|
+
|
|
269
|
+
return (
|
|
270
|
+
<Stack gap={3} style={{ width: 560 }}>
|
|
271
|
+
<Table
|
|
272
|
+
columns={COLUMNS}
|
|
273
|
+
rows={SERVICES}
|
|
274
|
+
rowKey={(s) => s.id}
|
|
275
|
+
headerVariant="overline"
|
|
276
|
+
striped={false}
|
|
277
|
+
selectedKey={selected}
|
|
278
|
+
onRowClick={(s) => setSelected((cur) => (cur === s.id ? null : s.id))}
|
|
279
|
+
/>
|
|
280
|
+
<Text variant="body-sm" tone="secondary">
|
|
281
|
+
{service ? `${service.name} 서비스를 골랐어요. 다시 누르면 선택이 풀려요.` : '행을 누르거나 Tab으로 옮겨 Enter를 눌러 보세요.'}
|
|
282
|
+
</Text>
|
|
283
|
+
</Stack>
|
|
284
|
+
)
|
|
285
|
+
}
|
|
286
|
+
```
|