@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.
- package/dist/chunk-2CUFS5LF.js +80 -0
- package/dist/chunk-3GWWZKX7.js +33 -0
- package/dist/chunk-3VMDCCCX.js +10 -0
- package/dist/chunk-4AVS6CV4.js +89 -0
- package/dist/chunk-4JOV7FXW.js +17 -0
- package/dist/chunk-4KOMHDZD.js +89 -0
- package/dist/chunk-4UO73SKC.js +26 -0
- package/dist/chunk-7H54PTVH.js +116 -0
- package/dist/chunk-CW24PLDW.js +24 -0
- package/dist/chunk-EBAMCZDW.js +112 -0
- package/dist/chunk-ERMIA7NP.js +106 -0
- package/dist/chunk-ESO2EM3L.js +46 -0
- package/dist/chunk-EUHEIWHZ.js +32 -0
- package/dist/chunk-FEK5XGZW.js +8 -0
- package/dist/chunk-NKHH23YK.js +31 -0
- package/dist/chunk-R47NEOSI.js +78 -0
- package/dist/chunk-UXAYXRFN.js +69 -0
- package/dist/chunk-X6GATUI2.js +19 -0
- package/dist/components/accordion.d.ts +9 -0
- package/dist/components/accordion.js +53 -0
- package/dist/components/alert-dialog.d.ts +23 -0
- package/dist/components/alert-dialog.js +98 -0
- package/dist/components/alert.d.ts +11 -0
- package/dist/components/alert.js +52 -0
- package/dist/components/aspect-ratio.d.ts +6 -0
- package/dist/components/aspect-ratio.js +2 -0
- package/dist/components/avatar.d.ts +8 -0
- package/dist/components/avatar.js +47 -0
- package/dist/components/badge.d.ts +13 -0
- package/dist/components/badge.js +3 -0
- package/dist/components/breadcrumb.d.ts +14 -0
- package/dist/components/breadcrumb.js +96 -0
- package/dist/components/button.d.ts +16 -0
- package/dist/components/button.js +4 -0
- package/dist/components/calendar.d.ts +11 -0
- package/dist/components/calendar.js +56 -0
- package/dist/components/card.d.ts +13 -0
- package/dist/components/card.js +4 -0
- package/dist/components/carousel.d.ts +24 -0
- package/dist/components/carousel.js +198 -0
- package/dist/components/checkbox.d.ts +6 -0
- package/dist/components/checkbox.js +25 -0
- package/dist/components/collapsible.d.ts +8 -0
- package/dist/components/collapsible.js +26 -0
- package/dist/components/command.d.ts +84 -0
- package/dist/components/command.js +4 -0
- package/dist/components/currency-input.d.ts +17 -0
- package/dist/components/currency-input.js +121 -0
- package/dist/components/dialog.d.ts +22 -0
- package/dist/components/dialog.js +3 -0
- package/dist/components/drawer.d.ts +27 -0
- package/dist/components/drawer.js +85 -0
- package/dist/components/dropdown-menu.d.ts +28 -0
- package/dist/components/dropdown-menu.js +211 -0
- package/dist/components/empty-state.d.ts +22 -0
- package/dist/components/empty-state.js +81 -0
- package/dist/components/form.d.ts +28 -0
- package/dist/components/form.js +97 -0
- package/dist/components/haptic-button.d.ts +12 -0
- package/dist/components/haptic-button.js +17 -0
- package/dist/components/input-otp.d.ts +14 -0
- package/dist/components/input-otp.js +62 -0
- package/dist/components/input.d.ts +6 -0
- package/dist/components/input.js +3 -0
- package/dist/components/label.d.ts +8 -0
- package/dist/components/label.js +3 -0
- package/dist/components/lazy-markdown.d.ts +11 -0
- package/dist/components/lazy-markdown.js +13 -0
- package/dist/components/link-button.d.ts +30 -0
- package/dist/components/link-button.js +17 -0
- package/dist/components/markdown-renderer.d.ts +11 -0
- package/dist/components/markdown-renderer.js +10 -0
- package/dist/components/multi-select-combobox.d.ts +23 -0
- package/dist/components/multi-select-combobox.js +114 -0
- package/dist/components/pagination.d.ts +18 -0
- package/dist/components/pagination.js +101 -0
- package/dist/components/popover.d.ts +8 -0
- package/dist/components/popover.js +3 -0
- package/dist/components/progress.d.ts +6 -0
- package/dist/components/progress.js +30 -0
- package/dist/components/radio-group.d.ts +7 -0
- package/dist/components/radio-group.js +30 -0
- package/dist/components/rating.d.ts +15 -0
- package/dist/components/rating.js +120 -0
- package/dist/components/scroll-area.d.ts +7 -0
- package/dist/components/scroll-area.js +44 -0
- package/dist/components/search-bar.d.ts +17 -0
- package/dist/components/search-bar.js +92 -0
- package/dist/components/searchable-select.d.ts +22 -0
- package/dist/components/searchable-select.js +104 -0
- package/dist/components/select.d.ts +15 -0
- package/dist/components/select.js +129 -0
- package/dist/components/separator.d.ts +6 -0
- package/dist/components/separator.js +25 -0
- package/dist/components/sheet.d.ts +29 -0
- package/dist/components/sheet.js +96 -0
- package/dist/components/skeleton-card.d.ts +13 -0
- package/dist/components/skeleton-card.js +154 -0
- package/dist/components/skeleton.d.ts +6 -0
- package/dist/components/skeleton.js +3 -0
- package/dist/components/slider.d.ts +6 -0
- package/dist/components/slider.js +24 -0
- package/dist/components/sliding-panels.d.ts +19 -0
- package/dist/components/sliding-panels.js +75 -0
- package/dist/components/sonner.d.ts +6 -0
- package/dist/components/sonner.js +23 -0
- package/dist/components/sticky-container.d.ts +44 -0
- package/dist/components/sticky-container.js +39 -0
- package/dist/components/switch.d.ts +6 -0
- package/dist/components/switch.js +31 -0
- package/dist/components/table.d.ts +12 -0
- package/dist/components/table.js +81 -0
- package/dist/components/tabs.d.ts +12 -0
- package/dist/components/tabs.js +55 -0
- package/dist/components/text.d.ts +31 -0
- package/dist/components/text.js +3 -0
- package/dist/components/textarea.d.ts +6 -0
- package/dist/components/textarea.js +23 -0
- package/dist/components/toast.d.ts +18 -0
- package/dist/components/toast.js +3 -0
- package/dist/components/toaster.d.ts +5 -0
- package/dist/components/toaster.js +25 -0
- package/dist/components/toggle-group.d.ts +12 -0
- package/dist/components/toggle-group.js +72 -0
- package/dist/components/toggle.d.ts +13 -0
- package/dist/components/toggle.js +3 -0
- package/dist/components/tooltip.d.ts +9 -0
- package/dist/components/tooltip.js +26 -0
- package/dist/components/use-mobile.d.ts +3 -0
- package/dist/components/use-mobile.js +19 -0
- package/dist/components/use-toast.d.ts +42 -0
- package/dist/components/use-toast.js +2 -0
- package/dist/hooks/use-haptic.d.ts +22 -0
- package/dist/hooks/use-haptic.js +2 -0
- package/dist/hooks/use-mobile.d.ts +3 -0
- package/dist/hooks/use-mobile.js +19 -0
- package/dist/hooks/use-mounted-theme.d.ts +6 -0
- package/dist/hooks/use-mounted-theme.js +18 -0
- package/dist/hooks/use-sticky.d.ts +18 -0
- package/dist/hooks/use-sticky.js +2 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +2 -0
- package/package.json +203 -0
- package/src/components/accordion.tsx +57 -0
- package/src/components/alert-dialog.tsx +116 -0
- package/src/components/alert.tsx +57 -0
- package/src/components/aspect-ratio.tsx +9 -0
- package/src/components/avatar.tsx +49 -0
- package/src/components/badge.tsx +38 -0
- package/src/components/breadcrumb.tsx +102 -0
- package/src/components/button.tsx +94 -0
- package/src/components/calendar.tsx +60 -0
- package/src/components/card.tsx +67 -0
- package/src/components/carousel.tsx +230 -0
- package/src/components/checkbox.tsx +27 -0
- package/src/components/collapsible.tsx +28 -0
- package/src/components/command.tsx +148 -0
- package/src/components/currency-input.tsx +158 -0
- package/src/components/dialog.tsx +103 -0
- package/src/components/drawer.tsx +99 -0
- package/src/components/dropdown-menu.tsx +228 -0
- package/src/components/empty-state.tsx +118 -0
- package/src/components/form.tsx +152 -0
- package/src/components/haptic-button.tsx +19 -0
- package/src/components/input-otp.tsx +70 -0
- package/src/components/input.tsx +23 -0
- package/src/components/label.tsx +20 -0
- package/src/components/lazy-markdown.tsx +20 -0
- package/src/components/link-button.tsx +40 -0
- package/src/components/markdown-renderer.tsx +20 -0
- package/src/components/multi-select-combobox.tsx +148 -0
- package/src/components/pagination.tsx +106 -0
- package/src/components/popover.tsx +30 -0
- package/src/components/progress.tsx +27 -0
- package/src/components/radio-group.tsx +37 -0
- package/src/components/rating.tsx +136 -0
- package/src/components/scroll-area.tsx +45 -0
- package/src/components/search-bar.tsx +113 -0
- package/src/components/searchable-select.tsx +134 -0
- package/src/components/select.tsx +152 -0
- package/src/components/separator.tsx +25 -0
- package/src/components/sheet.tsx +121 -0
- package/src/components/skeleton-card.tsx +282 -0
- package/src/components/skeleton.tsx +17 -0
- package/src/components/slider.tsx +24 -0
- package/src/components/sliding-panels.tsx +99 -0
- package/src/components/sonner.tsx +25 -0
- package/src/components/sticky-container.tsx +88 -0
- package/src/components/switch.tsx +28 -0
- package/src/components/table.tsx +90 -0
- package/src/components/tabs.tsx +72 -0
- package/src/components/text.test.tsx +192 -0
- package/src/components/text.tsx +114 -0
- package/src/components/textarea.tsx +22 -0
- package/src/components/toast.tsx +129 -0
- package/src/components/toaster.tsx +31 -0
- package/src/components/toggle-group.tsx +69 -0
- package/src/components/toggle.tsx +46 -0
- package/src/components/tooltip.tsx +29 -0
- package/src/components/use-mobile.tsx +19 -0
- package/src/components/use-toast.ts +180 -0
- package/src/globals.css +409 -0
- package/src/hooks/use-haptic.ts +118 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/hooks/use-mounted-theme.ts +20 -0
- package/src/hooks/use-sticky.ts +47 -0
- 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
|
+
};
|