UNPKG

aura-glass

Version:

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

326 lines (323 loc) 12.8 kB
'use client'; import { jsx, jsxs } from 'react/jsx-runtime'; import { forwardRef, useState, useEffect, useCallback } from 'react'; import '../../primitives/GlassCore.js'; import '../../primitives/glass/GlassAdvanced.js'; import { OptimizedGlassCore } from '../../primitives/OptimizedGlassCore.js'; import '../../primitives/glass/OptimizedGlassAdvanced.js'; import '../../primitives/MotionNative.js'; import { MotionFramer } from '../../primitives/motion/MotionFramer.js'; import { cn } from '../../lib/utilsComprehensive.js'; import { useA11yId } from '../../utils/a11y.js'; import { useMotionPreferenceContext } from '../../contexts/MotionPreferenceContext.js'; import { useGlassSound } from '../../utils/soundDesign.js'; const defaultMoodStates = [{ name: "Happy", color: "#FFD700", intensity: 0.8, description: "Feeling joyful and content" }, { name: "Calm", color: "#87CEEB", intensity: 0.6, description: "Peaceful and relaxed" }, { name: "Energetic", color: "#FF4500", intensity: 0.9, description: "Full of energy and excitement" }, { name: "Focused", color: "#9370DB", intensity: 0.7, description: "Concentrated and determined" }, { name: "Stressed", color: "#DC143C", intensity: 0.8, description: "Feeling overwhelmed or tense" }, { name: "Creative", color: "#FF69B4", intensity: 0.75, description: "In a creative and imaginative state" }, { name: "Melancholic", color: "#4169E1", intensity: 0.5, description: "Reflective and somewhat sad" }, { name: "Excited", color: "#32CD32", intensity: 0.85, description: "Thrilled and anticipatory" }, { name: "Anxious", color: "#FF6347", intensity: 0.7, description: "Worried or apprehensive" }, { name: "Peaceful", color: "#98FB98", intensity: 0.4, description: "Completely at ease and serene" }]; const GlassMoodRing = /*#__PURE__*/forwardRef(({ mood, moodStates = defaultMoodStates, size = "md", interactive = true, animated = true, transitionDuration = 1000, showLabels = true, showDescription = false, onMoodChange, autoTransition, biometricIntegration = false, ambientResponse = false, thickness = "medium", glowIntensity = "medium", pulse = false, respectMotionPreference = true, className, ...props }, ref) => { const { prefersReducedMotion } = useMotionPreferenceContext(); const { play } = useGlassSound(); const moodRingId = useA11yId("glass-mood-ring"); const [currentMood, setCurrentMood] = useState(mood || moodStates[0]); const [isTransitioning, setIsTransitioning] = useState(false); const [autoTransitionActive, setAutoTransitionActive] = useState(false); const sizeConfig = { sm: { ring: "w-16 h-16", center: "w-8 h-8", text: "glass-text-xs", description: "glass-text-xs", glow: "shadow-lg" }, md: { ring: "w-24 h-24", center: "w-12 h-12", text: "glass-text-sm", description: "glass-text-sm", glow: "shadow-xl" }, lg: { ring: "w-32 h-32", center: "w-16 h-16", text: "glass-text-base", description: "glass-text-base", glow: "shadow-2xl" }, xl: { ring: "w-40 h-40", center: "w-20 h-20", text: "glass-text-lg", description: "glass-text-lg", glow: "shadow-2xl" } }; const thicknessConfig = { thin: "border-2", medium: "border-4", thick: "border-8" }; const glowConfig = { none: "", subtle: "shadow-sm", medium: "shadow-lg shadow-current/30", strong: "shadow-2xl shadow-current/50" }; const config = sizeConfig[size]; // Auto-transition effect useEffect(() => { if (!autoTransition || !autoTransitionActive) return; const interval = setInterval(() => { const currentIndex = moodStates.findIndex(m => m.name === currentMood.name); const nextIndex = (currentIndex + 1) % moodStates.length; handleMoodChange(moodStates[nextIndex]); }, autoTransition); return () => clearInterval(interval); }, [autoTransition, autoTransitionActive, currentMood, moodStates]); // Biometric integration simulation useEffect(() => { if (!biometricIntegration) return; // Simulate biometric data affecting mood const biometricInterval = setInterval(() => { // This would normally connect to actual biometric sensors const randomMood = moodStates[Math.floor(Math.random() * moodStates.length)]; if (Math.random() > 0.8) { // 20% chance to change handleMoodChange(randomMood); } }, 10000); return () => clearInterval(biometricInterval); }, [biometricIntegration, moodStates]); // Ambient response simulation useEffect(() => { if (!ambientResponse) return; // Simulate environmental factors affecting mood const ambientInterval = setInterval(() => { const hour = new Date().getHours(); let ambientMood = currentMood; // Simulate time of day effects if (hour >= 6 && hour < 12) { ambientMood = moodStates.find(m => m.name === "Energetic") || currentMood; } else if (hour >= 12 && hour < 18) { ambientMood = moodStates.find(m => m.name === "Focused") || currentMood; } else if (hour >= 18 && hour < 22) { ambientMood = moodStates.find(m => m.name === "Calm") || currentMood; } else { ambientMood = moodStates.find(m => m.name === "Peaceful") || currentMood; } if (ambientMood !== currentMood) { handleMoodChange(ambientMood); } }, 60000); // Check every minute return () => clearInterval(ambientInterval); }, [ambientResponse, currentMood, moodStates]); // Handle mood changes const handleMoodChange = useCallback(newMood => { if (newMood.name === currentMood.name) return; setIsTransitioning(true); setTimeout(() => { setCurrentMood(newMood); setIsTransitioning(false); onMoodChange?.(newMood); play("mood_change"); }, animated ? transitionDuration / 2 : 0); }, [currentMood, animated, transitionDuration, onMoodChange, play]); // Handle ring click const handleRingClick = useCallback(() => { if (!interactive) return; const currentIndex = moodStates.findIndex(m => m.name === currentMood.name); const nextIndex = (currentIndex + 1) % moodStates.length; handleMoodChange(moodStates[nextIndex]); }, [interactive, moodStates, currentMood, handleMoodChange]); // Toggle auto-transition const toggleAutoTransition = useCallback(() => { setAutoTransitionActive(!autoTransitionActive); play("toggle"); }, [autoTransitionActive, play]); return jsx(OptimizedGlassCore, { ref: ref, id: moodRingId, elevation: "level2", intensity: "medium", depth: 2, tint: "neutral", border: "subtle", className: cn("glass-mood-ring relative inline-flex flex-col items-center justify-center glass-p-6 glass-radius-lg", "glass-backdrop-blur-md border border-border/20", className), ...props, children: jsxs(MotionFramer, { preset: !prefersReducedMotion && respectMotionPreference ? "fadeIn" : "none", className: "glass-flex glass-flex-col glass-items-center glass-gap-4", children: [jsxs("div", { className: 'relative', children: [jsxs(MotionFramer, { as: "div", preset: !prefersReducedMotion && respectMotionPreference ? "scaleIn" : "none", className: cn("relative glass-radius-full border-solid transition-all duration-1000", config.ring, thicknessConfig[thickness], glowConfig[glowIntensity], interactive && "cursor-pointer hover:scale-105", pulse && !prefersReducedMotion && "animate-pulse", isTransitioning && "opacity-50"), style: { borderColor: currentMood.color, boxShadow: glowIntensity !== "none" ? `0 0 20px ${currentMood.color}40` : undefined }, onClick: handleRingClick, role: interactive ? "button" : "status", "aria-label": `Current mood: ${currentMood.name} - ${currentMood.description}`, tabIndex: interactive ? 0 : -1, onKeyDown: e => { if ((e.key === "Enter" || e.key === " ") && interactive) { e.preventDefault(); handleRingClick(); } }, children: [jsx("div", { className: cn("absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2", "glass-radius-full flex items-center justify-center transition-all duration-1000", config.center, !prefersReducedMotion && "animate-pulse"), style: { backgroundColor: `${currentMood.color}${Math.round(currentMood.intensity * 255).toString(16)}`, boxShadow: `inset 0 0 10px ${currentMood.color}80` }, children: currentMood.icon && jsx("div", { className: 'text-primary/90', children: currentMood.icon }) }), Array.from({ length: 3 }, (_, i) => jsx("div", { className: cn("absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2", "glass-radius-full border transition-all duration-1000", !prefersReducedMotion && "animate-pulse"), style: { width: `${60 + i * 20}%`, height: `${60 + i * 20}%`, borderColor: `${currentMood.color}${Math.round((currentMood.intensity - i * 0.2) * 255).toString(16)}`, animationDelay: `${i * 200}ms`, opacity: Math.max(0, currentMood.intensity - i * 0.3) } }, i))] }), isTransitioning && jsx("div", { className: cn("absolute inset-0 glass-radius-full bg-gradient-radial from-white/20 to-transparent", "animate-spin") })] }), jsxs("div", { className: 'text-center glass-gap-2', children: [showLabels && jsx(MotionFramer, { preset: !prefersReducedMotion && respectMotionPreference ? "slideUp" : "none", className: cn("font-semibold transition-colors duration-500", config.text), style: { color: currentMood.color }, children: currentMood.name }), showDescription && jsx(MotionFramer, { preset: !prefersReducedMotion && respectMotionPreference ? "slideUp" : "none", delay: 100, className: cn("glass-text-secondary max-w-xs text-center", config.description), children: currentMood.description })] }), interactive && moodStates.length > 1 && jsx(MotionFramer, { preset: !prefersReducedMotion && respectMotionPreference ? "slideUp" : "none", delay: 200, className: 'glass-flex glass-flex-wrap glass-gap-1 glass-justify-center max-w-xs', children: moodStates.map((mood, index) => jsx("button", { onClick: () => handleMoodChange(mood), className: cn("w-6 h-6 glass-radius-full border-2 transition-all duration-200", "hover:scale-110 focus:outline-none focus:ring-2 focus:ring-offset-2", currentMood.name === mood.name && "ring-2 ring-white", "focus:ring-white/50"), style: { backgroundColor: mood.color, borderColor: currentMood.name === mood.name ? "white" : mood.color }, title: mood.name, "aria-label": `Select ${mood.name} mood` }, mood.name)) }), (autoTransition || biometricIntegration || ambientResponse) && jsxs(MotionFramer, { preset: !prefersReducedMotion && respectMotionPreference ? "slideUp" : "none", delay: 300, className: "glass-flex glass-gap-2 glass-items-center glass-text-xs glass-text-secondary", children: [autoTransition && jsxs("button", { onClick: toggleAutoTransition, className: cn("glass-px-2 glass-py-1 glass-radius-md border transition-colors", autoTransitionActive ? "bg-primary/20 border-primary/40 text-primary" : "border-border/40 hover:border-border"), children: ["Auto ", autoTransitionActive ? "On" : "Off"] }), biometricIntegration && jsxs("div", { className: "glass-flex glass-items-center glass-gap-1", children: [jsx("div", { className: 'w-2 h-2 glass-surface-green glass-radius-full animate-pulse' }), jsx("span", { children: "Bio" })] }), ambientResponse && jsxs("div", { className: "glass-flex glass-items-center glass-gap-1", children: [jsx("div", { className: 'w-2 h-2 glass-surface-blue glass-radius-full animate-pulse' }), jsx("span", { children: "Ambient" })] })] })] }) }); }); GlassMoodRing.displayName = "GlassMoodRing"; export { GlassMoodRing, GlassMoodRing as default }; //# sourceMappingURL=GlassMoodRing.js.map