UNPKG

aura-glass

Version:

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

558 lines (555 loc) 16.6 kB
'use client'; import { jsx, jsxs, Fragment } from 'react/jsx-runtime'; import { useReducedMotion, useInView, AnimatePresence, motion } from 'framer-motion'; import React, { useState, useEffect, useRef, useMemo, createContext, useContext } from 'react'; import { cn } from '../../lib/utilsComprehensive.js'; import { createGlassStyle } from '../../core/mixins/glassMixins.js'; const PerformanceContext = /*#__PURE__*/createContext(null); function GlassPerformanceProvider({ children, adaptivePerformance = true }) { const [performanceMode, setPerformanceMode] = useState('balanced'); const [batteryLevel, setBatteryLevel] = useState(); const [cpuLoad, setCpuLoad] = useState(0); const [gpuAcceleration, setGpuAcceleration] = useState(true); const [lazyLoading, setLazyLoading] = useState(true); const reducedMotion = useReducedMotion() || false; // Battery API monitoring useEffect(() => { if (typeof navigator !== 'undefined' && 'getBattery' in navigator) { navigator.getBattery().then(battery => { const updateBatteryInfo = () => { setBatteryLevel(Math.round(battery.level * 100)); }; updateBatteryInfo(); battery.addEventListener('levelchange', updateBatteryInfo); battery.addEventListener('chargingchange', updateBatteryInfo); return () => { battery.removeEventListener('levelchange', updateBatteryInfo); battery.removeEventListener('chargingchange', updateBatteryInfo); }; }); } }, []); // CPU load estimation (simplified) useEffect(() => { let frameCount = 0; let lastTime = performance.now(); const measurePerformance = () => { frameCount++; const currentTime = performance.now(); if (currentTime - lastTime >= 1000) { const fps = Math.round(frameCount * 1000 / (currentTime - lastTime)); const load = Math.max(0, Math.min(100, 100 - fps / 60 * 100)); setCpuLoad(load); frameCount = 0; lastTime = currentTime; } requestAnimationFrame(measurePerformance); }; const animationFrame = requestAnimationFrame(measurePerformance); return () => cancelAnimationFrame(animationFrame); }, []); // Adaptive performance adjustments useEffect(() => { if (!adaptivePerformance) return; let newMode = performanceMode; // Battery-based adjustments if (batteryLevel !== undefined && batteryLevel < 20) { newMode = 'battery-saver'; } else if (batteryLevel !== undefined && batteryLevel > 80 && cpuLoad < 30) { newMode = 'high'; } else { newMode = 'balanced'; } // CPU load adjustments if (cpuLoad > 70) { newMode = 'battery-saver'; setGpuAcceleration(false); } else if (cpuLoad < 30) { setGpuAcceleration(true); } if (newMode !== performanceMode) { setPerformanceMode(newMode); } }, [batteryLevel, cpuLoad, adaptivePerformance, performanceMode]); const contextValue = { performanceMode, gpuAcceleration, reducedMotion, lazyLoading, setPerformanceMode, batteryLevel, cpuLoad }; return jsx(PerformanceContext.Provider, { value: contextValue, children: children }); } function useGlassPerformance() { const context = useContext(PerformanceContext); if (!context) { throw new Error('useGlassPerformance must be used within a GlassPerformanceProvider'); } return context; } function EfficientGlassRendering({ children, className = '', enableGPU = true, virtualizeContent = false, deferRender = false, renderDistance = 100, style = {} }) { const { performanceMode, gpuAcceleration } = useGlassPerformance(); const [isVisible, setIsVisible] = useState(!deferRender); const containerRef = useRef(null); const isInView = useInView(containerRef, { margin: `${renderDistance}px`, once: false }); useEffect(() => { if (deferRender) { setIsVisible(isInView); } }, [isInView, deferRender]); // Performance-based glass styles const getOptimizedGlassStyles = useMemo(() => { return createGlassStyle({ intent: "neutral", elevation: "level2" }); }, [performanceMode, enableGPU, gpuAcceleration, style]); if (!isVisible && deferRender) { return jsx("div", { ref: containerRef, className: cn('glass-surface-placeholder glass-border-dashed', className), style: { minHeight: '100px', background: 'transparent', border: '1px dashed rgba(var(--glass-color-black) / var(--glass-opacity-10))' } }); } return jsx("div", { ref: containerRef, className: cn('glass-surface-primary glass-blur-backdrop', className), style: getOptimizedGlassStyles, children: virtualizeContent ? jsx(VirtualizedContent, { children: children }) : children }); } function LazyGlassLoading({ children, placeholder, threshold = 0.1, rootMargin = '50px', className = '', onLoad }) { const [isLoaded, setIsLoaded] = useState(false); const containerRef = useRef(null); const isInView = useInView(containerRef, { amount: threshold, margin: rootMargin, once: true }); useEffect(() => { if (isInView && !isLoaded) { // Simulate async glass effect loading const timer = setTimeout(() => { setIsLoaded(true); onLoad?.(); }, 100); return () => clearTimeout(timer); } }, [isInView, isLoaded, onLoad]); const defaultPlaceholder = jsx("div", { className: cn('glass-surface-placeholder glass-animate-pulse'), style: { background: '/* Use createGlassStyle({ intent: "neutral", elevation: "level2" }) */', backgroundSize: '200% 100%', animation: 'shimmer 1.5s infinite', borderRadius: '12px', minHeight: '100px' } }); return jsx("div", { ref: containerRef, className: className, children: jsx(AnimatePresence, { mode: "wait", children: !isLoaded ? jsx(motion.div, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.3 }, children: placeholder || defaultPlaceholder }, "placeholder") : jsx(motion.div, { initial: { opacity: 0, y: 10 }, animate: { opacity: 1, y: 0 }, transition: { duration: 0.4 }, children: children }, "content") }) }); } function ReducedMotionGlass({ children, className = '', staticAlternative, respectUserPreference = true }) { const { reducedMotion } = useGlassPerformance(); const shouldReduceMotion = respectUserPreference && reducedMotion; if (shouldReduceMotion && staticAlternative) { return jsx("div", { className: cn('glass-surface-primary glass-reduced-motion', className), children: staticAlternative }); } const motionProps = shouldReduceMotion ? { // Disable animations when reduced motion is preferred animate: undefined, transition: { duration: 0 }, whileHover: undefined, whileTap: undefined } : { // Normal animation props initial: { opacity: 0, scale: 0.95 }, animate: { opacity: 1, scale: 1 }, transition: { duration: 0.3, type: 'spring' }, whileHover: { scale: 1.02, y: -2 }, whileTap: { scale: 0.98 } }; return jsx(motion.div, { className: cn('glass-surface-primary glass-reduced-motion', className), style: createGlassStyle({ intent: "neutral", elevation: "level2" }), ...motionProps, children: children }); } function BatteryAwareGlass({ children, className = '', energyThresholds = { high: 50, medium: 25, low: 10 } }) { const { batteryLevel, performanceMode } = useGlassPerformance(); const getEnergyEfficientStyles = () => { const level = batteryLevel || 100; if (level > energyThresholds.high && performanceMode !== 'battery-saver') { // Full effects return createGlassStyle({ intent: "neutral", elevation: "level2" }); } else if (level > energyThresholds.medium) { // Reduced effects return createGlassStyle({ intent: "neutral", elevation: "level2" }); } else { // Minimal effects return createGlassStyle({ intent: "neutral", elevation: "level2" }); } }; return jsxs(motion.div, { className: cn('glass-surface-adaptive glass-border-radius-lg', className), style: { borderRadius: '12px', transition: 'all 0.3s ease-in-out', ...getEnergyEfficientStyles() }, layout: true, children: [children, process.env.NODE_ENV === 'development' && batteryLevel !== undefined && jsxs("div", { className: cn('glass-absolute glass-top-2 glass-left-2 glass-text-xs glass-surface-debug glass-text-on-debug glass-px-2 glass-py-1 glass-radius-sm glass-opacity-50'), children: ["Battery: ", batteryLevel, "%"] })] }); } function ProgressiveGlassEnhancement({ children, tiers = { basic: { background: '/* Use createGlassStyle({ intent: "neutral", elevation: "level2" }) */', border: '1px solid var(--glass-border-default)', borderRadius: '8px' }, enhanced: createGlassStyle({ intent: "neutral", elevation: "level2" }), premium: createGlassStyle({ intent: "neutral", elevation: "level2" }) }, className = '', autoDetect = true }) { const { performanceMode, gpuAcceleration, cpuLoad } = useGlassPerformance(); const getTierStyles = () => { if (!autoDetect) { return tiers.enhanced; // Default to enhanced if not auto-detecting } // Determine tier based on performance indicators if (performanceMode === 'battery-saver' || cpuLoad > 70 || !gpuAcceleration) { return tiers.basic; } else if (performanceMode === 'high' && cpuLoad < 30) { return tiers.premium; } else { return tiers.enhanced; } }; return jsx(motion.div, { className: cn('glass-surface-progressive', className), style: getTierStyles(), layout: true, transition: { duration: 0.3 }, children: children }); } // Virtualized Content Helper function VirtualizedContent({ children }) { const [visibleRange, setVisibleRange] = useState({ start: 0, end: 10 }); const containerRef = useRef(null); useEffect(() => { const container = containerRef.current; if (!container) return; const handleScroll = () => { const containerHeight = container.clientHeight; const scrollTop = container.scrollTop; const itemHeight = 100; // Approximate item height const start = Math.floor(scrollTop / itemHeight); const end = Math.ceil((scrollTop + containerHeight) / itemHeight); setVisibleRange({ start: Math.max(0, start - 2), end: end + 2 }); }; container.addEventListener('scroll', handleScroll); return () => container.removeEventListener('scroll', handleScroll); }, []); const childArray = React.Children.toArray(children); const visibleChildren = childArray.slice(visibleRange.start, visibleRange.end); return jsxs("div", { ref: containerRef, className: cn('glass-virtualized-content glass-h-400 glass-overflow-y-auto'), children: [jsx("div", { style: { height: visibleRange.start * 100 } }), " ", visibleChildren, jsx("div", { style: { height: (childArray.length - visibleRange.end) * 100 } }), " "] }); } // Performance Monitor Component function GlassPerformanceMonitor({ className = '' }) { const { performanceMode, batteryLevel, cpuLoad, gpuAcceleration } = useGlassPerformance(); return jsxs(motion.div, { className: cn('glass-performance-monitor glass-fixed glass-top-10 glass-right-10 glass-z-max', className), style: createGlassStyle({ intent: "neutral", elevation: "level2" }), initial: { opacity: 0, x: 50 }, animate: { opacity: 1, x: 0 }, children: [jsxs("div", { children: ["Mode: ", performanceMode] }), batteryLevel !== undefined && jsxs("div", { children: ["Battery: ", batteryLevel, "%"] }), jsxs("div", { children: ["CPU: ", cpuLoad.toFixed(1), "%"] }), jsxs("div", { children: ["GPU: ", gpuAcceleration ? 'ON' : 'OFF'] })] }); } function PerformanceSummaryCard() { const { performanceMode, batteryLevel, cpuLoad, lazyLoading } = useGlassPerformance(); const metrics = [{ label: 'Mode', value: performanceMode.replace('-', ' ') }, { label: 'Battery', value: batteryLevel !== undefined ? `${batteryLevel}%` : '—' }, { label: 'CPU Load', value: `${cpuLoad.toFixed(0)}%` }, { label: 'Lazy Loading', value: lazyLoading ? 'enabled' : 'disabled' }]; return jsxs("div", { className: "glass-surface-primary glass-radius-2xl glass-p-6 glass-space-y-4 glass-border glass-border-white/10", children: [jsxs("div", { children: [jsx("p", { className: "glass-text-xs glass-text-tertiary uppercase tracking-wide", children: "Performance profile" }), jsx("h2", { className: "glass-text-2xl glass-text-primary font-semibold", children: "Adaptive glass effects" })] }), jsx("div", { className: "glass-grid glass-grid-cols-2 glass-gap-3", children: metrics.map(metric => jsxs("div", { className: "glass-surface-subtle glass-radius-xl glass-p-4", children: [jsx("p", { className: "glass-text-xs glass-text-tertiary mb-1", children: metric.label }), jsx("p", { className: "glass-text-lg glass-text-primary font-semibold", children: metric.value })] }, metric.label)) }), jsx("p", { className: "glass-text-xs glass-text-secondary", children: "The engine continuously balances fidelity with resource usage." })] }); } const DemoPerformanceGrid = () => jsxs("div", { className: "glass-grid md:grid-cols-2 glass-gap-4", children: [jsxs(EfficientGlassRendering, { className: "glass-p-4 glass-radius-xl", children: [jsx("h3", { className: "glass-text-lg glass-text-primary font-semibold", children: "Efficient rendering" }), jsx("p", { className: "glass-text-sm glass-text-secondary", children: "Defers heavy effects when out of view." })] }), jsxs(BatteryAwareGlass, { className: "glass-p-4 glass-radius-xl", children: [jsx("h3", { className: "glass-text-lg glass-text-primary font-semibold", children: "Battery-aware styling" }), jsx("p", { className: "glass-text-sm glass-text-secondary", children: "Automatically dials visuals up or down." })] }), jsxs(LazyGlassLoading, { className: "glass-p-4 glass-radius-xl", children: [jsx("h3", { className: "glass-text-lg glass-text-primary font-semibold", children: "Lazy loading" }), jsx("p", { className: "glass-text-sm glass-text-secondary", children: "Streams content just in time." })] }), jsxs(ReducedMotionGlass, { className: "glass-p-4 glass-radius-xl", children: [jsx("h3", { className: "glass-text-lg glass-text-primary font-semibold", children: "Motion aware" }), jsx("p", { className: "glass-text-sm glass-text-secondary", children: "Respects prefers-reduced-motion automatically." })] })] }); const GlassPerformanceOptimization = ({ adaptivePerformance = true, className, children, showMonitor = false, ...rest }) => jsx(GlassPerformanceProvider, { adaptivePerformance: adaptivePerformance, children: jsxs("div", { className: cn('glass-performance-optimization glass-space-y-6', className), ...rest, children: [children ?? jsxs(Fragment, { children: [jsx(PerformanceSummaryCard, {}), jsx(DemoPerformanceGrid, {})] }), showMonitor && jsx(GlassPerformanceMonitor, {})] }) }); export { BatteryAwareGlass, EfficientGlassRendering, GlassPerformanceMonitor, GlassPerformanceOptimization, GlassPerformanceProvider, LazyGlassLoading, ProgressiveGlassEnhancement, ReducedMotionGlass, GlassPerformanceOptimization as default, useGlassPerformance }; //# sourceMappingURL=GlassPerformanceOptimization.js.map