{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "animated-beam",
  "type": "registry:ui",
  "title": "Animated Beam",
  "description": "An animated beam of light which travels along a path. Useful for showcasing the integration features of a website.",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "registry/magicui/animated-beam.tsx",
      "content": "\"use client\"\n\nimport { useEffect, useId, useState, type RefObject } from \"react\"\nimport { motion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface AnimatedBeamProps {\n  className?: string\n  containerRef: RefObject<HTMLElement | null> // Container ref\n  fromRef: RefObject<HTMLElement | null>\n  toRef: RefObject<HTMLElement | null>\n  curvature?: number\n  reverse?: boolean\n  pathColor?: string\n  pathWidth?: number\n  pathOpacity?: number\n  gradientStartColor?: string\n  gradientStopColor?: string\n  delay?: number\n  duration?: number\n  repeat?: number\n  repeatDelay?: number\n  startXOffset?: number\n  startYOffset?: number\n  endXOffset?: number\n  endYOffset?: number\n}\n\nexport const AnimatedBeam: React.FC<AnimatedBeamProps> = ({\n  className,\n  containerRef,\n  fromRef,\n  toRef,\n  curvature = 0,\n  reverse = false, // Include the reverse prop\n  duration = 5,\n  delay = 0,\n  pathColor = \"gray\",\n  pathWidth = 2,\n  pathOpacity = 0.2,\n  gradientStartColor = \"#ffaa40\",\n  gradientStopColor = \"#9c40ff\",\n  repeat = Infinity,\n  repeatDelay = 0,\n  startXOffset = 0,\n  startYOffset = 0,\n  endXOffset = 0,\n  endYOffset = 0,\n}) => {\n  const id = useId()\n  const [pathD, setPathD] = useState(\"\")\n  const [svgDimensions, setSvgDimensions] = useState({ width: 0, height: 0 })\n\n  // Calculate the gradient coordinates based on the reverse prop\n  const gradientCoordinates = reverse\n    ? {\n        x1: [\"90%\", \"-10%\"],\n        x2: [\"100%\", \"0%\"],\n        y1: [\"0%\", \"0%\"],\n        y2: [\"0%\", \"0%\"],\n      }\n    : {\n        x1: [\"10%\", \"110%\"],\n        x2: [\"0%\", \"100%\"],\n        y1: [\"0%\", \"0%\"],\n        y2: [\"0%\", \"0%\"],\n      }\n\n  useEffect(() => {\n    const updatePath = () => {\n      if (containerRef.current && fromRef.current && toRef.current) {\n        const containerRect = containerRef.current.getBoundingClientRect()\n        const rectA = fromRef.current.getBoundingClientRect()\n        const rectB = toRef.current.getBoundingClientRect()\n\n        const svgWidth = containerRect.width\n        const svgHeight = containerRect.height\n        setSvgDimensions({ width: svgWidth, height: svgHeight })\n\n        const startX =\n          rectA.left - containerRect.left + rectA.width / 2 + startXOffset\n        const startY =\n          rectA.top - containerRect.top + rectA.height / 2 + startYOffset\n        const endX =\n          rectB.left - containerRect.left + rectB.width / 2 + endXOffset\n        const endY =\n          rectB.top - containerRect.top + rectB.height / 2 + endYOffset\n\n        const controlY = startY - curvature\n        const d = `M ${startX},${startY} Q ${\n          (startX + endX) / 2\n        },${controlY} ${endX},${endY}`\n        setPathD(d)\n      }\n    }\n\n    // Initialize ResizeObserver\n    const resizeObserver = new ResizeObserver(() => {\n      updatePath()\n    })\n\n    // Observe the container element\n    if (containerRef.current) {\n      resizeObserver.observe(containerRef.current)\n    }\n\n    // Call the updatePath initially to set the initial path\n    updatePath()\n\n    // Clean up the observer on component unmount\n    return () => {\n      resizeObserver.disconnect()\n    }\n  }, [\n    containerRef,\n    fromRef,\n    toRef,\n    curvature,\n    startXOffset,\n    startYOffset,\n    endXOffset,\n    endYOffset,\n  ])\n\n  return (\n    <svg\n      fill=\"none\"\n      width={svgDimensions.width}\n      height={svgDimensions.height}\n      xmlns=\"http://www.w3.org/2000/svg\"\n      className={cn(\n        \"pointer-events-none absolute top-0 left-0 transform-gpu stroke-2\",\n        className\n      )}\n      viewBox={`0 0 ${svgDimensions.width} ${svgDimensions.height}`}\n    >\n      <path\n        d={pathD}\n        stroke={pathColor}\n        strokeWidth={pathWidth}\n        strokeOpacity={pathOpacity}\n        strokeLinecap=\"round\"\n      />\n      <path\n        d={pathD}\n        strokeWidth={pathWidth}\n        stroke={`url(#${id})`}\n        strokeOpacity=\"1\"\n        strokeLinecap=\"round\"\n      />\n      <defs>\n        <motion.linearGradient\n          className=\"transform-gpu\"\n          id={id}\n          gradientUnits={\"userSpaceOnUse\"}\n          initial={{\n            x1: \"0%\",\n            x2: \"0%\",\n            y1: \"0%\",\n            y2: \"0%\",\n          }}\n          animate={{\n            x1: gradientCoordinates.x1,\n            x2: gradientCoordinates.x2,\n            y1: gradientCoordinates.y1,\n            y2: gradientCoordinates.y2,\n          }}\n          transition={{\n            delay,\n            duration,\n            ease: [0.16, 1, 0.3, 1], // https://easings.net/#easeOutExpo\n            repeat,\n            repeatDelay,\n          }}\n        >\n          <stop stopColor={gradientStartColor} stopOpacity=\"0\"></stop>\n          <stop stopColor={gradientStartColor}></stop>\n          <stop offset=\"32.5%\" stopColor={gradientStopColor}></stop>\n          <stop\n            offset=\"100%\"\n            stopColor={gradientStopColor}\n            stopOpacity=\"0\"\n          ></stop>\n        </motion.linearGradient>\n      </defs>\n    </svg>\n  )\n}\n",
      "type": "registry:ui"
    }
  ]
}