{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pagination-base",
  "type": "registry:component",
  "title": "Pagination (base)",
  "description": "Theme-ready base variant of An animated pagination control with previous and next arrows, where the page number rolls digit by digit as you move between pages..",
  "dependencies": [
    "motion",
    "react-icons"
  ],
  "files": [
    {
      "path": "components/watermelon/pagination.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { motion, AnimatePresence } from 'motion/react';\nimport { HiOutlineArrowLeft, HiOutlineArrowRight } from 'react-icons/hi2';\n\nexport interface PaginationProps {\n  totalPages?: number;\n  value?: number;\n  defaultValue?: number;\n  onChange?: (page: number) => void;\n}\n\nconst digitVariants = {\n  initial: (dir: number) => ({\n    y: dir > 0 ? 20 : -20,\n    opacity: 0,\n    scale: 0.5,\n    filter: 'blur(2px)',\n  }),\n  animate: {\n    y: 0,\n    opacity: 1,\n    scale: 1,\n    filter: 'blur(0px)',\n  },\n  exit: (dir: number) => ({\n    y: dir > 0 ? -20 : 20,\n    opacity: 0,\n    scale: 0.5,\n    filter: 'blur(2px)',\n  }),\n};\n\nexport function Pagination({\n  totalPages = 15,\n  value,\n  defaultValue = 1,\n  onChange,\n}: PaginationProps) {\n  const isControlled = value !== undefined;\n\n  const [internalPage, setInternalPage] = React.useState(defaultValue);\n  const [direction, setDirection] = React.useState(0);\n\n  const currentPage = isControlled ? value! : internalPage;\n\n  const digits = currentPage.toString().split('');\n\n  const [prevDigits, setPrevDigits] = React.useState<string[]>([]);\n  const [prevTicks, setPrevTicks] = React.useState<number[]>([]);\n\n  const len = digits.length;\n  const lenDiff = len - prevDigits.length;\n\n  const nextTicks = digits.map((digit, i) => {\n    const prevI = i - lenDiff;\n    const prevDigit = prevI >= 0 ? prevDigits[prevI] : undefined;\n    const prevTick = prevI >= 0 ? prevTicks[prevI] : 0;\n\n    return digit !== prevDigit ? (prevTick ?? 0) + 1 : (prevTick ?? 0);\n  });\n\n  if (prevDigits.join(\"\") !== digits.join(\"\")) {\n    setPrevTicks(nextTicks);\n    setPrevDigits(digits);\n  }\n\n  const paginate = (dir: number) => {\n    const next = Math.min(totalPages, Math.max(1, currentPage + dir));\n\n    if (next === currentPage) return;\n\n    setDirection(dir);\n\n    if (!isControlled) {\n      setInternalPage(next);\n    }\n\n    onChange?.(next);\n  };\n\n  return (\n    <div className=\"theme-injected flex w-full justify-center\">\n      <div className=\"border-border bg-muted flex items-center gap-2 rounded-lg border px-1 py-1 sm:gap-3\">\n        <motion.button\n          whileTap={{ scale: 0.9 }}\n          transition={{ type: 'spring', stiffness: 400, damping: 20 }}\n          onClick={() => paginate(-1)}\n          disabled={currentPage === 1}\n          className={`bg-background dark:bg-foreground dark:text-background dark:hover:bg-foreground/80 text-foregroundhover:text-foreground/80 hover:text-accent-foreground flex h-11 w-11 items-center justify-center rounded-lg shadow transition-colors duration-200 sm:h-14 sm:w-14 ${\n            currentPage === 1\n              ? 'cursor-not-allowed opacity-50'\n              : 'cursor-pointer'\n          }`}\n        >\n          <HiOutlineArrowLeft className=\"h-5 w-5 sm:h-7 sm:w-7\" />\n        </motion.button>\n\n        <div className=\"text-muted-foreground mr-1 flex items-center pr-1 text-base font-bold select-none sm:text-xl\">\n          <div className=\"flex h-7 items-center justify-center sm:h-8\">\n            {digits.map((digit, index) => (\n              <div\n                key={`${index}-${len}`}\n                className=\"relative h-7 w-[1ch] overflow-hidden\"\n              >\n                <AnimatePresence\n                  mode=\"popLayout\"\n                  initial={false}\n                  custom={direction}\n                >\n                  <motion.span\n                    key={nextTicks[index]}\n                    custom={direction}\n                    variants={digitVariants}\n                    initial=\"initial\"\n                    animate=\"animate\"\n                    exit=\"exit\"\n                    transition={{\n                      type: 'spring',\n                      stiffness: 200,\n                      damping: 16,\n                      mass: 1.2,\n                    }}\n                    className=\"text-muted-foreground absolute inset-0 flex items-center justify-center tabular-nums\"\n                  >\n                    {digit}\n                  </motion.span>\n                </AnimatePresence>\n              </div>\n            ))}\n          </div>\n\n          <span className=\"text-muted-foreground ml-1 flex h-7 items-center sm:h-8\">\n            of {totalPages}\n          </span>\n        </div>\n\n        <motion.button\n          whileTap={{ scale: 0.9 }}\n          transition={{ type: 'spring', stiffness: 400, damping: 20 }}\n          onClick={() => paginate(1)}\n          disabled={currentPage === totalPages}\n          className={`bg-background dark:bg-foreground dark:text-background dark:hover:bg-foreground/80 text-foreground hover:bg-background/80 hover:text-foreground/80 flex h-11 w-11 items-center justify-center rounded-lg shadow transition-colors duration-200 sm:h-14 sm:w-14 ${\n            currentPage === totalPages\n              ? 'cursor-not-allowed opacity-50'\n              : 'cursor-pointer'\n          }`}\n        >\n          <HiOutlineArrowRight className=\"h-5 w-5 sm:h-7 sm:w-7\" />\n        </motion.button>\n      </div>\n    </div>\n  );\n}\n"
    }
  ]
}
