aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
121 lines (118 loc) • 4.34 kB
JavaScript
'use client';
import React, { forwardRef } from 'react';
import { cn } from '../../design-system/utilsCore.js';
import { useReducedMotion } from '../../hooks/useReducedMotion.js';
/**
* Advanced Glass Primitive Component
* Token-first glassmorphism with full a11y support
*/
const GlassAdvanced = /*#__PURE__*/forwardRef(({
as: Component = 'div',
elev = 2,
variant = 'default',
radius = 'lg',
blur = 'lg',
motion = 'none',
interactive = false,
contrast = 'auto',
disabled = false,
noise = false,
specular = false,
edge = false,
glow = 'none',
className,
children,
onKeyDown,
onClick,
role,
tabIndex,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
'aria-describedby': ariaDescribedBy,
...props
}, ref) => {
// MOTION_RESPECT: Check for reduced motion preference
const prefersReducedMotion = useReducedMotion();
// Handle keyboard accessibility for interactive elements
const isClickable = !!onClick && !disabled;
const computedRole = role || (isClickable && Component === 'div' ? 'button' : undefined);
const computedTabIndex = tabIndex ?? (isClickable || interactive ? 0 : undefined);
const handleKeyDown = e => {
// Call custom handler first
onKeyDown?.(e);
// Handle space/enter for clickable divs
if (isClickable && Component === 'div' && (e.key === 'Enter' || e.key === ' ')) {
e.preventDefault();
onClick?.(e);
}
};
// Token validation in development
if (process.env.NODE_ENV === 'development') {
const validElevations = [0, 1, 2, 3, 4, 5, 6];
const validRadii = ['none', 'sm', 'md', 'lg', 'xl', '2xl', 'full'];
const validBlurs = ['none', 'sm', 'md', 'lg', 'xl'];
const validMotions = ['none', 'float', 'shimmer', 'ambient', 'press'];
if (!validElevations.includes(elev)) {
console.warn(`GlassAdvanced: Invalid elevation "${elev}". Use 0-6.`);
}
if (!validRadii.includes(radius)) {
console.warn(`GlassAdvanced: Invalid radius "${radius}". Use ${validRadii.join(', ')}.`);
}
if (!validBlurs.includes(blur)) {
console.warn(`GlassAdvanced: Invalid blur "${blur}". Use ${validBlurs.join(', ')}.`);
}
if (!validMotions.includes(motion)) {
console.warn(`GlassAdvanced: Invalid motion "${motion}". Use ${validMotions.join(', ')}.`);
}
}
// Build class names using tokens
const classes = cn(
// Base glass foundation
'glass-foundation-complete',
// Elevation
elev > 0 && `glass-elev-${elev}`,
// Radius
`glass-radius-${radius}`,
// CLASS_PREFIX: Blur classes use 'glass-' prefix
blur !== 'lg' && `glass-blur-${blur}`,
// Variant surfaces
variant !== 'default' && `glass-surface-${variant}`,
// MOTION_RESPECT: Respect reduced motion preference for animations
motion !== 'none' && !prefersReducedMotion && `glass-animate-${motion}`,
// Interactive states
interactive && 'glass-state-hoverable glass-state-active',
// CONTRAST_GUARD: Glass elements need contrast guard class
contrast === 'auto' && 'glass-contrast-guard',
// Disabled state
disabled && 'glass-state-disabled',
// Overlay effects
noise && 'glass-overlay-noise', specular && 'glass-overlay-specular', edge && 'glass-edge',
// Glow effects
glow !== 'none' && `glass-glow${glow !== 'default' ? `-${glow}` : ''}`,
// INTERACTIVE_FOCUS: Interactive elements with onClick need glass-focus class
(isClickable || interactive) && 'glass-focus',
// Custom classes
className);
// TOUCH_TARGET: Ensure minimum touch target for interactive elements
const touchTargetClasses = isClickable || interactive ? 'glass-touch-target' : '';
return /*#__PURE__*/React.createElement(Component, {
ref,
className: cn(classes, touchTargetClasses),
role: computedRole,
tabIndex: computedTabIndex,
'aria-disabled': disabled || undefined,
'aria-label': ariaLabel,
'aria-labelledby': ariaLabelledBy,
'aria-describedby': ariaDescribedBy,
onClick: disabled ? undefined : onClick,
onKeyDown: handleKeyDown,
...props
}, /*#__PURE__*/React.createElement('div', {
className: 'glass-layer-frost'
}), /*#__PURE__*/React.createElement('div', {
className: 'glass-layer-ink'
}, children));
});
GlassAdvanced.displayName = 'GlassAdvanced';
export { GlassAdvanced };
//# sourceMappingURL=GlassAdvanced.js.map