stunning screenshots in seconds https://moocup.jaydip.me
at from-github 4.1 kB view raw
1import * as React from "react" 2import * as LabelPrimitive from "@radix-ui/react-label" 3import { Slot } from "@radix-ui/react-slot" 4import { 5 Controller, 6 ControllerProps, 7 FieldPath, 8 FieldValues, 9 FormProvider, 10 useFormContext, 11} from "react-hook-form" 12 13import { cn } from "@/lib/utils" 14import { Label } from "@/components/ui/label" 15 16const Form = FormProvider 17 18type FormFieldContextValue< 19 TFieldValues extends FieldValues = FieldValues, 20 TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues> 21> = { 22 name: TName 23} 24 25const FormFieldContext = React.createContext<FormFieldContextValue>( 26 {} as FormFieldContextValue 27) 28 29const 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 42const 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 65type FormItemContextValue = { 66 id: string 67} 68 69const FormItemContext = React.createContext<FormItemContextValue>( 70 {} as FormItemContextValue 71) 72 73const 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}) 85FormItem.displayName = "FormItem" 86 87const 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}) 102FormLabel.displayName = "FormLabel" 103 104const FormControl = React.forwardRef< 105 React.ElementRef<typeof Slot>, 106 React.ComponentPropsWithoutRef<typeof Slot> 107>(({ ...props }, ref) => { 108 const { error, formItemId, formDescriptionId, formMessageId } = useFormField() 109 110 return ( 111 <Slot 112 ref={ref} 113 id={formItemId} 114 aria-describedby={ 115 !error 116 ? `${formDescriptionId}` 117 : `${formDescriptionId} ${formMessageId}` 118 } 119 aria-invalid={!!error} 120 {...props} 121 /> 122 ) 123}) 124FormControl.displayName = "FormControl" 125 126const FormDescription = React.forwardRef< 127 HTMLParagraphElement, 128 React.HTMLAttributes<HTMLParagraphElement> 129>(({ className, ...props }, ref) => { 130 const { formDescriptionId } = useFormField() 131 132 return ( 133 <p 134 ref={ref} 135 id={formDescriptionId} 136 className={cn("text-sm text-muted-foreground", className)} 137 {...props} 138 /> 139 ) 140}) 141FormDescription.displayName = "FormDescription" 142 143const FormMessage = React.forwardRef< 144 HTMLParagraphElement, 145 React.HTMLAttributes<HTMLParagraphElement> 146>(({ className, children, ...props }, ref) => { 147 const { error, formMessageId } = useFormField() 148 const body = error ? String(error?.message) : children 149 150 if (!body) { 151 return null 152 } 153 154 return ( 155 <p 156 ref={ref} 157 id={formMessageId} 158 className={cn("text-sm font-medium text-destructive", className)} 159 {...props} 160 > 161 {body} 162 </p> 163 ) 164}) 165FormMessage.displayName = "FormMessage" 166 167export { 168 useFormField, 169 Form, 170 FormItem, 171 FormLabel, 172 FormControl, 173 FormDescription, 174 FormMessage, 175 FormField, 176}