@bearmenu/ui 0.1.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 (207) hide show
  1. package/dist/chunk-2CUFS5LF.js +80 -0
  2. package/dist/chunk-3GWWZKX7.js +33 -0
  3. package/dist/chunk-3VMDCCCX.js +10 -0
  4. package/dist/chunk-4AVS6CV4.js +89 -0
  5. package/dist/chunk-4JOV7FXW.js +17 -0
  6. package/dist/chunk-4KOMHDZD.js +89 -0
  7. package/dist/chunk-4UO73SKC.js +26 -0
  8. package/dist/chunk-7H54PTVH.js +116 -0
  9. package/dist/chunk-CW24PLDW.js +24 -0
  10. package/dist/chunk-EBAMCZDW.js +112 -0
  11. package/dist/chunk-ERMIA7NP.js +106 -0
  12. package/dist/chunk-ESO2EM3L.js +46 -0
  13. package/dist/chunk-EUHEIWHZ.js +32 -0
  14. package/dist/chunk-FEK5XGZW.js +8 -0
  15. package/dist/chunk-NKHH23YK.js +31 -0
  16. package/dist/chunk-R47NEOSI.js +78 -0
  17. package/dist/chunk-UXAYXRFN.js +69 -0
  18. package/dist/chunk-X6GATUI2.js +19 -0
  19. package/dist/components/accordion.d.ts +9 -0
  20. package/dist/components/accordion.js +53 -0
  21. package/dist/components/alert-dialog.d.ts +23 -0
  22. package/dist/components/alert-dialog.js +98 -0
  23. package/dist/components/alert.d.ts +11 -0
  24. package/dist/components/alert.js +52 -0
  25. package/dist/components/aspect-ratio.d.ts +6 -0
  26. package/dist/components/aspect-ratio.js +2 -0
  27. package/dist/components/avatar.d.ts +8 -0
  28. package/dist/components/avatar.js +47 -0
  29. package/dist/components/badge.d.ts +13 -0
  30. package/dist/components/badge.js +3 -0
  31. package/dist/components/breadcrumb.d.ts +14 -0
  32. package/dist/components/breadcrumb.js +96 -0
  33. package/dist/components/button.d.ts +16 -0
  34. package/dist/components/button.js +4 -0
  35. package/dist/components/calendar.d.ts +11 -0
  36. package/dist/components/calendar.js +56 -0
  37. package/dist/components/card.d.ts +13 -0
  38. package/dist/components/card.js +4 -0
  39. package/dist/components/carousel.d.ts +24 -0
  40. package/dist/components/carousel.js +198 -0
  41. package/dist/components/checkbox.d.ts +6 -0
  42. package/dist/components/checkbox.js +25 -0
  43. package/dist/components/collapsible.d.ts +8 -0
  44. package/dist/components/collapsible.js +26 -0
  45. package/dist/components/command.d.ts +84 -0
  46. package/dist/components/command.js +4 -0
  47. package/dist/components/currency-input.d.ts +17 -0
  48. package/dist/components/currency-input.js +121 -0
  49. package/dist/components/dialog.d.ts +22 -0
  50. package/dist/components/dialog.js +3 -0
  51. package/dist/components/drawer.d.ts +27 -0
  52. package/dist/components/drawer.js +85 -0
  53. package/dist/components/dropdown-menu.d.ts +28 -0
  54. package/dist/components/dropdown-menu.js +211 -0
  55. package/dist/components/empty-state.d.ts +22 -0
  56. package/dist/components/empty-state.js +81 -0
  57. package/dist/components/form.d.ts +28 -0
  58. package/dist/components/form.js +97 -0
  59. package/dist/components/haptic-button.d.ts +12 -0
  60. package/dist/components/haptic-button.js +17 -0
  61. package/dist/components/input-otp.d.ts +14 -0
  62. package/dist/components/input-otp.js +62 -0
  63. package/dist/components/input.d.ts +6 -0
  64. package/dist/components/input.js +3 -0
  65. package/dist/components/label.d.ts +8 -0
  66. package/dist/components/label.js +3 -0
  67. package/dist/components/lazy-markdown.d.ts +11 -0
  68. package/dist/components/lazy-markdown.js +13 -0
  69. package/dist/components/link-button.d.ts +30 -0
  70. package/dist/components/link-button.js +17 -0
  71. package/dist/components/markdown-renderer.d.ts +11 -0
  72. package/dist/components/markdown-renderer.js +10 -0
  73. package/dist/components/multi-select-combobox.d.ts +23 -0
  74. package/dist/components/multi-select-combobox.js +114 -0
  75. package/dist/components/pagination.d.ts +18 -0
  76. package/dist/components/pagination.js +101 -0
  77. package/dist/components/popover.d.ts +8 -0
  78. package/dist/components/popover.js +3 -0
  79. package/dist/components/progress.d.ts +6 -0
  80. package/dist/components/progress.js +30 -0
  81. package/dist/components/radio-group.d.ts +7 -0
  82. package/dist/components/radio-group.js +30 -0
  83. package/dist/components/rating.d.ts +15 -0
  84. package/dist/components/rating.js +120 -0
  85. package/dist/components/scroll-area.d.ts +7 -0
  86. package/dist/components/scroll-area.js +44 -0
  87. package/dist/components/search-bar.d.ts +17 -0
  88. package/dist/components/search-bar.js +92 -0
  89. package/dist/components/searchable-select.d.ts +22 -0
  90. package/dist/components/searchable-select.js +104 -0
  91. package/dist/components/select.d.ts +15 -0
  92. package/dist/components/select.js +129 -0
  93. package/dist/components/separator.d.ts +6 -0
  94. package/dist/components/separator.js +25 -0
  95. package/dist/components/sheet.d.ts +29 -0
  96. package/dist/components/sheet.js +96 -0
  97. package/dist/components/skeleton-card.d.ts +13 -0
  98. package/dist/components/skeleton-card.js +154 -0
  99. package/dist/components/skeleton.d.ts +6 -0
  100. package/dist/components/skeleton.js +3 -0
  101. package/dist/components/slider.d.ts +6 -0
  102. package/dist/components/slider.js +24 -0
  103. package/dist/components/sliding-panels.d.ts +19 -0
  104. package/dist/components/sliding-panels.js +75 -0
  105. package/dist/components/sonner.d.ts +6 -0
  106. package/dist/components/sonner.js +23 -0
  107. package/dist/components/sticky-container.d.ts +44 -0
  108. package/dist/components/sticky-container.js +39 -0
  109. package/dist/components/switch.d.ts +6 -0
  110. package/dist/components/switch.js +31 -0
  111. package/dist/components/table.d.ts +12 -0
  112. package/dist/components/table.js +81 -0
  113. package/dist/components/tabs.d.ts +12 -0
  114. package/dist/components/tabs.js +55 -0
  115. package/dist/components/text.d.ts +31 -0
  116. package/dist/components/text.js +3 -0
  117. package/dist/components/textarea.d.ts +6 -0
  118. package/dist/components/textarea.js +23 -0
  119. package/dist/components/toast.d.ts +18 -0
  120. package/dist/components/toast.js +3 -0
  121. package/dist/components/toaster.d.ts +5 -0
  122. package/dist/components/toaster.js +25 -0
  123. package/dist/components/toggle-group.d.ts +12 -0
  124. package/dist/components/toggle-group.js +72 -0
  125. package/dist/components/toggle.d.ts +13 -0
  126. package/dist/components/toggle.js +3 -0
  127. package/dist/components/tooltip.d.ts +9 -0
  128. package/dist/components/tooltip.js +26 -0
  129. package/dist/components/use-mobile.d.ts +3 -0
  130. package/dist/components/use-mobile.js +19 -0
  131. package/dist/components/use-toast.d.ts +42 -0
  132. package/dist/components/use-toast.js +2 -0
  133. package/dist/hooks/use-haptic.d.ts +22 -0
  134. package/dist/hooks/use-haptic.js +2 -0
  135. package/dist/hooks/use-mobile.d.ts +3 -0
  136. package/dist/hooks/use-mobile.js +19 -0
  137. package/dist/hooks/use-mounted-theme.d.ts +6 -0
  138. package/dist/hooks/use-mounted-theme.js +18 -0
  139. package/dist/hooks/use-sticky.d.ts +18 -0
  140. package/dist/hooks/use-sticky.js +2 -0
  141. package/dist/lib/utils.d.ts +5 -0
  142. package/dist/lib/utils.js +2 -0
  143. package/package.json +203 -0
  144. package/src/components/accordion.tsx +57 -0
  145. package/src/components/alert-dialog.tsx +116 -0
  146. package/src/components/alert.tsx +57 -0
  147. package/src/components/aspect-ratio.tsx +9 -0
  148. package/src/components/avatar.tsx +49 -0
  149. package/src/components/badge.tsx +38 -0
  150. package/src/components/breadcrumb.tsx +102 -0
  151. package/src/components/button.tsx +94 -0
  152. package/src/components/calendar.tsx +60 -0
  153. package/src/components/card.tsx +67 -0
  154. package/src/components/carousel.tsx +230 -0
  155. package/src/components/checkbox.tsx +27 -0
  156. package/src/components/collapsible.tsx +28 -0
  157. package/src/components/command.tsx +148 -0
  158. package/src/components/currency-input.tsx +158 -0
  159. package/src/components/dialog.tsx +103 -0
  160. package/src/components/drawer.tsx +99 -0
  161. package/src/components/dropdown-menu.tsx +228 -0
  162. package/src/components/empty-state.tsx +118 -0
  163. package/src/components/form.tsx +152 -0
  164. package/src/components/haptic-button.tsx +19 -0
  165. package/src/components/input-otp.tsx +70 -0
  166. package/src/components/input.tsx +23 -0
  167. package/src/components/label.tsx +20 -0
  168. package/src/components/lazy-markdown.tsx +20 -0
  169. package/src/components/link-button.tsx +40 -0
  170. package/src/components/markdown-renderer.tsx +20 -0
  171. package/src/components/multi-select-combobox.tsx +148 -0
  172. package/src/components/pagination.tsx +106 -0
  173. package/src/components/popover.tsx +30 -0
  174. package/src/components/progress.tsx +27 -0
  175. package/src/components/radio-group.tsx +37 -0
  176. package/src/components/rating.tsx +136 -0
  177. package/src/components/scroll-area.tsx +45 -0
  178. package/src/components/search-bar.tsx +113 -0
  179. package/src/components/searchable-select.tsx +134 -0
  180. package/src/components/select.tsx +152 -0
  181. package/src/components/separator.tsx +25 -0
  182. package/src/components/sheet.tsx +121 -0
  183. package/src/components/skeleton-card.tsx +282 -0
  184. package/src/components/skeleton.tsx +17 -0
  185. package/src/components/slider.tsx +24 -0
  186. package/src/components/sliding-panels.tsx +99 -0
  187. package/src/components/sonner.tsx +25 -0
  188. package/src/components/sticky-container.tsx +88 -0
  189. package/src/components/switch.tsx +28 -0
  190. package/src/components/table.tsx +90 -0
  191. package/src/components/tabs.tsx +72 -0
  192. package/src/components/text.test.tsx +192 -0
  193. package/src/components/text.tsx +114 -0
  194. package/src/components/textarea.tsx +22 -0
  195. package/src/components/toast.tsx +129 -0
  196. package/src/components/toaster.tsx +31 -0
  197. package/src/components/toggle-group.tsx +69 -0
  198. package/src/components/toggle.tsx +46 -0
  199. package/src/components/tooltip.tsx +29 -0
  200. package/src/components/use-mobile.tsx +19 -0
  201. package/src/components/use-toast.ts +180 -0
  202. package/src/globals.css +409 -0
  203. package/src/hooks/use-haptic.ts +118 -0
  204. package/src/hooks/use-mobile.ts +19 -0
  205. package/src/hooks/use-mounted-theme.ts +20 -0
  206. package/src/hooks/use-sticky.ts +47 -0
  207. package/src/lib/utils.ts +6 -0
@@ -0,0 +1,148 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import type { DialogProps } from "@radix-ui/react-dialog";
5
+ import { Command as CommandPrimitive } from "cmdk";
6
+ import { Search } from "lucide-react";
7
+ import { cn } from "../lib/utils";
8
+ import { Dialog, DialogContent } from "./dialog";
9
+
10
+ const Command = React.forwardRef<
11
+ React.ElementRef<typeof CommandPrimitive>,
12
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive>
13
+ >(({ className, ...props }, ref) => (
14
+ <CommandPrimitive
15
+ ref={ref}
16
+ className={cn(
17
+ "flex h-full w-full flex-col overflow-hidden rounded-xl glass border border-border/50",
18
+ className
19
+ )}
20
+ {...props}
21
+ />
22
+ ));
23
+ Command.displayName = CommandPrimitive.displayName;
24
+
25
+ type CommandDialogProps = DialogProps;
26
+
27
+ const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
28
+ return (
29
+ <Dialog {...props}>
30
+ <DialogContent className="overflow-hidden p-0 shadow-2xl">
31
+ <Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[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">
32
+ {children}
33
+ </Command>
34
+ </DialogContent>
35
+ </Dialog>
36
+ );
37
+ };
38
+
39
+ const CommandInput = React.forwardRef<
40
+ React.ElementRef<typeof CommandPrimitive.Input>,
41
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
42
+ >(({ className, ...props }, ref) => (
43
+ <div className="flex items-center border-b border-border/50 px-3" cmdk-input-wrapper="">
44
+ <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
45
+ <CommandPrimitive.Input
46
+ ref={ref}
47
+ className={cn(
48
+ "flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50",
49
+ className
50
+ )}
51
+ {...props}
52
+ />
53
+ </div>
54
+ ));
55
+
56
+ CommandInput.displayName = CommandPrimitive.Input.displayName;
57
+
58
+ const CommandList = React.forwardRef<
59
+ React.ElementRef<typeof CommandPrimitive.List>,
60
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
61
+ >(({ className, ...props }, ref) => (
62
+ <CommandPrimitive.List
63
+ ref={ref}
64
+ className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
65
+ {...props}
66
+ />
67
+ ));
68
+
69
+ CommandList.displayName = CommandPrimitive.List.displayName;
70
+
71
+ const CommandEmpty = React.forwardRef<
72
+ React.ElementRef<typeof CommandPrimitive.Empty>,
73
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
74
+ >(({ className, ...props }, ref) => (
75
+ <CommandPrimitive.Empty
76
+ ref={ref}
77
+ className={cn("py-6 text-center text-sm", className)}
78
+ {...props}
79
+ />
80
+ ));
81
+
82
+ CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
83
+
84
+ const CommandGroup = React.forwardRef<
85
+ React.ElementRef<typeof CommandPrimitive.Group>,
86
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
87
+ >(({ className, ...props }, ref) => (
88
+ <CommandPrimitive.Group
89
+ ref={ref}
90
+ className={cn(
91
+ "overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground",
92
+ className
93
+ )}
94
+ {...props}
95
+ />
96
+ ));
97
+
98
+ CommandGroup.displayName = CommandPrimitive.Group.displayName;
99
+
100
+ const CommandSeparator = React.forwardRef<
101
+ React.ElementRef<typeof CommandPrimitive.Separator>,
102
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
103
+ >(({ className, ...props }, ref) => (
104
+ <CommandPrimitive.Separator
105
+ ref={ref}
106
+ className={cn("-mx-1 h-px bg-border", className)}
107
+ {...props}
108
+ />
109
+ ));
110
+ CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
111
+
112
+ const CommandItem = React.forwardRef<
113
+ React.ElementRef<typeof CommandPrimitive.Item>,
114
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
115
+ >(({ className, ...props }, ref) => (
116
+ <CommandPrimitive.Item
117
+ ref={ref}
118
+ className={cn(
119
+ "relative flex cursor-default select-none items-center rounded-lg px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 transition-all duration-200 hover:bg-accent/50",
120
+ className
121
+ )}
122
+ {...props}
123
+ />
124
+ ));
125
+
126
+ CommandItem.displayName = CommandPrimitive.Item.displayName;
127
+
128
+ const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
129
+ return (
130
+ <span
131
+ className={cn("ml-auto text-xs tracking-widest text-muted-foreground", className)}
132
+ {...props}
133
+ />
134
+ );
135
+ };
136
+ CommandShortcut.displayName = "CommandShortcut";
137
+
138
+ export {
139
+ Command,
140
+ CommandDialog,
141
+ CommandInput,
142
+ CommandList,
143
+ CommandEmpty,
144
+ CommandGroup,
145
+ CommandItem,
146
+ CommandShortcut,
147
+ CommandSeparator,
148
+ };
@@ -0,0 +1,158 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { cn } from "../lib/utils";
5
+ import { Input } from "./input";
6
+
7
+ interface CurrencyInputProps {
8
+ value: number | null;
9
+ onChange: (value: number | null) => void;
10
+ placeholder?: string;
11
+ currency?: string; // default '$'
12
+ locale?: string; // default 'en-US'
13
+ min?: number;
14
+ max?: number;
15
+ disabled?: boolean;
16
+ className?: string;
17
+ error?: string;
18
+ }
19
+
20
+ const CurrencyInput = React.forwardRef<HTMLInputElement, CurrencyInputProps>(
21
+ (
22
+ {
23
+ value,
24
+ onChange,
25
+ placeholder = "Enter amount",
26
+ currency: _currency = "$",
27
+ locale = "en-US",
28
+ min,
29
+ max,
30
+ disabled = false,
31
+ className,
32
+ error,
33
+ ...props
34
+ },
35
+ ref
36
+ ) => {
37
+ const [displayValue, setDisplayValue] = React.useState("");
38
+ const [isFocused, setIsFocused] = React.useState(false);
39
+
40
+ // Format number for display
41
+ const formatNumber = (num: number | null): string => {
42
+ if (num === null || isNaN(num)) return "";
43
+ return new Intl.NumberFormat(locale, {
44
+ minimumFractionDigits: 0,
45
+ maximumFractionDigits: 2,
46
+ }).format(num);
47
+ };
48
+
49
+ // Parse input value to number
50
+ const parseInput = (input: string): number | null => {
51
+ // Remove currency symbol and non-numeric characters except decimal point
52
+ const cleaned = input.replace(/[^\d.-]/g, "");
53
+ const parsed = parseFloat(cleaned);
54
+ return isNaN(parsed) ? null : parsed;
55
+ };
56
+
57
+ // Update display value when prop value changes
58
+ React.useEffect(() => {
59
+ if (!isFocused) {
60
+ setDisplayValue(formatNumber(value));
61
+ }
62
+ // formatNumber is inline and recreated each render; locale is the actual dep
63
+ // eslint-disable-next-line react-hooks/exhaustive-deps
64
+ }, [value, isFocused, locale]);
65
+
66
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
67
+ const inputValue = e.target.value;
68
+ setDisplayValue(inputValue);
69
+
70
+ const parsedValue = parseInput(inputValue);
71
+
72
+ // Validate min/max constraints
73
+ if (parsedValue !== null) {
74
+ if (min !== undefined && parsedValue < min) {
75
+ return; // Don't update if below minimum
76
+ }
77
+ if (max !== undefined && parsedValue > max) {
78
+ return; // Don't update if above maximum
79
+ }
80
+ }
81
+
82
+ onChange(parsedValue);
83
+ };
84
+
85
+ const handleFocus = () => {
86
+ setIsFocused(true);
87
+ // Show raw number when focused for easier editing
88
+ if (value !== null && value !== undefined && !isNaN(value)) {
89
+ setDisplayValue(value.toString());
90
+ }
91
+ };
92
+
93
+ const handleBlur = () => {
94
+ setIsFocused(false);
95
+ // Format the value when losing focus
96
+ if (value !== null && value !== undefined && !isNaN(value)) {
97
+ setDisplayValue(formatNumber(value));
98
+ } else {
99
+ setDisplayValue("");
100
+ }
101
+ };
102
+
103
+ const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
104
+ // Allow: backspace, delete, tab, escape, enter, home, end, left, right, up, down
105
+ if ([8, 9, 27, 13, 46, 35, 36, 37, 38, 39, 40].includes(e.keyCode)) {
106
+ return;
107
+ }
108
+
109
+ // Allow: Ctrl+A, Ctrl+C, Ctrl+V, Ctrl+X, Ctrl+Z
110
+ if ((e.ctrlKey || e.metaKey) && [65, 67, 86, 88, 90].includes(e.keyCode)) {
111
+ return;
112
+ }
113
+
114
+ // Allow: numbers, decimal point, minus sign
115
+ if (
116
+ (e.keyCode >= 48 && e.keyCode <= 57) || // 0-9
117
+ (e.keyCode >= 96 && e.keyCode <= 105) || // numpad 0-9
118
+ e.keyCode === 190 ||
119
+ e.keyCode === 110 || // decimal point
120
+ e.keyCode === 189 ||
121
+ e.keyCode === 109
122
+ ) {
123
+ // minus sign
124
+ return;
125
+ }
126
+
127
+ // Prevent all other keys
128
+ e.preventDefault();
129
+ };
130
+
131
+ return (
132
+ <div className="relative">
133
+ <Input
134
+ ref={ref}
135
+ type="text"
136
+ value={displayValue}
137
+ onChange={handleInputChange}
138
+ onFocus={handleFocus}
139
+ onBlur={handleBlur}
140
+ onKeyDown={handleKeyDown}
141
+ placeholder={placeholder}
142
+ disabled={disabled}
143
+ className={cn(
144
+ "pl-8", // Space for currency symbol
145
+ error && "border-destructive focus-visible:ring-destructive",
146
+ className
147
+ )}
148
+ {...props}
149
+ />
150
+ {error && <p className="text-sm text-destructive mt-1 ml-1">{error}</p>}
151
+ </div>
152
+ );
153
+ }
154
+ );
155
+
156
+ CurrencyInput.displayName = "CurrencyInput";
157
+
158
+ export { CurrencyInput };
@@ -0,0 +1,103 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as DialogPrimitive from "@radix-ui/react-dialog";
5
+ import { X } from "lucide-react";
6
+ import { cn } from "../lib/utils";
7
+
8
+ const Dialog = DialogPrimitive.Root;
9
+
10
+ const DialogTrigger = DialogPrimitive.Trigger;
11
+
12
+ const DialogPortal = DialogPrimitive.Portal;
13
+
14
+ const DialogClose = DialogPrimitive.Close;
15
+
16
+ const DialogOverlay = React.forwardRef<
17
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
18
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
19
+ >(({ className, ...props }, ref) => (
20
+ <DialogPrimitive.Overlay
21
+ ref={ref}
22
+ className={cn(
23
+ "fixed inset-0 z-[1000] bg-black/50 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ ));
29
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
30
+
31
+ const DialogContent = React.forwardRef<
32
+ React.ElementRef<typeof DialogPrimitive.Content>,
33
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
34
+ >(({ className, children, ...props }, ref) => (
35
+ <DialogPortal>
36
+ <DialogOverlay />
37
+ <DialogPrimitive.Content
38
+ ref={ref}
39
+ className={cn(
40
+ "fixed left-[50%] top-[50%] z-[1000] grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 bg-card p-6 shadow-2xl duration-300 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 rounded-2xl border border-border",
41
+ className
42
+ )}
43
+ {...props}
44
+ >
45
+ {children}
46
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-lg opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground hover:bg-muted p-2">
47
+ <X className="h-4 w-4" />
48
+ <span className="sr-only">Close</span>
49
+ </DialogPrimitive.Close>
50
+ </DialogPrimitive.Content>
51
+ </DialogPortal>
52
+ ));
53
+ DialogContent.displayName = DialogPrimitive.Content.displayName;
54
+
55
+ const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
56
+ <div className={cn("flex flex-col space-y-1.5 text-center sm:text-left", className)} {...props} />
57
+ );
58
+ DialogHeader.displayName = "DialogHeader";
59
+
60
+ const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
61
+ <div
62
+ className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
63
+ {...props}
64
+ />
65
+ );
66
+ DialogFooter.displayName = "DialogFooter";
67
+
68
+ const DialogTitle = React.forwardRef<
69
+ React.ElementRef<typeof DialogPrimitive.Title>,
70
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
71
+ >(({ className, ...props }, ref) => (
72
+ <DialogPrimitive.Title
73
+ ref={ref}
74
+ className={cn("text-lg font-semibold leading-none tracking-tight", className)}
75
+ {...props}
76
+ />
77
+ ));
78
+ DialogTitle.displayName = DialogPrimitive.Title.displayName;
79
+
80
+ const DialogDescription = React.forwardRef<
81
+ React.ElementRef<typeof DialogPrimitive.Description>,
82
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
83
+ >(({ className, ...props }, ref) => (
84
+ <DialogPrimitive.Description
85
+ ref={ref}
86
+ className={cn("text-sm text-muted-foreground", className)}
87
+ {...props}
88
+ />
89
+ ));
90
+ DialogDescription.displayName = DialogPrimitive.Description.displayName;
91
+
92
+ export {
93
+ Dialog,
94
+ DialogPortal,
95
+ DialogOverlay,
96
+ DialogTrigger,
97
+ DialogClose,
98
+ DialogContent,
99
+ DialogHeader,
100
+ DialogFooter,
101
+ DialogTitle,
102
+ DialogDescription,
103
+ };
@@ -0,0 +1,99 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Drawer as DrawerPrimitive } from "vaul";
5
+ import { cn } from "../lib/utils";
6
+
7
+ const Drawer = ({
8
+ shouldScaleBackground = false,
9
+ ...props
10
+ }: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
11
+ <DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />
12
+ );
13
+ Drawer.displayName = "Drawer";
14
+
15
+ const DrawerTrigger = DrawerPrimitive.Trigger;
16
+
17
+ const DrawerPortal = DrawerPrimitive.Portal;
18
+
19
+ const DrawerClose = DrawerPrimitive.Close;
20
+
21
+ const DrawerOverlay = React.forwardRef<
22
+ React.ElementRef<typeof DrawerPrimitive.Overlay>,
23
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
24
+ >(({ className, ...props }, ref) => (
25
+ <DrawerPrimitive.Overlay
26
+ ref={ref}
27
+ className={cn("fixed inset-0 z-[1000] bg-black/60", className)}
28
+ {...props}
29
+ />
30
+ ));
31
+ DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
32
+
33
+ const DrawerContent = React.forwardRef<
34
+ React.ElementRef<typeof DrawerPrimitive.Content>,
35
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
36
+ >(({ className, children, ...props }, ref) => (
37
+ <DrawerPortal>
38
+ <DrawerOverlay />
39
+ <DrawerPrimitive.Content
40
+ ref={ref}
41
+ className={cn(
42
+ "fixed inset-x-0 bottom-0 z-[1000] flex h-auto max-h-[90vh] flex-col rounded-t-2xl bg-surface border-t border-border shadow-2xl",
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ <div className="mx-auto mt-4 h-2 w-[100px] rounded-full dark:bg-muted bg-primary" />
48
+ {children}
49
+ </DrawerPrimitive.Content>
50
+ </DrawerPortal>
51
+ ));
52
+ DrawerContent.displayName = "DrawerContent";
53
+
54
+ const DrawerHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
55
+ <div className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)} {...props} />
56
+ );
57
+ DrawerHeader.displayName = "DrawerHeader";
58
+
59
+ const DrawerFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
60
+ <div className={cn("mt-auto flex flex-col gap-2 p-4", className)} {...props} />
61
+ );
62
+ DrawerFooter.displayName = "DrawerFooter";
63
+
64
+ const DrawerTitle = React.forwardRef<
65
+ React.ElementRef<typeof DrawerPrimitive.Title>,
66
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
67
+ >(({ className, ...props }, ref) => (
68
+ <DrawerPrimitive.Title
69
+ ref={ref}
70
+ className={cn("text-lg font-semibold leading-none tracking-tight", className)}
71
+ {...props}
72
+ />
73
+ ));
74
+ DrawerTitle.displayName = DrawerPrimitive.Title.displayName;
75
+
76
+ const DrawerDescription = React.forwardRef<
77
+ React.ElementRef<typeof DrawerPrimitive.Description>,
78
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
79
+ >(({ className, ...props }, ref) => (
80
+ <DrawerPrimitive.Description
81
+ ref={ref}
82
+ className={cn("text-sm dark:text-muted-foreground light:text-dark", className)}
83
+ {...props}
84
+ />
85
+ ));
86
+ DrawerDescription.displayName = DrawerPrimitive.Description.displayName;
87
+
88
+ export {
89
+ Drawer,
90
+ DrawerPortal,
91
+ DrawerOverlay,
92
+ DrawerTrigger,
93
+ DrawerClose,
94
+ DrawerContent,
95
+ DrawerHeader,
96
+ DrawerFooter,
97
+ DrawerTitle,
98
+ DrawerDescription,
99
+ };