aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
223 lines (220 loc) • 6.76 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { GlassButton } from '../button/GlassButton.js';
import { cn } from '../../lib/utilsComprehensive.js';
import { forwardRef } 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 { MotionFramer } from '../../primitives/motion/MotionFramer.js';
import { useA11yId } from '../../utils/a11y.js';
import { useMotionPreferenceContext } from '../../contexts/MotionPreferenceContext.js';
/**
* GlassBadge component
* A glassmorphism badge with various styles and states
*/
const GlassBadge = /*#__PURE__*/forwardRef(({
// TODO: Integrate ContrastGuard for table cells, list items, badges, card titles, and other text content for WCAG AA compliance
variant = "default",
size = "sm",
shape = "glass-radius-md",
dot = false,
leftIcon,
rightIcon,
removable = false,
onRemove,
animate = false,
animation = "scale",
respectMotionPreference = true,
"aria-label": ariaLabel,
className,
children,
...props
}, ref) => {
const badgeId = useA11yId("badge");
const {
prefersReducedMotion
} = useMotionPreferenceContext();
const shouldAnimate = animate && (!respectMotionPreference || !prefersReducedMotion);
const sizeClasses = {
xs: dot ? "w-2 h-2" : "glass-px-1.5 glass-py-0.5 glass-text-xs",
sm: dot ? "w-2.5 h-2.5" : "glass-px-2 glass-py-1 glass-text-xs",
md: dot ? "w-3 h-3" : "glass-px-2.5 glass-py-1 glass-text-sm",
lg: dot ? "w-3.5 h-3.5" : "glass-px-3 glass-py-1.5 glass-text-sm"
};
const shapeClasses = {
"glass-radius-md": "glass-radius-md",
pill: "glass-radius-full",
square: "rounded-none"
};
const variantClasses = {
default: "bg-muted/50 glass-text-secondary border-0",
primary: "glass-surface-primary/10 glass-text-primary border-0",
secondary: "bg-secondary/10 glass-text-primary/90 border-0",
success: "glass-surface-success/10 glass-text-success border-0",
warning: "glass-surface-warning/10 glass-text-primary border-0",
error: "glass-surface-danger/10 glass-text-danger border-0",
info: "glass-surface-info/10 glass-text-primary border-0",
outline: "bg-transparent text-foreground border border-white/10",
ghost: "bg-transparent glass-text-primary/70 border-0"
};
const dotVariantClasses = {
default: "bg-muted-foreground",
primary: "bg-primary",
secondary: "bg-secondary",
success: "bg-success",
warning: "bg-warning",
error: "bg-destructive",
info: "bg-info",
outline: "bg-foreground",
ghost: "bg-muted-foreground"
};
const iconSize = {
xs: "w-3 h-3",
sm: "w-3 h-3",
md: "w-4 h-4",
lg: "w-4 h-4"
};
const getAnimationPreset = () => {
switch (animation) {
case "scale":
return "scaleIn";
case "fade":
return "fadeIn";
case "bounce":
return "bounceIn";
default:
return "scaleIn";
}
};
if (dot) {
const content = jsx("span", {
ref: ref,
id: badgeId,
className: cn("inline-block glass-radius-full flex-shrink-0", sizeClasses[size], dotVariantClasses[variant] ?? dotVariantClasses.default, className),
role: "status",
"aria-label": ariaLabel || `${variant} status indicator`,
...props
});
return shouldAnimate ? jsx(MotionFramer, {
preset: getAnimationPreset(),
children: content
}) : content;
}
const content = jsxs(OptimizedGlassCore, {
elevation: variant === "ghost" ? undefined : "level1",
intensity: "medium",
depth: 2,
tint: "neutral",
border: "subtle",
animation: "none",
performanceMode: "medium",
ref: ref,
id: badgeId,
className: cn("inline-flex items-center glass-gap-1 font-medium", "transition-all duration-200", sizeClasses[size], shapeClasses[shape], variantClasses[variant] ?? variantClasses.default, className),
role: removable ? "button" : "status",
"aria-label": ariaLabel || (children ? `Badge: ${children}` : `${variant} badge`),
...props,
children: [leftIcon && jsx("span", {
className: cn("flex-shrink-0", iconSize[size]),
children: leftIcon
}), children && jsx("span", {
className: 'whitespace-nowrap',
children: children
}), rightIcon && !removable && jsx("span", {
className: cn("flex-shrink-0", iconSize[size]),
children: rightIcon
}), removable && jsx(GlassButton, {
type: "button",
onClick: onRemove,
className: cn("flex-shrink-0 flex items-center justify-center", "hover:bg-current/20 glass-radius-full transition-colors", "focus:outline-none focus:ring-1 focus:ring-current", iconSize[size]),
"aria-label": "Remove badge",
children: jsx("svg", {
className: 'w-2.5 h-2.5',
fill: "none",
stroke: "currentColor",
viewBox: "0 0 24 24",
children: jsx("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
strokeWidth: 2,
d: "M6 18L18 6M6 6l12 12"
})
})
})]
});
return shouldAnimate ? jsx(MotionFramer, {
preset: getAnimationPreset(),
children: content
}) : content;
});
GlassBadge.displayName = "GlassBadge";
const StatusBadge = /*#__PURE__*/forwardRef(({
status,
dotOnly = false,
...props
}, ref) => {
const statusConfig = {
online: {
variant: "success",
label: "Online"
},
offline: {
variant: "default",
label: "Offline"
},
away: {
variant: "warning",
label: "Away"
},
busy: {
variant: "error",
label: "Busy"
},
pending: {
variant: "warning",
label: "Pending"
},
active: {
variant: "success",
label: "Active"
},
inactive: {
variant: "default",
label: "Inactive"
}
};
const config = statusConfig[status];
return jsx(GlassBadge, {
ref: ref,
variant: config.variant,
dot: dotOnly,
...props,
children: !dotOnly && config.label
});
});
StatusBadge.displayName = "StatusBadge";
const CountBadge = /*#__PURE__*/forwardRef(({
count,
max = 99,
showZero = false,
...props
}, ref) => {
if (count <= 0 && !showZero) {
return null;
}
const displayCount = count > max ? `${max}+` : count.toString();
return jsx(GlassBadge, {
ref: ref,
variant: "default",
size: "xs",
shape: "pill",
...props,
children: displayCount
});
});
CountBadge.displayName = "CountBadge";
export { CountBadge, GlassBadge, StatusBadge };
//# sourceMappingURL=GlassBadge.js.map