{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "textarea",
  "title": "Textarea",
  "description": "Multi-line text field that starts at 64 px and grows with its content, so the answer is never hidden behind a scrollbar.",
  "registryDependencies": [
    "utils",
    "https://miseui.junsu4621.workers.dev/r/shimmer-text.json"
  ],
  "files": [
    {
      "path": "registry/miseui/ui/textarea.tsx",
      "content": "import type * as React from \"react\"\nimport { ShimmerText } from \"@/registry/miseui/ui/shimmer-text\"\nimport { cn } from \"@/registry/miseui/lib/utils\"\n\n/** 64 px: about three lines of room before any typing, so the field invites a real answer. */\nconst MIN_HEIGHT_CLASS = \"min-h-16\"\n\ntype TextareaEffect = \"glow\" | \"ai\"\n\ntype TextareaProps = React.ComponentProps<\"textarea\"> & {\n  /** A living treatment on the field. Undefined is the plain textarea. */\n  effect?: TextareaEffect\n  /** With effect=\"ai\": the placeholder shimmers while the model prepares a suggestion. */\n  pending?: boolean\n}\n\n/** Box-shadow is in the base transition list, so ring and halo grow from nothing on focus. An error must not glow warm. */\nconst GLOW_CLASS = cn(\n  \"duration-(--duration-base) ease-(--ease-mise-out) motion-reduce:transition-none\",\n  \"focus-visible:border-mise focus-visible:ring-4 focus-visible:ring-mise/35\",\n  \"focus-visible:shadow-[0_0_28px_4px_color-mix(in_oklab,var(--mise)_45%,transparent)]\",\n  \"[@media(prefers-reduced-transparency:reduce)]:focus-visible:shadow-none\",\n  \"aria-invalid:focus-visible:border-destructive aria-invalid:focus-visible:ring-destructive/30 aria-invalid:focus-visible:shadow-none\",\n)\n/** The native placeholder stays for assistive tech and for :placeholder-shown, which hides the overlay as soon as someone types. */\nconst PENDING_FIELD_CLASS = \"border-mise/60 placeholder:text-transparent\"\n/** Shimmer's bright band in the accent: mise is the colour of AI activity. Re-declared in this scope only. */\nconst PENDING_BAND_STYLE = { \"--foreground\": \"var(--mise)\" } as React.CSSProperties\n\nfunction Textarea({ className, effect, pending = false, ...props }: TextareaProps) {\n  const isAi = effect === \"ai\"\n  const shimmering = isAi && pending && Boolean(props.placeholder)\n  const field = (\n    <textarea\n      data-slot=\"textarea\"\n      data-effect={effect}\n      aria-busy={isAi && pending ? true : undefined}\n      className={cn(\n        MIN_HEIGHT_CLASS,\n        \"field-sizing-content flex w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-xs md:text-sm\",\n        \"placeholder:text-muted-foreground\",\n        \"transition-[color,border-color,box-shadow] duration-(--duration-fast) ease-(--ease-mise)\",\n        \"outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50\",\n        \"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40\",\n        \"disabled:cursor-not-allowed disabled:opacity-50\",\n        effect === \"glow\" && GLOW_CLASS,\n        isAi && \"peer\",\n        shimmering && PENDING_FIELD_CLASS,\n        className,\n      )}\n      {...props}\n    />\n  )\n  if (!isAi) return field\n  return (\n    // Stays mounted across `pending` so the field never remounts and keeps focus and typed text.\n    <div data-slot=\"textarea-frame\" className=\"relative w-full min-w-0\">\n      {field}\n      {shimmering ? (\n        <span\n          aria-hidden=\"true\"\n          data-testid=\"textarea-shimmer\"\n          className=\"pointer-events-none absolute top-[9px] right-[13px] left-[13px] hidden text-base peer-placeholder-shown:block md:text-sm\"\n        >\n          <ShimmerText style={PENDING_BAND_STYLE}>{props.placeholder ?? \"\"}</ShimmerText>\n        </span>\n      ) : null}\n    </div>\n  )\n}\n\nexport { Textarea, type TextareaProps, type TextareaEffect }\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "forms"
  ],
  "type": "registry:ui"
}