{"version":3,"file":"pagination.cjs","names":[],"sources":["../src/content/pagination/pagination.ts"],"sourcesContent":["import { define, getHost, html, prop, useEmit } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\n\nimport '../icon/icon';\nimport '../../inputs/button/button';\n\nimport { sizableBundle, themableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, sizeVariantMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\nimport componentStyles from './pagination.css?inline';\n\nexport type OrePaginationEvents = {\n  change: { page: number };\n};\n\nexport type OrePaginationProps = {\n  color?: ThemeColor;\n  label?: string;\n  page?: number;\n  'show-first-last'?: boolean;\n  'show-prev-next'?: boolean;\n  siblings?: number;\n  size?: ComponentSize;\n  'total-pages'?: number;\n  variant?: VisualVariant;\n};\n\nfunction buildPageRange(\n  currentPage: number,\n  totalPages: number,\n  siblings: number,\n): Array<number | 'ellipsis-start' | 'ellipsis-end'> {\n  const BOUNDARY = 1; // always show first and last page\n  const total = totalPages;\n  const pages: Array<number | 'ellipsis-start' | 'ellipsis-end'> = [];\n\n  // If total is small enough, show all pages\n  if (total <= 2 * BOUNDARY + 2 * siblings + 3) {\n    return Array.from({ length: total }, (_, i) => i + 1);\n  }\n\n  const leftSibling = Math.max(currentPage - siblings, BOUNDARY + 1);\n  const rightSibling = Math.min(currentPage + siblings, total - BOUNDARY);\n\n  pages.push(1);\n\n  if (leftSibling > BOUNDARY + 2) pages.push('ellipsis-start');\n  else if (leftSibling === BOUNDARY + 2) pages.push(BOUNDARY + 1);\n\n  for (let i = leftSibling; i <= rightSibling; i++) pages.push(i);\n\n  if (rightSibling < total - BOUNDARY - 1) pages.push('ellipsis-end');\n  else if (rightSibling === total - BOUNDARY - 1) pages.push(total - BOUNDARY);\n\n  pages.push(total);\n\n  return pages;\n}\n\n/**\n * Page-based navigation control.\n *\n * @element ore-pagination\n *\n * @attr {number} page - Current page (1-indexed, default: 1)\n * @attr {number} total-pages - Total number of pages (required)\n * @attr {number} siblings - Sibling pages around current (default: 1)\n * @attr {boolean} show-first-last - Show first/last page buttons (default: false)\n * @attr {boolean} show-prev-next - Show prev/next buttons (default: false)\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant for nav buttons: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text' | 'frost' (default: 'ghost')\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} label - Accessible nav label (default: 'Pagination')\n *\n * @fires change - Emitted when the page changes, with { page: number }\n *\n * @cssprop --pagination-item-size - Width/height of each item\n * @cssprop --pagination-gap - Gap between items\n * @cssprop --pagination-radius - Border radius of items\n *\n * @part page-btn - Page button.\n * @part nav - Navigation container.\n * @part list - List container.\n * @part first-btn - First page button.\n * @part prev-btn - Previous page button.\n * @part next-btn - Next page button.\n * @part last-btn - Last page button.\n * @example\n * ```html\n * <!-- Basic -->\n * <ore-pagination page=\"3\" total-pages=\"10\" color=\"primary\"></ore-pagination>\n *\n * <!-- With prev/next and first/last buttons -->\n * <ore-pagination page=\"5\" total-pages=\"20\" show-prev-next show-first-last siblings=\"2\"></ore-pagination>\n *\n * <!-- Compact size -->\n * <ore-pagination page=\"1\" total-pages=\"5\" size=\"sm\" variant=\"ghost\"></ore-pagination>\n * ```\n */\nexport const PAGINATION_TAG = 'ore-pagination' as const;\ndefine<OrePaginationProps>(PAGINATION_TAG, {\n  props: {\n    ...themableBundle,\n    ...sizableBundle,\n    label: prop.string('Pagination'),\n    page: prop.number(1),\n    'show-first-last': prop.bool(false),\n    'show-prev-next': prop.bool(false),\n    siblings: prop.number(1),\n    'total-pages': prop.number(1),\n    variant: prop.string<VisualVariant>(),\n  },\n  setup(props) {\n    const el = getHost();\n    const emit = useEmit<OrePaginationEvents>();\n\n    function goTo(page: number) {\n      const total = props['total-pages'].value || 1;\n      const next = Math.min(Math.max(1, page), total);\n\n      if (next === props.page.value) return;\n\n      el.setAttribute('page', String(next));\n      emit('change', { page: next });\n    }\n\n    const pageItems = computed(() =>\n      buildPageRange(props.page.value || 1, props['total-pages'].value || 1, props.siblings.value ?? 1),\n    );\n\n    const isFirst = computed(() => (props.page.value || 1) <= 1);\n    const isLast = computed(() => (props.page.value || 1) >= (props['total-pages'].value || 1));\n\n    return html`\n      <nav aria-label=\"${props.label}\" part=\"nav\">\n        <ol class=\"pagination\" part=\"list\">\n          ${() =>\n            props['show-first-last'].value\n              ? html`\n                  <li>\n                    <button\n                      type=\"button\"\n                      class=\"nav-btn\"\n                      part=\"first-btn\"\n                      aria-label=\"First page\"\n                      ?disabled=${isFirst}\n                      @click=${() => goTo(1)}>\n                      <ore-icon name=\"chevrons-left\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n                    </button>\n                  </li>\n                `\n              : ''}\n          ${() =>\n            props['show-prev-next'].value\n              ? html`\n                  <li>\n                    <button\n                      type=\"button\"\n                      class=\"nav-btn\"\n                      part=\"prev-btn\"\n                      aria-label=\"Previous page\"\n                      ?disabled=${isFirst}\n                      @click=${() => goTo((props.page.value || 1) - 1)}>\n                      <ore-icon name=\"chevron-left\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n                    </button>\n                  </li>\n                `\n              : ''}\n          <li style=\"display: contents;\">\n            ${() =>\n              pageItems.value.map((item) => {\n                if (item === 'ellipsis-start' || item === 'ellipsis-end') {\n                  return html`\n                    <span class=\"ellipsis\" aria-hidden=\"true\">&hellip;</span>\n                  `;\n                }\n\n                const pg = item as number;\n                const isCurrent = pg === (props.page.value || 1);\n                const pgLabel = `Page ${pg}`;\n\n                return isCurrent\n                  ? html`\n                      <button\n                        type=\"button\"\n                        part=\"page-btn\"\n                        aria-label=\"${pgLabel}\"\n                        aria-current=\"page\"\n                        @click=${() => goTo(pg)}>\n                        ${pg}\n                      </button>\n                    `\n                  : html`\n                      <button type=\"button\" part=\"page-btn\" aria-label=\"${pgLabel}\" @click=${() => goTo(pg)}>\n                        ${pg}\n                      </button>\n                    `;\n              })}\n          </li>\n          ${() =>\n            props['show-prev-next'].value\n              ? html`\n                  <li>\n                    <button\n                      type=\"button\"\n                      class=\"nav-btn\"\n                      part=\"next-btn\"\n                      aria-label=\"Next page\"\n                      ?disabled=${isLast}\n                      @click=${() => goTo((props.page.value || 1) + 1)}>\n                      <ore-icon name=\"chevron-right\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n                    </button>\n                  </li>\n                `\n              : ''}\n          ${() =>\n            props['show-first-last'].value\n              ? html`\n                  <li>\n                    <button\n                      type=\"button\"\n                      class=\"nav-btn\"\n                      part=\"last-btn\"\n                      aria-label=\"Last page\"\n                      ?disabled=${isLast}\n                      @click=${() => goTo(props['total-pages'].value || 1)}>\n                      <ore-icon name=\"chevrons-right\" size=\"16\" aria-hidden=\"true\"></ore-icon>\n                    </button>\n                  </li>\n                `\n              : ''}\n        </ol>\n      </nav>\n    `;\n  },\n\n  styles: [coarsePointerMixin, colorThemeMixin, sizeVariantMixin(), componentStyles],\n});\n"],"mappings":"2WA2BA,SAAS,EACP,EACA,EACA,EACmD,CACnD,IACM,EAAQ,EACR,EAA2D,CAAC,EAGlE,GAAI,GAAS,EAAe,EAAI,EAAW,EACzC,OAAO,MAAM,KAAK,CAAE,OAAQ,CAAM,GAAI,EAAG,IAAM,EAAI,CAAC,EAGtD,IAAM,EAAc,KAAK,IAAI,EAAc,EAAU,CAAY,EAC3D,EAAe,KAAK,IAAI,EAAc,EAAU,EAAQ,CAAQ,EAEtE,EAAM,KAAK,CAAC,EAER,EAAc,EAAc,EAAM,KAAK,gBAAgB,EAClD,IAAgB,GAAc,EAAM,KAAK,CAAY,EAE9D,IAAK,IAAI,EAAI,EAAa,GAAK,EAAc,IAAK,EAAM,KAAK,CAAC,EAO9D,OALI,EAAe,EAAQ,EAAW,EAAG,EAAM,KAAK,cAAc,EACzD,IAAiB,EAAQ,EAAW,GAAG,EAAM,KAAK,EAAQ,CAAQ,EAE3E,EAAM,KAAK,CAAK,EAET,CACT,CA0CA,IAAa,EAAiB,kBAC9B,EAAA,EAAA,OAAA,CAA2B,EAAgB,CACzC,MAAO,CACL,GAAG,EAAA,eACH,GAAG,EAAA,cACH,MAAO,EAAA,KAAK,OAAO,YAAY,EAC/B,KAAM,EAAA,KAAK,OAAO,CAAC,EACnB,kBAAmB,EAAA,KAAK,KAAK,EAAK,EAClC,iBAAkB,EAAA,KAAK,KAAK,EAAK,EACjC,SAAU,EAAA,KAAK,OAAO,CAAC,EACvB,cAAe,EAAA,KAAK,OAAO,CAAC,EAC5B,QAAS,EAAA,KAAK,OAAsB,CACtC,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,GAAA,EAAO,EAAA,QAAA,CAA6B,EAE1C,SAAS,EAAK,EAAc,CAC1B,IAAM,EAAQ,EAAM,cAAc,CAAC,OAAS,EACtC,EAAO,KAAK,IAAI,KAAK,IAAI,EAAG,CAAI,EAAG,CAAK,EAE1C,IAAS,EAAM,KAAK,QAExB,EAAG,aAAa,OAAQ,OAAO,CAAI,CAAC,EACpC,EAAK,SAAU,CAAE,KAAM,CAAK,CAAC,EAC/B,CAEA,IAAM,GAAA,EAAY,EAAA,SAAA,KAChB,EAAe,EAAM,KAAK,OAAS,EAAG,EAAM,cAAc,CAAC,OAAS,EAAG,EAAM,SAAS,OAAS,CAAC,CAClG,EAEM,GAAA,EAAU,EAAA,SAAA,MAAgB,EAAM,KAAK,OAAS,IAAM,CAAC,EACrD,GAAA,EAAS,EAAA,SAAA,MAAgB,EAAM,KAAK,OAAS,KAAO,EAAM,cAAc,CAAC,OAAS,EAAE,EAE1F,MAAO,GAAA,IAAI;yBACU,EAAM,MAAM;;gBAGzB,EAAM,kBAAkB,CAAC,MACrB,EAAA,IAAI;;;;;;;kCAOc,EAAQ;mCACL,EAAK,CAAC,EAAE;;;;kBAK7B,GAAG;gBAEP,EAAM,iBAAiB,CAAC,MACpB,EAAA,IAAI;;;;;;;kCAOc,EAAQ;mCACL,GAAM,EAAM,KAAK,OAAS,GAAK,CAAC,EAAE;;;;kBAKvD,GAAG;;kBAGL,EAAU,MAAM,IAAK,GAAS,CAC5B,GAAI,IAAS,kBAAoB,IAAS,eACxC,MAAO,GAAA,IAAI;;oBAKb,IAAM,EAAK,EACL,EAAY,KAAQ,EAAM,KAAK,OAAS,GACxC,EAAU,QAAQ,IAExB,OAAO,EACH,EAAA,IAAI;;;;sCAIc,EAAQ;;qCAEP,EAAK,CAAE,EAAE;0BACtB,EAAG;;sBAGT,EAAA,IAAI;0EACkD,EAAQ,eAAiB,EAAK,CAAE,EAAE;0BAClF,EAAG;;qBAGf,CAAC,EAAE;;gBAGL,EAAM,iBAAiB,CAAC,MACpB,EAAA,IAAI;;;;;;;kCAOc,EAAO;mCACJ,GAAM,EAAM,KAAK,OAAS,GAAK,CAAC,EAAE;;;;kBAKvD,GAAG;gBAEP,EAAM,kBAAkB,CAAC,MACrB,EAAA,IAAI;;;;;;;kCAOc,EAAO;mCACJ,EAAK,EAAM,cAAc,CAAC,OAAS,CAAC,EAAE;;;;kBAK3D,GAAG;;;KAIjB,EAEA,OAAQ,CAAC,EAAA,mBAAoB,EAAA,gBAAiB,EAAA,iBAAiB,EAAG,EAAA,OAAe,CACnF,CAAC"}