@oppulence/design-system 1.0.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.
Files changed (80) hide show
  1. package/README.md +115 -0
  2. package/components.json +21 -0
  3. package/hooks/use-mobile.tsx +21 -0
  4. package/lib/utils.ts +6 -0
  5. package/package.json +104 -0
  6. package/postcss.config.mjs +8 -0
  7. package/src/components/atoms/aspect-ratio.tsx +21 -0
  8. package/src/components/atoms/avatar.tsx +91 -0
  9. package/src/components/atoms/badge.tsx +47 -0
  10. package/src/components/atoms/button.tsx +128 -0
  11. package/src/components/atoms/checkbox.tsx +24 -0
  12. package/src/components/atoms/container.tsx +42 -0
  13. package/src/components/atoms/heading.tsx +56 -0
  14. package/src/components/atoms/index.ts +21 -0
  15. package/src/components/atoms/input.tsx +18 -0
  16. package/src/components/atoms/kbd.tsx +23 -0
  17. package/src/components/atoms/label.tsx +15 -0
  18. package/src/components/atoms/logo.tsx +52 -0
  19. package/src/components/atoms/progress.tsx +79 -0
  20. package/src/components/atoms/separator.tsx +17 -0
  21. package/src/components/atoms/skeleton.tsx +13 -0
  22. package/src/components/atoms/slider.tsx +56 -0
  23. package/src/components/atoms/spinner.tsx +14 -0
  24. package/src/components/atoms/stack.tsx +126 -0
  25. package/src/components/atoms/switch.tsx +26 -0
  26. package/src/components/atoms/text.tsx +69 -0
  27. package/src/components/atoms/textarea.tsx +19 -0
  28. package/src/components/atoms/toggle.tsx +40 -0
  29. package/src/components/molecules/accordion.tsx +72 -0
  30. package/src/components/molecules/ai-chat.tsx +251 -0
  31. package/src/components/molecules/alert.tsx +131 -0
  32. package/src/components/molecules/breadcrumb.tsx +301 -0
  33. package/src/components/molecules/button-group.tsx +96 -0
  34. package/src/components/molecules/card.tsx +184 -0
  35. package/src/components/molecules/collapsible.tsx +21 -0
  36. package/src/components/molecules/command-search.tsx +148 -0
  37. package/src/components/molecules/empty.tsx +98 -0
  38. package/src/components/molecules/field.tsx +217 -0
  39. package/src/components/molecules/grid.tsx +141 -0
  40. package/src/components/molecules/hover-card.tsx +45 -0
  41. package/src/components/molecules/index.ts +29 -0
  42. package/src/components/molecules/input-group.tsx +151 -0
  43. package/src/components/molecules/input-otp.tsx +74 -0
  44. package/src/components/molecules/item.tsx +194 -0
  45. package/src/components/molecules/page-header.tsx +89 -0
  46. package/src/components/molecules/pagination.tsx +130 -0
  47. package/src/components/molecules/popover.tsx +96 -0
  48. package/src/components/molecules/radio-group.tsx +37 -0
  49. package/src/components/molecules/resizable.tsx +52 -0
  50. package/src/components/molecules/scroll-area.tsx +45 -0
  51. package/src/components/molecules/section.tsx +108 -0
  52. package/src/components/molecules/select.tsx +201 -0
  53. package/src/components/molecules/settings.tsx +197 -0
  54. package/src/components/molecules/table.tsx +111 -0
  55. package/src/components/molecules/tabs.tsx +74 -0
  56. package/src/components/molecules/theme-switcher.tsx +187 -0
  57. package/src/components/molecules/toggle-group.tsx +89 -0
  58. package/src/components/molecules/tooltip.tsx +66 -0
  59. package/src/components/organisms/alert-dialog.tsx +152 -0
  60. package/src/components/organisms/app-shell.tsx +939 -0
  61. package/src/components/organisms/calendar.tsx +212 -0
  62. package/src/components/organisms/carousel.tsx +230 -0
  63. package/src/components/organisms/chart.tsx +333 -0
  64. package/src/components/organisms/combobox.tsx +274 -0
  65. package/src/components/organisms/command.tsx +200 -0
  66. package/src/components/organisms/context-menu.tsx +229 -0
  67. package/src/components/organisms/dialog.tsx +134 -0
  68. package/src/components/organisms/drawer.tsx +123 -0
  69. package/src/components/organisms/dropdown-menu.tsx +256 -0
  70. package/src/components/organisms/index.ts +17 -0
  71. package/src/components/organisms/menubar.tsx +203 -0
  72. package/src/components/organisms/navigation-menu.tsx +143 -0
  73. package/src/components/organisms/page-layout.tsx +105 -0
  74. package/src/components/organisms/sheet.tsx +126 -0
  75. package/src/components/organisms/sidebar.tsx +723 -0
  76. package/src/components/organisms/sonner.tsx +41 -0
  77. package/src/components/ui/index.ts +3 -0
  78. package/src/index.ts +3 -0
  79. package/src/styles/globals.css +297 -0
  80. package/tailwind.config.ts +77 -0
@@ -0,0 +1,200 @@
1
+ "use client";
2
+
3
+ import { Command as CommandPrimitive } from "cmdk";
4
+ import * as React from "react";
5
+
6
+ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
7
+ import { cva, type VariantProps } from "class-variance-authority";
8
+ import { CheckIcon, SearchIcon } from "lucide-react";
9
+
10
+ const commandVariants = cva(
11
+ "bg-popover text-popover-foreground rounded-xl p-1 flex size-full flex-col overflow-hidden",
12
+ {
13
+ variants: {
14
+ width: {
15
+ auto: "",
16
+ sm: "w-sm",
17
+ md: "w-md",
18
+ lg: "w-lg",
19
+ },
20
+ },
21
+ defaultVariants: {
22
+ width: "auto",
23
+ },
24
+ },
25
+ );
26
+
27
+ interface CommandProps
28
+ extends
29
+ Omit<React.ComponentProps<typeof CommandPrimitive>, "className">,
30
+ VariantProps<typeof commandVariants> {}
31
+
32
+ function Command({ width, ...props }: CommandProps) {
33
+ return (
34
+ <CommandPrimitive
35
+ data-slot="command"
36
+ className={commandVariants({ width })}
37
+ {...props}
38
+ />
39
+ );
40
+ }
41
+
42
+ function CommandDialog({
43
+ title = "Command Palette",
44
+ description = "Search for a command to run...",
45
+ children,
46
+ ...props
47
+ }: Omit<DialogPrimitive.Root.Props, "children"> & {
48
+ title?: string;
49
+ description?: string;
50
+ children: React.ReactNode;
51
+ }) {
52
+ return (
53
+ <DialogPrimitive.Root data-slot="dialog" {...props}>
54
+ <DialogPrimitive.Portal>
55
+ <DialogPrimitive.Backdrop
56
+ data-slot="dialog-overlay"
57
+ className="data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50"
58
+ />
59
+ <DialogPrimitive.Popup
60
+ data-slot="command-dialog-content"
61
+ className="data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 bg-background ring-foreground/10 rounded-xl p-0 ring-1 duration-100 sm:max-w-lg group/dialog-content fixed top-1/2 left-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-hidden outline-none"
62
+ >
63
+ <div
64
+ data-slot="dialog-header"
65
+ className="sr-only flex flex-col gap-1.5 text-center sm:text-left"
66
+ >
67
+ <DialogPrimitive.Title
68
+ data-slot="dialog-title"
69
+ className="text-lg font-medium"
70
+ >
71
+ {title}
72
+ </DialogPrimitive.Title>
73
+ <DialogPrimitive.Description
74
+ data-slot="dialog-description"
75
+ className="text-muted-foreground text-sm text-balance md:text-pretty"
76
+ >
77
+ {description}
78
+ </DialogPrimitive.Description>
79
+ </div>
80
+ {children}
81
+ </DialogPrimitive.Popup>
82
+ </DialogPrimitive.Portal>
83
+ </DialogPrimitive.Root>
84
+ );
85
+ }
86
+
87
+ function CommandInput({
88
+ ...props
89
+ }: Omit<React.ComponentProps<typeof CommandPrimitive.Input>, "className">) {
90
+ return (
91
+ <div data-slot="command-input-wrapper" className="p-1 pb-0">
92
+ <div
93
+ data-slot="input-group"
94
+ role="group"
95
+ className="border-input/30 bg-input/30 h-8 rounded-lg border shadow-none transition-[color,box-shadow] has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] group/input-group relative flex w-full min-w-0 items-center outline-none"
96
+ >
97
+ <CommandPrimitive.Input
98
+ data-slot="command-input"
99
+ className="w-full flex-1 bg-transparent px-2.5 py-1 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50"
100
+ {...props}
101
+ />
102
+ <div
103
+ data-slot="input-group-addon"
104
+ data-align="inline-end"
105
+ className="text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 pr-2 text-sm font-medium select-none"
106
+ >
107
+ <SearchIcon className="size-4 shrink-0 opacity-50" />
108
+ </div>
109
+ </div>
110
+ </div>
111
+ );
112
+ }
113
+
114
+ function CommandList({
115
+ ...props
116
+ }: Omit<React.ComponentProps<typeof CommandPrimitive.List>, "className">) {
117
+ return (
118
+ <CommandPrimitive.List
119
+ data-slot="command-list"
120
+ className="no-scrollbar max-h-72 scroll-py-1 outline-none overflow-x-hidden overflow-y-auto"
121
+ {...props}
122
+ />
123
+ );
124
+ }
125
+
126
+ function CommandEmpty({
127
+ ...props
128
+ }: Omit<React.ComponentProps<typeof CommandPrimitive.Empty>, "className">) {
129
+ return (
130
+ <CommandPrimitive.Empty
131
+ data-slot="command-empty"
132
+ className="py-6 text-center text-sm"
133
+ {...props}
134
+ />
135
+ );
136
+ }
137
+
138
+ function CommandGroup({
139
+ ...props
140
+ }: Omit<React.ComponentProps<typeof CommandPrimitive.Group>, "className">) {
141
+ return (
142
+ <CommandPrimitive.Group
143
+ data-slot="command-group"
144
+ className="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"
145
+ {...props}
146
+ />
147
+ );
148
+ }
149
+
150
+ function CommandSeparator({
151
+ ...props
152
+ }: Omit<React.ComponentProps<typeof CommandPrimitive.Separator>, "className">) {
153
+ return (
154
+ <CommandPrimitive.Separator
155
+ data-slot="command-separator"
156
+ className="bg-border -mx-1 h-px w-auto"
157
+ {...props}
158
+ />
159
+ );
160
+ }
161
+
162
+ function CommandItem({
163
+ children,
164
+ ...props
165
+ }: Omit<React.ComponentProps<typeof CommandPrimitive.Item>, "className">) {
166
+ return (
167
+ <CommandPrimitive.Item
168
+ data-slot="command-item"
169
+ className="data-[selected=true]:bg-muted data-[selected=true]:text-foreground data-[selected=true]:**:[svg]:text-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none [&_svg:not([class*='size-'])]:size-4 [[data-slot=dialog-content]_&]:rounded-lg group/command-item data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0"
170
+ {...props}
171
+ >
172
+ {children}
173
+ <CheckIcon className="ml-auto opacity-0 group-has-[[data-slot=command-shortcut]]/command-item:hidden group-data-[checked=true]/command-item:opacity-100" />
174
+ </CommandPrimitive.Item>
175
+ );
176
+ }
177
+
178
+ function CommandShortcut({
179
+ ...props
180
+ }: Omit<React.ComponentProps<"span">, "className">) {
181
+ return (
182
+ <span
183
+ data-slot="command-shortcut"
184
+ className="text-muted-foreground group-data-[selected=true]/command-item:text-foreground ml-auto text-xs tracking-widest"
185
+ {...props}
186
+ />
187
+ );
188
+ }
189
+
190
+ export {
191
+ Command,
192
+ CommandDialog,
193
+ CommandEmpty,
194
+ CommandGroup,
195
+ CommandInput,
196
+ CommandItem,
197
+ CommandList,
198
+ CommandSeparator,
199
+ CommandShortcut,
200
+ };
@@ -0,0 +1,229 @@
1
+ import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu";
2
+
3
+ import { CheckIcon, ChevronRightIcon } from "lucide-react";
4
+
5
+ function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) {
6
+ return <ContextMenuPrimitive.Root data-slot="context-menu" {...props} />;
7
+ }
8
+
9
+ function ContextMenuPortal({ ...props }: ContextMenuPrimitive.Portal.Props) {
10
+ return (
11
+ <ContextMenuPrimitive.Portal data-slot="context-menu-portal" {...props} />
12
+ );
13
+ }
14
+
15
+ function ContextMenuTrigger({
16
+ ...props
17
+ }: Omit<ContextMenuPrimitive.Trigger.Props, "className">) {
18
+ return (
19
+ <ContextMenuPrimitive.Trigger
20
+ data-slot="context-menu-trigger"
21
+ className="select-none"
22
+ {...props}
23
+ />
24
+ );
25
+ }
26
+
27
+ function ContextMenuContent({
28
+ align = "start",
29
+ alignOffset = 4,
30
+ side = "right",
31
+ sideOffset = 0,
32
+ ...props
33
+ }: Omit<ContextMenuPrimitive.Popup.Props, "className"> &
34
+ Pick<
35
+ ContextMenuPrimitive.Positioner.Props,
36
+ "align" | "alignOffset" | "side" | "sideOffset"
37
+ >) {
38
+ return (
39
+ <ContextMenuPrimitive.Portal>
40
+ <ContextMenuPrimitive.Positioner
41
+ className="isolate z-50 outline-none"
42
+ align={align}
43
+ alignOffset={alignOffset}
44
+ side={side}
45
+ sideOffset={sideOffset}
46
+ >
47
+ <ContextMenuPrimitive.Popup
48
+ data-slot="context-menu-content"
49
+ className="data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 ring-foreground/10 bg-popover text-popover-foreground min-w-36 rounded-md p-1 shadow-md ring-1 duration-100 z-50 max-h-(--available-height) origin-(--transform-origin) overflow-x-hidden overflow-y-auto outline-none"
50
+ {...props}
51
+ />
52
+ </ContextMenuPrimitive.Positioner>
53
+ </ContextMenuPrimitive.Portal>
54
+ );
55
+ }
56
+
57
+ function ContextMenuGroup({ ...props }: ContextMenuPrimitive.Group.Props) {
58
+ return (
59
+ <ContextMenuPrimitive.Group data-slot="context-menu-group" {...props} />
60
+ );
61
+ }
62
+
63
+ function ContextMenuLabel({
64
+ inset,
65
+ ...props
66
+ }: Omit<ContextMenuPrimitive.GroupLabel.Props, "className"> & {
67
+ inset?: boolean;
68
+ }) {
69
+ return (
70
+ <ContextMenuPrimitive.GroupLabel
71
+ data-slot="context-menu-label"
72
+ data-inset={inset}
73
+ className="text-muted-foreground px-2 py-1.5 text-xs font-medium data-[inset]:pl-8"
74
+ {...props}
75
+ />
76
+ );
77
+ }
78
+
79
+ function ContextMenuItem({
80
+ inset,
81
+ variant = "default",
82
+ ...props
83
+ }: Omit<ContextMenuPrimitive.Item.Props, "className"> & {
84
+ inset?: boolean;
85
+ variant?: "default" | "destructive";
86
+ }) {
87
+ return (
88
+ <ContextMenuPrimitive.Item
89
+ data-slot="context-menu-item"
90
+ data-inset={inset}
91
+ data-variant={variant}
92
+ className="focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:text-destructive focus:*:[svg]:text-accent-foreground gap-2 rounded-sm px-2 py-1.5 text-sm [&_svg:not([class*='size-'])]:size-4 group/context-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0"
93
+ {...props}
94
+ />
95
+ );
96
+ }
97
+
98
+ function ContextMenuSub({ ...props }: ContextMenuPrimitive.SubmenuRoot.Props) {
99
+ return (
100
+ <ContextMenuPrimitive.SubmenuRoot data-slot="context-menu-sub" {...props} />
101
+ );
102
+ }
103
+
104
+ function ContextMenuSubTrigger({
105
+ inset,
106
+ children,
107
+ ...props
108
+ }: Omit<ContextMenuPrimitive.SubmenuTrigger.Props, "className"> & {
109
+ inset?: boolean;
110
+ }) {
111
+ return (
112
+ <ContextMenuPrimitive.SubmenuTrigger
113
+ data-slot="context-menu-sub-trigger"
114
+ data-inset={inset}
115
+ className="focus:bg-accent focus:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground rounded-sm px-2 py-1.5 text-sm [&_svg:not([class*='size-'])]:size-4 flex cursor-default items-center outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0"
116
+ {...props}
117
+ >
118
+ {children}
119
+ <ChevronRightIcon className="ml-auto" />
120
+ </ContextMenuPrimitive.SubmenuTrigger>
121
+ );
122
+ }
123
+
124
+ function ContextMenuSubContent({
125
+ ...props
126
+ }: Omit<React.ComponentProps<typeof ContextMenuContent>, "className">) {
127
+ return (
128
+ <ContextMenuContent
129
+ data-slot="context-menu-sub-content"
130
+ side="right"
131
+ {...props}
132
+ />
133
+ );
134
+ }
135
+
136
+ function ContextMenuCheckboxItem({
137
+ children,
138
+ checked,
139
+ ...props
140
+ }: Omit<ContextMenuPrimitive.CheckboxItem.Props, "className">) {
141
+ return (
142
+ <ContextMenuPrimitive.CheckboxItem
143
+ data-slot="context-menu-checkbox-item"
144
+ className="focus:bg-accent focus:text-accent-foreground gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0"
145
+ checked={checked}
146
+ {...props}
147
+ >
148
+ <span className="absolute right-2 pointer-events-none">
149
+ <ContextMenuPrimitive.CheckboxItemIndicator>
150
+ <CheckIcon />
151
+ </ContextMenuPrimitive.CheckboxItemIndicator>
152
+ </span>
153
+ {children}
154
+ </ContextMenuPrimitive.CheckboxItem>
155
+ );
156
+ }
157
+
158
+ function ContextMenuRadioGroup({
159
+ ...props
160
+ }: ContextMenuPrimitive.RadioGroup.Props) {
161
+ return (
162
+ <ContextMenuPrimitive.RadioGroup
163
+ data-slot="context-menu-radio-group"
164
+ {...props}
165
+ />
166
+ );
167
+ }
168
+
169
+ function ContextMenuRadioItem({
170
+ children,
171
+ ...props
172
+ }: Omit<ContextMenuPrimitive.RadioItem.Props, "className">) {
173
+ return (
174
+ <ContextMenuPrimitive.RadioItem
175
+ data-slot="context-menu-radio-item"
176
+ className="focus:bg-accent focus:text-accent-foreground gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0"
177
+ {...props}
178
+ >
179
+ <span className="absolute right-2 pointer-events-none">
180
+ <ContextMenuPrimitive.RadioItemIndicator>
181
+ <CheckIcon />
182
+ </ContextMenuPrimitive.RadioItemIndicator>
183
+ </span>
184
+ {children}
185
+ </ContextMenuPrimitive.RadioItem>
186
+ );
187
+ }
188
+
189
+ function ContextMenuSeparator({
190
+ ...props
191
+ }: Omit<ContextMenuPrimitive.Separator.Props, "className">) {
192
+ return (
193
+ <ContextMenuPrimitive.Separator
194
+ data-slot="context-menu-separator"
195
+ className="bg-border -mx-1 my-1 h-px"
196
+ {...props}
197
+ />
198
+ );
199
+ }
200
+
201
+ function ContextMenuShortcut({
202
+ ...props
203
+ }: Omit<React.ComponentProps<"span">, "className">) {
204
+ return (
205
+ <span
206
+ data-slot="context-menu-shortcut"
207
+ className="text-muted-foreground group-focus/context-menu-item:text-accent-foreground ml-auto text-xs tracking-widest"
208
+ {...props}
209
+ />
210
+ );
211
+ }
212
+
213
+ export {
214
+ ContextMenu,
215
+ ContextMenuCheckboxItem,
216
+ ContextMenuContent,
217
+ ContextMenuGroup,
218
+ ContextMenuItem,
219
+ ContextMenuLabel,
220
+ ContextMenuPortal,
221
+ ContextMenuRadioGroup,
222
+ ContextMenuRadioItem,
223
+ ContextMenuSeparator,
224
+ ContextMenuShortcut,
225
+ ContextMenuSub,
226
+ ContextMenuSubContent,
227
+ ContextMenuSubTrigger,
228
+ ContextMenuTrigger,
229
+ };
@@ -0,0 +1,134 @@
1
+ "use client";
2
+
3
+ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
4
+ import * as React from "react";
5
+
6
+ import { XIcon } from "lucide-react";
7
+ import { Button } from "../atoms/button";
8
+
9
+ function Dialog({ ...props }: DialogPrimitive.Root.Props) {
10
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />;
11
+ }
12
+
13
+ function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) {
14
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
15
+ }
16
+
17
+ function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) {
18
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
19
+ }
20
+
21
+ function DialogClose({ ...props }: DialogPrimitive.Close.Props) {
22
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
23
+ }
24
+
25
+ function DialogOverlay({
26
+ ...props
27
+ }: Omit<DialogPrimitive.Backdrop.Props, "className">) {
28
+ return (
29
+ <DialogPrimitive.Backdrop
30
+ data-slot="dialog-overlay"
31
+ className="data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 isolate z-50"
32
+ {...props}
33
+ />
34
+ );
35
+ }
36
+
37
+ function DialogContent({
38
+ children,
39
+ showCloseButton = true,
40
+ ...props
41
+ }: Omit<DialogPrimitive.Popup.Props, "className"> & {
42
+ showCloseButton?: boolean;
43
+ }) {
44
+ return (
45
+ <DialogPortal>
46
+ <DialogOverlay />
47
+ <DialogPrimitive.Popup
48
+ data-slot="dialog-content"
49
+ className="bg-background data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-open:zoom-in-95 ring-foreground/10 grid max-w-[calc(100%-2rem)] gap-4 rounded-xl p-4 text-sm ring-1 duration-100 sm:max-w-sm fixed top-1/2 left-1/2 z-50 w-full -translate-x-1/2 -translate-y-1/2 outline-none"
50
+ {...props}
51
+ >
52
+ {children}
53
+ {showCloseButton && (
54
+ <DialogPrimitive.Close
55
+ data-slot="dialog-close"
56
+ render={<Button variant="ghost" size="icon-sm" />}
57
+ className="absolute top-2 right-2"
58
+ >
59
+ <XIcon />
60
+ <span className="sr-only">Close</span>
61
+ </DialogPrimitive.Close>
62
+ )}
63
+ </DialogPrimitive.Popup>
64
+ </DialogPortal>
65
+ );
66
+ }
67
+
68
+ function DialogHeader({
69
+ ...props
70
+ }: Omit<React.ComponentProps<"div">, "className">) {
71
+ return (
72
+ <div data-slot="dialog-header" className="gap-2 flex flex-col" {...props} />
73
+ );
74
+ }
75
+
76
+ function DialogFooter({
77
+ showCloseButton = false,
78
+ children,
79
+ ...props
80
+ }: Omit<React.ComponentProps<"div">, "className"> & {
81
+ showCloseButton?: boolean;
82
+ }) {
83
+ return (
84
+ <div
85
+ data-slot="dialog-footer"
86
+ className="bg-muted/50 -mx-4 -mb-4 rounded-b-xl border-t p-4 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end"
87
+ {...props}
88
+ >
89
+ {children}
90
+ {showCloseButton && (
91
+ <DialogPrimitive.Close render={<Button variant="outline" />}>
92
+ Close
93
+ </DialogPrimitive.Close>
94
+ )}
95
+ </div>
96
+ );
97
+ }
98
+
99
+ function DialogTitle({
100
+ ...props
101
+ }: Omit<DialogPrimitive.Title.Props, "className">) {
102
+ return (
103
+ <DialogPrimitive.Title
104
+ data-slot="dialog-title"
105
+ className="text-sm leading-none font-medium"
106
+ {...props}
107
+ />
108
+ );
109
+ }
110
+
111
+ function DialogDescription({
112
+ ...props
113
+ }: Omit<DialogPrimitive.Description.Props, "className">) {
114
+ return (
115
+ <DialogPrimitive.Description
116
+ data-slot="dialog-description"
117
+ className="text-muted-foreground *:[a]:hover:text-foreground text-sm *:[a]:underline *:[a]:underline-offset-3"
118
+ {...props}
119
+ />
120
+ );
121
+ }
122
+
123
+ export {
124
+ Dialog,
125
+ DialogClose,
126
+ DialogContent,
127
+ DialogDescription,
128
+ DialogFooter,
129
+ DialogHeader,
130
+ DialogOverlay,
131
+ DialogPortal,
132
+ DialogTitle,
133
+ DialogTrigger,
134
+ };
@@ -0,0 +1,123 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Drawer as DrawerPrimitive } from "vaul";
5
+
6
+ function Drawer({
7
+ ...props
8
+ }: React.ComponentProps<typeof DrawerPrimitive.Root>) {
9
+ return <DrawerPrimitive.Root data-slot="drawer" {...props} />;
10
+ }
11
+
12
+ function DrawerTrigger({
13
+ ...props
14
+ }: React.ComponentProps<typeof DrawerPrimitive.Trigger>) {
15
+ return <DrawerPrimitive.Trigger data-slot="drawer-trigger" {...props} />;
16
+ }
17
+
18
+ function DrawerPortal({
19
+ ...props
20
+ }: React.ComponentProps<typeof DrawerPrimitive.Portal>) {
21
+ return <DrawerPrimitive.Portal data-slot="drawer-portal" {...props} />;
22
+ }
23
+
24
+ function DrawerClose({
25
+ ...props
26
+ }: React.ComponentProps<typeof DrawerPrimitive.Close>) {
27
+ return <DrawerPrimitive.Close data-slot="drawer-close" {...props} />;
28
+ }
29
+
30
+ function DrawerOverlay({
31
+ ...props
32
+ }: Omit<React.ComponentProps<typeof DrawerPrimitive.Overlay>, "className">) {
33
+ return (
34
+ <DrawerPrimitive.Overlay
35
+ data-slot="drawer-overlay"
36
+ className="data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 bg-black/10 supports-backdrop-filter:backdrop-blur-xs fixed inset-0 z-50"
37
+ {...props}
38
+ />
39
+ );
40
+ }
41
+
42
+ function DrawerContent({
43
+ children,
44
+ ...props
45
+ }: Omit<React.ComponentProps<typeof DrawerPrimitive.Content>, "className">) {
46
+ return (
47
+ <DrawerPortal data-slot="drawer-portal">
48
+ <DrawerOverlay />
49
+ <DrawerPrimitive.Content
50
+ data-slot="drawer-content"
51
+ className="bg-background flex h-auto flex-col text-sm 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-xl data-[vaul-drawer-direction=bottom]:border-t 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]:rounded-r-xl data-[vaul-drawer-direction=left]:border-r 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]:rounded-l-xl data-[vaul-drawer-direction=right]:border-l 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-xl data-[vaul-drawer-direction=top]:border-b data-[vaul-drawer-direction=left]:sm:max-w-sm data-[vaul-drawer-direction=right]:sm:max-w-sm group/drawer-content fixed z-50"
52
+ {...props}
53
+ >
54
+ <div className="bg-muted mx-auto mt-4 hidden h-1.5 w-[100px] shrink-0 rounded-full group-data-[vaul-drawer-direction=bottom]/drawer-content:block bg-muted mx-auto hidden shrink-0 group-data-[vaul-drawer-direction=bottom]/drawer-content:block" />
55
+ {children}
56
+ </DrawerPrimitive.Content>
57
+ </DrawerPortal>
58
+ );
59
+ }
60
+
61
+ function DrawerHeader({
62
+ ...props
63
+ }: Omit<React.ComponentProps<"div">, "className">) {
64
+ return (
65
+ <div
66
+ data-slot="drawer-header"
67
+ className="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 flex flex-col"
68
+ {...props}
69
+ />
70
+ );
71
+ }
72
+
73
+ function DrawerFooter({
74
+ ...props
75
+ }: Omit<React.ComponentProps<"div">, "className">) {
76
+ return (
77
+ <div
78
+ data-slot="drawer-footer"
79
+ className="gap-2 p-4 mt-auto flex flex-col"
80
+ {...props}
81
+ />
82
+ );
83
+ }
84
+
85
+ function DrawerTitle({
86
+ ...props
87
+ }: Omit<React.ComponentProps<typeof DrawerPrimitive.Title>, "className">) {
88
+ return (
89
+ <DrawerPrimitive.Title
90
+ data-slot="drawer-title"
91
+ className="text-foreground font-medium"
92
+ {...props}
93
+ />
94
+ );
95
+ }
96
+
97
+ function DrawerDescription({
98
+ ...props
99
+ }: Omit<
100
+ React.ComponentProps<typeof DrawerPrimitive.Description>,
101
+ "className"
102
+ >) {
103
+ return (
104
+ <DrawerPrimitive.Description
105
+ data-slot="drawer-description"
106
+ className="text-muted-foreground text-sm"
107
+ {...props}
108
+ />
109
+ );
110
+ }
111
+
112
+ export {
113
+ Drawer,
114
+ DrawerClose,
115
+ DrawerContent,
116
+ DrawerDescription,
117
+ DrawerFooter,
118
+ DrawerHeader,
119
+ DrawerOverlay,
120
+ DrawerPortal,
121
+ DrawerTitle,
122
+ DrawerTrigger,
123
+ };