aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
162 lines (159 loc) • 5.54 kB
JavaScript
'use client';
import { jsx } from 'react/jsx-runtime';
import { useReducedMotion } from '../../hooks/useReducedMotion.js';
import { useRef, useEffect, useMemo } from 'react';
import { useAnimationFrame } from 'framer-motion';
import { cn } from '../../lib/utilsComprehensive.js';
import '../../primitives/GlassCore.js';
import '../../primitives/glass/GlassAdvanced.js';
import '../../primitives/OptimizedGlassCore.js';
import '../../primitives/glass/OptimizedGlassAdvanced.js';
import '../../primitives/MotionNative.js';
import '../../primitives/motion/MotionFramer.js';
function GlassMeshGradient({
className,
colors = ["var(--glass-color-primary)", "#8b5cf6", "#ec4899", "var(--glass-color-warning)"],
points = 4,
speed = 0.5,
blur = 100,
opacity = 0.8,
animate = true,
interactive = false,
complexity = "moderate",
variant = "ambient"
}) {
useReducedMotion();
const canvasRef = useRef(null);
const meshPoints = useRef([]);
const mousePos = useRef({
x: 0,
y: 0
});
const frame = useRef(0);
// Initialize mesh points
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const numPoints = complexity === "simple" ? 3 : complexity === "moderate" ? points : points * 2;
meshPoints.current = Array.from({
length: numPoints
}, (_, i) => ({
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: (Math.random() - 0.5) * speed,
vy: (Math.random() - 0.5) * speed,
color: colors[i % colors.length],
radius: 100 + Math.random() * 200
}));
}, [colors, points, speed, complexity]);
// Handle mouse interaction
useEffect(() => {
if (!interactive) return;
const handleMouseMove = e => {
const canvas = canvasRef.current;
if (!canvas) return;
const rect = canvas.getBoundingClientRect();
mousePos.current = {
x: e.clientX - rect.left,
y: e.clientY - rect.top
};
};
window.addEventListener("mousemove", handleMouseMove);
return () => window.removeEventListener("mousemove", handleMouseMove);
}, [interactive]);
// Resize handler
useEffect(() => {
const handleResize = () => {
const canvas = canvasRef.current;
if (!canvas) return;
const parent = canvas.parentElement;
if (!parent) return;
canvas.width = parent.clientWidth;
canvas.height = parent.clientHeight;
};
handleResize();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
// Animation loop
useAnimationFrame(time => {
if (!animate) return;
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
if (!canvas || !ctx) return;
frame.current += 1;
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Update and draw mesh points
meshPoints.current.forEach((point, i) => {
// Update position
if (animate) {
point.x += point.vx;
point.y += point.vy;
// Bounce off walls
if (point.x < 0 || point.x > canvas.width) point.vx *= -1;
if (point.y < 0 || point.y > canvas.height) point.vy *= -1;
// Keep in bounds
point.x = Math.max(0, Math.min(canvas.width, point.x));
point.y = Math.max(0, Math.min(canvas.height, point.y));
// Interactive mouse repulsion
if (interactive) {
const dx = mousePos.current.x - point.x;
const dy = mousePos.current.y - point.y;
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 150) {
const force = (150 - dist) / 150;
point.vx -= dx / dist * force * 0.5;
point.vy -= dy / dist * force * 0.5;
}
}
// Add sinusoidal movement for organic feel
point.x += Math.sin(frame.current * 0.01 + i) * 0.3;
point.y += Math.cos(frame.current * 0.01 + i) * 0.3;
}
// Create gradient
const gradient = ctx.createRadialGradient(point.x, point.y, 0, point.x, point.y, point.radius);
const color = point.color;
gradient.addColorStop(0, `${color}${Math.floor(opacity * 255).toString(16)}`);
gradient.addColorStop(0.5, `${color}${Math.floor(opacity * 0.5 * 255).toString(16)}`);
gradient.addColorStop(1, `${color}00`);
// Draw gradient
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
});
// Apply additional effects based on variant
if (variant === "vibrant") {
ctx.globalCompositeOperation = "screen";
} else if (variant === "dark") {
ctx.globalCompositeOperation = "multiply";
} else if (variant === "subtle") {
ctx.globalAlpha = 0.5;
}
});
// Generate CSS filter based on variant
const filterStyle = useMemo(() => {
switch (variant) {
case "vibrant":
return "saturate(1.5) brightness(1.2)";
case "subtle":
return "saturate(0.8) brightness(0.9)";
case "dark":
return "saturate(1.2) brightness(0.7) contrast(1.2)";
default:
return "saturate(1) brightness(1)";
}
}, [variant]);
return jsx("div", {
className: cn("relative overflow-hidden", className),
children: jsx("canvas", {
ref: canvasRef,
className: 'absolute inset-0 glass-w-full glass-h-full',
style: {
filter: `blur(${blur}px) ${filterStyle}`,
opacity
}
})
});
}
export { GlassMeshGradient };
//# sourceMappingURL=GlassMeshGradient.js.map