{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "form-field",
  "type": "registry:ui",
  "title": "FormField",
  "description": "Native-first Form and Field primitives for labels, descriptions, errors, invalid state, fieldsets, legends, and dependency-free form composition.",
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://components.dethink.co.uk/r/dethink-base.json"
  ],
  "files": [
    {
      "path": "packages/components/src/components/form-field/form-field.tsx",
      "type": "registry:file",
      "target": "~/components/dethink/components/form-field/form-field.tsx",
      "content": "import {\n  Children,\n  cloneElement,\n  createContext,\n  createElement,\n  forwardRef,\n  isValidElement,\n  useCallback,\n  useContext,\n  useEffect,\n  useId,\n  useMemo,\n  useState,\n  type FieldsetHTMLAttributes,\n  type FormHTMLAttributes,\n  type HTMLAttributes,\n  type LabelHTMLAttributes,\n  type ReactElement,\n  type ReactNode,\n  type Ref,\n} from \"react\";\nimport { cn } from \"../../utils/cn\";\n\nexport type FieldElement = \"div\" | \"section\";\nexport type FieldOrientation = \"vertical\" | \"horizontal\";\nexport type FieldDescriptionElement = \"p\" | \"div\" | \"span\";\nexport type FieldErrorElement = \"div\" | \"p\";\nexport type FieldGroupElement = \"div\" | \"section\";\nexport type FieldGroupGap = \"sm\" | \"md\" | \"lg\";\nexport type FieldLegendVariant = \"legend\" | \"label\";\nexport type FieldTitleElement = \"div\" | \"span\" | \"p\";\nexport type FormSpacing = \"sm\" | \"md\" | \"lg\";\nexport type FieldErrorItem =\n  | string\n  | {\n      message?: ReactNode;\n    }\n  | null\n  | undefined;\n\nexport interface FormProps extends FormHTMLAttributes<HTMLFormElement> {\n  children?: ReactNode;\n  spacing?: FormSpacing;\n}\n\nexport interface FieldProps extends HTMLAttributes<HTMLElement> {\n  as?: FieldElement;\n  children?: ReactNode;\n  disabled?: boolean;\n  invalid?: boolean;\n  orientation?: FieldOrientation;\n  readOnly?: boolean;\n  required?: boolean;\n}\n\nexport interface FieldLabelProps extends LabelHTMLAttributes<HTMLLabelElement> {\n  children?: ReactNode;\n  requiredMarker?: ReactNode | false;\n}\n\nexport interface FieldControlProps extends Omit<\n  HTMLAttributes<HTMLElement>,\n  \"children\"\n> {\n  asChild?: boolean;\n  children?: ReactElement<FieldControlSlotProps>;\n  disabled?: boolean;\n  readOnly?: boolean;\n  required?: boolean;\n}\n\nexport interface FieldDescriptionProps extends HTMLAttributes<HTMLElement> {\n  as?: FieldDescriptionElement;\n  children?: ReactNode;\n}\n\nexport interface FieldErrorProps extends HTMLAttributes<HTMLElement> {\n  as?: FieldErrorElement;\n  children?: ReactNode;\n  errors?: FieldErrorItem[];\n}\n\nexport interface FieldGroupProps extends HTMLAttributes<HTMLElement> {\n  as?: FieldGroupElement;\n  children?: ReactNode;\n  gap?: FieldGroupGap;\n}\n\nexport interface FieldSetProps extends FieldsetHTMLAttributes<HTMLFieldSetElement> {\n  children?: ReactNode;\n}\n\nexport interface FieldLegendProps extends HTMLAttributes<HTMLLegendElement> {\n  children?: ReactNode;\n  variant?: FieldLegendVariant;\n}\n\nexport interface FieldContentProps extends HTMLAttributes<HTMLDivElement> {\n  children?: ReactNode;\n}\n\nexport interface FieldTitleProps extends HTMLAttributes<HTMLElement> {\n  as?: FieldTitleElement;\n  children?: ReactNode;\n}\n\ntype FieldControlSlotProps = Record<string, unknown> & {\n  \"aria-describedby\"?: string;\n  \"aria-errormessage\"?: string;\n  \"aria-invalid\"?: boolean | \"false\" | \"true\" | \"grammar\" | \"spelling\";\n  children?: ReactNode;\n  className?: string;\n  disabled?: boolean;\n  id?: string;\n  readOnly?: boolean;\n  ref?: Ref<HTMLElement>;\n  required?: boolean;\n};\n\ntype FieldContextValue = {\n  controlId: string;\n  descriptionIds: string[];\n  disabled: boolean;\n  errorIds: string[];\n  invalid: boolean;\n  orientation: FieldOrientation;\n  readOnly: boolean;\n  registerDescription: (id: string) => () => void;\n  registerError: (id: string) => () => void;\n  required: boolean;\n};\n\nconst FieldContext = createContext<FieldContextValue | null>(null);\n\nconst formBaseClasses = \"grid w-full min-w-0 text-foreground\";\n\nconst formSpacingClasses: Record<FormSpacing, string> = {\n  sm: \"gap-[calc(var(--dt-density-gap)*2)]\",\n  md: \"gap-[calc(var(--dt-density-gap)*3)]\",\n  lg: \"gap-[calc(var(--dt-density-gap)*4)]\",\n};\n\nconst fieldBaseClasses =\n  \"group/field grid min-w-0 gap-[var(--dt-space-2)] text-foreground data-[disabled=true]:opacity-60 data-[orientation=horizontal]:grid-cols-[minmax(0,1fr)_auto] data-[orientation=horizontal]:items-start data-[orientation=horizontal]:gap-x-density-gap data-[orientation=horizontal]:gap-y-[var(--dt-space-1-5)] data-[orientation=horizontal]:[&:has(>[data-slot=field-control]:first-child)]:grid-cols-[auto_minmax(0,1fr)] data-[orientation=horizontal]:[&:has(>[data-slot=field-control]:first-child+[data-slot=field-label])]:items-center\";\n\nconst fieldLabelBaseClasses =\n  \"text-sm font-medium leading-none text-foreground data-[disabled=true]:cursor-not-allowed data-[invalid=true]:text-destructive\";\n\nconst fieldRequiredMarkerClasses = \"ms-[var(--dt-space-1)] text-destructive\";\n\nconst fieldControlBaseClasses =\n  \"min-w-0 data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-60 data-[invalid=true]:border-destructive data-[invalid=true]:ring-destructive/15\";\n\nconst fieldDescriptionBaseClasses =\n  \"text-xs leading-5 text-muted-foreground data-[disabled=true]:opacity-70\";\n\nconst fieldErrorBaseClasses =\n  \"text-xs font-medium leading-5 text-destructive motion-safe:animate-feedback-in\";\n\nconst fieldGroupBaseClasses = \"grid min-w-0\";\n\nconst fieldGroupGapClasses: Record<FieldGroupGap, string> = {\n  sm: \"gap-[var(--dt-density-gap)]\",\n  md: \"gap-[calc(var(--dt-density-gap)*2)]\",\n  lg: \"gap-[calc(var(--dt-density-gap)*3)]\",\n};\n\nconst fieldSetBaseClasses =\n  \"group/field-set min-w-0 border-0 p-0 text-foreground disabled:opacity-60\";\n\nconst fieldLegendBaseClasses = \"max-w-full text-foreground\";\n\nconst fieldLegendVariantClasses: Record<FieldLegendVariant, string> = {\n  legend:\n    \"mb-[var(--dt-space-2)] font-heading text-base font-semibold leading-6\",\n  label: \"mb-[var(--dt-space-2)] text-sm font-medium leading-none\",\n};\n\nconst fieldContentBaseClasses = \"grid min-w-0 gap-[var(--dt-space-1-5)]\";\n\nconst fieldTitleBaseClasses =\n  \"text-sm font-medium leading-none text-foreground\";\n\nfunction useFieldContext() {\n  return useContext(FieldContext);\n}\n\nfunction addUniqueId(ids: string[], id: string) {\n  if (ids.includes(id)) {\n    return ids;\n  }\n\n  return [...ids, id];\n}\n\nfunction removeId(ids: string[], id: string) {\n  return ids.filter((registeredId) => registeredId !== id);\n}\n\nfunction mergeIds(...values: Array<string | undefined>) {\n  const ids = values\n    .flatMap((value) => value?.split(/\\s+/) ?? [])\n    .map((value) => value.trim())\n    .filter(Boolean);\n\n  return Array.from(new Set(ids)).join(\" \") || undefined;\n}\n\nfunction setRef<T>(ref: Ref<T> | undefined, node: T | null) {\n  if (typeof ref === \"function\") {\n    ref(node);\n    return;\n  }\n\n  if (ref) {\n    ref.current = node;\n  }\n}\n\nfunction composeRefs<T>(...refs: Array<Ref<T> | undefined>) {\n  return (node: T | null) => {\n    for (const ref of refs) {\n      setRef(ref, node);\n    }\n  };\n}\n\nfunction getChildRef(child: ReactElement<FieldControlSlotProps>) {\n  return child.props.ref;\n}\n\nfunction getErrorMessage(error: FieldErrorItem) {\n  if (!error) {\n    return undefined;\n  }\n\n  if (typeof error === \"string\") {\n    return error;\n  }\n\n  return error.message;\n}\n\nfunction hasRenderableContent(content: ReactNode) {\n  return content !== null && content !== undefined && content !== false;\n}\n\nfunction getDefaultDescriptionId(controlId: string, index: number) {\n  return index === 0\n    ? `${controlId}-description`\n    : `${controlId}-description-${index + 1}`;\n}\n\nfunction getDefaultErrorId(controlId: string, index: number) {\n  return index === 0 ? `${controlId}-error` : `${controlId}-error-${index + 1}`;\n}\n\nfunction getErrorContent({\n  children,\n  errors,\n}: Pick<FieldErrorProps, \"children\" | \"errors\">) {\n  const messages = (errors ?? [])\n    .map((error) => getErrorMessage(error))\n    .filter(\n      (message): message is ReactNode =>\n        message !== null && message !== undefined,\n    );\n\n  return {\n    content:\n      children ??\n      (messages.length === 0 ? null : messages.length === 1 ? (\n        messages[0]\n      ) : (\n        <ul className=\"list-disc ps-[var(--dt-space-4)]\">\n          {messages.map((message, index) => (\n            <li key={index}>{message}</li>\n          ))}\n        </ul>\n      )),\n    messages,\n  };\n}\n\nfunction collectFieldRelationshipIds(children: ReactNode, controlId: string) {\n  const descriptionIds: string[] = [];\n  const errorIds: string[] = [];\n  function visit(node: ReactNode): ReactNode {\n    return Children.map(node, (child) => {\n      if (\n        !isValidElement<{\n          children?: ReactNode;\n          errors?: FieldErrorItem[];\n          id?: string;\n        }>(child)\n      )\n        return child;\n      if (\n        child.type === FieldDescription &&\n        hasRenderableContent(child.props.children)\n      ) {\n        const id =\n          child.props.id ??\n          getDefaultDescriptionId(controlId, descriptionIds.length);\n        descriptionIds.push(id);\n        return cloneElement(child, { id });\n      }\n      if (\n        child.type === FieldError &&\n        hasRenderableContent(getErrorContent(child.props).content)\n      ) {\n        const id =\n          child.props.id ?? getDefaultErrorId(controlId, errorIds.length);\n        errorIds.push(id);\n        return cloneElement(child, { id });\n      }\n      if (child.type !== Field && child.props.children !== undefined) {\n        return cloneElement(child, { children: visit(child.props.children) });\n      }\n      return child;\n    });\n  }\n  const resolvedChildren = visit(children);\n  return { descriptionIds, errorIds, children: resolvedChildren };\n}\n\nfunction mergeIdLists(...lists: string[][]) {\n  return lists.reduce<string[]>((mergedIds, ids) => {\n    for (const id of ids) {\n      if (!mergedIds.includes(id)) {\n        mergedIds.push(id);\n      }\n    }\n\n    return mergedIds;\n  }, []);\n}\n\nfunction useRegisteredId({\n  id,\n  register,\n  shouldRegister,\n}: {\n  id: string;\n  register: ((id: string) => () => void) | undefined;\n  shouldRegister: boolean;\n}) {\n  useEffect(() => {\n    if (!register || !shouldRegister) {\n      return undefined;\n    }\n\n    return register(id);\n  }, [id, register, shouldRegister]);\n}\n\nexport function fieldClassNames({\n  className,\n}: Pick<FieldProps, \"className\"> = {}) {\n  return cn(fieldBaseClasses, className);\n}\n\nexport function formClassNames({\n  className,\n  spacing = \"md\",\n}: Pick<FormProps, \"className\" | \"spacing\"> = {}) {\n  return cn(formBaseClasses, formSpacingClasses[spacing], className);\n}\n\nexport function fieldLabelClassNames({\n  className,\n}: Pick<FieldLabelProps, \"className\"> = {}) {\n  return cn(fieldLabelBaseClasses, className);\n}\n\nexport function fieldControlClassNames({\n  className,\n}: Pick<FieldControlProps, \"className\"> = {}) {\n  return cn(fieldControlBaseClasses, className);\n}\n\nexport function fieldDescriptionClassNames({\n  className,\n}: Pick<FieldDescriptionProps, \"className\"> = {}) {\n  return cn(fieldDescriptionBaseClasses, className);\n}\n\nexport function fieldErrorClassNames({\n  className,\n}: Pick<FieldErrorProps, \"className\"> = {}) {\n  return cn(fieldErrorBaseClasses, className);\n}\n\nexport function fieldGroupClassNames({\n  className,\n  gap = \"md\",\n}: Pick<FieldGroupProps, \"className\" | \"gap\"> = {}) {\n  return cn(fieldGroupBaseClasses, fieldGroupGapClasses[gap], className);\n}\n\nexport function fieldSetClassNames({\n  className,\n}: Pick<FieldSetProps, \"className\"> = {}) {\n  return cn(fieldSetBaseClasses, className);\n}\n\nexport function fieldLegendClassNames({\n  className,\n  variant = \"legend\",\n}: Pick<FieldLegendProps, \"className\" | \"variant\"> = {}) {\n  return cn(\n    fieldLegendBaseClasses,\n    fieldLegendVariantClasses[variant],\n    className,\n  );\n}\n\nexport function fieldContentClassNames({\n  className,\n}: Pick<FieldContentProps, \"className\"> = {}) {\n  return cn(fieldContentBaseClasses, className);\n}\n\nexport function fieldTitleClassNames({\n  className,\n}: Pick<FieldTitleProps, \"className\"> = {}) {\n  return cn(fieldTitleBaseClasses, className);\n}\n\nexport const Form = forwardRef<HTMLFormElement, FormProps>(\n  ({ children, className, spacing = \"md\", ...props }, ref) => (\n    <form\n      {...props}\n      ref={ref}\n      data-slot=\"form\"\n      data-spacing={spacing}\n      className={formClassNames({ className, spacing })}\n    >\n      {children}\n    </form>\n  ),\n);\n\nForm.displayName = \"Form\";\n\nexport const Field = forwardRef<HTMLElement, FieldProps>(\n  (\n    {\n      as: Element = \"div\",\n      children,\n      className,\n      disabled = false,\n      id,\n      invalid = false,\n      orientation = \"vertical\",\n      readOnly = false,\n      required = false,\n      ...props\n    },\n    ref,\n  ) => {\n    const generatedId = useId();\n    const controlId = id ?? generatedId;\n    const staticRelationshipIds = useMemo(\n      () => collectFieldRelationshipIds(children, controlId),\n      [children, controlId],\n    );\n    const [registeredDescriptionIds, setRegisteredDescriptionIds] = useState<\n      string[]\n    >([]);\n    const [registeredErrorIds, setRegisteredErrorIds] = useState<string[]>([]);\n    const descriptionIds = useMemo(\n      () =>\n        mergeIdLists(\n          staticRelationshipIds.descriptionIds,\n          registeredDescriptionIds,\n        ),\n      [registeredDescriptionIds, staticRelationshipIds.descriptionIds],\n    );\n    const errorIds = useMemo(\n      () => mergeIdLists(staticRelationshipIds.errorIds, registeredErrorIds),\n      [registeredErrorIds, staticRelationshipIds.errorIds],\n    );\n    const registerDescription = useCallback((descriptionId: string) => {\n      setRegisteredDescriptionIds((ids) => addUniqueId(ids, descriptionId));\n\n      return () => {\n        setRegisteredDescriptionIds((ids) => removeId(ids, descriptionId));\n      };\n    }, []);\n    const registerError = useCallback((errorId: string) => {\n      setRegisteredErrorIds((ids) => addUniqueId(ids, errorId));\n\n      return () => {\n        setRegisteredErrorIds((ids) => removeId(ids, errorId));\n      };\n    }, []);\n    const contextValue = useMemo<FieldContextValue>(\n      () => ({\n        controlId,\n        descriptionIds,\n        disabled,\n        errorIds,\n        invalid,\n        orientation,\n        readOnly,\n        registerDescription,\n        registerError,\n        required,\n      }),\n      [\n        controlId,\n        descriptionIds,\n        disabled,\n        errorIds,\n        invalid,\n        orientation,\n        readOnly,\n        registerDescription,\n        registerError,\n        required,\n      ],\n    );\n\n    return (\n      <FieldContext.Provider value={contextValue}>\n        {createElement(\n          Element,\n          {\n            ...props,\n            ref,\n            \"data-slot\": \"field\",\n            \"data-disabled\": disabled ? \"true\" : undefined,\n            \"data-invalid\": invalid ? \"true\" : undefined,\n            \"data-orientation\": orientation,\n            \"data-readonly\": readOnly ? \"true\" : undefined,\n            \"data-required\": required ? \"true\" : undefined,\n            className: fieldClassNames({ className }),\n          },\n          staticRelationshipIds.children,\n        )}\n      </FieldContext.Provider>\n    );\n  },\n);\n\nField.displayName = \"Field\";\n\nexport const FieldLabel = forwardRef<HTMLLabelElement, FieldLabelProps>(\n  ({ children, className, htmlFor, requiredMarker = \"*\", ...props }, ref) => {\n    const field = useFieldContext();\n    const required = field?.required ?? false;\n\n    return (\n      <label\n        {...props}\n        ref={ref}\n        htmlFor={htmlFor ?? field?.controlId}\n        data-slot=\"field-label\"\n        data-disabled={field?.disabled ? \"true\" : undefined}\n        data-invalid={field?.invalid ? \"true\" : undefined}\n        data-required={required ? \"true\" : undefined}\n        className={fieldLabelClassNames({ className })}\n      >\n        {children}\n        {required && requiredMarker !== false ? (\n          <span aria-hidden=\"true\" className={fieldRequiredMarkerClasses}>\n            {requiredMarker}\n          </span>\n        ) : null}\n      </label>\n    );\n  },\n);\n\nFieldLabel.displayName = \"FieldLabel\";\n\nexport const FieldControl = forwardRef<HTMLElement, FieldControlProps>(\n  (\n    {\n      \"aria-describedby\": ariaDescribedBy,\n      \"aria-errormessage\": ariaErrorMessage,\n      \"aria-invalid\": ariaInvalid,\n      asChild = false,\n      children,\n      className,\n      disabled,\n      id,\n      readOnly,\n      required,\n      ...props\n    },\n    ref,\n  ) => {\n    const field = useFieldContext();\n    const resolvedId = field?.controlId ?? id;\n    const resolvedDisabled = Boolean(field?.disabled || disabled);\n    const resolvedReadOnly = Boolean(field?.readOnly || readOnly);\n    const resolvedRequired = Boolean(field?.required || required);\n    const resolvedInvalid = Boolean(field?.invalid);\n    const describedBy = mergeIds(\n      ariaDescribedBy,\n      ...(field?.descriptionIds ?? []),\n      ...(resolvedInvalid ? (field?.errorIds ?? []) : []),\n    );\n    const errorMessage = resolvedInvalid\n      ? mergeIds(ariaErrorMessage, ...(field?.errorIds ?? []))\n      : ariaErrorMessage;\n    const controlProps = {\n      ...props,\n      id: resolvedId,\n      \"aria-describedby\": describedBy,\n      \"aria-errormessage\": errorMessage,\n      \"aria-invalid\": resolvedInvalid ? true : ariaInvalid,\n      \"data-slot\": \"field-control\",\n      \"data-disabled\": resolvedDisabled ? \"true\" : undefined,\n      \"data-invalid\": resolvedInvalid ? \"true\" : undefined,\n      \"data-readonly\": resolvedReadOnly ? \"true\" : undefined,\n      \"data-required\": resolvedRequired ? \"true\" : undefined,\n      className: fieldControlClassNames({ className }),\n    };\n\n    if (asChild) {\n      const childArray = Children.toArray(children);\n      const child = childArray[0];\n\n      if (\n        childArray.length !== 1 ||\n        !isValidElement<FieldControlSlotProps>(child)\n      ) {\n        throw new Error(\n          \"FieldControl with asChild expects a single React element child.\",\n        );\n      }\n\n      const childDescribedBy = mergeIds(\n        child.props[\"aria-describedby\"],\n        controlProps[\"aria-describedby\"],\n      );\n      const childErrorMessage = resolvedInvalid\n        ? mergeIds(\n            child.props[\"aria-errormessage\"],\n            controlProps[\"aria-errormessage\"],\n          )\n        : mergeIds(child.props[\"aria-errormessage\"], ariaErrorMessage);\n\n      // eslint-disable-next-line react-hooks/refs -- React forwards this ref during commit; createElement/cloneElement does not read ref.current.\n      return cloneElement(child, {\n        ...controlProps,\n        ...child.props,\n        ref: (node) => {\n          composeRefs(ref, getChildRef(child))(node);\n        },\n        id: controlProps.id ?? child.props.id,\n        \"aria-describedby\": childDescribedBy,\n        \"aria-errormessage\": childErrorMessage,\n        \"aria-invalid\": resolvedInvalid\n          ? true\n          : (child.props[\"aria-invalid\"] ?? ariaInvalid),\n        \"data-slot\": \"field-control\",\n        \"data-disabled\": resolvedDisabled ? \"true\" : undefined,\n        \"data-invalid\": resolvedInvalid ? \"true\" : undefined,\n        \"data-readonly\": resolvedReadOnly ? \"true\" : undefined,\n        \"data-required\": resolvedRequired ? \"true\" : undefined,\n        disabled: resolvedDisabled || child.props.disabled || undefined,\n        readOnly: resolvedReadOnly || child.props.readOnly || undefined,\n        required: resolvedRequired || child.props.required || undefined,\n        className: cn(controlProps.className, child.props.className),\n      } as Partial<FieldControlSlotProps>);\n    }\n\n    // eslint-disable-next-line react-hooks/refs -- React forwards this ref during commit; createElement/cloneElement does not read ref.current.\n    return createElement(\"div\", { ...controlProps, ref }, children);\n  },\n);\n\nFieldControl.displayName = \"FieldControl\";\n\nexport const FieldDescription = forwardRef<HTMLElement, FieldDescriptionProps>(\n  ({ as: Element = \"p\", children, className, id, ...props }, ref) => {\n    const field = useFieldContext();\n    const generatedId = useId();\n    const hasContent = hasRenderableContent(children);\n    const resolvedId = id ?? `field-${generatedId}-description`;\n\n    useRegisteredId({\n      id: resolvedId,\n      register: field?.registerDescription,\n      shouldRegister: hasContent,\n    });\n\n    if (!hasContent) {\n      return null;\n    }\n\n    return createElement(\n      Element,\n      // eslint-disable-next-line react-hooks/refs -- React forwards this ref during commit; createElement/cloneElement does not read ref.current.\n      {\n        ...props,\n        ref,\n        id: resolvedId,\n        \"data-slot\": \"field-description\",\n        \"data-disabled\": field?.disabled ? \"true\" : undefined,\n        className: fieldDescriptionClassNames({ className }),\n      },\n      children,\n    );\n  },\n);\n\nFieldDescription.displayName = \"FieldDescription\";\n\nexport const FieldError = forwardRef<HTMLElement, FieldErrorProps>(\n  ({ as: Element = \"div\", children, className, errors, id, ...props }, ref) => {\n    const field = useFieldContext();\n    const generatedId = useId();\n    const { content } = getErrorContent({ children, errors });\n    const hasContent = hasRenderableContent(content);\n    const resolvedId = id ?? `field-${generatedId}-error`;\n\n    useRegisteredId({\n      id: resolvedId,\n      register: field?.registerError,\n      shouldRegister: hasContent && Boolean(field?.invalid),\n    });\n\n    if (!hasContent) {\n      return null;\n    }\n\n    return createElement(\n      Element,\n      // eslint-disable-next-line react-hooks/refs -- React forwards this ref during commit; createElement/cloneElement does not read ref.current.\n      {\n        ...props,\n        ref,\n        id: resolvedId,\n        \"data-slot\": \"field-error\",\n        \"data-invalid\": field?.invalid ? \"true\" : undefined,\n        className: fieldErrorClassNames({ className }),\n      },\n      content,\n    );\n  },\n);\n\nFieldError.displayName = \"FieldError\";\n\nexport const FieldGroup = forwardRef<HTMLElement, FieldGroupProps>(\n  ({ as: Element = \"div\", children, className, gap = \"md\", ...props }, ref) =>\n    createElement(\n      Element,\n      {\n        ...props,\n        ref,\n        \"data-slot\": \"field-group\",\n        \"data-gap\": gap,\n        className: fieldGroupClassNames({ className, gap }),\n      },\n      children,\n    ),\n);\n\nFieldGroup.displayName = \"FieldGroup\";\n\nexport const FieldSet = forwardRef<HTMLFieldSetElement, FieldSetProps>(\n  ({ children, className, disabled, ...props }, ref) => (\n    <fieldset\n      {...props}\n      ref={ref}\n      disabled={disabled}\n      data-slot=\"field-set\"\n      data-disabled={disabled ? \"true\" : undefined}\n      className={fieldSetClassNames({ className })}\n    >\n      {children}\n    </fieldset>\n  ),\n);\n\nFieldSet.displayName = \"FieldSet\";\n\nexport const FieldLegend = forwardRef<HTMLLegendElement, FieldLegendProps>(\n  ({ children, className, variant = \"legend\", ...props }, ref) => (\n    <legend\n      {...props}\n      ref={ref}\n      data-slot=\"field-legend\"\n      data-variant={variant}\n      className={fieldLegendClassNames({ className, variant })}\n    >\n      {children}\n    </legend>\n  ),\n);\n\nFieldLegend.displayName = \"FieldLegend\";\n\nexport const FieldContent = forwardRef<HTMLDivElement, FieldContentProps>(\n  ({ children, className, ...props }, ref) => (\n    <div\n      {...props}\n      ref={ref}\n      data-slot=\"field-content\"\n      className={fieldContentClassNames({ className })}\n    >\n      {children}\n    </div>\n  ),\n);\n\nFieldContent.displayName = \"FieldContent\";\n\nexport const FieldTitle = forwardRef<HTMLElement, FieldTitleProps>(\n  ({ as: Element = \"div\", children, className, ...props }, ref) =>\n    createElement(\n      Element,\n      {\n        ...props,\n        ref,\n        \"data-slot\": \"field-title\",\n        className: fieldTitleClassNames({ className }),\n      },\n      children,\n    ),\n);\n\nFieldTitle.displayName = \"FieldTitle\";\n"
    },
    {
      "path": "packages/components/src/components/form-field/index.ts",
      "type": "registry:file",
      "target": "~/components/dethink/components/form-field/index.ts",
      "content": "export {\n  FieldContent,\n  Field,\n  FieldControl,\n  FieldDescription,\n  FieldError,\n  FieldGroup,\n  FieldLabel,\n  FieldLegend,\n  FieldSet,\n  FieldTitle,\n  Form,\n  fieldClassNames,\n  fieldContentClassNames,\n  fieldControlClassNames,\n  fieldDescriptionClassNames,\n  fieldErrorClassNames,\n  fieldGroupClassNames,\n  fieldLabelClassNames,\n  fieldLegendClassNames,\n  fieldSetClassNames,\n  fieldTitleClassNames,\n  formClassNames,\n  type FieldContentProps,\n  type FieldControlProps,\n  type FieldDescriptionElement,\n  type FieldDescriptionProps,\n  type FieldElement,\n  type FieldErrorElement,\n  type FieldErrorItem,\n  type FieldErrorProps,\n  type FieldGroupElement,\n  type FieldGroupGap,\n  type FieldGroupProps,\n  type FieldLabelProps,\n  type FieldLegendProps,\n  type FieldLegendVariant,\n  type FieldOrientation,\n  type FieldProps,\n  type FieldSetProps,\n  type FieldTitleElement,\n  type FieldTitleProps,\n  type FormProps,\n  type FormSpacing,\n} from \"./form-field\";\n"
    },
    {
      "path": "packages/components/src/utils/cn.ts",
      "type": "registry:file",
      "target": "~/components/dethink/utils/cn.ts",
      "content": "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n"
    }
  ]
}
