{
  "generatedFrom": "empty.contract.json",
  "component": "Empty",
  "slug": "empty",
  "group": "Data Display",
  "tier": "leaf-lit",
  "summary": "The placeholder for a surface that has no data yet.",
  "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/aha-empty';",
    "element": "aha-empty",
    "registers": "aha-empty"
  },
  "feeds": {
    "doc": "https://ahaslides-product.github.io/ahaslides-design/empty/index.html",
    "md": "https://ahaslides-product.github.io/ahaslides-design/empty/empty.md",
    "agentJson": "https://ahaslides-product.github.io/ahaslides-design/empty.agent.json",
    "llms": "https://ahaslides-product.github.io/ahaslides-design/empty.llms.txt",
    "index": "https://ahaslides-product.github.io/ahaslides-design/llms.txt"
  },
  "recommendedSnippet": "html",
  "vibeCode": "Emit the HTML snippet by default — <aha-empty> is a standard custom element that renders on open — React/Vue are thin adapters over the same element. Paste into an .html file and it renders with no build step.",
  "frameworks": {
    "react": {
      "via": "web-component",
      "ref": "aha-empty"
    },
    "vue": {
      "via": "web-component",
      "ref": "aha-empty"
    },
    "html": {
      "via": "web-component",
      "ref": "aha-empty",
      "runnable": "paste-and-run — no build step, renders on open"
    }
  },
  "props": [
    {
      "name": "image",
      "type": "'default' | 'simple'",
      "default": "default",
      "desc": "Built-in illustration: 64×41 line art, or a smaller 48×30 low-key graphic for tight surfaces"
    },
    {
      "name": "description",
      "type": "string",
      "default": "—",
      "desc": "The caption; falls back to the default slot when absent, and renders nothing when set to \"\""
    },
    {
      "name": "(default slot)",
      "type": "slot",
      "default": "No data",
      "desc": "The caption (alternative to the `description` attribute)"
    },
    {
      "name": "image",
      "type": "slot",
      "default": "—",
      "desc": "A custom picture (e.g. an <aha-icon>) that supersedes the built-in illustration"
    },
    {
      "name": "action",
      "type": "slot",
      "default": "—",
      "desc": "An optional call to action (a button or link)"
    }
  ],
  "tokens": [
    "text-tertiary",
    "text-disabled",
    "font-product"
  ],
  "spec": [
    {
      "label": "Layout",
      "value": "centred column · gap 10 · padding 32/16 (simple: gap 8 · 20/16)"
    },
    {
      "label": "Illustration",
      "value": "default 64×41 · simple 48×30 line art · #B5B5B5 (text-disabled)"
    },
    {
      "label": "Caption",
      "value": "14/22 (simple 13/20) #8A8A8A (text-tertiary) · hidden when description=\"\""
    },
    {
      "label": "Custom image",
      "value": "slot=\"image\" · supersedes the built-in art"
    },
    {
      "label": "Action",
      "value": "slot=\"action\" · hidden when empty"
    }
  ],
  "opinion": {
    "whenToUse": [
      {
        "what": "Empty",
        "when": "a list, table, or panel has nothing to show yet"
      },
      {
        "what": "Result",
        "when": "reporting the outcome of an action (success, 404)"
      },
      {
        "what": "Skeleton",
        "when": "content is loading, not absent"
      }
    ],
    "note": "The caption says what's missing and, ideally, the next step — 'No responses yet — share the join link'. Keep one action; an empty state is a nudge, not a menu.",
    "dsv3": "COVERED — enumerated from the DS V3 <Empty> component-set (fileKey MwjvUjVI0HnfwD9EwPXRAy: <Empty> set + Empty/Customize + a separate Illustration component), matching antd Empty's matrix: a default illustration vs a smaller `simple` image, a `description` (or none), a custom picture (Customize / slot=\"image\"), and an optional action. Colour/size derived from the token layer (text-tertiary caption, text-disabled art) — a deliberate extension, not a per-cell measured match."
  },
  "surfaces": [
    "editor",
    "dashboard",
    "settings",
    "audience"
  ],
  "snippets": {
    "html": "<!-- Paste-and-run: save as .html and open in a browser. No build step.\n     <aha-empty> is the SAME shared custom element React and Vue consume — here in its\n     native form. Theming comes only from the --aha-* tokens in tokens.css. -->\n<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/tokens.css\">\n<script type=\"module\">\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/icons.js';       // registers <aha-icon> (custom-image slot)\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-empty.js';   // registers <aha-empty>\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-button.js';  // registers <aha-button>\n</script>\n\n<!-- description=\"…\" is the caption (or use the default slot); description=\"\" hides it.\n     image=\"default\" (line art) | \"simple\" (smaller, for tight surfaces).\n     slot=\"image\" swaps in a custom picture; slot=\"action\" is an optional CTA. -->\n<aha-empty description=\"No responses yet — share the join link\" style=\"width:280px\">\n  <aha-button slot=\"action\" variant=\"primary\">Copy link</aha-button>\n</aha-empty>\n\n<!-- simple variant, custom illustration, no action -->\n<aha-empty image=\"simple\" description=\"No results\">\n  <aha-icon slot=\"image\" name=\"system-folder\" size=\"40\"></aha-icon>\n</aha-empty>\n",
    "react": "import '@ahaslides-product/design/icons';      // registers <aha-icon> (custom-image slot)\nimport '@ahaslides-product/design/aha-empty';  // registers <aha-empty>\nimport '@ahaslides-product/design/aha-button'; // registers <aha-button>\n\n// `description` is the caption (or use children); description=\"\" hides it.\n// image=\"default\" | \"simple\"; slot=\"image\" swaps in a custom picture; slot=\"action\" is a CTA.\nfunction NoResponses({ onShare }) {\n  return (\n    <aha-empty description=\"No responses yet — share the join link\">\n      <aha-button slot=\"action\" variant=\"primary\" onClick={onShare}>Copy link</aha-button>\n    </aha-empty>\n  );\n}\n\n// simple variant with a custom illustration and no action\nfunction NoResults() {\n  return (\n    <aha-empty image=\"simple\" description=\"No results\">\n      <aha-icon slot=\"image\" name=\"system-folder\" size=\"40\" />\n    </aha-empty>\n  );\n}\n\n// usage\n<NoResponses onShare={copyJoinLink} />\n",
    "vue": "// main.ts — register the elements + mark aha-* as custom elements\nimport '@ahaslides-product/design/icons';      // registers <aha-icon> (custom-image slot)\nimport '@ahaslides-product/design/aha-empty';\nimport '@ahaslides-product/design/aha-button';\napp.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');\n\n// Component.vue\n// `description` is the caption (or use the default slot); description=\"\" hides it.\n// image=\"default\" | \"simple\"; slot=\"image\" swaps in a custom picture; slot=\"action\" is a CTA.\n<template>\n  <aha-empty description=\"No responses yet — share the join link\">\n    <aha-button slot=\"action\" variant=\"primary\" @click=\"copyJoinLink\">Copy link</aha-button>\n  </aha-empty>\n\n  <!-- simple variant with a custom illustration and no action -->\n  <aha-empty image=\"simple\" description=\"No results\">\n    <aha-icon slot=\"image\" name=\"system-folder\" size=\"40\" />\n  </aha-empty>\n</template>\n"
  }
}
