UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

162 lines (159 loc) 5.54 kB
'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