@sonamu-kit/react-components 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/dist/components/index.d.ts +65 -0
  2. package/dist/components/ui/accordion.d.ts +7 -0
  3. package/dist/components/ui/alert-dialog.d.ts +20 -0
  4. package/dist/components/ui/alert.d.ts +8 -0
  5. package/dist/components/ui/aspect-ratio.d.ts +3 -0
  6. package/dist/components/ui/async-select.d.ts +36 -0
  7. package/dist/components/ui/avatar.d.ts +6 -0
  8. package/dist/components/ui/badge.d.ts +9 -0
  9. package/dist/components/ui/breadcrumb.d.ts +19 -0
  10. package/dist/components/ui/button.d.ts +13 -0
  11. package/dist/components/ui/calendar.d.ts +5 -0
  12. package/dist/components/ui/card.d.ts +9 -0
  13. package/dist/components/ui/carousel.d.ts +18 -0
  14. package/dist/components/ui/checkbox.d.ts +8 -0
  15. package/dist/components/ui/collapsible.d.ts +5 -0
  16. package/dist/components/ui/combobox.d.ts +20 -0
  17. package/dist/components/ui/command.d.ts +80 -0
  18. package/dist/components/ui/common-modal.d.ts +28 -0
  19. package/dist/components/ui/context-menu.d.ts +27 -0
  20. package/dist/components/ui/date-input.d.ts +7 -0
  21. package/dist/components/ui/date-picker.d.ts +26 -0
  22. package/dist/components/ui/date-selector-multiple.d.ts +38 -0
  23. package/dist/components/ui/dialog.d.ts +19 -0
  24. package/dist/components/ui/drawer.d.ts +22 -0
  25. package/dist/components/ui/dropdown-menu.d.ts +27 -0
  26. package/dist/components/ui/form.d.ts +23 -0
  27. package/dist/components/ui/hover-card.d.ts +6 -0
  28. package/dist/components/ui/image-uploader.d.ts +14 -0
  29. package/dist/components/ui/input-otp.d.ts +34 -0
  30. package/dist/components/ui/input.d.ts +7 -0
  31. package/dist/components/ui/label.d.ts +5 -0
  32. package/dist/components/ui/menubar.d.ts +28 -0
  33. package/dist/components/ui/month-picker-multiple.d.ts +41 -0
  34. package/dist/components/ui/multi-image-uploader.d.ts +15 -0
  35. package/dist/components/ui/multi-select.d.ts +229 -0
  36. package/dist/components/ui/navigation-menu.d.ts +12 -0
  37. package/dist/components/ui/pagination.d.ts +10 -0
  38. package/dist/components/ui/popover.d.ts +7 -0
  39. package/dist/components/ui/progress.d.ts +4 -0
  40. package/dist/components/ui/radio-group.d.ts +5 -0
  41. package/dist/components/ui/resizable.d.ts +23 -0
  42. package/dist/components/ui/scroll-area.d.ts +5 -0
  43. package/dist/components/ui/select.d.ts +20 -0
  44. package/dist/components/ui/separator.d.ts +4 -0
  45. package/dist/components/ui/sheet.d.ts +25 -0
  46. package/dist/components/ui/sidebar.d.ts +69 -0
  47. package/dist/components/ui/skeleton.d.ts +2 -0
  48. package/dist/components/ui/slider.d.ts +8 -0
  49. package/dist/components/ui/sonner.d.ts +4 -0
  50. package/dist/components/ui/switch.d.ts +8 -0
  51. package/dist/components/ui/table.d.ts +24 -0
  52. package/dist/components/ui/tabs.d.ts +7 -0
  53. package/dist/components/ui/textarea.d.ts +7 -0
  54. package/dist/components/ui/toast.d.ts +15 -0
  55. package/dist/components/ui/toaster.d.ts +1 -0
  56. package/dist/components/ui/toggle-group.d.ts +12 -0
  57. package/dist/components/ui/toggle.d.ts +12 -0
  58. package/dist/components/ui/tooltip.d.ts +7 -0
  59. package/dist/hooks/index.d.ts +1 -0
  60. package/dist/hooks/use-toast.d.ts +44 -0
  61. package/dist/index.d.ts +3 -0
  62. package/dist/lib/caster.d.ts +3 -0
  63. package/dist/lib/helpers.d.ts +72 -0
  64. package/dist/lib/index.d.ts +6 -0
  65. package/{src/lib/lazy-upload.ts → dist/lib/lazy-upload.d.ts} +1 -12
  66. package/dist/lib/use-mobile.d.ts +1 -0
  67. package/dist/lib/utils.d.ts +2 -0
  68. package/dist/react-components.es.js +28375 -0
  69. package/package.json +105 -76
  70. package/COMPONENTS_LIST.md +0 -106
  71. package/COMPONENTS_STATUS.md +0 -114
  72. package/HELPERS_GUIDE.md +0 -489
  73. package/MIGRATION_PLAN.md +0 -404
  74. package/SETUP_GUIDE.md +0 -125
  75. package/components.json +0 -21
  76. package/postcss.config.js +0 -6
  77. package/src/components/index.ts +0 -315
  78. package/src/components/ui/accordion.tsx +0 -54
  79. package/src/components/ui/alert-dialog.tsx +0 -115
  80. package/src/components/ui/alert.tsx +0 -49
  81. package/src/components/ui/aspect-ratio.tsx +0 -5
  82. package/src/components/ui/async-select.tsx +0 -186
  83. package/src/components/ui/avatar.tsx +0 -45
  84. package/src/components/ui/badge.tsx +0 -38
  85. package/src/components/ui/breadcrumb.tsx +0 -102
  86. package/src/components/ui/button.tsx +0 -54
  87. package/src/components/ui/calendar.tsx +0 -193
  88. package/src/components/ui/card.tsx +0 -65
  89. package/src/components/ui/carousel.tsx +0 -243
  90. package/src/components/ui/checkbox.tsx +0 -67
  91. package/src/components/ui/collapsible.tsx +0 -9
  92. package/src/components/ui/combobox.tsx +0 -135
  93. package/src/components/ui/command.tsx +0 -143
  94. package/src/components/ui/common-modal.tsx +0 -95
  95. package/src/components/ui/context-menu.tsx +0 -189
  96. package/src/components/ui/date-picker.tsx +0 -112
  97. package/src/components/ui/date-selector-multiple.tsx +0 -197
  98. package/src/components/ui/dialog.tsx +0 -104
  99. package/src/components/ui/drawer.tsx +0 -100
  100. package/src/components/ui/dropdown-menu.tsx +0 -189
  101. package/src/components/ui/form.tsx +0 -171
  102. package/src/components/ui/hover-card.tsx +0 -27
  103. package/src/components/ui/image-uploader.tsx +0 -251
  104. package/src/components/ui/input-otp.tsx +0 -69
  105. package/src/components/ui/input.tsx +0 -38
  106. package/src/components/ui/label.tsx +0 -19
  107. package/src/components/ui/menubar.tsx +0 -231
  108. package/src/components/ui/month-picker-multiple.tsx +0 -351
  109. package/src/components/ui/multi-image-uploader.tsx +0 -283
  110. package/src/components/ui/multi-select.tsx +0 -1143
  111. package/src/components/ui/navigation-menu.tsx +0 -120
  112. package/src/components/ui/pagination.tsx +0 -72
  113. package/src/components/ui/popover.tsx +0 -42
  114. package/src/components/ui/progress.tsx +0 -25
  115. package/src/components/ui/radio-group.tsx +0 -38
  116. package/src/components/ui/resizable.tsx +0 -42
  117. package/src/components/ui/scroll-area.tsx +0 -46
  118. package/src/components/ui/select.tsx +0 -235
  119. package/src/components/ui/separator.tsx +0 -24
  120. package/src/components/ui/sheet.tsx +0 -119
  121. package/src/components/ui/sidebar.tsx +0 -683
  122. package/src/components/ui/skeleton.tsx +0 -7
  123. package/src/components/ui/slider.tsx +0 -57
  124. package/src/components/ui/sonner.tsx +0 -39
  125. package/src/components/ui/switch.tsx +0 -63
  126. package/src/components/ui/table.tsx +0 -94
  127. package/src/components/ui/tabs.tsx +0 -53
  128. package/src/components/ui/textarea.tsx +0 -34
  129. package/src/components/ui/toast.tsx +0 -122
  130. package/src/components/ui/toaster.tsx +0 -29
  131. package/src/components/ui/toggle-group.tsx +0 -55
  132. package/src/components/ui/toggle.tsx +0 -41
  133. package/src/components/ui/tooltip.tsx +0 -28
  134. package/src/hooks/index.ts +0 -2
  135. package/src/hooks/use-toast.ts +0 -189
  136. package/src/icons.d.ts +0 -1
  137. package/src/index.ts +0 -4
  138. package/src/lib/caster.ts +0 -66
  139. package/src/lib/helpers.ts +0 -394
  140. package/src/lib/index.ts +0 -31
  141. package/src/lib/use-mobile.ts +0 -19
  142. package/src/lib/utils.ts +0 -6
  143. package/src/styles/globals.css +0 -658
  144. package/tailwind.config.ts +0 -8
  145. package/tsconfig.json +0 -31
  146. package/tsconfig.node.json +0 -11
@@ -1,189 +0,0 @@
1
- "use client";
2
-
3
- import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
4
- import * as React from "react";
5
- import CheckIcon from "~icons/lucide/check";
6
- import ChevronRightIcon from "~icons/lucide/chevron-right";
7
- import CircleIcon from "~icons/lucide/circle";
8
-
9
- import { cn } from "../../lib/utils";
10
-
11
- const DropdownMenu = DropdownMenuPrimitive.Root;
12
-
13
- const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
14
-
15
- const DropdownMenuGroup = DropdownMenuPrimitive.Group;
16
-
17
- const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
18
-
19
- const DropdownMenuSub = DropdownMenuPrimitive.Sub;
20
-
21
- const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
22
-
23
- const DropdownMenuSubTrigger = React.forwardRef<
24
- React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
25
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
26
- inset?: boolean;
27
- }
28
- >(({ className, inset, children, ...props }, ref) => (
29
- <DropdownMenuPrimitive.SubTrigger
30
- ref={ref}
31
- className={cn(
32
- "flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
33
- inset && "pl-8",
34
- className,
35
- )}
36
- {...props}
37
- >
38
- {children}
39
- <ChevronRightIcon className="ml-auto" />
40
- </DropdownMenuPrimitive.SubTrigger>
41
- ));
42
- DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName;
43
-
44
- const DropdownMenuSubContent = React.forwardRef<
45
- React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
46
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
47
- >(({ className, ...props }, ref) => (
48
- <DropdownMenuPrimitive.SubContent
49
- ref={ref}
50
- className={cn(
51
- "z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
52
- className,
53
- )}
54
- {...props}
55
- />
56
- ));
57
- DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName;
58
-
59
- const DropdownMenuContent = React.forwardRef<
60
- React.ElementRef<typeof DropdownMenuPrimitive.Content>,
61
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
62
- >(({ className, sideOffset = 4, ...props }, ref) => (
63
- <DropdownMenuPrimitive.Portal>
64
- <DropdownMenuPrimitive.Content
65
- ref={ref}
66
- sideOffset={sideOffset}
67
- className={cn(
68
- "z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-32 overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
69
- className,
70
- )}
71
- {...props}
72
- />
73
- </DropdownMenuPrimitive.Portal>
74
- ));
75
- DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
76
-
77
- const DropdownMenuItem = React.forwardRef<
78
- React.ElementRef<typeof DropdownMenuPrimitive.Item>,
79
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
80
- inset?: boolean;
81
- }
82
- >(({ className, inset, ...props }, ref) => (
83
- <DropdownMenuPrimitive.Item
84
- ref={ref}
85
- className={cn(
86
- "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
87
- inset && "pl-8",
88
- className,
89
- )}
90
- {...props}
91
- />
92
- ));
93
- DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
94
-
95
- const DropdownMenuCheckboxItem = React.forwardRef<
96
- React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
97
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
98
- >(({ className, children, checked, ...props }, ref) => (
99
- <DropdownMenuPrimitive.CheckboxItem
100
- ref={ref}
101
- className={cn(
102
- "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
103
- className,
104
- )}
105
- checked={checked}
106
- {...props}
107
- >
108
- <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
109
- <DropdownMenuPrimitive.ItemIndicator>
110
- <CheckIcon className="h-4 w-4" />
111
- </DropdownMenuPrimitive.ItemIndicator>
112
- </span>
113
- {children}
114
- </DropdownMenuPrimitive.CheckboxItem>
115
- ));
116
- DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName;
117
-
118
- const DropdownMenuRadioItem = React.forwardRef<
119
- React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
120
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
121
- >(({ className, children, ...props }, ref) => (
122
- <DropdownMenuPrimitive.RadioItem
123
- ref={ref}
124
- className={cn(
125
- "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50",
126
- className,
127
- )}
128
- {...props}
129
- >
130
- <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
131
- <DropdownMenuPrimitive.ItemIndicator>
132
- <CircleIcon className="h-2 w-2 fill-current" />
133
- </DropdownMenuPrimitive.ItemIndicator>
134
- </span>
135
- {children}
136
- </DropdownMenuPrimitive.RadioItem>
137
- ));
138
- DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
139
-
140
- const DropdownMenuLabel = React.forwardRef<
141
- React.ElementRef<typeof DropdownMenuPrimitive.Label>,
142
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
143
- inset?: boolean;
144
- }
145
- >(({ className, inset, ...props }, ref) => (
146
- <DropdownMenuPrimitive.Label
147
- ref={ref}
148
- className={cn("px-2 py-1.5 text-sm font-semibold", inset && "pl-8", className)}
149
- {...props}
150
- />
151
- ));
152
- DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
153
-
154
- const DropdownMenuSeparator = React.forwardRef<
155
- React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
156
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
157
- >(({ className, ...props }, ref) => (
158
- <DropdownMenuPrimitive.Separator
159
- ref={ref}
160
- className={cn("-mx-1 my-1 h-px bg-muted", className)}
161
- {...props}
162
- />
163
- ));
164
- DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
165
-
166
- const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
167
- return (
168
- <span className={cn("ml-auto text-xs tracking-widest opacity-60", className)} {...props} />
169
- );
170
- };
171
- DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
172
-
173
- export {
174
- DropdownMenu,
175
- DropdownMenuTrigger,
176
- DropdownMenuContent,
177
- DropdownMenuItem,
178
- DropdownMenuCheckboxItem,
179
- DropdownMenuRadioItem,
180
- DropdownMenuLabel,
181
- DropdownMenuSeparator,
182
- DropdownMenuShortcut,
183
- DropdownMenuGroup,
184
- DropdownMenuPortal,
185
- DropdownMenuSub,
186
- DropdownMenuSubContent,
187
- DropdownMenuSubTrigger,
188
- DropdownMenuRadioGroup,
189
- };
@@ -1,171 +0,0 @@
1
- import type * as LabelPrimitive from "@radix-ui/react-label";
2
- import { Slot } from "@radix-ui/react-slot";
3
- import * as React from "react";
4
- import {
5
- Controller,
6
- type ControllerProps,
7
- type FieldPath,
8
- type FieldValues,
9
- FormProvider,
10
- useFormContext,
11
- } from "react-hook-form";
12
-
13
- import { cn } from "../../lib/utils";
14
- import { Label } from "./label";
15
-
16
- const Form = FormProvider;
17
-
18
- type FormFieldContextValue<
19
- TFieldValues extends FieldValues = FieldValues,
20
- TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
21
- > = {
22
- name: TName;
23
- };
24
-
25
- const FormFieldContext = React.createContext<FormFieldContextValue | null>(null);
26
-
27
- const FormField = <
28
- TFieldValues extends FieldValues = FieldValues,
29
- TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
30
- >({
31
- ...props
32
- }: ControllerProps<TFieldValues, TName>) => {
33
- return (
34
- <FormFieldContext.Provider value={{ name: props.name }}>
35
- <Controller {...props} />
36
- </FormFieldContext.Provider>
37
- );
38
- };
39
-
40
- const useFormField = () => {
41
- const fieldContext = React.useContext(FormFieldContext);
42
- const itemContext = React.useContext(FormItemContext);
43
- const { getFieldState, formState } = useFormContext();
44
-
45
- if (!fieldContext) {
46
- throw new Error("useFormField should be used within <FormField>");
47
- }
48
-
49
- if (!itemContext) {
50
- throw new Error("useFormField should be used within <FormItem>");
51
- }
52
-
53
- const fieldState = getFieldState(fieldContext.name, formState);
54
-
55
- const { id } = itemContext;
56
-
57
- return {
58
- id,
59
- name: fieldContext.name,
60
- formItemId: `${id}-form-item`,
61
- formDescriptionId: `${id}-form-item-description`,
62
- formMessageId: `${id}-form-item-message`,
63
- ...fieldState,
64
- };
65
- };
66
-
67
- type FormItemContextValue = {
68
- id: string;
69
- };
70
-
71
- const FormItemContext = React.createContext<FormItemContextValue | null>(null);
72
-
73
- const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
74
- ({ className, ...props }, ref) => {
75
- const id = React.useId();
76
-
77
- return (
78
- <FormItemContext.Provider value={{ id }}>
79
- <div ref={ref} className={cn("space-y-2", className)} {...props} />
80
- </FormItemContext.Provider>
81
- );
82
- },
83
- );
84
- FormItem.displayName = "FormItem";
85
-
86
- const FormLabel = React.forwardRef<
87
- React.ElementRef<typeof LabelPrimitive.Root>,
88
- React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
89
- >(({ className, ...props }, ref) => {
90
- const { error, formItemId } = useFormField();
91
-
92
- return (
93
- <Label
94
- ref={ref}
95
- className={cn(error && "text-destructive", className)}
96
- htmlFor={formItemId}
97
- {...props}
98
- />
99
- );
100
- });
101
- FormLabel.displayName = "FormLabel";
102
-
103
- const FormControl = React.forwardRef<
104
- React.ElementRef<typeof Slot>,
105
- React.ComponentPropsWithoutRef<typeof Slot>
106
- >(({ ...props }, ref) => {
107
- const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
108
-
109
- return (
110
- <Slot
111
- ref={ref}
112
- id={formItemId}
113
- aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
114
- aria-invalid={!!error}
115
- {...props}
116
- />
117
- );
118
- });
119
- FormControl.displayName = "FormControl";
120
-
121
- const FormDescription = React.forwardRef<
122
- HTMLParagraphElement,
123
- React.HTMLAttributes<HTMLParagraphElement>
124
- >(({ className, ...props }, ref) => {
125
- const { formDescriptionId } = useFormField();
126
-
127
- return (
128
- <p
129
- ref={ref}
130
- id={formDescriptionId}
131
- className={cn("text-sm text-muted-foreground", className)}
132
- {...props}
133
- />
134
- );
135
- });
136
- FormDescription.displayName = "FormDescription";
137
-
138
- const FormMessage = React.forwardRef<
139
- HTMLParagraphElement,
140
- React.HTMLAttributes<HTMLParagraphElement>
141
- >(({ className, children, ...props }, ref) => {
142
- const { error, formMessageId } = useFormField();
143
- const body = error ? String(error?.message ?? "") : children;
144
-
145
- if (!body) {
146
- return null;
147
- }
148
-
149
- return (
150
- <p
151
- ref={ref}
152
- id={formMessageId}
153
- className={cn("text-sm font-medium text-destructive", className)}
154
- {...props}
155
- >
156
- {body}
157
- </p>
158
- );
159
- });
160
- FormMessage.displayName = "FormMessage";
161
-
162
- export {
163
- useFormField,
164
- Form,
165
- FormItem,
166
- FormLabel,
167
- FormControl,
168
- FormDescription,
169
- FormMessage,
170
- FormField,
171
- };
@@ -1,27 +0,0 @@
1
- import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
2
- import * as React from "react";
3
-
4
- import { cn } from "../../lib/utils";
5
-
6
- const HoverCard = HoverCardPrimitive.Root;
7
-
8
- const HoverCardTrigger = HoverCardPrimitive.Trigger;
9
-
10
- const HoverCardContent = React.forwardRef<
11
- React.ElementRef<typeof HoverCardPrimitive.Content>,
12
- React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
13
- >(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
14
- <HoverCardPrimitive.Content
15
- ref={ref}
16
- align={align}
17
- sideOffset={sideOffset}
18
- className={cn(
19
- "z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-hover-card-content-transform-origin]",
20
- className,
21
- )}
22
- {...props}
23
- />
24
- ));
25
- HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
26
-
27
- export { HoverCard, HoverCardTrigger, HoverCardContent };
@@ -1,251 +0,0 @@
1
- import type React from "react";
2
- import { useCallback, useEffect, useRef, useState } from "react";
3
- import Loader2Icon from "~icons/lucide/loader2";
4
- import UploadIcon from "~icons/lucide/upload";
5
- import XIcon from "~icons/lucide/x";
6
- import { cn } from "../../lib/utils";
7
- import { Button } from "./button";
8
-
9
- export type ImageUploaderProps = {
10
- value?: string | null;
11
- onValueChange?: (value: string | null) => void;
12
- onBlur?: React.FocusEventHandler<HTMLInputElement>;
13
- uploader?: (file: File) => Promise<string>;
14
- placeholder?: string;
15
- accept?: string;
16
- disabled?: boolean;
17
- className?: string;
18
- previewSize?: "sm" | "md" | "lg";
19
- mode?: "eager" | "lazy";
20
- };
21
-
22
- export function ImageUploader({
23
- value,
24
- onValueChange,
25
- onBlur,
26
- uploader,
27
- placeholder = "Click to upload image",
28
- accept = "image/*",
29
- disabled = false,
30
- className,
31
- previewSize = "md",
32
- mode = "eager",
33
- }: ImageUploaderProps) {
34
- const inputRef = useRef<HTMLInputElement>(null);
35
- const [isUploading, setIsUploading] = useState(false);
36
- const [dragOver, setDragOver] = useState(false);
37
- const [pendingFile, setPendingFile] = useState<File | null>(null);
38
- const [previewUrl, setPreviewUrl] = useState<string | null>(null);
39
-
40
- const sizeClasses = {
41
- sm: "h-20 w-20",
42
- md: "h-32 w-32",
43
- lg: "h-48 w-48",
44
- };
45
-
46
- const handleFileChange = useCallback(
47
- async (file: File | null) => {
48
- if (!file || disabled) return;
49
-
50
- if (mode === "lazy") {
51
- // Lazy mode: store file and create preview
52
- setPendingFile(file);
53
- const objectUrl = URL.createObjectURL(file);
54
- setPreviewUrl(objectUrl);
55
- onValueChange?.(objectUrl); // Store preview URL temporarily
56
- return;
57
- }
58
-
59
- // Eager mode: upload immediately
60
- if (!uploader) {
61
- console.error("uploader prop is required in eager mode");
62
- return;
63
- }
64
-
65
- setIsUploading(true);
66
- try {
67
- const uploadedUrl = await uploader(file);
68
- onValueChange?.(uploadedUrl);
69
- } catch (error) {
70
- console.error("Upload failed:", error);
71
- } finally {
72
- setIsUploading(false);
73
- }
74
- },
75
- [uploader, onValueChange, disabled, mode],
76
- );
77
-
78
- const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
79
- const file = e.target.files?.[0] ?? null;
80
- handleFileChange(file);
81
- // Reset input value to allow re-uploading same file
82
- e.target.value = "";
83
- };
84
-
85
- const handleDrop = useCallback(
86
- (e: React.DragEvent<HTMLDivElement>) => {
87
- e.preventDefault();
88
- e.stopPropagation();
89
- setDragOver(false);
90
-
91
- const file = e.dataTransfer.files?.[0] ?? null;
92
- handleFileChange(file);
93
- },
94
- [handleFileChange],
95
- );
96
-
97
- const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
98
- e.preventDefault();
99
- e.stopPropagation();
100
- if (!disabled) {
101
- setDragOver(true);
102
- }
103
- };
104
-
105
- const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
106
- e.preventDefault();
107
- e.stopPropagation();
108
- setDragOver(false);
109
- };
110
-
111
- const handleClear = (e: React.MouseEvent) => {
112
- e.preventDefault();
113
- e.stopPropagation();
114
-
115
- // Clean up preview URL if in lazy mode
116
- if (previewUrl && mode === "lazy") {
117
- URL.revokeObjectURL(previewUrl);
118
- setPreviewUrl(null);
119
- setPendingFile(null);
120
- }
121
-
122
- onValueChange?.(null);
123
- };
124
-
125
- // Commit function for lazy mode
126
- const commitUpload = useCallback(async (): Promise<string | null> => {
127
- if (mode !== "lazy" || !pendingFile || !uploader) {
128
- return value || null;
129
- }
130
-
131
- setIsUploading(true);
132
- try {
133
- const uploadedUrl = await uploader(pendingFile);
134
-
135
- // Clean up preview URL
136
- if (previewUrl) {
137
- URL.revokeObjectURL(previewUrl);
138
- setPreviewUrl(null);
139
- }
140
-
141
- setPendingFile(null);
142
- onValueChange?.(uploadedUrl);
143
- return uploadedUrl;
144
- } catch (error) {
145
- console.error("Upload failed:", error);
146
- return null;
147
- } finally {
148
- setIsUploading(false);
149
- }
150
- }, [mode, pendingFile, uploader, value, previewUrl, onValueChange]);
151
-
152
- const handleClick = () => {
153
- if (!disabled && !isUploading) {
154
- inputRef.current?.click();
155
- }
156
- };
157
-
158
- // Listen for commit event in lazy mode
159
- useEffect(() => {
160
- if (mode !== "lazy") return;
161
-
162
- const handleCommit = async (event: Event) => {
163
- const customEvent = event as CustomEvent<{
164
- channel: string;
165
- done: (urls: string[]) => void;
166
- }>;
167
-
168
- if (customEvent.detail?.channel !== "image-uploader") return;
169
-
170
- const result = await commitUpload();
171
- customEvent.detail.done(result ? [result] : []);
172
- };
173
-
174
- document.addEventListener("app:image-uploader/commit", handleCommit);
175
- return () => {
176
- document.removeEventListener("app:image-uploader/commit", handleCommit);
177
- };
178
- }, [mode, commitUpload]);
179
-
180
- // Clean up preview URL on unmount
181
- useEffect(() => {
182
- return () => {
183
- if (previewUrl) {
184
- URL.revokeObjectURL(previewUrl);
185
- }
186
- };
187
- }, [previewUrl]);
188
-
189
- const displayValue = mode === "lazy" && previewUrl ? previewUrl : value;
190
-
191
- return (
192
- <div className={cn("relative inline-block", className)}>
193
- <input
194
- ref={inputRef}
195
- type="file"
196
- accept={accept}
197
- onChange={handleInputChange}
198
- onBlur={onBlur}
199
- disabled={disabled || isUploading}
200
- className="sr-only"
201
- />
202
-
203
- <div
204
- onClick={handleClick}
205
- onDrop={handleDrop}
206
- onDragOver={handleDragOver}
207
- onDragLeave={handleDragLeave}
208
- className={cn(
209
- "relative flex items-center justify-center rounded-lg border-2 border-dashed cursor-pointer transition-all",
210
- sizeClasses[previewSize],
211
- dragOver
212
- ? "border-primary bg-primary/5"
213
- : "border-muted-foreground/25 hover:border-muted-foreground/50",
214
- disabled && "opacity-50 cursor-not-allowed",
215
- isUploading && "cursor-wait",
216
- )}
217
- >
218
- {isUploading ? (
219
- <div className="flex flex-col items-center gap-2 text-muted-foreground">
220
- <Loader2Icon className="h-6 w-6 animate-spin" />
221
- <span className="text-xs">Uploading...</span>
222
- </div>
223
- ) : displayValue ? (
224
- <>
225
- <img
226
- src={displayValue}
227
- alt="Uploaded"
228
- className="h-full w-full object-cover rounded-lg"
229
- />
230
- {!disabled && (
231
- <Button
232
- type="button"
233
- variant="destructive"
234
- size="icon"
235
- className="absolute -top-2 -right-2 h-6 w-6 rounded-full"
236
- onClick={handleClear}
237
- >
238
- <XIcon className="h-3 w-3" />
239
- </Button>
240
- )}
241
- </>
242
- ) : (
243
- <div className="flex flex-col items-center gap-2 text-muted-foreground p-2">
244
- <UploadIcon className="h-6 w-6" />
245
- <span className="text-xs text-center">{placeholder}</span>
246
- </div>
247
- )}
248
- </div>
249
- </div>
250
- );
251
- }
@@ -1,69 +0,0 @@
1
- import { OTPInput, OTPInputContext } from "input-otp";
2
- import * as React from "react";
3
- import DotIcon from "~icons/lucide/dot";
4
-
5
- import { cn } from "../../lib/utils";
6
-
7
- const InputOTP = React.forwardRef<
8
- React.ElementRef<typeof OTPInput>,
9
- React.ComponentPropsWithoutRef<typeof OTPInput>
10
- >(({ className, containerClassName, ...props }, ref) => (
11
- <OTPInput
12
- ref={ref}
13
- containerClassName={cn(
14
- "flex items-center gap-2 has-[:disabled]:opacity-50",
15
- containerClassName,
16
- )}
17
- className={cn("disabled:cursor-not-allowed", className)}
18
- {...props}
19
- />
20
- ));
21
- InputOTP.displayName = "InputOTP";
22
-
23
- const InputOTPGroup = React.forwardRef<
24
- React.ElementRef<"div">,
25
- React.ComponentPropsWithoutRef<"div">
26
- >(({ className, ...props }, ref) => (
27
- <div ref={ref} className={cn("flex items-center", className)} {...props} />
28
- ));
29
- InputOTPGroup.displayName = "InputOTPGroup";
30
-
31
- const InputOTPSlot = React.forwardRef<
32
- React.ElementRef<"div">,
33
- React.ComponentPropsWithoutRef<"div"> & { index: number }
34
- >(({ index, className, ...props }, ref) => {
35
- const inputOTPContext = React.useContext(OTPInputContext);
36
- const { char, hasFakeCaret, isActive } = inputOTPContext.slots[index];
37
-
38
- return (
39
- <div
40
- ref={ref}
41
- className={cn(
42
- "relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md",
43
- isActive && "z-10 ring-2 ring-ring ring-offset-background",
44
- className,
45
- )}
46
- {...props}
47
- >
48
- {char}
49
- {hasFakeCaret && (
50
- <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
51
- <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
52
- </div>
53
- )}
54
- </div>
55
- );
56
- });
57
- InputOTPSlot.displayName = "InputOTPSlot";
58
-
59
- const InputOTPSeparator = React.forwardRef<
60
- React.ElementRef<"div">,
61
- React.ComponentPropsWithoutRef<"div">
62
- >(({ ...props }, ref) => (
63
- <div ref={ref} role="separator" {...props}>
64
- <DotIcon />
65
- </div>
66
- ));
67
- InputOTPSeparator.displayName = "InputOTPSeparator";
68
-
69
- export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };