{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "form",
  "title": "Form",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-react/components/form/form.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\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'\nimport { CircleAlert, CircleCheck, TriangleAlert } from 'lucide-react'\n\nimport { cn } from '@/lib/utils'\nimport { Label } from '@/components/ui/label'\n\nexport type FormStatusValue = 'error' | 'warning' | 'success' | null | undefined\n\n// The canonical shadcn form: react-hook-form + zod + @hookform/resolvers.\n// `Form` is just FormProvider — wire your form with useForm({ resolver:\n// zodResolver(schema) }) and spread the returned methods. `FormField` is a\n// thin Controller wrapper that publishes the field name on context so the\n// label / control / description / message parts can derive their ids and\n// error state without prop-drilling.\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>(\n  {} as FormFieldContextValue,\n)\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\nfunction 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>(\n  {} as FormItemContextValue,\n)\n\ntype FormItemProps = React.ComponentProps<'div'> & {\n  label?: string\n  required?: boolean\n  description?: string\n  status?: FormStatusValue\n  help?: string\n  layout?: 'vertical' | 'horizontal'\n  labelWidth?: string\n}\n\nfunction FormItem({\n  className,\n  label,\n  required,\n  description,\n  status,\n  help,\n  layout = 'vertical',\n  labelWidth,\n  children,\n  ...props\n}: FormItemProps) {\n  const id = React.useId()\n  const isHorizontal = layout === 'horizontal'\n\n  return (\n    <FormItemContext.Provider value={{ id }}>\n      <div\n        data-uipkge=\"\"\n        data-slot=\"form-item\"\n        className={cn(\n          'grid gap-1.5',\n          isHorizontal && 'grid-cols-[var(--label-width,140px)_1fr] items-start gap-x-4 gap-y-0',\n          className,\n        )}\n        style={labelWidth ? ({ '--label-width': labelWidth } as React.CSSProperties) : undefined}\n        {...props}\n      >\n        {(label || required) && (\n          <div className=\"flex items-center gap-1\">\n            {label && (\n              <Label htmlFor={id} className={cn(status === 'error' && 'text-destructive')}>\n                {label}\n              </Label>\n            )}\n            {required && <span className=\"text-destructive text-sm\">*</span>}\n          </div>\n        )}\n        <div className=\"space-y-1\">\n          {children}\n          {description && <p className=\"text-muted-foreground text-xs\">{description}</p>}\n          {help && (\n            <p\n              className={cn(\n                'text-xs',\n                status === 'error' && 'text-destructive',\n                status === 'warning' && 'text-warning',\n                status === 'success' && 'text-success',\n                !status && 'text-muted-foreground',\n              )}\n            >\n              {help}\n            </p>\n          )}\n        </div>\n      </div>\n    </FormItemContext.Provider>\n  )\n}\n\nfunction FormLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof Label>) {\n  const { error, formItemId } = useFormField()\n\n  return (\n    <Label\n      data-uipkge=\"\"\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-uipkge=\"\"\n      data-slot=\"form-control\"\n      id={formItemId}\n      aria-describedby={\n        !error\n          ? `${formDescriptionId}`\n          : `${formDescriptionId} ${formMessageId}`\n      }\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-uipkge=\"\"\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\n      data-uipkge=\"\"\n      data-slot=\"form-message\"\n      id={formMessageId}\n      className={cn('text-destructive text-sm', className)}\n      {...props}\n    >\n      {body}\n    </p>\n  )\n}\n\nfunction FormSection({\n  className,\n  title,\n  subtitle,\n  description,\n  divider,\n  headingLevel: Heading = 'h4',\n  children,\n  ...props\n}: React.ComponentProps<'div'> & {\n  title?: string\n  subtitle?: string\n  description?: string\n  divider?: boolean\n  headingLevel?: 'h2' | 'h3' | 'h4' | 'h5'\n}) {\n  return (\n    <div data-uipkge=\"\" data-slot=\"form-section\" className={cn('space-y-3', className)} {...props}>\n      {(divider || title || subtitle) && (\n        <div className={cn(divider && 'border-t pt-4')}>\n          {(title || subtitle) && (\n            <div className=\"space-y-1\">\n              {title && <Heading className=\"text-sm font-semibold\">{title}</Heading>}\n              {subtitle && <p className=\"text-muted-foreground text-xs\">{subtitle}</p>}\n            </div>\n          )}\n        </div>\n      )}\n      {description && <p className=\"text-muted-foreground text-xs\">{description}</p>}\n      {children}\n    </div>\n  )\n}\n\nfunction FormActions({\n  className,\n  align = 'right',\n  gap = 'md',\n  ...props\n}: React.ComponentProps<'div'> & {\n  align?: 'left' | 'center' | 'right'\n  gap?: 'sm' | 'md' | 'lg'\n}) {\n  const alignClasses = {\n    left: 'justify-start',\n    center: 'justify-center',\n    right: 'justify-end',\n  }\n  const gapClasses = {\n    sm: 'gap-2',\n    md: 'gap-3',\n    lg: 'gap-4',\n  }\n\n  return (\n    <div\n      data-uipkge=\"\"\n      data-slot=\"form-actions\"\n      className={cn('flex flex-wrap items-center', alignClasses[align], gapClasses[gap], className)}\n      {...props}\n    />\n  )\n}\n\nconst statusConfig = {\n  error: {\n    icon: CircleAlert,\n    container: 'bg-destructive/10 text-destructive border-destructive/20',\n  },\n  warning: {\n    icon: TriangleAlert,\n    container: 'bg-warning/10 text-warning border-warning/30',\n  },\n  success: {\n    icon: CircleCheck,\n    container: 'bg-success/10 text-success border-success/30',\n  },\n} as const\n\nfunction FormStatus({\n  className,\n  status,\n  message,\n  ...props\n}: React.ComponentProps<'div'> & {\n  status: NonNullable<FormStatusValue>\n  message: string\n}) {\n  const config = statusConfig[status]\n  const Icon = config.icon\n\n  return (\n    <div\n      data-uipkge=\"\"\n      data-slot=\"form-status\"\n      className={cn('flex items-center gap-2 rounded-md border px-3 py-2 text-sm', config.container, className)}\n      {...props}\n    >\n      <Icon className=\"size-4 shrink-0\" />\n      <span>{message}</span>\n    </div>\n  )\n}\n\nexport {\n  useFormField,\n  Form,\n  FormItem,\n  FormLabel,\n  FormControl,\n  FormDescription,\n  FormMessage,\n  FormField,\n  FormSection,\n  FormActions,\n  FormStatus,\n}\n",
      "type": "registry:ui",
      "target": "~/components/ui/form/form.tsx"
    },
    {
      "path": "packages/registry-react/components/form/index.ts",
      "content": "export {\n  useFormField,\n  Form,\n  FormItem,\n  FormLabel,\n  FormControl,\n  FormDescription,\n  FormMessage,\n  FormField,\n  FormSection,\n  FormActions,\n  FormStatus,\n  type FormStatusValue,\n} from './form'\n",
      "type": "registry:ui",
      "target": "~/components/ui/form/index.ts"
    }
  ],
  "dependencies": [
    "react-hook-form",
    "zod",
    "@hookform/resolvers",
    "@radix-ui/react-label",
    "@radix-ui/react-slot",
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/label.json"
  ],
  "description": "Zod-first form block built on React Hook Form. Wires field labels, descriptions, error messages, and validation together; bind a field once and the rest is automatic.",
  "categories": [
    "form"
  ]
}