{
  "name": "morphing-cursor",
  "files": [
    {
      "path": "ui/morphing-cursor.tsx",
      "content": "\"use client\";\n\nimport type React from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface MagneticTextProps {\n  text: string;\n  hoverText?: string;\n  className?: string;\n}\n\nexport function MagneticText({\n  text = \"CREATIVE\",\n  hoverText = \"EXPLORE\",\n  className,\n}: MagneticTextProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const circleRef = useRef<HTMLDivElement>(null);\n  const innerTextRef = useRef<HTMLDivElement>(null);\n  const [isHovered, setIsHovered] = useState(false);\n  const [containerSize, setContainerSize] = useState({ width: 0, height: 0 });\n\n  const mousePos = useRef({ x: 0, y: 0 });\n  const currentPos = useRef({ x: 0, y: 0 });\n  const animationFrameRef = useRef<number | undefined>(undefined);\n\n  useEffect(() => {\n    const updateSize = () => {\n      if (containerRef.current) {\n        setContainerSize({\n          width: containerRef.current.offsetWidth,\n          height: containerRef.current.offsetHeight,\n        });\n      }\n    };\n    updateSize();\n    window.addEventListener(\"resize\", updateSize);\n    return () => window.removeEventListener(\"resize\", updateSize);\n  }, []);\n\n  useEffect(() => {\n    const lerp = (start: number, end: number, factor: number) =>\n      start + (end - start) * factor;\n\n    const animate = () => {\n      currentPos.current.x = lerp(\n        currentPos.current.x,\n        mousePos.current.x,\n        0.15,\n      );\n      currentPos.current.y = lerp(\n        currentPos.current.y,\n        mousePos.current.y,\n        0.15,\n      );\n\n      if (circleRef.current) {\n        circleRef.current.style.transform = `translate(${currentPos.current.x}px, ${currentPos.current.y}px) translate(-50%, -50%)`;\n      }\n\n      if (innerTextRef.current) {\n        innerTextRef.current.style.transform = `translate(${-currentPos.current.x}px, ${-currentPos.current.y}px)`;\n      }\n\n      animationFrameRef.current = requestAnimationFrame(animate);\n    };\n\n    animationFrameRef.current = requestAnimationFrame(animate);\n    return () => {\n      if (animationFrameRef.current)\n        cancelAnimationFrame(animationFrameRef.current);\n    };\n  }, []);\n\n  const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {\n    if (!containerRef.current) return;\n    const rect = containerRef.current.getBoundingClientRect();\n    mousePos.current = {\n      x: e.clientX - rect.left,\n      y: e.clientY - rect.top,\n    };\n  }, []);\n\n  const handleMouseEnter = useCallback(\n    (e: React.MouseEvent<HTMLDivElement>) => {\n      if (!containerRef.current) return;\n      const rect = containerRef.current.getBoundingClientRect();\n      const x = e.clientX - rect.left;\n      const y = e.clientY - rect.top;\n      mousePos.current = { x, y };\n      currentPos.current = { x, y };\n      setIsHovered(true);\n    },\n    [],\n  );\n\n  const handleMouseLeave = useCallback(() => {\n    setIsHovered(false);\n  }, []);\n\n  return (\n    // biome-ignore lint/a11y/noStaticElementInteractions: This is a decorative visual effect that tracks mouse position for aesthetic purposes only\n    <div\n      ref={containerRef}\n      onMouseMove={handleMouseMove}\n      onMouseEnter={handleMouseEnter}\n      onMouseLeave={handleMouseLeave}\n      className={cn(\n        \"relative inline-flex cursor-none select-none items-center justify-center\",\n        className,\n      )}\n    >\n      {/* Base text layer - original text */}\n      <span className=\"font-bold text-5xl text-foreground tracking-tighter tracking-wide\">\n        {text}\n      </span>\n\n      <div\n        ref={circleRef}\n        className=\"pointer-events-none absolute top-0 left-0 overflow-hidden rounded-full bg-foreground\"\n        style={{\n          width: isHovered ? 150 : 0,\n          height: isHovered ? 150 : 0,\n          transition:\n            \"width 0.5s cubic-bezier(0.33, 1, 0.68, 1), height 0.5s cubic-bezier(0.33, 1, 0.68, 1)\",\n          willChange: \"transform, width, height\",\n        }}\n      >\n        <div\n          ref={innerTextRef}\n          className=\"absolute flex items-center justify-center\"\n          style={{\n            width: containerSize.width,\n            height: containerSize.height,\n            top: \"50%\",\n            left: \"50%\",\n            willChange: \"transform\",\n          }}\n        >\n          <span className=\"whitespace-nowrap font-bold text-5xl text-background tracking-tighter tracking-wide\">\n            {hoverText}\n          </span>\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": ""
    }
  ],
  "type": "registry:ui"
}