@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,290 @@
|
|
|
1
|
+
# SplitView
|
|
2
|
+
|
|
3
|
+
> 컨테이너 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
|
|
4
|
+
|
|
5
|
+
목록 – 상세(master–detail) 두 칸 레이아웃. 왼쪽 목록과 오른쪽 상세가 각자 스크롤되고, 목록은 옅은 회색 판 위에 놓여 ListItem variant="raised"로 고른 행이 흰 카드처럼 떠올라요. resizable이면 가운데 경계를 끌거나, 포커스한 뒤 ← → 로 목록 너비를 바꿔요. 높이는 부모가 정해요.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { SplitView } from '@iamfiro/design'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 디자인 규칙
|
|
12
|
+
|
|
13
|
+
- 목록–상세는 `SplitView`(칸마다 스크롤, 경계는 `role="separator"`). 회색 판 위의 선택 행은 `ListItem variant="raised"`.
|
|
14
|
+
|
|
15
|
+
## API
|
|
16
|
+
|
|
17
|
+
### SplitView
|
|
18
|
+
|
|
19
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
20
|
+
| --- | --- | --- | --- |
|
|
21
|
+
| `list` (필수) | `ReactNode` | | 왼쪽 목록 칸. |
|
|
22
|
+
| `children` (필수) | `ReactNode` | | 오른쪽 상세 칸. 세로 flex라 ActionBar가 아래에 붙어요. |
|
|
23
|
+
| `listWidth` | `number` | | 목록 너비 px(제어). |
|
|
24
|
+
| `defaultListWidth` | `number` | `300` | 처음 너비(비제어). 더블 클릭 · Enter로 돌아가는 너비. |
|
|
25
|
+
| `onListWidthChange` | `(width: number) => void` | | 끌거나 키로 바꿀 때. |
|
|
26
|
+
| `minListWidth / maxListWidth` | `number` | `220 / 520` | 너비 범위. |
|
|
27
|
+
| `resizable` | `boolean` | | 경계를 끌어 너비 조절. role="separator"(aria-valuenow), ← → (Shift는 크게) · Home / End. |
|
|
28
|
+
| `listTone` | `'soft' \| 'plain'` | `'soft'` | soft: 목록 칸이 옅은 회색 판 · plain: 흰 바탕. |
|
|
29
|
+
| `listLabel / detailLabel` | `string` | `'목록' / '상세'` | 두 칸(section)의 접근성 이름. |
|
|
30
|
+
| `className / style` | `string / CSSProperties` | | 바깥 요소에 전달. 부모가 flex 세로면 style={{ flex: 1, minHeight: 0 }}. |
|
|
31
|
+
|
|
32
|
+
## 예제
|
|
33
|
+
|
|
34
|
+
예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
|
|
35
|
+
|
|
36
|
+
### 검토 대기열
|
|
37
|
+
|
|
38
|
+
위쪽은 제목 · 작은 진행 막대 · "26 / 33 검토" · 실행 취소(Z). 왼쪽은 개수가 붙은 Tabs와 요청 목록, 오른쪽은 요청 내용과 아래에 붙은 ActionBar(승인 A · 수정 E · 거절 R · 건너뛰기 S). 처리 중엔 버튼과 단축키가 잠기고, 끝나면 다음 요청이 골라져요.
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { useEffect, useState, type ReactNode } from 'react'
|
|
42
|
+
import { Check, ChevronsRight, CircleCheck, FileSignature, KeyRound, Pencil, Receipt, Undo2, UserPlus, X } from 'lucide-react'
|
|
43
|
+
import { Badge, Box, Button, Grid, IconTile, Inline, Progress, Stack, Text, ActionBar, Card, List, ListItem, SplitView, Tab, TabList, TabPanel, Tabs } from '@iamfiro/design'
|
|
44
|
+
|
|
45
|
+
interface ReviewItem {
|
|
46
|
+
id: string
|
|
47
|
+
icon: ReactNode
|
|
48
|
+
title: string
|
|
49
|
+
kind: string
|
|
50
|
+
time: string
|
|
51
|
+
from: string
|
|
52
|
+
risk?: boolean
|
|
53
|
+
note: string
|
|
54
|
+
amount: string
|
|
55
|
+
due: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const REQUESTS: ReviewItem[] = [
|
|
59
|
+
{ id: 'r1', icon: <Receipt />, title: '10월 법인 카드 정산', kind: '경비', time: '방금', from: '김민지', risk: true, note: '영수증 12장 중 2장의 금액이 카드 내역과 달라요.', amount: '1,248,000원', due: '10월 27일' },
|
|
60
|
+
{ id: 'r2', icon: <UserPlus />, title: '이도현 님 관리자 권한 요청', kind: '권한', time: '14분', from: '이도현', note: '디자인팀 워크스페이스의 관리자 권한을 요청했어요.', amount: '—', due: '10월 26일' },
|
|
61
|
+
{ id: 'r3', icon: <FileSignature />, title: '협력사 계약서 갱신', kind: '계약', time: '1시간', from: '김민지', note: '단가가 작년보다 4% 올랐어요. 나머지 조건은 같아요.', amount: '32,000,000원', due: '10월 31일' },
|
|
62
|
+
{ id: 'r4', icon: <KeyRound />, title: '외부 공유 링크 허용', kind: '보안', time: '2시간', from: '이도현', risk: true, note: '고객사에 보낼 폴더를 링크로 공유하려고 해요.', amount: '—', due: '10월 25일' },
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
const REVIEWED_BEFORE = 26
|
|
66
|
+
const TOTAL = REVIEWED_BEFORE + REQUESTS.length
|
|
67
|
+
|
|
68
|
+
export default function Example() {
|
|
69
|
+
const [queue, setQueue] = useState(REQUESTS)
|
|
70
|
+
const [done, setDone] = useState<ReviewItem[]>([])
|
|
71
|
+
const [tab, setTab] = useState('all')
|
|
72
|
+
const [selectedId, setSelectedId] = useState(REQUESTS[0].id)
|
|
73
|
+
const [pending, setPending] = useState(false)
|
|
74
|
+
|
|
75
|
+
const shown = tab === 'risk' ? queue.filter((r) => r.risk) : queue
|
|
76
|
+
const selected = queue.find((r) => r.id === selectedId) ?? shown[0]
|
|
77
|
+
|
|
78
|
+
// 데모용 처리: 0.6초 동안 잠갔다가 목록에서 빼고 다음 요청을 골라요.
|
|
79
|
+
useEffect(() => {
|
|
80
|
+
if (!pending || !selected) return
|
|
81
|
+
const id = window.setTimeout(() => {
|
|
82
|
+
const rest = queue.filter((r) => r.id !== selected.id)
|
|
83
|
+
setQueue(rest)
|
|
84
|
+
setDone((d) => [selected, ...d])
|
|
85
|
+
setSelectedId(rest[0]?.id ?? '')
|
|
86
|
+
setPending(false)
|
|
87
|
+
}, 600)
|
|
88
|
+
return () => window.clearTimeout(id)
|
|
89
|
+
}, [pending, selected, queue])
|
|
90
|
+
|
|
91
|
+
const undo = () => {
|
|
92
|
+
const [last, ...older] = done
|
|
93
|
+
if (!last) return
|
|
94
|
+
setDone(older)
|
|
95
|
+
setQueue((q) => REQUESTS.filter((r) => r.id === last.id || q.some((x) => x.id === r.id)))
|
|
96
|
+
setSelectedId(last.id)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const act = () => setPending(true)
|
|
100
|
+
const reviewed = REVIEWED_BEFORE + done.length
|
|
101
|
+
|
|
102
|
+
const rows = (items: ReviewItem[]) => (
|
|
103
|
+
<List density="compact" aria-label="검토할 요청">
|
|
104
|
+
{items.map((r) => (
|
|
105
|
+
<ListItem
|
|
106
|
+
key={r.id}
|
|
107
|
+
variant="raised"
|
|
108
|
+
selected={selected?.id === r.id}
|
|
109
|
+
onClick={() => setSelectedId(r.id)}
|
|
110
|
+
leading={<IconTile tone="surface">{r.icon}</IconTile>}
|
|
111
|
+
title={r.title}
|
|
112
|
+
description={r.kind}
|
|
113
|
+
meta={r.time}
|
|
114
|
+
/>
|
|
115
|
+
))}
|
|
116
|
+
</List>
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<Card padding="none" style={{ width: '100%', maxWidth: 880, height: 520 }}>
|
|
121
|
+
<Box paddingX={4} paddingY={3}>
|
|
122
|
+
<Inline justify="between" wrap={false}>
|
|
123
|
+
<Inline gap={2} wrap={false}>
|
|
124
|
+
<IconTile tone="accent" size={24}>
|
|
125
|
+
<CircleCheck />
|
|
126
|
+
</IconTile>
|
|
127
|
+
<Text variant="label-md">검토 센터</Text>
|
|
128
|
+
<Progress value={reviewed} max={TOTAL} size="sm" tone="accent" aria-label="검토 진행률" style={{ width: 72 }} />
|
|
129
|
+
<Text variant="label-sm" numeric>
|
|
130
|
+
{reviewed} / {TOTAL} 검토
|
|
131
|
+
</Text>
|
|
132
|
+
<Text variant="caption" tone="tertiary">
|
|
133
|
+
가장 오래된 요청 2시간
|
|
134
|
+
</Text>
|
|
135
|
+
</Inline>
|
|
136
|
+
<Button variant="ghost" size="sm" icon={<Undo2 />} shortcut="Z" hotkey disabled={done.length === 0 || pending} onClick={undo}>
|
|
137
|
+
실행 취소
|
|
138
|
+
</Button>
|
|
139
|
+
</Inline>
|
|
140
|
+
</Box>
|
|
141
|
+
|
|
142
|
+
<SplitView
|
|
143
|
+
resizable
|
|
144
|
+
defaultListWidth={300}
|
|
145
|
+
listLabel="요청 목록"
|
|
146
|
+
detailLabel="요청 내용"
|
|
147
|
+
style={{ flex: 1, minHeight: 0 }}
|
|
148
|
+
list={
|
|
149
|
+
<Tabs value={tab} onValueChange={setTab}>
|
|
150
|
+
<TabList size="sm" aria-label="요청 거르기">
|
|
151
|
+
<Tab value="all" count={queue.length}>
|
|
152
|
+
전체
|
|
153
|
+
</Tab>
|
|
154
|
+
<Tab value="risk" count={queue.filter((r) => r.risk).length}>
|
|
155
|
+
위험 높음
|
|
156
|
+
</Tab>
|
|
157
|
+
</TabList>
|
|
158
|
+
<TabPanel value="all">{rows(queue)}</TabPanel>
|
|
159
|
+
<TabPanel value="risk">{rows(queue.filter((r) => r.risk))}</TabPanel>
|
|
160
|
+
</Tabs>
|
|
161
|
+
}
|
|
162
|
+
>
|
|
163
|
+
{selected ? (
|
|
164
|
+
<>
|
|
165
|
+
<Box padding={5}>
|
|
166
|
+
<Stack gap={4}>
|
|
167
|
+
<Inline gap={2}>
|
|
168
|
+
<Text variant="label-md">{selected.from}</Text>
|
|
169
|
+
{selected.risk && (
|
|
170
|
+
<Badge tone="danger" size="sm">
|
|
171
|
+
위험 높음
|
|
172
|
+
</Badge>
|
|
173
|
+
)}
|
|
174
|
+
<Text variant="caption" tone="tertiary">
|
|
175
|
+
{selected.kind} · {selected.time} 전
|
|
176
|
+
</Text>
|
|
177
|
+
</Inline>
|
|
178
|
+
<Text variant="heading-sm">{selected.title}</Text>
|
|
179
|
+
<Text variant="body-md" tone="secondary">
|
|
180
|
+
{selected.note}
|
|
181
|
+
</Text>
|
|
182
|
+
<Grid columns={2} gap={4} style={{ maxWidth: 360 }}>
|
|
183
|
+
<Stack gap={1}>
|
|
184
|
+
<Text variant="caption" tone="tertiary">
|
|
185
|
+
금액
|
|
186
|
+
</Text>
|
|
187
|
+
<Text variant="label-md" numeric>
|
|
188
|
+
{selected.amount}
|
|
189
|
+
</Text>
|
|
190
|
+
</Stack>
|
|
191
|
+
<Stack gap={1}>
|
|
192
|
+
<Text variant="caption" tone="tertiary">
|
|
193
|
+
기한
|
|
194
|
+
</Text>
|
|
195
|
+
<Text variant="label-md">{selected.due}</Text>
|
|
196
|
+
</Stack>
|
|
197
|
+
</Grid>
|
|
198
|
+
</Stack>
|
|
199
|
+
</Box>
|
|
200
|
+
<ActionBar pending={pending} aria-label="요청 처리">
|
|
201
|
+
<Button variant="primary" icon={<Check />} shortcut="A" hotkey loading={pending} onClick={act}>
|
|
202
|
+
승인
|
|
203
|
+
</Button>
|
|
204
|
+
<Button variant="ghost" icon={<Pencil />} shortcut="E" hotkey onClick={act}>
|
|
205
|
+
수정
|
|
206
|
+
</Button>
|
|
207
|
+
<Button variant="ghost" icon={<X />} shortcut="R" hotkey onClick={act}>
|
|
208
|
+
거절
|
|
209
|
+
</Button>
|
|
210
|
+
<Button variant="ghost" icon={<ChevronsRight />} shortcut="S" hotkey onClick={act}>
|
|
211
|
+
건너뛰기
|
|
212
|
+
</Button>
|
|
213
|
+
</ActionBar>
|
|
214
|
+
</>
|
|
215
|
+
) : (
|
|
216
|
+
<Box padding={6}>
|
|
217
|
+
<Text variant="body-md" tone="tertiary" align="center">
|
|
218
|
+
모든 요청을 검토했어요.
|
|
219
|
+
</Text>
|
|
220
|
+
</Box>
|
|
221
|
+
)}
|
|
222
|
+
</SplitView>
|
|
223
|
+
</Card>
|
|
224
|
+
)
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### 너비 제어
|
|
229
|
+
|
|
230
|
+
listWidth / onListWidthChange로 제어해요. 경계를 끄는 동안엔 포인터를 그대로 따르고, 키보드 · 버튼으로 바꾸면 부드럽게 움직여요. 끄는 중 Esc는 원래 너비로, 더블 클릭 · Enter는 기본 너비로 돌아가요.
|
|
231
|
+
|
|
232
|
+
```tsx
|
|
233
|
+
import { useState } from 'react'
|
|
234
|
+
import { Bell, Lock, User } from 'lucide-react'
|
|
235
|
+
import { Box, Button, Inline, Stack, Text, Card, List, ListItem, SplitView } from '@iamfiro/design'
|
|
236
|
+
|
|
237
|
+
const SECTIONS = [
|
|
238
|
+
{ id: 'profile', icon: <User />, title: '프로필', body: '이름, 사진, 소개를 바꿔요. 김민지 님의 프로필은 팀원 모두에게 보여요.' },
|
|
239
|
+
{ id: 'alarm', icon: <Bell />, title: '알림', body: '멘션과 승인 요청만 바로 알려 드리고, 나머지는 하루 한 번 모아서 보내요.' },
|
|
240
|
+
{ id: 'security', icon: <Lock />, title: '보안', body: '2단계 인증이 켜져 있어요. 마지막 로그인은 10월 25일 오전 9시예요.' },
|
|
241
|
+
]
|
|
242
|
+
|
|
243
|
+
export default function Example() {
|
|
244
|
+
const [width, setWidth] = useState(220)
|
|
245
|
+
const [selected, setSelected] = useState('profile')
|
|
246
|
+
const section = SECTIONS.find((s) => s.id === selected) ?? SECTIONS[0]
|
|
247
|
+
return (
|
|
248
|
+
<Stack gap={3} style={{ width: '100%', maxWidth: 640 }}>
|
|
249
|
+
<Inline gap={2}>
|
|
250
|
+
<Text variant="caption" tone="tertiary" numeric>
|
|
251
|
+
목록 너비 {width}px
|
|
252
|
+
</Text>
|
|
253
|
+
<Button size="sm" variant="ghost" onClick={() => setWidth(180)}>
|
|
254
|
+
좁게
|
|
255
|
+
</Button>
|
|
256
|
+
<Button size="sm" variant="ghost" onClick={() => setWidth(300)}>
|
|
257
|
+
넓게
|
|
258
|
+
</Button>
|
|
259
|
+
</Inline>
|
|
260
|
+
<Card padding="none" style={{ height: 280 }}>
|
|
261
|
+
<SplitView
|
|
262
|
+
resizable
|
|
263
|
+
listWidth={width}
|
|
264
|
+
onListWidthChange={setWidth}
|
|
265
|
+
minListWidth={160}
|
|
266
|
+
maxListWidth={360}
|
|
267
|
+
listLabel="설정 목록"
|
|
268
|
+
detailLabel="설정 내용"
|
|
269
|
+
list={
|
|
270
|
+
<List aria-label="설정">
|
|
271
|
+
{SECTIONS.map((s) => (
|
|
272
|
+
<ListItem key={s.id} variant="raised" leading={s.icon} title={s.title} selected={selected === s.id} onClick={() => setSelected(s.id)} />
|
|
273
|
+
))}
|
|
274
|
+
</List>
|
|
275
|
+
}
|
|
276
|
+
>
|
|
277
|
+
<Box padding={5}>
|
|
278
|
+
<Stack gap={2}>
|
|
279
|
+
<Text variant="heading-sm">{section.title}</Text>
|
|
280
|
+
<Text variant="body-md" tone="secondary">
|
|
281
|
+
{section.body}
|
|
282
|
+
</Text>
|
|
283
|
+
</Stack>
|
|
284
|
+
</Box>
|
|
285
|
+
</SplitView>
|
|
286
|
+
</Card>
|
|
287
|
+
</Stack>
|
|
288
|
+
)
|
|
289
|
+
}
|
|
290
|
+
```
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Stat
|
|
2
|
+
|
|
3
|
+
> 데이터 표시 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
|
|
4
|
+
|
|
5
|
+
라벨과 숫자 하나. 옅은 라벨, 굵은 값, 옅은 "/ 전체"나 단위, 그리고 증감(Delta) 자리로 이뤄져요. 한 줄(inline)로 행 안에 넣거나, 라벨 위 큰 숫자(stacked)로 지표 띠를 만들어요. StatGroup은 여러 Stat을 옅은 세로선으로 나눠 한 줄에 놓고, 좁아지면 줄을 바꿔요.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Stat, StatGroup } from '@iamfiro/design'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 디자인 규칙
|
|
12
|
+
|
|
13
|
+
- 표 칸 · KPI 카드의 작은 추이는 `SparkLine` · `SparkArea` · `Sparkbar`(같은 props, 하나로 고르면 `SparkChart type`). 축 없음, 실제 픽셀 크기로 그려 24–40px에서도 또렷하게, 값 범위는 0이 아니라 최솟값–최댓값. 색은 `tone="trend"` + `higherIs`(Delta와 같은 규칙), 마지막 값은 `endDot`. 긴 표에선 `tooltip={false}`로 이벤트 없는 정적 그림(`role="img"`). KPI 카드는 Card 안 `Stat` + `Delta` + `SparkArea`.
|
|
14
|
+
- 라벨 + 숫자는 `Stat`(한 줄 "시간 1:52 / 2:55" 또는 오버라인 라벨 위 큰 숫자), 지표 띠는 `StatGroup`(칸 사이 `Separator`, 줄이 바뀌어도 줄 첫 칸 앞엔 선 없음).
|
|
15
|
+
- 단독 개수 타일("완료 137 / 실패 3")은 `Stat tile icon iconTone`. 카드 · 팝오버 안의 옅은 회색 패널은 모서리 `--r-panel`(12px) + 여백 12px.
|
|
16
|
+
|
|
17
|
+
## API
|
|
18
|
+
|
|
19
|
+
### Stat
|
|
20
|
+
|
|
21
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
22
|
+
| --- | --- | --- | --- |
|
|
23
|
+
| `label` (필수) | `ReactNode` | | 무엇을 잰 값인지. |
|
|
24
|
+
| `value` (필수) | `ReactNode` | | 형식을 맞춘 값("1:52", "₩8,500"). |
|
|
25
|
+
| `total` | `ReactNode` | | 값이 속한 전체. 옅게 "/ 전체"로 붙어요. |
|
|
26
|
+
| `unit` | `ReactNode` | | 값 뒤 옅은 단위("초", "건"). |
|
|
27
|
+
| `delta` | `ReactNode` | | 값 뒤 증감 자리. 보통 <Delta>. |
|
|
28
|
+
| `caption` | `ReactNode` | | 값 아래 옅은 한 줄(stacked). |
|
|
29
|
+
| `layout` | `'stacked' \| 'inline'` | `'stacked'` | 라벨 위 큰 숫자 / 한 줄. |
|
|
30
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 값 크기(number-sm · md · lg 역할). |
|
|
31
|
+
| `tone` | `TextTone` | `'default'` | 값 색. 오류가 있으면 danger 같은 식으로. |
|
|
32
|
+
| `tile` | `boolean` | | 옅은 회색 패널(--surface-active, 모서리 12, 여백 12)로 감싼 단독 타일. |
|
|
33
|
+
| `icon` | `ReactNode` | | 라벨 앞 작은 아이콘. IconTile 네모 안에 들어가요. |
|
|
34
|
+
| `iconTone` | `'neutral' \| 'accent' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | 아이콘 네모의 색. |
|
|
35
|
+
| `className` | `string` | | 추가 클래스. |
|
|
36
|
+
| `style` | `CSSProperties` | | 인라인 스타일. |
|
|
37
|
+
|
|
38
|
+
### StatGroup
|
|
39
|
+
|
|
40
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
41
|
+
| --- | --- | --- | --- |
|
|
42
|
+
| `children` (필수) | `ReactNode` | | Stat들(또는 아무 칸). |
|
|
43
|
+
| `gap` | `Space` | `6` | 칸 사이 간격. 세로선은 그 가운데에 놓여요. |
|
|
44
|
+
| `minItemWidth` | `number` | `96` | 칸의 최소 폭(px). 모자라면 줄을 바꿔요. |
|
|
45
|
+
| `fill` | `boolean` | `true` | 칸이 폭을 똑같이 나눠 가질지, 내용 폭만 쓸지. |
|
|
46
|
+
| `dividers` | `boolean` | `true` | 칸 사이 옅은 세로선. |
|
|
47
|
+
| `aria-label` | `string` | | 묶음 이름("배포 지표"). |
|
|
48
|
+
|
|
49
|
+
## 예제
|
|
50
|
+
|
|
51
|
+
예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
|
|
52
|
+
|
|
53
|
+
### 한 줄
|
|
54
|
+
|
|
55
|
+
layout="inline": "시간 1:52 / 2:55"처럼 행 · 카드 아래쪽에 넣는 짧은 지표.
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { Delta, Inline, Stack, Stat } from '@iamfiro/design'
|
|
59
|
+
|
|
60
|
+
export default function Example() {
|
|
61
|
+
return (
|
|
62
|
+
<Stack gap={4}>
|
|
63
|
+
<Inline gap={5}>
|
|
64
|
+
<Stat layout="inline" label="시간" value="1:52" total="2:55" />
|
|
65
|
+
<Stat layout="inline" label="비용" value="₩8,500" total="₩10,300" />
|
|
66
|
+
<Stat layout="inline" label="완료" value="7" total="12" />
|
|
67
|
+
</Inline>
|
|
68
|
+
<Inline gap={5}>
|
|
69
|
+
<Stat layout="inline" size="sm" label="빌드" value="48" unit="초" delta={<Delta value={-6} higherIs="worse" format={(n) => `${n}초`} size="sm" />} />
|
|
70
|
+
<Stat layout="inline" size="sm" label="경고" value="3" unit="건" tone="warning" />
|
|
71
|
+
</Inline>
|
|
72
|
+
</Stack>
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 라벨 위 숫자
|
|
78
|
+
|
|
79
|
+
layout="stacked"(기본): 오버라인 라벨 + 큰 숫자. size로 숫자 크기를, delta로 증감을 붙여요.
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
import { Delta, Grid, Stat } from '@iamfiro/design'
|
|
83
|
+
|
|
84
|
+
export default function Example() {
|
|
85
|
+
return (
|
|
86
|
+
<Grid minItemWidth={160} gap={6} style={{ width: '100%' }}>
|
|
87
|
+
<Stat size="sm" label="이번 주 배포" value="14" unit="회" />
|
|
88
|
+
<Stat label="평균 리뷰 시간" value="3.2" unit="시간" delta={<Delta value={-0.8} higherIs="worse" format={(n) => `${n}시간`} size="sm" />} />
|
|
89
|
+
<Stat size="lg" label="활성 사용자" value="12,480" delta={<Delta value={4.2} format={(n) => `${n}%`} arrow size="sm" />} caption="지난주 11,977명" />
|
|
90
|
+
</Grid>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 타일
|
|
96
|
+
|
|
97
|
+
tile: 옅은 회색 패널(모서리 12, 촘촘한 여백) 안의 Stat. icon은 라벨 앞 색 네모(IconTile)로 들어가고, iconTone으로 상태색을 고르며, 숫자 색은 tone으로 따로 정해요.
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import { Check, Clock, X } from 'lucide-react'
|
|
101
|
+
import { Grid, Stat } from '@iamfiro/design'
|
|
102
|
+
|
|
103
|
+
export default function Example() {
|
|
104
|
+
return (
|
|
105
|
+
<Grid columns={3} gap={2} style={{ width: '100%', maxWidth: 420 }}>
|
|
106
|
+
<Stat tile icon={<Check />} iconTone="success" label="완료" value="137" />
|
|
107
|
+
<Stat tile icon={<X />} iconTone="danger" label="실패" value="3" tone="danger" />
|
|
108
|
+
<Stat tile icon={<Clock />} label="대기" value="12" unit="건" />
|
|
109
|
+
</Grid>
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### StatGroup
|
|
115
|
+
|
|
116
|
+
지표 띠. 칸 사이 세로선은 Separator이고, 줄이 바뀌어도 각 줄의 첫 칸 앞에는 선이 생기지 않아요. 미리보기 폭을 줄여 보세요.
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { Delta, Card, CardBody, CardHeader, Stat, StatGroup } from '@iamfiro/design'
|
|
120
|
+
|
|
121
|
+
export default function Example() {
|
|
122
|
+
return (
|
|
123
|
+
<Card style={{ width: '100%' }}>
|
|
124
|
+
<CardHeader title="배포 #1284" description="main · 10월 25일 오후 2:14" />
|
|
125
|
+
<CardBody>
|
|
126
|
+
<StatGroup aria-label="배포 지표">
|
|
127
|
+
<Stat label="소요 시간" value="25" unit="초" />
|
|
128
|
+
<Stat label="비용" value="₩2,500" />
|
|
129
|
+
<Stat label="요청" value="128" />
|
|
130
|
+
<Stat label="캐시 적중" value="92%" />
|
|
131
|
+
<Stat label="재시도" value="3" delta={<Delta value={2} higherIs="worse" size="sm" />} />
|
|
132
|
+
<Stat label="오류" value="0" />
|
|
133
|
+
</StatGroup>
|
|
134
|
+
</CardBody>
|
|
135
|
+
</Card>
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
```
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# StatusIcon
|
|
2
|
+
|
|
3
|
+
> 아이콘 & 아바타 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
|
|
4
|
+
|
|
5
|
+
체크리스트 · 일정 행 앞에 붙는 작은 단계 아이콘. 대기는 회색 점선 원, 진행 중은 파란 링(돌거나 채워짐), 완료는 회색 체크, 오류는 빨간 ×, 확인 필요는 주황 !예요. 모든 상태가 svg 하나에 들어 있어 상태가 바뀌면 링이 차오르고 체크가 그려지며 자연스럽게 넘어가요.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { StatusIcon } from '@iamfiro/design'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 디자인 규칙
|
|
12
|
+
|
|
13
|
+
- 단계 행 앞 아이콘은 `StatusIcon`(대기 = 회색 점선 원, 진행 = 파란 링, 완료 = 회색 체크, 오류 · 확인 필요). 상태마다 아이콘을 바꿔 끼우지 않고 한 svg 안에서 전환한다.
|
|
14
|
+
- 읽기 전용 단계 타임라인(계획 · 활동 기록 · 승인 흐름)은 `StepList`(`ol`, 마커 + 연결선, `meta` 시간, 아래 내용엔 Collapsible inline). 번호 원은 `StatusIcon number`(`persistNumber`면 모든 상태에서 번호). 사용자가 체크하는 목록은 `ProgressTracker`. 카드 아래 상태 띠는 `CardFooter band`.
|
|
15
|
+
|
|
16
|
+
## API
|
|
17
|
+
|
|
18
|
+
### StatusIcon
|
|
19
|
+
|
|
20
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `status` (필수) | `'pending' \| 'active' \| 'done' \| 'error' \| 'warning'` | | 단계 상태. |
|
|
23
|
+
| `size` | `'sm' \| 'md' \| 'lg' \| number` | `'md'` | 크기(px 숫자도 가능). |
|
|
24
|
+
| `progress` | `number` | | active일 때 0–100. 생략하면 링이 계속 돌아요. |
|
|
25
|
+
| `colored` | `boolean` | | 완료를 회색 대신 초록으로. |
|
|
26
|
+
| `number` | `number \| string` | | 대기 상태를 회색 실선 원 + 번호("5")로. 다른 상태에선 링 · 기호로 넘어가요. |
|
|
27
|
+
| `persistNumber` | `boolean` | | number와 함께: 모든 상태에서 번호를 남기고 테두리가 상태 색(완료 회색 · 진행 파랑 · 오류 빨강 · 확인 주황)이 돼요. |
|
|
28
|
+
| `label` | `string` | | 스크린 리더가 읽을 이름. 기본은 "완료", "진행 중 40%"처럼 상태 이름이에요. |
|
|
29
|
+
| `decorative` | `boolean` | | 옆 글자가 이미 상태를 말할 때 스크린 리더에서 숨겨요. |
|
|
30
|
+
| `className` | `string` | | 추가 클래스. |
|
|
31
|
+
| `style` | `CSSProperties` | | 인라인 스타일. |
|
|
32
|
+
|
|
33
|
+
## 예제
|
|
34
|
+
|
|
35
|
+
예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
|
|
36
|
+
|
|
37
|
+
### 상태
|
|
38
|
+
|
|
39
|
+
pending · active · done · error · warning. colored를 주면 완료가 초록이 돼요.
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
import { Inline, StatusIcon, Text, type StatusIconStatus } from '@iamfiro/design'
|
|
43
|
+
|
|
44
|
+
const STATES: Array<{ status: StatusIconStatus; label: string }> = [
|
|
45
|
+
{ status: 'pending', label: '대기' },
|
|
46
|
+
{ status: 'active', label: '진행 중' },
|
|
47
|
+
{ status: 'done', label: '완료' },
|
|
48
|
+
{ status: 'error', label: '오류' },
|
|
49
|
+
{ status: 'warning', label: '확인 필요' },
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
export default function Example() {
|
|
53
|
+
return (
|
|
54
|
+
<Inline gap={6}>
|
|
55
|
+
{STATES.map((s) => (
|
|
56
|
+
<Inline key={s.status} gap={2} wrap={false}>
|
|
57
|
+
<StatusIcon status={s.status} decorative />
|
|
58
|
+
<Text variant="label-sm">{s.label}</Text>
|
|
59
|
+
</Inline>
|
|
60
|
+
))}
|
|
61
|
+
<Inline gap={2} wrap={false}>
|
|
62
|
+
<StatusIcon status="done" colored decorative />
|
|
63
|
+
<Text variant="label-sm">완료 (colored)</Text>
|
|
64
|
+
</Inline>
|
|
65
|
+
</Inline>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 작업 단계
|
|
71
|
+
|
|
72
|
+
ListItem의 leading에 놓아 단계 목록을 만들어요. 버튼을 눌러 상태가 바뀌는 움직임을 확인해 보세요.
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
import { useState } from 'react'
|
|
76
|
+
import { Button, Inline, Stack, StatusIcon, type StatusIconStatus, List, ListItem } from '@iamfiro/design'
|
|
77
|
+
|
|
78
|
+
const STEPS = [
|
|
79
|
+
{ id: 'lint', title: '코드 검사', description: '규칙 위반 0건' },
|
|
80
|
+
{ id: 'test', title: '테스트', description: '412개 통과' },
|
|
81
|
+
{ id: 'build', title: '빌드', description: '번들 크기 확인 중' },
|
|
82
|
+
{ id: 'deploy', title: '운영 배포', description: '서울 리전' },
|
|
83
|
+
{ id: 'notify', title: '팀에 알리기', description: '#release 채널' },
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
export default function Example() {
|
|
87
|
+
// Index of the step in progress; steps before it are done.
|
|
88
|
+
const [current, setCurrent] = useState(2)
|
|
89
|
+
const [failed, setFailed] = useState(false)
|
|
90
|
+
|
|
91
|
+
const statusOf = (i: number): StatusIconStatus => {
|
|
92
|
+
if (i < current) return 'done'
|
|
93
|
+
if (i === current) return failed ? 'error' : 'active'
|
|
94
|
+
return 'pending'
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return (
|
|
98
|
+
<Stack gap={4} style={{ width: '100%', maxWidth: 420 }}>
|
|
99
|
+
<List label="배포 단계">
|
|
100
|
+
{STEPS.map((s, i) => (
|
|
101
|
+
<ListItem
|
|
102
|
+
key={s.id}
|
|
103
|
+
leading={<StatusIcon status={statusOf(i)} />}
|
|
104
|
+
title={s.title}
|
|
105
|
+
description={i === current && failed ? '빌드 스크립트가 종료 코드 1로 끝났어요' : s.description}
|
|
106
|
+
/>
|
|
107
|
+
))}
|
|
108
|
+
</List>
|
|
109
|
+
<Inline gap={2}>
|
|
110
|
+
<Button
|
|
111
|
+
variant="primary"
|
|
112
|
+
size="sm"
|
|
113
|
+
disabled={current >= STEPS.length}
|
|
114
|
+
onClick={() => {
|
|
115
|
+
setFailed(false)
|
|
116
|
+
setCurrent((c) => c + 1)
|
|
117
|
+
}}
|
|
118
|
+
>
|
|
119
|
+
다음 단계
|
|
120
|
+
</Button>
|
|
121
|
+
<Button size="sm" disabled={current >= STEPS.length} onClick={() => setFailed((f) => !f)}>
|
|
122
|
+
{failed ? '다시 시도' : '실패로 표시'}
|
|
123
|
+
</Button>
|
|
124
|
+
<Button
|
|
125
|
+
variant="ghost"
|
|
126
|
+
size="sm"
|
|
127
|
+
onClick={() => {
|
|
128
|
+
setFailed(false)
|
|
129
|
+
setCurrent(0)
|
|
130
|
+
}}
|
|
131
|
+
>
|
|
132
|
+
처음부터
|
|
133
|
+
</Button>
|
|
134
|
+
</Inline>
|
|
135
|
+
</Stack>
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 번호
|
|
141
|
+
|
|
142
|
+
number를 주면 대기 상태가 점선 원 대신 회색 실선 원 + 번호가 돼요. 시작하면 링으로, 끝나면 체크로 넘어가요. persistNumber면 모든 상태에서 번호가 남고 테두리 색만 상태를 따라가요(번호 타임라인).
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
import { useState } from 'react'
|
|
146
|
+
import { Button, Inline, Stack, StatusIcon, Text, type StatusIconStatus } from '@iamfiro/design'
|
|
147
|
+
|
|
148
|
+
const ORDER: StatusIconStatus[] = ['pending', 'active', 'done']
|
|
149
|
+
|
|
150
|
+
export default function Example() {
|
|
151
|
+
const [step, setStep] = useState(0)
|
|
152
|
+
const status = ORDER[step]
|
|
153
|
+
return (
|
|
154
|
+
<Stack gap={5}>
|
|
155
|
+
<Inline gap={6}>
|
|
156
|
+
<Inline gap={2} wrap={false}>
|
|
157
|
+
<StatusIcon status="pending" number={5} size="lg" decorative />
|
|
158
|
+
<Text variant="label-sm">대기 (number)</Text>
|
|
159
|
+
</Inline>
|
|
160
|
+
<Inline gap={2} wrap={false}>
|
|
161
|
+
<StatusIcon status="pending" number={12} size="lg" decorative />
|
|
162
|
+
<Text variant="label-sm">두 자리</Text>
|
|
163
|
+
</Inline>
|
|
164
|
+
</Inline>
|
|
165
|
+
<Inline gap={4}>
|
|
166
|
+
{(['pending', 'active', 'done', 'error', 'warning'] as const).map((s, i) => (
|
|
167
|
+
<StatusIcon key={s} status={s} number={i + 1} persistNumber size="lg" />
|
|
168
|
+
))}
|
|
169
|
+
<Text variant="label-sm" tone="secondary">
|
|
170
|
+
persistNumber
|
|
171
|
+
</Text>
|
|
172
|
+
</Inline>
|
|
173
|
+
<Inline gap={3}>
|
|
174
|
+
<StatusIcon status={status} number={3} size="lg" />
|
|
175
|
+
<Button size="sm" onClick={() => setStep((s) => (s + 1) % ORDER.length)}>
|
|
176
|
+
{status === 'pending' ? '시작하기' : status === 'active' ? '완료하기' : '처음으로'}
|
|
177
|
+
</Button>
|
|
178
|
+
</Inline>
|
|
179
|
+
</Stack>
|
|
180
|
+
)
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 진행률
|
|
185
|
+
|
|
186
|
+
active에 progress(0–100)를 주면 링이 그만큼 채워지고, 없으면 Spinner처럼 돌아요.
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
import { useState } from 'react'
|
|
190
|
+
import { Button, Inline, Stack, StatusIcon, Text } from '@iamfiro/design'
|
|
191
|
+
|
|
192
|
+
export default function Example() {
|
|
193
|
+
const [progress, setProgress] = useState(35)
|
|
194
|
+
const done = progress >= 100
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<Stack gap={4} align="start">
|
|
198
|
+
<Inline gap={6}>
|
|
199
|
+
<Inline gap={2} wrap={false}>
|
|
200
|
+
<StatusIcon status="active" size="lg" />
|
|
201
|
+
<Text variant="label-sm">파일 정리 중</Text>
|
|
202
|
+
</Inline>
|
|
203
|
+
<Inline gap={2} wrap={false}>
|
|
204
|
+
<StatusIcon status={done ? 'done' : 'active'} progress={progress} size="lg" />
|
|
205
|
+
<Text variant="label-sm" numeric>
|
|
206
|
+
{done ? '업로드 완료' : `업로드 ${progress}%`}
|
|
207
|
+
</Text>
|
|
208
|
+
</Inline>
|
|
209
|
+
</Inline>
|
|
210
|
+
<Inline gap={2}>
|
|
211
|
+
<Button size="sm" disabled={done} onClick={() => setProgress((p) => Math.min(100, p + 25))}>
|
|
212
|
+
25% 올리기
|
|
213
|
+
</Button>
|
|
214
|
+
<Button variant="ghost" size="sm" onClick={() => setProgress(0)}>
|
|
215
|
+
초기화
|
|
216
|
+
</Button>
|
|
217
|
+
</Inline>
|
|
218
|
+
</Stack>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### 크기
|
|
224
|
+
|
|
225
|
+
sm 14 · md 16 · lg 20px, 또는 px 숫자. 텍스트 옆에서도 찌그러지지 않아요(flex: none).
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
import { Inline, StatusIcon } from '@iamfiro/design'
|
|
229
|
+
|
|
230
|
+
export default function Example() {
|
|
231
|
+
return (
|
|
232
|
+
<Inline gap={6}>
|
|
233
|
+
{(['sm', 'md', 'lg', 28] as const).map((size) => (
|
|
234
|
+
<Inline key={size} gap={2} wrap={false}>
|
|
235
|
+
<StatusIcon status="done" size={size} />
|
|
236
|
+
<StatusIcon status="active" progress={60} size={size} />
|
|
237
|
+
<StatusIcon status="pending" size={size} />
|
|
238
|
+
</Inline>
|
|
239
|
+
))}
|
|
240
|
+
</Inline>
|
|
241
|
+
)
|
|
242
|
+
}
|
|
243
|
+
```
|