{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "pagination",
  "title": "Pagination",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-svelte/components/pagination/Pagination.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface PaginationItem {\n    type: 'page' | 'ellipsis'\n    value?: number\n  }\n\n  export interface PaginationSlotProps {\n    page: number\n    pageCount: number\n  }\n\n  export interface PaginationProps extends Omit<HTMLAttributes<HTMLElement>, 'children'> {\n    /** Controlled page (1-based). Pair with `bind:page` or `onPageChange`. */\n    page?: number | undefined\n    defaultPage?: number\n    /** Total row count across all pages. */\n    total?: number\n    itemsPerPage?: number\n    siblingCount?: number\n    showEdges?: boolean\n    disabled?: boolean\n    ariaLabel?: string\n    children?: Snippet<[PaginationSlotProps]>\n    onPageChange?: (page: number) => void\n    ref?: HTMLElement | null\n  }\n\n  export interface PaginationContext {\n    readonly page: number\n    readonly pageCount: number\n    readonly disabled: boolean\n    readonly items: PaginationItem[]\n    goTo: (value: number) => void\n    goFirst: () => void\n    goPrev: () => void\n    goNext: () => void\n    goLast: () => void\n  }\n\n  export const PAGINATION_CTX = Symbol('uipkge-pagination')\n\n  /** Page/ellipsis window around the current page. Edges always win; a gap of exactly one page renders the page, not dots. */\n  export function buildPaginationItems(\n    page: number,\n    pageCount: number,\n    siblingCount = 1,\n    showEdges = false,\n  ): PaginationItem[] {\n    const total = Math.max(1, pageCount)\n    const current = Math.min(Math.max(page, 1), total)\n    const siblings = Math.max(0, siblingCount)\n    const start = Math.max(1, current - siblings)\n    const end = Math.min(total, current + siblings)\n    const items: PaginationItem[] = []\n    if (showEdges) {\n      if (start > 1) {\n        items.push({ type: 'page', value: 1 })\n        if (start > 2) items.push({ type: 'ellipsis' })\n      }\n      for (let v = start; v <= end; v++) items.push({ type: 'page', value: v })\n      if (end < total) {\n        if (end < total - 1) items.push({ type: 'ellipsis' })\n        items.push({ type: 'page', value: total })\n      }\n      return items\n    }\n    if (start > 1) items.push({ type: 'ellipsis' })\n    for (let v = start; v <= end; v++) items.push({ type: 'page', value: v })\n    if (end < total) items.push({ type: 'ellipsis' })\n    return items\n  }\n</script>\n\n<script lang=\"ts\">\n  import { setContext } from 'svelte'\n  import { cn } from '$lib/utils'\n\n  let {\n    class: className,\n    page = $bindable(undefined),\n    defaultPage = 1,\n    total = 0,\n    itemsPerPage = 10,\n    siblingCount = 1,\n    showEdges = false,\n    disabled = false,\n    ariaLabel = 'Pagination',\n    children,\n    onPageChange,\n    ref = $bindable(null),\n    ...restProps\n  }: PaginationProps = $props()\n\n  // svelte-ignore state_referenced_locally -- uncontrolled seed: later defaultPage changes must not reset the page.\n  let internalPage = $state(defaultPage)\n  const pageCount = $derived(Math.max(1, Math.ceil(total / Math.max(1, itemsPerPage))))\n  const currentPage = $derived(Math.min(Math.max(page ?? internalPage, 1), pageCount))\n  const items = $derived(buildPaginationItems(currentPage, pageCount, siblingCount, showEdges))\n\n  function setPage(value: number) {\n    if (disabled) return\n    const next = Math.min(Math.max(value, 1), pageCount)\n    if (page === undefined) internalPage = next\n    page = next\n    onPageChange?.(next)\n  }\n\n  // Getters stay reactive: consumers read them inside $derived / templates.\n  setContext<PaginationContext>(PAGINATION_CTX, {\n    get page() {\n      return currentPage\n    },\n    get pageCount() {\n      return pageCount\n    },\n    get disabled() {\n      return disabled\n    },\n    get items() {\n      return items\n    },\n    goTo: setPage,\n    goFirst: () => setPage(1),\n    goPrev: () => setPage(currentPage - 1),\n    goNext: () => setPage(currentPage + 1),\n    goLast: () => setPage(pageCount),\n  })\n</script>\n\n<nav\n  bind:this={ref}\n  aria-label={ariaLabel}\n  data-uipkge\n  data-slot=\"pagination\"\n  class={cn('flex items-center gap-1', className)}\n  {...restProps}\n>\n  {@render children?.({ page: currentPage, pageCount })}\n</nav>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/pagination/Pagination.svelte"
    },
    {
      "path": "packages/registry-svelte/components/pagination/PaginationEllipsis.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n\n  export interface PaginationEllipsisProps extends HTMLAttributes<HTMLSpanElement> {\n    children?: Snippet\n  }\n</script>\n\n<script lang=\"ts\">\n  import { MoreHorizontal } from '@lucide/svelte'\n  import { cn } from '$lib/utils'\n\n  let { class: className, children, ...restProps }: PaginationEllipsisProps = $props()\n</script>\n\n<li>\n  <span aria-hidden=\"true\" data-uipkge data-slot=\"pagination-ellipsis\" class={cn('shrink-0', className)} {...restProps}>\n    {#if children}\n      {@render children()}\n    {:else}\n      <MoreHorizontal class=\"size-4\" aria-hidden=\"true\" />\n    {/if}\n  </span>\n</li>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/pagination/PaginationEllipsis.svelte"
    },
    {
      "path": "packages/registry-svelte/components/pagination/PaginationFirst.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n\n  export interface PaginationFirstProps extends HTMLButtonAttributes {\n    children?: Snippet\n    ref?: HTMLButtonElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { ChevronsLeft } from '@lucide/svelte'\n  import { PAGINATION_CTX, type PaginationContext } from './Pagination.svelte'\n\n  let { class: className, children, disabled = false, ref = $bindable(null), ...restProps }: PaginationFirstProps =\n    $props()\n\n  const ctx = getContext<PaginationContext | undefined>(PAGINATION_CTX)\n  if (!ctx) throw new Error('PaginationFirst must be used inside <Pagination>')\n\n  const isDisabled = $derived(disabled || ctx.disabled || ctx.page <= 1)\n</script>\n\n<button\n  bind:this={ref}\n  type=\"button\"\n  data-uipkge\n  data-slot=\"pagination-first\"\n  aria-label=\"Go to first page\"\n  disabled={isDisabled}\n  class={className}\n  {...restProps}\n  onclick={() => ctx.goFirst()}\n>\n  {#if children}\n    {@render children()}\n  {:else}\n    <ChevronsLeft class=\"size-4\" aria-hidden=\"true\" />\n  {/if}\n</button>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/pagination/PaginationFirst.svelte"
    },
    {
      "path": "packages/registry-svelte/components/pagination/PaginationLast.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n\n  export interface PaginationLastProps extends HTMLButtonAttributes {\n    children?: Snippet\n    ref?: HTMLButtonElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { ChevronsRight } from '@lucide/svelte'\n  import { PAGINATION_CTX, type PaginationContext } from './Pagination.svelte'\n\n  let { class: className, children, disabled = false, ref = $bindable(null), ...restProps }: PaginationLastProps =\n    $props()\n\n  const ctx = getContext<PaginationContext | undefined>(PAGINATION_CTX)\n  if (!ctx) throw new Error('PaginationLast must be used inside <Pagination>')\n\n  const isDisabled = $derived(disabled || ctx.disabled || ctx.page >= ctx.pageCount)\n</script>\n\n<button\n  bind:this={ref}\n  type=\"button\"\n  data-uipkge\n  data-slot=\"pagination-last\"\n  aria-label=\"Go to last page\"\n  disabled={isDisabled}\n  class={className}\n  {...restProps}\n  onclick={() => ctx.goLast()}\n>\n  {#if children}\n    {@render children()}\n  {:else}\n    <ChevronsRight class=\"size-4\" aria-hidden=\"true\" />\n  {/if}\n</button>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/pagination/PaginationLast.svelte"
    },
    {
      "path": "packages/registry-svelte/components/pagination/PaginationList.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLAttributes } from 'svelte/elements'\n  import type { PaginationItem } from './Pagination.svelte'\n\n  export interface PaginationListSlotProps {\n    items: PaginationItem[]\n  }\n\n  export interface PaginationListProps extends Omit<HTMLAttributes<HTMLUListElement>, 'children'> {\n    children?: Snippet<[PaginationListSlotProps]>\n    ref?: HTMLUListElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { cn } from '$lib/utils'\n  import { PAGINATION_CTX, type PaginationContext } from './Pagination.svelte'\n\n  let { class: className, children, ref = $bindable(null), ...restProps }: PaginationListProps = $props()\n\n  const ctx = getContext<PaginationContext | undefined>(PAGINATION_CTX)\n  if (!ctx) throw new Error('PaginationList must be used inside <Pagination>')\n</script>\n\n<ul\n  bind:this={ref}\n  data-uipkge\n  data-slot=\"pagination-list\"\n  class={cn('flex items-center gap-1', className)}\n  {...restProps}\n>\n  {@render children?.({ items: ctx.items })}\n</ul>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/pagination/PaginationList.svelte"
    },
    {
      "path": "packages/registry-svelte/components/pagination/PaginationListItem.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n\n  export interface PaginationListItemProps extends HTMLButtonAttributes {\n    /** 1-based page number this item navigates to. */\n    value: number\n    children?: Snippet\n    ref?: HTMLButtonElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { cn } from '$lib/utils'\n  import { PAGINATION_CTX, type PaginationContext } from './Pagination.svelte'\n\n  let {\n    class: className,\n    value,\n    children,\n    disabled = false,\n    ref = $bindable(null),\n    ...restProps\n  }: PaginationListItemProps = $props()\n\n  const ctx = getContext<PaginationContext | undefined>(PAGINATION_CTX)\n  if (!ctx) throw new Error('PaginationListItem must be used inside <Pagination>')\n\n  const isActive = $derived(ctx.page === value)\n  const isDisabled = $derived(disabled || ctx.disabled)\n</script>\n\n<li>\n  <button\n    bind:this={ref}\n    type=\"button\"\n    data-uipkge\n    data-slot=\"pagination-list-item\"\n    data-selected={isActive ? true : undefined}\n    aria-current={isActive ? 'page' : undefined}\n    aria-label={`Page ${value}`}\n    disabled={isDisabled}\n    class={cn('shrink-0', className)}\n    {...restProps}\n    onclick={() => ctx.goTo(value)}\n  >\n    {@render children?.()}\n  </button>\n</li>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/pagination/PaginationListItem.svelte"
    },
    {
      "path": "packages/registry-svelte/components/pagination/PaginationNext.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n\n  export interface PaginationNextProps extends HTMLButtonAttributes {\n    children?: Snippet\n    ref?: HTMLButtonElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { ChevronRight } from '@lucide/svelte'\n  import { PAGINATION_CTX, type PaginationContext } from './Pagination.svelte'\n\n  let { class: className, children, disabled = false, ref = $bindable(null), ...restProps }: PaginationNextProps =\n    $props()\n\n  const ctx = getContext<PaginationContext | undefined>(PAGINATION_CTX)\n  if (!ctx) throw new Error('PaginationNext must be used inside <Pagination>')\n\n  const isDisabled = $derived(disabled || ctx.disabled || ctx.page >= ctx.pageCount)\n</script>\n\n<button\n  bind:this={ref}\n  type=\"button\"\n  data-uipkge\n  data-slot=\"pagination-next\"\n  aria-label=\"Go to next page\"\n  disabled={isDisabled}\n  class={className}\n  {...restProps}\n  onclick={() => ctx.goNext()}\n>\n  {#if children}\n    {@render children()}\n  {:else}\n    <ChevronRight class=\"size-4\" aria-hidden=\"true\" />\n  {/if}\n</button>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/pagination/PaginationNext.svelte"
    },
    {
      "path": "packages/registry-svelte/components/pagination/PaginationPrev.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Snippet } from 'svelte'\n  import type { HTMLButtonAttributes } from 'svelte/elements'\n\n  export interface PaginationPrevProps extends HTMLButtonAttributes {\n    children?: Snippet\n    ref?: HTMLButtonElement | null\n  }\n</script>\n\n<script lang=\"ts\">\n  import { getContext } from 'svelte'\n  import { ChevronLeft } from '@lucide/svelte'\n  import { PAGINATION_CTX, type PaginationContext } from './Pagination.svelte'\n\n  let { class: className, children, disabled = false, ref = $bindable(null), ...restProps }: PaginationPrevProps =\n    $props()\n\n  const ctx = getContext<PaginationContext | undefined>(PAGINATION_CTX)\n  if (!ctx) throw new Error('PaginationPrev must be used inside <Pagination>')\n\n  const isDisabled = $derived(disabled || ctx.disabled || ctx.page <= 1)\n</script>\n\n<button\n  bind:this={ref}\n  type=\"button\"\n  data-uipkge\n  data-slot=\"pagination-prev\"\n  aria-label=\"Go to previous page\"\n  disabled={isDisabled}\n  class={className}\n  {...restProps}\n  onclick={() => ctx.goPrev()}\n>\n  {#if children}\n    {@render children()}\n  {:else}\n    <ChevronLeft class=\"size-4\" aria-hidden=\"true\" />\n  {/if}\n</button>\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/pagination/PaginationPrev.svelte"
    },
    {
      "path": "packages/registry-svelte/components/pagination/index.ts",
      "content": "export {\n  default as Pagination,\n  buildPaginationItems,\n  type PaginationProps,\n  type PaginationSlotProps,\n  type PaginationItem,\n  type PaginationContext,\n} from './Pagination.svelte'\nexport {\n  default as PaginationList,\n  type PaginationListProps,\n  type PaginationListSlotProps,\n} from './PaginationList.svelte'\nexport { default as PaginationListItem, type PaginationListItemProps } from './PaginationListItem.svelte'\nexport { default as PaginationFirst, type PaginationFirstProps } from './PaginationFirst.svelte'\nexport { default as PaginationPrev, type PaginationPrevProps } from './PaginationPrev.svelte'\nexport { default as PaginationNext, type PaginationNextProps } from './PaginationNext.svelte'\nexport { default as PaginationLast, type PaginationLastProps } from './PaginationLast.svelte'\nexport { default as PaginationEllipsis, type PaginationEllipsisProps } from './PaginationEllipsis.svelte'\n",
      "type": "registry:ui",
      "target": "~/src/lib/components/ui/pagination/index.ts"
    }
  ],
  "dependencies": [
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Page-number bar with previous/next, ellipsis collapse, and a configurable visible-window size. Pair with a data-table or any paged list.",
  "categories": [
    "navigation"
  ]
}