"use client"; import { motion } from "motion/react"; import { ComponentPropsWithoutRef, useCallback, useEffect, useId, useRef, useState, } from "react"; import { twMerge as cn } from "tailwind-merge"; export interface AnimatedGridPatternProps extends ComponentPropsWithoutRef<"svg"> { width?: number; height?: number; x?: number; y?: number; strokeDasharray?: string | number; numSquares?: number; maxOpacity?: number; duration?: number; repeatDelay?: number; } export function AnimatedGridPattern({ width = 40, height = 40, x = -1, y = -1, strokeDasharray = 0, numSquares = 50, className, maxOpacity = 0.5, duration = 4, repeatDelay = 0.5, ...props }: AnimatedGridPatternProps) { const id = useId(); const containerRef = useRef(null); const [dimensions, setDimensions] = useState({ width: 0, height: 0 }); const getPos = useCallback(() => { return [ Math.floor((Math.random() * dimensions.width) / width), Math.floor((Math.random() * dimensions.height) / height), ]; }, [dimensions.width, dimensions.height, width, height]); const generateSquares = useCallback( (count: number) => { return Array.from({ length: count }, (_, i) => ({ id: i, pos: getPos(), })); }, [getPos], ); const [squares, setSquares] = useState(() => generateSquares(numSquares)); const updateSquarePosition = (id: number) => { setSquares((currentSquares) => currentSquares.map((sq) => sq.id === id ? { ...sq, pos: getPos(), } : sq, ), ); }; useEffect(() => { if (dimensions.width && dimensions.height) { setSquares(generateSquares(numSquares)); } }, [dimensions, numSquares, generateSquares]); useEffect(() => { const current = containerRef.current; if (!current) return; const resizeObserver = new ResizeObserver((entries) => { for (const entry of entries) { setDimensions({ width: entry.contentRect.width, height: entry.contentRect.height, }); } }); resizeObserver.observe(current); return () => { resizeObserver.unobserve(current); }; }, []); return ( ); }