@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,277 @@
|
|
|
1
|
+
# Toolbar
|
|
2
|
+
|
|
3
|
+
> 버튼 & 링크 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
|
|
4
|
+
|
|
5
|
+
버튼 · 토글 · ToggleGroup · 메뉴 트리거를 한 줄로 묶는 WAI-ARIA 툴바. Tab 정지점은 툴바 전체에 하나뿐이고, 안에서는 ←→(세로면 ↑↓) · Home · End로 옮겨 다녀요. 다시 Tab으로 들어오면 마지막에 있던 버튼으로 돌아와요. 아이콘 버튼은 label이 이름 · 툴팁이 되고, 툴팁에 단축키 키캡이 함께 보여요. 테두리 없이 plain(여백만) · floating(흰 바탕 + 그림자) 두 가지.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Toolbar, ToolbarButton, ToolbarSeparator, ToolbarSpacer } from '@iamfiro/design'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### Toolbar
|
|
14
|
+
|
|
15
|
+
role="toolbar" + aria-orientation. 안의 button · input · [data-toolbar-item]이 모두 로빙 tabindex 대상이에요(비활성 · 숨김 제외).
|
|
16
|
+
|
|
17
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
18
|
+
| --- | --- | --- | --- |
|
|
19
|
+
| `children` (필수) | `ReactNode` | | ToolbarButton, ToolbarSeparator, ToggleGroup, DropdownMenu 등. |
|
|
20
|
+
| `aria-label / aria-labelledby` | `string` | | 툴바 이름("서식"). |
|
|
21
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | 배치와 화살표 키 방향. |
|
|
22
|
+
| `variant` | `'plain' \| 'floating'` | `'plain'` | plain: 여백만 · floating: 흰 바탕 + 그림자(테두리 없음). |
|
|
23
|
+
| `size` | `'sm' \| 'md'` | `'md'` | 안의 ToolbarButton 크기. ToggleGroup은 size를 직접 맞춰요. |
|
|
24
|
+
| `loop` | `boolean` | `true` | 끝에서 화살표를 누르면 처음으로. |
|
|
25
|
+
| `overflow` | `boolean` | | 자리가 모자라면 ToolbarButton · ToolbarSeparator를 뒤에서부터 "더보기" 메뉴로(가로만). 이때 툴바는 부모 폭을 채워요. |
|
|
26
|
+
| `overflowLabel` | `string` | `'더보기'` | 더보기 버튼 이름. |
|
|
27
|
+
|
|
28
|
+
### ToolbarButton
|
|
29
|
+
|
|
30
|
+
ghost Button 기반. 나머지 Button 속성(icon, iconRight, onClick, hotkey, disabled…)을 그대로 받아요.
|
|
31
|
+
|
|
32
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
33
|
+
| --- | --- | --- | --- |
|
|
34
|
+
| `label` (필수) | `string` | | 하는 일. 아이콘 버튼의 이름 · 툴팁 · 더보기 메뉴 글자. |
|
|
35
|
+
| `children` | `ReactNode` | | 글자 버튼일 때. 없으면 아이콘만 있는 정사각형 버튼. |
|
|
36
|
+
| `pressed / defaultPressed` | `boolean` | | 주면 토글 버튼(aria-pressed). 제어 / 비제어. |
|
|
37
|
+
| `onPressedChange` | `(pressed: boolean) => void` | | 토글이 바뀔 때. |
|
|
38
|
+
| `shortcut` | `string[]` | | 단축키 힌트(['mod', 'B']). 툴팁 · 더보기 메뉴에 키캡으로. hotkey를 함께 주면 실제로 들어요. |
|
|
39
|
+
| `tooltip` | `boolean \| ReactNode` | `아이콘 버튼이면 true` | 툴팁. false로 끄거나 내용을 바꿔요. |
|
|
40
|
+
| `tooltipSide` | `'top' \| 'bottom' \| 'left' \| 'right'` | | 기본은 가로 툴바 위, 세로 툴바 오른쪽. |
|
|
41
|
+
| `variant` | `ButtonVariant` | `'ghost'` | 끝의 주요 동작은 primary로. |
|
|
42
|
+
| `collapsible` | `boolean` | `true` | 더보기로 옮겨 갈 수 있는지. DropdownMenu 트리거처럼 클릭이 제 동작이 아닌 버튼은 false. |
|
|
43
|
+
|
|
44
|
+
### ToolbarSeparator
|
|
45
|
+
|
|
46
|
+
묶음 사이 짧은 선(가로 툴바면 세로선). role="separator".
|
|
47
|
+
|
|
48
|
+
### ToolbarSpacer
|
|
49
|
+
|
|
50
|
+
뒤의 항목을 반대쪽 끝으로 밀어요(flex: 1).
|
|
51
|
+
|
|
52
|
+
## 예제
|
|
53
|
+
|
|
54
|
+
예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
|
|
55
|
+
|
|
56
|
+
### 글 서식 툴바
|
|
57
|
+
|
|
58
|
+
실행 취소 · 문단 스타일 메뉴 · 굵게/기울임/밑줄 토글(⌘/Ctrl+B · I · U로도 눌려요) · 정렬 ToggleGroup · 링크 · 더보기 메뉴. Tab으로 들어와 ←→로 이동하고, 메뉴 트리거에선 ↓ · Enter로 메뉴를 열어요. 정렬 묶음 안에서도 화살표는 툴바 전체를 따라 움직이고, Space · Enter로 골라요.
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { useState } from 'react'
|
|
62
|
+
import {
|
|
63
|
+
AlignCenter,
|
|
64
|
+
AlignLeft,
|
|
65
|
+
AlignRight,
|
|
66
|
+
Bold,
|
|
67
|
+
ChevronDown,
|
|
68
|
+
Code,
|
|
69
|
+
Eraser,
|
|
70
|
+
Italic,
|
|
71
|
+
Link,
|
|
72
|
+
MoreHorizontal,
|
|
73
|
+
Quote,
|
|
74
|
+
Redo2,
|
|
75
|
+
Strikethrough,
|
|
76
|
+
Table2,
|
|
77
|
+
Underline,
|
|
78
|
+
Undo2,
|
|
79
|
+
} from 'lucide-react'
|
|
80
|
+
import { DropdownMenu, DropdownMenuItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, ToggleGroup, ToggleGroupItem, Toolbar, ToolbarButton, ToolbarSeparator, Stack, Text } from '@iamfiro/design'
|
|
81
|
+
|
|
82
|
+
const BLOCKS = { body: '본문', h1: '제목 1', h2: '제목 2', h3: '제목 3' } as const
|
|
83
|
+
type Block = keyof typeof BLOCKS
|
|
84
|
+
|
|
85
|
+
export default function Example() {
|
|
86
|
+
const [block, setBlock] = useState<Block>('body')
|
|
87
|
+
const [marks, setMarks] = useState({ bold: true, italic: false, underline: false, strike: false })
|
|
88
|
+
const [align, setAlign] = useState<string | null>('left')
|
|
89
|
+
const [last, setLast] = useState('')
|
|
90
|
+
const mark = (key: keyof typeof marks) => ({
|
|
91
|
+
pressed: marks[key],
|
|
92
|
+
onPressedChange: (on: boolean) => setMarks((m) => ({ ...m, [key]: on })),
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const on = Object.entries(marks)
|
|
96
|
+
.filter(([, v]) => v)
|
|
97
|
+
.map(([k]) => ({ bold: '굵게', italic: '기울임', underline: '밑줄', strike: '취소선' })[k])
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<Stack gap={4} align="start">
|
|
101
|
+
<Toolbar aria-label="서식" variant="floating">
|
|
102
|
+
<ToolbarButton label="실행 취소" icon={<Undo2 />} shortcut={['mod', 'Z']} onClick={() => setLast('실행 취소')} />
|
|
103
|
+
<ToolbarButton label="다시 실행" icon={<Redo2 />} shortcut={['mod', 'shift', 'Z']} onClick={() => setLast('다시 실행')} />
|
|
104
|
+
<ToolbarSeparator />
|
|
105
|
+
<DropdownMenu
|
|
106
|
+
minWidth={160}
|
|
107
|
+
trigger={
|
|
108
|
+
<ToolbarButton label="문단 스타일" iconRight={<ChevronDown />} tooltip collapsible={false}>
|
|
109
|
+
{BLOCKS[block]}
|
|
110
|
+
</ToolbarButton>
|
|
111
|
+
}
|
|
112
|
+
>
|
|
113
|
+
<DropdownMenuRadioGroup value={block} onValueChange={(v) => setBlock(v as Block)}>
|
|
114
|
+
{(Object.keys(BLOCKS) as Block[]).map((k) => (
|
|
115
|
+
<DropdownMenuRadioItem key={k} value={k}>
|
|
116
|
+
{BLOCKS[k]}
|
|
117
|
+
</DropdownMenuRadioItem>
|
|
118
|
+
))}
|
|
119
|
+
</DropdownMenuRadioGroup>
|
|
120
|
+
</DropdownMenu>
|
|
121
|
+
<ToolbarSeparator />
|
|
122
|
+
<ToolbarButton label="굵게" icon={<Bold />} shortcut={['mod', 'B']} hotkey {...mark('bold')} />
|
|
123
|
+
<ToolbarButton label="기울임" icon={<Italic />} shortcut={['mod', 'I']} hotkey {...mark('italic')} />
|
|
124
|
+
<ToolbarButton label="밑줄" icon={<Underline />} shortcut={['mod', 'U']} hotkey {...mark('underline')} />
|
|
125
|
+
<ToolbarButton label="취소선" icon={<Strikethrough />} shortcut={['mod', 'shift', 'X']} {...mark('strike')} />
|
|
126
|
+
<ToolbarSeparator />
|
|
127
|
+
<ToggleGroup type="single" required variant="ghost" value={align} onValueChange={setAlign} aria-label="정렬">
|
|
128
|
+
<ToggleGroupItem value="left" icon={<AlignLeft />} aria-label="왼쪽 정렬" />
|
|
129
|
+
<ToggleGroupItem value="center" icon={<AlignCenter />} aria-label="가운데 정렬" />
|
|
130
|
+
<ToggleGroupItem value="right" icon={<AlignRight />} aria-label="오른쪽 정렬" />
|
|
131
|
+
</ToggleGroup>
|
|
132
|
+
<ToolbarSeparator />
|
|
133
|
+
<ToolbarButton label="링크" icon={<Link />} shortcut={['mod', 'K']} onClick={() => setLast('링크 넣기')} />
|
|
134
|
+
<DropdownMenu align="end" trigger={<ToolbarButton label="더보기" icon={<MoreHorizontal />} collapsible={false} />}>
|
|
135
|
+
<DropdownMenuItem icon={<Quote />} onSelect={() => setLast('인용')}>
|
|
136
|
+
인용
|
|
137
|
+
</DropdownMenuItem>
|
|
138
|
+
<DropdownMenuItem icon={<Code />} shortcut={['mod', 'E']} onSelect={() => setLast('코드 블록')}>
|
|
139
|
+
코드 블록
|
|
140
|
+
</DropdownMenuItem>
|
|
141
|
+
<DropdownMenuItem icon={<Table2 />} onSelect={() => setLast('표 넣기')}>
|
|
142
|
+
표 넣기
|
|
143
|
+
</DropdownMenuItem>
|
|
144
|
+
<DropdownMenuSeparator />
|
|
145
|
+
<DropdownMenuItem icon={<Eraser />} onSelect={() => setMarks({ bold: false, italic: false, underline: false, strike: false })}>
|
|
146
|
+
서식 지우기
|
|
147
|
+
</DropdownMenuItem>
|
|
148
|
+
</DropdownMenu>
|
|
149
|
+
</Toolbar>
|
|
150
|
+
<Text variant="body-sm" tone="secondary">
|
|
151
|
+
{BLOCKS[block]} · {on.length ? on.join(', ') : '서식 없음'} · {{ left: '왼쪽', center: '가운데', right: '오른쪽' }[align ?? 'left']} 정렬
|
|
152
|
+
{last && ` · 방금: ${last}`}
|
|
153
|
+
</Text>
|
|
154
|
+
</Stack>
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### plain · 목록 위 도구
|
|
160
|
+
|
|
161
|
+
글자 버튼은 툴팁 없이(tooltip={false}), ToolbarSpacer로 뒤쪽 버튼을 오른쪽 끝에 붙여요. 토글은 눌리면 회색 채움이 자라나요.
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
import { useState } from 'react'
|
|
165
|
+
import { ArrowDownUp, Download, LayoutGrid, List, ListFilter, Plus } from 'lucide-react'
|
|
166
|
+
import { ToggleGroup, ToggleGroupItem, Toolbar, ToolbarButton, ToolbarSeparator, ToolbarSpacer, Stack, Text } from '@iamfiro/design'
|
|
167
|
+
|
|
168
|
+
export default function Example() {
|
|
169
|
+
const [view, setView] = useState<string | null>('list')
|
|
170
|
+
const [filtered, setFiltered] = useState(false)
|
|
171
|
+
return (
|
|
172
|
+
<Stack gap={3}>
|
|
173
|
+
<Toolbar aria-label="문서 목록 도구" size="sm" style={{ width: '100%' }}>
|
|
174
|
+
<ToolbarButton label="필터" icon={<ListFilter />} pressed={filtered} onPressedChange={setFiltered} tooltip={false}>
|
|
175
|
+
필터
|
|
176
|
+
</ToolbarButton>
|
|
177
|
+
<ToolbarButton label="정렬" icon={<ArrowDownUp />} tooltip={false}>
|
|
178
|
+
최근 수정순
|
|
179
|
+
</ToolbarButton>
|
|
180
|
+
<ToolbarSeparator />
|
|
181
|
+
<ToggleGroup type="single" required size="sm" variant="ghost" value={view} onValueChange={setView} aria-label="보기">
|
|
182
|
+
<ToggleGroupItem value="list" icon={<List />} aria-label="목록으로 보기" />
|
|
183
|
+
<ToggleGroupItem value="grid" icon={<LayoutGrid />} aria-label="격자로 보기" />
|
|
184
|
+
</ToggleGroup>
|
|
185
|
+
<ToolbarSpacer />
|
|
186
|
+
<ToolbarButton label="내보내기" icon={<Download />} />
|
|
187
|
+
<ToolbarButton label="새 문서" variant="primary" icon={<Plus />} tooltip={false}>
|
|
188
|
+
새 문서
|
|
189
|
+
</ToolbarButton>
|
|
190
|
+
</Toolbar>
|
|
191
|
+
<Text variant="body-sm" tone="secondary">
|
|
192
|
+
{filtered ? '필터 적용됨' : '전체 문서'} · {view === 'grid' ? '격자' : '목록'} 보기
|
|
193
|
+
</Text>
|
|
194
|
+
</Stack>
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### 세로 · 그리기 도구
|
|
200
|
+
|
|
201
|
+
orientation='vertical'이면 ↑↓로 이동하고 툴팁은 오른쪽에 떠요. 구분선도 가로로 바뀌어요.
|
|
202
|
+
|
|
203
|
+
```tsx
|
|
204
|
+
import { useState } from 'react'
|
|
205
|
+
import { Circle, Hand, MousePointer2, Pen, Square, Type, ZoomIn, ZoomOut } from 'lucide-react'
|
|
206
|
+
import { ToggleGroup, ToggleGroupItem, Toolbar, ToolbarButton, ToolbarSeparator, Inline, Text } from '@iamfiro/design'
|
|
207
|
+
|
|
208
|
+
const TOOLS = { select: '선택', hand: '손', rect: '사각형', ellipse: '원', pen: '펜', text: '텍스트' } as const
|
|
209
|
+
|
|
210
|
+
export default function Example() {
|
|
211
|
+
const [tool, setTool] = useState<string | null>('select')
|
|
212
|
+
const [zoom, setZoom] = useState(100)
|
|
213
|
+
return (
|
|
214
|
+
<Inline gap={6} align="start">
|
|
215
|
+
<Toolbar aria-label="그리기 도구" orientation="vertical" variant="floating">
|
|
216
|
+
<ToggleGroup type="single" required orientation="vertical" variant="ghost" value={tool} onValueChange={setTool} aria-label="도구">
|
|
217
|
+
<ToggleGroupItem value="select" icon={<MousePointer2 />} aria-label="선택 (V)" />
|
|
218
|
+
<ToggleGroupItem value="hand" icon={<Hand />} aria-label="손 (H)" />
|
|
219
|
+
<ToggleGroupItem value="rect" icon={<Square />} aria-label="사각형 (R)" />
|
|
220
|
+
<ToggleGroupItem value="ellipse" icon={<Circle />} aria-label="원 (O)" />
|
|
221
|
+
<ToggleGroupItem value="pen" icon={<Pen />} aria-label="펜 (P)" />
|
|
222
|
+
<ToggleGroupItem value="text" icon={<Type />} aria-label="텍스트 (T)" />
|
|
223
|
+
</ToggleGroup>
|
|
224
|
+
<ToolbarSeparator />
|
|
225
|
+
<ToolbarButton label="확대" icon={<ZoomIn />} shortcut={['mod', '=']} disabled={zoom >= 400} onClick={() => setZoom((z) => z * 2)} />
|
|
226
|
+
<ToolbarButton label="축소" icon={<ZoomOut />} shortcut={['mod', '-']} disabled={zoom <= 25} onClick={() => setZoom((z) => z / 2)} />
|
|
227
|
+
</Toolbar>
|
|
228
|
+
<Text variant="body-sm" tone="secondary" numeric>
|
|
229
|
+
도구: {TOOLS[tool as keyof typeof TOOLS]} · 확대 {zoom}%
|
|
230
|
+
</Text>
|
|
231
|
+
</Inline>
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### 자리가 모자라면 더보기로
|
|
237
|
+
|
|
238
|
+
overflow를 주면 들어가지 않는 버튼이 뒤에서부터 "더보기" 메뉴로 옮겨 가요. 토글은 메뉴에서 체크 항목이 되고, 단축키 힌트도 그대로 따라가요. 폭을 줄여 보세요.
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
import { useState } from 'react'
|
|
242
|
+
import { Bold, Code, Highlighter, Image, Italic, Link, List, ListOrdered, Quote, Strikethrough, Underline } from 'lucide-react'
|
|
243
|
+
import { Slider, Toolbar, ToolbarButton, ToolbarSeparator, Box, Field, Stack } from '@iamfiro/design'
|
|
244
|
+
|
|
245
|
+
export default function Example() {
|
|
246
|
+
const [width, setWidth] = useState(300)
|
|
247
|
+
const [marks, setMarks] = useState<Record<string, boolean>>({ bold: false, italic: true })
|
|
248
|
+
const toggle = (key: string) => ({
|
|
249
|
+
pressed: !!marks[key],
|
|
250
|
+
onPressedChange: (on: boolean) => setMarks((m) => ({ ...m, [key]: on })),
|
|
251
|
+
})
|
|
252
|
+
return (
|
|
253
|
+
<Stack gap={5}>
|
|
254
|
+
<Field label="툴바 폭">
|
|
255
|
+
<Slider value={width} onValueChange={setWidth} min={160} max={560} step={10} formatValue={(v) => `${v}px`} aria-label="툴바 폭" />
|
|
256
|
+
</Field>
|
|
257
|
+
<Box style={{ width }}>
|
|
258
|
+
<Toolbar aria-label="댓글 서식" variant="floating" overflow>
|
|
259
|
+
<ToolbarButton label="굵게" icon={<Bold />} shortcut={['mod', 'B']} {...toggle('bold')} />
|
|
260
|
+
<ToolbarButton label="기울임" icon={<Italic />} shortcut={['mod', 'I']} {...toggle('italic')} />
|
|
261
|
+
<ToolbarButton label="밑줄" icon={<Underline />} shortcut={['mod', 'U']} {...toggle('underline')} />
|
|
262
|
+
<ToolbarButton label="취소선" icon={<Strikethrough />} {...toggle('strike')} />
|
|
263
|
+
<ToolbarButton label="형광펜" icon={<Highlighter />} {...toggle('highlight')} />
|
|
264
|
+
<ToolbarSeparator />
|
|
265
|
+
<ToolbarButton label="글머리 목록" icon={<List />} />
|
|
266
|
+
<ToolbarButton label="번호 목록" icon={<ListOrdered />} />
|
|
267
|
+
<ToolbarButton label="인용" icon={<Quote />} />
|
|
268
|
+
<ToolbarSeparator />
|
|
269
|
+
<ToolbarButton label="링크" icon={<Link />} shortcut={['mod', 'K']} />
|
|
270
|
+
<ToolbarButton label="이미지" icon={<Image />} />
|
|
271
|
+
<ToolbarButton label="코드" icon={<Code />} shortcut={['mod', 'E']} />
|
|
272
|
+
</Toolbar>
|
|
273
|
+
</Box>
|
|
274
|
+
</Stack>
|
|
275
|
+
)
|
|
276
|
+
}
|
|
277
|
+
```
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Tooltip
|
|
2
|
+
|
|
3
|
+
> 메뉴 & 오버레이 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
|
|
4
|
+
|
|
5
|
+
아이콘 버튼처럼 글자가 없는 요소에 짧은 설명을 붙여요. 마우스는 500ms 머물러야 열려서 툴바를 훑고 지나갈 때 깜빡이지 않고, 하나가 열린 뒤(또는 닫힌 지 300ms 안에) 옆으로 옮기면 기다림 없이 바로 열려요. 키보드 포커스는 즉시 열리고, 누르거나 Esc를 누르면 닫혀요.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Tooltip } from '@iamfiro/design'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 디자인 규칙
|
|
12
|
+
|
|
13
|
+
- 툴팁: 첫 번째는 `TIMING.tooltipDelay`(500ms) 뒤, 닫힌 지 `TIMING.tooltipSkip`(300ms) 안에 옆 툴팁으로 옮기면 즉시. 단 "즉시"는 **이미 기다린 시간만큼만** 건너뛴다 — `delay={0}` 툴팁을 거쳐 왔다고 `delay={1000}` 툴팁이 바로 열리면 안 된다(대기 시간 고장 버그). 키보드 포커스는 즉시, 누르면 닫고, Esc로 닫힌다. → `Tooltip`
|
|
14
|
+
- 아바타는 hover하면 이름 `Tooltip`이 기본(`tooltip={false}`로 끔). `title` 속성 툴팁은 쓰지 않는다.
|
|
15
|
+
|
|
16
|
+
## API
|
|
17
|
+
|
|
18
|
+
### Tooltip
|
|
19
|
+
|
|
20
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
21
|
+
| --- | --- | --- | --- |
|
|
22
|
+
| `content` (필수) | `ReactNode` | | 말풍선 내용. 짧은 글자나 작은 인라인 요소(Kbd 등). |
|
|
23
|
+
| `children` (필수) | `ReactNode` | | 툴팁을 붙일 트리거. 아이콘 버튼이면 aria-label도 함께 주세요. |
|
|
24
|
+
| `side` | `'top' \| 'bottom' \| 'left' \| 'right'` | `'top'` | 말풍선이 열리는 방향. |
|
|
25
|
+
| `delay` | `number` | `500` | 마우스를 올린 뒤 첫 툴팁이 열리기까지(ms). 다른 툴팁이 열려 있거나 닫힌 지 300ms(TIMING.tooltipSkip) 안이면 그 툴팁에서 이미 기다린 시간만큼 빼고 기다려요(같은 delay끼리는 즉시). |
|
|
26
|
+
|
|
27
|
+
## 예제
|
|
28
|
+
|
|
29
|
+
예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
|
|
30
|
+
|
|
31
|
+
### 툴바
|
|
32
|
+
|
|
33
|
+
첫 툴팁은 잠깐 기다렸다 열리고, 그다음부터는 옆 버튼으로 옮기는 즉시 바뀌어요. Tab으로 이동해도 바로 보여요.
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { Bold, Code, Italic, Link, List, Strikethrough, Underline } from 'lucide-react'
|
|
37
|
+
import { Button, Tooltip } from '@iamfiro/design'
|
|
38
|
+
|
|
39
|
+
const TOOLS = [
|
|
40
|
+
{ label: '굵게', icon: <Bold /> },
|
|
41
|
+
{ label: '기울임', icon: <Italic /> },
|
|
42
|
+
{ label: '밑줄', icon: <Underline /> },
|
|
43
|
+
{ label: '취소선', icon: <Strikethrough /> },
|
|
44
|
+
{ label: '링크 삽입', icon: <Link /> },
|
|
45
|
+
{ label: '목록', icon: <List /> },
|
|
46
|
+
{ label: '코드', icon: <Code /> },
|
|
47
|
+
]
|
|
48
|
+
|
|
49
|
+
export default function Example() {
|
|
50
|
+
return (
|
|
51
|
+
<div role="toolbar" aria-label="서식" style={{ display: 'flex', gap: 4 }}>
|
|
52
|
+
{TOOLS.map((tool) => (
|
|
53
|
+
<Tooltip key={tool.label} content={tool.label}>
|
|
54
|
+
<Button iconOnly variant="ghost" icon={tool.icon} aria-label={tool.label} />
|
|
55
|
+
</Tooltip>
|
|
56
|
+
))}
|
|
57
|
+
</div>
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 방향
|
|
63
|
+
|
|
64
|
+
side로 위 · 아래 · 왼쪽 · 오른쪽. 열릴 때 트리거 쪽에서 살짝 밀려 나와요.
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { Button, Tooltip, type TooltipSide } from '@iamfiro/design'
|
|
68
|
+
|
|
69
|
+
const SIDES: Array<[TooltipSide, string]> = [
|
|
70
|
+
['top', '위'],
|
|
71
|
+
['bottom', '아래'],
|
|
72
|
+
['left', '왼쪽'],
|
|
73
|
+
['right', '오른쪽'],
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
export default function Example() {
|
|
77
|
+
return (
|
|
78
|
+
<div style={{ display: 'flex', gap: 16 }}>
|
|
79
|
+
{SIDES.map(([side, label]) => (
|
|
80
|
+
<Tooltip key={side} side={side} content={`${label}에 열려요`}>
|
|
81
|
+
<Button variant="secondary">{label}</Button>
|
|
82
|
+
</Tooltip>
|
|
83
|
+
))}
|
|
84
|
+
</div>
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 단축키 함께 보여주기
|
|
90
|
+
|
|
91
|
+
content에 Kbd를 넣으면 어두운 말풍선에 맞춰 키캡 색이 바뀌어요.
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
import { Bell, Plus, Search } from 'lucide-react'
|
|
95
|
+
import { Button, Kbd, Tooltip } from '@iamfiro/design'
|
|
96
|
+
|
|
97
|
+
export default function Example() {
|
|
98
|
+
return (
|
|
99
|
+
<div style={{ display: 'flex', gap: 8 }}>
|
|
100
|
+
<Tooltip
|
|
101
|
+
content={
|
|
102
|
+
<>
|
|
103
|
+
검색 <Kbd keys={['mod', 'K']} size="sm" />
|
|
104
|
+
</>
|
|
105
|
+
}
|
|
106
|
+
>
|
|
107
|
+
<Button iconOnly variant="ghost" icon={<Search />} aria-label="검색" aria-keyshortcuts="Meta+K Control+K" />
|
|
108
|
+
</Tooltip>
|
|
109
|
+
<Tooltip
|
|
110
|
+
content={
|
|
111
|
+
<>
|
|
112
|
+
새 문서 <Kbd keys={['C']} size="sm" />
|
|
113
|
+
</>
|
|
114
|
+
}
|
|
115
|
+
>
|
|
116
|
+
<Button iconOnly variant="ghost" icon={<Plus />} aria-label="새 문서" aria-keyshortcuts="C" />
|
|
117
|
+
</Tooltip>
|
|
118
|
+
<Tooltip
|
|
119
|
+
content={
|
|
120
|
+
<>
|
|
121
|
+
알림 <Kbd keys={['G', 'N']} separator="다음" size="sm" />
|
|
122
|
+
</>
|
|
123
|
+
}
|
|
124
|
+
>
|
|
125
|
+
<Button iconOnly variant="ghost" icon={<Bell />} aria-label="알림" />
|
|
126
|
+
</Tooltip>
|
|
127
|
+
</div>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 대기 시간
|
|
133
|
+
|
|
134
|
+
delay로 첫 툴팁의 대기 시간을 바꿔요. 기본값(TIMING.tooltipDelay, 500ms)을 쓰는 게 좋아요. 옆 툴팁이 막 열려 있었다면 이미 기다린 시간만큼은 건너뛰어요. 기본(500ms) 툴팁을 보다가 delay 1000으로 옮기면 남은 500ms만, delay 0을 보다 옮기면 1초를 다 기다려요.
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
import { Button, Tooltip } from '@iamfiro/design'
|
|
138
|
+
|
|
139
|
+
export default function Example() {
|
|
140
|
+
return (
|
|
141
|
+
<div style={{ display: 'flex', gap: 16 }}>
|
|
142
|
+
<Tooltip content="바로 열려요" delay={0}>
|
|
143
|
+
<Button variant="secondary">delay 0</Button>
|
|
144
|
+
</Tooltip>
|
|
145
|
+
<Tooltip content="0.5초 뒤에 열려요">
|
|
146
|
+
<Button variant="secondary">기본 (500ms)</Button>
|
|
147
|
+
</Tooltip>
|
|
148
|
+
<Tooltip content="1초 뒤에 열려요" delay={1000}>
|
|
149
|
+
<Button variant="secondary">delay 1000</Button>
|
|
150
|
+
</Tooltip>
|
|
151
|
+
</div>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
```
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Tracker
|
|
2
|
+
|
|
3
|
+
> 데이터 표시 · `@iamfiro/design` · 직접 만들지 말고 이 컴포넌트를 쓴다.
|
|
4
|
+
|
|
5
|
+
하루(또는 한 시간)에 한 칸씩 상태를 색으로 늘어놓은 기록 띠. 가동률 · 배포 · 장애 이력을 한눈에 보여 줘요. 띠의 양 끝만 둥글고 안쪽 칸은 작은 모서리예요. 처음엔 칸이 왼쪽부터 차례로 올라오고, 마우스를 올리면 날짜와 상태가 차트 툴팁 카드에 떠요. 첫 툴팁은 잠깐 기다린 뒤 열리고, 그다음 칸으로 옮기면 바로 바뀌어요.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Tracker } from '@iamfiro/design'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 디자인 규칙
|
|
12
|
+
|
|
13
|
+
- 상태 이력(가동률 · 배포 · 장애)은 `Tracker`: 같은 칸이 2–3px 간격으로, 띠의 양 끝만 둥글고 안쪽 칸은 2px. 정상 `--success` · 배포/기록 없음 회색 · 장애 빨강 · 저하 주황. 툴팁은 portal(fixed)로 띄워 Card `overflow: hidden`에 잘리지 않게, 첫 툴팁만 `TIMING.tooltipDelay`.
|
|
14
|
+
|
|
15
|
+
## API
|
|
16
|
+
|
|
17
|
+
### Tracker
|
|
18
|
+
|
|
19
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
20
|
+
| --- | --- | --- | --- |
|
|
21
|
+
| `data` (필수) | `TrackerBlock[]` | | { key, tone?, color?, tooltip?, status?, value? } 목록. 오래된 칸부터. |
|
|
22
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | 칸 높이 24 · 32 · 40px(fixed일 때 칸 폭 6 · 8 · 10px). |
|
|
23
|
+
| `height` | `number` | | 칸 높이(px). size보다 우선. |
|
|
24
|
+
| `layout` | `'fill' \| 'fixed'` | `'fill'` | fill: 폭에 맞춰 칸이 줄고 늘어요 · fixed: 칸 폭 고정. |
|
|
25
|
+
| `tooltip` | `boolean` | `true` | 날짜 · 상태 카드 표시. |
|
|
26
|
+
| `activeIndex / defaultActiveIndex / onActiveIndexChange` | `number \| null` | | 고른 칸(제어/비제어). |
|
|
27
|
+
| `aria-label` | `string` | `'상태 기록'` | 이름. 고른 칸은 aria-live로 읽어요. |
|
|
28
|
+
|
|
29
|
+
### TrackerBlock
|
|
30
|
+
|
|
31
|
+
| prop | 타입 | 기본값 | 설명 |
|
|
32
|
+
| --- | --- | --- | --- |
|
|
33
|
+
| `key` (필수) | `string` | | 칸의 고유 키. |
|
|
34
|
+
| `tone` | `'success' \| 'warning' \| 'danger' \| 'neutral' \| 'accent' \| 'empty'` | `'success'` | 정상 · 성능 저하 · 장애 · 배포 · 점검 · 기록 없음. |
|
|
35
|
+
| `color` | `string` | | tone 대신 쓸 색. CSS 변수 이름('--chart-3') 또는 색. |
|
|
36
|
+
| `tooltip` | `ReactNode` | | 툴팁 제목(보통 날짜). |
|
|
37
|
+
| `status` | `ReactNode` | | 툴팁 행 이름. 기본은 tone 이름("정상", "장애"…). |
|
|
38
|
+
| `value` | `ReactNode` | | 툴팁 행 오른쪽 값("99.2%"). |
|
|
39
|
+
|
|
40
|
+
## 예제
|
|
41
|
+
|
|
42
|
+
예제를 감싼 `style={{ ... }}` div는 미리보기 배치용이다. 실제 화면 배치는 `Stack` · `Inline` · `Grid`로 한다.
|
|
43
|
+
|
|
44
|
+
### 기본
|
|
45
|
+
|
|
46
|
+
정상은 초록, 배포 · 기록 없음은 회색, 장애는 빨강 · 성능 저하는 주황이에요. 포커스한 뒤 ←/→, Home/End로 칸을 옮기고 Esc로 닫아요.
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import { Tracker, type TrackerBlock, type TrackerTone } from '@iamfiro/design'
|
|
50
|
+
|
|
51
|
+
// 9월 26일 … 10월 25일, 하루에 한 칸. s 정상 · w 성능 저하 · d 장애 · n 배포 · e 기록 없음
|
|
52
|
+
const PATTERN = 'eessssssnssssswssssssdsssnssss'
|
|
53
|
+
const TONES: Record<string, TrackerTone> = { s: 'success', w: 'warning', d: 'danger', n: 'neutral', e: 'empty' }
|
|
54
|
+
const dayLabel = (i: number) => (i < 5 ? `9월 ${26 + i}일` : `10월 ${i - 4}일`)
|
|
55
|
+
|
|
56
|
+
const DAYS: TrackerBlock[] = PATTERN.split('').map((c, i) => ({ key: `d${i}`, tone: TONES[c], tooltip: dayLabel(i) }))
|
|
57
|
+
|
|
58
|
+
export default function Example() {
|
|
59
|
+
return (
|
|
60
|
+
<div style={{ width: '100%', maxWidth: 480 }}>
|
|
61
|
+
<Tracker data={DAYS} aria-label="최근 30일 상태" />
|
|
62
|
+
</div>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 크기 · 높이 · 칸 폭
|
|
68
|
+
|
|
69
|
+
size(sm · md · lg)나 height로 높이를 정해요. 기본 layout="fill"은 칸이 폭에 맞춰 줄고 늘며, "fixed"는 칸 폭을 고정해요.
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { Stack, Text, Tracker, type TrackerBlock, type TrackerTone } from '@iamfiro/design'
|
|
73
|
+
|
|
74
|
+
const PATTERN = 'sssssssssssswsssssssssssssdssssssssssssssssnssssssssssss'
|
|
75
|
+
const TONES: Record<string, TrackerTone> = { s: 'success', w: 'warning', d: 'danger', n: 'neutral' }
|
|
76
|
+
|
|
77
|
+
// 지난 56시간, 한 시간에 한 칸.
|
|
78
|
+
const HOURS: TrackerBlock[] = PATTERN.split('').map((c, i) => ({ key: `h${i}`, tone: TONES[c], tooltip: `${56 - i}시간 전` }))
|
|
79
|
+
|
|
80
|
+
export default function Example() {
|
|
81
|
+
return (
|
|
82
|
+
<Stack gap={5} style={{ width: '100%', maxWidth: 520 }}>
|
|
83
|
+
<Stack gap={2}>
|
|
84
|
+
<Text variant="label-sm">sm · 24px</Text>
|
|
85
|
+
<Tracker data={HOURS} size="sm" aria-label="시간별 상태" />
|
|
86
|
+
</Stack>
|
|
87
|
+
<Stack gap={2}>
|
|
88
|
+
<Text variant="label-sm">lg · 40px</Text>
|
|
89
|
+
<Tracker data={HOURS} size="lg" aria-label="시간별 상태" />
|
|
90
|
+
</Stack>
|
|
91
|
+
<Stack gap={2}>
|
|
92
|
+
<Text variant="label-sm">height · 16px</Text>
|
|
93
|
+
<Tracker data={HOURS} height={16} size="sm" aria-label="시간별 상태" />
|
|
94
|
+
</Stack>
|
|
95
|
+
<Stack gap={2}>
|
|
96
|
+
<Text variant="label-sm">layout="fixed" · 칸 폭 고정</Text>
|
|
97
|
+
<Tracker data={HOURS.slice(-24)} layout="fixed" aria-label="최근 24시간 상태" />
|
|
98
|
+
</Stack>
|
|
99
|
+
</Stack>
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 가동률 카드
|
|
105
|
+
|
|
106
|
+
CardHeader 아래에 라벨 줄("가동률 99.8%")과 양 끝 날짜("30일 전" … "오늘")를 붙여 조립해요. value는 툴팁 행 오른쪽에 나와요.
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
import { Badge, Inline, Stack, Text, Card, CardBody, CardHeader, Tracker, type TrackerBlock, type TrackerTone } from '@iamfiro/design'
|
|
110
|
+
|
|
111
|
+
// s 정상 · w 성능 저하 · d 장애 · n 배포
|
|
112
|
+
const PATTERN = 'sssssnsssssssssswsssssssnsdsss'
|
|
113
|
+
const TONES: Record<string, TrackerTone> = { s: 'success', w: 'warning', d: 'danger', n: 'neutral' }
|
|
114
|
+
const UPTIME: Record<string, string> = { s: '100%', w: '99.1%', d: '97.4%', n: '100%' }
|
|
115
|
+
const dayLabel = (i: number) => (i < 5 ? `9월 ${26 + i}일` : `10월 ${i - 4}일`)
|
|
116
|
+
|
|
117
|
+
const DAYS: TrackerBlock[] = PATTERN.split('').map((c, i) => ({
|
|
118
|
+
key: `d${i}`,
|
|
119
|
+
tone: TONES[c],
|
|
120
|
+
tooltip: dayLabel(i),
|
|
121
|
+
value: UPTIME[c],
|
|
122
|
+
}))
|
|
123
|
+
|
|
124
|
+
export default function Example() {
|
|
125
|
+
return (
|
|
126
|
+
<Card style={{ width: '100%', maxWidth: 480 }}>
|
|
127
|
+
<CardHeader
|
|
128
|
+
title="API 서버"
|
|
129
|
+
description="api.example.com"
|
|
130
|
+
actions={
|
|
131
|
+
<Badge tone="success" dot>
|
|
132
|
+
정상 운영
|
|
133
|
+
</Badge>
|
|
134
|
+
}
|
|
135
|
+
/>
|
|
136
|
+
<CardBody>
|
|
137
|
+
<Stack gap={2}>
|
|
138
|
+
<Inline justify="between" gap={3}>
|
|
139
|
+
<Text variant="label-sm">최근 30일</Text>
|
|
140
|
+
<Text variant="label-sm" tone="secondary" numeric>
|
|
141
|
+
가동률 99.8%
|
|
142
|
+
</Text>
|
|
143
|
+
</Inline>
|
|
144
|
+
<Tracker data={DAYS} aria-label="API 서버 최근 30일 가동 기록" />
|
|
145
|
+
<Inline justify="between" gap={3}>
|
|
146
|
+
<Text variant="caption" tone="tertiary">
|
|
147
|
+
30일 전
|
|
148
|
+
</Text>
|
|
149
|
+
<Text variant="caption" tone="tertiary">
|
|
150
|
+
오늘
|
|
151
|
+
</Text>
|
|
152
|
+
</Inline>
|
|
153
|
+
</Stack>
|
|
154
|
+
</CardBody>
|
|
155
|
+
</Card>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
```
|