@blips/ui 0.0.1 → 2.0.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 (60) hide show
  1. package/dist/index.cjs +4308 -2010
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +435 -411
  4. package/dist/index.d.ts +435 -411
  5. package/dist/index.js +4244 -2008
  6. package/dist/index.js.map +1 -1
  7. package/package.json +18 -4
  8. package/src/components/accordion.tsx +58 -48
  9. package/src/components/alert-dialog.tsx +170 -112
  10. package/src/components/alert.tsx +49 -42
  11. package/src/components/aspect-ratio.tsx +9 -3
  12. package/src/components/avatar.tsx +109 -50
  13. package/src/components/badge.tsx +29 -17
  14. package/src/components/breadcrumb.tsx +81 -87
  15. package/src/components/button-group.tsx +83 -0
  16. package/src/components/button.tsx +40 -32
  17. package/src/components/calendar.tsx +49 -45
  18. package/src/components/card.tsx +77 -71
  19. package/src/components/carousel.tsx +150 -168
  20. package/src/components/chart.tsx +357 -0
  21. package/src/components/checkbox.tsx +28 -24
  22. package/src/components/collapsible.tsx +28 -6
  23. package/src/components/command.tsx +144 -110
  24. package/src/components/context-menu.tsx +220 -166
  25. package/src/components/dialog.tsx +131 -95
  26. package/src/components/drawer.tsx +105 -86
  27. package/src/components/dropdown-menu.tsx +234 -177
  28. package/src/components/form.tsx +167 -0
  29. package/src/components/hover-card.tsx +39 -22
  30. package/src/components/input-group.tsx +175 -0
  31. package/src/components/input-otp.tsx +56 -48
  32. package/src/components/input.tsx +18 -19
  33. package/src/components/kbd.tsx +28 -0
  34. package/src/components/label.tsx +20 -22
  35. package/src/components/menubar.tsx +221 -199
  36. package/src/components/navigation-menu.tsx +144 -102
  37. package/src/components/pagination.tsx +102 -91
  38. package/src/components/popover.tsx +86 -26
  39. package/src/components/progress.tsx +27 -24
  40. package/src/components/radio-group.tsx +28 -25
  41. package/src/components/resizable.tsx +42 -34
  42. package/src/components/scroll-area.tsx +54 -42
  43. package/src/components/select.tsx +165 -135
  44. package/src/components/separator.tsx +16 -17
  45. package/src/components/sheet.tsx +116 -113
  46. package/src/components/sidebar.tsx +726 -0
  47. package/src/components/skeleton.tsx +6 -8
  48. package/src/components/slider.tsx +60 -23
  49. package/src/components/sonner.tsx +25 -30
  50. package/src/components/spinner.tsx +16 -0
  51. package/src/components/switch.tsx +30 -22
  52. package/src/components/table.tsx +96 -97
  53. package/src/components/tabs.tsx +91 -53
  54. package/src/components/textarea.tsx +8 -12
  55. package/src/components/toggle-group.tsx +60 -37
  56. package/src/components/toggle.tsx +28 -24
  57. package/src/components/tooltip.tsx +50 -23
  58. package/src/globals.css +230 -68
  59. package/src/hooks/use-mobile.tsx +19 -0
  60. package/src/index.ts +105 -6
@@ -1,200 +1,257 @@
1
- "use client";
2
-
3
- import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
4
- import { Check, ChevronRight, Circle } from "lucide-react";
5
- import * as React from "react";
6
-
7
- import { cn } from "../lib/utils";
8
-
9
- const DropdownMenu = DropdownMenuPrimitive.Root;
10
-
11
- const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
12
-
13
- const DropdownMenuGroup = DropdownMenuPrimitive.Group;
14
-
15
- const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
16
-
17
- const DropdownMenuSub = DropdownMenuPrimitive.Sub;
18
-
19
- const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
20
-
21
- const DropdownMenuSubTrigger = React.forwardRef<
22
- React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
23
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
24
- inset?: boolean;
25
- }
26
- >(({ className, inset, children, ...props }, ref) => (
27
- <DropdownMenuPrimitive.SubTrigger
28
- ref={ref}
29
- className={cn(
30
- "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",
31
- inset && "pl-8",
32
- className
33
- )}
34
- {...props}
35
- >
36
- {children}
37
- <ChevronRight className="ml-auto" />
38
- </DropdownMenuPrimitive.SubTrigger>
39
- ));
40
- DropdownMenuSubTrigger.displayName =
41
- DropdownMenuPrimitive.SubTrigger.displayName;
42
-
43
- const DropdownMenuSubContent = React.forwardRef<
44
- React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
45
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
46
- >(({ className, ...props }, ref) => (
47
- <DropdownMenuPrimitive.SubContent
48
- ref={ref}
49
- className={cn(
50
- "z-50 min-w-[8rem] 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]",
51
- className
52
- )}
53
- {...props}
54
- />
55
- ));
56
- DropdownMenuSubContent.displayName =
57
- 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}
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Check, CaretRight, Circle } from "@phosphor-icons/react"
5
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
6
+
7
+ import { cn } from "../lib/utils"
8
+
9
+ function DropdownMenu({
10
+ ...props
11
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
12
+ return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
13
+ }
14
+
15
+ function DropdownMenuPortal({
16
+ ...props
17
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
18
+ return (
19
+ <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
20
+ )
21
+ }
22
+
23
+ function DropdownMenuTrigger({
24
+ ...props
25
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
26
+ return (
27
+ <DropdownMenuPrimitive.Trigger
28
+ data-slot="dropdown-menu-trigger"
29
+ {...props}
30
+ />
31
+ )
32
+ }
33
+
34
+ function DropdownMenuContent({
35
+ className,
36
+ sideOffset = 4,
37
+ ...props
38
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
39
+ return (
40
+ <DropdownMenuPrimitive.Portal>
41
+ <DropdownMenuPrimitive.Content
42
+ data-slot="dropdown-menu-content"
43
+ sideOffset={sideOffset}
44
+ className={cn(
45
+ "z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
46
+ className
47
+ )}
48
+ {...props}
49
+ />
50
+ </DropdownMenuPrimitive.Portal>
51
+ )
52
+ }
53
+
54
+ function DropdownMenuGroup({
55
+ ...props
56
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
57
+ return (
58
+ <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
59
+ )
60
+ }
61
+
62
+ function DropdownMenuItem({
63
+ className,
64
+ inset,
65
+ variant = "default",
66
+ ...props
67
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
68
+ inset?: boolean
69
+ variant?: "default" | "destructive"
70
+ }) {
71
+ return (
72
+ <DropdownMenuPrimitive.Item
73
+ data-slot="dropdown-menu-item"
74
+ data-inset={inset}
75
+ data-variant={variant}
76
+ className={cn(
77
+ "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",
78
+ className
79
+ )}
80
+ {...props}
81
+ />
82
+ )
83
+ }
84
+
85
+ function DropdownMenuCheckboxItem({
86
+ className,
87
+ children,
88
+ checked,
89
+ ...props
90
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
91
+ return (
92
+ <DropdownMenuPrimitive.CheckboxItem
93
+ data-slot="dropdown-menu-checkbox-item"
94
+ className={cn(
95
+ "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
96
+ className
97
+ )}
98
+ checked={checked}
99
+ {...props}
100
+ >
101
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
102
+ <DropdownMenuPrimitive.ItemIndicator>
103
+ <Check className="size-4" />
104
+ </DropdownMenuPrimitive.ItemIndicator>
105
+ </span>
106
+ {children}
107
+ </DropdownMenuPrimitive.CheckboxItem>
108
+ )
109
+ }
110
+
111
+ function DropdownMenuRadioGroup({
112
+ ...props
113
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
114
+ return (
115
+ <DropdownMenuPrimitive.RadioGroup
116
+ data-slot="dropdown-menu-radio-group"
117
+ {...props}
118
+ />
119
+ )
120
+ }
121
+
122
+ function DropdownMenuRadioItem({
123
+ className,
124
+ children,
125
+ ...props
126
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
127
+ return (
128
+ <DropdownMenuPrimitive.RadioItem
129
+ data-slot="dropdown-menu-radio-item"
130
+ className={cn(
131
+ "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
132
+ className
133
+ )}
134
+ {...props}
135
+ >
136
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
137
+ <DropdownMenuPrimitive.ItemIndicator>
138
+ <Circle className="size-2 fill-current" />
139
+ </DropdownMenuPrimitive.ItemIndicator>
140
+ </span>
141
+ {children}
142
+ </DropdownMenuPrimitive.RadioItem>
143
+ )
144
+ }
145
+
146
+ function DropdownMenuLabel({
147
+ className,
148
+ inset,
149
+ ...props
150
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
151
+ inset?: boolean
152
+ }) {
153
+ return (
154
+ <DropdownMenuPrimitive.Label
155
+ data-slot="dropdown-menu-label"
156
+ data-inset={inset}
67
157
  className={cn(
68
- "z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] 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]",
158
+ "px-2 py-1.5 text-sm font-medium data-[inset]:pl-8",
69
159
  className
70
160
  )}
71
161
  {...props}
72
162
  />
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
- <Check className="h-4 w-4" />
111
- </DropdownMenuPrimitive.ItemIndicator>
112
- </span>
113
- {children}
114
- </DropdownMenuPrimitive.CheckboxItem>
115
- ));
116
- DropdownMenuCheckboxItem.displayName =
117
- DropdownMenuPrimitive.CheckboxItem.displayName;
118
-
119
- const DropdownMenuRadioItem = React.forwardRef<
120
- React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
121
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
122
- >(({ className, children, ...props }, ref) => (
123
- <DropdownMenuPrimitive.RadioItem
124
- ref={ref}
125
- className={cn(
126
- "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",
127
- className
128
- )}
129
- {...props}
130
- >
131
- <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
132
- <DropdownMenuPrimitive.ItemIndicator>
133
- <Circle className="h-2 w-2 fill-current" />
134
- </DropdownMenuPrimitive.ItemIndicator>
135
- </span>
136
- {children}
137
- </DropdownMenuPrimitive.RadioItem>
138
- ));
139
- DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
140
-
141
- const DropdownMenuLabel = React.forwardRef<
142
- React.ElementRef<typeof DropdownMenuPrimitive.Label>,
143
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
144
- inset?: boolean;
145
- }
146
- >(({ className, inset, ...props }, ref) => (
147
- <DropdownMenuPrimitive.Label
148
- ref={ref}
149
- className={cn(
150
- "px-2 py-1.5 text-sm font-semibold",
151
- inset && "pl-8",
152
- className
153
- )}
154
- {...props}
155
- />
156
- ));
157
- DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
158
-
159
- const DropdownMenuSeparator = React.forwardRef<
160
- React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
161
- React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
162
- >(({ className, ...props }, ref) => (
163
- <DropdownMenuPrimitive.Separator
164
- ref={ref}
165
- className={cn("-mx-1 my-1 h-px bg-muted", className)}
166
- {...props}
167
- />
168
- ));
169
- DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
170
-
171
- const DropdownMenuShortcut = ({
163
+ )
164
+ }
165
+
166
+ function DropdownMenuSeparator({
172
167
  className,
173
168
  ...props
174
- }: React.HTMLAttributes<HTMLSpanElement>) => {
169
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
170
+ return (
171
+ <DropdownMenuPrimitive.Separator
172
+ data-slot="dropdown-menu-separator"
173
+ className={cn("-mx-1 my-1 h-px bg-border", className)}
174
+ {...props}
175
+ />
176
+ )
177
+ }
178
+
179
+ function DropdownMenuShortcut({
180
+ className,
181
+ ...props
182
+ }: React.ComponentProps<"span">) {
175
183
  return (
176
184
  <span
177
- className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
185
+ data-slot="dropdown-menu-shortcut"
186
+ className={cn(
187
+ "ml-auto text-xs tracking-widest text-muted-foreground",
188
+ className
189
+ )}
190
+ {...props}
191
+ />
192
+ )
193
+ }
194
+
195
+ function DropdownMenuSub({
196
+ ...props
197
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
198
+ return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
199
+ }
200
+
201
+ function DropdownMenuSubTrigger({
202
+ className,
203
+ inset,
204
+ children,
205
+ ...props
206
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
207
+ inset?: boolean
208
+ }) {
209
+ return (
210
+ <DropdownMenuPrimitive.SubTrigger
211
+ data-slot="dropdown-menu-sub-trigger"
212
+ data-inset={inset}
213
+ className={cn(
214
+ "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
215
+ className
216
+ )}
217
+ {...props}
218
+ >
219
+ {children}
220
+ <CaretRight className="ml-auto size-4" />
221
+ </DropdownMenuPrimitive.SubTrigger>
222
+ )
223
+ }
224
+
225
+ function DropdownMenuSubContent({
226
+ className,
227
+ ...props
228
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
229
+ return (
230
+ <DropdownMenuPrimitive.SubContent
231
+ data-slot="dropdown-menu-sub-content"
232
+ className={cn(
233
+ "z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
234
+ className
235
+ )}
178
236
  {...props}
179
237
  />
180
- );
181
- };
182
- DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
238
+ )
239
+ }
183
240
 
184
241
  export {
185
242
  DropdownMenu,
243
+ DropdownMenuPortal,
186
244
  DropdownMenuTrigger,
187
245
  DropdownMenuContent,
246
+ DropdownMenuGroup,
247
+ DropdownMenuLabel,
188
248
  DropdownMenuItem,
189
249
  DropdownMenuCheckboxItem,
250
+ DropdownMenuRadioGroup,
190
251
  DropdownMenuRadioItem,
191
- DropdownMenuLabel,
192
252
  DropdownMenuSeparator,
193
253
  DropdownMenuShortcut,
194
- DropdownMenuGroup,
195
- DropdownMenuPortal,
196
254
  DropdownMenuSub,
197
- DropdownMenuSubContent,
198
255
  DropdownMenuSubTrigger,
199
- DropdownMenuRadioGroup,
200
- };
256
+ DropdownMenuSubContent,
257
+ }
@@ -0,0 +1,167 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import * as LabelPrimitive from "@radix-ui/react-label"
5
+ import { Slot } from "@radix-ui/react-slot"
6
+ import {
7
+ Controller,
8
+ FormProvider,
9
+ useFormContext,
10
+ useFormState,
11
+ type ControllerProps,
12
+ type FieldPath,
13
+ type FieldValues,
14
+ } from "react-hook-form"
15
+
16
+ import { cn } from "../lib/utils"
17
+ import { Label } from "./label"
18
+
19
+ const Form = FormProvider
20
+
21
+ type FormFieldContextValue<
22
+ TFieldValues extends FieldValues = FieldValues,
23
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
24
+ > = {
25
+ name: TName
26
+ }
27
+
28
+ const FormFieldContext = React.createContext<FormFieldContextValue>(
29
+ {} as FormFieldContextValue
30
+ )
31
+
32
+ const FormField = <
33
+ TFieldValues extends FieldValues = FieldValues,
34
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
35
+ >({
36
+ ...props
37
+ }: ControllerProps<TFieldValues, TName>) => {
38
+ return (
39
+ <FormFieldContext.Provider value={{ name: props.name }}>
40
+ <Controller {...props} />
41
+ </FormFieldContext.Provider>
42
+ )
43
+ }
44
+
45
+ const useFormField = () => {
46
+ const fieldContext = React.useContext(FormFieldContext)
47
+ const itemContext = React.useContext(FormItemContext)
48
+ const { getFieldState } = useFormContext()
49
+ const formState = useFormState({ name: fieldContext.name })
50
+ const fieldState = getFieldState(fieldContext.name, formState)
51
+
52
+ if (!fieldContext) {
53
+ throw new Error("useFormField should be used within <FormField>")
54
+ }
55
+
56
+ const { id } = itemContext
57
+
58
+ return {
59
+ id,
60
+ name: fieldContext.name,
61
+ formItemId: `${id}-form-item`,
62
+ formDescriptionId: `${id}-form-item-description`,
63
+ formMessageId: `${id}-form-item-message`,
64
+ ...fieldState,
65
+ }
66
+ }
67
+
68
+ type FormItemContextValue = {
69
+ id: string
70
+ }
71
+
72
+ const FormItemContext = React.createContext<FormItemContextValue>(
73
+ {} as FormItemContextValue
74
+ )
75
+
76
+ function FormItem({ className, ...props }: React.ComponentProps<"div">) {
77
+ const id = React.useId()
78
+
79
+ return (
80
+ <FormItemContext.Provider value={{ id }}>
81
+ <div
82
+ data-slot="form-item"
83
+ className={cn("grid gap-2", className)}
84
+ {...props}
85
+ />
86
+ </FormItemContext.Provider>
87
+ )
88
+ }
89
+
90
+ function FormLabel({
91
+ className,
92
+ ...props
93
+ }: React.ComponentProps<typeof LabelPrimitive.Root>) {
94
+ const { error, formItemId } = useFormField()
95
+
96
+ return (
97
+ <Label
98
+ data-slot="form-label"
99
+ data-error={!!error}
100
+ className={cn("data-[error=true]:text-destructive", className)}
101
+ htmlFor={formItemId}
102
+ {...props}
103
+ />
104
+ )
105
+ }
106
+
107
+ function FormControl({ ...props }: React.ComponentProps<typeof Slot>) {
108
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
109
+
110
+ return (
111
+ <Slot
112
+ data-slot="form-control"
113
+ id={formItemId}
114
+ aria-describedby={
115
+ !error
116
+ ? `${formDescriptionId}`
117
+ : `${formDescriptionId} ${formMessageId}`
118
+ }
119
+ aria-invalid={!!error}
120
+ {...props}
121
+ />
122
+ )
123
+ }
124
+
125
+ function FormDescription({ className, ...props }: React.ComponentProps<"p">) {
126
+ const { formDescriptionId } = useFormField()
127
+
128
+ return (
129
+ <p
130
+ data-slot="form-description"
131
+ id={formDescriptionId}
132
+ className={cn("text-sm text-muted-foreground", className)}
133
+ {...props}
134
+ />
135
+ )
136
+ }
137
+
138
+ function FormMessage({ className, ...props }: React.ComponentProps<"p">) {
139
+ const { error, formMessageId } = useFormField()
140
+ const body = error ? String(error?.message ?? "") : props.children
141
+
142
+ if (!body) {
143
+ return null
144
+ }
145
+
146
+ return (
147
+ <p
148
+ data-slot="form-message"
149
+ id={formMessageId}
150
+ className={cn("text-sm text-destructive", className)}
151
+ {...props}
152
+ >
153
+ {body}
154
+ </p>
155
+ )
156
+ }
157
+
158
+ export {
159
+ useFormField,
160
+ Form,
161
+ FormItem,
162
+ FormLabel,
163
+ FormControl,
164
+ FormDescription,
165
+ FormMessage,
166
+ FormField,
167
+ }
@@ -1,27 +1,44 @@
1
- import * as HoverCardPrimitive from "@radix-ui/react-hover-card";
2
- import * as React from "react";
1
+ "use client"
3
2
 
4
- import { cn } from "../lib/utils";
3
+ import * as React from "react"
4
+ import * as HoverCardPrimitive from "@radix-ui/react-hover-card"
5
5
 
6
- const HoverCard = HoverCardPrimitive.Root;
6
+ import { cn } from "../lib/utils"
7
7
 
8
- const HoverCardTrigger = HoverCardPrimitive.Trigger;
8
+ function HoverCard({
9
+ ...props
10
+ }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
11
+ return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />
12
+ }
9
13
 
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;
14
+ function HoverCardTrigger({
15
+ ...props
16
+ }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
17
+ return (
18
+ <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
19
+ )
20
+ }
26
21
 
27
- export { HoverCard, HoverCardTrigger, HoverCardContent };
22
+ function HoverCardContent({
23
+ className,
24
+ align = "center",
25
+ sideOffset = 4,
26
+ ...props
27
+ }: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
28
+ return (
29
+ <HoverCardPrimitive.Portal data-slot="hover-card-portal">
30
+ <HoverCardPrimitive.Content
31
+ data-slot="hover-card-content"
32
+ align={align}
33
+ sideOffset={sideOffset}
34
+ className={cn(
35
+ "z-50 w-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden 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 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
36
+ className
37
+ )}
38
+ {...props}
39
+ />
40
+ </HoverCardPrimitive.Portal>
41
+ )
42
+ }
43
+
44
+ export { HoverCard, HoverCardTrigger, HoverCardContent }