aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
277 lines (274 loc) • 9.27 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { cn } from '../../../../lib/utilsComprehensive.js';
import { forwardRef } from 'react';
import { GlassCore } from '../../../../primitives/GlassCore.js';
import '../../../../primitives/glass/GlassAdvanced.js';
import '../../../../primitives/OptimizedGlassCore.js';
import '../../../../primitives/glass/OptimizedGlassAdvanced.js';
import '../../../../primitives/MotionNative.js';
import { MotionFramer } from '../../../../primitives/motion/MotionFramer.js';
import { GlassBadge } from '../../../data-display/GlassBadge.js';
import { VStack, HStack } from '../../../layout/GlassStack.js';
/**
* MetricWidget component
* Display key metrics with trends and targets
*/
const MetricWidget = /*#__PURE__*/forwardRef(({
data,
variant = "default",
size = "md",
colorScheme = "default",
showTrend = true,
showTarget = false,
trendIcons,
className,
...props
}, ref) => {
const sizeClasses = {
sm: {
value: "glass-text-lg",
label: "glass-text-xs",
icon: "glass-text-lg",
padding: "glass-p-3"
},
md: {
value: "glass-text-2xl",
label: "glass-text-sm",
icon: "glass-text-xl",
padding: "glass-p-4"
},
lg: {
value: "text-3xl",
label: "glass-text-base",
icon: "glass-text-2xl",
padding: "glass-p-6"
}
};
const colorSchemes = {
default: {
value: "text-foreground",
change: {
up: "text-success",
down: "text-destructive",
neutral: "glass-text-secondary"
},
icon: "glass-text-secondary",
background: ""
},
primary: {
value: "text-primary",
change: {
up: "text-success",
down: "text-destructive",
neutral: "glass-text-secondary"
},
icon: "text-primary/70",
background: "bg-primary/5"
},
success: {
value: "text-success",
change: {
up: "text-success",
down: "text-destructive",
neutral: "glass-text-secondary"
},
icon: "text-success/70",
background: "bg-success/5"
},
warning: {
value: "text-warning",
change: {
up: "text-success",
down: "text-destructive",
neutral: "glass-text-secondary"
},
icon: "text-warning/70",
background: "bg-warning/5"
},
destructive: {
value: "text-destructive",
change: {
up: "text-success",
down: "text-destructive",
neutral: "glass-text-secondary"
},
icon: "text-destructive/70",
background: "bg-destructive/5"
}
};
const config = sizeClasses?.[size];
const colors = colorSchemes?.[colorScheme];
const defaultTrendIcons = {
up: "↗️",
down: "↘️",
neutral: "→"
};
const icons = trendIcons || defaultTrendIcons;
const formatValue = value => {
if (typeof value === "number") {
return new Intl.NumberFormat().format(value);
}
return value;
};
const getTrendIcon = () => {
if (!data?.trend) return null;
return icons?.[data?.trend];
};
const getChangeColor = () => {
if (!data?.change) return colors.change.neutral;
if (data?.change > 0) return colors.change.up;
if (data?.change < 0) return colors.change.down;
return colors.change.neutral;
};
const getTargetProgress = () => {
if (!data?.target || typeof data?.value !== "number") return 0;
return Math.min(data?.value / data?.target * 100, 100);
};
const renderContent = () => {
switch (variant) {
case "minimal":
return jsxs(HStack, {
"data-glass-component": true,
space: "sm",
align: "center",
children: [data?.icon && jsx("div", {
className: cn(config.icon, colors.icon),
children: data?.icon
}), jsxs(VStack, {
space: "none",
children: [jsxs("div", {
className: cn("font-bold", config.value, colors.value),
children: [formatValue(data?.value), data?.unit]
}), jsx("div", {
className: cn("glass-text-secondary", config.label),
children: data?.label || "Metric"
})]
}), showTrend && data?.change && jsxs(GlassBadge, {
variant: "outline",
size: "xs",
className: getChangeColor(),
children: [getTrendIcon(), " ", data?.change > 0 ? "+" : "", data?.change, "%"]
})]
});
case "featured":
return jsxs(VStack, {
space: "md",
children: [jsxs(HStack, {
space: "sm",
align: "center",
justify: "between",
children: [jsx("div", {
className: cn("glass-text-secondary", config.label),
children: data?.label || "Metric"
}), data?.icon && jsx("div", {
className: cn(config.icon, colors.icon),
children: data?.icon
})]
}), jsxs(VStack, {
space: "xs",
children: [jsxs("div", {
className: cn("font-bold", config.value, colors.value),
children: [formatValue(data?.value), data?.unit]
}), showTarget && data?.target && jsxs("div", {
className: "glass-w-full",
children: [jsxs("div", {
className: 'glass-flex glass-justify-between glass-text-xs glass-text-secondary mb-1',
children: [jsx("span", {
children: "Progress"
}), jsxs("span", {
children: [Math.round(getTargetProgress()), "%"]
})]
}), jsx("div", {
className: 'glass-w-full glass-surface-subtle glass-radius-full h-2',
children: jsx(MotionFramer, {
className: cn("h-full glass-radius-full transition-all duration-500", getTargetProgress() >= 100 ? "bg-success" : "bg-primary"),
style: {
width: `${getTargetProgress()}%`
}
})
})]
})]
}), showTrend && (data?.change || data?.changeLabel) && jsxs(HStack, {
space: "sm",
align: "center",
children: [data?.change && jsxs("div", {
className: cn("glass-text-xs font-medium flex items-center glass-gap-1", getChangeColor()),
children: [jsx("span", {
children: getTrendIcon()
}), jsxs("span", {
children: [data?.change > 0 ? "+" : "", data?.change, "%"]
})]
}), data?.changeLabel && jsx("div", {
className: "glass-text-xs glass-text-secondary",
children: data?.changeLabel
})]
}), data?.description && jsx("div", {
className: "glass-text-xs glass-text-secondary",
children: data?.description
})]
});
case "compact":
return jsxs(HStack, {
space: "sm",
align: "center",
justify: "between",
children: [jsxs(VStack, {
space: "none",
children: [jsxs("div", {
className: cn("font-bold glass-text-lg", colors.value),
children: [formatValue(data?.value), data?.unit]
}), jsx("div", {
className: "glass-text-xs glass-text-secondary",
children: data?.label || "Metric"
})]
}), data?.icon && jsx("div", {
className: cn("glass-text-lg", colors.icon),
children: data?.icon
})]
});
default:
return jsxs(VStack, {
space: "md",
children: [jsxs(HStack, {
space: "sm",
align: "center",
justify: "between",
children: [jsx("div", {
className: cn("glass-text-secondary", config.label),
children: data?.label || "Metric"
}), data?.icon && jsx("div", {
className: cn(config.icon, colors.icon),
children: data?.icon
})]
}), jsxs("div", {
className: cn("font-bold", config.value, colors.value),
children: [formatValue(data?.value), data?.unit]
}), showTrend && data?.change && jsxs(HStack, {
space: "sm",
align: "center",
children: [jsxs("div", {
className: cn("glass-text-sm font-medium flex items-center glass-gap-1", getChangeColor()),
children: [jsx("span", {
children: getTrendIcon()
}), jsxs("span", {
children: [data?.change > 0 ? "+" : "", data?.change, "%"]
})]
}), data?.changeLabel && jsx("div", {
className: "glass-text-sm glass-text-secondary",
children: data?.changeLabel
})]
})]
});
}
};
return jsx(GlassCore, {
ref: ref,
className: cn("w-full h-full glass-radius-lg", config.padding, colors.background, className),
...props,
children: renderContent()
});
});
MetricWidget.displayName = "MetricWidget";
export { MetricWidget };
//# sourceMappingURL=MetricWidget.js.map