aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
371 lines (368 loc) • 14 kB
JavaScript
'use client';
import { jsx } from 'react/jsx-runtime';
import { cn } from '../../lib/utilsComprehensive.js';
import { forwardRef, useState, useRef, useImperativeHandle, 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 '../../primitives/motion/MotionFramer.js';
import { LiquidGlassMaterial } from '../../primitives/LiquidGlassMaterial.js';
import { useAchievements } from '../advanced/GlassAchievementSystem.js';
import { useBiometricAdaptation } from '../advanced/GlassBiometricAdaptation.js';
import { useEyeTracking } from '../advanced/GlassEyeTracking.js';
import { usePredictiveEngine, useInteractionRecorder } from '../advanced/GlassPredictiveEngine.js';
import { useSpatialAudio } from '../advanced/GlassSpatialAudio.js';
/**
* GlassContainer component
* Responsive container with glassmorphism styling, flexible sizing, and consciousness interface integration
*/
const GlassContainer = /*#__PURE__*/forwardRef(({
// TODO: Integrate ContrastGuard for any section titles, labels, and helper text for WCAG AA compliance
size = 'lg',
centered = true,
padding = 'md',
responsivePadding,
variant = 'default',
glass = false,
elevation = 'level1',
radius = 'none',
material = 'glass',
materialProps,
className,
children,
// Consciousness features
predictive = false,
preloadContent = false,
eyeTracking = false,
gazeResponsive = false,
adaptive = false,
biometricResponsive = false,
spatialAudio = false,
audioFeedback = false,
trackAchievements = false,
achievementId,
usageContext = 'main',
...props
}, ref) => {
const [containerElement, setContainerElement] = useState(null);
const localRef = useRef(null);
const [isVisible, setIsVisible] = useState(false);
// Forward ref to parent
useImperativeHandle(ref, () => localRef.current);
const [adaptiveSize, setAdaptiveSize] = useState(size);
const [adaptivePadding, setAdaptivePadding] = useState(padding);
// Consciousness feature hooks - only initialize if features are enabled
predictive ? usePredictiveEngine() : null;
const eyeTracker = eyeTracking ? useEyeTracking() : null;
const biometricAdapter = adaptive ? useBiometricAdaptation() : null;
const spatialAudioEngine = spatialAudio ? useSpatialAudio() : null;
const achievementTracker = trackAchievements ? useAchievements() : null;
const interactionRecorder = predictive || trackAchievements ? useInteractionRecorder(`glass-container-${usageContext}`) : null;
// Visibility tracking for predictive preloading
useEffect(() => {
if (!containerElement || !preloadContent) return;
const observer = new IntersectionObserver(([entry]) => {
setIsVisible(entry.isIntersecting);
if (entry.isIntersecting && interactionRecorder) {
// Create synthetic scroll event
const syntheticEvent = {
currentTarget: {
id: `container-${usageContext}`
},
type: 'scroll'
};
interactionRecorder.recordFocus(syntheticEvent);
}
}, {
threshold: 0.1
});
observer.observe(containerElement);
return () => observer.disconnect();
}, [preloadContent, usageContext, interactionRecorder]);
// Biometric adaptation effects
useEffect(() => {
if (!biometricResponsive || !biometricAdapter) return;
const adaptContainer = () => {
const stressLevel = biometricAdapter.currentStressLevel;
// For now, assume desktop capabilities
const deviceCapabilities = {
isMobile: false,
isDesktop: true
};
// Adapt size based on device and stress
if (stressLevel < 0.3 && deviceCapabilities.isDesktop) {
setAdaptiveSize('md'); // Compact size when relaxed on desktop
setAdaptivePadding('sm'); // Less padding for efficiency
} else {
setAdaptiveSize(size); // Use original size
setAdaptivePadding(padding); // Use original padding
}
};
// Initial adaptation
adaptContainer();
// Listen for biometric changes
const interval = setInterval(adaptContainer, 5000);
return () => clearInterval(interval);
}, [biometricResponsive, biometricAdapter, size, padding]);
// Eye tracking effects
useEffect(() => {
if (!gazeResponsive || !eyeTracker || !containerElement) return;
// Note: Eye tracking event handlers not yet implemented
// eyeTracker.onGazeEnter(containerRef.current, handleGazeEnter);
// eyeTracker.onGazeExit(containerRef.current, handleGazeExit);
return () => {
// Note: Eye tracking cleanup not yet implemented
// if (containerRef.current) {
// eyeTracker.offGazeEnter(containerRef.current, handleGazeEnter);
// eyeTracker.offGazeExit(containerRef.current, handleGazeExit);
// }
};
}, [gazeResponsive, eyeTracker, spatialAudioEngine, audioFeedback, achievementTracker, trackAchievements, usageContext]);
// Predictive interaction tracking
const handleInteraction = useCallback(event => {
if (!interactionRecorder) return;
if (event.type === 'click') {
interactionRecorder.recordClick(event);
}
if (achievementTracker && trackAchievements) {
achievementTracker.recordAction(achievementId || 'container_interaction', {
context: usageContext,
timestamp: Date.now()
});
}
}, [interactionRecorder, achievementTracker, trackAchievements, achievementId, usageContext]);
// Filter out component-specific props and consciousness features that shouldn't be passed to DOM
const {
maxWidth,
minWidth,
maxHeight,
minHeight,
// Prevent leaking master toggle to DOM
consciousness: _consciousness,
predictive: _predictive,
preloadContent: _preloadContent,
eyeTracking: _eyeTracking,
gazeResponsive: _gazeResponsive,
adaptive: _adaptive,
biometricResponsive: _biometricResponsive,
spatialAudio: _spatialAudio,
audioFeedback: _audioFeedback,
trackAchievements: _trackAchievements,
achievementId: _achievementId,
usageContext: _usageContext,
...domProps
} = props;
// Use adaptive values if biometric adaptation is enabled, otherwise use original values
const effectiveSize = biometricResponsive ? adaptiveSize : size;
const effectivePadding = biometricResponsive ? adaptivePadding : padding;
const sizeClasses = {
xs: 'max-w-xs',
// 320px
sm: 'max-w-sm',
// 384px
md: 'max-w-md',
// 448px
lg: 'max-w-4xl',
// 896px
xl: 'max-w-6xl',
// 1152px
'2xl': 'max-w-7xl',
// 1280px
full: 'max-w-full'
};
const paddingClasses = {
none: 'glass-p-0',
xs: 'glass-p-2',
sm: 'glass-p-4',
md: 'glass-p-6',
lg: 'glass-p-8',
xl: 'glass-p-12',
'2xl': 'glass-p-16'
};
const variantClasses = {
default: '',
fluid: 'w-full',
breakout: 'w-screen relative left-1/2 right-1/2 -mx-[50vw]'
};
// Map elevation to OptimizedGlass elevation values
const getGlassElevation = elevation => {
if (elevation === 'float') return 'level3';
if (elevation === 'modal') return 'level4';
if (typeof elevation === 'number') {
const level = Math.min(5, Math.max(1, elevation + 1));
switch (level) {
case 1:
return 'level1';
case 2:
return 'level2';
case 3:
return 'level3';
case 4:
return 'level4';
case 5:
return 'level5';
default:
return 'level1';
}
}
// Handle string values that aren't the expected literals
if (typeof elevation === 'string') {
// Try to parse as number
const numValue = parseInt(elevation, 10);
if (!isNaN(numValue)) {
return getGlassElevation(numValue);
}
// Default for unrecognized strings
return 'level1';
}
return 'level1';
};
const responsivePaddingClasses = responsivePadding ? [responsivePadding.sm && `sm:${paddingClasses[responsivePadding.sm]}`, responsivePadding.md && `md:${paddingClasses[responsivePadding.md]}`, responsivePadding.lg && `lg:${paddingClasses[responsivePadding.lg]}`, responsivePadding.xl && `xl:${paddingClasses[responsivePadding.xl]}`, responsivePadding['2xl'] && `2xl:${paddingClasses[responsivePadding['2xl']]}`].filter(Boolean) : [];
if (glass) {
return material === 'liquid' ? jsx(LiquidGlassMaterial, {
ior: materialProps?.ior || (elevation === 'modal' ? 1.50 : elevation === 'float' ? 1.48 : 1.45),
thickness: materialProps?.thickness || (size === 'xs' ? 6 : size === 'sm' ? 8 : size === 'md' ? 12 : 16),
tint: materialProps?.tint || (usageContext === 'modal' ? {
r: 0,
g: 0,
b: 0,
a: 0.08
} : {
r: 0,
g: 0,
b: 0,
a: 0.05
}),
variant: materialProps?.variant || (usageContext === 'modal' ? 'regular' : 'clear'),
quality: materialProps?.quality || 'high',
environmentAdaptation: true,
motionResponsive: true,
interactive: usageContext === 'card' || usageContext === 'form',
className: cn(
// Base container styles
'w-full transition-all duration-300 liquid-glass-container-surface',
// Size and centering
sizeClasses[effectiveSize], centered && 'mx-auto',
// Variant
variantClasses[variant],
// Padding
paddingClasses[effectivePadding], ...responsivePaddingClasses,
// Radius
radius === 'none' ? 'rounded-none' : radius === 'sm' ? 'glass-radius-sm' : radius === 'md' ? 'glass-radius-md' : radius === 'lg' ? 'glass-radius-lg' : radius === 'xl' ? 'glass-radius-xl' : radius === '2xl' ? 'rounded-2xl' : radius === 'full' ? 'glass-radius-full' : 'glass-radius-lg',
// Consciousness feature styles
isVisible && preloadContent && 'animate-pulse', biometricResponsive && 'transform-gpu', className),
style: {
'--liquid-glass-container-density': usageContext === 'modal' ? '0.95' : '0.88',
'--liquid-glass-environment-adapt': '0.7'
},
"data-liquid-glass-container": "true",
"data-container-context": usageContext,
"data-container-size": effectiveSize,
onClick: handleInteraction,
onFocus: handleInteraction,
ref: node => {
const divNode = node ?? null;
setContainerElement(divNode);
if (ref) {
if (typeof ref === 'function') {
ref(divNode);
} else if ('current' in ref) {
ref.current = divNode;
}
}
},
...domProps,
children: children
}) : jsx(OptimizedGlassCore, {
intent: "neutral",
elevation: getGlassElevation(elevation),
intensity: "medium",
depth: 2,
tint: "neutral",
border: "subtle",
animation: "none",
performanceMode: "medium",
className: cn(
// Base container styles
'w-full transition-all duration-300',
// Size and centering
sizeClasses[effectiveSize], centered && 'mx-auto',
// Variant
variantClasses[variant],
// Padding
paddingClasses[effectivePadding], ...responsivePaddingClasses,
// Radius
radius === 'none' ? 'rounded-none' : radius === 'sm' ? 'glass-radius-sm' : radius === 'md' ? 'glass-radius-md' : radius === 'lg' ? 'glass-radius-lg' : radius === 'xl' ? 'glass-radius-xl' : radius === '2xl' ? 'rounded-2xl' : radius === 'full' ? 'glass-radius-full' : 'glass-radius-lg',
// Consciousness feature styles
// gazeResponsive && eyeTracker?.isGazing && 'ring-2 ring-blue-400/50 shadow-lg shadow-blue-400/25',
isVisible && preloadContent && 'animate-pulse', biometricResponsive && 'transform-gpu',
// Motion preferences - already handled by consciousness features
className),
onClick: handleInteraction,
onFocus: handleInteraction,
ref: node => {
setContainerElement(node);
if (ref) {
if (typeof ref === 'function') {
ref(node);
} else if ('current' in ref) {
ref.current = node;
}
}
},
...domProps,
children: children
});
}
return jsx("div", {
"data-glass-component": true,
className: cn(
// Base container styles
'w-full transition-all duration-300',
// Size and centering
sizeClasses[effectiveSize], centered && 'mx-auto',
// Variant
variantClasses[variant],
// Padding
paddingClasses[effectivePadding], ...responsivePaddingClasses,
// Consciousness feature styles
// gazeResponsive && eyeTracker?.isGazing && 'ring-1 ring-blue-400/30 shadow-md shadow-blue-400/10',
isVisible && preloadContent && 'animate-pulse opacity-75', biometricResponsive && 'transform-gpu',
// Motion preferences - already handled by consciousness features
className),
onClick: handleInteraction,
onFocus: handleInteraction,
ref: node => {
setContainerElement(node);
if (ref) {
if (typeof ref === 'function') {
ref(node);
} else {
ref.current = node;
}
}
},
...domProps,
children: children
});
});
GlassContainer.displayName = 'GlassContainer';
/**
* Enhanced GlassContainer with consciousness features enabled by default
* Use this for containers that should be intelligent and adaptive
*/
const ConsciousGlassContainer = /*#__PURE__*/forwardRef((props, ref) => jsx(GlassContainer, {
ref: ref,
predictive: true,
preloadContent: true,
adaptive: true,
biometricResponsive: true,
trackAchievements: true,
achievementId: "conscious_container_usage",
...props
}));
ConsciousGlassContainer.displayName = 'ConsciousGlassContainer';
export { ConsciousGlassContainer, GlassContainer };
//# sourceMappingURL=GlassContainer.js.map