@inspirare/design-system 0.0.9 → 0.0.11

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 (54) hide show
  1. package/dist/index.css +1 -1
  2. package/package.json +5 -3
  3. package/src/App.css +184 -0
  4. package/src/App.tsx +222 -0
  5. package/src/assets/hero.png +0 -0
  6. package/src/assets/react.svg +1 -0
  7. package/src/assets/vite.svg +1 -0
  8. package/src/components/ui/accessibility-improvements.tsx +117 -0
  9. package/src/components/ui/accordion.tsx +66 -0
  10. package/src/components/ui/alert-dialog.tsx +151 -0
  11. package/src/components/ui/avatar.tsx +53 -0
  12. package/src/components/ui/badge.tsx +46 -0
  13. package/src/components/ui/button.tsx +59 -0
  14. package/src/components/ui/calendar.tsx +220 -0
  15. package/src/components/ui/card.tsx +92 -0
  16. package/src/components/ui/checkbox.tsx +32 -0
  17. package/src/components/ui/collapsible.tsx +36 -0
  18. package/src/components/ui/color-picker.tsx +183 -0
  19. package/src/components/ui/command.tsx +184 -0
  20. package/src/components/ui/dialog.tsx +157 -0
  21. package/src/components/ui/drawer.tsx +149 -0
  22. package/src/components/ui/dropdown-menu.tsx +259 -0
  23. package/src/components/ui/form.tsx +168 -0
  24. package/src/components/ui/hover-card.tsx +49 -0
  25. package/src/components/ui/input.tsx +21 -0
  26. package/src/components/ui/label.tsx +24 -0
  27. package/src/components/ui/popover.tsx +55 -0
  28. package/src/components/ui/progress.tsx +31 -0
  29. package/src/components/ui/radio-group.tsx +43 -0
  30. package/src/components/ui/scroll-area.tsx +32 -0
  31. package/src/components/ui/select.tsx +185 -0
  32. package/src/components/ui/separator.tsx +28 -0
  33. package/src/components/ui/sheet.tsx +153 -0
  34. package/src/components/ui/skeleton.tsx +121 -0
  35. package/src/components/ui/slider.tsx +63 -0
  36. package/src/components/ui/sonner.tsx +25 -0
  37. package/src/components/ui/switch.tsx +35 -0
  38. package/src/components/ui/table.tsx +116 -0
  39. package/src/components/ui/tabs.tsx +66 -0
  40. package/src/components/ui/textarea.tsx +18 -0
  41. package/src/components/ui/theme-toggle.tsx +106 -0
  42. package/src/components/ui/toggle-group.tsx +73 -0
  43. package/src/components/ui/toggle.tsx +47 -0
  44. package/src/components/ui/tooltip.tsx +68 -0
  45. package/src/demo/ButtonsDemo.tsx +82 -0
  46. package/src/demo/CalendarDemo.tsx +25 -0
  47. package/src/demo/FeedbackDemo.tsx +113 -0
  48. package/src/demo/FormsDemo.tsx +100 -0
  49. package/src/demo/NavigationDemo.tsx +141 -0
  50. package/src/demo/OverlaysDemo.tsx +187 -0
  51. package/src/index.css +1434 -0
  52. package/src/index.ts +41 -0
  53. package/src/lib/utils.ts +6 -0
  54. package/src/main.tsx +13 -0
@@ -0,0 +1,183 @@
1
+ "use client";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import { Input } from "@/components/ui/input";
5
+ import {
6
+ Popover,
7
+ PopoverContent,
8
+ PopoverTrigger,
9
+ } from "@/components/ui/popover";
10
+ import { cn } from "@/lib/utils";
11
+ import { useState } from "react";
12
+ import { HexColorPicker } from "react-colorful";
13
+
14
+ interface ColorPickerProps {
15
+ value: string;
16
+ onChange: (color: string) => void;
17
+ className?: string;
18
+ disabled?: boolean;
19
+ }
20
+
21
+ export function ColorPicker({
22
+ value,
23
+ onChange,
24
+ className,
25
+ disabled = false,
26
+ }: ColorPickerProps) {
27
+ const [color, setColor] = useState(value);
28
+ const [isOpen, setIsOpen] = useState(false);
29
+
30
+ const handleColorChange = (newColor: string) => {
31
+ setColor(newColor);
32
+ onChange(newColor);
33
+ };
34
+
35
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
36
+ const newColor = e.target.value;
37
+ if (/^#[0-9A-F]{6}$/i.test(newColor) || newColor === "") {
38
+ setColor(newColor);
39
+ if (newColor !== "") {
40
+ onChange(newColor);
41
+ }
42
+ }
43
+ };
44
+
45
+ // Paleta de cores premium alinhada com a marca
46
+ const presetColors = [
47
+ // Cores da marca Inspirare
48
+ "#9192FA", // Inspirare Purple
49
+ "#60A5FA", // Inspirare Blue
50
+ "#e0e7ff", // Inspirare Purple Light
51
+ "#dbeafe", // Inspirare Blue Light
52
+
53
+ // Cores neutras sofisticadas
54
+ "#1f2937", // Gray 800
55
+ "#374151", // Gray 700
56
+ "#6b7280", // Gray 500
57
+ "#9ca3af", // Gray 400
58
+ "#d1d5db", // Gray 300
59
+ "#f3f4f6", // Gray 100
60
+ "#ffffff", // White
61
+ "#000000", // Black
62
+
63
+ // Cores semânticas modernas
64
+ "#dc2626", // Red 600
65
+ "#ea580c", // Orange 600
66
+ "#d97706", // Amber 600
67
+ "#16a34a", // Green 600
68
+ "#2563eb", // Blue 600
69
+ "#4f46e5", // Indigo 600
70
+ "#9333ea", // Purple 600
71
+ "#e11d48", // Rose 600
72
+
73
+ // Tons pastéis para destaque
74
+ "#fef3c7", // Amber 100
75
+ "#d1fae5", // Green 100
76
+ "#fce7f3", // Pink 100
77
+ "#e9d5ff", // Purple 100
78
+ ];
79
+
80
+ return (
81
+ <Popover open={isOpen} onOpenChange={setIsOpen}>
82
+ <PopoverTrigger asChild>
83
+ <Button
84
+ variant="outline"
85
+ className={cn(
86
+ "w-[200px] justify-start text-left font-normal border-border hover:border-primary/50 transition-colors gap-2 px-3",
87
+ !color && "text-muted-foreground",
88
+ className
89
+ )}
90
+ disabled={disabled}
91
+ >
92
+ <div
93
+ className="w-4 h-4 rounded border border-border shadow-sm shrink-0"
94
+ style={{ backgroundColor: color || "#ffffff" }}
95
+ />
96
+ <span className="truncate flex-1">
97
+ {color ? (
98
+ <span className="font-mono text-xs">{color.toUpperCase()}</span>
99
+ ) : (
100
+ "Selecionar cor"
101
+ )}
102
+ </span>
103
+ </Button>
104
+ </PopoverTrigger>
105
+ <PopoverContent className="w-80 p-0">
106
+ <div className="p-4 space-y-4">
107
+ {/* Header */}
108
+ <div className="text-sm font-medium text-foreground pb-2 border-b border-border">
109
+ Seletor de Cor
110
+ </div>
111
+
112
+ {/* Color Picker */}
113
+ <div className="space-y-3">
114
+ <HexColorPicker
115
+ color={color || "#ffffff"}
116
+ onChange={handleColorChange}
117
+ className="w-full !h-32"
118
+ />
119
+
120
+ {/* Input para código hex */}
121
+ <div className="space-y-1">
122
+ <label className="text-xs font-medium text-muted-foreground">
123
+ Código Hexadecimal
124
+ </label>
125
+ <Input
126
+ value={color || ""}
127
+ onChange={handleInputChange}
128
+ placeholder="#000000"
129
+ className="font-mono text-sm border-border focus:border-primary/50 focus:ring-primary/20 bg-background text-foreground"
130
+ />
131
+ </div>
132
+ </div>
133
+
134
+ {/* Paleta de cores predefinidas */}
135
+ <div className="space-y-2">
136
+ <label className="text-xs font-medium text-muted-foreground">
137
+ Cores Predefinidas
138
+ </label>
139
+ <div className="grid grid-cols-8 gap-1.5">
140
+ {presetColors.map((presetColor) => (
141
+ <button
142
+ key={presetColor}
143
+ className={cn(
144
+ "w-7 h-7 rounded border cursor-pointer transition-all duration-200 hover:scale-110 hover:shadow-md",
145
+ color === presetColor
146
+ ? "border-primary ring-2 ring-primary/20"
147
+ : "border-border hover:border-muted-foreground/50"
148
+ )}
149
+ style={{ backgroundColor: presetColor }}
150
+ onClick={() => handleColorChange(presetColor)}
151
+ title={presetColor.toUpperCase()}
152
+ />
153
+ ))}
154
+ </div>
155
+ </div>
156
+
157
+ {/* Preview da cor atual */}
158
+ {color && (
159
+ <div className="pt-2 border-t border-border">
160
+ <div className="text-xs font-medium text-muted-foreground mb-2">
161
+ Cor Atual
162
+ </div>
163
+ <div className="flex items-center gap-3 p-2 bg-muted/50 rounded-md cursor-pointer hover:bg-muted transition-colors">
164
+ <div
165
+ className="w-8 h-8 rounded border border-border shadow-sm shrink-0"
166
+ style={{ backgroundColor: color }}
167
+ />
168
+ <div className="flex-1">
169
+ <div className="font-mono text-sm font-medium text-foreground">
170
+ {color.toUpperCase()}
171
+ </div>
172
+ <div className="text-xs text-muted-foreground">
173
+ Clique para copiar
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </div>
178
+ )}
179
+ </div>
180
+ </PopoverContent>
181
+ </Popover>
182
+ );
183
+ }
@@ -0,0 +1,184 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Command as CommandPrimitive } from "cmdk";
5
+ import { SearchIcon } from "lucide-react";
6
+
7
+ import { cn } from "@/lib/utils";
8
+ import {
9
+ Dialog,
10
+ DialogContent,
11
+ DialogDescription,
12
+ DialogHeader,
13
+ DialogTitle,
14
+ } from "@/components/ui/dialog";
15
+
16
+ function Command({
17
+ className,
18
+ ...props
19
+ }: React.ComponentProps<typeof CommandPrimitive>) {
20
+ return (
21
+ <CommandPrimitive
22
+ data-slot="command"
23
+ className={cn(
24
+ "bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
25
+ className
26
+ )}
27
+ {...props}
28
+ />
29
+ );
30
+ }
31
+
32
+ function CommandDialog({
33
+ title = "Command Palette",
34
+ description = "Search for a command to run...",
35
+ children,
36
+ className,
37
+ showCloseButton = true,
38
+ ...props
39
+ }: React.ComponentProps<typeof Dialog> & {
40
+ title?: string;
41
+ description?: string;
42
+ className?: string;
43
+ showCloseButton?: boolean;
44
+ }) {
45
+ return (
46
+ <Dialog {...props}>
47
+ <DialogHeader className="sr-only">
48
+ <DialogTitle>{title}</DialogTitle>
49
+ <DialogDescription>{description}</DialogDescription>
50
+ </DialogHeader>
51
+ <DialogContent
52
+ className={cn("overflow-hidden p-0", className)}
53
+ showCloseButton={showCloseButton}
54
+ >
55
+ <Command className="[&_[cmdk-group-heading]]:text-muted-foreground **:data-[slot=command-input-wrapper]:h-12 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]]:px-2 [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
56
+ {children}
57
+ </Command>
58
+ </DialogContent>
59
+ </Dialog>
60
+ );
61
+ }
62
+
63
+ function CommandInput({
64
+ className,
65
+ ...props
66
+ }: React.ComponentProps<typeof CommandPrimitive.Input>) {
67
+ return (
68
+ <div
69
+ data-slot="command-input-wrapper"
70
+ className="flex h-9 items-center gap-2 border-b px-3"
71
+ >
72
+ <SearchIcon className="size-4 shrink-0 opacity-50" />
73
+ <CommandPrimitive.Input
74
+ data-slot="command-input"
75
+ className={cn(
76
+ "placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
77
+ className
78
+ )}
79
+ {...props}
80
+ />
81
+ </div>
82
+ );
83
+ }
84
+
85
+ function CommandList({
86
+ className,
87
+ ...props
88
+ }: React.ComponentProps<typeof CommandPrimitive.List>) {
89
+ return (
90
+ <CommandPrimitive.List
91
+ data-slot="command-list"
92
+ className={cn(
93
+ "max-h-[300px] scroll-py-1 overflow-x-hidden overflow-y-auto",
94
+ className
95
+ )}
96
+ {...props}
97
+ />
98
+ );
99
+ }
100
+
101
+ function CommandEmpty({
102
+ ...props
103
+ }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
104
+ return (
105
+ <CommandPrimitive.Empty
106
+ data-slot="command-empty"
107
+ className="py-6 text-center text-sm"
108
+ {...props}
109
+ />
110
+ );
111
+ }
112
+
113
+ function CommandGroup({
114
+ className,
115
+ ...props
116
+ }: React.ComponentProps<typeof CommandPrimitive.Group>) {
117
+ return (
118
+ <CommandPrimitive.Group
119
+ data-slot="command-group"
120
+ className={cn(
121
+ "text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
122
+ className
123
+ )}
124
+ {...props}
125
+ />
126
+ );
127
+ }
128
+
129
+ function CommandSeparator({
130
+ className,
131
+ ...props
132
+ }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
133
+ return (
134
+ <CommandPrimitive.Separator
135
+ data-slot="command-separator"
136
+ className={cn("bg-border -mx-1 h-px", className)}
137
+ {...props}
138
+ />
139
+ );
140
+ }
141
+
142
+ function CommandItem({
143
+ className,
144
+ ...props
145
+ }: React.ComponentProps<typeof CommandPrimitive.Item>) {
146
+ return (
147
+ <CommandPrimitive.Item
148
+ data-slot="command-item"
149
+ className={cn(
150
+ "data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
151
+ className
152
+ )}
153
+ {...props}
154
+ />
155
+ );
156
+ }
157
+
158
+ function CommandShortcut({
159
+ className,
160
+ ...props
161
+ }: React.ComponentProps<"span">) {
162
+ return (
163
+ <span
164
+ data-slot="command-shortcut"
165
+ className={cn(
166
+ "text-muted-foreground ml-auto text-xs tracking-widest",
167
+ className
168
+ )}
169
+ {...props}
170
+ />
171
+ );
172
+ }
173
+
174
+ export {
175
+ Command,
176
+ CommandDialog,
177
+ CommandInput,
178
+ CommandList,
179
+ CommandEmpty,
180
+ CommandGroup,
181
+ CommandItem,
182
+ CommandShortcut,
183
+ CommandSeparator,
184
+ };
@@ -0,0 +1,157 @@
1
+ "use client";
2
+
3
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
4
+ import { XIcon } from "lucide-react";
5
+ import * as React from "react";
6
+
7
+ import { cn } from "@/lib/utils";
8
+
9
+ function Dialog({
10
+ ...props
11
+ }: React.ComponentProps<typeof DialogPrimitive.Root>) {
12
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />;
13
+ }
14
+
15
+ function DialogTrigger({
16
+ className,
17
+ ...props
18
+ }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
19
+ return (
20
+ <DialogPrimitive.Trigger
21
+ data-slot="dialog-trigger"
22
+ className={cn("cursor-pointer", className)}
23
+ {...props}
24
+ />
25
+ );
26
+ }
27
+
28
+ function DialogPortal({
29
+ ...props
30
+ }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
31
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
32
+ }
33
+
34
+ function DialogClose({
35
+ className,
36
+ ...props
37
+ }: React.ComponentProps<typeof DialogPrimitive.Close>) {
38
+ return (
39
+ <DialogPrimitive.Close
40
+ data-slot="dialog-close"
41
+ className={cn("cursor-pointer", className)}
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+
47
+ function DialogOverlay({
48
+ className,
49
+ ...props
50
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
51
+ return (
52
+ <DialogPrimitive.Overlay
53
+ data-slot="dialog-overlay"
54
+ className={cn(
55
+ "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 bg-black/50",
56
+ className
57
+ )}
58
+ {...props}
59
+ />
60
+ );
61
+ }
62
+
63
+ function DialogContent({
64
+ className,
65
+ children,
66
+ showCloseButton = true,
67
+ ...props
68
+ }: React.ComponentProps<typeof DialogPrimitive.Content> & {
69
+ showCloseButton?: boolean;
70
+ }) {
71
+ return (
72
+ <DialogPortal data-slot="dialog-portal">
73
+ <DialogOverlay />
74
+ <DialogPrimitive.Content
75
+ data-slot="dialog-content"
76
+ className={cn(
77
+ "bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-border p-6 shadow-lg duration-200 sm:max-w-xl md:max-w-2xl lg:max-w-3xl",
78
+ className
79
+ )}
80
+ {...props}
81
+ >
82
+ {children}
83
+ {showCloseButton && (
84
+ <DialogPrimitive.Close
85
+ data-slot="dialog-close"
86
+ className="ring-offset-background cursor-pointer focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
87
+ >
88
+ <XIcon />
89
+ <span className="sr-only">Close</span>
90
+ </DialogPrimitive.Close>
91
+ )}
92
+ </DialogPrimitive.Content>
93
+ </DialogPortal>
94
+ );
95
+ }
96
+
97
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
98
+ return (
99
+ <div
100
+ data-slot="dialog-header"
101
+ className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
102
+ {...props}
103
+ />
104
+ );
105
+ }
106
+
107
+ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
108
+ return (
109
+ <div
110
+ data-slot="dialog-footer"
111
+ className={cn(
112
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
113
+ className
114
+ )}
115
+ {...props}
116
+ />
117
+ );
118
+ }
119
+
120
+ function DialogTitle({
121
+ className,
122
+ ...props
123
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
124
+ return (
125
+ <DialogPrimitive.Title
126
+ data-slot="dialog-title"
127
+ className={cn("text-lg leading-none font-semibold", className)}
128
+ {...props}
129
+ />
130
+ );
131
+ }
132
+
133
+ function DialogDescription({
134
+ className,
135
+ ...props
136
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
137
+ return (
138
+ <DialogPrimitive.Description
139
+ data-slot="dialog-description"
140
+ className={cn("text-muted-foreground text-sm", className)}
141
+ {...props}
142
+ />
143
+ );
144
+ }
145
+
146
+ export {
147
+ Dialog,
148
+ DialogClose,
149
+ DialogContent,
150
+ DialogDescription,
151
+ DialogFooter,
152
+ DialogHeader,
153
+ DialogOverlay,
154
+ DialogPortal,
155
+ DialogTitle,
156
+ DialogTrigger,
157
+ };
@@ -0,0 +1,149 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Drawer as DrawerPrimitive } from "vaul";
5
+
6
+ import { cn } from "@/lib/utils";
7
+
8
+ function Drawer({
9
+ ...props
10
+ }: React.ComponentProps<typeof DrawerPrimitive.Root>) {
11
+ return <DrawerPrimitive.Root data-slot="drawer" {...props} />;
12
+ }
13
+
14
+ function DrawerTrigger({
15
+ className,
16
+ ...props
17
+ }: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
18
+ return (
19
+ <DrawerPrimitive.Trigger
20
+ data-slot="drawer-trigger"
21
+ className={cn("cursor-pointer", className)}
22
+ {...props}
23
+ />
24
+ );
25
+ }
26
+
27
+ function DrawerPortal({
28
+ ...props
29
+ }: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
30
+ return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />;
31
+ }
32
+
33
+ function DrawerClose({
34
+ className,
35
+ ...props
36
+ }: React.ComponentProps<typeof DrawerPrimitive.Close>) {
37
+ return (
38
+ <DrawerPrimitive.Close
39
+ data-slot="drawer-close"
40
+ className={cn("cursor-pointer", className)}
41
+ {...props}
42
+ />
43
+ );
44
+ }
45
+
46
+ function DrawerOverlay({
47
+ className,
48
+ ...props
49
+ }: React.ComponentProps<typeof DrawerPrimitive.Overlay>) {
50
+ return (
51
+ <DrawerPrimitive.Overlay
52
+ data-slot="drawer-overlay"
53
+ className={cn(
54
+ "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 bg-black/50",
55
+ className
56
+ )}
57
+ {...props}
58
+ />
59
+ );
60
+ }
61
+
62
+ function DrawerContent({
63
+ className,
64
+ children,
65
+ ...props
66
+ }: React.ComponentProps<typeof DrawerPrimitive.Content>) {
67
+ return (
68
+ <DrawerPortal data-slot="drawer-portal">
69
+ <DrawerOverlay />
70
+ <DrawerPrimitive.Content
71
+ data-slot="drawer-content"
72
+ className={cn(
73
+ "group/drawer-content bg-background fixed z-50 flex h-auto flex-col",
74
+ "data-[vaul-drawer-direction=top]:inset-x-0 data-[vaul-drawer-direction=top]:top-0 data-[vaul-drawer-direction=top]:mb-24 data-[vaul-drawer-direction=top]:max-h-[80vh] data-[vaul-drawer-direction=top]:rounded-b-lg data-[vaul-drawer-direction=top]:border-b",
75
+ "data-[vaul-drawer-direction=bottom]:inset-x-0 data-[vaul-drawer-direction=bottom]:bottom-0 data-[vaul-drawer-direction=bottom]:mt-24 data-[vaul-drawer-direction=bottom]:max-h-[80vh] data-[vaul-drawer-direction=bottom]:rounded-t-lg data-[vaul-drawer-direction=bottom]:border-t",
76
+ "data-[vaul-drawer-direction=right]:inset-y-0 data-[vaul-drawer-direction=right]:right-0 data-[vaul-drawer-direction=right]:w-3/4 data-[vaul-drawer-direction=right]:border-l data-[vaul-drawer-direction=right]:sm:max-w-sm",
77
+ "data-[vaul-drawer-direction=left]:inset-y-0 data-[vaul-drawer-direction=left]:left-0 data-[vaul-drawer-direction=left]:w-3/4 data-[vaul-drawer-direction=left]:border-r data-[vaul-drawer-direction=left]:sm:max-w-sm",
78
+ className
79
+ )}
80
+ {...props}
81
+ >
82
+ <div className="bg-muted mx-auto mt-4 hidden h-2 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
83
+ {children}
84
+ </DrawerPrimitive.Content>
85
+ </DrawerPortal>
86
+ );
87
+ }
88
+
89
+ function DrawerHeader({ className, ...props }: React.ComponentProps<"div">) {
90
+ return (
91
+ <div
92
+ data-slot="drawer-header"
93
+ className={cn(
94
+ "flex flex-col gap-0.5 p-4 group-data-[vaul-drawer-direction=bottom]/drawer-content:text-center group-data-[vaul-drawer-direction=top]/drawer-content:text-center md:gap-1.5 md:text-left",
95
+ className
96
+ )}
97
+ {...props}
98
+ />
99
+ );
100
+ }
101
+
102
+ function DrawerFooter({ className, ...props }: React.ComponentProps<"div">) {
103
+ return (
104
+ <div
105
+ data-slot="drawer-footer"
106
+ className={cn("mt-auto flex flex-col gap-2 p-4", className)}
107
+ {...props}
108
+ />
109
+ );
110
+ }
111
+
112
+ function DrawerTitle({
113
+ className,
114
+ ...props
115
+ }: React.ComponentProps<typeof DrawerPrimitive.Title>) {
116
+ return (
117
+ <DrawerPrimitive.Title
118
+ data-slot="drawer-title"
119
+ className={cn("text-foreground font-semibold", className)}
120
+ {...props}
121
+ />
122
+ );
123
+ }
124
+
125
+ function DrawerDescription({
126
+ className,
127
+ ...props
128
+ }: React.ComponentProps<typeof DrawerPrimitive.Description>) {
129
+ return (
130
+ <DrawerPrimitive.Description
131
+ data-slot="drawer-description"
132
+ className={cn("text-muted-foreground text-sm", className)}
133
+ {...props}
134
+ />
135
+ );
136
+ }
137
+
138
+ export {
139
+ Drawer,
140
+ DrawerPortal,
141
+ DrawerOverlay,
142
+ DrawerTrigger,
143
+ DrawerClose,
144
+ DrawerContent,
145
+ DrawerHeader,
146
+ DrawerFooter,
147
+ DrawerTitle,
148
+ DrawerDescription,
149
+ };