{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "form",
  "title": "Form",
  "author": "andongmin94",
  "description": "Accessible form helpers with React Hook Form and Zod validation.",
  "dependencies": [
    "@base-ui/react@^1.6.0",
    "@hookform/resolvers@^5.4.0",
    "react-hook-form@^7.81.0",
    "zod@^4.4.3"
  ],
  "registryDependencies": [
    "https://neobrutal-ui.andongmin.com/r/label.json"
  ],
  "files": [
    {
      "path": "src/components/ui/form.tsx",
      "content": "\"use client\";\n\nimport {\n  Controller,\n  FormProvider,\n  useFormContext,\n  useFormState,\n  type ControllerProps,\n  type FieldPath,\n  type FieldValues,\n} from \"react-hook-form\";\nimport { useRender } from \"@base-ui/react/use-render\";\n\nimport * as React from \"react\";\n\nimport { Label } from \"@/components/ui/label\";\n\nimport { cn } from \"@/lib/utils\";\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\nfunction FormField<\n  TFieldValues extends FieldValues = FieldValues,\n  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({ ...props }: 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 Label>) {\n  const { error, formItemId } = useFormField();\n\n  return (\n    <Label\n      data-slot=\"form-label\"\n      data-error={!!error}\n      className={cn(\"font-heading\", className)}\n      htmlFor={formItemId}\n      {...props}\n    />\n  );\n}\n\ntype FormControlProps = React.HTMLAttributes<HTMLElement> & {\n  children?: React.ReactNode;\n};\n\nconst FormControl = React.forwardRef<HTMLElement, FormControlProps>(function FormControl(\n  { children, ...props },\n  forwardedRef,\n) {\n  const { error, formItemId, formDescriptionId, formMessageId } = useFormField();\n  const child = React.Children.toArray(children).find(React.isValidElement);\n\n  return useRender({\n    defaultTagName: \"span\",\n    enabled: child !== undefined,\n    props: {\n      \"data-slot\": \"form-control\",\n      id: formItemId,\n      \"aria-describedby\": !error ? formDescriptionId : `${formDescriptionId} ${formMessageId}`,\n      \"aria-invalid\": !!error,\n      ...props,\n    },\n    ref: forwardedRef,\n    render: child,\n    state: {},\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-sm font-base text-foreground\", 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\n      data-slot=\"form-message\"\n      id={formMessageId}\n      className={cn(\"text-sm font-base text-red-500\", className)}\n      {...props}\n    >\n      {body}\n    </p>\n  );\n}\n\nexport {\n  useFormField,\n  Form,\n  FormItem,\n  FormLabel,\n  FormControl,\n  FormDescription,\n  FormMessage,\n  FormField,\n};\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "form",
    "validation"
  ],
  "type": "registry:ui"
}