{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pagination",
  "title": "Pagination",
  "description": "Page numbers with gaps where the run is broken, as buttons or as your own links.",
  "dependencies": [
    "lucide-react@^1.31.0"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "registry/default/pagination/pagination.tsx",
      "content": "import * as React from \"react\"\nimport { ChevronLeft, ChevronRight } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport type PaginationLink = {\n  page: number\n  children: React.ReactNode\n  \"aria-label\"?: string\n  \"aria-current\"?: \"page\"\n  className: string\n}\n\nexport type PaginationProps = Omit<\n  React.HTMLAttributes<HTMLElement>,\n  \"children\" | \"onChange\"\n> & {\n  /** One-based. */\n  page: number\n  pageCount: number\n  onPageChange?: (page: number) => void\n  /** Pages either side of the current one. Defaults to 1. */\n  siblingCount?: number\n  /** Pages kept at each end. Defaults to 1. */\n  boundaryCount?: number\n  label?: string\n  /** Renders every page as your own link, for a paginated URL. */\n  renderLink?: (link: PaginationLink) => React.ReactNode\n}\n\nconst GAP = \"gap\"\n\n/** The pages to draw, with gaps where the run is broken. */\nexport function paginationRange({\n  page,\n  pageCount,\n  siblingCount = 1,\n  boundaryCount = 1,\n}: {\n  page: number\n  pageCount: number\n  siblingCount?: number\n  boundaryCount?: number\n}): (number | typeof GAP)[] {\n  if (pageCount <= 0) return []\n\n  const all = Array.from({ length: pageCount }, (_, index) => index + 1)\n  // Every gap costs a slot, so showing them is only worth it past this many.\n  if (pageCount <= boundaryCount * 2 + siblingCount * 2 + 3) return all\n\n  const start = Math.max(\n    Math.min(\n      page - siblingCount,\n      pageCount - boundaryCount - siblingCount * 2 - 1\n    ),\n    boundaryCount + 2\n  )\n  const end = Math.min(\n    Math.max(page + siblingCount, boundaryCount + siblingCount * 2 + 2),\n    pageCount - boundaryCount - 1\n  )\n\n  return [\n    ...all.slice(0, boundaryCount),\n    ...(start > boundaryCount + 1 ? [GAP as typeof GAP] : []),\n    ...all.slice(start - 1, end),\n    ...(end < pageCount - boundaryCount ? [GAP as typeof GAP] : []),\n    ...all.slice(pageCount - boundaryCount),\n  ]\n}\n\nconst ITEM =\n  \"inline-flex min-h-9 min-w-9 items-center justify-center rounded-md px-2 text-sm no-underline transition-colors duration-150 motion-reduce:transition-none\"\nconst IDLE = \"text-muted-foreground hover:bg-muted hover:text-foreground\"\nconst CURRENT = \"border-border bg-card text-foreground border font-medium\"\n\nexport function Pagination({\n  page,\n  pageCount,\n  onPageChange,\n  siblingCount = 1,\n  boundaryCount = 1,\n  label = \"Pagination\",\n  renderLink,\n  className,\n  ...rootProps\n}: PaginationProps) {\n  if (pageCount <= 1) return null\n\n  const pages = paginationRange({\n    page,\n    pageCount,\n    siblingCount,\n    boundaryCount,\n  })\n\n  function item(link: PaginationLink) {\n    if (renderLink) return renderLink(link)\n\n    const { page: target, children, className: itemClass, ...rest } = link\n\n    return (\n      <button\n        type=\"button\"\n        className={itemClass}\n        disabled={onPageChange === undefined}\n        onClick={() => onPageChange?.(target)}\n        {...rest}\n      >\n        {children}\n      </button>\n    )\n  }\n\n  return (\n    <nav\n      aria-label={label}\n      data-slot=\"pagination\"\n      className={cn(\"flex items-center gap-1\", className)}\n      {...rootProps}\n    >\n      {page > 1 &&\n        item({\n          page: page - 1,\n          \"aria-label\": \"Previous page\",\n          className: cn(ITEM, IDLE),\n          children: <ChevronLeft aria-hidden=\"true\" size={16} />,\n        })}\n\n      {pages.map((entry, index) =>\n        entry === GAP ? (\n          <span\n            key={`gap-${index}`}\n            aria-hidden=\"true\"\n            className=\"text-muted-foreground px-1 text-sm\"\n          >\n            …\n          </span>\n        ) : (\n          <React.Fragment key={entry}>\n            {item({\n              page: entry,\n              \"aria-label\": `Page ${entry}`,\n              ...(entry === page ? { \"aria-current\": \"page\" as const } : {}),\n              className: cn(ITEM, entry === page ? CURRENT : IDLE),\n              children: entry,\n            })}\n          </React.Fragment>\n        )\n      )}\n\n      {page < pageCount &&\n        item({\n          page: page + 1,\n          \"aria-label\": \"Next page\",\n          className: cn(ITEM, IDLE),\n          children: <ChevronRight aria-hidden=\"true\" size={16} />,\n        })}\n    </nav>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "categories": [
    "navigation",
    "list"
  ],
  "type": "registry:ui"
}