{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "field-help",
  "title": "Help field",
  "description": "Styled field: the Help set. 5 decorative field variations (HintHelpField, TooltipField, CounterField, DescriptionField, LinkField) on the ai2 token system, driven by CSS token transitions and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/field-help.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { HelpCircle, Info } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Help field family: 5 form fields that share the same skeleton but each carry a\n   different HELP apparatus (an inline hint, a tooltip beside the label, a character\n   counter, a long description block, a link to the relevant documentation). In\n   every field the label is bound to the control with htmlFor/id and ALL the help\n   text enters the aria-describedby chain, so a screen reader sees it too.\n   Invalidity falls back to the standard danger appearance ON THE CONTROL via\n   aria-invalid. The ids come from useId. Color comes ONLY from tokens. Renders with\n   no props too. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst gap: Record<StyledSize, string> = {\n  sm: \"gap-1\",\n  md: \"gap-1.5\",\n  lg: \"gap-2\",\n  xl: \"gap-2.5\",\n}\n\nconst labelText: Record<StyledSize, string> = {\n  sm: \"text-xs\",\n  md: \"text-sm\",\n  lg: \"text-sm\",\n  xl: \"text-base\",\n}\n\nconst helpText: Record<StyledSize, string> = {\n  sm: \"text-xs\",\n  md: \"text-xs\",\n  lg: \"text-sm\",\n  xl: \"text-sm\",\n}\n\nconst controlHeight: Record<StyledSize, string> = {\n  sm: \"h-8 text-sm\",\n  md: \"h-9 text-sm\",\n  lg: \"h-10 text-base\",\n  xl: \"h-12 text-base\",\n}\n\nconst controlBase =\n  \"w-full rounded-md border border-field-border bg-transparent px-3 py-1 text-foreground outline-none transition-colors placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 aria-invalid:border-danger aria-invalid:ring-danger/20 dark:aria-invalid:ring-danger/40\"\n\nconst DEFAULT_LABEL = \"Display name\"\nconst DEFAULT_PLACEHOLDER = \"Ada Lovelace\"\n\ninterface FieldProps {\n  className?: string\n  size?: StyledSize\n  label?: React.ReactNode\n  description?: React.ReactNode\n}\n\nfunction FieldLabel({\n  htmlFor,\n  size,\n  children,\n  className,\n}: {\n  htmlFor: string\n  size: StyledSize\n  children: React.ReactNode\n  className?: string\n}) {\n  return (\n    <label\n      htmlFor={htmlFor}\n      data-slot=\"styled-field-label\"\n      className={cn(\"w-fit font-medium leading-none text-foreground select-none\", labelText[size], className)}\n    >\n      {children}\n    </label>\n  )\n}\n\n/* Hint: kontrolun altinda ikonlu, kisa bir ipucu satiri. */\nexport function HintHelpField({\n  className,\n  size = \"md\",\n  label = DEFAULT_LABEL,\n  description = \"Two to thirty characters. Letters and spaces only.\",\n}: FieldProps) {\n  const base = React.useId()\n  const controlId = `${base}-control`\n  const hintId = description != null && description !== false ? `${base}-hint` : undefined\n\n  return (\n    <div data-slot=\"styled-field\" className={cn(\"flex w-full max-w-xs flex-col\", gap[size], className)}>\n      <FieldLabel htmlFor={controlId} size={size}>\n        {label}\n      </FieldLabel>\n      <input id={controlId} placeholder={DEFAULT_PLACEHOLDER} aria-describedby={hintId} className={cn(controlBase, controlHeight[size])} />\n      {hintId ? (\n        <p\n          id={hintId}\n          data-slot=\"styled-field-description\"\n          className={cn(\n            \"flex items-center gap-1.5 leading-snug text-muted-foreground [&>svg]:size-3.5 [&>svg]:shrink-0 [&>i]:text-xs [&>i]:leading-none\",\n            helpText[size]\n          )}\n        >\n          <Info />\n          <span>{description}</span>\n        </p>\n      ) : null}\n    </div>\n  )\n}\n\n/* Tooltip: a help button beside the label that shows the description on\n   hover/focus. The description is always in the aria-describedby chain, independent\n   of its visibility. */\nexport function TooltipField({\n  className,\n  size = \"md\",\n  label = DEFAULT_LABEL,\n  description = \"This is the name other people see on your profile.\",\n}: FieldProps) {\n  const base = React.useId()\n  const controlId = `${base}-control`\n  const tipId = `${base}-tip`\n  const [open, setOpen] = React.useState(false)\n\n  return (\n    <div data-slot=\"styled-field\" className={cn(\"flex w-full max-w-xs flex-col\", gap[size], className)}>\n      <div className=\"flex items-center gap-1.5\">\n        <FieldLabel htmlFor={controlId} size={size}>\n          {label}\n        </FieldLabel>\n        <span className=\"relative inline-flex\">\n          <button\n            type=\"button\"\n            aria-label=\"Show help for this field\"\n            aria-expanded={open}\n            onMouseEnter={() => setOpen(true)}\n            onMouseLeave={() => setOpen(false)}\n            onFocus={() => setOpen(true)}\n            onBlur={() => setOpen(false)}\n            className=\"inline-flex size-4 items-center justify-center rounded-full text-muted-foreground outline-none transition-colors hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 [&>svg]:size-3.5 [&>svg]:shrink-0 [&>i]:text-xs [&>i]:leading-none\"\n          >\n            <HelpCircle />\n          </button>\n          {open ? (\n            <span\n              role=\"tooltip\"\n              className=\"absolute bottom-full left-1/2 z-10 mb-1.5 w-48 -translate-x-1/2 rounded-md border border-border bg-popover px-2.5 py-1.5 text-xs leading-snug text-popover-foreground shadow-md\"\n            >\n              {description}\n            </span>\n          ) : null}\n        </span>\n      </div>\n      <input id={controlId} placeholder={DEFAULT_PLACEHOLDER} aria-describedby={tipId} className={cn(controlBase, controlHeight[size])} />\n      <span id={tipId} className=\"sr-only\">\n        {description}\n      </span>\n    </div>\n  )\n}\n\n/* Counter: a character counter. Once the limit is exceeded the control turns aria-invalid and the counter shifts to the danger tone. State is held at the top, not in the unmounting subtree. */\nexport function CounterField({\n  className,\n  size = \"md\",\n  label = \"Bio\",\n  description = \"A short line about yourself.\",\n}: FieldProps) {\n  const base = React.useId()\n  const controlId = `${base}-control`\n  const descId = description != null && description !== false ? `${base}-desc` : undefined\n  const countId = `${base}-count`\n  const maxLength = 60\n  const [value, setValue] = React.useState(\"\")\n  const over = value.length > maxLength\n  const describedBy = [descId, countId].filter(Boolean).join(\" \")\n\n  return (\n    <div data-slot=\"styled-field\" className={cn(\"flex w-full max-w-xs flex-col\", gap[size], className)}>\n      <FieldLabel htmlFor={controlId} size={size}>\n        {label}\n      </FieldLabel>\n      <input\n        id={controlId}\n        placeholder=\"Builds design systems.\"\n        value={value}\n        onChange={(e) => setValue(e.target.value)}\n        aria-describedby={describedBy}\n        aria-invalid={over ? true : undefined}\n        className={cn(controlBase, controlHeight[size])}\n      />\n      <div className=\"flex items-start justify-between gap-3\">\n        {descId ? (\n          <p id={descId} data-slot=\"styled-field-description\" className={cn(\"leading-snug text-muted-foreground\", helpText[size])}>\n            {description}\n          </p>\n        ) : (\n          <span />\n        )}\n        <span\n          id={countId}\n          aria-live=\"polite\"\n          className={cn(\"shrink-0 font-mono tabular-nums leading-snug\", helpText[size], over ? \"font-medium text-danger\" : \"text-muted-foreground\")}\n        >\n          {value.length}/{maxLength}\n        </span>\n      </div>\n    </div>\n  )\n}\n\n/* Description: kontrolun USTUNDE duran genis aciklama blogu - kural uzunsa\n   kullanici yazmadan once okur. */\nexport function DescriptionField({\n  className,\n  size = \"md\",\n  label = \"Workspace slug\",\n  description = \"Used in your workspace URL. Lowercase letters, numbers and dashes only, between three and forty characters. You can change it later, but old links stop working.\",\n}: FieldProps) {\n  const base = React.useId()\n  const controlId = `${base}-control`\n  const descId = description != null && description !== false ? `${base}-desc` : undefined\n\n  return (\n    <div data-slot=\"styled-field\" className={cn(\"flex w-full max-w-xs flex-col\", gap[size], className)}>\n      <FieldLabel htmlFor={controlId} size={size}>\n        {label}\n      </FieldLabel>\n      {descId ? (\n        <p\n          id={descId}\n          data-slot=\"styled-field-description\"\n          className={cn(\"rounded-md border-l-2 border-border bg-surface-2 px-3 py-2 leading-relaxed text-muted-foreground\", helpText[size])}\n        >\n          {description}\n        </p>\n      ) : null}\n      <input id={controlId} placeholder=\"acme-design\" aria-describedby={descId} className={cn(controlBase, controlHeight[size])} />\n    </div>\n  )\n}\n\n/* Link: a link inside the description pointing to the relevant document; the link carries its own focus ring. */\nexport function LinkField({\n  className,\n  size = \"md\",\n  label = \"API key\",\n  description = \"Paste the secret key from your dashboard.\",\n  helpHref = \"/docs/agents\",\n}: FieldProps & { helpHref?: string }) {\n  const base = React.useId()\n  const controlId = `${base}-control`\n  const descId = description != null && description !== false ? `${base}-desc` : undefined\n\n  return (\n    <div data-slot=\"styled-field\" className={cn(\"flex w-full max-w-xs flex-col\", gap[size], className)}>\n      <FieldLabel htmlFor={controlId} size={size}>\n        {label}\n      </FieldLabel>\n      <input id={controlId} placeholder=\"sk_live_...\" aria-describedby={descId} className={cn(controlBase, controlHeight[size])} />\n      {descId ? (\n        <p id={descId} data-slot=\"styled-field-description\" className={cn(\"leading-snug text-muted-foreground\", helpText[size])}>\n          {description}{\" \"}\n          <a\n            href={helpHref}\n            className=\"rounded-sm font-medium text-primary underline underline-offset-2 outline-none transition-colors hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n          >\n            Where do I find it?\n          </a>\n        </p>\n      ) : null}\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/field-help.tsx"
    }
  ],
  "categories": [
    "styled",
    "field"
  ],
  "type": "registry:component"
}