{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pagination",
  "type": "registry:ui",
  "title": "Pagination",
  "description": "Link pagination and controlled previous/next controls with rows per page.",
  "dependencies": [
    "radix-ui",
    "lucide-react"
  ],
  "registryDependencies": [
    "@wibo/utils",
    "@wibo/button",
    "@wibo/select"
  ],
  "files": [
    {
      "path": "src/components/pagination.tsx",
      "type": "registry:ui",
      "content": "import type { ComponentProps } from \"react\";\nimport { Slot } from \"radix-ui\";\nimport { ChevronLeft, ChevronRight, Ellipsis } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { Button, buttonVariants } from \"@/components/ui/button\";\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@/components/ui/select\";\n\n/* ------------------------------------------------------------------------ */\n/* Link-based pagination (page URLs).                                        */\n/* ------------------------------------------------------------------------ */\n\n/** Page navigation with links. For in-memory tables use `PaginationControls`. */\nfunction Pagination({ className, \"aria-label\": ariaLabel = \"Pagination\", ...props }: ComponentProps<\"nav\">) {\n  return (\n    <nav\n      aria-label={ariaLabel}\n      data-slot=\"pagination\"\n      className={cn(\"mx-auto flex w-full justify-center\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction PaginationContent({ className, ...props }: ComponentProps<\"ul\">) {\n  return (\n    <ul\n      data-slot=\"pagination-content\"\n      className={cn(\"flex flex-row items-center gap-1\", className)}\n      {...props}\n    />\n  );\n}\n\nfunction PaginationItem(props: ComponentProps<\"li\">) {\n  return <li data-slot=\"pagination-item\" {...props} />;\n}\n\ntype PaginationLinkProps = ComponentProps<\"a\"> & {\n  isActive?: boolean;\n  size?: \"icon\" | \"md\";\n  /** Render the child (for example a router link) instead of an anchor. */\n  asChild?: boolean;\n};\n\nfunction PaginationLink({ className, isActive, size = \"icon\", asChild, ...props }: PaginationLinkProps) {\n  const Comp = asChild ? Slot.Root : \"a\";\n  return (\n    <Comp\n      aria-current={isActive ? \"page\" : undefined}\n      data-slot=\"pagination-link\"\n      data-active={isActive}\n      className={cn(\n        buttonVariants({ variant: isActive ? \"outline\" : \"ghost\", size }),\n        \"font-mono tabular-nums\",\n        className,\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction PaginationPrevious({\n  className,\n  label = \"Previous\",\n  ...props\n}: PaginationLinkProps & { label?: string }) {\n  return (\n    <PaginationLink aria-label={label} size=\"md\" className={cn(\"gap-1 px-2.5 font-sans\", className)} {...props}>\n      <ChevronLeft aria-hidden=\"true\" />\n      <span className=\"hidden sm:block\">{label}</span>\n    </PaginationLink>\n  );\n}\n\nfunction PaginationNext({ className, label = \"Next\", ...props }: PaginationLinkProps & { label?: string }) {\n  return (\n    <PaginationLink aria-label={label} size=\"md\" className={cn(\"gap-1 px-2.5 font-sans\", className)} {...props}>\n      <span className=\"hidden sm:block\">{label}</span>\n      <ChevronRight aria-hidden=\"true\" />\n    </PaginationLink>\n  );\n}\n\nfunction PaginationEllipsis({\n  className,\n  label = \"More pages\",\n  ...props\n}: ComponentProps<\"span\"> & { label?: string }) {\n  return (\n    <span\n      aria-hidden=\"true\"\n      data-slot=\"pagination-ellipsis\"\n      className={cn(\"flex size-8 items-center justify-center text-muted-foreground\", className)}\n      {...props}\n    >\n      <Ellipsis className=\"size-4\" />\n      <span className=\"sr-only\">{label}</span>\n    </span>\n  );\n}\n\n/* ------------------------------------------------------------------------ */\n/* Controlled pagination (tables, lists).                                    */\n/* ------------------------------------------------------------------------ */\n\ninterface PaginationControlsLabels {\n  previous: string;\n  next: string;\n  rowsPerPage: string;\n  /** Receives the 1-based page and the page count. */\n  page: (page: number, pageCount: number) => string;\n  /** Receives the first and last row on the page and the total. */\n  range: (from: number, to: number, total: number) => string;\n}\n\nconst defaultControlsLabels: PaginationControlsLabels = {\n  previous: \"Previous page\",\n  next: \"Next page\",\n  rowsPerPage: \"Rows per page\",\n  page: (page, pageCount) => `Page ${page} of ${pageCount}`,\n  range: (from, to, total) => `${from}-${to} of ${total}`,\n};\n\ninterface PaginationControlsProps extends Omit<ComponentProps<\"div\">, \"children\"> {\n  /** Zero-based current page. */\n  pageIndex: number;\n  pageCount: number;\n  onPageChange: (pageIndex: number) => void;\n  pageSize?: number;\n  /** Total number of rows; enables the \"1-10 of 50\" range label. */\n  totalCount?: number;\n  /** Enables the rows-per-page select. */\n  onPageSizeChange?: (pageSize: number) => void;\n  pageSizeOptions?: number[];\n  labels?: Partial<PaginationControlsLabels>;\n}\n\n/** Previous and next buttons with page position and an optional rows-per-page select. */\nfunction PaginationControls({\n  pageIndex,\n  pageCount,\n  onPageChange,\n  pageSize,\n  totalCount,\n  onPageSizeChange,\n  pageSizeOptions = [10, 25, 50, 100],\n  labels: labelOverrides,\n  className,\n  ...props\n}: PaginationControlsProps) {\n  const labels = { ...defaultControlsLabels, ...labelOverrides };\n  const safeCount = Math.max(pageCount, 1);\n  const canPrevious = pageIndex > 0;\n  const canNext = pageIndex < safeCount - 1;\n  const showRange = pageSize !== undefined && totalCount !== undefined;\n  const from = showRange ? Math.min(pageIndex * pageSize + 1, totalCount) : 0;\n  const to = showRange ? Math.min((pageIndex + 1) * pageSize, totalCount) : 0;\n\n  return (\n    <div\n      data-slot=\"pagination-controls\"\n      className={cn(\"flex flex-wrap items-center justify-between gap-3 text-sm\", className)}\n      {...props}\n    >\n      <div className=\"font-mono text-xs text-muted-foreground tabular-nums\" aria-live=\"polite\">\n        {showRange ? labels.range(from, to, totalCount) : null}\n      </div>\n      <div className=\"flex items-center gap-3\">\n        {onPageSizeChange && pageSize !== undefined ? (\n          <div className=\"flex items-center gap-2\">\n            <span className=\"text-xs text-muted-foreground\" aria-hidden=\"true\">\n              {labels.rowsPerPage}\n            </span>\n            <Select value={String(pageSize)} onValueChange={(value) => onPageSizeChange(Number(value))}>\n              <SelectTrigger size=\"sm\" aria-label={labels.rowsPerPage} className=\"w-[4.5rem]\">\n                <SelectValue />\n              </SelectTrigger>\n              <SelectContent>\n                {pageSizeOptions.map((option) => (\n                  <SelectItem key={option} value={String(option)}>\n                    {option}\n                  </SelectItem>\n                ))}\n              </SelectContent>\n            </Select>\n          </div>\n        ) : null}\n        <span className=\"text-xs text-muted-foreground tabular-nums\">\n          {labels.page(Math.min(pageIndex + 1, safeCount), safeCount)}\n        </span>\n        <div className=\"flex items-center gap-1\">\n          <Button\n            variant=\"outline\"\n            size=\"icon-sm\"\n            aria-label={labels.previous}\n            disabled={!canPrevious}\n            onClick={() => onPageChange(pageIndex - 1)}\n          >\n            <ChevronLeft aria-hidden=\"true\" />\n          </Button>\n          <Button\n            variant=\"outline\"\n            size=\"icon-sm\"\n            aria-label={labels.next}\n            disabled={!canNext}\n            onClick={() => onPageChange(pageIndex + 1)}\n          >\n            <ChevronRight aria-hidden=\"true\" />\n          </Button>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport {\n  Pagination,\n  PaginationContent,\n  PaginationControls,\n  PaginationEllipsis,\n  PaginationItem,\n  PaginationLink,\n  PaginationNext,\n  PaginationPrevious,\n};\nexport type { PaginationControlsLabels, PaginationControlsProps };\n"
    }
  ]
}
