ui-aesthetic-utils
Version:
A lightweight utility library for modern UI aesthetics including glassmorphism, neumorphism, glow effects, and soft shadows
1,354 lines (1,346 loc) • 50.4 kB
JavaScript
/**
* Default glass configuration
*/
const defaultGlassConfig = {
blur: {
sm: '8px',
md: '15px',
lg: '25px',
xl: '40px'
}};
/**
* Resolves blur size to pixel value
*/
function resolveBlurSize(blur, config) {
if (typeof blur === 'string' && blur.endsWith('px')) {
return blur;
}
const blurConfig = config?.blur || defaultGlassConfig.blur;
switch (blur) {
case 'sm':
return blurConfig.sm;
case 'md':
return blurConfig.md;
case 'lg':
return blurConfig.lg;
case 'xl':
return blurConfig.xl;
default:
return typeof blur === 'string' ? blur : blurConfig.md;
}
}
/**
* Generates glassmorphism CSS properties
*/
function generateGlassStyles(options = {}) {
const { blur = 'md', opacity = 0.6, background, border, borderRadius = '12px' } = options;
const blurValue = resolveBlurSize(blur);
const finalBackground = background || `rgba(255, 255, 255, ${opacity})`;
const finalBorder = border || `1px solid rgba(255, 255, 255, ${Math.min(opacity + 0.1, 1)})`;
return {
backdropFilter: `blur(${blurValue})`,
WebkitBackdropFilter: `blur(${blurValue})`, // Safari support
background: finalBackground,
border: finalBorder,
borderRadius,
position: 'relative',
overflow: 'hidden'
};
}
/**
* Generates glass CSS class name based on options
*/
function generateGlassClassName(options = {}) {
const { blur = 'md', opacity } = options;
let className = `glass-${blur}`;
if (opacity && opacity !== 0.6) {
const opacityPercent = Math.round(opacity * 100);
className += `-opacity-${opacityPercent}`;
}
return className;
}
/**
* Creates CSS variables for glass configuration
*/
function createGlassCSSVariables(config) {
return {
'--glass-blur-sm': config.blur.sm,
'--glass-blur-md': config.blur.md,
'--glass-blur-lg': config.blur.lg,
'--glass-blur-xl': config.blur.xl,
'--glass-background-light': config.glassmorphic.variants.light,
'--glass-background-dark': config.glassmorphic.variants.dark,
'--glass-background-primary': config.glassmorphic.variants.primary,
'--glass-background-secondary': config.glassmorphic.variants.secondary,
'--glass-border-opacity': config.glassmorphic.borderOpacity.toString(),
'--glass-backdrop-blur': config.glassmorphic.backdropBlur
};
}
/**
* Validates glass style options
*/
function validateGlassOptions(options) {
const errors = [];
if (options.opacity && (options.opacity < 0 || options.opacity > 1)) {
errors.push('Opacity must be between 0 and 1');
}
if (options.blur && typeof options.blur === 'string' &&
!['sm', 'md', 'lg', 'xl'].includes(options.blur) &&
!options.blur.endsWith('px')) {
errors.push('Blur must be a valid size (sm, md, lg, xl) or a pixel value');
}
return {
isValid: errors.length === 0,
errors
};
}
/**
* Creates responsive glass styles for different breakpoints
*/
function createResponsiveGlassStyles(breakpoints) {
const responsiveStyles = {};
Object.entries(breakpoints).forEach(([breakpoint, options]) => {
responsiveStyles[breakpoint] = generateGlassStyles(options);
});
return responsiveStyles;
}
/**
* Merges glass styles with custom styles
*/
function mergeGlassStyles(glassOptions, customStyles = {}) {
const glassStyles = generateGlassStyles(glassOptions);
return {
...glassStyles,
...customStyles
};
}
/**
* Creates glass effect with animation
*/
function createAnimatedGlassStyles(options) {
const baseStyles = generateGlassStyles(options);
const { animation } = options;
if (!animation)
return baseStyles;
return {
...baseStyles,
transition: `${animation.property || 'all'} ${animation.duration || '0.3s'} ${animation.easing || 'ease-in-out'}`
};
}
/**
* Default neumorphic configuration
*/
const defaultNeumorphicConfig = {
baseColor: '#e0e5ec',
lightSource: '145deg',
darkShadow: 'rgba(163, 177, 198, 0.6)',
lightShadow: 'rgba(255, 255, 255, 0.8)',
depth: {
sm: '2px 2px 4px',
md: '4px 4px 8px',
lg: '8px 8px 16px',
xl: '12px 12px 24px'
}
};
/**
* Resolves depth size to shadow values
*/
function resolveNeumorphicDepth(depth, config) {
const depthConfig = config?.neumorphic.depth || defaultNeumorphicConfig.depth;
switch (depth) {
case 'sm':
return depthConfig.sm;
case 'md':
return depthConfig.md;
case 'lg':
return depthConfig.lg;
case 'xl':
return depthConfig.xl;
default:
return depthConfig.md;
}
}
/**
* Generates neumorphic shadow based on shape and depth
*/
function generateNeumorphicShadow(shape, depth, config) {
const neuroConfig = config?.neumorphic || defaultNeumorphicConfig;
const depthValue = resolveNeumorphicDepth(depth, config);
const [x, y, blur] = depthValue.split(' ');
const darkShadow = `${x} ${y} ${blur} ${neuroConfig.darkShadow}`;
const lightShadow = `${x.replace('-', '')} ${y.replace('-', '')} ${blur} ${neuroConfig.lightShadow}`;
switch (shape) {
case 'flat':
return `${darkShadow}, -${lightShadow}`;
case 'concave':
return `inset ${darkShadow}, inset -${lightShadow}`;
case 'convex':
return `${darkShadow}, -${lightShadow}, inset 1px 1px 2px ${neuroConfig.lightShadow}`;
default:
return `${darkShadow}, -${lightShadow}`;
}
}
/**
* Generates neumorphism CSS properties
*/
function generateNeumorphicStyles(options = {}) {
const { depth = 'md', shape = 'flat', baseColor, borderRadius = '12px' } = options;
const config = {
neumorphic: {
...defaultNeumorphicConfig,
...(baseColor && { baseColor })
}
};
const boxShadow = generateNeumorphicShadow(shape, depth, config);
const background = baseColor || defaultNeumorphicConfig.baseColor;
return {
background,
borderRadius,
boxShadow,
border: 'none',
position: 'relative',
cursor: shape === 'flat' ? 'pointer' : 'default'
};
}
/**
* Generates neumorphic CSS class name based on options
*/
function generateNeumorphicClassName(options = {}) {
const { depth = 'md', shape = 'flat' } = options;
return `neuro-${shape}-${depth}`;
}
/**
* Creates CSS variables for neumorphic configuration
*/
function createNeumorphicCSSVariables(config) {
return {
'--neuro-base-color': config.neumorphic.baseColor,
'--neuro-light-source': config.neumorphic.lightSource,
'--neuro-dark-shadow': config.neumorphic.darkShadow,
'--neuro-light-shadow': config.neumorphic.lightShadow,
'--neuro-depth-sm': config.neumorphic.depth.sm,
'--neuro-depth-md': config.neumorphic.depth.md,
'--neuro-depth-lg': config.neumorphic.depth.lg,
'--neuro-depth-xl': config.neumorphic.depth.xl
};
}
/**
* Creates neumorphic button states (normal, hover, active)
*/
function createNeumorphicButtonStates(options) {
const baseStyles = generateNeumorphicStyles(options);
const { depth = 'md', shape = 'flat' } = options;
// Create hover state with slightly reduced depth
const hoverDepth = depth === 'sm' ? 'sm' :
depth === 'md' ? 'sm' :
depth === 'lg' ? 'md' : 'lg';
const hoverStyles = generateNeumorphicStyles({
...options,
depth: hoverDepth
});
// Create active state (pressed/inset effect)
const activeStyles = generateNeumorphicStyles({
...options,
shape: 'concave',
depth: 'sm'
});
return {
normal: baseStyles,
hover: {
...hoverStyles,
transform: 'translateY(-1px)'
},
active: {
...activeStyles,
transform: 'translateY(1px)'
}
};
}
/**
* Validates neumorphic style options
*/
function validateNeumorphicOptions(options) {
const errors = [];
if (options.shape && !['flat', 'concave', 'convex'].includes(options.shape)) {
errors.push('Shape must be one of: flat, concave, convex');
}
if (options.depth && !['sm', 'md', 'lg', 'xl'].includes(options.depth)) {
errors.push('Depth must be one of: sm, md, lg, xl');
}
if (options.baseColor && !isValidColor(options.baseColor)) {
errors.push('Base color must be a valid CSS color value');
}
return {
isValid: errors.length === 0,
errors
};
}
/**
* Utility function to validate CSS color values
*/
function isValidColor(color) {
const colorRegex = /^(#[0-9A-F]{6}|#[0-9A-F]{3}|rgb\(|rgba\(|hsl\(|hsla\()/i;
return colorRegex.test(color) || CSS.supports('color', color);
}
/**
* Creates adaptive neumorphic styles based on background color
*/
function createAdaptiveNeumorphicStyles(backgroundColor, options) {
// Convert background color to determine if it's light or dark
isLightColor(backgroundColor);
// Adjust shadow colors based on background
const adaptedConfig = {
...options,
baseColor: backgroundColor
};
return generateNeumorphicStyles(adaptedConfig);
}
/**
* Utility function to determine if a color is light or dark
*/
function isLightColor(color) {
// Simple implementation - can be enhanced with proper color parsing
const hex = color.replace('#', '');
const r = parseInt(hex.substr(0, 2), 16);
const g = parseInt(hex.substr(2, 2), 16);
const b = parseInt(hex.substr(4, 2), 16);
const brightness = ((r * 299) + (g * 587) + (b * 114)) / 1000;
return brightness > 155;
}
/**
* Creates neumorphic input field styles
*/
function createNeumorphicInputStyles(options) {
const baseStyles = generateNeumorphicStyles({
...options,
shape: options.focused ? 'concave' : 'flat'
});
return {
...baseStyles,
padding: '12px 16px',
border: 'none',
outline: 'none',
fontSize: '14px',
fontFamily: 'inherit',
color: 'inherit',
backgroundColor: 'transparent',
transition: 'box-shadow 0.3s ease'
};
}
/**
* Default glow configuration
*/
const defaultGlowConfig = {
primary: '#3b82f6'};
/**
* Resolves glow intensity to blur and opacity values
*/
function resolveGlowIntensity(intensity) {
switch (intensity) {
case 'subtle':
return { blur: 10, opacity: 0.3, spread: 0 };
case 'medium':
return { blur: 20, opacity: 0.5, spread: 0 };
case 'strong':
return { blur: 30, opacity: 0.7, spread: 2 };
case 'neon':
return { blur: 40, opacity: 0.9, spread: 4 };
default:
return { blur: 20, opacity: 0.5, spread: 0 };
}
}
/**
* Converts color to rgba format with opacity
*/
function colorToRgba(color, opacity) {
// Handle hex colors
if (color.startsWith('#')) {
const hex = color.replace('#', '');
const r = parseInt(hex.substr(0, 2), 16);
const g = parseInt(hex.substr(2, 2), 16);
const b = parseInt(hex.substr(4, 2), 16);
return `rgba(${r}, ${g}, ${b}, ${opacity})`;
}
// Handle rgb/rgba colors
if (color.startsWith('rgb')) {
const match = color.match(/\d+/g);
if (match && match.length >= 3) {
return `rgba(${match[0]}, ${match[1]}, ${match[2]}, ${opacity})`;
}
}
// Handle named colors (basic support)
const namedColors = {
red: '255, 0, 0',
green: '0, 255, 0',
blue: '0, 0, 255',
white: '255, 255, 255',
black: '0, 0, 0'
};
if (namedColors[color.toLowerCase()]) {
return `rgba(${namedColors[color.toLowerCase()]}, ${opacity})`;
}
// Fallback - return as is (might not work for all cases)
return color;
}
/**
* Generates glow CSS properties
*/
function generateGlowStyles(options = {}) {
const { color = defaultGlowConfig.primary, intensity = 'medium', spread, blur, inset = false } = options;
const resolvedIntensity = resolveGlowIntensity(intensity);
const finalBlur = blur ?? resolvedIntensity.blur;
const finalSpread = spread ?? resolvedIntensity.spread;
const glowColor = colorToRgba(color, resolvedIntensity.opacity);
const shadowPrefix = inset ? 'inset ' : '';
const boxShadow = `${shadowPrefix}0 0 ${finalBlur}px ${finalSpread}px ${glowColor}`;
return {
boxShadow,
transition: 'box-shadow 0.3s ease-in-out'
};
}
/**
* Generates glow CSS class name based on options
*/
function generateGlowClassName(options = {}) {
const { intensity = 'medium', color } = options;
let className = `glow-${intensity}`;
if (color) {
// Convert color to a class-safe name
const colorName = getColorName(color);
if (colorName) {
className += `-${colorName}`;
}
}
return className;
}
/**
* Gets a safe class name from a color value
*/
function getColorName(color) {
const colorMap = {
'#3b82f6': 'blue',
'#8b5cf6': 'purple',
'#f59e0b': 'amber',
'#00ff88': 'neon',
'#ef4444': 'red',
'#22c55e': 'green',
'#06b6d4': 'cyan',
'#f97316': 'orange'
};
return colorMap[color.toLowerCase()] || null;
}
/**
* Creates CSS variables for glow configuration
*/
function createGlowCSSVariables(config) {
return {
'--glow-primary': config.glow.primary,
'--glow-secondary': config.glow.secondary,
'--glow-accent': config.glow.accent,
'--glow-neon': config.glow.neon,
'--glow-subtle': config.glow.subtle,
'--glow-medium': config.glow.medium,
'--glow-strong': config.glow.strong
};
}
/**
* Creates animated glow effect with pulsing
*/
function createAnimatedGlowStyles(options) {
const baseStyles = generateGlowStyles(options);
const { animation } = options;
if (!animation)
return baseStyles;
const duration = animation.duration || '2s';
const pulseIntensity = animation.pulseIntensity || 1.5;
// Create stronger glow for animation peak
generateGlowStyles({
...options,
blur: (options.blur || 20) * pulseIntensity,
spread: (options.spread || 0) * pulseIntensity
});
return {
...baseStyles,
animation: `glowPulse ${duration} ease-in-out infinite alternate`,
// CSS keyframes would need to be injected separately
};
}
/**
* Creates multi-layered glow effect
*/
function createLayeredGlowStyles(layers) {
const shadows = layers.map(layer => {
const styles = generateGlowStyles(layer);
return styles.boxShadow;
}).join(', ');
return {
boxShadow: shadows,
transition: 'box-shadow 0.3s ease-in-out'
};
}
/**
* Creates glow hover effect
*/
function createGlowHoverStyles(normalOptions, hoverOptions) {
const normal = generateGlowStyles(normalOptions);
const hoverConfig = {
...normalOptions,
...hoverOptions,
intensity: hoverOptions?.intensity || 'strong'
};
const hover = generateGlowStyles(hoverConfig);
return { normal, hover };
}
/**
* Creates text glow effect
*/
function createTextGlowStyles(options = {}) {
const { color = defaultGlowConfig.primary, intensity = 'medium' } = options;
const resolvedIntensity = resolveGlowIntensity(intensity);
const glowColor = colorToRgba(color, resolvedIntensity.opacity);
return {
textShadow: `0 0 ${resolvedIntensity.blur}px ${glowColor}`,
color: color,
transition: 'text-shadow 0.3s ease-in-out'
};
}
/**
* Creates neon glow effect with inner glow
*/
function createNeonGlowStyles(color, intensity = 'neon') {
const outerGlow = generateGlowStyles({ color, intensity });
const innerGlow = generateGlowStyles({
color,
intensity: 'subtle',
inset: true,
blur: 5,
spread: 1
});
return {
boxShadow: `${outerGlow.boxShadow}, ${innerGlow.boxShadow}`,
border: `1px solid ${colorToRgba(color, 0.5)}`,
transition: 'box-shadow 0.3s ease-in-out'
};
}
/**
* Validates glow style options
*/
function validateGlowOptions(options) {
const errors = [];
if (options.intensity && !['subtle', 'medium', 'strong', 'neon'].includes(options.intensity)) {
errors.push('Intensity must be one of: subtle, medium, strong, neon');
}
if (options.blur && (options.blur < 0 || options.blur > 100)) {
errors.push('Blur must be between 0 and 100 pixels');
}
if (options.spread && (options.spread < 0 || options.spread > 20)) {
errors.push('Spread must be between 0 and 20 pixels');
}
return {
isValid: errors.length === 0,
errors
};
}
/**
* Default shadow configuration
*/
const defaultShadowConfig = {
elevation: {
sm: '0 1px 3px rgba(0, 0, 0, 0.1)',
md: '0 4px 12px rgba(0, 0, 0, 0.15)',
lg: '0 8px 24px rgba(0, 0, 0, 0.2)',
xl: '0 16px 48px rgba(0, 0, 0, 0.25)',
xxl: '0 32px 64px rgba(0, 0, 0, 0.3)'
}};
/**
* Resolves shadow size to shadow values
*/
function resolveShadowSize(size, config) {
const shadowConfig = config?.shadow.elevation || defaultShadowConfig.elevation;
switch (size) {
case 'sm':
return shadowConfig.sm;
case 'md':
return shadowConfig.md;
case 'lg':
return shadowConfig.lg;
case 'xl':
return shadowConfig.xl;
case 'xxl':
return shadowConfig.xxl;
default:
return shadowConfig.md;
}
}
/**
* Adjusts shadow opacity based on softness
*/
function adjustShadowSoftness(shadowValue, softness) {
const softnessMultiplier = {
soft: 0.7,
medium: 1.0,
hard: 1.3
};
const multiplier = softnessMultiplier[softness] || 1.0;
// Extract rgba opacity and adjust it
return shadowValue.replace(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/g, (match, r, g, b, a) => {
const newOpacity = Math.min(parseFloat(a) * multiplier, 1);
return `rgba(${r}, ${g}, ${b}, ${newOpacity})`;
});
}
/**
* Generates directional shadow based on direction
*/
function generateDirectionalShadow(baseShadow, direction) {
// Parse shadow values (assumes format: "x y blur spread color")
const shadowParts = baseShadow.split(' ');
if (shadowParts.length < 3)
return baseShadow;
const [x, y, blur, ...rest] = shadowParts;
const spread = rest.length > 1 ? rest[0] : '0';
const color = rest.length > 1 ? rest.slice(1).join(' ') : rest[0];
let newX = x;
let newY = y;
switch (direction) {
case 'top':
newY = `-${Math.abs(parseInt(y))}px`;
newX = '0';
break;
case 'bottom':
newY = `${Math.abs(parseInt(y))}px`;
newX = '0';
break;
case 'left':
newX = `-${Math.abs(parseInt(x))}px`;
newY = '0';
break;
case 'right':
newX = `${Math.abs(parseInt(x))}px`;
newY = '0';
break;
case 'center':
newX = '0';
newY = '0';
break;
}
return `${newX} ${newY} ${blur} ${spread !== '0' ? spread + ' ' : ''}${color}`;
}
/**
* Generates shadow CSS properties
*/
function generateShadowStyles(options = {}) {
const { elevation = 'md', softness = 'soft', direction = 'center', color } = options;
let shadowValue = resolveShadowSize(elevation);
// Adjust softness
shadowValue = adjustShadowSoftness(shadowValue, softness);
// Apply custom color if provided
if (color) {
shadowValue = shadowValue.replace(/rgba\(\d+,\s*\d+,\s*\d+,\s*[\d.]+\)/g, color);
}
// Apply direction
shadowValue = generateDirectionalShadow(shadowValue, direction);
return {
boxShadow: shadowValue,
transition: 'box-shadow 0.3s ease'
};
}
/**
* Generates shadow CSS class name based on options
*/
function generateShadowClassName(options = {}) {
const { elevation = 'md', softness = 'soft', direction = 'center' } = options;
let className = `shadow-${elevation}-${softness}`;
if (direction !== 'center') {
className += `-${direction}`;
}
return className;
}
/**
* Creates CSS variables for shadow configuration
*/
function createShadowCSSVariables(config) {
return {
'--shadow-sm': config.shadow.elevation.sm,
'--shadow-md': config.shadow.elevation.md,
'--shadow-lg': config.shadow.elevation.lg,
'--shadow-xl': config.shadow.elevation.xl,
'--shadow-xxl': config.shadow.elevation.xxl,
'--shadow-soft': config.shadow.soft,
'--shadow-medium': config.shadow.medium,
'--shadow-hard': config.shadow.hard
};
}
/**
* Creates layered shadow effect
*/
function createLayeredShadowStyles(layers) {
const shadows = layers.map(layer => {
const styles = generateShadowStyles(layer);
return styles.boxShadow;
}).join(', ');
return {
boxShadow: shadows,
transition: 'box-shadow 0.3s ease'
};
}
/**
* Creates hover shadow effect with elevation change
*/
function createHoverShadowStyles(normalOptions, hoverElevationIncrease = 1) {
const normal = generateShadowStyles(normalOptions);
// Increase elevation for hover
const elevationMap = {
sm: 'md',
md: 'lg',
lg: 'xl',
xl: 'xxl',
xxl: 'xxl'
};
const currentElevation = normalOptions.elevation || 'md';
const hoverElevation = elevationMap[currentElevation] || currentElevation;
const hover = generateShadowStyles({
...normalOptions,
elevation: hoverElevation
});
return { normal, hover };
}
/**
* Creates animated shadow with floating effect
*/
function createFloatingShadowStyles(options) {
const baseStyles = generateShadowStyles(options);
const { floatHeight = '4px', animationDuration = '3s' } = options;
return {
...baseStyles,
animation: `float ${animationDuration} ease-in-out infinite`,
// Transform would be handled by keyframes
'--float-height': floatHeight
};
}
/**
* Creates card-style shadow with multiple layers
*/
function createCardShadowStyles(elevation = 'md', interactive = false) {
const baseShadow = generateShadowStyles({ elevation, softness: 'soft' });
if (!interactive) {
return baseShadow;
}
// Add subtle ambient shadow for interactive cards
const ambientShadow = generateShadowStyles({
elevation: 'sm',
softness: 'soft',
color: 'rgba(0, 0, 0, 0.05)'
});
return {
boxShadow: `${baseShadow.boxShadow}, ${ambientShadow.boxShadow}`,
transition: 'box-shadow 0.3s ease, transform 0.3s ease'
};
}
/**
* Creates inset shadow effect
*/
function createInsetShadowStyles(options = {}) {
const shadowStyles = generateShadowStyles(options);
const insetShadow = `inset ${shadowStyles.boxShadow}`;
return {
boxShadow: insetShadow,
transition: 'box-shadow 0.3s ease'
};
}
/**
* Validates shadow style options
*/
function validateShadowOptions(options) {
const errors = [];
if (options.elevation && !['sm', 'md', 'lg', 'xl', 'xxl'].includes(options.elevation)) {
errors.push('Elevation must be one of: sm, md, lg, xl, xxl');
}
if (options.softness && !['soft', 'medium', 'hard'].includes(options.softness)) {
errors.push('Softness must be one of: soft, medium, hard');
}
if (options.direction && !['top', 'bottom', 'left', 'right', 'center'].includes(options.direction)) {
errors.push('Direction must be one of: top, bottom, left, right, center');
}
return {
isValid: errors.length === 0,
errors
};
}
/**
* Creates responsive shadow styles
*/
function createResponsiveShadowStyles(breakpoints) {
const responsiveStyles = {};
Object.entries(breakpoints).forEach(([breakpoint, options]) => {
responsiveStyles[breakpoint] = generateShadowStyles(options);
});
return responsiveStyles;
}
/**
* Default configuration loader
*/
let defaultConfig = null;
/**
* Loads the default configuration
*/
function loadDefaultConfig() {
if (defaultConfig) {
return defaultConfig;
}
try {
// Try to load from aesthetic.config.js
defaultConfig = require('../../aesthetic.config.js');
}
catch (error) {
// Fallback to built-in default configuration
defaultConfig = {
blur: {
sm: "8px",
md: "15px",
lg: "25px",
xl: "40px",
default: "15px",
heavy: "50px"
},
shadow: {
soft: "0 4px 12px rgba(0, 0, 0, 0.1)",
medium: "0 8px 24px rgba(0, 0, 0, 0.15)",
hard: "0 12px 36px rgba(0, 0, 0, 0.25)",
elevation: {
sm: "0 1px 3px rgba(0, 0, 0, 0.1)",
md: "0 4px 12px rgba(0, 0, 0, 0.15)",
lg: "0 8px 24px rgba(0, 0, 0, 0.2)",
xl: "0 16px 48px rgba(0, 0, 0, 0.25)",
xxl: "0 32px 64px rgba(0, 0, 0, 0.3)"
}
},
glow: {
primary: "0 0 15px #3b82f6",
secondary: "0 0 15px #8b5cf6",
accent: "0 0 15px #f59e0b",
neon: "0 0 25px #00ff88",
subtle: "0 0 10px rgba(59, 130, 246, 0.3)",
medium: "0 0 20px rgba(59, 130, 246, 0.5)",
strong: "0 0 30px rgba(59, 130, 246, 0.7)"
},
neumorphic: {
baseColor: "#e0e5ec",
lightSource: "145deg",
darkShadow: "rgba(163, 177, 198, 0.6)",
lightShadow: "rgba(255, 255, 255, 0.8)",
depth: {
sm: "2px 2px 4px",
md: "4px 4px 8px",
lg: "8px 8px 16px",
xl: "12px 12px 24px"
}
},
glassmorphic: {
background: "rgba(255, 255, 255, 0.1)",
borderOpacity: 0.2,
backdropBlur: "15px",
variants: {
light: "rgba(255, 255, 255, 0.1)",
dark: "rgba(0, 0, 0, 0.1)",
primary: "rgba(59, 130, 246, 0.1)",
secondary: "rgba(139, 92, 246, 0.1)"
}
},
borderRadius: {
sm: "4px",
md: "8px",
lg: "12px",
xl: "16px",
full: "9999px"
},
colors: {
primary: {
50: "#eff6ff",
500: "#3b82f6",
600: "#2563eb",
900: "#1e3a8a"
},
secondary: {
50: "#f5f3ff",
500: "#8b5cf6",
600: "#7c3aed",
900: "#581c87"
},
accent: {
50: "#fffbeb",
500: "#f59e0b",
600: "#d97706",
900: "#92400e"
}
}
};
}
return defaultConfig;
}
/**
* Configuration manager class
*/
class AestheticConfigManager {
constructor(customConfig) {
this.cssVariablesApplied = false;
this.config = this.mergeConfig(customConfig);
}
/**
* Merges custom configuration with defaults
*/
mergeConfig(customConfig) {
const defaultConfig = loadDefaultConfig();
if (!customConfig) {
return { ...defaultConfig };
}
return {
blur: { ...defaultConfig.blur, ...customConfig.blur },
shadow: {
...defaultConfig.shadow,
...customConfig.shadow,
elevation: {
...defaultConfig.shadow.elevation,
...customConfig.shadow?.elevation
}
},
glow: { ...defaultConfig.glow, ...customConfig.glow },
neumorphic: {
...defaultConfig.neumorphic,
...customConfig.neumorphic,
depth: {
...defaultConfig.neumorphic.depth,
...customConfig.neumorphic?.depth
}
},
glassmorphic: {
...defaultConfig.glassmorphic,
...customConfig.glassmorphic,
variants: {
...defaultConfig.glassmorphic.variants,
...customConfig.glassmorphic?.variants
}
},
borderRadius: { ...defaultConfig.borderRadius, ...customConfig.borderRadius },
colors: {
...defaultConfig.colors,
...customConfig.colors,
primary: { ...defaultConfig.colors.primary, ...customConfig.colors?.primary },
secondary: { ...defaultConfig.colors.secondary, ...customConfig.colors?.secondary },
accent: { ...defaultConfig.colors.accent, ...customConfig.colors?.accent }
}
};
}
/**
* Gets the current configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Updates the configuration
*/
updateConfig(updates) {
this.config = this.mergeConfig(updates);
if (this.cssVariablesApplied) {
this.applyCSSVariables();
}
}
/**
* Applies configuration as CSS custom properties
*/
applyCSSVariables(rootElement) {
if (typeof document === 'undefined') {
// Server-side rendering support
return;
}
const root = rootElement || document.documentElement;
const config = this.config;
// Apply blur variables
root.style.setProperty('--aesthetic-blur-sm', config.blur.sm);
root.style.setProperty('--aesthetic-blur-md', config.blur.md);
root.style.setProperty('--aesthetic-blur-lg', config.blur.lg);
root.style.setProperty('--aesthetic-blur-xl', config.blur.xl);
root.style.setProperty('--aesthetic-blur-default', config.blur.default);
root.style.setProperty('--aesthetic-blur-heavy', config.blur.heavy);
// Apply shadow variables
root.style.setProperty('--aesthetic-shadow-soft', config.shadow.soft);
root.style.setProperty('--aesthetic-shadow-medium', config.shadow.medium);
root.style.setProperty('--aesthetic-shadow-hard', config.shadow.hard);
root.style.setProperty('--aesthetic-shadow-sm', config.shadow.elevation.sm);
root.style.setProperty('--aesthetic-shadow-md', config.shadow.elevation.md);
root.style.setProperty('--aesthetic-shadow-lg', config.shadow.elevation.lg);
root.style.setProperty('--aesthetic-shadow-xl', config.shadow.elevation.xl);
root.style.setProperty('--aesthetic-shadow-xxl', config.shadow.elevation.xxl);
// Apply glow variables
root.style.setProperty('--aesthetic-glow-primary', config.glow.primary);
root.style.setProperty('--aesthetic-glow-secondary', config.glow.secondary);
root.style.setProperty('--aesthetic-glow-accent', config.glow.accent);
root.style.setProperty('--aesthetic-glow-neon', config.glow.neon);
root.style.setProperty('--aesthetic-glow-subtle', config.glow.subtle);
root.style.setProperty('--aesthetic-glow-medium', config.glow.medium);
root.style.setProperty('--aesthetic-glow-strong', config.glow.strong);
// Apply neumorphic variables
root.style.setProperty('--aesthetic-neuro-base', config.neumorphic.baseColor);
root.style.setProperty('--aesthetic-neuro-light-source', config.neumorphic.lightSource);
root.style.setProperty('--aesthetic-neuro-dark-shadow', config.neumorphic.darkShadow);
root.style.setProperty('--aesthetic-neuro-light-shadow', config.neumorphic.lightShadow);
root.style.setProperty('--aesthetic-neuro-depth-sm', config.neumorphic.depth.sm);
root.style.setProperty('--aesthetic-neuro-depth-md', config.neumorphic.depth.md);
root.style.setProperty('--aesthetic-neuro-depth-lg', config.neumorphic.depth.lg);
root.style.setProperty('--aesthetic-neuro-depth-xl', config.neumorphic.depth.xl);
// Apply glassmorphic variables
root.style.setProperty('--aesthetic-glass-background', config.glassmorphic.background);
root.style.setProperty('--aesthetic-glass-border-opacity', config.glassmorphic.borderOpacity.toString());
root.style.setProperty('--aesthetic-glass-backdrop-blur', config.glassmorphic.backdropBlur);
root.style.setProperty('--aesthetic-glass-light', config.glassmorphic.variants.light);
root.style.setProperty('--aesthetic-glass-dark', config.glassmorphic.variants.dark);
root.style.setProperty('--aesthetic-glass-primary', config.glassmorphic.variants.primary);
root.style.setProperty('--aesthetic-glass-secondary', config.glassmorphic.variants.secondary);
// Apply border radius variables
root.style.setProperty('--aesthetic-radius-sm', config.borderRadius.sm);
root.style.setProperty('--aesthetic-radius-md', config.borderRadius.md);
root.style.setProperty('--aesthetic-radius-lg', config.borderRadius.lg);
root.style.setProperty('--aesthetic-radius-xl', config.borderRadius.xl);
root.style.setProperty('--aesthetic-radius-full', config.borderRadius.full);
// Apply color variables
root.style.setProperty('--aesthetic-primary-50', config.colors.primary[50]);
root.style.setProperty('--aesthetic-primary-500', config.colors.primary[500]);
root.style.setProperty('--aesthetic-primary-600', config.colors.primary[600]);
root.style.setProperty('--aesthetic-primary-900', config.colors.primary[900]);
root.style.setProperty('--aesthetic-secondary-50', config.colors.secondary[50]);
root.style.setProperty('--aesthetic-secondary-500', config.colors.secondary[500]);
root.style.setProperty('--aesthetic-secondary-600', config.colors.secondary[600]);
root.style.setProperty('--aesthetic-secondary-900', config.colors.secondary[900]);
root.style.setProperty('--aesthetic-accent-50', config.colors.accent[50]);
root.style.setProperty('--aesthetic-accent-500', config.colors.accent[500]);
root.style.setProperty('--aesthetic-accent-600', config.colors.accent[600]);
root.style.setProperty('--aesthetic-accent-900', config.colors.accent[900]);
this.cssVariablesApplied = true;
}
/**
* Generates CSS string with all utility classes
*/
generateCSS() {
const config = this.config;
const classes = [];
// Add CSS variables
classes.push(`:root {`);
// Blur variables
classes.push(` --aesthetic-blur-sm: ${config.blur.sm};`);
classes.push(` --aesthetic-blur-md: ${config.blur.md};`);
classes.push(` --aesthetic-blur-lg: ${config.blur.lg};`);
classes.push(` --aesthetic-blur-xl: ${config.blur.xl};`);
// Shadow variables
classes.push(` --aesthetic-shadow-sm: ${config.shadow.elevation.sm};`);
classes.push(` --aesthetic-shadow-md: ${config.shadow.elevation.md};`);
classes.push(` --aesthetic-shadow-lg: ${config.shadow.elevation.lg};`);
classes.push(` --aesthetic-shadow-xl: ${config.shadow.elevation.xl};`);
classes.push(` --aesthetic-shadow-xxl: ${config.shadow.elevation.xxl};`);
// Glow variables
classes.push(` --aesthetic-glow-subtle: ${config.glow.subtle};`);
classes.push(` --aesthetic-glow-medium: ${config.glow.medium};`);
classes.push(` --aesthetic-glow-strong: ${config.glow.strong};`);
// Neumorphic variables
classes.push(` --aesthetic-neuro-base: ${config.neumorphic.baseColor};`);
classes.push(` --aesthetic-neuro-depth-sm: ${config.neumorphic.depth.sm};`);
classes.push(` --aesthetic-neuro-depth-md: ${config.neumorphic.depth.md};`);
classes.push(` --aesthetic-neuro-depth-lg: ${config.neumorphic.depth.lg};`);
classes.push(` --aesthetic-neuro-depth-xl: ${config.neumorphic.depth.xl};`);
classes.push(`}`);
return classes.join('\n');
}
/**
* Validates the configuration
*/
validate() {
const errors = [];
const config = this.config;
// Validate blur values
Object.entries(config.blur).forEach(([key, value]) => {
if (!value.endsWith('px')) {
errors.push(`Blur ${key} must be a pixel value`);
}
});
// Validate border radius values
Object.entries(config.borderRadius).forEach(([key, value]) => {
if (!value.endsWith('px') && value !== '9999px') {
errors.push(`Border radius ${key} must be a pixel value`);
}
});
// Validate opacity
if (config.glassmorphic.borderOpacity < 0 || config.glassmorphic.borderOpacity > 1) {
errors.push('Glassmorphic border opacity must be between 0 and 1');
}
return {
isValid: errors.length === 0,
errors
};
}
/**
* Resets configuration to defaults
*/
reset() {
this.config = loadDefaultConfig();
if (this.cssVariablesApplied) {
this.applyCSSVariables();
}
}
/**
* Exports configuration as JSON
*/
export() {
return JSON.stringify(this.config, null, 2);
}
/**
* Imports configuration from JSON
*/
import(jsonConfig) {
try {
const parsedConfig = JSON.parse(jsonConfig);
this.updateConfig(parsedConfig);
}
catch (error) {
throw new Error('Invalid JSON configuration');
}
}
}
/**
* Global configuration manager instance
*/
let globalConfigManager = null;
/**
* Gets or creates the global configuration manager
*/
function getGlobalConfig() {
if (!globalConfigManager) {
globalConfigManager = new AestheticConfigManager();
}
return globalConfigManager;
}
/**
* Sets up the global configuration
*/
function setupGlobalConfig(customConfig) {
globalConfigManager = new AestheticConfigManager(customConfig);
return globalConfigManager;
}
/**
* Auto-initialization function (runs when imported)
*/
function autoInit() {
if (typeof window !== 'undefined' && !globalConfigManager) {
// Auto-initialize in browser environment
globalConfigManager = new AestheticConfigManager();
globalConfigManager.applyCSSVariables();
}
}
var config = /*#__PURE__*/Object.freeze({
__proto__: null,
AestheticConfigManager: AestheticConfigManager,
autoInit: autoInit,
getGlobalConfig: getGlobalConfig,
setupGlobalConfig: setupGlobalConfig
});
// Core utility exports
/**
* Creates a new aesthetic configuration by merging with defaults
*/
function createAestheticConfig(customConfig = {}) {
const defaultConfig = require('../../aesthetic.config.js');
return {
...defaultConfig,
...customConfig,
// Deep merge nested objects
blur: { ...defaultConfig.blur, ...customConfig.blur },
shadow: {
...defaultConfig.shadow,
...customConfig.shadow,
elevation: { ...defaultConfig.shadow.elevation, ...customConfig.shadow?.elevation }
},
glow: { ...defaultConfig.glow, ...customConfig.glow },
neumorphic: {
...defaultConfig.neumorphic,
...customConfig.neumorphic,
depth: { ...defaultConfig.neumorphic.depth, ...customConfig.neumorphic?.depth }
},
glassmorphic: {
...defaultConfig.glassmorphic,
...customConfig.glassmorphic,
variants: { ...defaultConfig.glassmorphic.variants, ...customConfig.glassmorphic?.variants }
},
borderRadius: { ...defaultConfig.borderRadius, ...customConfig.borderRadius },
colors: {
...defaultConfig.colors,
...customConfig.colors,
primary: { ...defaultConfig.colors.primary, ...customConfig.colors?.primary },
secondary: { ...defaultConfig.colors.secondary, ...customConfig.colors?.secondary },
accent: { ...defaultConfig.colors.accent, ...customConfig.colors?.accent }
}
};
}
/**
* Applies aesthetic tokens to CSS custom properties
*/
function applyAestheticTokens(config, rootElement) {
const root = rootElement || document.documentElement;
// Apply blur tokens
root.style.setProperty('--aesthetic-blur-sm', config.blur.sm);
root.style.setProperty('--aesthetic-blur-md', config.blur.md);
root.style.setProperty('--aesthetic-blur-lg', config.blur.lg);
root.style.setProperty('--aesthetic-blur-xl', config.blur.xl);
root.style.setProperty('--aesthetic-blur-default', config.blur.default);
root.style.setProperty('--aesthetic-blur-heavy', config.blur.heavy);
// Apply shadow tokens
root.style.setProperty('--aesthetic-shadow-soft', config.shadow.soft);
root.style.setProperty('--aesthetic-shadow-medium', config.shadow.medium);
root.style.setProperty('--aesthetic-shadow-hard', config.shadow.hard);
root.style.setProperty('--aesthetic-shadow-sm', config.shadow.elevation.sm);
root.style.setProperty('--aesthetic-shadow-md', config.shadow.elevation.md);
root.style.setProperty('--aesthetic-shadow-lg', config.shadow.elevation.lg);
root.style.setProperty('--aesthetic-shadow-xl', config.shadow.elevation.xl);
root.style.setProperty('--aesthetic-shadow-xxl', config.shadow.elevation.xxl);
// Apply glow tokens
root.style.setProperty('--aesthetic-glow-primary', config.glow.primary);
root.style.setProperty('--aesthetic-glow-secondary', config.glow.secondary);
root.style.setProperty('--aesthetic-glow-accent', config.glow.accent);
root.style.setProperty('--aesthetic-glow-neon', config.glow.neon);
root.style.setProperty('--aesthetic-glow-subtle', config.glow.subtle);
root.style.setProperty('--aesthetic-glow-medium', config.glow.medium);
root.style.setProperty('--aesthetic-glow-strong', config.glow.strong);
// Apply neumorphic tokens
root.style.setProperty('--aesthetic-neuro-base', config.neumorphic.baseColor);
root.style.setProperty('--aesthetic-neuro-light-source', config.neumorphic.lightSource);
root.style.setProperty('--aesthetic-neuro-dark-shadow', config.neumorphic.darkShadow);
root.style.setProperty('--aesthetic-neuro-light-shadow', config.neumorphic.lightShadow);
root.style.setProperty('--aesthetic-neuro-depth-sm', config.neumorphic.depth.sm);
root.style.setProperty('--aesthetic-neuro-depth-md', config.neumorphic.depth.md);
root.style.setProperty('--aesthetic-neuro-depth-lg', config.neumorphic.depth.lg);
root.style.setProperty('--aesthetic-neuro-depth-xl', config.neumorphic.depth.xl);
// Apply glassmorphic tokens
root.style.setProperty('--aesthetic-glass-background', config.glassmorphic.background);
root.style.setProperty('--aesthetic-glass-border-opacity', config.glassmorphic.borderOpacity.toString());
root.style.setProperty('--aesthetic-glass-backdrop-blur', config.glassmorphic.backdropBlur);
root.style.setProperty('--aesthetic-glass-light', config.glassmorphic.variants.light);
root.style.setProperty('--aesthetic-glass-dark', config.glassmorphic.variants.dark);
root.style.setProperty('--aesthetic-glass-primary', config.glassmorphic.variants.primary);
root.style.setProperty('--aesthetic-glass-secondary', config.glassmorphic.variants.secondary);
// Apply border radius tokens
root.style.setProperty('--aesthetic-radius-sm', config.borderRadius.sm);
root.style.setProperty('--aesthetic-radius-md', config.borderRadius.md);
root.style.setProperty('--aesthetic-radius-lg', config.borderRadius.lg);
root.style.setProperty('--aesthetic-radius-xl', config.borderRadius.xl);
root.style.setProperty('--aesthetic-radius-full', config.borderRadius.full);
// Apply color tokens
root.style.setProperty('--aesthetic-primary-50', config.colors.primary[50]);
root.style.setProperty('--aesthetic-primary-500', config.colors.primary[500]);
root.style.setProperty('--aesthetic-primary-600', config.colors.primary[600]);
root.style.setProperty('--aesthetic-primary-900', config.colors.primary[900]);
root.style.setProperty('--aesthetic-secondary-50', config.colors.secondary[50]);
root.style.setProperty('--aesthetic-secondary-500', config.colors.secondary[500]);
root.style.setProperty('--aesthetic-secondary-600', config.colors.secondary[600]);
root.style.setProperty('--aesthetic-secondary-900', config.colors.secondary[900]);
root.style.setProperty('--aesthetic-accent-50', config.colors.accent[50]);
root.style.setProperty('--aesthetic-accent-500', config.colors.accent[500]);
root.style.setProperty('--aesthetic-accent-600', config.colors.accent[600]);
root.style.setProperty('--aesthetic-accent-900', config.colors.accent[900]);
}
/**
* Generates all CSS utility classes based on configuration
*/
function generateAllCSSClasses(config) {
const classes = [];
// Generate glass classes
['sm', 'md', 'lg', 'xl'].forEach(size => {
classes.push(`
.glass-${size} {
backdrop-filter: blur(var(--aesthetic-blur-${size}));
-webkit-backdrop-filter: blur(var(--aesthetic-blur-${size}));
background: var(--aesthetic-glass-background);
border: 1px solid rgba(255, 255, 255, var(--aesthetic-glass-border-opacity));
border-radius: var(--aesthetic-radius-md);
}
`.trim());
});
// Generate neumorphic classes
['flat', 'concave', 'convex'].forEach(shape => {
['sm', 'md', 'lg', 'xl'].forEach(depth => {
const shadowType = shape === 'concave' ? 'inset ' : shape === 'convex' ? '' : '';
classes.push(`
.neuro-${shape}-${depth} {
background: var(--aesthetic-neuro-base);
border-radius: var(--aesthetic-radius-md);
box-shadow: ${shadowType}var(--aesthetic-neuro-depth-${depth}) var(--aesthetic-neuro-dark-shadow),
${shadowType === 'inset ' ? 'inset ' : ''}-var(--aesthetic-neuro-depth-${depth}) var(--aesthetic-neuro-light-shadow);
}
`.trim());
});
});
// Generate glow classes
['subtle', 'medium', 'strong', 'neon'].forEach(intensity => {
classes.push(`
.glow-${intensity} {
box-shadow: var(--aesthetic-glow-${intensity});
transition: box-shadow 0.3s ease-in-out;
}
`.trim());
});
// Generate shadow classes
['sm', 'md', 'lg', 'xl', 'xxl'].forEach(size => {
['soft', 'medium', 'hard'].forEach(type => {
classes.push(`
.shadow-${size}-${type} {
box-shadow: var(--aesthetic-shadow-${size});
transition: box-shadow 0.3s ease;
}
`.trim());
});
});
return classes.join('\n\n');
}
/**
* Validates aesthetic configuration
*/
function validateAestheticConfig(config) {
const errors = [];
// Validate blur values
if (config.blur) {
Object.entries(config.blur).forEach(([key, value]) => {
if (typeof value !== 'string' || !value.endsWith('px')) {
errors.push(`Blur ${key} must be a pixel value (e.g., "15px")`);
}
});
}
// Validate colors
if (config.colors) {
Object.entries(config.colors).forEach(([colorName, shades]) => {
if (typeof shades === 'object') {
Object.entries(shades).forEach(([shade, color]) => {
if (typeof color !== 'string' || !isValidCSSColor(color)) {
errors.push(`Color ${colorName}.${shade} must be a valid CSS color`);
}
});
}
});
}
return {
isValid: errors.length === 0,
errors
};
}
/**
* Utility function to validate CSS color
*/
function isValidCSSColor(color) {
const colorRegex = /^(#[0-9A-F]{6}|#[0-9A-F]{3}|rgb\(|rgba\(|hsl\(|hsla\()/i;
return colorRegex.test(color);
}
// Core utilities and configuration
// Auto-initialize in browser environment
if (typeof window !== 'undefined') {
Promise.resolve().then(function () { return config; }).then(({ autoInit }) => {
autoInit();
});
}
// CSS import (users can import this separately)
// import './css/index.css';
export { AestheticConfigManager, adjustShadowSoftness, applyAestheticTokens, autoInit, colorToRgba, createAdaptiveNeumorphicStyles, createAestheticConfig, createAnimatedGlassStyles, createAnimatedGlowStyles, createCardShadowStyles, createFloatingShadowStyles, createGlassCSSVariables, createGlowCSSVariables, createGlowHoverStyles, createHoverShadowStyles, createInsetShadowStyles, createLayeredGlowStyles, createLayeredShadowStyles, createNeonGlowStyles, createNeumorphicButtonStates, createNeumorphicCSSVariables, createNeumorphicInputStyles, createResponsiveGlassStyles, createResponsiveShadowStyles, createShadowCSSVariables, createTextGlowStyles, generateAllCSSClasses, generateDirectionalShadow, generateGlassClassName, generateGlassStyles, generateGlowClassName, generateGlowStyles, generateNeumorphicClassName, generateNeumorphicShadow