@alpic-ai/ui 0.0.0 → 1.111.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/components/alert.d.mts +1 -1
  2. package/dist/components/avatar.d.mts +1 -1
  3. package/dist/components/badge.d.mts +1 -1
  4. package/dist/components/button.d.mts +2 -2
  5. package/dist/components/combobox.mjs +1 -1
  6. package/dist/components/dialog.mjs +2 -2
  7. package/dist/components/form.d.mts +119 -0
  8. package/dist/components/form.mjs +192 -0
  9. package/dist/components/input.d.mts +2 -0
  10. package/dist/components/input.mjs +19 -10
  11. package/dist/components/select-trigger-variants.mjs +1 -0
  12. package/dist/components/select.d.mts +1 -9
  13. package/dist/components/select.mjs +8 -28
  14. package/dist/components/sidebar.d.mts +1 -1
  15. package/dist/components/sidebar.mjs +6 -6
  16. package/dist/components/spinner.d.mts +1 -1
  17. package/dist/components/status-dot.d.mts +1 -1
  18. package/dist/components/tabs.d.mts +1 -1
  19. package/dist/components/textarea.d.mts +2 -0
  20. package/dist/components/textarea.mjs +19 -10
  21. package/dist/components/toggle-group.d.mts +1 -1
  22. package/package.json +31 -40
  23. package/src/components/combobox.tsx +1 -1
  24. package/src/components/dialog.tsx +2 -2
  25. package/src/components/form.tsx +343 -0
  26. package/src/components/input.tsx +12 -0
  27. package/src/components/select-trigger-variants.ts +1 -0
  28. package/src/components/select.tsx +2 -35
  29. package/src/components/sidebar.tsx +8 -10
  30. package/src/components/textarea.tsx +12 -1
  31. package/src/stories/accordion-card.stories.tsx +53 -0
  32. package/src/stories/accordion.stories.tsx +65 -0
  33. package/src/stories/alert.stories.tsx +58 -0
  34. package/src/stories/attachment-tile.stories.tsx +37 -0
  35. package/src/stories/avatar.stories.tsx +54 -0
  36. package/src/stories/badge.stories.tsx +50 -0
  37. package/src/stories/breadcrumb.stories.tsx +107 -0
  38. package/src/stories/button.stories.tsx +342 -0
  39. package/src/stories/card.stories.tsx +89 -0
  40. package/src/stories/checkbox.stories.tsx +56 -0
  41. package/src/stories/collapsible.stories.tsx +69 -0
  42. package/src/stories/combobox.stories.tsx +214 -0
  43. package/src/stories/command.stories.tsx +95 -0
  44. package/src/stories/copyable.stories.tsx +29 -0
  45. package/src/stories/description-list.stories.tsx +71 -0
  46. package/src/stories/dialog.stories.tsx +135 -0
  47. package/src/stories/dropdown-menu.stories.tsx +191 -0
  48. package/src/stories/form.stories.tsx +91 -0
  49. package/src/stories/input-group.stories.tsx +63 -0
  50. package/src/stories/input.stories.tsx +72 -0
  51. package/src/stories/label.stories.tsx +26 -0
  52. package/src/stories/ladle.css +3 -0
  53. package/src/stories/pagination.stories.tsx +35 -0
  54. package/src/stories/popover.stories.tsx +34 -0
  55. package/src/stories/radio-group.stories.tsx +59 -0
  56. package/src/stories/scroll-area.stories.tsx +43 -0
  57. package/src/stories/select.stories.tsx +95 -0
  58. package/src/stories/separator.stories.tsx +36 -0
  59. package/src/stories/sheet.stories.tsx +76 -0
  60. package/src/stories/sidebar.stories.tsx +255 -0
  61. package/src/stories/skeleton.stories.tsx +47 -0
  62. package/src/stories/sonner.stories.tsx +91 -0
  63. package/src/stories/spinner.stories.tsx +66 -0
  64. package/src/stories/status-dot.stories.tsx +27 -0
  65. package/src/stories/switch.stories.tsx +46 -0
  66. package/src/stories/table.stories.tsx +242 -0
  67. package/src/stories/tabs.stories.tsx +169 -0
  68. package/src/stories/tag.stories.tsx +82 -0
  69. package/src/stories/textarea.stories.tsx +60 -0
  70. package/src/stories/toggle-group.stories.tsx +142 -0
  71. package/src/stories/tooltip-icon-button.stories.tsx +59 -0
  72. package/src/stories/tooltip.stories.tsx +54 -0
@@ -0,0 +1,95 @@
1
+ import type { Story } from "@ladle/react";
2
+ import {
3
+ Select,
4
+ SelectContent,
5
+ SelectGroup,
6
+ SelectItem,
7
+ SelectLabel,
8
+ SelectSeparator,
9
+ SelectTrigger,
10
+ SelectValue,
11
+ } from "../components/select";
12
+
13
+ export const AllVariants: Story = () => (
14
+ <div className="grid grid-cols-1 gap-10 p-10 md:grid-cols-2">
15
+ <div className="flex flex-col gap-1.5">
16
+ <p className="type-text-xs font-medium text-subtle-foreground">Default (md)</p>
17
+ <Select>
18
+ <SelectTrigger size="md" className="w-full">
19
+ <SelectValue placeholder="Select a fruit..." />
20
+ </SelectTrigger>
21
+ <SelectContent>
22
+ <SelectItem value="apple">Apple</SelectItem>
23
+ <SelectItem value="banana">Banana</SelectItem>
24
+ <SelectItem value="cherry">Cherry</SelectItem>
25
+ <SelectItem value="dragonfruit">Dragonfruit</SelectItem>
26
+ <SelectItem value="elderberry">Elderberry</SelectItem>
27
+ </SelectContent>
28
+ </Select>
29
+ </div>
30
+
31
+ <div className="flex flex-col gap-1.5">
32
+ <p className="type-text-xs font-medium text-subtle-foreground">Size: sm (pre-selected)</p>
33
+ <Select defaultValue="banana">
34
+ <SelectTrigger size="sm" className="w-full">
35
+ <SelectValue placeholder="Select..." />
36
+ </SelectTrigger>
37
+ <SelectContent>
38
+ <SelectItem value="apple">Apple</SelectItem>
39
+ <SelectItem value="banana">Banana</SelectItem>
40
+ <SelectItem value="cherry">Cherry</SelectItem>
41
+ </SelectContent>
42
+ </Select>
43
+ </div>
44
+
45
+ <div className="flex flex-col gap-1.5">
46
+ <p className="type-text-xs font-medium text-subtle-foreground">Grouped with labels</p>
47
+ <Select>
48
+ <SelectTrigger size="md" className="w-full">
49
+ <SelectValue placeholder="Select a region..." />
50
+ </SelectTrigger>
51
+ <SelectContent>
52
+ <SelectGroup>
53
+ <SelectLabel>North America</SelectLabel>
54
+ <SelectItem value="us-east-1">US East (N. Virginia)</SelectItem>
55
+ <SelectItem value="us-west-2">US West (Oregon)</SelectItem>
56
+ </SelectGroup>
57
+ <SelectSeparator />
58
+ <SelectGroup>
59
+ <SelectLabel>Europe</SelectLabel>
60
+ <SelectItem value="eu-west-1">EU West (Ireland)</SelectItem>
61
+ <SelectItem value="eu-central-1">EU Central (Frankfurt)</SelectItem>
62
+ </SelectGroup>
63
+ </SelectContent>
64
+ </Select>
65
+ </div>
66
+
67
+ <div className="flex flex-col gap-1.5">
68
+ <p className="type-text-xs font-medium text-subtle-foreground">Disabled</p>
69
+ <Select defaultValue="apple" disabled>
70
+ <SelectTrigger size="md" className="w-full">
71
+ <SelectValue />
72
+ </SelectTrigger>
73
+ <SelectContent>
74
+ <SelectItem value="apple">Apple</SelectItem>
75
+ </SelectContent>
76
+ </Select>
77
+ </div>
78
+
79
+ <div className="flex flex-col gap-1.5">
80
+ <p className="type-text-xs font-medium text-subtle-foreground">Disabled items</p>
81
+ <Select>
82
+ <SelectTrigger size="md" className="w-full">
83
+ <SelectValue placeholder="Select..." />
84
+ </SelectTrigger>
85
+ <SelectContent>
86
+ <SelectItem value="available">Available option</SelectItem>
87
+ <SelectItem value="unavailable" disabled>
88
+ Unavailable option
89
+ </SelectItem>
90
+ <SelectItem value="another">Another option</SelectItem>
91
+ </SelectContent>
92
+ </Select>
93
+ </div>
94
+ </div>
95
+ );
@@ -0,0 +1,36 @@
1
+ import type { Story } from "@ladle/react";
2
+ import { Separator } from "../components/separator";
3
+
4
+ export const AllVariants: Story = () => (
5
+ <div className="flex flex-col gap-6 max-w-md">
6
+ <div className="flex flex-col gap-1.5">
7
+ <p className="type-text-xs font-medium text-subtle-foreground">Horizontal (default)</p>
8
+ <div className="flex flex-col gap-3">
9
+ <p className="type-text-sm">Content above</p>
10
+ <Separator />
11
+ <p className="type-text-sm">Content below</p>
12
+ </div>
13
+ </div>
14
+
15
+ <div className="flex flex-col gap-1.5">
16
+ <p className="type-text-xs font-medium text-subtle-foreground">Vertical</p>
17
+ <div className="flex items-center gap-3 h-6">
18
+ <span className="type-text-sm">Left</span>
19
+ <Separator orientation="vertical" />
20
+ <span className="type-text-sm">Right</span>
21
+ </div>
22
+ </div>
23
+
24
+ <div className="flex flex-col gap-1.5">
25
+ <p className="type-text-xs font-medium text-subtle-foreground">In a menu-like list</p>
26
+ <div className="flex flex-col rounded-lg border p-1">
27
+ <div className="rounded-md px-3 py-1.5 type-text-sm">Item one</div>
28
+ <div className="rounded-md px-3 py-1.5 type-text-sm">Item two</div>
29
+ <Separator className="my-1" />
30
+ <div className="rounded-md px-3 py-1.5 type-text-sm">Item three</div>
31
+ <Separator className="my-1" />
32
+ <div className="rounded-md px-3 py-1.5 type-text-sm text-destructive">Delete</div>
33
+ </div>
34
+ </div>
35
+ </div>
36
+ );
@@ -0,0 +1,76 @@
1
+ import type { Story } from "@ladle/react";
2
+ import { Button } from "../components/button";
3
+ import {
4
+ Sheet,
5
+ SheetClose,
6
+ SheetContent,
7
+ SheetDescription,
8
+ SheetFooter,
9
+ SheetHeader,
10
+ SheetTitle,
11
+ SheetTrigger,
12
+ } from "../components/sheet";
13
+
14
+ export const AllVariants: Story = () => (
15
+ <div className="flex flex-col gap-6">
16
+ <div className="flex flex-col gap-1.5">
17
+ <p className="type-text-xs font-medium text-subtle-foreground">Right (default)</p>
18
+ <Sheet>
19
+ <SheetTrigger asChild>
20
+ <Button variant="secondary">Open Right Sheet</Button>
21
+ </SheetTrigger>
22
+ <SheetContent>
23
+ <SheetHeader>
24
+ <SheetTitle>Edit profile</SheetTitle>
25
+ <SheetDescription>Make changes to your profile here. Click save when you're done.</SheetDescription>
26
+ </SheetHeader>
27
+ <div className="flex-1 px-4">
28
+ <p className="type-text-sm text-muted-foreground">Sheet content goes here.</p>
29
+ </div>
30
+ <SheetFooter>
31
+ <SheetClose asChild>
32
+ <Button variant="secondary">Cancel</Button>
33
+ </SheetClose>
34
+ <Button>Save changes</Button>
35
+ </SheetFooter>
36
+ </SheetContent>
37
+ </Sheet>
38
+ </div>
39
+
40
+ <div className="flex flex-col gap-1.5">
41
+ <p className="type-text-xs font-medium text-subtle-foreground">Left</p>
42
+ <Sheet>
43
+ <SheetTrigger asChild>
44
+ <Button variant="secondary">Open Left Sheet</Button>
45
+ </SheetTrigger>
46
+ <SheetContent side="left">
47
+ <SheetHeader>
48
+ <SheetTitle>Navigation</SheetTitle>
49
+ <SheetDescription>Browse sections of the application.</SheetDescription>
50
+ </SheetHeader>
51
+ <div className="flex-1 px-4">
52
+ <p className="type-text-sm text-muted-foreground">Navigation content here.</p>
53
+ </div>
54
+ </SheetContent>
55
+ </Sheet>
56
+ </div>
57
+
58
+ <div className="flex flex-col gap-1.5">
59
+ <p className="type-text-xs font-medium text-subtle-foreground">Bottom</p>
60
+ <Sheet>
61
+ <SheetTrigger asChild>
62
+ <Button variant="secondary">Open Bottom Sheet</Button>
63
+ </SheetTrigger>
64
+ <SheetContent side="bottom">
65
+ <SheetHeader>
66
+ <SheetTitle>Filters</SheetTitle>
67
+ <SheetDescription>Adjust filters to refine your results.</SheetDescription>
68
+ </SheetHeader>
69
+ <div className="px-4 pb-4">
70
+ <p className="type-text-sm text-muted-foreground">Filter controls here.</p>
71
+ </div>
72
+ </SheetContent>
73
+ </Sheet>
74
+ </div>
75
+ </div>
76
+ );
@@ -0,0 +1,255 @@
1
+ import type { Story } from "@ladle/react";
2
+ import { ChevronDownIcon, CodeIcon, CreditCardIcon, KeyIcon, SettingsIcon, UsersIcon } from "lucide-react";
3
+ import type { ReactNode } from "react";
4
+ import {
5
+ Sidebar,
6
+ SidebarContent,
7
+ SidebarFooter,
8
+ SidebarGroup,
9
+ SidebarGroupContent,
10
+ SidebarGroupLabel,
11
+ SidebarHeader,
12
+ SidebarInset,
13
+ SidebarMenu,
14
+ SidebarMenuBadge,
15
+ SidebarMenuButton,
16
+ SidebarMenuItem,
17
+ SidebarMenuSkeleton,
18
+ SidebarMenuSub,
19
+ SidebarMenuSubButton,
20
+ SidebarMenuSubItem,
21
+ SidebarProvider,
22
+ SidebarSeparator,
23
+ SidebarTrigger,
24
+ } from "../components/sidebar";
25
+
26
+ /**
27
+ * Wraps stories so `fixed` inside SidebarProvider becomes `absolute`
28
+ * relative to this container (via `transform: scale(1)` trick).
29
+ */
30
+ function StoryFrame({ children, height = 600 }: { children: ReactNode; height?: number }) {
31
+ return (
32
+ <div
33
+ className="relative overflow-hidden rounded-lg border [&_[data-slot=sidebar-wrapper]]:min-h-full [&_[data-slot=sidebar-container]]:h-full"
34
+ style={{ height, transform: "scale(1)" }}
35
+ >
36
+ {children}
37
+ </div>
38
+ );
39
+ }
40
+
41
+ function TeamHeader() {
42
+ return <SidebarHeader icon={<div className="size-4 rounded-xs bg-inverted" />} title="Alpic" />;
43
+ }
44
+
45
+ function UserFooter() {
46
+ return (
47
+ <SidebarFooter className="px-3 pb-4">
48
+ <div className="flex items-center gap-1.5 rounded-md px-2 h-8 group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0">
49
+ <div className="size-5 rounded-full bg-sidebar-accent border border-sidebar-border shrink-0" />
50
+ <span className="type-text-sm font-medium text-sidebar-primary group-data-[collapsible=icon]:hidden">
51
+ Alice Dupont
52
+ </span>
53
+ </div>
54
+ </SidebarFooter>
55
+ );
56
+ }
57
+
58
+ export const AllVariants: Story = () => (
59
+ <div className="flex flex-col gap-4">
60
+ <StoryFrame>
61
+ <SidebarProvider defaultOpen>
62
+ <Sidebar collapsible="icon">
63
+ <TeamHeader />
64
+ <SidebarContent>
65
+ <SidebarGroup>
66
+ <SidebarGroupContent>
67
+ <SidebarMenu>
68
+ <SidebarMenuItem>
69
+ <SidebarMenuButton>
70
+ <CodeIcon />
71
+ <span>Projects</span>
72
+ </SidebarMenuButton>
73
+ </SidebarMenuItem>
74
+ <SidebarMenuItem>
75
+ <SidebarMenuButton>
76
+ <SettingsIcon />
77
+ <span>Settings</span>
78
+ </SidebarMenuButton>
79
+ <SidebarMenuSub>
80
+ <SidebarMenuSubItem>
81
+ <SidebarMenuSubButton isActive>
82
+ <span>General</span>
83
+ </SidebarMenuSubButton>
84
+ </SidebarMenuSubItem>
85
+ <SidebarMenuSubItem>
86
+ <SidebarMenuSubButton>
87
+ <span>Notifications</span>
88
+ </SidebarMenuSubButton>
89
+ </SidebarMenuSubItem>
90
+ <SidebarMenuSubItem>
91
+ <SidebarMenuSubButton>
92
+ <span>Integrations</span>
93
+ </SidebarMenuSubButton>
94
+ </SidebarMenuSubItem>
95
+ </SidebarMenuSub>
96
+ </SidebarMenuItem>
97
+ <SidebarMenuItem>
98
+ <SidebarMenuButton>
99
+ <UsersIcon />
100
+ <span>Members</span>
101
+ </SidebarMenuButton>
102
+ </SidebarMenuItem>
103
+ </SidebarMenu>
104
+ </SidebarGroupContent>
105
+ </SidebarGroup>
106
+ </SidebarContent>
107
+ <UserFooter />
108
+ </Sidebar>
109
+ <SidebarInset>
110
+ <div className="p-4">
111
+ <span className="type-text-sm text-muted-foreground">Sub-menus expand inline under their parent</span>
112
+ </div>
113
+ </SidebarInset>
114
+ </SidebarProvider>
115
+ </StoryFrame>
116
+ <StoryFrame>
117
+ <SidebarProvider defaultOpen>
118
+ <Sidebar collapsible="icon">
119
+ <TeamHeader />
120
+ <SidebarContent>
121
+ <SidebarGroup>
122
+ <SidebarGroupLabel>Workspace</SidebarGroupLabel>
123
+ <SidebarGroupContent>
124
+ <SidebarMenu>
125
+ <SidebarMenuItem>
126
+ <SidebarMenuButton isActive>
127
+ <CodeIcon />
128
+ <span>Projects</span>
129
+ </SidebarMenuButton>
130
+ <SidebarMenuBadge>12</SidebarMenuBadge>
131
+ </SidebarMenuItem>
132
+ <SidebarMenuItem>
133
+ <SidebarMenuButton>
134
+ <UsersIcon />
135
+ <span>Members</span>
136
+ </SidebarMenuButton>
137
+ <SidebarMenuBadge>3</SidebarMenuBadge>
138
+ </SidebarMenuItem>
139
+ <SidebarMenuItem>
140
+ <SidebarMenuButton>
141
+ <KeyIcon />
142
+ <span>API keys</span>
143
+ </SidebarMenuButton>
144
+ </SidebarMenuItem>
145
+ </SidebarMenu>
146
+ </SidebarGroupContent>
147
+ </SidebarGroup>
148
+ <SidebarSeparator />
149
+ <SidebarGroup>
150
+ <SidebarGroupLabel>Account</SidebarGroupLabel>
151
+ <SidebarGroupContent>
152
+ <SidebarMenu>
153
+ <SidebarMenuItem>
154
+ <SidebarMenuButton>
155
+ <SettingsIcon />
156
+ <span>Settings</span>
157
+ </SidebarMenuButton>
158
+ </SidebarMenuItem>
159
+ <SidebarMenuItem>
160
+ <SidebarMenuButton>
161
+ <CreditCardIcon />
162
+ <span>Billing</span>
163
+ </SidebarMenuButton>
164
+ </SidebarMenuItem>
165
+ </SidebarMenu>
166
+ </SidebarGroupContent>
167
+ </SidebarGroup>
168
+ </SidebarContent>
169
+ <UserFooter />
170
+ </Sidebar>
171
+ <SidebarInset>
172
+ <div className="p-4">
173
+ <span className="type-text-sm text-muted-foreground">Groups with labels, badges, and separator</span>
174
+ </div>
175
+ </SidebarInset>
176
+ </SidebarProvider>
177
+ </StoryFrame>
178
+ <StoryFrame height={400}>
179
+ <SidebarProvider defaultOpen>
180
+ <Sidebar collapsible="icon">
181
+ <TeamHeader />
182
+ <SidebarContent>
183
+ <SidebarGroup>
184
+ <SidebarGroupContent>
185
+ <SidebarMenu>
186
+ {["skeleton-1", "skeleton-2", "skeleton-3", "skeleton-4", "skeleton-5"].map((key) => (
187
+ <SidebarMenuItem key={key}>
188
+ <SidebarMenuSkeleton />
189
+ </SidebarMenuItem>
190
+ ))}
191
+ </SidebarMenu>
192
+ </SidebarGroupContent>
193
+ </SidebarGroup>
194
+ </SidebarContent>
195
+ <UserFooter />
196
+ </Sidebar>
197
+ <SidebarInset>
198
+ <div className="p-4">
199
+ <span className="type-text-sm text-muted-foreground">Loading state with skeleton placeholders</span>
200
+ </div>
201
+ </SidebarInset>
202
+ </SidebarProvider>
203
+ </StoryFrame>
204
+ <StoryFrame>
205
+ <SidebarProvider defaultOpen={false}>
206
+ <Sidebar collapsible="offcanvas">
207
+ <SidebarHeader className="px-3 pt-4 pb-0">
208
+ <div className="flex items-center justify-between">
209
+ <div className="flex items-center gap-1.5 rounded-md bg-sidebar-accent px-2 h-8">
210
+ <div className="size-5 rounded-xs bg-inverted shrink-0" />
211
+ <span className="type-text-sm font-medium text-sidebar-primary">Alpic</span>
212
+ <ChevronDownIcon className="size-4 text-sidebar-foreground" />
213
+ </div>
214
+ </div>
215
+ </SidebarHeader>
216
+ <SidebarContent>
217
+ <SidebarGroup>
218
+ <SidebarGroupContent>
219
+ <SidebarMenu>
220
+ <SidebarMenuItem>
221
+ <SidebarMenuButton isActive>
222
+ <CodeIcon />
223
+ <span>Projects</span>
224
+ </SidebarMenuButton>
225
+ </SidebarMenuItem>
226
+ <SidebarMenuItem>
227
+ <SidebarMenuButton>
228
+ <UsersIcon />
229
+ <span>Members</span>
230
+ </SidebarMenuButton>
231
+ </SidebarMenuItem>
232
+ <SidebarMenuItem>
233
+ <SidebarMenuButton>
234
+ <SettingsIcon />
235
+ <span>Settings</span>
236
+ </SidebarMenuButton>
237
+ </SidebarMenuItem>
238
+ </SidebarMenu>
239
+ </SidebarGroupContent>
240
+ </SidebarGroup>
241
+ </SidebarContent>
242
+ <UserFooter />
243
+ </Sidebar>
244
+ <SidebarInset>
245
+ <div className="flex items-center gap-2 p-4">
246
+ <SidebarTrigger />
247
+ <span className="type-text-sm text-muted-foreground">
248
+ Activate the mobile mode in your browser to see the mobile version
249
+ </span>
250
+ </div>
251
+ </SidebarInset>
252
+ </SidebarProvider>
253
+ </StoryFrame>
254
+ </div>
255
+ );
@@ -0,0 +1,47 @@
1
+ import type { Story } from "@ladle/react";
2
+
3
+ import { Skeleton } from "../components/skeleton";
4
+
5
+ export const AllVariants: Story = () => (
6
+ <div className="flex flex-col gap-8">
7
+ {/* Shape variants */}
8
+ <div className="flex flex-col gap-1.5">
9
+ <p className="type-text-xs font-medium text-subtle-foreground">Rectangle (default)</p>
10
+ <div className="flex flex-col gap-2">
11
+ <Skeleton className="h-4 w-48" />
12
+ <Skeleton className="h-4 w-36" />
13
+ <Skeleton className="h-4 w-52" />
14
+ </div>
15
+ </div>
16
+
17
+ <div className="flex flex-col gap-1.5">
18
+ <p className="type-text-xs font-medium text-subtle-foreground">Circle</p>
19
+ <div className="flex items-center gap-3">
20
+ <Skeleton shape="circle" className="size-8" />
21
+ <Skeleton shape="circle" className="size-10" />
22
+ <Skeleton shape="circle" className="size-14" />
23
+ </div>
24
+ </div>
25
+
26
+ {/* Common compositions */}
27
+ <div className="flex flex-col gap-1.5">
28
+ <p className="type-text-xs font-medium text-subtle-foreground">Card placeholder</p>
29
+ <div className="flex flex-col gap-3 rounded-lg border border-border p-4">
30
+ <Skeleton className="h-5 w-40" />
31
+ <Skeleton className="h-4 w-full" />
32
+ <Skeleton className="h-4 w-3/4" />
33
+ </div>
34
+ </div>
35
+
36
+ <div className="flex flex-col gap-1.5">
37
+ <p className="type-text-xs font-medium text-subtle-foreground">List item with avatar</p>
38
+ <div className="flex items-center gap-3">
39
+ <Skeleton shape="circle" className="size-10 shrink-0" />
40
+ <div className="flex flex-1 flex-col gap-2">
41
+ <Skeleton className="h-4 w-32" />
42
+ <Skeleton className="h-3 w-48" />
43
+ </div>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ );
@@ -0,0 +1,91 @@
1
+ import type { Story } from "@ladle/react";
2
+ import { Mail, RotateCcw } from "lucide-react";
3
+ import { ActionToast, Toaster, toast } from "../components/sonner";
4
+
5
+ export const AllVariants: Story = () => (
6
+ <div className="flex min-h-80 flex-col gap-6">
7
+ <div className="flex flex-col gap-1.5">
8
+ <p className="type-text-xs font-medium text-subtle-foreground">Standard toasts — click to trigger</p>
9
+ <div className="flex flex-wrap gap-2">
10
+ <button
11
+ type="button"
12
+ className="h-8 rounded-md border border-border bg-background px-3 type-text-sm font-medium text-foreground [@media(hover:hover)]:hover:bg-background-hover"
13
+ onClick={() => toast.success("Changes saved", { description: "Your project settings have been updated." })}
14
+ >
15
+ Success
16
+ </button>
17
+ <button
18
+ type="button"
19
+ className="h-8 rounded-md border border-border bg-background px-3 type-text-sm font-medium text-foreground [@media(hover:hover)]:hover:bg-background-hover"
20
+ onClick={() => toast.error("Deployment failed", { description: "Build exited with code 1. Check the logs." })}
21
+ >
22
+ Error
23
+ </button>
24
+ <button
25
+ type="button"
26
+ className="h-8 rounded-md border border-border bg-background px-3 type-text-sm font-medium text-foreground [@media(hover:hover)]:hover:bg-background-hover"
27
+ onClick={() =>
28
+ toast.warning("Rate limit approaching", { description: "You've used 90% of your monthly quota." })
29
+ }
30
+ >
31
+ Warning
32
+ </button>
33
+ <button
34
+ type="button"
35
+ className="h-8 rounded-md border border-border bg-background px-3 type-text-sm font-medium text-foreground [@media(hover:hover)]:hover:bg-background-hover"
36
+ onClick={() =>
37
+ toast.info("New version available", { description: "v2.4.0 includes performance improvements." })
38
+ }
39
+ >
40
+ Info
41
+ </button>
42
+ <button
43
+ type="button"
44
+ className="h-8 rounded-md border border-border bg-background px-3 type-text-sm font-medium text-foreground [@media(hover:hover)]:hover:bg-background-hover"
45
+ onClick={() => toast.loading("Deploying...")}
46
+ >
47
+ Loading
48
+ </button>
49
+ <button
50
+ type="button"
51
+ className="h-8 rounded-md border border-border bg-background px-3 type-text-sm font-medium text-foreground [@media(hover:hover)]:hover:bg-background-hover"
52
+ onClick={() => toast("File uploaded", { closeButton: true })}
53
+ >
54
+ With Close
55
+ </button>
56
+ </div>
57
+ </div>
58
+
59
+ <div className="flex flex-col gap-1.5">
60
+ <p className="type-text-xs font-medium text-subtle-foreground">ActionToast</p>
61
+ <div className="flex max-w-sm flex-col gap-4">
62
+ <div className="rounded-lg border border-border bg-background p-4 shadow-md">
63
+ <ActionToast
64
+ toastId="story-1"
65
+ title="Environment variables added"
66
+ description="A new deployment is needed for changes to take effect."
67
+ confirm={{ label: "Redeploy", icon: <RotateCcw />, onClick: () => {} }}
68
+ />
69
+ </div>
70
+ <div className="rounded-lg border border-border bg-background p-4 shadow-md">
71
+ <ActionToast
72
+ toastId="story-2"
73
+ title="Redeploying..."
74
+ description="A new deployment is needed for changes to take effect."
75
+ confirm={{ label: "Redeploy", icon: <RotateCcw />, onClick: () => {}, loading: true }}
76
+ />
77
+ </div>
78
+ <div className="rounded-lg border border-border bg-background p-4 shadow-md">
79
+ <ActionToast
80
+ toastId="story-3"
81
+ title="Stay in the loop!"
82
+ description="We ship new features regularly. Get a quick update when something useful drops."
83
+ confirm={{ label: "Subscribe", icon: <Mail />, onClick: () => {} }}
84
+ />
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ <Toaster />
90
+ </div>
91
+ );
@@ -0,0 +1,66 @@
1
+ import type { Story } from "@ladle/react";
2
+
3
+ import { Spinner, SpinnerBlock } from "../components/spinner";
4
+
5
+ export const AllVariants: Story = () => (
6
+ <div className="flex flex-col gap-6">
7
+ <div className="flex flex-col gap-1.5">
8
+ <p className="type-text-xs font-medium text-subtle-foreground">Sizes</p>
9
+ <div className="flex items-center gap-4">
10
+ <div className="flex flex-col items-center gap-1.5">
11
+ <Spinner size="sm" />
12
+ <p className="type-text-xs text-muted-foreground">sm</p>
13
+ </div>
14
+ <div className="flex flex-col items-center gap-1.5">
15
+ <Spinner size="md" />
16
+ <p className="type-text-xs text-muted-foreground">md</p>
17
+ </div>
18
+ <div className="flex flex-col items-center gap-1.5">
19
+ <Spinner size="lg" />
20
+ <p className="type-text-xs text-muted-foreground">lg</p>
21
+ </div>
22
+ <div className="flex flex-col items-center gap-1.5">
23
+ <Spinner size="xl" />
24
+ <p className="type-text-xs text-muted-foreground">xl</p>
25
+ </div>
26
+ </div>
27
+ </div>
28
+
29
+ <div className="flex flex-col gap-1.5">
30
+ <p className="type-text-xs font-medium text-subtle-foreground">Variants</p>
31
+ <div className="flex items-center gap-4">
32
+ <div className="flex flex-col items-center gap-1.5">
33
+ <Spinner size="lg" variant="primary" />
34
+ <p className="type-text-xs text-muted-foreground">primary</p>
35
+ </div>
36
+ <div className="flex flex-col items-center gap-1.5">
37
+ <Spinner size="lg" variant="secondary" />
38
+ <p className="type-text-xs text-muted-foreground">secondary</p>
39
+ </div>
40
+ </div>
41
+ </div>
42
+
43
+ <div className="flex flex-col gap-1.5">
44
+ <p className="type-text-xs font-medium text-subtle-foreground">SpinnerBlock</p>
45
+ <div className="rounded-md border border-border">
46
+ <SpinnerBlock variant="secondary" size="lg" />
47
+ </div>
48
+ </div>
49
+
50
+ <div className="flex flex-col gap-1.5">
51
+ <p className="type-text-xs font-medium text-subtle-foreground">SpinnerBlock with label</p>
52
+ <div className="rounded-md border border-border">
53
+ <SpinnerBlock variant="secondary" withLabel />
54
+ </div>
55
+ </div>
56
+
57
+ <div className="flex flex-col gap-1.5">
58
+ <p className="type-text-xs font-medium text-subtle-foreground">
59
+ SpinnerBlock fullscreen (uses min-h-screen — shown inline for preview)
60
+ </p>
61
+ <div className="flex h-48 items-center justify-center rounded-md border border-border">
62
+ <Spinner size="xl" />
63
+ </div>
64
+ </div>
65
+ </div>
66
+ );