{
  "generatedFrom": "aha-loader.contract.json",
  "component": "Loader",
  "slug": "aha-loader",
  "group": "AhaSlides surfaces",
  "tier": "leaf-lit",
  "summary": "The full-surface branded loading screen shown while a new environment boots — workspace → editor, or editor → presenting.",
  "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-loader';",
    "element": "aha-loader",
    "registers": "aha-loader"
  },
  "feeds": {
    "doc": "https://ahaslides-product.github.io/ahaslides-design/aha-loader/index.html",
    "md": "https://ahaslides-product.github.io/ahaslides-design/aha-loader/aha-loader.md",
    "agentJson": "https://ahaslides-product.github.io/ahaslides-design/aha-loader.agent.json",
    "llms": "https://ahaslides-product.github.io/ahaslides-design/aha-loader.llms.txt",
    "index": "https://ahaslides-product.github.io/ahaslides-design/llms.txt"
  },
  "recommendedSnippet": "html",
  "vibeCode": "Emit the HTML snippet by default — <aha-loader> 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-loader"
    },
    "vue": {
      "via": "web-component",
      "ref": "aha-loader"
    },
    "html": {
      "via": "web-component",
      "ref": "aha-loader",
      "runnable": "paste-and-run — no build step, renders on open"
    }
  },
  "props": [
    {
      "name": "label",
      "type": "string",
      "default": "Loading",
      "desc": "Accessible name announced by the role=status live region (e.g. \"Opening the editor…\")"
    }
  ],
  "tokens": [
    "white",
    "bg-container",
    "radius-xl",
    "ease-in-out"
  ],
  "spec": [
    {
      "label": "Ground",
      "value": "white full-surface (--aha-white); fills its container, min-height 240px"
    },
    {
      "label": "Tiles",
      "value": "five 120×120 rounded tiles (radius-xl 16), each centred, one prominent at a time"
    },
    {
      "label": "Art",
      "value": "reused <aha-illustration> spot art at 96px — loader-award · loader-wand · loader-plane · loader-ballot · loader-chart"
    },
    {
      "label": "Motion",
      "value": "soft-flow keyframe · 7.5s loop · 1.5s stagger across the five · easing --aha-ease-in-out"
    },
    {
      "label": "Reduced motion",
      "value": "prefers-reduced-motion stills the loop and holds one branded tile"
    },
    {
      "label": "Duration",
      "value": "override the loop length via the CSS custom property --aha-loader-duration (default 7.5s)"
    }
  ],
  "opinion": {
    "whenToUse": [
      {
        "what": "Loader",
        "when": "a full-screen environment transition — the user lands in a new surface (workspace → editor, editor → presenting) and waits for it to boot"
      },
      {
        "what": "Spin",
        "when": "an inline, indeterminate wait inside an existing surface — a button, a panel, a section loading in place"
      },
      {
        "what": "Skeleton",
        "when": "the layout of the content being loaded is known — show its shape rather than a spinner"
      }
    ],
    "note": "One Loader per transition, filling the whole surface. It is decorative brand motion, not a progress bar — don't pair it with a percentage. Keep the `label` a short present-tense phrase naming the destination (\"Opening the editor…\").",
    "dsv3": "COVERED — ported from the product Loader (stpancras-storybook UI/AhaLoader): a white full-screen screen cycling five branded icon-cards with a staggered soft-flow (7.5s loop, 1.5s stagger). Bindings: tile 120×120 radius-xl 16 (snapped onto the DS scale from the source 14), art the reused <aha-illustration> loader-* family at 96, easing --aha-ease-in-out. a11y: host role=status + aria-live=polite + aria-label from `label`; the loop stills under prefers-reduced-motion, holding one tile."
  },
  "surfaces": [
    "editor",
    "dashboard",
    "audience",
    "settings"
  ],
  "snippets": {
    "html": "<!-- Paste-and-run: save as .html and open in a browser. No build step.\n     <aha-loader> is the full-surface branded loading SCREEN for an environment transition\n     (workspace → editor, editor → presenting). One import registers it (and pulls the shared\n     <aha-illustration> spot art it reuses). Make its container full-screen for a real transition. -->\n<script type=\"module\">\n  import 'https://cdn.jsdelivr.net/gh/ahaslides-product/ahaslides-design@master/lib/aha-loader.js';   // registers <aha-loader> (+ <aha-illustration>)\n</script>\n\n<!-- Fill the viewport while the next environment boots. -->\n<div style=\"position:fixed; inset:0\">\n  <aha-loader label=\"Opening the editor…\"></aha-loader>\n</div>\n\n<!-- Or drop it into any sized box (it fills its container, min-height 240px). -->\n<div style=\"width:100%; height:360px\">\n  <aha-loader label=\"Starting the presentation…\"></aha-loader>\n</div>\n",
    "react": "import '@ahaslides-product/design/aha-loader';   // registers <aha-loader> (+ the reused <aha-illustration> spot art)\n\n// The full-surface branded loading SCREEN for an environment transition — workspace → editor,\n// editor → presenting. It fills its container, so make that container full-screen for a real\n// transition. Decorative brand motion, not a progress bar: give it a `label`, never a percentage.\n// For an inline indeterminate wait inside an existing surface, reach for <aha-spin> instead.\n\n// Full-screen while the next environment boots.\nfunction EnvironmentTransition({ loading, children }) {\n  if (loading) {\n    return (\n      <div style={{ position: 'fixed', inset: 0 }}>\n        <aha-loader label=\"Opening the editor…\" />\n      </div>\n    );\n  }\n  return children;\n}\n\n// Or inside any sized box (it fills its container, min-height 240px).\n<div style={{ width: '100%', height: 360 }}>\n  <aha-loader label=\"Starting the presentation…\" />\n</div>\n",
    "vue": "// main.ts — register the element + its reused spot art, and mark aha-* as custom elements\nimport '@ahaslides-product/design/aha-loader';   // registers <aha-loader> (+ the reused <aha-illustration>)\napp.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');\n\n// Component.vue — the full-surface branded loading SCREEN for an environment transition\n// (workspace → editor, editor → presenting). It fills its container, so make that container\n// full-screen for a real transition. Decorative brand motion, not a progress bar: pass a `label`,\n// never a percentage. For an inline indeterminate wait, reach for <aha-spin> instead.\n<template>\n  <!-- Full-screen while the next environment boots -->\n  <div v-if=\"loading\" style=\"position:fixed; inset:0\">\n    <aha-loader label=\"Opening the editor…\" />\n  </div>\n\n  <!-- Or inside any sized box (it fills its container, min-height 240px) -->\n  <div style=\"width:100%; height:360px\">\n    <aha-loader label=\"Starting the presentation…\" />\n  </div>\n</template>\n"
  }
}
