{
  "generatedFrom": "skeleton.contract.json",
  "component": "Skeleton",
  "slug": "skeleton",
  "group": "Feedback",
  "tier": "leaf-lit",
  "summary": "A greyed placeholder that holds a component's shape while its content loads.",
  "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-skeleton';",
    "element": "aha-skeleton",
    "registers": "aha-skeleton"
  },
  "feeds": {
    "doc": "https://ahaslides-product.github.io/ahaslides-design/skeleton/index.html",
    "md": "https://ahaslides-product.github.io/ahaslides-design/skeleton/skeleton.md",
    "agentJson": "https://ahaslides-product.github.io/ahaslides-design/skeleton.agent.json",
    "llms": "https://ahaslides-product.github.io/ahaslides-design/skeleton.llms.txt",
    "index": "https://ahaslides-product.github.io/ahaslides-design/llms.txt"
  },
  "recommendedSnippet": "html",
  "vibeCode": "Emit the HTML snippet by default — <aha-skeleton> 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-skeleton"
    },
    "vue": {
      "via": "web-component",
      "ref": "aha-skeleton"
    },
    "html": {
      "via": "web-component",
      "ref": "aha-skeleton",
      "runnable": "paste-and-run — no build step, renders on open"
    }
  },
  "props": [
    {
      "name": "variant",
      "type": "text | paragraph | title | avatar | button | input | image",
      "default": "text",
      "desc": "Placeholder shape"
    },
    {
      "name": "rows",
      "type": "number",
      "default": "3",
      "desc": "Paragraph line count (last row is shorter); paragraph variant only"
    },
    {
      "name": "round",
      "type": "boolean",
      "default": "false",
      "desc": "Soften button/input/image corners to the pill"
    },
    {
      "name": "active",
      "type": "boolean",
      "default": "true",
      "desc": "Animate the shimmer (set 'false' to freeze)"
    }
  ],
  "tokens": [
    "gray-30",
    "gray-50",
    "radius-xs",
    "radius-default",
    "radius-pill"
  ],
  "spec": [
    {
      "label": "Fill",
      "value": "#F1F1F1 · radius xs (4)"
    },
    {
      "label": "Text",
      "value": "height 16 · full width"
    },
    {
      "label": "Paragraph",
      "value": "N rows (12 gap); last row 60% width"
    },
    {
      "label": "Title",
      "value": "height 24 · 38% width"
    },
    {
      "label": "Avatar",
      "value": "40×40 · radius pill"
    },
    {
      "label": "Button / Input",
      "value": "height 32 / 36 · radius default (8)"
    },
    {
      "label": "Image",
      "value": "height 96 · centred gray-50 image glyph · radius default"
    },
    {
      "label": "Round",
      "value": "corner-bearing variants soften to the pill"
    },
    {
      "label": "Motion",
      "value": "opacity pulse 1.6s (respects reduced-motion); active=false stops it"
    }
  ],
  "opinion": {
    "whenToUse": [
      {
        "what": "Skeleton",
        "when": "content is loading and you want to hold its exact layout to avoid a jump"
      },
      {
        "what": "Spin",
        "when": "a short, indeterminate wait where the final shape is unknown"
      },
      {
        "what": "Progress",
        "when": "you can measure completion (a percentage)"
      }
    ],
    "note": "Match the skeleton to the real content's shape and size so nothing shifts when it resolves. Use it for the first load of a region; don't stack many pulsing blocks for a sub-second wait — a Spin is calmer.",
    "dsv3": "COVERED — enumerated from the DS V3 Skeleton component-set (Design System V3 / 'Sceleton', fileKey MwjvUjVI0HnfwD9EwPXRAy) + antd Skeleton building blocks: paragraph (N rows, last shorter), title, avatar (round bust), button, input, and image (framed picture placeholder), plus an `active` shimmer and `round` corners. The common composite is avatar + title + paragraph (a list item). Token layer: fill gray-30, image glyph gray-50, radius-xs default / radius-default for controls / radius-pill for avatar + round. Shimmer is an opacity pulse, NOT a gradient, to honour the no-gradient-on-fills rule."
  },
  "surfaces": [
    "editor",
    "dashboard",
    "audience"
  ],
  "snippets": {
    "html": "<!-- Paste-and-run: save as .html and open in a browser. No build step.\n     <aha-skeleton> 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';        // <aha-icon> for the image glyph\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-skeleton.js'; // registers <aha-skeleton>\n</script>\n\n<!-- The common list-item shape: avatar + title + a multi-row paragraph (last row shorter) -->\n<div style=\"display:flex; gap:16px; align-items:flex-start; max-width:420px\">\n  <aha-skeleton variant=\"avatar\"></aha-skeleton>\n  <div style=\"flex:1; display:flex; flex-direction:column; gap:12px\">\n    <aha-skeleton variant=\"title\"></aha-skeleton>\n    <aha-skeleton variant=\"paragraph\" rows=\"3\"></aha-skeleton>\n    <div style=\"display:flex; gap:12px\">\n      <aha-skeleton variant=\"button\"></aha-skeleton>       <!-- round for a pill: variant=\"button\" round -->\n      <aha-skeleton variant=\"image\" style=\"width:120px\"></aha-skeleton>\n    </div>\n  </div>\n</div>\n",
    "react": "import '@ahaslides-product/design/icons';        // registers <aha-icon> (image variant)\nimport '@ahaslides-product/design/aha-skeleton'; // registers <aha-skeleton>\n\n// Attributes only — no events — so React 18/19 can render the element directly.\nfunction AhaSkeleton({ variant, rows, active, round }) {\n  return (\n    <aha-skeleton\n      variant={variant}\n      {...(rows != null ? { rows: String(rows) } : {})}\n      {...(round ? { round: '' } : {})}\n      {...(active === false ? { active: 'false' } : {})}\n    />\n  );\n}\n\n// usage — hold the list-item shape while the card loads\n{loading\n  ? <AhaSkeleton variant=\"paragraph\" rows={3} />\n  : <CardBody>{body}</CardBody>}\n",
    "vue": "// main.ts — register the elements + mark aha-* as custom elements\nimport '@ahaslides-product/design/icons';        // registers <aha-icon> (image variant)\nimport '@ahaslides-product/design/aha-skeleton';\napp.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');\n\n// Component.vue\n<script setup>\nimport { ref } from 'vue';\nconst loading = ref(true);\n</script>\n\n<template>\n  <aha-skeleton v-if=\"loading\" variant=\"paragraph\" rows=\"3\" />\n  <CardBody v-else>{{ body }}</CardBody>\n</template>\n"
  }
}
