aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
329 lines (326 loc) • 11.6 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { forwardRef, useRef, useState, useImperativeHandle, useEffect, useCallback } from 'react';
import { cn } from '../../lib/utilsComprehensive.js';
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 { useA11yId, createButtonA11y } from '../../utils/a11y.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';
// Get variant classes
const getVariantClasses = (variant, selected, color) => {
const baseClasses = "transition-all duration-200 ease-in-out";
switch (variant) {
case "primary":
return cn(baseClasses, selected ? "bg-primary-500 glass-text-primary border-primary-600 shadow-md" : "bg-transparent text-primary-400 border-primary-300 hover:bg-primary-500/10");
case "secondary":
return cn(baseClasses, selected ? "bg-secondary-500 glass-text-primary border-secondary-600 shadow-md" : "bg-transparent text-secondary-400 border-secondary-300 hover:bg-secondary-500/10");
case "outlined":
return cn(baseClasses, "border-2", selected ? `bg-${color}-500 glass-text-primary border-${color}-600` : `bg-transparent text-${color}-400 border-${color}-300 hover:bg-${color}-500/10`);
default:
return cn(baseClasses, selected ? "bg-gray-600 glass-text-primary border-gray-700 shadow-md" : "bg-transparent glass-text-secondary border-gray-500 hover:bg-gray-600/10");
}
};
// Get size classes
const getSizeClasses = size => {
switch (size) {
case "sm":
return "h-8 px-3 text-sm min-w-16";
case "lg":
return "h-12 px-6 text-base min-w-24";
case "md":
case "medium":
default:
return "h-10 px-4 text-sm min-w-20";
}
};
// Get group classes
const getGroupClasses = (grouped, groupOrientation = "horizontal", isGroupStart = false, isGroupEnd = false) => {
if (!grouped) return "";
const classes = [];
if (groupOrientation === "horizontal") {
if (!isGroupStart) classes.push("rounded-l-none border-l-0 -ml-px");
if (!isGroupEnd) classes.push("rounded-r-none");
} else {
if (!isGroupStart) classes.push("rounded-t-none border-t-0 -mt-px");
if (!isGroupEnd) classes.push("rounded-b-none");
}
return classes.join(" ");
};
/**
* ToggleButton Component Implementation
*/
function ToggleButtonComponent(props, ref) {
const {
value,
selected = false,
disabled = false,
onChange,
children,
className,
style,
glass = false,
// Prevent custom props from leaking to DOM
glassVariant,
blurStrength,
color = "default",
size = "medium",
fullWidth = false,
variant = "outlined",
// Group props
grouped = false,
groupOrientation = "horizontal",
isGroupStart = false,
isGroupEnd = false,
// Glass props
intent = "neutral",
elevation = "level2",
tier = "medium",
// Accessibility props
description,
"aria-label": ariaLabel,
"aria-labelledby": ariaLabelledBy,
"aria-describedby": ariaDescribedBy,
"aria-expanded": ariaExpanded,
"aria-controls": ariaControls,
"aria-haspopup": ariaHaspopup,
// Consciousness features
predictive = false,
preloadContent = false,
eyeTracking = false,
gazeResponsive = false,
adaptive = false,
biometricResponsive = false,
spatialAudio = false,
audioFeedback = false,
trackAchievements = false,
achievementId,
usageContext = "toggle",
...rest
} = props;
const buttonRef = useRef(null);
const [isHovered, setIsHovered] = useState(false);
const [clickCount, setClickCount] = useState(0);
// Consciousness feature hooks - only initialize if features are enabled
predictive ? usePredictiveEngine() : null;
const eyeTracker = eyeTracking ? useEyeTracking() : null;
adaptive ? useBiometricAdaptation() : null;
const spatialAudioEngine = spatialAudio ? useSpatialAudio() : null;
const achievementTracker = trackAchievements ? useAchievements() : null;
const {
recordInteraction
} = usePredictiveEngine();
const interactionRecorder = predictive || trackAchievements ? useInteractionRecorder(`glass-toggle-${variant}-${usageContext}`) : null;
// Generate unique ID for accessibility
const componentId = useA11yId("glass-toggle");
const descriptionId = description ? useA11yId("glass-toggle-desc") : undefined;
// Handle ref forwarding
useImperativeHandle(ref, () => buttonRef.current);
// Eye tracking effects
useEffect(() => {
if (!gazeResponsive || !eyeTracker || !buttonRef.current) return;
// Eye tracking methods not available in current implementation
// eyeTracker.onGazeEnter(buttonRef.current, handleGazeEnter);
// eyeTracker.onGazeExit(buttonRef.current, handleGazeExit);
return () => {
if (buttonRef.current) ;
};
}, [gazeResponsive, eyeTracker, disabled, spatialAudioEngine, audioFeedback]);
// Enhanced interaction tracking
const handleClick = useCallback(event => {
if (disabled) return;
setClickCount(prev => prev + 1);
// Record interaction for predictive learning
if (recordInteraction) {
recordInteraction({
type: "click",
element: "toggle-button",
context: {
viewport: {
width: window.innerWidth,
height: window.innerHeight
},
timeOfDay: new Date().getHours(),
deviceType: window.innerWidth < 768 ? "mobile" : window.innerWidth < 1024 ? "tablet" : "desktop"
},
metadata: {
action: "toggle-click",
selected: !selected
}
});
}
// Play spatial audio feedback
if (spatialAudioEngine && audioFeedback) {
spatialAudioEngine.playGlassSound("toggle_click", {
x: buttonRef.current?.offsetLeft || 0,
y: buttonRef.current?.offsetTop || 0,
z: 0
});
}
// Track achievements
if (achievementTracker && trackAchievements) {
achievementTracker.recordAction(achievementId || "toggle_interaction", {
variant,
context: usageContext,
selected: !selected,
clickCount,
timestamp: Date.now()
});
}
// Call original onChange handler
if (onChange && value !== undefined) {
onChange(event, value);
}
}, [disabled, interactionRecorder, spatialAudioEngine, audioFeedback, achievementTracker, trackAchievements, achievementId, variant, usageContext, selected, clickCount, onChange, value]);
// Create accessibility attributes
const a11yProps = createButtonA11y({
id: componentId,
label: ariaLabel,
description,
pressed: selected,
expanded: typeof ariaExpanded === "boolean" ? ariaExpanded : ariaExpanded === "true" ? true : ariaExpanded === "false" ? false : undefined,
controls: ariaControls,
haspopup: ariaHaspopup === "false" ? false : ariaHaspopup === "true" ? true : ariaHaspopup,
disabled: disabled,
descriptionId
});
const variantClasses = getVariantClasses(variant, selected, color);
const sizeClasses = getSizeClasses(size);
const groupClasses = getGroupClasses(grouped, groupOrientation, isGroupStart, isGroupEnd);
const baseClasses = cn(
// Base styles
"inline-flex items-center justify-center relative", "box-border outline-none border-0 m-0", "select-none align-middle appearance-none no-underline", "font-medium leading-7", "glass-radius-md border",
// Size classes
sizeClasses,
// Variant classes
variantClasses,
// Group classes
groupClasses,
// Full width
fullWidth && "w-full",
// Disabled state
disabled && "cursor-default pointer-events-none opacity-50", !disabled && "cursor-pointer glass-focus glass-touch-target",
// Consciousness feature styles
gazeResponsive && isHovered /* || (eyeTracker?.isGazing && !disabled) */ && "ring-2 ring-blue-400/40", className);
const combinedStyle = {
...style
};
if (glass) {
return jsx(MotionFramer, {
"data-glass-component": true,
preset: "scaleIn",
animateOnHover: true,
duration: 0.2,
className: 'inline-block',
children: jsxs(OptimizedGlassCore, {
ref: node => {
if (ref) {
if (typeof ref === "function") {
ref(node);
} else {
ref.current = node;
}
}
if (buttonRef.current !== undefined) {
buttonRef.current = node;
}
},
as: "button",
intent: intent,
elevation: elevation,
tier: tier,
variant: "frosted",
intensity: "medium",
border: "subtle",
interactive: true,
hoverSheen: true,
liftOnHover: true,
press: true,
className: baseClasses,
style: combinedStyle,
type: "button",
disabled: disabled,
onClick: handleClick,
onMouseEnter: () => setIsHovered(true),
onMouseLeave: () => setIsHovered(false),
...a11yProps,
...rest,
children: [jsx("span", {
className: 'relative z-10',
children: children
}), description && jsx("span", {
id: descriptionId,
className: 'sr-only',
children: description
})]
})
});
}
return jsx(MotionFramer, {
preset: "scaleIn",
animateOnHover: true,
duration: 0.2,
className: 'inline-block',
children: jsxs("button", {
ref: node => {
if (ref) {
if (typeof ref === "function") {
ref(node);
} else {
ref.current = node;
}
}
if (buttonRef.current !== undefined) {
buttonRef.current = node;
}
},
className: baseClasses,
style: combinedStyle,
type: "button",
disabled: disabled,
onClick: handleClick,
onMouseEnter: () => setIsHovered(true),
onMouseLeave: () => setIsHovered(false),
...a11yProps,
...rest,
children: [children, description && jsx("span", {
id: descriptionId,
className: 'sr-only',
children: description
})]
})
});
}
/**
* ToggleButton Component
*
* A button that can be toggled on/off, with glass morphism styling.
*/
const ToggleButton = /*#__PURE__*/forwardRef(ToggleButtonComponent);
/**
* GlassToggleButton Component
*
* Glass variant of the ToggleButton component.
*/
const GlassToggleButton = /*#__PURE__*/forwardRef((props, ref) => {
// Convert Booleanish aria-expanded to boolean
const processedProps = {
...props,
"aria-expanded": typeof props["aria-expanded"] === "boolean" ? props["aria-expanded"] : props["aria-expanded"] === "true" ? true : props["aria-expanded"] === "false" ? false : props["aria-expanded"]
};
return jsx(ToggleButton, {
...processedProps,
glass: true,
ref: ref
});
});
GlassToggleButton.displayName = "GlassToggleButton";
export { GlassToggleButton, ToggleButton, ToggleButton as default };
//# sourceMappingURL=ToggleButton.js.map