{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "magnetic-button",
  "title": "Magnetic Button",
  "description": "A button that magnetically follows cursor proximity with spring physics. Smoothly snaps back when the cursor leaves.",
  "dependencies": [
    "motion",
    "class-variance-authority"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/components/unlumen/magnetic-button/index.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  type SpringOptions,\n  type HTMLMotionProps,\n} from \"motion/react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst magneticButtonVariants = cva(\n  \"relative inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 select-none\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"bg-primary text-primary-foreground shadow hover:bg-primary/90\",\n        destructive:\n          \"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90\",\n        outline:\n          \"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground\",\n        secondary:\n          \"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80\",\n        ghost: \"hover:bg-accent hover:text-accent-foreground\",\n        link: \"text-primary underline-offset-4 hover:underline\",\n      },\n      size: {\n        default: \"h-9 px-4 py-2\",\n        sm: \"h-8 rounded-md px-3 text-xs\",\n        lg: \"h-10 rounded-md px-8\",\n        icon: \"h-9 w-9\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"default\",\n    },\n  },\n);\n\nexport interface MagneticButtonProps\n  extends Omit<HTMLMotionProps<\"button\">, \"style\">,\n    VariantProps<typeof magneticButtonVariants> {\n  /** activation radius in px — @default 100 */\n  radius?: number;\n  springOptions?: SpringOptions;\n  /** pull strength multiplier 0–1 — @default 0.5 */\n  strength?: number;\n  asChild?: boolean;\n}\n\nexport function MagneticButton({\n  children,\n  radius = 100,\n  springOptions = { stiffness: 150, damping: 15, mass: 0.1 },\n  strength = 0.5,\n  variant,\n  size,\n  className,\n  ...props\n}: MagneticButtonProps) {\n  const ref = React.useRef<HTMLButtonElement>(null);\n\n  const rawX = useMotionValue(0);\n  const rawY = useMotionValue(0);\n\n  const x = useSpring(rawX, springOptions);\n  const y = useSpring(rawY, springOptions);\n\n  const handleMouseMove = React.useCallback(\n    (e: React.MouseEvent<HTMLButtonElement>) => {\n      const el = ref.current;\n      if (!el) return;\n      const rect = el.getBoundingClientRect();\n      const cx = rect.left + rect.width / 2;\n      const cy = rect.top + rect.height / 2;\n      const dx = e.clientX - cx;\n      const dy = e.clientY - cy;\n      const dist = Math.sqrt(dx * dx + dy * dy);\n\n      if (dist < radius) {\n        const pull = (1 - dist / radius) * strength;\n        rawX.set(dx * pull);\n        rawY.set(dy * pull);\n      }\n    },\n    [radius, strength, rawX, rawY],\n  );\n\n  const handleMouseLeave = React.useCallback(() => {\n    rawX.set(0);\n    rawY.set(0);\n  }, [rawX, rawY]);\n\n  return (\n    <motion.button\n      ref={ref}\n      style={{ x, y }}\n      className={cn(magneticButtonVariants({ variant, size }), className)}\n      onMouseMove={handleMouseMove}\n      onMouseLeave={handleMouseLeave}\n      {...props}\n    >\n      {children}\n    </motion.button>\n  );\n}\n\nexport { magneticButtonVariants };\n",
      "type": "registry:ui",
      "target": "components/unlumen-ui/magnetic-button.tsx"
    }
  ],
  "type": "registry:ui"
}