{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pagination",
  "type": "registry:ui",
  "title": "Pagination",
  "description": "Page links in a debossed well; the active page is an embossed key that springs between links.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://seamui.dev/r/utils.json",
    "https://seamui.dev/r/motion.json",
    "https://seamui.dev/r/haptics.json",
    "https://seamui.dev/r/button.json"
  ],
  "files": [
    {
      "path": "registry/seam/ui/pagination.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronLeft, ChevronRight, MoreHorizontal } from \"lucide-react\"\nimport { motion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { springs, useReducedMotion } from \"@/lib/motion\"\nimport { useHaptics } from \"@/lib/haptics\"\nimport { buttonVariants } from \"./button\"\n\n// Each Pagination instance gets a unique layoutId so multiple paginations on\n// one page don't share (and fight over) the sliding active key.\nconst PaginationLayoutContext = React.createContext<string>(\"seam-pagination\")\n\nfunction Pagination({ className, ...props }: React.ComponentProps<\"nav\">) {\n  const layoutId = React.useId()\n  return (\n    <PaginationLayoutContext.Provider value={layoutId}>\n      <nav\n        aria-label=\"pagination\"\n        data-slot=\"pagination\"\n        className={cn(\"mx-auto flex w-full justify-center\", className)}\n        {...props}\n      />\n    </PaginationLayoutContext.Provider>\n  )\n}\n\nfunction PaginationContent({\n  className,\n  ...props\n}: React.ComponentProps<\"ul\">) {\n  return (\n    // The debossed well the page keys sit in (the tabs-list shape) — the\n    // active page rises from it as an embossed key.\n    <ul\n      data-slot=\"pagination-content\"\n      className={cn(\n        \"bg-muted text-muted-foreground shadow-well inline-flex w-fit items-center gap-1 rounded-lg squircle p-1.5\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction PaginationItem({ className, ...props }: React.ComponentProps<\"li\">) {\n  return (\n    <li\n      data-slot=\"pagination-item\"\n      className={cn(\"flex\", className)}\n      {...props}\n    />\n  )\n}\n\ntype PaginationLinkProps = React.ComponentProps<\"a\"> & {\n  /** The current page — embossed key, `aria-current=\"page\"`. */\n  isActive?: boolean\n  /** Non-navigable state for prev/next at the range ends. */\n  disabled?: boolean\n  size?: \"default\" | \"icon\"\n}\n\n// A page key is a link, not a button — wrapping it in the Button component\n// would impose button semantics inside the pagination nav, so it wears\n// buttonVariants directly (§5A option 2) and reuses the tabs signature: a\n// transparent key whose embossed active state springs between links.\nfunction PaginationLink({\n  className,\n  isActive,\n  disabled,\n  size = \"icon\",\n  children,\n  onClick,\n  ...props\n}: PaginationLinkProps) {\n  const layoutId = React.useContext(PaginationLayoutContext)\n  const reduceMotion = useReducedMotion()\n  const { trigger } = useHaptics()\n\n  return (\n    // biome-ignore lint/a11y/noStaticElementInteractions: this renders an interactive link — biome just can't see the consumer's href through the spread.\n    <a\n      data-slot=\"pagination-link\"\n      data-active={isActive || undefined}\n      aria-current={isActive ? \"page\" : undefined}\n      aria-disabled={disabled || undefined}\n      tabIndex={disabled ? -1 : undefined}\n      className={cn(\n        buttonVariants({ variant: \"ghost\", size }),\n        \"relative hover:bg-transparent\",\n        isActive\n          ? \"text-foreground\"\n          : \"text-muted-foreground hover:text-foreground\",\n        disabled && \"pointer-events-none opacity-50\",\n        className\n      )}\n      // tactile feedback: committing a page change ticks (§3b); re-clicking\n      // the active page is a no-op.\n      // biome-ignore lint/a11y/useValidAnchor: the consumer supplies href via the spread; this handler only adds the haptic tick alongside real navigation.\n      onClick={(e) => {\n        if (!isActive && !disabled) trigger(\"tick\")\n        onClick?.(e)\n      }}\n      {...props}\n    >\n      {isActive &&\n        (reduceMotion ? (\n          <span className=\"bg-secondary shadow-resting absolute inset-0 z-0 rounded-md squircle\" />\n        ) : (\n          // seam motion: the embossed key springs to the active page.\n          <motion.span\n            layoutId={layoutId}\n            transition={springs.snappy}\n            className=\"bg-secondary shadow-resting absolute inset-0 z-0 rounded-md squircle\"\n          />\n        ))}\n      <span className=\"relative z-10 inline-flex items-center gap-1\">\n        {children}\n      </span>\n    </a>\n  )\n}\n\nfunction PaginationPrevious({\n  className,\n  ...props\n}: Omit<PaginationLinkProps, \"size\" | \"isActive\">) {\n  return (\n    <PaginationLink\n      data-slot=\"pagination-previous\"\n      aria-label=\"Go to previous page\"\n      size=\"default\"\n      className={cn(\"pl-3.5\", className)}\n      {...props}\n    >\n      <ChevronLeft />\n      <span className=\"hidden sm:block\">Previous</span>\n    </PaginationLink>\n  )\n}\n\nfunction PaginationNext({\n  className,\n  ...props\n}: Omit<PaginationLinkProps, \"size\" | \"isActive\">) {\n  return (\n    <PaginationLink\n      data-slot=\"pagination-next\"\n      aria-label=\"Go to next page\"\n      size=\"default\"\n      className={cn(\"pr-3.5\", className)}\n      {...props}\n    >\n      <span className=\"hidden sm:block\">Next</span>\n      <ChevronRight />\n    </PaginationLink>\n  )\n}\n\nfunction PaginationEllipsis({\n  className,\n  ...props\n}: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      data-slot=\"pagination-ellipsis\"\n      aria-hidden\n      className={cn(\"flex size-10 items-center justify-center\", className)}\n      {...props}\n    >\n      <MoreHorizontal className=\"size-4\" />\n      <span className=\"sr-only\">More pages</span>\n    </span>\n  )\n}\n\nexport {\n  Pagination,\n  PaginationContent,\n  PaginationItem,\n  PaginationLink,\n  PaginationPrevious,\n  PaginationNext,\n  PaginationEllipsis,\n}\n",
      "type": "registry:ui",
      "target": "components/ui/pagination.tsx"
    }
  ]
}