{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "magnetize-button",
  "title": "Magnetize Button",
  "description": "A magnetic particle-attraction button built with Framer Motion.",
  "dependencies": [
    "react",
    "motion",
    "@tabler/icons-react"
  ],
  "files": [
    {
      "path": "registry/gammaui/magnetize-button.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { useCallback, useEffect, useState } from \"react\"\nimport { Magnet } from \"lucide-react\"\nimport { motion, useAnimation } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\n\ninterface MagnetizeButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  particleCount?: number\n  attractRadius?: number\n}\n\ninterface Particle {\n  id: number\n  x: number\n  y: number\n}\n\nexport default function MagnetizeButton({\n  className,\n  particleCount = 12,\n  attractRadius = 50,\n  ...props\n}: MagnetizeButtonProps) {\n  const [isAttracting, setIsAttracting] = useState(false)\n  const [particles, setParticles] = useState<Particle[]>([])\n  const particlesControl = useAnimation()\n\n  useEffect(() => {\n    const newParticles = Array.from({ length: particleCount }, (_, i) => ({\n      id: i,\n      x: Math.random() * 360 - 180,\n      y: Math.random() * 360 - 180,\n    }))\n    setParticles(newParticles)\n  }, [particleCount])\n\n  const handleInteractionStart = useCallback(async () => {\n    setIsAttracting(true)\n    await particlesControl.start({\n      x: 0,\n      y: 0,\n      transition: {\n        type: \"spring\",\n        stiffness: 50,\n        damping: 10,\n      },\n    })\n  }, [particlesControl])\n\n  const handleInteractionEnd = useCallback(async () => {\n    setIsAttracting(false)\n    await particlesControl.start((i) => ({\n      x: particles[i].x,\n      y: particles[i].y,\n      transition: {\n        type: \"spring\",\n        stiffness: 100,\n        damping: 15,\n      },\n    }))\n  }, [particlesControl, particles])\n\n  return (\n    <Button\n      className={cn(\n        \"relative min-w-40 touch-none\",\n        \"bg-violet-100 dark:bg-violet-900\",\n        \"hover:bg-violet-200 dark:hover:bg-violet-800\",\n        \"text-violet-600 dark:text-violet-300\",\n        \"border border-violet-300 dark:border-violet-700\",\n        \"cursor-pointer transition-all duration-300\",\n        className\n      )}\n      onMouseEnter={handleInteractionStart}\n      onMouseLeave={handleInteractionEnd}\n      onTouchStart={handleInteractionStart}\n      onTouchEnd={handleInteractionEnd}\n      {...props}\n    >\n      {particles.map((_, index) => (\n        <motion.div\n          key={index}\n          custom={index}\n          initial={{ x: particles[index].x, y: particles[index].y }}\n          animate={particlesControl}\n          className={cn(\n            \"absolute h-1.5 w-1.5 rounded-full\",\n            \"bg-violet-400 dark:bg-violet-300\",\n            \"transition-opacity duration-300\",\n            isAttracting ? \"opacity-100\" : \"opacity-40\"\n          )}\n        />\n      ))}\n      <span className=\"relative flex w-full items-center justify-center gap-2\">\n        <Magnet\n          className={cn(\n            \"h-4 w-4 transition-transform duration-300\",\n            isAttracting && \"scale-110\"\n          )}\n        />\n        {isAttracting ? \"Attracting\" : \"Hover me\"}\n      </span>\n    </Button>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}