{
  "generatedFrom": "textarea.contract.json",
  "component": "Textarea",
  "slug": "textarea",
  "group": "Data Entry",
  "tier": "composite-antd",
  "summary": "Enter multi-line free text — descriptions, messages, notes — with autosize and char count, rendered through the shared Textarea.",
  "install": {
    "package": "@ahaslides-product/design",
    "registry": "https://npm.pkg.github.com",
    "scope": "@ahaslides-product",
    "auth": "Published to GitHub Packages — needs a GitHub token with read:packages. Configure the @ahaslides-product scope in .npmrc before installing.",
    "npmrc": "@ahaslides-product:registry=https://npm.pkg.github.com\n//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}   # a GitHub token with read:packages",
    "command": "npm i @ahaslides-product/design",
    "tokenLayer": "import '@ahaslides-product/design/tokens.css';",
    "import": "import '@ahaslides-product/design/textarea-theme';",
    "element": null,
    "registers": null
  },
  "feeds": {
    "doc": "https://ahaslides-product.github.io/ahaslides-design/textarea/index.html",
    "md": "https://ahaslides-product.github.io/ahaslides-design/textarea/textarea.md",
    "agentJson": "https://ahaslides-product.github.io/ahaslides-design/textarea.agent.json",
    "llms": "https://ahaslides-product.github.io/ahaslides-design/textarea.llms.txt",
    "index": "https://ahaslides-product.github.io/ahaslides-design/llms.txt"
  },
  "recommendedSnippet": "html",
  "vibeCode": "Emit the HTML snippet by default — a CDN-React runnable page (React + antd loaded from a CDN, no build step) — React/Vue use the same shared-themed DataTable via your bundler. Paste into an .html file and it renders with no build step.",
  "frameworks": {
    "react": {
      "package": "antd",
      "major": 6
    },
    "vue": {
      "package": "ant-design-vue",
      "major": 4
    },
    "html": {
      "via": "cdn-react",
      "runnable": "paste-and-run — React + antd loaded from a CDN, no build step"
    }
  },
  "props": [
    {
      "name": "value",
      "type": "string",
      "default": "\"\"",
      "desc": "Controlled text value"
    },
    {
      "name": "size",
      "type": "'small' | 'middle' | 'large'",
      "default": "'middle'",
      "desc": "Control height / padding: small 24, default 32, large 40"
    },
    {
      "name": "status",
      "type": "'error' | 'warning'",
      "default": "—",
      "desc": "Validation state — recolours the border"
    },
    {
      "name": "disabled",
      "type": "boolean",
      "default": "false",
      "desc": "Non-interactive; greyed fill"
    },
    {
      "name": "readOnly",
      "type": "boolean",
      "default": "false",
      "desc": "Shows value but blocks editing"
    },
    {
      "name": "placeholder",
      "type": "string",
      "default": "—",
      "desc": "Empty-state hint (#8A8A8A)"
    },
    {
      "name": "rows",
      "type": "number",
      "default": "—",
      "desc": "Fixed visible rows"
    },
    {
      "name": "autoSize",
      "type": "boolean | { minRows, maxRows }",
      "default": "false",
      "desc": "Grow with content between bounds"
    },
    {
      "name": "maxLength",
      "type": "number",
      "default": "—",
      "desc": "Cap length; pair with showCount"
    },
    {
      "name": "showCount",
      "type": "boolean",
      "default": "false",
      "desc": "Show the character counter"
    },
    {
      "name": "onChange",
      "type": "(e) => void",
      "default": "—",
      "desc": "Fires on each change; read e.target.value"
    }
  ],
  "tokens": [
    "colorPrimary",
    "borderRadius",
    "colorBorder",
    "colorTextPlaceholder",
    "Input.activeBorderColor",
    "Input.hoverBorderColor"
  ],
  "spec": [
    {
      "label": "Box",
      "value": "radius 8 · 1px #E3E3E3 border · padding 4 11"
    },
    {
      "label": "Hover",
      "value": "#D3B4FF (purple-30) border"
    },
    {
      "label": "Focus",
      "value": "brand #6A1EBB border"
    },
    {
      "label": "Text",
      "value": "Plus Jakarta 14/21; placeholder #8A8A8A"
    },
    {
      "label": "Sizing",
      "value": "rows or autoSize={{minRows,maxRows}}"
    },
    {
      "label": "Size",
      "value": "small · default · large (control height 24/32/40)"
    },
    {
      "label": "Status",
      "value": "error #F5222D · warning #FAAD14 border"
    }
  ],
  "opinion": {
    "whenToUse": [
      {
        "what": "Textarea",
        "when": "multi-line free text — a description, a message, notes"
      },
      {
        "what": "Input",
        "when": "short single-line text — a name, a title, a search term"
      },
      {
        "what": "Select",
        "when": "one value from a known set — don't make the user type it"
      }
    ],
    "note": "Prefer autoSize with a minRows/maxRows band so the field grows with content but never dominates the layout. Pair maxLength with showCount so the limit is visible, not a surprise on submit.",
    "dsv3": "COVERED — antd v6 Input.TextArea themed by textareaTheme; matrix: size {small,middle(default),large} × status {none,error,warning} × extras {autoSize,showCount+maxLength,disabled,readOnly}, placeholder throughout. Sizes map to control heights 24/32/40 and status to #F5222D/#FAAD14 borders (measured inp|{sm,md,lg}|{rest,focus,disabled,error}); verified via Figma search_design_system against the DS V3 Textarea + Form-Item/Textarea set (fileKey MwjvUjVI0HnfwD9EwPXRAy)."
  },
  "surfaces": [
    "editor",
    "dashboard",
    "settings",
    "audience"
  ],
  "snippets": {
    "html": "<!-- Paste-and-run: save as .html and open in a browser. No build step, no bundler.\n     Textarea is a COMPOSITE (antd, no framework-free element), so its HTML form is a CDN-React\n     page — React + antd load from a CDN (esm.sh) and mount on open. It consumes the SAME shared\n     `textareaTheme` the React/Vue wrappers use, so it renders the DS V3 look (radius 8, #E3E3E3\n     border, brand focus/hover, #8A8A8A placeholder).\n     No JSX here (JSX needs a compiler) — we use React.createElement via the `h` alias. -->\n<div id=\"root\"></div>\n<script type=\"module\">\n  import React from 'https://esm.sh/react@18';\n  import { createRoot } from 'https://esm.sh/react-dom@18/client';\n  import { ConfigProvider, Input } from 'https://esm.sh/antd@6?deps=react@18,react-dom@18';\n  import { textareaTheme } from 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/textarea-theme.js';\n\n  const h = React.createElement;\n  const { TextArea } = Input;\n\n  // size: 'small' | 'middle' (default) | 'large' → control height 24 / 32 / 40\n  // status: 'error' | 'warning' → recolours the border for validation\n  createRoot(document.getElementById('root')).render(\n    h(ConfigProvider, { theme: textareaTheme },\n      h('div', { style: { display: 'grid', gap: 12, width: 340 } },\n        h(TextArea, { placeholder: 'Describe your event', size: 'middle',\n                      autoSize: { minRows: 3, maxRows: 6 }, showCount: true, maxLength: 200 }),\n        h(TextArea, { status: 'error', defaultValue: 'Fix this', autoSize: { minRows: 2 } }),\n        h(TextArea, { readOnly: true, defaultValue: 'Read-only content' }),\n        h(TextArea, { disabled: true, placeholder: 'Disabled' })\n      )\n    )\n  );\n</script>\n",
    "react": "import { ConfigProvider, Input } from 'antd';   // antd v6\nimport { textareaTheme } from '@ahaslides-product/design/textarea-theme';\n\nconst { TextArea } = Input;\n\n<ConfigProvider theme={textareaTheme}>\n  {/* size: 'small' | 'middle' (default) | 'large' → control height 24 / 32 / 40 */}\n  {/* status: 'error' | 'warning' → recolours the border for validation */}\n  <TextArea\n    placeholder=\"Describe your event\"\n    size=\"middle\"\n    status={hasError ? 'error' : undefined}\n    autoSize={{ minRows: 3, maxRows: 6 }}\n    showCount\n    maxLength={200}\n    onChange={(e) => setText(e.target.value)}\n    style={{ width: 340 }}\n  />\n\n  {/* Non-editable states inherit the same theme */}\n  <TextArea readOnly value=\"Read-only content\" style={{ width: 340 }} />\n  <TextArea disabled placeholder=\"Disabled\" style={{ width: 340 }} />\n</ConfigProvider>\n// One shared textareaTheme → the DS V3 look; size/status/disabled/readOnly all inherit it.\n// autoSize grows with content, showCount surfaces the cap.\n",
    "vue": "<script setup>\nimport { ref } from 'vue';\nimport { ConfigProvider, Input } from 'ant-design-vue';   // ant-design-vue v4\nimport { textareaTheme } from '@ahaslides-product/design/textarea-theme';\n\nconst Textarea = Input.TextArea;\nconst text = ref('');\nconst hasError = ref(false);\n</script>\n\n<template>\n  <a-config-provider :theme=\"textareaTheme\">\n    <!-- size: 'small' | 'middle' (default) | 'large' → control height 24 / 32 / 40 -->\n    <!-- status: 'error' | 'warning' → recolours the border for validation -->\n    <Textarea\n      v-model:value=\"text\"\n      placeholder=\"Describe your event\"\n      size=\"middle\"\n      :status=\"hasError ? 'error' : undefined\"\n      :auto-size=\"{ minRows: 3, maxRows: 6 }\"\n      show-count\n      :maxlength=\"200\"\n      style=\"width: 340px\"\n    />\n\n    <!-- Non-editable states inherit the same theme -->\n    <Textarea read-only value=\"Read-only content\" style=\"width: 340px\" />\n    <Textarea disabled placeholder=\"Disabled\" style=\"width: 340px\" />\n  </a-config-provider>\n</template>\n<!-- The SAME textareaTheme as React → one DS V3 look across both vendor libraries. -->\n",
    "theme": "// @ahaslides-product/design/textarea-theme — declared ONCE, consumed by both tiers.\nimport { textareaTheme } from '@ahaslides-product/design/textarea-theme';\n\nexport const textareaTheme = {\n  token: {\n    colorPrimary: '#6A1EBB',\n    borderRadius: 8,\n    colorBorder: '#E3E3E3',\n    colorTextPlaceholder: '#8A8A8A',\n    fontFamily: 'var(--aha-font-product, \"Plus Jakarta Sans\", sans-serif)',\n  },\n  components: {\n    Input: {\n      activeBorderColor: '#6A1EBB',   // brand focus border\n      hoverBorderColor: '#D3B4FF',    // purple-30 hover border\n      borderRadius: 8,\n    },\n  },\n};\n"
  }
}
