{
  "name": "glowing-effect",
  "type": "registry:ui",
  "dependencies": [
    "lucide-react"
  ],
  "files": [
    {
      "path": "components/ui/glowing-effect.tsx",
      "content": "\"use client\";\n\nimport { memo, useCallback, useEffect, useRef } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { animate } from \"motion/react\";\n\ninterface GlowingEffectProps {\n  blur?: number;\n  inactiveZone?: number;\n  proximity?: number;\n  spread?: number;\n  variant?: \"default\" | \"white\";\n  glow?: boolean;\n  className?: string;\n  disabled?: boolean;\n  movementDuration?: number;\n  borderWidth?: number;\n}\nconst GlowingEffect = memo(\n  ({\n    blur = 0,\n    inactiveZone = 0.7,\n    proximity = 0,\n    spread = 20,\n    variant = \"default\",\n    glow = false,\n    className,\n    movementDuration = 2,\n    borderWidth = 1,\n    disabled = true,\n  }: GlowingEffectProps) => {\n    const containerRef = useRef<HTMLDivElement>(null);\n    const lastPosition = useRef({ x: 0, y: 0 });\n    const animationFrameRef = useRef<number>(0);\n\n    const handleMove = useCallback(\n      (e?: MouseEvent | { x: number; y: number }) => {\n        if (!containerRef.current) return;\n\n        if (animationFrameRef.current) {\n          cancelAnimationFrame(animationFrameRef.current);\n        }\n\n        animationFrameRef.current = requestAnimationFrame(() => {\n          const element = containerRef.current;\n          if (!element) return;\n\n          const { left, top, width, height } = element.getBoundingClientRect();\n          const mouseX = e?.x ?? lastPosition.current.x;\n          const mouseY = e?.y ?? lastPosition.current.y;\n\n          if (e) {\n            lastPosition.current = { x: mouseX, y: mouseY };\n          }\n\n          const center = [left + width * 0.5, top + height * 0.5];\n          const distanceFromCenter = Math.hypot(\n            mouseX - center[0],\n            mouseY - center[1]\n          );\n          const inactiveRadius = 0.5 * Math.min(width, height) * inactiveZone;\n\n          if (distanceFromCenter < inactiveRadius) {\n            element.style.setProperty(\"--active\", \"0\");\n            return;\n          }\n\n          const isActive =\n            mouseX > left - proximity &&\n            mouseX < left + width + proximity &&\n            mouseY > top - proximity &&\n            mouseY < top + height + proximity;\n\n          element.style.setProperty(\"--active\", isActive ? \"1\" : \"0\");\n\n          if (!isActive) return;\n\n          const currentAngle =\n            parseFloat(element.style.getPropertyValue(\"--start\")) || 0;\n          let targetAngle =\n            (180 * Math.atan2(mouseY - center[1], mouseX - center[0])) /\n              Math.PI +\n            90;\n\n          const angleDiff = ((targetAngle - currentAngle + 180) % 360) - 180;\n          const newAngle = currentAngle + angleDiff;\n\n          animate(currentAngle, newAngle, {\n            duration: movementDuration,\n            ease: [0.16, 1, 0.3, 1],\n            onUpdate: (value) => {\n              element.style.setProperty(\"--start\", String(value));\n            },\n          });\n        });\n      },\n      [inactiveZone, proximity, movementDuration]\n    );\n\n    useEffect(() => {\n      if (disabled) return;\n\n      const handleScroll = () => handleMove();\n      const handlePointerMove = (e: PointerEvent) => handleMove(e);\n\n      window.addEventListener(\"scroll\", handleScroll, { passive: true });\n      document.body.addEventListener(\"pointermove\", handlePointerMove, {\n        passive: true,\n      });\n\n      return () => {\n        if (animationFrameRef.current) {\n          cancelAnimationFrame(animationFrameRef.current);\n        }\n        window.removeEventListener(\"scroll\", handleScroll);\n        document.body.removeEventListener(\"pointermove\", handlePointerMove);\n      };\n    }, [handleMove, disabled]);\n\n    return (\n      <>\n        <div\n          className={cn(\n            \"pointer-events-none absolute -inset-px hidden rounded-[inherit] border opacity-0 transition-opacity\",\n            glow && \"opacity-100\",\n            variant === \"white\" && \"border-white\",\n            disabled && \"!block\"\n          )}\n        />\n        <div\n          ref={containerRef}\n          style={\n            {\n              \"--blur\": `${blur}px`,\n              \"--spread\": spread,\n              \"--start\": \"0\",\n              \"--active\": \"0\",\n              \"--glowingeffect-border-width\": `${borderWidth}px`,\n              \"--repeating-conic-gradient-times\": \"5\",\n              \"--gradient\":\n                variant === \"white\"\n                  ? `repeating-conic-gradient(\n                  from 236.84deg at 50% 50%,\n                  var(--black),\n                  var(--black) calc(25% / var(--repeating-conic-gradient-times))\n                )`\n                  : `radial-gradient(circle, #dd7bbb 10%, #dd7bbb00 20%),\n                radial-gradient(circle at 40% 40%, #d79f1e 5%, #d79f1e00 15%),\n                radial-gradient(circle at 60% 60%, #5a922c 10%, #5a922c00 20%), \n                radial-gradient(circle at 40% 60%, #4c7894 10%, #4c789400 20%),\n                repeating-conic-gradient(\n                  from 236.84deg at 50% 50%,\n                  #dd7bbb 0%,\n                  #d79f1e calc(25% / var(--repeating-conic-gradient-times)),\n                  #5a922c calc(50% / var(--repeating-conic-gradient-times)), \n                  #4c7894 calc(75% / var(--repeating-conic-gradient-times)),\n                  #dd7bbb calc(100% / var(--repeating-conic-gradient-times))\n                )`,\n            } as React.CSSProperties\n          }\n          className={cn(\n            \"pointer-events-none absolute inset-0 rounded-[inherit] opacity-100 transition-opacity\",\n            glow && \"opacity-100\",\n            blur > 0 && \"blur-[var(--blur)] \",\n            className,\n            disabled && \"!hidden\"\n          )}\n        >\n          <div\n            className={cn(\n              \"glow\",\n              \"rounded-[inherit]\",\n              'after:content-[\"\"] after:rounded-[inherit] after:absolute after:inset-[calc(-1*var(--glowingeffect-border-width))]',\n              \"after:[border:var(--glowingeffect-border-width)_solid_transparent]\",\n              \"after:[background:var(--gradient)] after:[background-attachment:fixed]\",\n              \"after:opacity-[var(--active)] after:transition-opacity after:duration-300\",\n              \"after:[mask-clip:padding-box,border-box]\",\n              \"after:[mask-composite:intersect]\",\n              \"after:[mask-image:linear-gradient(#0000,#0000),conic-gradient(from_calc((var(--start)-var(--spread))*1deg),#00000000_0deg,#fff,#00000000_calc(var(--spread)*2deg))]\"\n            )}\n          />\n        </div>\n      </>\n    );\n  }\n);\n\nGlowingEffect.displayName = \"GlowingEffect\";\n\nexport { GlowingEffect };\n",
      "type": "registry:ui",
      "target": "components/ui/glowing-effect.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Glowing Effect"
}