{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "move-to-top-button",
  "title": "Move To Top",
  "author": "mrap10",
  "description": "Direction aware scroll progress button that helps to jump top or bottom on click.",
  "dependencies": ["motion"],
  "files": [
    {
      "path": "registry/default/button/move-to-top.tsx",
      "content": "\"use client\";\n\nimport {\n  motion,\n  AnimatePresence,\n  useScroll,\n  useMotionValueEvent,\n  useTransform,\n} from \"motion/react\";\nimport { useRef, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\n\ntype Mode = \"down\" | \"up\";\n\ninterface MoveToTopProps {\n  className?: string;\n  size?: number;\n}\n\nexport default function MoveToTop({ className, size = 44 }: MoveToTopProps) {\n  const [iconMode, setIconMode] = useState<Mode>(\"down\");\n\n  const { scrollY, scrollYProgress } = useScroll();\n\n  const lastY = useRef(0);\n  const directionRef = useRef<Mode>(\"down\");\n\n  useMotionValueEvent(scrollY, \"change\", (y) => {\n    if (y > lastY.current + 4) {\n      directionRef.current = \"down\";\n    } else if (y < lastY.current - 4) {\n      directionRef.current = \"up\";\n    }\n\n    lastY.current = y;\n  });\n\n  useMotionValueEvent(scrollYProgress, \"change\", (p) => {\n    const next: Mode =\n      p <= 0.01 ? \"down\" : p >= 0.99 ? \"up\" : directionRef.current;\n\n    setIconMode((prev) => (prev === next ? prev : next));\n  });\n\n  const r = (size - 4) / 2;\n  const cx = size / 2;\n  const cy = size / 2;\n  const circumference = 2 * Math.PI * r;\n  const dashoffset = useTransform(\n    scrollYProgress,\n    (p) => circumference * (1 - p)\n  );\n\n  const handleClick = () => {\n    if (iconMode === \"down\") {\n      window.scrollTo({\n        top: document.documentElement.scrollHeight,\n        behavior: \"smooth\",\n      });\n      return;\n    }\n    window.scrollTo({ top: 0, behavior: \"smooth\" });\n  };\n\n  return (\n    <button\n      aria-label={iconMode === \"down\" ? \"Scroll to bottom\" : \"Scroll to top\"}\n      onClick={handleClick}\n      className={cn(\"fixed right-6 bottom-6 z-50 rounded-full\", className)}\n    >\n      <div\n        style={{ width: size, height: size }}\n        className=\"relative rounded-full bg-neutral-900 text-white shadow-lg shadow-black/30\"\n      >\n        <svg\n          width={size}\n          height={size}\n          viewBox={`0 0 ${size} ${size}`}\n          className=\"absolute inset-0\"\n        >\n          <circle\n            cx={cx}\n            cy={cy}\n            r={r}\n            fill=\"transparent\"\n            strokeWidth={4}\n            className=\"stroke-white/20\"\n          />\n\n          <motion.circle\n            cx={cx}\n            cy={cy}\n            r={r}\n            fill=\"transparent\"\n            strokeWidth={4}\n            stroke=\"currentColor\"\n            strokeLinecap=\"round\"\n            strokeDasharray={circumference}\n            strokeDashoffset={dashoffset}\n            transform={`rotate(-90 ${cx} ${cy})`}\n            className=\"text-neutral-400\"\n          />\n        </svg>\n\n        <div className=\"absolute inset-0 flex items-center justify-center\">\n          <AnimatePresence initial={false} mode=\"wait\">\n            {iconMode === \"down\" ? (\n              <motion.span\n                key=\"down\"\n                initial={{ opacity: 0, rotate: -90, scale: 0.85 }}\n                animate={{ opacity: 1, rotate: 0, scale: 1 }}\n                exit={{ opacity: 0, rotate: 90, scale: 0.85 }}\n                transition={{ duration: 0.4, ease: \"easeInOut\" }}\n                className=\"text-neutral-400 hover:text-neutral-100\"\n              >\n                <ArrowDownIcon className=\"h-5 w-5\" />\n              </motion.span>\n            ) : (\n              <motion.span\n                key=\"up\"\n                initial={{ opacity: 0, rotate: 90, scale: 0.85 }}\n                animate={{ opacity: 1, rotate: 0, scale: 1 }}\n                exit={{ opacity: 0, rotate: -90, scale: 0.85 }}\n                transition={{ duration: 0.4, ease: \"easeInOut\" }}\n                className=\"text-neutral-400 hover:text-neutral-100\"\n              >\n                <ChevronsUp className=\"h-5 w-5\" />\n              </motion.span>\n            )}\n          </AnimatePresence>\n        </div>\n      </div>\n    </button>\n  );\n}\n\nfunction ArrowDownIcon({ className }: { className?: string }) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"1.5\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      className={className}\n    >\n      <path d=\"M12 5v14\" />\n      <path d=\"M18 13l-6 6\" />\n      <path d=\"M6 13l6 6\" />\n    </svg>\n  );\n}\n\nfunction ChevronsUp({ className }: { className?: string }) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"1.5\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      className={className}\n    >\n      <path d=\"M7 11l5-5 5 5\" />\n      <path d=\"M7 17l5-5 5 5\" />\n    </svg>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": ["buttons"],
  "type": "registry:component"
}
