UNPKG

aura-glass

Version:

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

254 lines (251 loc) 8.41 kB
'use client'; import { useRef, useState, useEffect, useCallback, useMemo } from 'react'; import { PerformanceMonitor, MemoryManager } from '../../utils/performanceOptimizations.js'; const DEFAULT_OPTIONS = { enableMonitoring: true, targetFPS: 60, memoryLimit: 100, autoAdjustQuality: true, qualityThreshold: 45, onPerformanceMetrics: () => {}, onQualityChange: () => {} }; function useGlassPerformance(options = {}) { const finalOptions = { ...DEFAULT_OPTIONS, ...options }; const monitorRef = useRef(); const memoryManagerRef = useRef(); const frameCountRef = useRef(0); const lastTimeRef = useRef(0); const qualityRef = useRef(1.0); const [metrics, setMetrics] = useState({ fps: 0, frameTime: 0, memoryUsage: 0, renderTime: 0, quality: 1.0, isThrottled: false, recommendations: [] }); // Initialize performance monitoring useEffect(() => { if (!finalOptions.enableMonitoring) return; monitorRef.current = PerformanceMonitor.getInstance({ targetFPS: finalOptions.targetFPS, maxMemoryUsage: finalOptions.memoryLimit * 1024 * 1024 }); memoryManagerRef.current = MemoryManager.getInstance(finalOptions.memoryLimit * 1024 * 1024); return () => { // PerformanceMonitor is a singleton and doesn't need explicit cleanup }; }, [finalOptions.enableMonitoring, finalOptions.targetFPS, finalOptions.memoryLimit]); // FPS monitoring const measureFPS = useCallback(() => { const currentTime = performance.now(); frameCountRef.current++; if (lastTimeRef.current === 0) { lastTimeRef.current = currentTime; } const deltaTime = currentTime - lastTimeRef.current; if (deltaTime >= 1000) { const fps = Math.round(frameCountRef.current * 1000 / deltaTime); const frameTime = deltaTime / frameCountRef.current; setMetrics(prev => ({ ...prev, fps, frameTime })); frameCountRef.current = 0; lastTimeRef.current = currentTime; // Quality adjustment if (finalOptions.autoAdjustQuality) { adjustQuality(fps); } } requestAnimationFrame(measureFPS); }, [finalOptions.autoAdjustQuality]); const adjustQuality = useCallback(fps => { const targetFPS = finalOptions.targetFPS; const threshold = finalOptions.qualityThreshold; let newQuality = qualityRef.current; if (fps < threshold) { // Reduce quality newQuality = Math.max(0.1, qualityRef.current * 0.9); } else if (fps > targetFPS * 0.9) { // Increase quality newQuality = Math.min(1.0, qualityRef.current * 1.05); } if (newQuality !== qualityRef.current) { qualityRef.current = newQuality; finalOptions.onQualityChange(newQuality); setMetrics(prev => ({ ...prev, quality: newQuality })); } }, [finalOptions]); // Start monitoring useEffect(() => { if (!finalOptions.enableMonitoring) return; const animationId = requestAnimationFrame(measureFPS); return () => { cancelAnimationFrame(animationId); }; }, [finalOptions.enableMonitoring, measureFPS]); // Performance metrics callback useEffect(() => { if (!monitorRef.current) return; const interval = setInterval(() => { const monitorMetrics = monitorRef.current?.getMetrics(); const memoryStats = memoryManagerRef.current?.getStats(); if (monitorMetrics) { const recommendations = monitorRef.current?.getOptimizationSuggestions() || []; setMetrics(prev => ({ ...prev, memoryUsage: monitorMetrics.memoryUsage, renderTime: monitorMetrics.frameTime, isThrottled: prev.fps < finalOptions.qualityThreshold, recommendations })); finalOptions.onPerformanceMetrics({ ...monitorMetrics, memoryStats, recommendations }); } }, 2000); return () => clearInterval(interval); }, [finalOptions]); // Performance optimization methods const optimizeForLowPerformance = useCallback(() => { return { reduceParticles: true, disableShadows: true, lowerResolution: true, reduceAnimationComplexity: true }; }, []); const getOptimalSettings = useCallback(() => { const currentFPS = metrics.fps; const memoryUsage = metrics.memoryUsage; const memoryLimit = finalOptions.memoryLimit * 1024 * 1024; return { particleCount: currentFPS > 50 ? 100 : currentFPS > 30 ? 50 : 25, shadowQuality: memoryUsage < memoryLimit * 0.8 ? 'high' : 'low', textureSize: currentFPS > 50 ? 1024 : 512, animationEnabled: currentFPS > 25, blurEnabled: currentFPS > 40 }; }, [metrics.fps, metrics.memoryUsage, finalOptions.memoryLimit]); return { metrics, quality: qualityRef.current, optimizeForLowPerformance, getOptimalSettings, isLowPerformance: metrics.fps < finalOptions.qualityThreshold, isHighPerformance: metrics.fps > finalOptions.targetFPS * 0.9 }; } // Hook for debounced performance monitoring function useDebouncedPerformance(callback, delay = 1000, options = {}) { const [debouncedMetrics, setDebouncedMetrics] = useState(null); const timeoutRef = useRef(); const performance = useGlassPerformance({ ...options, onPerformanceMetrics: metrics => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } timeoutRef.current = setTimeout(() => { setDebouncedMetrics(metrics); callback(metrics); }, delay); } }); useEffect(() => { return () => { if (timeoutRef.current) { clearTimeout(timeoutRef.current); } }; }, []); return { ...performance, debouncedMetrics }; } // Hook for conditional rendering based on performance function useConditionalRendering(performance, thresholds = { low: 30, medium: 45, high: 55 }) { const performanceLevel = useMemo(() => { const fps = performance.metrics.fps; if (fps < thresholds.low) return 'low'; if (fps < thresholds.medium) return 'medium'; if (fps < thresholds.high) return 'high'; return 'ultra'; }, [performance.metrics.fps, thresholds]); const shouldRender = useCallback(minPerformance => { const levels = ['low', 'medium', 'high', 'ultra']; const currentIndex = levels.indexOf(performanceLevel); const minIndex = levels.indexOf(minPerformance); return currentIndex >= minIndex; }, [performanceLevel]); const getComponentVariant = useCallback(variants => { return variants[performanceLevel] || variants.default; }, [performanceLevel]); return { performanceLevel, shouldRender, getComponentVariant }; } // Hook for lazy loading based on performance function useLazyPerformance(component, fallback, options = {}) { const { minFPS = 30, loadDelay = 1000, ...performanceOptions } = options; const [isLoaded, setIsLoaded] = useState(false); const performance = useGlassPerformance(performanceOptions); useEffect(() => { if (performance.metrics.fps >= minFPS) { const timer = setTimeout(() => { setIsLoaded(true); }, loadDelay); return () => clearTimeout(timer); } }, [performance.metrics.fps, minFPS, loadDelay]); const Component = isLoaded ? component : fallback || (() => null); return { Component, isLoaded, performance }; } // Hook for progressive enhancement function useProgressiveEnhancement(performance, features) { const enabledFeatures = useMemo(() => { return features.filter(feature => performance.metrics.fps >= feature.minFPS); }, [features, performance.metrics.fps]); const getFeatureComponent = useCallback(featureName => { const feature = enabledFeatures.find(f => f.name === featureName); return feature?.component || (() => null); }, [enabledFeatures]); const isFeatureEnabled = useCallback(featureName => { return enabledFeatures.some(f => f.name === featureName); }, [enabledFeatures]); return { enabledFeatures, getFeatureComponent, isFeatureEnabled, performanceLevel: performance.metrics.fps >= 50 ? 'high' : performance.metrics.fps >= 30 ? 'medium' : 'low' }; } export { useConditionalRendering, useDebouncedPerformance, useGlassPerformance, useLazyPerformance, useProgressiveEnhancement }; //# sourceMappingURL=useGlassPerformance.js.map