@ponti-studios/ui 0.1.2
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/README.md +27 -0
- package/dist/index.js +2118 -0
- package/dist/index.js.map +1 -0
- package/package.json +130 -0
- package/src/animations.css +437 -0
- package/src/components/data-display/accordion.stories.tsx +57 -0
- package/src/components/data-display/accordion.tsx +65 -0
- package/src/components/data-display/filter-chip.tsx +41 -0
- package/src/components/data-display/index.ts +13 -0
- package/src/components/data-display/table.stories.tsx +75 -0
- package/src/components/data-display/table.tsx +84 -0
- package/src/components/feedback/alert.stories.tsx +51 -0
- package/src/components/feedback/alert.tsx +60 -0
- package/src/components/feedback/empty-state.tsx +66 -0
- package/src/components/feedback/index.ts +6 -0
- package/src/components/feedback/progress.stories.tsx +37 -0
- package/src/components/feedback/progress.tsx +30 -0
- package/src/components/feedback/spinner.stories.tsx +52 -0
- package/src/components/feedback/spinner.tsx +48 -0
- package/src/components/forms/calendar.stories.tsx +30 -0
- package/src/components/forms/calendar.tsx +67 -0
- package/src/components/forms/date-picker.stories.tsx +48 -0
- package/src/components/forms/date-picker.tsx +60 -0
- package/src/components/forms/field.stories.tsx +62 -0
- package/src/components/forms/field.tsx +65 -0
- package/src/components/forms/field.types.ts +7 -0
- package/src/components/forms/index.ts +24 -0
- package/src/components/forms/input.stories.tsx +47 -0
- package/src/components/forms/input.tsx +20 -0
- package/src/components/forms/radio-group.stories.tsx +48 -0
- package/src/components/forms/radio-group.tsx +38 -0
- package/src/components/forms/select.stories.tsx +88 -0
- package/src/components/forms/select.tsx +147 -0
- package/src/components/forms/slider.stories.tsx +67 -0
- package/src/components/forms/slider.tsx +25 -0
- package/src/components/forms/stepper.stories.tsx +111 -0
- package/src/components/forms/stepper.tsx +66 -0
- package/src/components/forms/switch.stories.tsx +144 -0
- package/src/components/forms/switch.tsx +36 -0
- package/src/components/forms/text-field.stories.tsx +87 -0
- package/src/components/forms/text-field.tsx +40 -0
- package/src/components/forms/text-field.types.ts +9 -0
- package/src/components/forms/textarea.stories.tsx +150 -0
- package/src/components/forms/textarea.tsx +18 -0
- package/src/components/layout/index.ts +2 -0
- package/src/components/layout/scroll-area.stories.tsx +83 -0
- package/src/components/layout/scroll-area.tsx +40 -0
- package/src/components/navigation/app-navigation.stories.tsx +81 -0
- package/src/components/navigation/app-navigation.tsx +155 -0
- package/src/components/navigation/index.ts +3 -0
- package/src/components/navigation/tabs.stories.tsx +69 -0
- package/src/components/navigation/tabs.tsx +49 -0
- package/src/components/overlays/alert-dialog.stories.tsx +45 -0
- package/src/components/overlays/alert-dialog.tsx +119 -0
- package/src/components/overlays/command.stories.tsx +65 -0
- package/src/components/overlays/command.tsx +130 -0
- package/src/components/overlays/dialog.stories.tsx +111 -0
- package/src/components/overlays/dialog.tsx +162 -0
- package/src/components/overlays/dropdown-menu.stories.tsx +79 -0
- package/src/components/overlays/dropdown-menu.tsx +214 -0
- package/src/components/overlays/index.ts +65 -0
- package/src/components/overlays/popover.stories.tsx +39 -0
- package/src/components/overlays/popover.tsx +40 -0
- package/src/components/overlays/sheet.stories.tsx +68 -0
- package/src/components/overlays/sheet.tsx +98 -0
- package/src/components/primitives/avatar.stories.tsx +71 -0
- package/src/components/primitives/avatar.tsx +132 -0
- package/src/components/primitives/badge.stories.tsx +33 -0
- package/src/components/primitives/badge.tsx +44 -0
- package/src/components/primitives/button.stories.tsx +113 -0
- package/src/components/primitives/button.tsx +95 -0
- package/src/components/primitives/button.types.ts +10 -0
- package/src/components/primitives/card.stories.tsx +59 -0
- package/src/components/primitives/card.tsx +69 -0
- package/src/components/primitives/index.ts +13 -0
- package/src/components/primitives/label.stories.tsx +47 -0
- package/src/components/primitives/label.tsx +21 -0
- package/src/constants/chart-colors.ts +39 -0
- package/src/env.d.ts +9 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/sort.types.ts +12 -0
- package/src/hooks/use-api-client.ts +122 -0
- package/src/hooks/use-debounced-value.ts +12 -0
- package/src/hooks/use-filter-state.ts +68 -0
- package/src/hooks/use-media-query.ts +65 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/index.ts +25 -0
- package/src/lib/auth.ts +5 -0
- package/src/lib/clipboard.ts +8 -0
- package/src/lib/create-memory-storage.ts +24 -0
- package/src/lib/index.ts +4 -0
- package/src/lib/utils.ts +6 -0
- package/src/storybook/controls.ts +117 -0
- package/src/storybook/options.ts +52 -0
- package/src/styles.css +1052 -0
- package/src/tokens/color-systems.stories.tsx +133 -0
- package/src/tokens/colors.ts +156 -0
- package/src/tokens/foundations.stories.tsx +151 -0
- package/src/tokens/index.ts +16 -0
- package/src/tokens/layout.stories.tsx +118 -0
- package/src/tokens/motion.ts +51 -0
- package/src/tokens/radii.ts +10 -0
- package/src/tokens/shadows.ts +34 -0
- package/src/tokens/spacing.ts +30 -0
- package/src/tokens/typography.ts +42 -0
- package/src/translations/en.ts +34 -0
- package/src/translations/index.ts +32 -0
- package/src/types/upload.ts +42 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
2
|
+
import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
|
|
5
|
+
import { cn } from "../../lib/utils";
|
|
6
|
+
|
|
7
|
+
function DropdownMenu(props: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
|
|
8
|
+
return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function DropdownMenuPortal(props: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
|
|
12
|
+
return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function DropdownMenuTrigger(props: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
|
16
|
+
return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function DropdownMenuContent({
|
|
20
|
+
className,
|
|
21
|
+
sideOffset = 4,
|
|
22
|
+
...props
|
|
23
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
|
24
|
+
return (
|
|
25
|
+
<DropdownMenuPrimitive.Portal>
|
|
26
|
+
<DropdownMenuPrimitive.Content
|
|
27
|
+
data-slot="dropdown-menu-content"
|
|
28
|
+
sideOffset={sideOffset}
|
|
29
|
+
className={cn(
|
|
30
|
+
"bg-raised text-primary data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1",
|
|
31
|
+
className,
|
|
32
|
+
)}
|
|
33
|
+
{...props}
|
|
34
|
+
/>
|
|
35
|
+
</DropdownMenuPrimitive.Portal>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function DropdownMenuGroup(props: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
|
|
40
|
+
return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function DropdownMenuLabel({
|
|
44
|
+
className,
|
|
45
|
+
inset,
|
|
46
|
+
...props
|
|
47
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }) {
|
|
48
|
+
return (
|
|
49
|
+
<DropdownMenuPrimitive.Label
|
|
50
|
+
data-slot="dropdown-menu-label"
|
|
51
|
+
data-inset={inset}
|
|
52
|
+
className={cn("px-2 py-1.5 text-sm font-medium data-[inset]:pl-8", className)}
|
|
53
|
+
{...props}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function DropdownMenuItem({
|
|
59
|
+
className,
|
|
60
|
+
inset,
|
|
61
|
+
variant = "default",
|
|
62
|
+
...props
|
|
63
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
|
64
|
+
inset?: boolean;
|
|
65
|
+
variant?: "default" | "destructive";
|
|
66
|
+
}) {
|
|
67
|
+
return (
|
|
68
|
+
<DropdownMenuPrimitive.Item
|
|
69
|
+
data-slot="dropdown-menu-item"
|
|
70
|
+
data-inset={inset}
|
|
71
|
+
data-variant={variant}
|
|
72
|
+
className={cn(
|
|
73
|
+
"focus:bg-accent focus:text-on-accent data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
74
|
+
className,
|
|
75
|
+
)}
|
|
76
|
+
{...props}
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function DropdownMenuCheckboxItem({
|
|
82
|
+
className,
|
|
83
|
+
children,
|
|
84
|
+
checked,
|
|
85
|
+
...props
|
|
86
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
|
|
87
|
+
return (
|
|
88
|
+
<DropdownMenuPrimitive.CheckboxItem
|
|
89
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
90
|
+
className={cn(
|
|
91
|
+
"focus:bg-accent focus:text-on-accent relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
92
|
+
className,
|
|
93
|
+
)}
|
|
94
|
+
checked={checked}
|
|
95
|
+
{...props}
|
|
96
|
+
>
|
|
97
|
+
<span className="absolute left-2 flex size-3.5 items-center justify-center">
|
|
98
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
99
|
+
<CheckIcon className="size-4" />
|
|
100
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
101
|
+
</span>
|
|
102
|
+
{children}
|
|
103
|
+
</DropdownMenuPrimitive.CheckboxItem>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function DropdownMenuRadioGroup(
|
|
108
|
+
props: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>,
|
|
109
|
+
) {
|
|
110
|
+
return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function DropdownMenuRadioItem({
|
|
114
|
+
className,
|
|
115
|
+
children,
|
|
116
|
+
...props
|
|
117
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
|
|
118
|
+
return (
|
|
119
|
+
<DropdownMenuPrimitive.RadioItem
|
|
120
|
+
data-slot="dropdown-menu-radio-item"
|
|
121
|
+
className={cn(
|
|
122
|
+
"focus:bg-accent focus:text-on-accent relative flex cursor-default items-center rounded-sm py-1.5 pr-2 pl-8 text-sm outline-none select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
123
|
+
className,
|
|
124
|
+
)}
|
|
125
|
+
{...props}
|
|
126
|
+
>
|
|
127
|
+
<span className="absolute left-2 flex size-3.5 items-center justify-center">
|
|
128
|
+
<DropdownMenuPrimitive.ItemIndicator>
|
|
129
|
+
<CircleIcon className="size-2 fill-current" />
|
|
130
|
+
</DropdownMenuPrimitive.ItemIndicator>
|
|
131
|
+
</span>
|
|
132
|
+
{children}
|
|
133
|
+
</DropdownMenuPrimitive.RadioItem>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function DropdownMenuSeparator({
|
|
138
|
+
className,
|
|
139
|
+
...props
|
|
140
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
|
|
141
|
+
return (
|
|
142
|
+
<DropdownMenuPrimitive.Separator
|
|
143
|
+
data-slot="dropdown-menu-separator"
|
|
144
|
+
className={cn("bg-border -mx-1 my-1 h-px", className)}
|
|
145
|
+
{...props}
|
|
146
|
+
/>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
|
|
151
|
+
return (
|
|
152
|
+
<span className={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...props} />
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function DropdownMenuSub(props: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
|
|
157
|
+
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function DropdownMenuSubTrigger({
|
|
161
|
+
className,
|
|
162
|
+
inset,
|
|
163
|
+
children,
|
|
164
|
+
...props
|
|
165
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }) {
|
|
166
|
+
return (
|
|
167
|
+
<DropdownMenuPrimitive.SubTrigger
|
|
168
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
169
|
+
data-inset={inset}
|
|
170
|
+
className={cn(
|
|
171
|
+
"focus:bg-accent focus:text-on-accent data-[state=open]:bg-accent data-[state=open]:text-on-accent flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none data-[inset]:pl-8",
|
|
172
|
+
className,
|
|
173
|
+
)}
|
|
174
|
+
{...props}
|
|
175
|
+
>
|
|
176
|
+
{children}
|
|
177
|
+
<ChevronRightIcon className="ml-auto size-4" />
|
|
178
|
+
</DropdownMenuPrimitive.SubTrigger>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function DropdownMenuSubContent({
|
|
183
|
+
className,
|
|
184
|
+
...props
|
|
185
|
+
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
|
186
|
+
return (
|
|
187
|
+
<DropdownMenuPrimitive.SubContent
|
|
188
|
+
data-slot="dropdown-menu-sub-content"
|
|
189
|
+
className={cn(
|
|
190
|
+
"bg-raised text-primary data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg",
|
|
191
|
+
className,
|
|
192
|
+
)}
|
|
193
|
+
{...props}
|
|
194
|
+
/>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export {
|
|
199
|
+
DropdownMenu,
|
|
200
|
+
DropdownMenuCheckboxItem,
|
|
201
|
+
DropdownMenuContent,
|
|
202
|
+
DropdownMenuGroup,
|
|
203
|
+
DropdownMenuItem,
|
|
204
|
+
DropdownMenuLabel,
|
|
205
|
+
DropdownMenuPortal,
|
|
206
|
+
DropdownMenuRadioGroup,
|
|
207
|
+
DropdownMenuRadioItem,
|
|
208
|
+
DropdownMenuSeparator,
|
|
209
|
+
DropdownMenuShortcut,
|
|
210
|
+
DropdownMenuSub,
|
|
211
|
+
DropdownMenuSubContent,
|
|
212
|
+
DropdownMenuSubTrigger,
|
|
213
|
+
DropdownMenuTrigger,
|
|
214
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export {
|
|
2
|
+
AlertDialog,
|
|
3
|
+
AlertDialogAction,
|
|
4
|
+
AlertDialogCancel,
|
|
5
|
+
AlertDialogContent,
|
|
6
|
+
AlertDialogDescription,
|
|
7
|
+
AlertDialogFooter,
|
|
8
|
+
AlertDialogHeader,
|
|
9
|
+
AlertDialogTitle,
|
|
10
|
+
AlertDialogTrigger,
|
|
11
|
+
} from "./alert-dialog";
|
|
12
|
+
export {
|
|
13
|
+
Command,
|
|
14
|
+
CommandDialog,
|
|
15
|
+
CommandEmpty,
|
|
16
|
+
CommandGroup,
|
|
17
|
+
CommandInput,
|
|
18
|
+
CommandItem,
|
|
19
|
+
CommandList,
|
|
20
|
+
CommandListLoading,
|
|
21
|
+
CommandSeparator,
|
|
22
|
+
CommandShortcut,
|
|
23
|
+
} from "./command";
|
|
24
|
+
export {
|
|
25
|
+
Dialog,
|
|
26
|
+
DialogClose,
|
|
27
|
+
DialogContent,
|
|
28
|
+
DialogDescription,
|
|
29
|
+
DialogFooter,
|
|
30
|
+
DialogHeader,
|
|
31
|
+
DialogOverlay,
|
|
32
|
+
DialogPortal,
|
|
33
|
+
DialogTitle,
|
|
34
|
+
DialogTrigger,
|
|
35
|
+
} from "./dialog";
|
|
36
|
+
export {
|
|
37
|
+
DropdownMenu,
|
|
38
|
+
DropdownMenuCheckboxItem,
|
|
39
|
+
DropdownMenuContent,
|
|
40
|
+
DropdownMenuGroup,
|
|
41
|
+
DropdownMenuItem,
|
|
42
|
+
DropdownMenuLabel,
|
|
43
|
+
DropdownMenuPortal,
|
|
44
|
+
DropdownMenuRadioGroup,
|
|
45
|
+
DropdownMenuRadioItem,
|
|
46
|
+
DropdownMenuSeparator,
|
|
47
|
+
DropdownMenuShortcut,
|
|
48
|
+
DropdownMenuSub,
|
|
49
|
+
DropdownMenuSubContent,
|
|
50
|
+
DropdownMenuSubTrigger,
|
|
51
|
+
DropdownMenuTrigger,
|
|
52
|
+
} from "./dropdown-menu";
|
|
53
|
+
export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "./popover";
|
|
54
|
+
export {
|
|
55
|
+
Sheet,
|
|
56
|
+
SheetClose,
|
|
57
|
+
SheetContent,
|
|
58
|
+
SheetDescription,
|
|
59
|
+
SheetFooter,
|
|
60
|
+
SheetHeader,
|
|
61
|
+
SheetOverlay,
|
|
62
|
+
SheetPortal,
|
|
63
|
+
SheetTitle,
|
|
64
|
+
SheetTrigger,
|
|
65
|
+
} from "./sheet";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
|
|
3
|
+
import { Button } from "../primitives/button";
|
|
4
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover";
|
|
5
|
+
|
|
6
|
+
const meta = {
|
|
7
|
+
title: "Overlays/Popover",
|
|
8
|
+
component: Popover,
|
|
9
|
+
tags: ["autodocs"],
|
|
10
|
+
} satisfies Meta<typeof Popover>;
|
|
11
|
+
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof meta>;
|
|
14
|
+
|
|
15
|
+
export const Default: Story = {
|
|
16
|
+
render: () => (
|
|
17
|
+
<Popover>
|
|
18
|
+
<PopoverTrigger asChild>
|
|
19
|
+
<Button variant="outline">Open Popover</Button>
|
|
20
|
+
</PopoverTrigger>
|
|
21
|
+
<PopoverContent>
|
|
22
|
+
<div className="grid gap-1.5">
|
|
23
|
+
<h4 className="text-primary leading-none font-medium">Dimensions</h4>
|
|
24
|
+
<p className="text-secondary text-sm">Set the dimensions for the layer.</p>
|
|
25
|
+
</div>
|
|
26
|
+
<div className="grid gap-4 pt-4">
|
|
27
|
+
<div className="grid grid-cols-3 items-center gap-4">
|
|
28
|
+
<label className="text-sm">Width</label>
|
|
29
|
+
<input className="col-span-2 h-8 rounded border px-2 text-sm" defaultValue="100%" />
|
|
30
|
+
</div>
|
|
31
|
+
<div className="grid grid-cols-3 items-center gap-4">
|
|
32
|
+
<label className="text-sm">Height</label>
|
|
33
|
+
<input className="col-span-2 h-8 rounded border px-2 text-sm" defaultValue="25px" />
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</PopoverContent>
|
|
37
|
+
</Popover>
|
|
38
|
+
),
|
|
39
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
|
|
4
|
+
import { cn } from "../../lib/utils";
|
|
5
|
+
|
|
6
|
+
function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
|
7
|
+
return <PopoverPrimitive.Root data-slot="popover" {...props} />;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
|
11
|
+
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function PopoverContent({
|
|
15
|
+
className,
|
|
16
|
+
align = "center",
|
|
17
|
+
sideOffset = 4,
|
|
18
|
+
...props
|
|
19
|
+
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
|
20
|
+
return (
|
|
21
|
+
<PopoverPrimitive.Portal>
|
|
22
|
+
<PopoverPrimitive.Content
|
|
23
|
+
data-slot="popover-content"
|
|
24
|
+
align={align}
|
|
25
|
+
sideOffset={sideOffset}
|
|
26
|
+
className={cn(
|
|
27
|
+
"bg-raised text-primary data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 outline-hidden",
|
|
28
|
+
className,
|
|
29
|
+
)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
</PopoverPrimitive.Portal>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
|
37
|
+
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
|
|
4
|
+
import { Button } from "../primitives/button";
|
|
5
|
+
import {
|
|
6
|
+
Sheet,
|
|
7
|
+
SheetClose,
|
|
8
|
+
SheetContent,
|
|
9
|
+
SheetDescription,
|
|
10
|
+
SheetFooter,
|
|
11
|
+
SheetHeader,
|
|
12
|
+
SheetTitle,
|
|
13
|
+
SheetTrigger,
|
|
14
|
+
} from "./sheet";
|
|
15
|
+
|
|
16
|
+
const meta: Meta<typeof Sheet> = {
|
|
17
|
+
title: "Overlays/Sheet",
|
|
18
|
+
component: Sheet,
|
|
19
|
+
tags: ["autodocs"],
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export default meta;
|
|
23
|
+
type Story = StoryObj<typeof meta>;
|
|
24
|
+
|
|
25
|
+
const SheetDemo = () => (
|
|
26
|
+
<Sheet>
|
|
27
|
+
<SheetTrigger asChild>
|
|
28
|
+
<Button variant="outline">Open sheet</Button>
|
|
29
|
+
</SheetTrigger>
|
|
30
|
+
<SheetContent>
|
|
31
|
+
<SheetHeader>
|
|
32
|
+
<SheetTitle>Edit profile</SheetTitle>
|
|
33
|
+
<SheetDescription>
|
|
34
|
+
Make changes to your profile here. Click save when you're done.
|
|
35
|
+
</SheetDescription>
|
|
36
|
+
</SheetHeader>
|
|
37
|
+
<div className="flex flex-col gap-4 py-6">
|
|
38
|
+
<div className="flex flex-col gap-2">
|
|
39
|
+
<span className="text-sm font-medium">Name</span>
|
|
40
|
+
<input
|
|
41
|
+
className="border-default placeholder:text-secondary focus-visible:ring-focus flex h-9 w-full rounded-md border bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:ring-1 focus-visible:outline-none"
|
|
42
|
+
placeholder="Jane Doe"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
<div className="flex flex-col gap-2">
|
|
46
|
+
<span className="text-sm font-medium">Email</span>
|
|
47
|
+
<input
|
|
48
|
+
className="border-default placeholder:text-secondary focus-visible:ring-focus flex h-9 w-full rounded-md border bg-transparent px-3 py-1 text-sm shadow-sm transition-colors focus-visible:ring-1 focus-visible:outline-none"
|
|
49
|
+
placeholder="jane@example.com"
|
|
50
|
+
type="email"
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
<SheetFooter>
|
|
55
|
+
<SheetClose asChild>
|
|
56
|
+
<Button variant="outline">Cancel</Button>
|
|
57
|
+
</SheetClose>
|
|
58
|
+
<SheetClose asChild>
|
|
59
|
+
<Button>Save changes</Button>
|
|
60
|
+
</SheetClose>
|
|
61
|
+
</SheetFooter>
|
|
62
|
+
</SheetContent>
|
|
63
|
+
</Sheet>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
export const Default: Story = {
|
|
67
|
+
render: () => <SheetDemo />,
|
|
68
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as SheetPrimitive from "@radix-ui/react-dialog";
|
|
4
|
+
import { X } from "lucide-react";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
|
|
7
|
+
import { cn } from "../../lib/utils";
|
|
8
|
+
|
|
9
|
+
const Sheet = SheetPrimitive.Root;
|
|
10
|
+
|
|
11
|
+
const SheetTrigger = SheetPrimitive.Trigger;
|
|
12
|
+
|
|
13
|
+
const SheetClose = SheetPrimitive.Close;
|
|
14
|
+
|
|
15
|
+
const SheetPortal = SheetPrimitive.Portal;
|
|
16
|
+
|
|
17
|
+
const SheetOverlay = React.forwardRef<
|
|
18
|
+
React.ComponentRef<typeof SheetPrimitive.Overlay>,
|
|
19
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
|
20
|
+
>(({ className, ...props }, ref) => (
|
|
21
|
+
<SheetPrimitive.Overlay
|
|
22
|
+
className={cn(
|
|
23
|
+
"overlay-backdrop data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 transition-opacity",
|
|
24
|
+
className,
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
ref={ref}
|
|
28
|
+
/>
|
|
29
|
+
));
|
|
30
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
|
31
|
+
|
|
32
|
+
const sheetClassName =
|
|
33
|
+
"sheet-responsive sheet-edge-responsive bg-canvas text-primary border-subtle fixed inset-x-0 bottom-0 z-50 flex max-h-[90dvh] min-h-[30dvh] flex-col gap-6 rounded-t-xl border border-r-0 border-b-0 border-l-0 p-4 pb-[max(1rem,env(safe-area-inset-bottom))] md:inset-y-0 md:right-0 md:bottom-auto md:left-auto md:h-full md:w-3/4 md:max-w-sm md:min-h-0 md:rounded-t-none md:rounded-l-xl md:border-t-0 md:border-r-0 md:border-b-0 md:border-l md:p-6 md:pb-6";
|
|
34
|
+
|
|
35
|
+
interface SheetContentProps extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> {}
|
|
36
|
+
|
|
37
|
+
const SheetContent = React.forwardRef<
|
|
38
|
+
React.ComponentRef<typeof SheetPrimitive.Content>,
|
|
39
|
+
SheetContentProps
|
|
40
|
+
>(({ className, children, ...props }, ref) => (
|
|
41
|
+
<SheetPortal>
|
|
42
|
+
<SheetOverlay />
|
|
43
|
+
<SheetPrimitive.Content ref={ref} className={cn(sheetClassName, className)} {...props}>
|
|
44
|
+
<SheetPrimitive.Close className="sheet-glass-control text-secondary hover:bg-inset/70 hover:text-primary focus-visible:outline-ring absolute top-3 right-3 inline-flex size-11 items-center justify-center rounded-md border border-transparent transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 disabled:pointer-events-none md:top-4 md:right-4">
|
|
45
|
+
<X className="size-4.5" />
|
|
46
|
+
<span className="sr-only">Close</span>
|
|
47
|
+
</SheetPrimitive.Close>
|
|
48
|
+
{children}
|
|
49
|
+
</SheetPrimitive.Content>
|
|
50
|
+
</SheetPortal>
|
|
51
|
+
));
|
|
52
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
|
53
|
+
|
|
54
|
+
const SheetHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
55
|
+
<div className={cn("flex flex-col gap-2 text-left", className)} {...props} />
|
|
56
|
+
);
|
|
57
|
+
SheetHeader.displayName = "SheetHeader";
|
|
58
|
+
|
|
59
|
+
const SheetFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
60
|
+
<div
|
|
61
|
+
className={cn("mt-auto flex flex-col-reverse gap-3 sm:flex-row sm:justify-end", className)}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
SheetFooter.displayName = "SheetFooter";
|
|
66
|
+
|
|
67
|
+
const SheetTitle = React.forwardRef<
|
|
68
|
+
React.ComponentRef<typeof SheetPrimitive.Title>,
|
|
69
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
|
70
|
+
>(({ className, ...props }, ref) => (
|
|
71
|
+
<SheetPrimitive.Title ref={ref} className={cn("heading-2 text-primary", className)} {...props} />
|
|
72
|
+
));
|
|
73
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName;
|
|
74
|
+
|
|
75
|
+
const SheetDescription = React.forwardRef<
|
|
76
|
+
React.ComponentRef<typeof SheetPrimitive.Description>,
|
|
77
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
|
78
|
+
>(({ className, ...props }, ref) => (
|
|
79
|
+
<SheetPrimitive.Description
|
|
80
|
+
ref={ref}
|
|
81
|
+
className={cn("body-2 text-secondary max-w-prose", className)}
|
|
82
|
+
{...props}
|
|
83
|
+
/>
|
|
84
|
+
));
|
|
85
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName;
|
|
86
|
+
|
|
87
|
+
export {
|
|
88
|
+
Sheet,
|
|
89
|
+
SheetClose,
|
|
90
|
+
SheetContent,
|
|
91
|
+
SheetDescription,
|
|
92
|
+
SheetFooter,
|
|
93
|
+
SheetHeader,
|
|
94
|
+
SheetOverlay,
|
|
95
|
+
SheetPortal,
|
|
96
|
+
SheetTitle,
|
|
97
|
+
SheetTrigger,
|
|
98
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
|
|
3
|
+
import { Avatar, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from "./avatar";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Primitives/Avatar",
|
|
7
|
+
component: Avatar,
|
|
8
|
+
tags: ["autodocs"],
|
|
9
|
+
} satisfies Meta<typeof Avatar>;
|
|
10
|
+
|
|
11
|
+
export default meta;
|
|
12
|
+
type Story = StoryObj<typeof meta>;
|
|
13
|
+
|
|
14
|
+
export const WithImage: Story = {
|
|
15
|
+
render: () => (
|
|
16
|
+
<Avatar>
|
|
17
|
+
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
|
|
18
|
+
<AvatarFallback>CN</AvatarFallback>
|
|
19
|
+
</Avatar>
|
|
20
|
+
),
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const WithFallback: Story = {
|
|
24
|
+
render: () => (
|
|
25
|
+
<Avatar>
|
|
26
|
+
<AvatarImage src="/broken-image.jpg" alt="Broken" />
|
|
27
|
+
<AvatarFallback>AB</AvatarFallback>
|
|
28
|
+
</Avatar>
|
|
29
|
+
),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const Sizes: Story = {
|
|
33
|
+
render: () => (
|
|
34
|
+
<div className="flex items-center gap-4">
|
|
35
|
+
<Avatar size="sm">
|
|
36
|
+
<AvatarFallback>SM</AvatarFallback>
|
|
37
|
+
</Avatar>
|
|
38
|
+
<Avatar size="default">
|
|
39
|
+
<AvatarFallback>MD</AvatarFallback>
|
|
40
|
+
</Avatar>
|
|
41
|
+
<Avatar size="lg">
|
|
42
|
+
<AvatarFallback>LG</AvatarFallback>
|
|
43
|
+
</Avatar>
|
|
44
|
+
</div>
|
|
45
|
+
),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const WithBadge: Story = {
|
|
49
|
+
render: () => (
|
|
50
|
+
<Avatar statusBadge>
|
|
51
|
+
<AvatarFallback>JD</AvatarFallback>
|
|
52
|
+
</Avatar>
|
|
53
|
+
),
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export const Group: Story = {
|
|
57
|
+
render: () => (
|
|
58
|
+
<AvatarGroup>
|
|
59
|
+
<Avatar>
|
|
60
|
+
<AvatarFallback>AB</AvatarFallback>
|
|
61
|
+
</Avatar>
|
|
62
|
+
<Avatar>
|
|
63
|
+
<AvatarFallback>CD</AvatarFallback>
|
|
64
|
+
</Avatar>
|
|
65
|
+
<Avatar>
|
|
66
|
+
<AvatarFallback>EF</AvatarFallback>
|
|
67
|
+
</Avatar>
|
|
68
|
+
<AvatarGroupCount>+3</AvatarGroupCount>
|
|
69
|
+
</AvatarGroup>
|
|
70
|
+
),
|
|
71
|
+
};
|