aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
171 lines (168 loc) • 6.1 kB
JavaScript
'use client';
import { jsxs, jsx } from 'react/jsx-runtime';
import { useMotionPreferenceContext } from '../../contexts/MotionPreferenceContext.js';
import { createMotionAwareVariants, createMotionAwareInteractive } from '../../lib/motionPrimitives.js';
import { cn } from '../../lib/utilsComprehensive.js';
import { motion } from 'framer-motion';
import { forwardRef } from 'react';
import '../../tokens/glass.js';
/**
* Motion-aware Glass component that automatically respects user's motion preferences
* Provides beautiful glass morphism effects while being fully accessible
*/
const MotionAwareGlass = /*#__PURE__*/forwardRef(({
variant = "base",
interactive = false,
animationType = "fadeInUp",
children,
className,
asButton = false,
disabled = false,
...props
}, ref) => {
const {
prefersReducedMotion,
isMotionSafe
} = useMotionPreferenceContext();
// Get appropriate glass variant classes
const getVariantClasses = () => {
const baseClasses = "backdrop-filter border border-opacity-20 glass-radius-lg";
switch (variant) {
case "subtle":
return cn(baseClasses, "glass-subtle bg-white/5 border-white/10");
case "strong":
return cn(baseClasses, "glass-strong bg-white/10 border-white/20");
case "card":
return cn(baseClasses, "glass-foundation-complete bg-white/8 border-white/15 glass-p-6 shadow-lg");
case "button":
return cn(baseClasses, "glass-button-secondary bg-white/8 border-white/15 glass-px-6 glass-py-3 cursor-pointer");
case "input":
return cn(baseClasses, "glass-input bg-white/5 border-white/10 glass-px-4 glass-py-2");
default:
return cn(baseClasses, "glass-foundation-complete bg-white/8 border-white/15");
}
};
// Get motion variants based on animation type and motion preference
const getAnimationVariants = () => {
switch (animationType) {
case "fadeInScale":
return createMotionAwareVariants.fadeInScale(prefersReducedMotion);
case "slideLeft":
return createMotionAwareVariants.slideIn("left", prefersReducedMotion);
case "slideRight":
return createMotionAwareVariants.slideIn("right", prefersReducedMotion);
default:
return createMotionAwareVariants.fadeInUp(prefersReducedMotion);
}
};
// Get interactive variants for hover/tap effects
const getInteractiveVariants = () => {
if (!interactive || disabled) return {};
if (variant === "button" || asButton) {
return createMotionAwareInteractive.button(prefersReducedMotion);
}
if (variant === "card") {
return createMotionAwareInteractive.card(prefersReducedMotion);
}
// Default interactive behavior
if (prefersReducedMotion) {
return {
hover: {
backgroundColor: '/* Use createGlassStyle({ intent: "neutral", elevation: "level2" }) */',
borderColor: "var(--glass-bg-default)",
transition: {
duration: 0.001
}
}
};
}
return {
hover: {
backgroundColor: '/* Use createGlassStyle({ intent: "neutral", elevation: "level2" }) */',
borderColor: "var(--glass-bg-default)",
y: -2,
transition: {
duration: 0.2
}
},
tap: {
y: -1,
transition: {
duration: 0.1
}
}
};
};
const combinedClassName = cn(getVariantClasses(), {
"glass-card-motion-aware": interactive && !prefersReducedMotion,
"cursor-pointer": (interactive || asButton) && !disabled,
"cursor-not-allowed opacity-50": disabled,
"focus:outline-none focus:ring-3 focus:ring-blue-500/50": asButton || interactive,
"transition-none": prefersReducedMotion
}, className);
const animationVariants = getAnimationVariants();
const interactiveVariants = getInteractiveVariants();
// Combine all motion props
({
variants: animationVariants,
initial: "hidden",
animate: "visible",
...(interactive && interactiveVariants && typeof interactiveVariants === "object" && {
whileHover: "hover" in interactiveVariants ? "hover" : undefined,
whileTap: "tap" in interactiveVariants ? "tap" : undefined
}),
...props
});
// Add accessibility attributes for buttons
const accessibilityProps = asButton || interactive ? {
role: asButton ? "button" : undefined,
tabIndex: disabled ? -1 : 0,
"aria-disabled": disabled,
onKeyDown: e => {
if ((e.key === "Enter" || e.key === " ") && (asButton || interactive) && !disabled) {
e.preventDefault();
props?.onClick?.(e);
}
}
} : {};
return jsxs(motion.div, {
ref: ref,
className: combinedClassName,
variants: animationVariants,
initial: "hidden",
animate: "visible",
whileHover: interactive && "hover" in interactiveVariants ? "hover" : undefined,
whileTap: interactive && "tap" in interactiveVariants ? "tap" : undefined,
...props,
...accessibilityProps,
children: [children, prefersReducedMotion && jsx("span", {
className: 'sr-only',
children: "Motion reduced for accessibility"
})]
});
});
MotionAwareGlass.displayName = "MotionAwareGlass";
// Specialized variants for common use cases
const MotionAwareGlassCard = /*#__PURE__*/forwardRef((props, ref) => jsx(MotionAwareGlass, {
ref: ref,
variant: "card",
interactive: true,
...props
}));
MotionAwareGlassCard.displayName = "MotionAwareGlassCard";
const MotionAwareGlassButton = /*#__PURE__*/forwardRef((props, ref) => jsx(MotionAwareGlass, {
ref: ref,
variant: "button",
asButton: true,
interactive: true,
...props
}));
MotionAwareGlassButton.displayName = "MotionAwareGlassButton";
const MotionAwareGlassInput = /*#__PURE__*/forwardRef((props, ref) => jsx(MotionAwareGlass, {
ref: ref,
variant: "input",
...props
}));
MotionAwareGlassInput.displayName = "MotionAwareGlassInput";
export { MotionAwareGlass, MotionAwareGlassButton, MotionAwareGlassCard, MotionAwareGlassInput, MotionAwareGlass as default };
//# sourceMappingURL=MotionAwareGlass.js.map