{
  "generatedFrom": "pagination.contract.json",
  "component": "Pagination",
  "slug": "pagination",
  "group": "Navigation",
  "tier": "leaf-lit",
  "summary": "A page selector for a paged list or table — prev / numbered pages with ellipsis / next; two sizes, a simple mode, and a whole-control disabled state.",
  "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-pagination';",
    "element": "aha-pagination",
    "registers": "aha-pagination"
  },
  "feeds": {
    "doc": "https://ahaslides-product.github.io/ahaslides-design/pagination/index.html",
    "md": "https://ahaslides-product.github.io/ahaslides-design/pagination/pagination.md",
    "agentJson": "https://ahaslides-product.github.io/ahaslides-design/pagination.agent.json",
    "llms": "https://ahaslides-product.github.io/ahaslides-design/pagination.llms.txt",
    "index": "https://ahaslides-product.github.io/ahaslides-design/llms.txt"
  },
  "recommendedSnippet": "html",
  "vibeCode": "Emit the HTML snippet by default — <aha-pagination> 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-pagination"
    },
    "vue": {
      "via": "web-component",
      "ref": "aha-pagination"
    },
    "html": {
      "via": "web-component",
      "ref": "aha-pagination",
      "runnable": "paste-and-run — no build step, renders on open"
    }
  },
  "props": [
    {
      "name": "total",
      "type": "number",
      "default": "0",
      "desc": "Total item count across all pages (used with page-size)"
    },
    {
      "name": "page-size",
      "type": "number",
      "default": "10",
      "desc": "Items per page; total ÷ page-size decides the page count"
    },
    {
      "name": "pages",
      "type": "number",
      "default": "—",
      "desc": "Direct page count; wins over total+page-size when set"
    },
    {
      "name": "current",
      "type": "number",
      "default": "1",
      "desc": "The active page (1-based); reflected as it changes"
    },
    {
      "name": "size",
      "type": "'default' | 'small'",
      "default": "default",
      "desc": "Cell scale: 32px square (default) or compact 24px (small)"
    },
    {
      "name": "simple",
      "type": "boolean",
      "default": "false",
      "desc": "Collapse the numbers to prev · n / total · next"
    },
    {
      "name": "disabled",
      "type": "boolean",
      "default": "false",
      "desc": "Disable the whole control (every cell not-allowed)"
    },
    {
      "name": "change",
      "type": "CustomEvent",
      "default": "—",
      "desc": "Composed event on page change, detail { page }"
    }
  ],
  "tokens": [
    "border",
    "border-hover",
    "border-disabled",
    "bg-container",
    "text-default",
    "text-inverse",
    "text-disabled",
    "text-tertiary",
    "color-primary",
    "border-focus",
    "radius-default"
  ],
  "spec": [
    {
      "label": "Cell (default)",
      "value": "min-width 32 · height 32 · radius 8 · SemiBold 600"
    },
    {
      "label": "Cell (small)",
      "value": "min-width 24 · height 24 · radius 6 · 12px"
    },
    {
      "label": "Rest",
      "value": "white bg, 1px border #E3E3E3, text-default"
    },
    {
      "label": "Hover",
      "value": "border-hover #D3B4FF + color-primary text (motion-fast + ease-out)"
    },
    {
      "label": "Current",
      "value": "color-primary #6A1EBB fill, text-inverse #FFFFFF"
    },
    {
      "label": "Ellipsis",
      "value": "… text-tertiary #8A8A8A, aria-hidden, for elided ranges"
    },
    {
      "label": "Simple",
      "value": "prev · <b>n</b> / total · next — n in color-primary"
    },
    {
      "label": "Disabled prev/next",
      "value": "text-disabled #B5B5B5, not-allowed"
    },
    {
      "label": "Disabled (all)",
      "value": "every cell not-allowed; current keeps brand fill at .55 opacity"
    },
    {
      "label": "Arrows",
      "value": "<aha-icon name=\"system-caret-left|right\" size=16>"
    }
  ],
  "opinion": {
    "whenToUse": [
      {
        "what": "Pagination",
        "when": "a long list or table is split into pages the user steps through"
      },
      {
        "what": "infinite scroll",
        "when": "a feed the user grazes — not a set they navigate by position"
      },
      {
        "what": "Load more",
        "when": "occasional appends where exact page position doesn't matter"
      }
    ],
    "note": "Show pagination only when there is more than one page. Keep page cells on the 32px square + radius-8 scale (or the 24px small scale for dense tables), and reserve the brand fill for the current page. The first/last ellipsis keeps long ranges compact; reach for simple mode when width is tight.",
    "dsv3": "COVERED — enumerated from the DS V3 Pagination component-set taxonomy: Pagination (the control) + Pagination / Page (the cell, carrying size + state variants) + a prev/next arrow. The family is size (default · small), the page window with ellipses for elided ranges, a current (brand-filled) page, a simple mode (prev · n / total · next), and a whole-control disabled. No measured Pagination cell ships in the reference set, so px/rgb are derived from the token layer (white rest, border #E3E3E3, border-hover #D3B4FF, color-primary #6A1EBB current fill, text-inverse label, radius-default 8 / radius-sm 6 small, text-tertiary ellipsis) + AntD Pagination conventions. Motion + arrow glyphs bound to the shared motion tokens and the DS icon library."
  },
  "surfaces": [
    "dashboard",
    "admin",
    "editor"
  ],
  "snippets": {
    "html": "<!-- Paste-and-run: save as .html and open in a browser. No build step.\n     <aha-pagination> 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/aha-pagination.js';   // registers <aha-pagination> (+ <aha-icon>)\n</script>\n\n<!-- total + page-size (the page count is total ÷ page-size); ellipsis appears for long ranges -->\n<aha-pagination id=\"pager\" total=\"248\" page-size=\"20\" current=\"3\"></aha-pagination>\n\n<!-- pages=\"12\" — pass a direct page count instead of total+page-size -->\n<aha-pagination pages=\"12\" current=\"3\"></aha-pagination>\n\n<!-- size=\"small\" — the compact 24px scale for dense tables -->\n<aha-pagination pages=\"12\" current=\"3\" size=\"small\"></aha-pagination>\n\n<!-- simple — prev · n / total · next, for tight widths -->\n<aha-pagination pages=\"12\" current=\"3\" simple></aha-pagination>\n\n<!-- disabled — the whole control -->\n<aha-pagination pages=\"12\" current=\"3\" disabled></aha-pagination>\n\n<script>\n  // `current` reflects as it changes; each step emits a composed `change` event.\n  document.getElementById('pager').addEventListener('change', (e) => console.log('page', e.detail.page));\n</script>\n",
    "react": "import '@ahaslides-product/design/aha-pagination';   // registers <aha-pagination> (+ <aha-icon>)\nimport { useRef, useEffect } from 'react';\n\n// React 18 needs a thin wrapper for the composed `change` event; React 19 can bind onChange directly.\nfunction AhaPagination({ total, pageSize, pages, current, size, simple, disabled, onChange }) {\n  const ref = useRef();\n  useEffect(() => {\n    const el = ref.current;\n    const h = (e) => onChange?.(e.detail.page);\n    el.addEventListener('change', h);\n    return () => el.removeEventListener('change', h);\n  });\n  return (\n    <aha-pagination\n      ref={ref}\n      total={total}\n      page-size={pageSize}\n      pages={pages}\n      current={current}\n      size={size}            // 'default' | 'small'\n      simple={simple ? '' : undefined}\n      disabled={disabled ? '' : undefined}\n    />\n  );\n}\n\n// usage — total+page-size (or pass pages instead), size, simple, disabled\n<AhaPagination total={248} pageSize={20} current={page} onChange={setPage} />\n<AhaPagination pages={12} current={page} size=\"small\" onChange={setPage} />\n<AhaPagination pages={12} current={page} simple onChange={setPage} />\n",
    "vue": "// main.ts — register the element + mark aha-* as custom elements\nimport '@ahaslides-product/design/aha-pagination';\napp.config.compilerOptions.isCustomElement = (tag) => tag.startsWith('aha-');\n\n// Component.vue\n<script setup>\nimport { ref } from 'vue';\nconst page = ref(3);\nfunction onChange(e) { page.value = e.detail.page; }\n</script>\n\n<template>\n  <!-- total + page-size (the page count is total ÷ page-size) -->\n  <aha-pagination :total=\"248\" :page-size=\"20\" :current=\"page\" @change=\"onChange\" />\n\n  <!-- pages=\"12\" — a direct page count; size=\"small\" | simple | disabled -->\n  <aha-pagination :pages=\"12\" :current=\"page\" size=\"small\" @change=\"onChange\" />\n  <aha-pagination :pages=\"12\" :current=\"page\" simple @change=\"onChange\" />\n  <aha-pagination :pages=\"12\" :current=\"page\" disabled @change=\"onChange\" />\n</template>\n"
  }
}
