{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "field",
  "title": "field",
  "description": "A form field's frame: Field, FieldLabel, FieldDescription, FieldError, FieldGroup, FieldSet, FieldLegend, FieldSeparator, FieldContent and FieldTitle. Field takes orientation vertical, horizontal or responsive; FieldLegend takes variant legend or label. FieldError takes a message, or react-hook-form errors as errors={[fieldState.error]}.",
  "dependencies": [
    "class-variance-authority@^0.7"
  ],
  "registryDependencies": [
    "@dwellir/dwellir-theme",
    "@dwellir/utils",
    "@dwellir/label",
    "@dwellir/separator"
  ],
  "files": [
    {
      "path": "components/ui/field.tsx",
      "content": "import { cva, type VariantProps } from 'class-variance-authority';\nimport type { ComponentProps, ReactNode } from 'react';\nimport { Label } from '@/components/ui/label';\nimport { Separator } from '@/components/ui/separator';\nimport { cn } from '@/lib/utils';\n\n/*\n * A form field's frame: its label, control, description and error, in a\n * column or a row. It holds no state, so any form library can drive it; with\n * react-hook-form, pass fieldState.error to FieldError and set data-invalid\n * and aria-invalid from fieldState.invalid.\n */\n\nfunction FieldSet({ className, ...props }: ComponentProps<'fieldset'>) {\n  return (\n    <fieldset\n      data-slot=\"field-set\"\n      className={cn(\n        'flex min-w-0 flex-col gap-6 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3',\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nconst fieldLegendVariants = cva('mb-3 leading-snug font-bold', {\n  variants: {\n    variant: {\n      /* A group's title, such as \"Billing address\". */\n      legend: 'text-base',\n      /* A group that reads as one field, such as a set of radios: the Label's size. */\n      label: 'text-sm',\n    },\n  },\n  defaultVariants: { variant: 'legend' },\n});\n\nfunction FieldLegend({\n  className,\n  variant,\n  ...props\n}: ComponentProps<'legend'> & VariantProps<typeof fieldLegendVariants>) {\n  return (\n    <legend\n      data-slot=\"field-legend\"\n      data-variant={variant ?? 'legend'}\n      className={cn(fieldLegendVariants({ variant }), className)}\n      {...props}\n    />\n  );\n}\n\nfunction FieldGroup({ className, ...props }: ComponentProps<'div'>) {\n  return (\n    <div\n      data-slot=\"field-group\"\n      className={cn(\n        'group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 [&>[data-slot=field-group]]:gap-4',\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\n/* An invalid field (data-invalid=\"true\") turns its label red; the error says why. */\nconst fieldVariants = cva('group/field flex w-full gap-3 data-[invalid=true]:text-destructive', {\n  variants: {\n    orientation: {\n      /* Label over control: text fields and selects. */\n      vertical: 'flex-col [&>*]:w-full [&>.sr-only]:w-auto',\n      /* Control beside its label: a switch, checkbox or radio. */\n      horizontal:\n        'flex-row items-center has-[>[data-slot=field-content]]:items-start [&>[data-slot=field-label]]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio],[role=switch]]:mt-px',\n      /* Vertical in a narrow FieldGroup, horizontal from its md container width. */\n      responsive:\n        'flex-col [&>*]:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:[&>*]:w-auto @md/field-group:[&>[data-slot=field-label]]:flex-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio],[role=switch]]:mt-px',\n    },\n  },\n  defaultVariants: { orientation: 'vertical' },\n});\n\nfunction Field({\n  className,\n  orientation,\n  ...props\n}: ComponentProps<'div'> & VariantProps<typeof fieldVariants>) {\n  return (\n    // biome-ignore lint/a11y/useSemanticElements: a fieldset is FieldSet; a single field is a group.\n    <div\n      role=\"group\"\n      data-slot=\"field\"\n      data-orientation={orientation ?? 'vertical'}\n      className={cn(fieldVariants({ orientation }), className)}\n      {...props}\n    />\n  );\n}\n\n/* The label and description beside a horizontal field's control. */\nfunction FieldContent({ className, ...props }: ComponentProps<'div'>) {\n  return (\n    <div\n      data-slot=\"field-content\"\n      className={cn('group/field-content flex flex-1 flex-col gap-1.5 leading-snug', className)}\n      {...props}\n    />\n  );\n}\n\n/*\n * The field's Label. Wrapped round a whole Field, it becomes a choice tile:\n * the chosen tile lights the aurora rim, as ChoiceGroup's tiles do.\n */\nfunction FieldLabel({ className, ...props }: ComponentProps<typeof Label>) {\n  return (\n    <Label\n      data-slot=\"field-label\"\n      className={cn(\n        'group/field-label peer/field-label relative flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50',\n        'has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-xl has-[>[data-slot=field]]:border has-[>[data-slot=field]]:border-border has-[>[data-slot=field]]:bg-background has-[>[data-slot=field]]:hover:border-foreground-35 has-[>[data-slot=field]]:has-data-[state=checked]:rim has-[>[data-slot=field]]:has-data-[state=checked]:border-transparent [&>*]:data-[slot=field]:p-4',\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\n/* A field's name when it is not a <label>, such as the title of a choice tile. */\nfunction FieldTitle({ className, ...props }: ComponentProps<'div'>) {\n  return (\n    <div\n      data-slot=\"field-label\"\n      className={cn(\n        'flex w-fit items-center gap-2 text-sm leading-snug font-bold group-data-[disabled=true]/field:opacity-50',\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction FieldDescription({ className, ...props }: ComponentProps<'p'>) {\n  return (\n    <p\n      data-slot=\"field-description\"\n      className={cn(\n        'text-sm leading-normal font-normal text-muted-foreground group-has-[[data-orientation=horizontal]]/field:text-balance',\n        'last:mt-0 nth-last-2:-mt-1 [[data-variant=legend]+&]:-mt-1.5',\n        '[&>a]:underline [&>a]:underline-offset-4 [&>a]:hover:text-foreground',\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\n/* A line between groups of fields, with optional text such as \"or\" in its middle. */\nfunction FieldSeparator({\n  children,\n  className,\n  ...props\n}: ComponentProps<'div'> & { children?: ReactNode }) {\n  return (\n    <div\n      data-slot=\"field-separator\"\n      data-content={Boolean(children)}\n      className={cn('-my-2 flex h-5 items-center gap-3 text-sm text-muted-foreground', className)}\n      {...props}\n    >\n      <Separator className=\"flex-1\" />\n      {children ? (\n        <>\n          <span data-slot=\"field-separator-content\">{children}</span>\n          <Separator className=\"flex-1\" />\n        </>\n      ) : null}\n    </div>\n  );\n}\n\n/** The shape of a react-hook-form FieldError, or any error with a message. */\ntype FieldErrorItem = { message?: string } | undefined;\n\nfunction errorContent(errors: FieldErrorItem[] | undefined): ReactNode {\n  const messages = [...new Set((errors ?? []).map((error) => error?.message).filter(Boolean))];\n  if (messages.length === 0) return null;\n  if (messages.length === 1) return messages[0];\n  return (\n    <ul data-slot=\"field-error-list\" className=\"ml-4 flex list-disc flex-col gap-1\">\n      {messages.map((message) => (\n        <li key={message} data-slot=\"field-error-item\">\n          {message}\n        </li>\n      ))}\n    </ul>\n  );\n}\n\n/*\n * The field's error in words. Pass the message as children, or react-hook-form\n * errors: errors={[fieldState.error]}. It renders nothing without a message.\n */\nfunction FieldError({\n  className,\n  children,\n  errors,\n  ...props\n}: ComponentProps<'div'> & { errors?: FieldErrorItem[] }) {\n  const content = children ?? errorContent(errors);\n  if (!content) return null;\n  return (\n    <div\n      role=\"alert\"\n      data-slot=\"field-error\"\n      className={cn('text-sm font-normal text-destructive', className)}\n      {...props}\n    >\n      {content}\n    </div>\n  );\n}\n\nexport {\n  Field,\n  FieldContent,\n  FieldDescription,\n  FieldError,\n  FieldGroup,\n  FieldLabel,\n  FieldLegend,\n  FieldSeparator,\n  FieldSet,\n  FieldTitle,\n  fieldLegendVariants,\n  fieldVariants,\n};\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}