@stacksjs/components 0.2.111 → 0.2.112
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/dist/{Sidebar-4hn7vw4n.stx → Sidebar-bg47fqmq.stx} +100 -3
- package/dist/{SidebarItem-gtrcw4ky.stx → SidebarItem-9rvbwhxr.stx} +11 -7
- package/dist/index.js +15 -12
- package/dist/ui/sidebar/themes.d.ts +26 -3
- package/package.json +4 -3
- package/src/components/CodeBlock.stx +54 -0
- package/src/components/Footer.stx +66 -0
- package/src/components/Hero.stx +25 -0
- package/src/components/Installation.stx +37 -0
- package/src/components/index.ts +4 -0
- package/src/composables/index.ts +4 -0
- package/src/composables/useCopyCode.ts +73 -0
- package/src/composables/useDarkMode.ts +100 -0
- package/src/composables/useSEO.ts +230 -0
- package/src/composables/utilities/index.ts +7 -0
- package/src/composables/utilities/useClickOutside.ts +72 -0
- package/src/composables/utilities/useFocusTrap.ts +159 -0
- package/src/composables/utilities/useKeyboard.ts +124 -0
- package/src/composables/utilities/useLocalStorage.ts +132 -0
- package/src/composables/utilities/useMediaQuery.ts +118 -0
- package/src/index.ts +99 -0
- package/src/stx.d.ts +4 -0
- package/src/ui/accordion/Accordion.stx +146 -0
- package/src/ui/accordion/AccordionItem.stx +37 -0
- package/src/ui/accordion/index.ts +47 -0
- package/src/ui/audio/Audio.stx +50 -0
- package/src/ui/audio/README.md +41 -0
- package/src/ui/audio/index.ts +13 -0
- package/src/ui/auth/Login.stx +161 -0
- package/src/ui/auth/README.md +142 -0
- package/src/ui/auth/Signup.stx +159 -0
- package/src/ui/auth/TwoFactorChallenge.stx +111 -0
- package/src/ui/auth/index.ts +32 -0
- package/src/ui/avatar/Avatar.stx +77 -0
- package/src/ui/avatar/index.ts +12 -0
- package/src/ui/badge/Badge.stx +62 -0
- package/src/ui/badge/index.ts +10 -0
- package/src/ui/breadcrumb/Breadcrumb.stx +79 -0
- package/src/ui/breadcrumb/index.ts +15 -0
- package/src/ui/button/Button.stx +74 -0
- package/src/ui/button/README.md +80 -0
- package/src/ui/button/index.ts +85 -0
- package/src/ui/calendar/Calendar.stx +189 -0
- package/src/ui/calendar/README.md +254 -0
- package/src/ui/calendar/index.ts +14 -0
- package/src/ui/card/Card.stx +68 -0
- package/src/ui/card/index.ts +13 -0
- package/src/ui/checkbox/Checkbox.stx +86 -0
- package/src/ui/checkbox/index.ts +16 -0
- package/src/ui/combobox/Combobox.stx +96 -0
- package/src/ui/combobox/ComboboxButton.stx +25 -0
- package/src/ui/combobox/ComboboxInput.stx +32 -0
- package/src/ui/combobox/ComboboxOption.stx +49 -0
- package/src/ui/combobox/ComboboxOptions.stx +16 -0
- package/src/ui/combobox/README.md +150 -0
- package/src/ui/combobox/index.ts +40 -0
- package/src/ui/command-palette/CommandPalette.stx +81 -0
- package/src/ui/command-palette/CommandPaletteItem.stx +27 -0
- package/src/ui/command-palette/README.md +42 -0
- package/src/ui/command-palette/index.ts +15 -0
- package/src/ui/dialog/Dialog.stx +41 -0
- package/src/ui/dialog/DialogBackdrop.stx +9 -0
- package/src/ui/dialog/DialogDescription.stx +11 -0
- package/src/ui/dialog/DialogPanel.stx +16 -0
- package/src/ui/dialog/DialogTitle.stx +11 -0
- package/src/ui/dialog/README.md +121 -0
- package/src/ui/dialog/index.ts +32 -0
- package/src/ui/drawer/Drawer.stx +120 -0
- package/src/ui/drawer/README.md +90 -0
- package/src/ui/drawer/index.ts +9 -0
- package/src/ui/dropdown/Dropdown.stx +82 -0
- package/src/ui/dropdown/DropdownButton.stx +29 -0
- package/src/ui/dropdown/DropdownItem.stx +35 -0
- package/src/ui/dropdown/DropdownItems.stx +18 -0
- package/src/ui/dropdown/README.md +114 -0
- package/src/ui/dropdown/index.ts +29 -0
- package/src/ui/form/Form.stx +95 -0
- package/src/ui/form/index.ts +67 -0
- package/src/ui/heatmap/Heatmap.stx +294 -0
- package/src/ui/image/Image.stx +165 -0
- package/src/ui/image/README.md +164 -0
- package/src/ui/image/index.ts +22 -0
- package/src/ui/input/EmailInput.stx +30 -0
- package/src/ui/input/NumberInput.stx +126 -0
- package/src/ui/input/PasswordInput.stx +143 -0
- package/src/ui/input/SearchInput.stx +44 -0
- package/src/ui/input/TextInput.stx +132 -0
- package/src/ui/input/index.ts +180 -0
- package/src/ui/listbox/Listbox.stx +101 -0
- package/src/ui/listbox/ListboxButton.stx +28 -0
- package/src/ui/listbox/ListboxLabel.stx +11 -0
- package/src/ui/listbox/ListboxOption.stx +49 -0
- package/src/ui/listbox/ListboxOptions.stx +16 -0
- package/src/ui/listbox/README.md +135 -0
- package/src/ui/listbox/index.ts +39 -0
- package/src/ui/navigator/Navigator.stx +113 -0
- package/src/ui/navigator/README.md +352 -0
- package/src/ui/navigator/index.ts +20 -0
- package/src/ui/notification/Notification.stx +117 -0
- package/src/ui/notification/README.md +114 -0
- package/src/ui/notification/index.ts +12 -0
- package/src/ui/pagination/Pagination.stx +150 -0
- package/src/ui/pagination/index.ts +11 -0
- package/src/ui/payment/Checkout.stx +31 -0
- package/src/ui/payment/DefaultPaymentMethod.stx +62 -0
- package/src/ui/payment/PaymentMethods.stx +104 -0
- package/src/ui/payment/README.md +345 -0
- package/src/ui/payment/SubscriptionCheckout.stx +323 -0
- package/src/ui/payment/index.ts +59 -0
- package/src/ui/popover/Popover.stx +60 -0
- package/src/ui/popover/PopoverButton.stx +29 -0
- package/src/ui/popover/PopoverPanel.stx +23 -0
- package/src/ui/popover/README.md +91 -0
- package/src/ui/popover/index.ts +22 -0
- package/src/ui/portal/Portal.stx +57 -0
- package/src/ui/portal/index.ts +6 -0
- package/src/ui/progress/Progress.stx +131 -0
- package/src/ui/progress/index.ts +12 -0
- package/src/ui/radio/Radio.stx +77 -0
- package/src/ui/radio/index.ts +15 -0
- package/src/ui/radio-group/README.md +139 -0
- package/src/ui/radio-group/RadioGroup.stx +60 -0
- package/src/ui/radio-group/RadioGroupDescription.stx +11 -0
- package/src/ui/radio-group/RadioGroupLabel.stx +11 -0
- package/src/ui/radio-group/RadioGroupOption.stx +58 -0
- package/src/ui/radio-group/index.ts +30 -0
- package/src/ui/select/README.md +180 -0
- package/src/ui/select/Select.stx +82 -0
- package/src/ui/select/index.ts +21 -0
- package/src/ui/sidebar/Sidebar.stx +573 -0
- package/src/ui/sidebar/SidebarFooter.stx +71 -0
- package/src/ui/sidebar/SidebarHeader.stx +103 -0
- package/src/ui/sidebar/SidebarItem.stx +90 -0
- package/src/ui/sidebar/SidebarSection.stx +83 -0
- package/src/ui/sidebar/index.ts +146 -0
- package/src/ui/sidebar/themes.ts +288 -0
- package/src/ui/skeleton/Skeleton.stx +48 -0
- package/src/ui/skeleton/index.ts +11 -0
- package/src/ui/spinner/Spinner.stx +109 -0
- package/src/ui/spinner/index.ts +9 -0
- package/src/ui/stepper/README.md +36 -0
- package/src/ui/stepper/Stepper.stx +17 -0
- package/src/ui/stepper/StepperStep.stx +57 -0
- package/src/ui/stepper/index.ts +19 -0
- package/src/ui/storage/README.md +193 -0
- package/src/ui/storage/index.ts +347 -0
- package/src/ui/switch/README.md +114 -0
- package/src/ui/switch/Switch.stx +72 -0
- package/src/ui/switch/index.ts +10 -0
- package/src/ui/table/README.md +39 -0
- package/src/ui/table/Table.stx +14 -0
- package/src/ui/table/TableBody.stx +10 -0
- package/src/ui/table/TableCell.stx +10 -0
- package/src/ui/table/TableHead.stx +10 -0
- package/src/ui/table/TableHeader.stx +20 -0
- package/src/ui/table/TableRow.stx +11 -0
- package/src/ui/table/index.ts +35 -0
- package/src/ui/tabs/TabPanel.stx +25 -0
- package/src/ui/tabs/Tabs.stx +202 -0
- package/src/ui/tabs/index.ts +50 -0
- package/src/ui/teleport/Teleport.stx +65 -0
- package/src/ui/teleport/index.ts +7 -0
- package/src/ui/textarea/Textarea.stx +108 -0
- package/src/ui/textarea/index.ts +20 -0
- package/src/ui/tooltip/Tooltip.stx +71 -0
- package/src/ui/tooltip/index.ts +10 -0
- package/src/ui/transition/README.md +30 -0
- package/src/ui/transition/Transition.stx +102 -0
- package/src/ui/transition/index.ts +25 -0
- package/src/ui/video/README.md +47 -0
- package/src/ui/video/Video.stx +45 -0
- package/src/ui/video/index.ts +16 -0
- package/src/ui/virtual-list/VirtualList.stx +67 -0
- package/src/ui/virtual-list/index.ts +10 -0
- package/src/ui/virtual-table/VirtualTable.stx +103 -0
- package/src/ui/virtual-table/index.ts +21 -0
- package/src/utils/PROP_VALIDATION.md +458 -0
- package/src/utils/THEME_SYSTEM.md +702 -0
- package/src/utils/accessibility.ts +841 -0
- package/src/utils/animation/easing.ts +368 -0
- package/src/utils/animation/helpers.ts +223 -0
- package/src/utils/animation/index.ts +5 -0
- package/src/utils/animation/keyframes.ts +230 -0
- package/src/utils/error-handling.ts +475 -0
- package/src/utils/highlighter.ts +93 -0
- package/src/utils/i18n.ts +634 -0
- package/src/utils/keep-alive.ts +819 -0
- package/src/utils/lazy-loading.ts +530 -0
- package/src/utils/prop-validation.ts +478 -0
- package/src/utils/theme.ts +626 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sidebar theme registry
|
|
3
|
+
*
|
|
4
|
+
* Every visual decision the sidebar makes lives here, expressed as utility
|
|
5
|
+
* classes, so a theme can be read top-to-bottom like a spec sheet.
|
|
6
|
+
*
|
|
7
|
+
* The flagship theme is `macos` — a faithful recreation of the sidebar in
|
|
8
|
+
* the latest macOS (Tahoe, macOS 26/27 "Liquid Glass"). Its metrics were
|
|
9
|
+
* measured pixel-by-pixel from Mail.app's source list at @2x:
|
|
10
|
+
*
|
|
11
|
+
* row pitch 32px, and the highlight fills the whole 32px — AppKit leaves
|
|
12
|
+
* no gap between rows, so consecutive selected/hovered rows touch
|
|
13
|
+
* highlight radius 8px
|
|
14
|
+
* label 13px · count 13px secondary gray · section header 11px semibold,
|
|
15
|
+
* Title Case (NOT uppercase — uppercasing section headers is the single
|
|
16
|
+
* most common tell of a web sidebar imitating macOS)
|
|
17
|
+
* icon 17px in a fixed 22px slot · disclosure gutter 18px · child indent 16px
|
|
18
|
+
* pane 234px wide, #f1f2f3 in light appearance, ~90% opaque so the
|
|
19
|
+
* backdrop bleeds through faintly rather than tinting the pane
|
|
20
|
+
*
|
|
21
|
+
* Selection follows AppKit's two-state model (`selection` below): in a key
|
|
22
|
+
* window the row takes the system accent with a white label, icon and count;
|
|
23
|
+
* when the window resigns key it falls back to a neutral fill with the label
|
|
24
|
+
* left dark. Icons desaturate to gray in the same non-key state.
|
|
25
|
+
*
|
|
26
|
+
* Legacy themes (`workspace`, `desktop`, `solid`, `transparent`, `vibrancy`)
|
|
27
|
+
* are preserved verbatim from the previous variant maps. `tahoe` now aliases
|
|
28
|
+
* `macos` — it always meant "look like macOS", and now it actually does.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/** macOS system colors (light appearance) for tinting sidebar icons. */
|
|
32
|
+
export const macosColors = {
|
|
33
|
+
blue: '#0088ff',
|
|
34
|
+
red: '#ff383c',
|
|
35
|
+
pink: '#ff2d55',
|
|
36
|
+
orange: '#ff8d28',
|
|
37
|
+
yellow: '#ffcc00',
|
|
38
|
+
green: '#34c759',
|
|
39
|
+
teal: '#00c3d0',
|
|
40
|
+
cyan: '#00c0e8',
|
|
41
|
+
indigo: '#6155f5',
|
|
42
|
+
purple: '#cb30e0',
|
|
43
|
+
brown: '#ac7f5e',
|
|
44
|
+
gray: '#8e8e93',
|
|
45
|
+
} as const
|
|
46
|
+
|
|
47
|
+
export type MacosColor = keyof typeof macosColors
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* How a theme paints the selected row.
|
|
51
|
+
*
|
|
52
|
+
* `accent` reproduces AppKit: the pane owns CSS custom properties for the
|
|
53
|
+
* key/non-key fills, and scoped rules recolor the row's label, icon, count
|
|
54
|
+
* and chevron together. `classes` is the older utility-class model, where
|
|
55
|
+
* `item.active` is simply added to the row element and children are left
|
|
56
|
+
* alone. Legacy themes stay on `classes` so they render exactly as before.
|
|
57
|
+
*/
|
|
58
|
+
export type SidebarSelectionModel = 'accent' | 'classes'
|
|
59
|
+
|
|
60
|
+
/** Class groups a sidebar theme provides. All values are utility classes. */
|
|
61
|
+
export interface SidebarTheme {
|
|
62
|
+
/** The <aside> pane itself: material, text color, borders. */
|
|
63
|
+
pane: string
|
|
64
|
+
/** Which selection model the Sidebar controller and scoped CSS apply. */
|
|
65
|
+
selection: SidebarSelectionModel
|
|
66
|
+
/** Extra overlay layers rendered inside the pane (visual only). */
|
|
67
|
+
layers: {
|
|
68
|
+
/** Liquid Glass edge highlight — a bright rim that subtly shimmers. */
|
|
69
|
+
shimmerRim?: boolean
|
|
70
|
+
/** Frosted material behind the pane (a real `backdrop-filter`). */
|
|
71
|
+
frosted?: boolean
|
|
72
|
+
/** Soft tint gradient blended over the material. */
|
|
73
|
+
tint?: string
|
|
74
|
+
}
|
|
75
|
+
/** Scrollable content area between header and footer. */
|
|
76
|
+
scrollArea: string
|
|
77
|
+
/** Section header row (e.g. "Favorites", "iCloud"). */
|
|
78
|
+
sectionHeader: string
|
|
79
|
+
/** Chevron inside the section header (revealed on hover). */
|
|
80
|
+
sectionChevron: string
|
|
81
|
+
/** Wrapper around a section's items. */
|
|
82
|
+
sectionGroup: string
|
|
83
|
+
/** One navigation row, layout + typography. State styles live below. */
|
|
84
|
+
item: {
|
|
85
|
+
base: string
|
|
86
|
+
hover: string
|
|
87
|
+
active: string
|
|
88
|
+
pressed: string
|
|
89
|
+
disabled: string
|
|
90
|
+
/** Fixed-width leading slot the disclosure chevron sits in. */
|
|
91
|
+
disclosure: string
|
|
92
|
+
/** Chevron glyph itself (rotates 90° when expanded). */
|
|
93
|
+
chevron: string
|
|
94
|
+
/** Fixed-width slot that centers the 17px icon. */
|
|
95
|
+
iconSlot: string
|
|
96
|
+
icon: string
|
|
97
|
+
/** Thumbnail images (album art, avatars) rendered instead of an icon. */
|
|
98
|
+
image: string
|
|
99
|
+
label: string
|
|
100
|
+
/** Right-aligned unread/item count — plain gray text on macOS. */
|
|
101
|
+
count: string
|
|
102
|
+
/** Indentation added per nesting depth. */
|
|
103
|
+
indentPerLevel: number
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const macos: SidebarTheme = {
|
|
108
|
+
pane: [
|
|
109
|
+
// Frosted sidebar material. In a Craft window with `webSidebarMaterial`
|
|
110
|
+
// the native vibrancy shows through; in a browser the backdrop blur
|
|
111
|
+
// approximates it over whatever sits behind the pane.
|
|
112
|
+
//
|
|
113
|
+
// The opacity is deliberately high. Sampling Mail.app over a saturated
|
|
114
|
+
// blue wallpaper, the pane moved by one or two 8-bit steps (#f1f2f2 to
|
|
115
|
+
// #f1f2f3) — AppKit's sidebar material is nearly opaque and only lets a
|
|
116
|
+
// hint of the backdrop through. A half-transparent pane reads as a web
|
|
117
|
+
// imitation, and over a dark page it inverts into a dark bar entirely.
|
|
118
|
+
'bg-[#f2f2f4]/90 dark:bg-[#1c1c1e]/88',
|
|
119
|
+
'text-black dark:text-white',
|
|
120
|
+
'select-none',
|
|
121
|
+
].join(' '),
|
|
122
|
+
selection: 'accent',
|
|
123
|
+
layers: {
|
|
124
|
+
shimmerRim: true,
|
|
125
|
+
// The blur itself is real CSS in Sidebar.stx rather than a utility.
|
|
126
|
+
// Expressed as `backdrop-blur-[50px]` / `backdrop-saturate-[180%]` the
|
|
127
|
+
// arbitrary values did not survive the stx dev server's class
|
|
128
|
+
// extraction: the pane computed `backdrop-filter: none`, and an earlier
|
|
129
|
+
// `backdrop-saturate-[1.7]` reached the generator with its brackets
|
|
130
|
+
// stripped, so it was read as a percentage and compiled to
|
|
131
|
+
// `saturate(0.017)` — draining the colour out of the whole backdrop.
|
|
132
|
+
// Crosswind parses and generates both correctly on its own, so the
|
|
133
|
+
// material is written as plain CSS to stay out of that path entirely.
|
|
134
|
+
frosted: true,
|
|
135
|
+
},
|
|
136
|
+
scrollArea: 'flex-1 overflow-y-auto overflow-x-hidden px-[10px] pb-[10px]',
|
|
137
|
+
sectionHeader: [
|
|
138
|
+
'group/section flex w-full items-center',
|
|
139
|
+
'pl-[8px] pr-[6px] pt-[16px] pb-[5px]',
|
|
140
|
+
'text-[11px] font-semibold leading-[13px]',
|
|
141
|
+
'text-[#3c3c43]/60 dark:text-[#ebebf5]/60',
|
|
142
|
+
].join(' '),
|
|
143
|
+
sectionChevron: [
|
|
144
|
+
'i-f7-chevron-down h-[11px] w-[11px] ml-auto',
|
|
145
|
+
'text-[#3c3c43]/45 dark:text-[#ebebf5]/45',
|
|
146
|
+
'opacity-0 group-hover/section:opacity-100 transition-opacity duration-150',
|
|
147
|
+
'transition-transform duration-200',
|
|
148
|
+
].join(' '),
|
|
149
|
+
// No gap: AppKit rows are contiguous, the 32px pitch IS the row.
|
|
150
|
+
sectionGroup: 'flex flex-col',
|
|
151
|
+
item: {
|
|
152
|
+
base: [
|
|
153
|
+
'flex w-full items-center',
|
|
154
|
+
'h-[32px] rounded-[8px] pl-[4px] pr-[8px]',
|
|
155
|
+
'text-[13px] leading-[16px] font-normal',
|
|
156
|
+
'text-black dark:text-white',
|
|
157
|
+
'transition-colors duration-150 ease-out',
|
|
158
|
+
'cursor-default',
|
|
159
|
+
].join(' '),
|
|
160
|
+
hover: 'hover:bg-black/4 dark:hover:bg-white/6',
|
|
161
|
+
// Selection is painted by the `accent` model in Sidebar.stx's scoped CSS,
|
|
162
|
+
// which has to recolor the label, icon and count together. Leaving this
|
|
163
|
+
// empty keeps the controller from also stacking a conflicting background.
|
|
164
|
+
active: '',
|
|
165
|
+
pressed: 'active:bg-black/10 dark:active:bg-white/18',
|
|
166
|
+
disabled: 'opacity-40 pointer-events-none',
|
|
167
|
+
disclosure: 'flex h-[16px] w-[18px] shrink-0 items-center justify-center',
|
|
168
|
+
chevron: [
|
|
169
|
+
'i-f7-chevron-right h-[11px] w-[11px]',
|
|
170
|
+
'text-[#3c3c43]/55 dark:text-[#ebebf5]/55',
|
|
171
|
+
'transition-transform duration-200 ease-out',
|
|
172
|
+
].join(' '),
|
|
173
|
+
iconSlot: 'flex h-[20px] w-[22px] shrink-0 items-center justify-center mr-[7px]',
|
|
174
|
+
icon: 'h-[17px] w-[17px]',
|
|
175
|
+
image: 'h-[20px] w-[20px] rounded-[4px] object-cover shadow-sm',
|
|
176
|
+
label: 'flex-1 truncate text-left',
|
|
177
|
+
count: [
|
|
178
|
+
'ml-[8px] shrink-0 tabular-nums',
|
|
179
|
+
'text-[13px] leading-[16px]',
|
|
180
|
+
'text-[#3c3c43]/60 dark:text-[#ebebf5]/60',
|
|
181
|
+
].join(' '),
|
|
182
|
+
indentPerLevel: 16,
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Legacy themes carried over from the old per-component variant maps so
|
|
188
|
+
* existing apps keep rendering identically. New work should use `macos`.
|
|
189
|
+
*/
|
|
190
|
+
const workspace: SidebarTheme = {
|
|
191
|
+
selection: 'classes',
|
|
192
|
+
pane: 'bg-[#f4f4f3] dark:bg-neutral-950 text-zinc-950 dark:text-white select-none',
|
|
193
|
+
layers: {},
|
|
194
|
+
scrollArea: 'flex-1 overflow-y-auto overflow-x-hidden px-5 py-5',
|
|
195
|
+
sectionHeader: 'group/section flex w-full items-center gap-2.5 px-4 pb-2 pt-5 text-[13px] font-semibold uppercase tracking-[0.12em] text-zinc-400 dark:text-zinc-500',
|
|
196
|
+
sectionChevron: 'i-f7-chevron-down h-3 w-3 ml-auto opacity-0 group-hover/section:opacity-100 transition-opacity duration-150 transition-transform duration-200',
|
|
197
|
+
sectionGroup: 'flex flex-col space-y-1',
|
|
198
|
+
item: {
|
|
199
|
+
base: 'flex w-full items-center gap-3 rounded-[16px] px-3.5 py-2 text-[14px] leading-tight transition-colors duration-150',
|
|
200
|
+
hover: 'hover:bg-[#ececea] hover:text-zinc-950 dark:hover:bg-white/10',
|
|
201
|
+
active: 'bg-[#e7e7e5] text-zinc-950 dark:bg-white/12 dark:text-white',
|
|
202
|
+
pressed: 'active:bg-[#e2e2e0] dark:active:bg-white/15',
|
|
203
|
+
disabled: 'opacity-50 pointer-events-none',
|
|
204
|
+
disclosure: 'flex h-4 w-4 shrink-0 items-center justify-center',
|
|
205
|
+
chevron: 'i-f7-chevron-right h-3 w-3 opacity-50 transition-transform duration-200',
|
|
206
|
+
iconSlot: 'flex h-5 w-5 shrink-0 items-center justify-center',
|
|
207
|
+
icon: 'h-[18px] w-[18px] text-zinc-500 dark:text-zinc-500',
|
|
208
|
+
image: 'h-5 w-5 rounded object-cover',
|
|
209
|
+
label: 'flex-1 truncate text-left text-zinc-700 dark:text-zinc-300',
|
|
210
|
+
count: 'ml-auto grid h-5 min-w-5 place-items-center rounded-full bg-white/70 px-1.5 text-[11px] font-medium text-zinc-500 shadow-sm dark:bg-white/10 dark:text-zinc-400',
|
|
211
|
+
indentPerLevel: 12,
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const desktop: SidebarTheme = {
|
|
216
|
+
selection: 'classes',
|
|
217
|
+
pane: 'bg-[#f3f3f1]/48 dark:bg-neutral-950/32 backdrop-blur-3xl backdrop-saturate-150 text-zinc-950 dark:text-white select-none',
|
|
218
|
+
layers: {
|
|
219
|
+
tint: 'bg-[linear-gradient(112deg,rgba(255,255,255,0.20)_0%,rgba(255,255,255,0.04)_45%,rgba(226,226,222,0.16)_100%)] dark:bg-[linear-gradient(112deg,rgba(255,255,255,0.08)_0%,rgba(255,255,255,0.02)_46%,rgba(255,255,255,0.06)_100%)]',
|
|
220
|
+
},
|
|
221
|
+
scrollArea: 'flex-1 overflow-y-auto overflow-x-hidden px-5 py-2',
|
|
222
|
+
sectionHeader: 'group/section flex w-full items-center gap-2.5 px-3 pb-1.5 pt-3 rounded-[14px] text-[12px] font-semibold uppercase tracking-[0.10em] text-zinc-500/80 dark:text-zinc-400/80',
|
|
223
|
+
sectionChevron: 'i-f7-chevron-down h-3 w-3 ml-auto opacity-0 group-hover/section:opacity-100 transition-opacity duration-150 transition-transform duration-200',
|
|
224
|
+
sectionGroup: 'flex flex-col space-y-1',
|
|
225
|
+
item: {
|
|
226
|
+
base: 'flex w-full items-center gap-3 rounded-[14px] px-3 py-1.5 text-[13.5px] leading-tight transition-colors duration-150',
|
|
227
|
+
hover: 'hover:bg-white/38 hover:text-zinc-950 dark:hover:bg-white/10',
|
|
228
|
+
active: 'bg-[#e8e8e6]/90 text-zinc-950 dark:bg-white/12 dark:text-white',
|
|
229
|
+
pressed: 'active:bg-white/50 dark:active:bg-white/15',
|
|
230
|
+
disabled: 'opacity-50 pointer-events-none',
|
|
231
|
+
disclosure: 'flex h-4 w-4 shrink-0 items-center justify-center',
|
|
232
|
+
chevron: 'i-f7-chevron-right h-3 w-3 opacity-50 transition-transform duration-200',
|
|
233
|
+
iconSlot: 'flex h-5 w-5 shrink-0 items-center justify-center',
|
|
234
|
+
icon: 'h-[18px] w-[18px] text-zinc-600 dark:text-zinc-400',
|
|
235
|
+
image: 'h-5 w-5 rounded object-cover',
|
|
236
|
+
label: 'flex-1 truncate text-left text-zinc-700 dark:text-zinc-300',
|
|
237
|
+
count: 'ml-auto grid h-5 min-w-5 place-items-center rounded-full bg-white/72 px-1.5 text-[11px] font-medium text-zinc-500 shadow-sm dark:bg-white/10 dark:text-zinc-400',
|
|
238
|
+
indentPerLevel: 12,
|
|
239
|
+
},
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const solid: SidebarTheme = {
|
|
243
|
+
...macos,
|
|
244
|
+
pane: 'bg-stone-100 dark:bg-neutral-900 text-black dark:text-white select-none',
|
|
245
|
+
layers: {},
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const transparent: SidebarTheme = {
|
|
249
|
+
...macos,
|
|
250
|
+
pane: 'bg-transparent text-black dark:text-white select-none',
|
|
251
|
+
layers: {},
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const vibrancy: SidebarTheme = {
|
|
255
|
+
...macos,
|
|
256
|
+
pane: 'bg-white/50 dark:bg-black/40 backdrop-blur-3xl backdrop-saturate-200 text-black dark:text-white select-none',
|
|
257
|
+
layers: {},
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export const sidebarThemes: Record<string, SidebarTheme> = {
|
|
261
|
+
macos,
|
|
262
|
+
// Historical names people may still pass — all render the macOS look.
|
|
263
|
+
'tahoe': macos,
|
|
264
|
+
'macos-tahoe': macos,
|
|
265
|
+
'macos-latest': macos,
|
|
266
|
+
workspace,
|
|
267
|
+
desktop,
|
|
268
|
+
solid,
|
|
269
|
+
transparent,
|
|
270
|
+
vibrancy,
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export type SidebarThemeName = keyof typeof sidebarThemes
|
|
274
|
+
|
|
275
|
+
export function resolveSidebarTheme(name?: string): SidebarTheme {
|
|
276
|
+
return sidebarThemes[name || 'macos'] || sidebarThemes.macos
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Resolve an item's icon tint. Accepts a macOS system color name
|
|
281
|
+
* (`"blue"`, `"red"`, …) or any CSS color, and falls back to the
|
|
282
|
+
* theme's default icon color when unset.
|
|
283
|
+
*/
|
|
284
|
+
export function resolveIconColor(color?: string): string | undefined {
|
|
285
|
+
if (!color)
|
|
286
|
+
return undefined
|
|
287
|
+
return macosColors[color as MacosColor] || color
|
|
288
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
export const variant = $props.variant || 'text'
|
|
3
|
+
export const count = $props.count || 1
|
|
4
|
+
export const width = $props.width || ''
|
|
5
|
+
export const height = $props.height || ''
|
|
6
|
+
export const circle = $props.circle || false
|
|
7
|
+
export const className = $props.className || ''
|
|
8
|
+
export const animate = $props.animate ?? true
|
|
9
|
+
|
|
10
|
+
// Variant classes
|
|
11
|
+
const variantClasses = {
|
|
12
|
+
text: 'h-4 rounded',
|
|
13
|
+
title: 'h-8 rounded',
|
|
14
|
+
avatar: 'w-10 h-10 rounded-full',
|
|
15
|
+
thumbnail: 'w-24 h-24 rounded-md',
|
|
16
|
+
button: 'h-10 w-32 rounded-md',
|
|
17
|
+
card: 'h-64 rounded-lg',
|
|
18
|
+
rect: 'rounded-md',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Animation classes
|
|
22
|
+
const animationClasses = animate ? 'animate-pulse' : ''
|
|
23
|
+
|
|
24
|
+
// Build base classes
|
|
25
|
+
const baseClasses = circle ? 'rounded-full' : variantClasses[variant]
|
|
26
|
+
|
|
27
|
+
// Build style object
|
|
28
|
+
let styleString = ''
|
|
29
|
+
if (width) {
|
|
30
|
+
styleString += `width: ${typeof width === 'number' ? width + 'px' : width};`
|
|
31
|
+
}
|
|
32
|
+
if (height) {
|
|
33
|
+
styleString += `height: ${typeof height === 'number' ? height + 'px' : height};`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const skeletonClasses = `bg-gray-200 dark:bg-gray-700 ${baseClasses} ${animationClasses} ${className}`.trim()
|
|
37
|
+
export const containerClasses = count > 1 ? 'space-y-3' : ''
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
@if(count > 1)
|
|
41
|
+
<div class="{{ containerClasses }}">
|
|
42
|
+
@for(i = 0; i < count; i++)
|
|
43
|
+
<div class="{{ skeletonClasses }}" style="{{ styleString }}" aria-busy="true" aria-live="polite"></div>
|
|
44
|
+
@endfor
|
|
45
|
+
</div>
|
|
46
|
+
@else
|
|
47
|
+
<div class="{{ skeletonClasses }}" style="{{ styleString }}" aria-busy="true" aria-live="polite"></div>
|
|
48
|
+
@endif
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { default as Skeleton } from './Skeleton.stx'
|
|
2
|
+
|
|
3
|
+
export interface SkeletonProps {
|
|
4
|
+
variant?: 'text' | 'title' | 'avatar' | 'thumbnail' | 'button' | 'card' | 'rect'
|
|
5
|
+
count?: number
|
|
6
|
+
width?: string | number
|
|
7
|
+
height?: string | number
|
|
8
|
+
circle?: boolean
|
|
9
|
+
animate?: boolean
|
|
10
|
+
className?: string
|
|
11
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
export const variant = $props.variant || 'circle'
|
|
3
|
+
export const size = $props.size || 'md'
|
|
4
|
+
export const color = $props.color || 'primary'
|
|
5
|
+
export const label = $props.label || ''
|
|
6
|
+
export const className = $props.className || ''
|
|
7
|
+
|
|
8
|
+
// Size classes
|
|
9
|
+
const sizeClasses = {
|
|
10
|
+
xs: 'w-3 h-3',
|
|
11
|
+
sm: 'w-4 h-4',
|
|
12
|
+
md: 'w-6 h-6',
|
|
13
|
+
lg: 'w-8 h-8',
|
|
14
|
+
xl: 'w-12 h-12',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Color classes
|
|
18
|
+
const colorClasses = {
|
|
19
|
+
primary: 'text-blue-600 dark:text-blue-500',
|
|
20
|
+
secondary: 'text-purple-600 dark:text-purple-500',
|
|
21
|
+
success: 'text-green-600 dark:text-green-500',
|
|
22
|
+
warning: 'text-yellow-600 dark:text-yellow-500',
|
|
23
|
+
danger: 'text-red-600 dark:text-red-500',
|
|
24
|
+
info: 'text-cyan-600 dark:text-cyan-500',
|
|
25
|
+
white: 'text-white',
|
|
26
|
+
gray: 'text-gray-600 dark:text-gray-400',
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const containerClasses = `inline-flex flex-col items-center gap-2 ${className}`.trim()
|
|
30
|
+
export const spinnerClasses = `${sizeClasses[size]} ${colorClasses[color]} animate-spin`.trim()
|
|
31
|
+
export const labelClasses = `text-sm font-medium text-gray-700 dark:text-gray-300`.trim()
|
|
32
|
+
|
|
33
|
+
// Dots size classes
|
|
34
|
+
const dotsSizeClasses = {
|
|
35
|
+
xs: 'w-1 h-1',
|
|
36
|
+
sm: 'w-1.5 h-1.5',
|
|
37
|
+
md: 'w-2 h-2',
|
|
38
|
+
lg: 'w-2.5 h-2.5',
|
|
39
|
+
xl: 'w-3 h-3',
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const dotsColorClasses = {
|
|
43
|
+
primary: 'bg-blue-600 dark:bg-blue-500',
|
|
44
|
+
secondary: 'bg-purple-600 dark:bg-purple-500',
|
|
45
|
+
success: 'bg-green-600 dark:bg-green-500',
|
|
46
|
+
warning: 'bg-yellow-600 dark:bg-yellow-500',
|
|
47
|
+
danger: 'bg-red-600 dark:bg-red-500',
|
|
48
|
+
info: 'bg-cyan-600 dark:bg-cyan-500',
|
|
49
|
+
white: 'bg-white',
|
|
50
|
+
gray: 'bg-gray-600 dark:bg-gray-400',
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const dotClasses = `${dotsSizeClasses[size]} ${dotsColorClasses[color]} rounded-full`.trim()
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<div class="{{ containerClasses }}" role="status" aria-live="polite" aria-busy="true">
|
|
57
|
+
@if(variant === 'circle')
|
|
58
|
+
<!-- Circle spinner (default) -->
|
|
59
|
+
<svg class="{{ spinnerClasses }}" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
60
|
+
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
61
|
+
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
62
|
+
</svg>
|
|
63
|
+
@elseif(variant === 'dots')
|
|
64
|
+
<!-- Dots spinner -->
|
|
65
|
+
<div class="flex items-center gap-1">
|
|
66
|
+
<div class="{{ dotClasses }}" style="animation: bounce 1.4s infinite ease-in-out both; animation-delay: -0.32s"></div>
|
|
67
|
+
<div class="{{ dotClasses }}" style="animation: bounce 1.4s infinite ease-in-out both; animation-delay: -0.16s"></div>
|
|
68
|
+
<div class="{{ dotClasses }}" style="animation: bounce 1.4s infinite ease-in-out both"></div>
|
|
69
|
+
</div>
|
|
70
|
+
@elseif(variant === 'bars')
|
|
71
|
+
<!-- Bars spinner -->
|
|
72
|
+
<div class="flex items-center gap-1">
|
|
73
|
+
<div class="w-1 bg-current rounded-full" style="height: {{ size === 'xs' ? '8px' : size === 'sm' ? '12px' : size === 'md' ? '16px' : size === 'lg' ? '20px' : '24px' }}; animation: bars 1.2s infinite ease-in-out; animation-delay: -0.24s"></div>
|
|
74
|
+
<div class="w-1 bg-current rounded-full" style="height: {{ size === 'xs' ? '8px' : size === 'sm' ? '12px' : size === 'md' ? '16px' : size === 'lg' ? '20px' : '24px' }}; animation: bars 1.2s infinite ease-in-out; animation-delay: -0.12s"></div>
|
|
75
|
+
<div class="w-1 bg-current rounded-full" style="height: {{ size === 'xs' ? '8px' : size === 'sm' ? '12px' : size === 'md' ? '16px' : size === 'lg' ? '20px' : '24px' }}; animation: bars 1.2s infinite ease-in-out"></div>
|
|
76
|
+
</div>
|
|
77
|
+
@elseif(variant === 'ring')
|
|
78
|
+
<!-- Ring spinner -->
|
|
79
|
+
<div class="{{ spinnerClasses }}" style="border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%;"></div>
|
|
80
|
+
@endif
|
|
81
|
+
|
|
82
|
+
@if(label)
|
|
83
|
+
<span class="{{ labelClasses }}">{{ label }}</span>
|
|
84
|
+
@endif
|
|
85
|
+
|
|
86
|
+
<span class="sr-only">{{ label || 'Loading...' }}</span>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<style>
|
|
90
|
+
@keyframes bounce {
|
|
91
|
+
0%, 80%, 100% {
|
|
92
|
+
transform: scale(0);
|
|
93
|
+
opacity: 0.5;
|
|
94
|
+
}
|
|
95
|
+
40% {
|
|
96
|
+
transform: scale(1);
|
|
97
|
+
opacity: 1;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@keyframes bars {
|
|
102
|
+
0%, 40%, 100% {
|
|
103
|
+
transform: scaleY(0.4);
|
|
104
|
+
}
|
|
105
|
+
20% {
|
|
106
|
+
transform: scaleY(1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { default as Spinner } from './Spinner.stx'
|
|
2
|
+
|
|
3
|
+
export interface SpinnerProps {
|
|
4
|
+
variant?: 'circle' | 'dots' | 'bars' | 'ring'
|
|
5
|
+
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
6
|
+
color?: 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'white' | 'gray'
|
|
7
|
+
label?: string
|
|
8
|
+
className?: string
|
|
9
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Stepper Component
|
|
2
|
+
|
|
3
|
+
A step-by-step progress indicator for multi-step processes.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @stacksjs/components
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```stx
|
|
14
|
+
<script server>
|
|
15
|
+
let currentStep = 0
|
|
16
|
+
|
|
17
|
+
function handleStepClick(step) {
|
|
18
|
+
currentStep = step
|
|
19
|
+
}
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<Stepper :currentStep="currentStep">
|
|
23
|
+
<StepperStep :stepNumber="0" :currentStep="currentStep" label="Account" :onClick="handleStepClick" />
|
|
24
|
+
<StepperStep :stepNumber="1" :currentStep="currentStep" label="Profile" :onClick="handleStepClick" />
|
|
25
|
+
<StepperStep :stepNumber="2" :currentStep="currentStep" label="Confirmation" :onClick="handleStepClick" />
|
|
26
|
+
</Stepper>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- Horizontal and vertical orientation
|
|
32
|
+
- Clickable steps
|
|
33
|
+
- Complete/current/upcoming states
|
|
34
|
+
- Dark mode support
|
|
35
|
+
- Accessible
|
|
36
|
+
- Customizable styling
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
export const currentStep = $props.currentStep || 0
|
|
3
|
+
export const orientation = $props.orientation || 'horizontal'
|
|
4
|
+
export const className = $props.className || ''
|
|
5
|
+
export const as = $props.as || 'div'
|
|
6
|
+
|
|
7
|
+
const orientationClasses = orientation === 'horizontal'
|
|
8
|
+
? 'flex flex-row'
|
|
9
|
+
: 'flex flex-col'
|
|
10
|
+
|
|
11
|
+
const baseClasses = 'w-full'
|
|
12
|
+
const stepperClasses = `${baseClasses} ${orientationClasses} ${className}`.trim()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<component :is="{{ as }}" class="{{ stepperClasses }}">
|
|
16
|
+
<slot :currentStep="currentStep" />
|
|
17
|
+
</component>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
export const stepNumber = $props.stepNumber
|
|
3
|
+
export const currentStep = $props.currentStep || 0
|
|
4
|
+
export const label = $props.label || ''
|
|
5
|
+
export const description = $props.description || ''
|
|
6
|
+
export const className = $props.className || ''
|
|
7
|
+
export const as = $props.as || 'div'
|
|
8
|
+
|
|
9
|
+
export const isComplete = stepNumber < currentStep
|
|
10
|
+
export const isCurrent = stepNumber === currentStep
|
|
11
|
+
export const isUpcoming = stepNumber > currentStep
|
|
12
|
+
|
|
13
|
+
const baseClasses = 'flex items-center'
|
|
14
|
+
export const stepClasses = `${baseClasses} ${className}`.trim()
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<script client>
|
|
18
|
+
const emit = defineEmits()
|
|
19
|
+
const stepNumber = {{ stepNumber }}
|
|
20
|
+
|
|
21
|
+
function onClick() {
|
|
22
|
+
emit('click', stepNumber)
|
|
23
|
+
}
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<component :is="{{ as }}" class="{{ stepClasses }}">
|
|
27
|
+
<button
|
|
28
|
+
type="button"
|
|
29
|
+
@click="onClick()"
|
|
30
|
+
class="flex items-center gap-3 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 rounded-lg p-2"
|
|
31
|
+
>
|
|
32
|
+
<div class="{{ isComplete ? 'bg-blue-600 dark:bg-blue-500' : isCurrent ? 'bg-blue-600 dark:bg-blue-500 ring-4 ring-blue-200 dark:ring-blue-800' : 'bg-neutral-300 dark:bg-neutral-600' }} w-10 h-10 rounded-full flex items-center justify-center text-white font-semibold transition-all">
|
|
33
|
+
@if(isComplete)
|
|
34
|
+
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
35
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
|
|
36
|
+
</svg>
|
|
37
|
+
@else
|
|
38
|
+
{{ stepNumber + 1 }}
|
|
39
|
+
@endif
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
@if(label)
|
|
43
|
+
<div class="text-left">
|
|
44
|
+
<div class="text-sm font-medium {{ isCurrent ? 'text-blue-600 dark:text-blue-400' : 'text-neutral-900 dark:text-white' }}">
|
|
45
|
+
{{ label }}
|
|
46
|
+
</div>
|
|
47
|
+
@if(description)
|
|
48
|
+
<div class="text-xs text-neutral-500 dark:text-neutral-400">
|
|
49
|
+
{{ description }}
|
|
50
|
+
</div>
|
|
51
|
+
@endif
|
|
52
|
+
</div>
|
|
53
|
+
@endif
|
|
54
|
+
</button>
|
|
55
|
+
|
|
56
|
+
<slot :isComplete="isComplete" :isCurrent="isCurrent" :isUpcoming="isUpcoming" />
|
|
57
|
+
</component>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { default as Stepper } from './Stepper.stx'
|
|
2
|
+
export { default as StepperStep } from './StepperStep.stx'
|
|
3
|
+
|
|
4
|
+
export interface StepperProps {
|
|
5
|
+
currentStep?: number
|
|
6
|
+
orientation?: 'horizontal' | 'vertical'
|
|
7
|
+
className?: string
|
|
8
|
+
as?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface StepperStepProps {
|
|
12
|
+
stepNumber: number
|
|
13
|
+
currentStep?: number
|
|
14
|
+
label?: string
|
|
15
|
+
description?: string
|
|
16
|
+
className?: string
|
|
17
|
+
as?: string
|
|
18
|
+
onClick?: (step: number) => void
|
|
19
|
+
}
|