@blocknote/shadcn 0.13.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 (75) hide show
  1. package/LICENSE +373 -0
  2. package/dist/blocknote-shadcn.js +1881 -0
  3. package/dist/blocknote-shadcn.js.map +1 -0
  4. package/dist/blocknote-shadcn.umd.cjs +28 -0
  5. package/dist/blocknote-shadcn.umd.cjs.map +1 -0
  6. package/dist/style.css +1 -0
  7. package/dist/webpack-stats.json +1 -0
  8. package/package.json +104 -0
  9. package/src/ShadCNComponentsContext.tsx +39 -0
  10. package/src/components/ui/badge.tsx +36 -0
  11. package/src/components/ui/button.tsx +56 -0
  12. package/src/components/ui/card.tsx +86 -0
  13. package/src/components/ui/dropdown-menu.tsx +195 -0
  14. package/src/components/ui/form.tsx +176 -0
  15. package/src/components/ui/input.tsx +24 -0
  16. package/src/components/ui/label.tsx +24 -0
  17. package/src/components/ui/popover.tsx +29 -0
  18. package/src/components/ui/select.tsx +152 -0
  19. package/src/components/ui/tabs.tsx +53 -0
  20. package/src/components/ui/toggle.tsx +43 -0
  21. package/src/components/ui/tooltip.tsx +28 -0
  22. package/src/form/Form.tsx +21 -0
  23. package/src/form/TextInput.tsx +61 -0
  24. package/src/index.tsx +122 -0
  25. package/src/lib/utils.ts +6 -0
  26. package/src/menu/Menu.tsx +212 -0
  27. package/src/panel/Panel.tsx +54 -0
  28. package/src/panel/PanelButton.tsx +27 -0
  29. package/src/panel/PanelFileInput.tsx +27 -0
  30. package/src/panel/PanelTab.tsx +25 -0
  31. package/src/panel/PanelTextInput.tsx +29 -0
  32. package/src/popover/popover.tsx +69 -0
  33. package/src/sideMenu/SideMenu.tsx +18 -0
  34. package/src/sideMenu/SideMenuButton.tsx +45 -0
  35. package/src/style.css +109 -0
  36. package/src/suggestionMenu/SuggestionMenu.tsx +28 -0
  37. package/src/suggestionMenu/SuggestionMenuEmptyItem.tsx +26 -0
  38. package/src/suggestionMenu/SuggestionMenuItem.tsx +47 -0
  39. package/src/suggestionMenu/SuggestionMenuLabel.tsx +22 -0
  40. package/src/suggestionMenu/SuggestionMenuLoader.tsx +18 -0
  41. package/src/tableHandle/TableHandle.tsx +43 -0
  42. package/src/toolbar/Toolbar.tsx +153 -0
  43. package/types/src/ShadCNComponentsContext.d.ts +56 -0
  44. package/types/src/components/ui/badge.d.ts +9 -0
  45. package/types/src/components/ui/button.d.ts +11 -0
  46. package/types/src/components/ui/card.d.ts +8 -0
  47. package/types/src/components/ui/dropdown-menu.d.ts +27 -0
  48. package/types/src/components/ui/form.d.ts +23 -0
  49. package/types/src/components/ui/input.d.ts +4 -0
  50. package/types/src/components/ui/label.d.ts +5 -0
  51. package/types/src/components/ui/popover.d.ts +6 -0
  52. package/types/src/components/ui/select.d.ts +13 -0
  53. package/types/src/components/ui/tabs.d.ts +7 -0
  54. package/types/src/components/ui/toggle.d.ts +12 -0
  55. package/types/src/components/ui/tooltip.d.ts +7 -0
  56. package/types/src/form/Form.d.ts +2 -0
  57. package/types/src/form/TextInput.d.ts +13 -0
  58. package/types/src/index.d.ts +12 -0
  59. package/types/src/lib/utils.d.ts +2 -0
  60. package/types/src/menu/Menu.d.ts +24 -0
  61. package/types/src/panel/Panel.d.ts +12 -0
  62. package/types/src/panel/PanelButton.d.ts +11 -0
  63. package/types/src/panel/PanelFileInput.d.ts +7 -0
  64. package/types/src/panel/PanelTab.d.ts +5 -0
  65. package/types/src/panel/PanelTextInput.d.ts +8 -0
  66. package/types/src/popover/popover.d.ts +11 -0
  67. package/types/src/sideMenu/SideMenu.d.ts +5 -0
  68. package/types/src/sideMenu/SideMenuButton.d.ts +15 -0
  69. package/types/src/suggestionMenu/SuggestionMenu.d.ts +6 -0
  70. package/types/src/suggestionMenu/SuggestionMenuEmptyItem.d.ts +5 -0
  71. package/types/src/suggestionMenu/SuggestionMenuItem.d.ts +8 -0
  72. package/types/src/suggestionMenu/SuggestionMenuLabel.d.ts +5 -0
  73. package/types/src/suggestionMenu/SuggestionMenuLoader.d.ts +5 -0
  74. package/types/src/tableHandle/TableHandle.d.ts +14 -0
  75. package/types/src/toolbar/Toolbar.d.ts +25 -0
@@ -0,0 +1,39 @@
1
+ import * as ShadCNBadge from "./components/ui/badge";
2
+ import * as ShadCNButton from "./components/ui/button";
3
+ import * as ShadCNCard from "./components/ui/card";
4
+ import * as ShadCNDropdownMenu from "./components/ui/dropdown-menu";
5
+ import * as ShadCNForm from "./components/ui/form";
6
+ import * as ShadCNInput from "./components/ui/input";
7
+ import * as ShadCNLabel from "./components/ui/label";
8
+ import * as ShadCNPopover from "./components/ui/popover";
9
+ import * as ShadCNSelect from "./components/ui/select";
10
+ import * as ShadCNTabs from "./components/ui/tabs";
11
+ import * as ShadCNToggle from "./components/ui/toggle";
12
+ import * as ShadCNTooltip from "./components/ui/tooltip";
13
+
14
+ import { createContext, useContext } from "react";
15
+
16
+ export const ShadCNDefaultComponents = {
17
+ Badge: ShadCNBadge,
18
+ Button: ShadCNButton,
19
+ Card: ShadCNCard,
20
+ DropdownMenu: ShadCNDropdownMenu,
21
+ Form: ShadCNForm,
22
+ Input: ShadCNInput,
23
+ Label: ShadCNLabel,
24
+ Popover: ShadCNPopover,
25
+ Select: ShadCNSelect,
26
+ Tabs: ShadCNTabs,
27
+ Toggle: ShadCNToggle,
28
+ Tooltip: ShadCNTooltip,
29
+ };
30
+
31
+ export type ShadCNComponents = typeof ShadCNDefaultComponents;
32
+
33
+ export const ShadCNComponentsContext = createContext<
34
+ ShadCNComponents | undefined
35
+ >(undefined);
36
+
37
+ export function useShadCNComponentsContext() {
38
+ return useContext(ShadCNComponentsContext);
39
+ }
@@ -0,0 +1,36 @@
1
+ import * as React from "react";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ const badgeVariants = cva(
7
+ "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default:
12
+ "border-transparent bg-primary text-primary-foreground hover:bg-primary/80",
13
+ secondary:
14
+ "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
15
+ destructive:
16
+ "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
17
+ outline: "text-foreground",
18
+ },
19
+ },
20
+ defaultVariants: {
21
+ variant: "default",
22
+ },
23
+ }
24
+ );
25
+
26
+ export interface BadgeProps
27
+ extends React.HTMLAttributes<HTMLDivElement>,
28
+ VariantProps<typeof badgeVariants> {}
29
+
30
+ function Badge({ className, variant, ...props }: BadgeProps) {
31
+ return (
32
+ <div className={cn(badgeVariants({ variant }), className)} {...props} />
33
+ );
34
+ }
35
+
36
+ export { Badge, badgeVariants };
@@ -0,0 +1,56 @@
1
+ import * as React from "react";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ const buttonVariants = cva(
8
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
13
+ destructive:
14
+ "bg-destructive text-destructive-foreground hover:bg-destructive/90",
15
+ outline:
16
+ "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
17
+ secondary:
18
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19
+ ghost: "hover:bg-accent hover:text-accent-foreground",
20
+ link: "text-primary underline-offset-4 hover:underline",
21
+ },
22
+ size: {
23
+ default: "h-10 px-4 py-2",
24
+ sm: "h-9 rounded-md px-3",
25
+ lg: "h-11 rounded-md px-8",
26
+ icon: "h-10 w-10",
27
+ },
28
+ },
29
+ defaultVariants: {
30
+ variant: "default",
31
+ size: "default",
32
+ },
33
+ }
34
+ );
35
+
36
+ export interface ButtonProps
37
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
38
+ VariantProps<typeof buttonVariants> {
39
+ asChild?: boolean;
40
+ }
41
+
42
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
43
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
44
+ const Comp = asChild ? Slot : "button";
45
+ return (
46
+ <Comp
47
+ className={cn(buttonVariants({ variant, size, className }))}
48
+ ref={ref}
49
+ {...props}
50
+ />
51
+ );
52
+ }
53
+ );
54
+ Button.displayName = "Button";
55
+
56
+ export { Button, buttonVariants };
@@ -0,0 +1,86 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ const Card = React.forwardRef<
6
+ HTMLDivElement,
7
+ React.HTMLAttributes<HTMLDivElement>
8
+ >(({ className, ...props }, ref) => (
9
+ <div
10
+ ref={ref}
11
+ className={cn(
12
+ "rounded-lg border bg-card text-card-foreground shadow-sm",
13
+ className
14
+ )}
15
+ {...props}
16
+ />
17
+ ));
18
+ Card.displayName = "Card";
19
+
20
+ const CardHeader = React.forwardRef<
21
+ HTMLDivElement,
22
+ React.HTMLAttributes<HTMLDivElement>
23
+ >(({ className, ...props }, ref) => (
24
+ <div
25
+ ref={ref}
26
+ className={cn("flex flex-col space-y-1.5 p-6", className)}
27
+ {...props}
28
+ />
29
+ ));
30
+ CardHeader.displayName = "CardHeader";
31
+
32
+ const CardTitle = React.forwardRef<
33
+ HTMLParagraphElement,
34
+ React.HTMLAttributes<HTMLHeadingElement>
35
+ >(({ className, ...props }, ref) => (
36
+ <h3
37
+ ref={ref}
38
+ className={cn(
39
+ "text-2xl font-semibold leading-none tracking-tight",
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ ));
45
+ CardTitle.displayName = "CardTitle";
46
+
47
+ const CardDescription = React.forwardRef<
48
+ HTMLParagraphElement,
49
+ React.HTMLAttributes<HTMLParagraphElement>
50
+ >(({ className, ...props }, ref) => (
51
+ <p
52
+ ref={ref}
53
+ className={cn("text-sm text-muted-foreground", className)}
54
+ {...props}
55
+ />
56
+ ));
57
+ CardDescription.displayName = "CardDescription";
58
+
59
+ const CardContent = React.forwardRef<
60
+ HTMLDivElement,
61
+ React.HTMLAttributes<HTMLDivElement>
62
+ >(({ className, ...props }, ref) => (
63
+ <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
64
+ ));
65
+ CardContent.displayName = "CardContent";
66
+
67
+ const CardFooter = React.forwardRef<
68
+ HTMLDivElement,
69
+ React.HTMLAttributes<HTMLDivElement>
70
+ >(({ className, ...props }, ref) => (
71
+ <div
72
+ ref={ref}
73
+ className={cn("flex items-center p-6 pt-0", className)}
74
+ {...props}
75
+ />
76
+ ));
77
+ CardFooter.displayName = "CardFooter";
78
+
79
+ export {
80
+ Card,
81
+ CardHeader,
82
+ CardFooter,
83
+ CardTitle,
84
+ CardDescription,
85
+ CardContent,
86
+ };
@@ -0,0 +1,195 @@
1
+ import * as React from "react";
2
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
3
+ import { Check, ChevronRight, Circle } from "lucide-react";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ const DropdownMenu = DropdownMenuPrimitive.Root;
8
+
9
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
10
+
11
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group;
12
+
13
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
14
+
15
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub;
16
+
17
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
18
+
19
+ const DropdownMenuSubTrigger = React.forwardRef<
20
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
21
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
22
+ inset?: boolean;
23
+ }
24
+ >(({ className, inset, children, ...props }, ref) => (
25
+ <DropdownMenuPrimitive.SubTrigger
26
+ ref={ref}
27
+ className={cn(
28
+ "flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
29
+ inset && "pl-8",
30
+ className
31
+ )}
32
+ {...props}>
33
+ {children}
34
+ <ChevronRight className="ml-auto h-4 w-4" />
35
+ </DropdownMenuPrimitive.SubTrigger>
36
+ ));
37
+ DropdownMenuSubTrigger.displayName =
38
+ DropdownMenuPrimitive.SubTrigger.displayName;
39
+
40
+ const DropdownMenuSubContent = React.forwardRef<
41
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
42
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
43
+ >(({ className, ...props }, ref) => (
44
+ <DropdownMenuPrimitive.SubContent
45
+ ref={ref}
46
+ className={cn(
47
+ "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",
48
+ className
49
+ )}
50
+ {...props}
51
+ />
52
+ ));
53
+ DropdownMenuSubContent.displayName =
54
+ DropdownMenuPrimitive.SubContent.displayName;
55
+
56
+ const DropdownMenuContent = React.forwardRef<
57
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
58
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
59
+ >(({ className, sideOffset = 4, ...props }, ref) => (
60
+ // <DropdownMenuPrimitive.Portal>
61
+ <DropdownMenuPrimitive.Content
62
+ ref={ref}
63
+ sideOffset={sideOffset}
64
+ className={cn(
65
+ "z-50 min-w-[8rem] overflow-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",
66
+ className
67
+ )}
68
+ {...props}
69
+ />
70
+ // </DropdownMenuPrimitive.Portal>
71
+ ));
72
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
73
+
74
+ const DropdownMenuItem = React.forwardRef<
75
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
76
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
77
+ inset?: boolean;
78
+ }
79
+ >(({ className, inset, ...props }, ref) => (
80
+ <DropdownMenuPrimitive.Item
81
+ ref={ref}
82
+ className={cn(
83
+ "relative flex cursor-default select-none items-center 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",
84
+ inset && "pl-8",
85
+ className
86
+ )}
87
+ {...props}
88
+ />
89
+ ));
90
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
91
+
92
+ const DropdownMenuCheckboxItem = React.forwardRef<
93
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
94
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
95
+ >(({ className, children, checked, ...props }, ref) => (
96
+ <DropdownMenuPrimitive.CheckboxItem
97
+ ref={ref}
98
+ className={cn(
99
+ "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",
100
+ className
101
+ )}
102
+ checked={checked}
103
+ {...props}>
104
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
105
+ <DropdownMenuPrimitive.ItemIndicator>
106
+ <Check className="h-4 w-4" />
107
+ </DropdownMenuPrimitive.ItemIndicator>
108
+ </span>
109
+ {children}
110
+ </DropdownMenuPrimitive.CheckboxItem>
111
+ ));
112
+ DropdownMenuCheckboxItem.displayName =
113
+ DropdownMenuPrimitive.CheckboxItem.displayName;
114
+
115
+ const DropdownMenuRadioItem = React.forwardRef<
116
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
117
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
118
+ >(({ className, children, ...props }, ref) => (
119
+ <DropdownMenuPrimitive.RadioItem
120
+ ref={ref}
121
+ className={cn(
122
+ "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",
123
+ className
124
+ )}
125
+ {...props}>
126
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
127
+ <DropdownMenuPrimitive.ItemIndicator>
128
+ <Circle className="h-2 w-2 fill-current" />
129
+ </DropdownMenuPrimitive.ItemIndicator>
130
+ </span>
131
+ {children}
132
+ </DropdownMenuPrimitive.RadioItem>
133
+ ));
134
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
135
+
136
+ const DropdownMenuLabel = React.forwardRef<
137
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
138
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
139
+ inset?: boolean;
140
+ }
141
+ >(({ className, inset, ...props }, ref) => (
142
+ <DropdownMenuPrimitive.Label
143
+ ref={ref}
144
+ className={cn(
145
+ "px-2 py-1.5 text-sm font-semibold",
146
+ inset && "pl-8",
147
+ className
148
+ )}
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 = ({
167
+ className,
168
+ ...props
169
+ }: React.HTMLAttributes<HTMLSpanElement>) => {
170
+ return (
171
+ <span
172
+ className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
173
+ {...props}
174
+ />
175
+ );
176
+ };
177
+ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
178
+
179
+ export {
180
+ DropdownMenu,
181
+ DropdownMenuTrigger,
182
+ DropdownMenuContent,
183
+ DropdownMenuItem,
184
+ DropdownMenuCheckboxItem,
185
+ DropdownMenuRadioItem,
186
+ DropdownMenuLabel,
187
+ DropdownMenuSeparator,
188
+ DropdownMenuShortcut,
189
+ DropdownMenuGroup,
190
+ DropdownMenuPortal,
191
+ DropdownMenuSub,
192
+ DropdownMenuSubContent,
193
+ DropdownMenuSubTrigger,
194
+ DropdownMenuRadioGroup,
195
+ };
@@ -0,0 +1,176 @@
1
+ import * as React from "react";
2
+ import * as LabelPrimitive from "@radix-ui/react-label";
3
+ import { Slot } from "@radix-ui/react-slot";
4
+ import {
5
+ Controller,
6
+ ControllerProps,
7
+ FieldPath,
8
+ 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>(
26
+ {} as FormFieldContextValue
27
+ );
28
+
29
+ const FormField = <
30
+ TFieldValues extends FieldValues = FieldValues,
31
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
32
+ >({
33
+ ...props
34
+ }: ControllerProps<TFieldValues, TName>) => {
35
+ return (
36
+ <FormFieldContext.Provider value={{ name: props.name }}>
37
+ <Controller {...props} />
38
+ </FormFieldContext.Provider>
39
+ );
40
+ };
41
+
42
+ const useFormField = () => {
43
+ const fieldContext = React.useContext(FormFieldContext);
44
+ const itemContext = React.useContext(FormItemContext);
45
+ const { getFieldState, formState } = useFormContext();
46
+
47
+ const fieldState = getFieldState(fieldContext.name, formState);
48
+
49
+ if (!fieldContext) {
50
+ throw new Error("useFormField should be used within <FormField>");
51
+ }
52
+
53
+ const { id } = itemContext;
54
+
55
+ return {
56
+ id,
57
+ name: fieldContext.name,
58
+ formItemId: `${id}-form-item`,
59
+ formDescriptionId: `${id}-form-item-description`,
60
+ formMessageId: `${id}-form-item-message`,
61
+ ...fieldState,
62
+ };
63
+ };
64
+
65
+ type FormItemContextValue = {
66
+ id: string;
67
+ };
68
+
69
+ const FormItemContext = React.createContext<FormItemContextValue>(
70
+ {} as FormItemContextValue
71
+ );
72
+
73
+ const FormItem = React.forwardRef<
74
+ HTMLDivElement,
75
+ React.HTMLAttributes<HTMLDivElement>
76
+ >(({ className, ...props }, ref) => {
77
+ const id = React.useId();
78
+
79
+ return (
80
+ <FormItemContext.Provider value={{ id }}>
81
+ <div ref={ref} className={cn("space-y-2", className)} {...props} />
82
+ </FormItemContext.Provider>
83
+ );
84
+ });
85
+ FormItem.displayName = "FormItem";
86
+
87
+ const FormLabel = React.forwardRef<
88
+ React.ElementRef<typeof LabelPrimitive.Root>,
89
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
90
+ >(({ className, ...props }, ref) => {
91
+ const { error, formItemId } = useFormField();
92
+
93
+ return (
94
+ <Label
95
+ ref={ref}
96
+ className={cn(error && "text-destructive", className)}
97
+ htmlFor={formItemId}
98
+ {...props}
99
+ />
100
+ );
101
+ });
102
+ FormLabel.displayName = "FormLabel";
103
+
104
+ const FormControl = React.forwardRef<
105
+ React.ElementRef<typeof Slot>,
106
+ React.ComponentPropsWithoutRef<typeof Slot>
107
+ >(({ ...props }, ref) => {
108
+ const { error, formItemId, formDescriptionId, formMessageId } =
109
+ useFormField();
110
+
111
+ return (
112
+ <Slot
113
+ ref={ref}
114
+ id={formItemId}
115
+ aria-describedby={
116
+ !error
117
+ ? `${formDescriptionId}`
118
+ : `${formDescriptionId} ${formMessageId}`
119
+ }
120
+ aria-invalid={!!error}
121
+ {...props}
122
+ />
123
+ );
124
+ });
125
+ FormControl.displayName = "FormControl";
126
+
127
+ const FormDescription = React.forwardRef<
128
+ HTMLParagraphElement,
129
+ React.HTMLAttributes<HTMLParagraphElement>
130
+ >(({ className, ...props }, ref) => {
131
+ const { formDescriptionId } = useFormField();
132
+
133
+ return (
134
+ <p
135
+ ref={ref}
136
+ id={formDescriptionId}
137
+ className={cn("text-sm text-muted-foreground", className)}
138
+ {...props}
139
+ />
140
+ );
141
+ });
142
+ FormDescription.displayName = "FormDescription";
143
+
144
+ const FormMessage = React.forwardRef<
145
+ HTMLParagraphElement,
146
+ React.HTMLAttributes<HTMLParagraphElement>
147
+ >(({ className, children, ...props }, ref) => {
148
+ const { error, formMessageId } = useFormField();
149
+ const body = error ? String(error?.message) : children;
150
+
151
+ if (!body) {
152
+ return null;
153
+ }
154
+
155
+ return (
156
+ <p
157
+ ref={ref}
158
+ id={formMessageId}
159
+ className={cn("text-sm font-medium text-destructive", className)}
160
+ {...props}>
161
+ {body}
162
+ </p>
163
+ );
164
+ });
165
+ FormMessage.displayName = "FormMessage";
166
+
167
+ export {
168
+ useFormField,
169
+ Form,
170
+ FormItem,
171
+ FormLabel,
172
+ FormControl,
173
+ FormDescription,
174
+ FormMessage,
175
+ FormField,
176
+ };
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ export type InputProps = React.InputHTMLAttributes<HTMLInputElement>;
6
+
7
+ const Input = React.forwardRef<HTMLInputElement, InputProps>(
8
+ ({ className, type, ...props }, ref) => {
9
+ return (
10
+ <input
11
+ type={type}
12
+ className={cn(
13
+ "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
14
+ className
15
+ )}
16
+ ref={ref}
17
+ {...props}
18
+ />
19
+ );
20
+ }
21
+ );
22
+ Input.displayName = "Input";
23
+
24
+ export { Input };
@@ -0,0 +1,24 @@
1
+ import * as React from "react";
2
+ import * as LabelPrimitive from "@radix-ui/react-label";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+
5
+ import { cn } from "../../lib/utils";
6
+
7
+ const labelVariants = cva(
8
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
9
+ );
10
+
11
+ const Label = React.forwardRef<
12
+ React.ElementRef<typeof LabelPrimitive.Root>,
13
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> &
14
+ VariantProps<typeof labelVariants>
15
+ >(({ className, ...props }, ref) => (
16
+ <LabelPrimitive.Root
17
+ ref={ref}
18
+ className={cn(labelVariants(), className)}
19
+ {...props}
20
+ />
21
+ ));
22
+ Label.displayName = LabelPrimitive.Root.displayName;
23
+
24
+ export { Label };
@@ -0,0 +1,29 @@
1
+ import * as React from "react";
2
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ const Popover = PopoverPrimitive.Root;
7
+
8
+ const PopoverTrigger = PopoverPrimitive.Trigger;
9
+
10
+ const PopoverContent = React.forwardRef<
11
+ React.ElementRef<typeof PopoverPrimitive.Content>,
12
+ React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
13
+ >(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
14
+ // <PopoverPrimitive.Portal>
15
+ <PopoverPrimitive.Content
16
+ ref={ref}
17
+ align={align}
18
+ sideOffset={sideOffset}
19
+ className={cn(
20
+ "z-50 w-72 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",
21
+ className
22
+ )}
23
+ {...props}
24
+ />
25
+ // </PopoverPrimitive.Portal>
26
+ ));
27
+ PopoverContent.displayName = PopoverPrimitive.Content.displayName;
28
+
29
+ export { Popover, PopoverTrigger, PopoverContent };