{
  "name": "background-ripple-effect",
  "type": "registry:ui",
  "dependencies": [
    "motion"
  ],
  "files": [
    {
      "path": "components/ui/background-ripple-effect.tsx",
      "content": "\"use client\";\nimport React, { useMemo, useRef, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport const BackgroundRippleEffect = ({\n  rows = 8,\n  cols = 27,\n  cellSize = 56,\n}: {\n  rows?: number;\n  cols?: number;\n  cellSize?: number;\n}) => {\n  const [clickedCell, setClickedCell] = useState<{\n    row: number;\n    col: number;\n  } | null>(null);\n  const [rippleKey, setRippleKey] = useState(0);\n  const ref = useRef<any>(null);\n\n  return (\n    <div\n      ref={ref}\n      className={cn(\n        \"absolute inset-0 h-full w-full\",\n        \"[--cell-border-color:var(--color-neutral-300)] [--cell-fill-color:var(--color-neutral-100)] [--cell-shadow-color:var(--color-neutral-500)]\",\n        \"dark:[--cell-border-color:var(--color-neutral-700)] dark:[--cell-fill-color:var(--color-neutral-900)] dark:[--cell-shadow-color:var(--color-neutral-800)]\",\n      )}\n    >\n      <div className=\"relative h-auto w-auto overflow-hidden\">\n        <div className=\"pointer-events-none absolute inset-0 z-[2] h-full w-full overflow-hidden\" />\n        <DivGrid\n          key={`base-${rippleKey}`}\n          className=\"mask-radial-from-20% mask-radial-at-top opacity-600\"\n          rows={rows}\n          cols={cols}\n          cellSize={cellSize}\n          borderColor=\"var(--cell-border-color)\"\n          fillColor=\"var(--cell-fill-color)\"\n          clickedCell={clickedCell}\n          onCellClick={(row, col) => {\n            setClickedCell({ row, col });\n            setRippleKey((k) => k + 1);\n          }}\n          interactive\n        />\n      </div>\n    </div>\n  );\n};\n\ntype DivGridProps = {\n  className?: string;\n  rows: number;\n  cols: number;\n  cellSize: number; // in pixels\n  borderColor: string;\n  fillColor: string;\n  clickedCell: { row: number; col: number } | null;\n  onCellClick?: (row: number, col: number) => void;\n  interactive?: boolean;\n};\n\ntype CellStyle = React.CSSProperties & {\n  [\"--delay\"]?: string;\n  [\"--duration\"]?: string;\n};\n\nconst DivGrid = ({\n  className,\n  rows = 7,\n  cols = 30,\n  cellSize = 56,\n  borderColor = \"#3f3f46\",\n  fillColor = \"rgba(14,165,233,0.3)\",\n  clickedCell = null,\n  onCellClick = () => {},\n  interactive = true,\n}: DivGridProps) => {\n  const cells = useMemo(\n    () => Array.from({ length: rows * cols }, (_, idx) => idx),\n    [rows, cols],\n  );\n\n  const gridStyle: React.CSSProperties = {\n    display: \"grid\",\n    gridTemplateColumns: `repeat(${cols}, ${cellSize}px)`,\n    gridTemplateRows: `repeat(${rows}, ${cellSize}px)`,\n    width: cols * cellSize,\n    height: rows * cellSize,\n    marginInline: \"auto\",\n  };\n\n  return (\n    <div className={cn(\"relative z-[3]\", className)} style={gridStyle}>\n      {cells.map((idx) => {\n        const rowIdx = Math.floor(idx / cols);\n        const colIdx = idx % cols;\n        const distance = clickedCell\n          ? Math.hypot(clickedCell.row - rowIdx, clickedCell.col - colIdx)\n          : 0;\n        const delay = clickedCell ? Math.max(0, distance * 55) : 0; // ms\n        const duration = 200 + distance * 80; // ms\n\n        const style: CellStyle = clickedCell\n          ? {\n              \"--delay\": `${delay}ms`,\n              \"--duration\": `${duration}ms`,\n            }\n          : {};\n\n        return (\n          <div\n            key={idx}\n            className={cn(\n              \"cell relative border-[0.5px] opacity-40 transition-opacity duration-150 will-change-transform hover:opacity-80 dark:shadow-[0px_0px_40px_1px_var(--cell-shadow-color)_inset]\",\n              clickedCell && \"animate-cell-ripple [animation-fill-mode:none]\",\n              !interactive && \"pointer-events-none\",\n            )}\n            style={{\n              backgroundColor: fillColor,\n              borderColor: borderColor,\n              ...style,\n            }}\n            onClick={\n              interactive ? () => onCellClick?.(rowIdx, colIdx) : undefined\n            }\n          />\n        );\n      })}\n    </div>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ui/background-ripple-effect.tsx"
    }
  ],
  "author": "Manu Arora <hi@manuarora.in>",
  "title": "Background Ripple Effect"
}