{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "textarea-autosize",
  "title": "Autosize textarea",
  "description": "Styled textarea: the Autosize set. 5 decorative textarea variations (GrowTextarea, MaxTextarea, MinTextarea, FluidTextarea, FixedTextarea) on the ai2 token system, driven by CSS token transitions and sized sm to xl. Part of the free styled layer.",
  "dependencies": [],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/textarea-autosize.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Autosize textarea family: 5 multi-line fields that change the height behavior.\n   The difference is only the height policy: growing with the content, capped,\n   floored, fluid and fixed. The growth is done with a single scrollHeight\n   measurement (the height is first set to auto, then written to scrollHeight) and\n   runs ONLY on mount and on input, not on every render; that way there is no layout\n   thrash. The cap/floor is given with CSS max-h/min-h and the inline height stays\n   within them; the floor derives from the size axis, which is why size stays\n   meaningful in every variant. A height change is a layout measure, not an\n   animation; that is why motion/react is not needed. Color comes ONLY from tokens.\n   Each one wraps a real <textarea> and passes through all the native props. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst height: Record<StyledSize, string> = {\n  sm: \"min-h-16 text-sm\",\n  md: \"min-h-20 text-sm\",\n  lg: \"min-h-24 text-base\",\n  xl: \"min-h-28 text-base\",\n}\n\n/* Min varyantinin comert tabani; size ile birlikte olceklenir. */\nconst floor: Record<StyledSize, string> = {\n  sm: \"min-h-24\",\n  md: \"min-h-32\",\n  lg: \"min-h-40\",\n  xl: \"min-h-48\",\n}\n\nconst areaBase =\n  \"w-full rounded-lg border border-field-border bg-transparent px-3 py-2 text-foreground outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-danger aria-invalid:ring-danger/20 dark:aria-invalid:ring-danger/40\"\n\ntype Props = React.ComponentProps<\"textarea\"> & { size?: StyledSize }\n\n/* A hook that measures height from the content. The measurement is triggered only on mount and on input, not in the render loop. */\nfunction useAutosize() {\n  const ref = React.useRef<HTMLTextAreaElement>(null)\n\n  const measure = React.useCallback(() => {\n    const el = ref.current\n    if (!el) return\n    el.style.height = \"auto\"\n    el.style.height = `${el.scrollHeight}px`\n  }, [])\n\n  React.useEffect(() => {\n    measure()\n  }, [measure])\n\n  return { ref, measure }\n}\n\n/* Shared field: it carries an accessible name instead of a visible label (aria-label), which the consumer can override through props. When autosize is off the measurement is never wired up. */\nfunction AutosizeField({\n  className,\n  size = \"md\",\n  autosize,\n  onChange,\n  ...props\n}: Props & { autosize: boolean }) {\n  const { ref, measure } = useAutosize()\n\n  function handleChange(e: React.ChangeEvent<HTMLTextAreaElement>) {\n    if (autosize) measure()\n    onChange?.(e)\n  }\n\n  return (\n    <textarea\n      ref={autosize ? ref : undefined}\n      rows={1}\n      aria-label=\"Message\"\n      {...props}\n      onChange={handleChange}\n      className={cn(areaBase, height[size], className)}\n    />\n  )\n}\n\n/* Grow: it grows as content is added; no handle, no ceiling. */\nexport function GrowTextarea({ className, size = \"md\", ...props }: Props) {\n  return (\n    <span data-slot=\"styled-textarea\" className=\"flex w-72 max-w-full flex-col\">\n      <AutosizeField autosize size={size} {...props} className={cn(\"resize-none overflow-hidden\", className)} />\n    </span>\n  )\n}\n\n/* Max: it grows with the content but stops at a ceiling and lets scrolling take\n   over. */\nexport function MaxTextarea({ className, size = \"md\", ...props }: Props) {\n  return (\n    <span data-slot=\"styled-textarea\" className=\"flex w-72 max-w-full flex-col\">\n      <AutosizeField autosize size={size} {...props} className={cn(\"max-h-40 resize-none overflow-y-auto\", className)} />\n    </span>\n  )\n}\n\n/* Min: it starts from a generous floor, never goes below it, and grows with the\n   content. */\nexport function MinTextarea({ className, size = \"md\", ...props }: Props) {\n  return (\n    <span data-slot=\"styled-textarea\" className=\"flex w-72 max-w-full flex-col\">\n      <AutosizeField autosize size={size} {...props} className={cn(floor[size], \"resize-none overflow-hidden\", className)} />\n    </span>\n  )\n}\n\n/* Fluid: takes the full width, flowing from the size baseline up to a ceiling. */\nexport function FluidTextarea({ className, size = \"md\", ...props }: Props) {\n  return (\n    <span data-slot=\"styled-textarea\" className=\"flex w-full max-w-full flex-col\">\n      <AutosizeField autosize size={size} {...props} className={cn(\"max-h-64 resize-none overflow-y-auto\", className)} />\n    </span>\n  )\n}\n\n/* Fixed: no growth; the height is fixed by size and overflowing content scrolls. */\nexport function FixedTextarea({ className, size = \"md\", ...props }: Props) {\n  return (\n    <span data-slot=\"styled-textarea\" className=\"flex w-72 max-w-full flex-col\">\n      <AutosizeField autosize={false} size={size} {...props} className={cn(\"resize-none overflow-y-auto\", className)} />\n    </span>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/textarea-autosize.tsx"
    }
  ],
  "categories": [
    "styled",
    "textarea"
  ],
  "type": "registry:component"
}