{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "glass-ripple",
  "title": "Glass Ripple",
  "description": "A ripple effect component that can be applied to various elements for a dynamic interaction experience.",
  "files": [
    {
      "path": "registry/innovative/glass-ripple.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"@/lib/utils\"\n\ninterface Ripple {\n  id: number\n  x: number\n  y: number\n  size: number\n}\n\ninterface GlassRippleProps extends React.HTMLAttributes<HTMLDivElement> {\n  color?: \"cyan\" | \"purple\" | \"white\" | \"blue\"\n  duration?: number\n  disabled?: boolean\n}\n\nconst rippleColors = {\n  cyan: \"bg-cyan-400/30\",\n  purple: \"bg-purple-400/30\",\n  white: \"bg-white/30\",\n  blue: \"bg-blue-400/30\",\n}\n\nconst GlassRipple = React.forwardRef<HTMLDivElement, GlassRippleProps>(\n  ({ className, children, color = \"white\", duration = 600, disabled = false, ...props }, ref) => {\n    const [ripples, setRipples] = React.useState<Ripple[]>([])\n    const containerRef = React.useRef<HTMLDivElement>(null)\n\n    const createRipple = React.useCallback(\n      (e: React.MouseEvent<HTMLDivElement> | React.TouchEvent<HTMLDivElement>) => {\n        if (disabled || !containerRef.current) return\n\n        const rect = containerRef.current.getBoundingClientRect()\n        let x: number, y: number\n\n        if (\"touches\" in e) {\n          x = e.touches[0].clientX - rect.left\n          y = e.touches[0].clientY - rect.top\n        } else {\n          x = e.clientX - rect.left\n          y = e.clientY - rect.top\n        }\n\n        const size = Math.max(rect.width, rect.height) * 2\n\n        const newRipple: Ripple = {\n          id: Date.now(),\n          x,\n          y,\n          size,\n        }\n\n        setRipples((prev) => [...prev, newRipple])\n\n        setTimeout(() => {\n          setRipples((prev) => prev.filter((r) => r.id !== newRipple.id))\n        }, duration)\n      },\n      [disabled, duration],\n    )\n\n    return (\n      <div ref={ref} className={cn(\"relative overflow-hidden cursor-pointer\", className)} {...props}>\n        <div ref={containerRef} className=\"absolute inset-0\" onMouseDown={createRipple} onTouchStart={createRipple}>\n          {ripples.map((ripple) => (\n            <span\n              key={ripple.id}\n              className={cn(\n                \"absolute rounded-full pointer-events-none\",\n                \"animate-[ripple_0.6s_ease-out_forwards]\",\n                rippleColors[color],\n              )}\n              style={{\n                left: ripple.x - ripple.size / 2,\n                top: ripple.y - ripple.size / 2,\n                width: ripple.size,\n                height: ripple.size,\n              }}\n            />\n          ))}\n        </div>\n        <div className=\"relative z-10 pointer-events-none\">{children}</div>\n      </div>\n    )\n  },\n)\nGlassRipple.displayName = \"GlassRipple\"\n\n// Button with built-in ripple\ninterface GlassRippleButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n  variant?: \"default\" | \"primary\" | \"outline\"\n  rippleColor?: \"cyan\" | \"purple\" | \"white\" | \"blue\"\n}\n\nconst GlassRippleButton = React.forwardRef<HTMLButtonElement, GlassRippleButtonProps>(\n  ({ className, children, variant = \"default\", rippleColor = \"white\", ...props }, ref) => {\n    const [ripples, setRipples] = React.useState<Ripple[]>([])\n    const buttonRef = React.useRef<HTMLButtonElement>(null)\n\n    React.useImperativeHandle(ref, () => buttonRef.current!)\n\n    const createRipple = React.useCallback((e: React.MouseEvent<HTMLButtonElement>) => {\n      if (!buttonRef.current) return\n\n      const rect = buttonRef.current.getBoundingClientRect()\n      const x = e.clientX - rect.left\n      const y = e.clientY - rect.top\n      const size = Math.max(rect.width, rect.height) * 2\n\n      const newRipple: Ripple = { id: Date.now(), x, y, size }\n      setRipples((prev) => [...prev, newRipple])\n\n      setTimeout(() => {\n        setRipples((prev) => prev.filter((r) => r.id !== newRipple.id))\n      }, 600)\n    }, [])\n\n    const variants = {\n      default: \"bg-white/20 backdrop-blur-xl border border-white/30 text-white hover:bg-white/30\",\n      primary:\n        \"bg-linear-to-r from-cyan-500/80 via-blue-500/80 to-purple-500/80 backdrop-blur-xl border border-white/30 text-white\",\n      outline: \"bg-transparent backdrop-blur-sm border-2 border-white/40 text-white hover:bg-white/10\",\n    }\n\n    return (\n      <button\n        ref={buttonRef}\n        className={cn(\n          \"relative overflow-hidden rounded-xl px-6 py-3 font-medium\",\n          \"transition-all duration-300 ease-out\",\n          \"hover:scale-105 active:scale-95\",\n          variants[variant],\n          className,\n        )}\n        onMouseDown={createRipple}\n        {...props}\n      >\n        {ripples.map((ripple) => (\n          <span\n            key={ripple.id}\n            className={cn(\n              \"absolute rounded-full pointer-events-none\",\n              \"animate-[ripple_0.6s_ease-out_forwards]\",\n              rippleColors[rippleColor],\n            )}\n            style={{\n              left: ripple.x - ripple.size / 2,\n              top: ripple.y - ripple.size / 2,\n              width: ripple.size,\n              height: ripple.size,\n            }}\n          />\n        ))}\n        <span className=\"relative z-10\">{children}</span>\n      </button>\n    )\n  },\n)\nGlassRippleButton.displayName = \"GlassRippleButton\"\n\nexport { GlassRipple, GlassRippleButton }\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}