{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "text-field",
  "title": "Text field",
  "description": "A text input cut into the panel as a slot, with a printed label above and description and error lines below. Focus lights the slot's edge amber, the colour of a caret; an invalid field edges in red and lights a lamp by its label. Inputs, textareas, search boxes with an icon and a key hint, amounts with a unit.",
  "dependencies": [
    "@base-ui/react",
    "cn"
  ],
  "registryDependencies": [
    "https://bevel-ui.vercel.app/r/bevel.json"
  ],
  "files": [
    {
      "path": "registry/bevel/ui/text-field.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Field } from \"@base-ui/react/field\"\nimport { Input } from \"@base-ui/react/input\"\nimport { cn } from \"cn\"\n\ntype TextFieldProps = Field.Root.Props & {\n  /** Row height: sm for dense forms and toolbars, md for everything else. */\n  size?: \"sm\" | \"md\"\n}\n\n/**\n * A text field: a printed label, a slot cut into the panel, and the lines\n * under it. Focus lights the slot's edge; an invalid field lights a red lamp\n * by its label. Wraps Base UI Field, so label, description and error are\n * wired to the control for you.\n */\nfunction TextField({ className, size = \"md\", ...props }: TextFieldProps) {\n  return (\n    <Field.Root\n      data-slot=\"text-field\"\n      data-size={size}\n      className={cn(\"flex min-w-0 flex-col gap-1.5\", className)}\n      {...props}\n    />\n  )\n}\n\n/** The printed label. Carries the error lamp, lit while the field is invalid. */\nfunction TextFieldLabel({ className, children, ...props }: Field.Label.Props) {\n  return (\n    <Field.Label\n      data-slot=\"text-field-label\"\n      className={cn(\n        \"flex w-fit items-center gap-1.5 text-(length:--bevel-label) font-semibold tracking-(--bevel-tracking-label) text-(--text-field-print) uppercase\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      <span\n        aria-hidden\n        data-slot=\"text-field-lamp\"\n        className=\"bevel-led size-1.5 shrink-0 rounded-full opacity-0 transition-opacity duration-(--bevel-duration-small) ease-(--bevel-ease-out) in-data-invalid:opacity-100 motion-reduce:transition-none\"\n      />\n    </Field.Label>\n  )\n}\n\n// flex-1 only inside a slot: on a bare input in the field's column, its 0% basis beats the height.\nconst control =\n  \"min-w-0 in-data-[slot=text-field-slot]:flex-1 text-sm text-foreground focus-visible:outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:text-muted-foreground\"\n\n/**\n * The slot, when the field has adornments: an icon, a unit, a key hint.\n * Put TextFieldAdornment, TextFieldKbd and the control inside it; pressing\n * anywhere in the slot focuses the control.\n */\nfunction TextFieldSlot({ className, onPointerDown, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"text-field-slot\"\n      onPointerDown={(event) => {\n        onPointerDown?.(event)\n        const target = event.target as HTMLElement\n        if (event.defaultPrevented || target.closest(\"input, textarea, button, a\")) return\n        const field = event.currentTarget.querySelector<HTMLElement>(\"input, textarea\")\n        if (!field || (field as HTMLInputElement).disabled) return\n        event.preventDefault()\n        field.focus()\n      }}\n      className={cn(\n        \"text-field-well flex min-h-(--text-field-height) w-full cursor-text items-center gap-2 rounded-(--bevel-radius-sm) px-3 in-data-disabled:cursor-not-allowed\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\n/** The input. Alone it is its own slot; inside TextFieldSlot it fills the slot. */\nfunction TextFieldInput({ className, ...props }: Input.Props) {\n  return (\n    <Input\n      data-slot=\"text-field-input\"\n      className={cn(\n        control,\n        \"text-field-well h-(--text-field-height) rounded-(--bevel-radius-sm) px-3\",\n        \"in-data-[slot=text-field-slot]:h-auto in-data-[slot=text-field-slot]:self-stretch in-data-[slot=text-field-slot]:rounded-none in-data-[slot=text-field-slot]:px-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\n/** A multi-line input in the same slot. Grows with its rows; resize vertically. */\nfunction TextFieldTextarea({ className, ...props }: Omit<Field.Control.Props, \"render\"> & React.ComponentProps<\"textarea\">) {\n  return (\n    <Field.Control\n      data-slot=\"text-field-textarea\"\n      render={<textarea />}\n      className={cn(\n        control,\n        \"text-field-well min-h-(--text-field-textarea-height) resize-y rounded-(--bevel-radius-sm) px-3 py-2 leading-relaxed\",\n        \"in-data-[slot=text-field-slot]:rounded-none in-data-[slot=text-field-slot]:px-0\",\n        className\n      )}\n      {...(props as Field.Control.Props)}\n    />\n  )\n}\n\n/** Something printed in the slot beside the text: an icon, a unit, a prefix. Decorative unless you label it. */\nfunction TextFieldAdornment({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"text-field-adornment\"\n      className={cn(\n        \"flex shrink-0 items-center text-sm text-(--text-field-print) select-none [&_svg]:size-4 [&_svg]:shrink-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\n/** A small keycap in the slot: the shortcut that focuses the field. */\nfunction TextFieldKbd({ className, ...props }: React.ComponentProps<\"kbd\">) {\n  return (\n    <kbd\n      data-slot=\"text-field-kbd\"\n      className={cn(\n        \"bevel-raised inline-flex h-5 shrink-0 items-center rounded-(--bevel-radius-xs) px-1.5 font-mono text-(length:--bevel-fine) leading-none text-(--text-field-key-print) select-none\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\n/** A line under the slot saying what goes in it. Linked to the control with aria-describedby. */\nfunction TextFieldDescription({ className, ...props }: Field.Description.Props) {\n  return (\n    <Field.Description\n      data-slot=\"text-field-description\"\n      className={cn(\"text-xs text-muted-foreground\", className)}\n      {...props}\n    />\n  )\n}\n\n/**\n * What's wrong, shown while the field is invalid and announced as it\n * appears. Pass match to show it for one validity state (valueMissing,\n * typeMismatch…), or match={true} to show it whenever it's rendered.\n */\nfunction TextFieldError({ className, ...props }: Field.Error.Props) {\n  return (\n    <Field.Error\n      data-slot=\"text-field-error\"\n      role=\"alert\"\n      className={cn(\"text-xs font-medium text-(--text-field-error-print)\", className)}\n      {...props}\n    />\n  )\n}\n\nexport {\n  TextField,\n  TextFieldLabel,\n  TextFieldSlot,\n  TextFieldInput,\n  TextFieldTextarea,\n  TextFieldAdornment,\n  TextFieldKbd,\n  TextFieldDescription,\n  TextFieldError,\n}\nexport type { TextFieldProps }\n",
      "type": "registry:ui"
    }
  ],
  "css": {
    ":root": {
      "--text-field-well": "oklch(0.955 0.004 90)",
      "--text-field-shade": "oklch(0 0 0 / 0.2)",
      "--text-field-glow": "oklch(0.76 0.15 68)",
      "--text-field-glow-soft": "oklch(0.76 0.15 68 / 0.35)",
      "--text-field-error": "oklch(0.6 0.21 27)",
      "--text-field-error-soft": "oklch(0.6 0.21 27 / 0.3)",
      "--text-field-error-print": "oklch(0.5 0.19 27)",
      "--text-field-print": "oklch(0.45 0.01 260)",
      "--text-field-key": "oklch(0.97 0.004 90)",
      "--text-field-key-edge": "oklch(0.8 0.006 90)",
      "--text-field-key-print": "oklch(0.4 0.01 260)",
      "--text-field-height": "2.25rem",
      "--text-field-textarea-height": "5.5rem"
    },
    ".dark": {
      "--text-field-well": "oklch(0.17 0.005 260)",
      "--text-field-shade": "oklch(0 0 0 / 0.7)",
      "--text-field-error-print": "oklch(0.72 0.17 25)",
      "--text-field-print": "oklch(0.72 0.01 260)",
      "--text-field-key": "oklch(0.32 0.006 260)",
      "--text-field-key-edge": "oklch(0.2 0.006 260)",
      "--text-field-key-print": "oklch(0.86 0.005 260)"
    },
    "[data-slot=\"text-field\"][data-size=\"sm\"]": {
      "--text-field-height": "2rem",
      "--text-field-textarea-height": "4.5rem"
    },
    "@utility text-field-well": {
      "--bevel-material-recess": "var(--text-field-well)",
      "--bevel-shade-strong": "var(--text-field-shade)",
      "background-color": "var(--bevel-material-recess)",
      "box-shadow": "var(--bevel-depth-recessed)"
    },
    "[data-slot=\"text-field-slot\"] :is([data-slot=\"text-field-input\"], [data-slot=\"text-field-textarea\"])": {
      "background-color": "transparent",
      "box-shadow": "none"
    },
    "[data-slot=\"text-field-slot\"]:has([data-slot=\"text-field-textarea\"])": {
      "align-items": "flex-start"
    },
    "[data-slot=\"text-field-slot\"]:focus-within, :is([data-slot=\"text-field-input\"], [data-slot=\"text-field-textarea\"]):not([data-slot=\"text-field-slot\"] *):focus-visible": {
      "box-shadow": "var(--bevel-depth-recessed), 0 0 0 1px var(--text-field-glow), 0 0 0 3px var(--text-field-glow-soft)"
    },
    "[data-slot=\"text-field\"][data-invalid] :is([data-slot=\"text-field-slot\"], [data-slot=\"text-field-input\"], [data-slot=\"text-field-textarea\"]):not([data-slot=\"text-field-slot\"] *)": {
      "box-shadow": "var(--bevel-depth-recessed), 0 0 0 1px var(--text-field-error)"
    },
    "[data-slot=\"text-field\"][data-invalid] :is([data-slot=\"text-field-slot\"]:focus-within, :is([data-slot=\"text-field-input\"], [data-slot=\"text-field-textarea\"]):not([data-slot=\"text-field-slot\"] *):focus-visible)": {
      "box-shadow": "var(--bevel-depth-recessed), 0 0 0 1px var(--text-field-error), 0 0 0 3px var(--text-field-error-soft)"
    },
    "[data-slot=\"text-field-lamp\"]": {
      "--bevel-led": "var(--text-field-error)"
    },
    "[data-slot=\"text-field-kbd\"]": {
      "--bevel-material": "var(--text-field-key)",
      "--bevel-material-edge": "var(--text-field-key-edge)"
    },
    "@media (forced-colors: active)": {
      "[data-slot=\"text-field-slot\"], :is([data-slot=\"text-field-input\"], [data-slot=\"text-field-textarea\"]):not([data-slot=\"text-field-slot\"] *)": {
        "border": "1px solid CanvasText"
      },
      "[data-slot=\"text-field-slot\"]:focus-within, :is([data-slot=\"text-field-input\"], [data-slot=\"text-field-textarea\"]):not([data-slot=\"text-field-slot\"] *):focus-visible": {
        "outline": "2px solid Highlight"
      }
    }
  },
  "categories": [
    "essentials"
  ],
  "type": "registry:ui"
}