{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"ui-form","type":"registry:component","title":"Form","description":"React Hook Form helpers for typed fields, labels, and validation messaging.","version":"1.0.0","status":"ga","registryDependencies":["react-hook-form"],"files":[{"path":"src/components/ui/form.tsx","type":"registry:component","content":"'use client'\n\nimport * as React from 'react'\n\nimport type * as LabelPrimitive from '@radix-ui/react-label'\nimport { Slot } from '@radix-ui/react-slot'\nimport {\n  Controller,\n  FormProvider,\n  useFormContext,\n  useFormState,\n  type ControllerProps,\n  type FieldPath,\n  type FieldValues\n} from 'react-hook-form'\n\nimport { cn } from '@/lib/utils'\nimport { Label } from '@/components/ui/label'\n\nconst Form = FormProvider\n\ntype FormFieldContextValue<\n  TFieldValues extends FieldValues = FieldValues,\n  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n  name: TName\n}\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue)\n\nconst FormField = <\n  TFieldValues extends FieldValues = FieldValues,\n  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n  ...props\n}: ControllerProps<TFieldValues, TName>) => {\n  return (\n    <FormFieldContext.Provider value={{ name: props.name }}>\n      <Controller {...props} />\n    </FormFieldContext.Provider>\n  )\n}\n\nconst useFormField = () => {\n  const fieldContext = React.useContext(FormFieldContext)\n  const itemContext = React.useContext(FormItemContext)\n  const { getFieldState } = useFormContext()\n  const formState = useFormState({ name: fieldContext.name })\n  const fieldState = getFieldState(fieldContext.name, formState)\n\n  if (!fieldContext) {\n    throw new Error('useFormField should be used within <FormField>')\n  }\n\n  const { id } = itemContext\n\n  return {\n    id,\n    name: fieldContext.name,\n    formItemId: `${id}-form-item`,\n    formDescriptionId: `${id}-form-item-description`,\n    formMessageId: `${id}-form-item-message`,\n    ...fieldState\n  }\n}\n\ntype FormItemContextValue = {\n  id: string\n}\n\nconst FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue)\n\nfunction FormItem({ className, ...props }: React.ComponentProps<'div'>) {\n  const id = React.useId()\n\n  return (\n    <FormItemContext.Provider value={{ id }}>\n      <div data-slot='form-item' className={cn('grid gap-2', className)} {...props} />\n    </FormItemContext.Provider>\n  )\n}\n\nfunction FormLabel({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {\n  const { error, formItemId } = useFormField()\n\n  return (\n    <Label\n      data-slot='form-label'\n      data-error={!!error}\n      className={cn('data-[error=true]:text-destructive', className)}\n      htmlFor={formItemId}\n      {...props}\n    />\n  )\n}\n\nfunction FormControl({ ...props }: React.ComponentProps<typeof Slot>) {\n  const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n  return (\n    <Slot\n      data-slot='form-control'\n      id={formItemId}\n      aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}\n      aria-invalid={!!error}\n      {...props}\n    />\n  )\n}\n\nfunction FormDescription({ className, ...props }: React.ComponentProps<'p'>) {\n  const { formDescriptionId } = useFormField()\n\n  return (\n    <p\n      data-slot='form-description'\n      id={formDescriptionId}\n      className={cn('text-muted-foreground text-sm', className)}\n      {...props}\n    />\n  )\n}\n\nfunction FormMessage({ className, ...props }: React.ComponentProps<'p'>) {\n  const { error, formMessageId } = useFormField()\n  const body = error ? String(error?.message ?? '') : props.children\n\n  if (!body) {\n    return null\n  }\n\n  return (\n    <p data-slot='form-message' id={formMessageId} className={cn('text-destructive text-sm', className)} {...props}>\n      {body}\n    </p>\n  )\n}\n\nexport { useFormField, Form, FormItem, FormLabel, FormControl, FormDescription, FormMessage, FormField }\n"}]}