{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pulse-loader",
  "title": "Pulse Loader",
  "description": "A breathing loader of concentric rings that pulse in and out with your own color.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/clover-ui/pulse-loader.tsx",
      "content": "\"use client\";\n\nimport { motion, useReducedMotion } from \"motion/react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nexport interface PulseLoaderProps {\n  ref?: React.Ref<PulseLoaderRef>;\n  color?: string;\n  rings?: number;\n  minOpacity?: number;\n  maxOpacity?: number;\n  size?: number;\n  duration?: number;\n  contraction?: number;\n  stagger?: number;\n\n  className?: string;\n  ringClassName?: string;\n\n  autoStart?: boolean;\n}\n\nexport interface PulseLoaderRef {\n  play: () => void;\n  pause: () => void;\n}\n\nfunction PulseLoader({\n  ref,\n  color = \"#0B87DA\",\n  rings = 4,\n  minOpacity = 0.2,\n  maxOpacity = 1,\n  size = 60,\n  duration = 1.8,\n  contraction = 0.55,\n  stagger = 0.15,\n  className,\n  ringClassName,\n  autoStart = true,\n}: PulseLoaderProps) {\n  const [running, setRunning] = React.useState(autoStart);\n  const reduceMotion = useReducedMotion();\n  const pulsing = running && !reduceMotion;\n\n  const play = React.useCallback(() => setRunning(true), []);\n  const pause = React.useCallback(() => setRunning(false), []);\n\n  React.useImperativeHandle(ref, () => ({ play, pause }), [play, pause]);\n  const ringData = React.useMemo(() => {\n    return Array.from({ length: rings }, (_, i) => {\n      const depth = i / (rings - 1 || 1);\n      const scale = 1 - depth * 0.72;\n      const opacity = minOpacity + depth * (maxOpacity - minOpacity);\n      return {\n        key: i,\n        scale,\n        opacity,\n        delay: (rings - 1 - i) * stagger,\n      };\n    });\n  }, [rings, minOpacity, maxOpacity, stagger]);\n\n  return (\n    <div\n      className={cn(\"relative inline-flex items-center justify-center\", className)}\n      style={{ width: size, height: size }}\n      role=\"status\"\n      aria-label=\"Loading\"\n    >\n      {ringData.map((ring) => (\n        <motion.span\n          key={ring.key}\n          className={cn(\"absolute rounded-full\", ringClassName)}\n          style={{\n            width: `${ring.scale * 100}%`,\n            height: `${ring.scale * 100}%`,\n            backgroundColor: color,\n            opacity: ring.opacity,\n          }}\n          animate={pulsing ? { scale: [1, contraction, 1] } : { scale: 1 }}\n          transition={{\n            duration,\n            delay: ring.delay,\n            repeat: pulsing ? Infinity : 0,\n            ease: \"easeInOut\",\n          }}\n        />\n      ))}\n    </div>\n  );\n}\n\nexport { PulseLoader };\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}