xlibs-components
Version:
Modern React component library with Aceternity, MagicUI, and ShadCN components for building beautiful web applications
78 lines (77 loc) • 3.35 kB
JavaScript
"use client";
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { cn } from '../../lib/utils.js';
import { motion } from "motion/react";
import { useEffect, useId, useRef, useState } from "react";
/**
* DotPattern Component
*
* A React component that creates an animated or static dot pattern background using SVG.
* The pattern automatically adjusts to fill its container and can optionally display glowing dots.
*
* @component
*
* @see DotPatternProps for the props interface.
*
* @example
* // Basic usage
* <DotPattern />
*
* // With glowing effect and custom spacing
* <DotPattern
* width={20}
* height={20}
* glow={true}
* className="opacity-50"
* />
*
* @notes
* - The component is client-side only ("use client")
* - Automatically responds to container size changes
* - When glow is enabled, dots will animate with random delays and durations
* - Uses Motion for animations
* - Dots color can be controlled via the text color utility classes
*/
export function DotPattern({ width = 16, height = 16, x = 0, y = 0, cx = 1, cy = 1, cr = 1, className, glow = false, ...props }) {
const id = useId();
const containerRef = useRef(null);
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
const updateDimensions = () => {
if (containerRef.current) {
const { width, height } = containerRef.current.getBoundingClientRect();
setDimensions({ width, height });
}
};
updateDimensions();
window.addEventListener("resize", updateDimensions);
return () => window.removeEventListener("resize", updateDimensions);
}, []);
const dots = Array.from({
length: Math.ceil(dimensions.width / width) *
Math.ceil(dimensions.height / height),
}, (_, i) => {
const col = i % Math.ceil(dimensions.width / width);
const row = Math.floor(i / Math.ceil(dimensions.width / width));
return {
x: col * width + cx,
y: row * height + cy,
delay: Math.random() * 5,
duration: Math.random() * 3 + 2,
};
});
return (_jsxs("svg", { ref: containerRef, "aria-hidden": "true", className: cn("pointer-events-none absolute inset-0 h-full w-full", className), ...props, children: [_jsx("defs", { children: _jsxs("radialGradient", { id: `${id}-gradient`, children: [_jsx("stop", { offset: "0%", stopColor: "currentColor", stopOpacity: "1" }), _jsx("stop", { offset: "100%", stopColor: "currentColor", stopOpacity: "0" })] }) }), dots.map((dot, index) => (_jsx(motion.circle, { cx: dot.x, cy: dot.y, r: cr, fill: glow ? `url(#${id}-gradient)` : "currentColor", className: "text-neutral-400/80", initial: glow ? { opacity: 0.4, scale: 1 } : {}, animate: glow
? {
opacity: [0.4, 1, 0.4],
scale: [1, 1.5, 1],
}
: {}, transition: glow
? {
duration: dot.duration,
repeat: Infinity,
repeatType: "reverse",
delay: dot.delay,
ease: "easeInOut",
}
: {} }, `${dot.x}-${dot.y}`)))] }));
}