UNPKG

aura-glass

Version:

A comprehensive glassmorphism design system for React applications with 142+ production-ready components

318 lines (315 loc) 12.2 kB
'use client'; import { jsx, jsxs } from 'react/jsx-runtime'; import { cn } from '../../lib/utilsComprehensive.js'; import { RefreshCw, Download, Minimize2, Maximize2, MoreVertical, Settings, BarChart3, PieChart, TrendingUp, LineChart } from 'lucide-react'; import { useState } from 'react'; import '../../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 { GlassButton } from '../button/GlassButton.js'; import '../button/GlassFab.js'; import '../button/GlassMagneticButton.js'; import { CardHeader, CardTitle, CardContent } from '../card/index.js'; import '../data-display/GlassAccordion.js'; import '../data-display/GlassAlert.js'; import '../data-display/GlassAvatar.js'; import { GlassBadge } from '../data-display/GlassBadge.js'; import '../data-display/GlassBadgeLine.js'; import '../data-display/GlassDataGrid.js'; import '../data-display/GlassDataTable.js'; import '../data-display/GlassHeatmap.js'; import '../data-display/GlassLoadingSkeleton.js'; import '../data-display/GlassProgress.js'; import '../data-display/GlassTimeline.js'; import '../data-display/GlassSkeleton.js'; import '../data-display/GlassNotificationCenter.js'; import '../data-display/GlassAnimatedNumber.js'; import { GlassCard } from '../card/GlassCard.js'; /** * GlassChartWidget component * A glassmorphism chart container widget with header, actions, and fullscreen support */ const GlassChartWidget = ({ // TODO: Integrate ContrastGuard in chart labels, tooltips, and legends for WCAG AA compliance title = "Analytics Overview", subtitle, children, size = "md", loading = false, error, emptyMessage, showHeader = true, showActions = true, actions = [], chartType, showChartType = true, timeRange, lastUpdated, showRefresh = true, showDownload = true, showFullscreen = true, fullscreen = false, onFullscreenChange, onRefresh, onDownload, headerContent, footerContent, className, ...props }) => { const [isFullscreen, setIsFullscreen] = useState(fullscreen); const [showActionMenu, setShowActionMenu] = useState(false); // Size configurations const sizeConfigs = { sm: { cardClass: "glass-p-4", titleClass: "glass-text-lg font-semibold", contentClass: "min-h-[200px]" }, md: { cardClass: "glass-p-6", titleClass: "glass-text-xl font-semibold", contentClass: "min-h-[300px]" }, lg: { cardClass: "p-8", titleClass: "glass-text-2xl font-semibold", contentClass: "min-h-[400px]" }, xl: { cardClass: "glass-p-10", titleClass: "text-3xl font-semibold", contentClass: "min-h-[500px]" } }; const config = sizeConfigs[size]; // Get chart type icon const getChartTypeIcon = () => { switch (chartType) { case "line": return jsx(LineChart, { className: 'w-5 h-5' }); case "bar": return jsx(BarChart3, { className: 'w-5 h-5' }); case "area": return jsx(TrendingUp, { className: 'w-5 h-5' }); case "pie": return jsx(PieChart, { className: 'w-5 h-5' }); case "donut": return jsx(PieChart, { className: 'w-5 h-5' }); default: return jsx(BarChart3, { className: 'w-5 h-5' }); } }; // Handle fullscreen toggle const handleFullscreenToggle = () => { const newFullscreen = !isFullscreen; setIsFullscreen(newFullscreen); onFullscreenChange?.(newFullscreen); }; // Handle refresh const handleRefresh = () => { onRefresh?.(); }; // Handle download const handleDownload = () => { onDownload?.(); }; // Format last updated time const formatLastUpdated = date => { const now = new Date(); const diff = now.getTime() - date.getTime(); const minutes = Math.floor(diff / 60000); const hours = Math.floor(diff / 3600000); const days = Math.floor(diff / 86400000); if (minutes < 1) return "Just now"; if (minutes < 60) return `${minutes}m ago`; if (hours < 24) return `${hours}h ago`; return `${days}d ago`; }; return jsx(MotionFramer, { "data-glass-component": true, preset: "fadeIn", className: "glass-w-full", children: jsxs(GlassCard, { variant: "elevated", elevation: "level3", className: cn(config.cardClass, isFullscreen && "fixed inset-4 z-50", className), ...props, children: [showHeader && jsx(CardHeader, { className: 'pb-4', children: jsxs("div", { className: "glass-flex glass-items-start glass-justify-between", children: [jsxs("div", { className: "glass-flex-1 glass-min-w-0", children: [jsxs("div", { className: 'glass-flex glass-items-center glass-gap-3 mb-2', children: [jsxs(CardTitle, { className: cn(config.titleClass, "glass-text-primary flex items-center glass-gap-2"), children: [showChartType && chartType && jsx("span", { className: 'text-primary/60', children: getChartTypeIcon() }), title] }), timeRange && jsx(GlassBadge, { variant: "secondary", size: "sm", children: timeRange })] }), subtitle && jsx("p", { className: 'glass-text-sm text-primary/60 mb-2', children: subtitle }), lastUpdated && jsxs("p", { className: 'glass-text-xs text-primary/50', children: ["Last updated: ", formatLastUpdated(lastUpdated)] })] }), jsxs("div", { className: "glass-flex glass-items-center glass-gap-2", children: [headerContent, jsxs("div", { className: "glass-flex glass-items-center glass-gap-1", children: [showRefresh && jsx(GlassButton, { variant: "ghost", size: "sm", onClick: handleRefresh, disabled: loading, className: "glass-p-2", "aria-label": "Refresh data", children: jsx(RefreshCw, { className: cn("w-4 h-4", loading && "animate-spin") }) }), showDownload && jsx(GlassButton, { variant: "ghost", size: "sm", onClick: handleDownload, className: "glass-p-2", "aria-label": "Download data", children: jsx(Download, { className: 'w-4 h-4' }) }), showFullscreen && jsx(GlassButton, { variant: "ghost", size: "sm", onClick: handleFullscreenToggle, className: "glass-p-2", "aria-label": isFullscreen ? "Exit fullscreen" : "Enter fullscreen", children: isFullscreen ? jsx(Minimize2, { className: 'w-4 h-4' }) : jsx(Maximize2, { className: 'w-4 h-4' }) })] }), showActions && actions.length > 0 && jsxs("div", { className: 'relative', children: [jsx(GlassButton, { variant: "ghost", size: "sm", onClick: e => setShowActionMenu(!showActionMenu), className: "glass-p-2", "aria-label": "Open widget actions", "aria-expanded": showActionMenu, "aria-haspopup": "menu", children: jsx(MoreVertical, { className: 'w-4 h-4' }) }), showActionMenu && jsx(MotionFramer, { preset: "fadeIn", className: 'absolute right-0 top-full glass-mt-2 z-10', children: jsxs("div", { className: "glass-surface-dark/80 glass-glass-backdrop-blur-md glass-border glass-border-white/20 glass-radius-lg glass-shadow-xl glass-min-w-48 glass-contrast-guard", children: [actions.map((action, index) => jsxs("button", { onClick: e => { action.onClick(); setShowActionMenu(false); }, disabled: action.disabled, className: cn("w-full text-left glass-px-4 glass-py-2 glass-text-sm glass-text-primary/80 hover:bg-white/10", "first:rounded-t-lg last:rounded-b-lg", "disabled:opacity-50 disabled:cursor-not-allowed", "flex items-center glass-gap-2"), children: [action.icon && jsx("span", { className: 'w-4 h-4', children: action.icon }), action.label] }, index)), jsxs("div", { className: "glass-border-t glass-border-white/10", children: [jsxs("button", { onClick: e => { onRefresh?.(); setShowActionMenu(false); }, className: 'glass-w-full text-left glass-px-4 glass-py-2 glass-text-sm text-primary/80 hover:glass-surface-subtle/10 glass-flex glass-items-center glass-gap-2 glass-focus glass-touch-target glass-contrast-guard', children: [jsx(RefreshCw, { className: 'w-4 h-4' }), "Refresh Data"] }), jsxs("button", { onClick: e => { onDownload?.(); setShowActionMenu(false); }, className: 'glass-w-full text-left glass-px-4 glass-py-2 glass-text-sm text-primary/80 hover:glass-surface-subtle/10 glass-flex glass-items-center glass-gap-2 glass-radius-b-lg glass-focus glass-touch-target glass-contrast-guard', children: [jsx(Download, { className: 'w-4 h-4' }), "Export Data"] })] })] }) })] })] })] }) }), jsx(CardContent, { className: 'pt-0', children: error ? jsxs("div", { className: cn("flex flex-col items-center justify-center", config.contentClass), children: [jsx("div", { className: 'text-primary mb-2', children: jsx(Settings, { className: 'w-8 h-8' }) }), jsx("p", { className: 'text-primary/80 text-center mb-4', children: error }), jsx(GlassButton, { variant: "outline", onClick: handleRefresh, children: "Try Again" })] }) : !children && emptyMessage ? jsxs("div", { className: cn("flex flex-col items-center justify-center", config.contentClass), children: [jsx("div", { className: 'text-primary/40 mb-2', children: jsx(BarChart3, { className: 'w-8 h-8' }) }), jsx("p", { className: 'text-primary/60 text-center', children: emptyMessage })] }) : jsx("div", { className: config.contentClass, children: loading ? jsx("div", { className: "glass-flex glass-items-center glass-justify-center glass-h-full", children: jsx("div", { className: 'animate-spin glass-radius-full h-8 w-8 glass-border-2 glass-border-white/20 glass-border-t-white/60' }) }) : children }) }), footerContent && jsx("div", { className: 'glass-mt-4 pt-4 glass-border-t glass-border-white/10', children: footerContent })] }) }); }; export { GlassChartWidget, GlassChartWidget as default }; //# sourceMappingURL=GlassChartWidget.js.map