aura-glass
Version:
A comprehensive glassmorphism design system for React applications with 142+ production-ready components
269 lines (266 loc) • 10.1 kB
JavaScript
'use client';
import { jsx, jsxs } from 'react/jsx-runtime';
import { cn } from '../../../../lib/utilsComprehensive.js';
import React, { forwardRef, useState } 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 '../../../../primitives/motion/MotionFramer.js';
import { GlassButton } from '../../../button/GlassButton.js';
import { GlassBadge } from '../../../data-display/GlassBadge.js';
import { VStack, HStack } from '../../../layout/GlassStack.js';
/**
* TableWidget component
* Display tabular data with sorting and styling
*/
const TableWidget = /*#__PURE__*/forwardRef(({
data,
variant = "default",
size = "md",
maxRows = 5,
showHeader = true,
sortable = true,
showRowNumbers = false,
hoverable = true,
striped = false,
loading = false,
actions,
onRowClick,
onSort,
className,
...props
}, ref) => {
const [sortColumn, setSortColumn] = useState(null);
const [sortDirection, setSortDirection] = useState("asc");
const sizeClasses = {
sm: {
padding: "glass-p-3",
title: "glass-text-sm",
subtitle: "glass-text-xs",
cell: "glass-px-2 glass-py-1 glass-text-xs",
header: "glass-px-2 glass-py-2 glass-text-xs"
},
md: {
padding: "glass-p-4",
title: "glass-text-base",
subtitle: "glass-text-sm",
cell: "glass-px-3 glass-py-2 glass-text-sm",
header: "glass-px-3 glass-py-2 glass-text-sm"
},
lg: {
padding: "glass-p-6",
title: "glass-text-lg",
subtitle: "glass-text-base",
cell: "glass-px-4 glass-py-3 glass-text-base",
header: "glass-px-4 glass-py-3 glass-text-base"
}
};
const config = sizeClasses?.[size];
// Handle column sort
const handleSort = columnId => {
const column = data?.columns.find(col => col.id === columnId);
if (!column?.sortable && !sortable) return;
const newDirection = sortColumn === columnId && sortDirection === "asc" ? "desc" : "asc";
setSortColumn(columnId);
setSortDirection(newDirection);
onSort?.(columnId, newDirection);
};
// Sort data if local sorting
const sortedRows = React.useMemo(() => {
if (!sortColumn || onSort) return data?.rows || [];
const column = (data?.columns || []).find(col => col.id === sortColumn);
if (!column) return data?.rows || [];
return [...(data?.rows || [])].sort((a, b) => {
const aValue = a[column.accessor];
const bValue = b?.[column.accessor];
if (aValue < bValue) return sortDirection === "asc" ? -1 : 1;
if (aValue > bValue) return sortDirection === "asc" ? 1 : -1;
return 0;
});
}, [data?.rows, data?.columns, sortColumn, sortDirection, onSort]);
const displayRows = sortedRows.slice(0, maxRows);
const renderCellContent = (column, row) => {
const value = row?.[column.accessor];
if (column.render) {
return column.render(value, row);
}
// Default renderers for common data types
if (typeof value === "boolean") {
return jsx(GlassBadge, {
"data-glass-component": true,
variant: value ? "success" : "error",
size: "xs",
children: value ? "Yes" : "No"
});
}
if (typeof value === "number") {
return value.toLocaleString();
}
if (value === null || value === undefined) {
return jsx("span", {
className: "glass-text-secondary",
children: "\u2014"
});
}
return String(value);
};
const renderTable = () => {
if (loading) {
return jsx("div", {
className: "glass-flex glass-items-center glass-justify-center glass-py-8",
children: jsx("div", {
className: 'w-6 h-6 glass-border-2 glass-border-primary glass-border-t-transparent glass-radius-full animate-spin'
})
});
}
if ((displayRows?.length || 0) === 0) {
return jsx("div", {
className: "glass-flex glass-items-center glass-justify-center glass-py-8 glass-text-secondary",
children: "No data available"
});
}
return jsx("div", {
className: 'overflow-x-auto',
children: jsxs("table", {
className: "glass-w-full",
children: [showHeader && jsx("thead", {
children: jsxs("tr", {
className: "glass-border-b glass-border-glass-border/20",
children: [showRowNumbers && jsx("th", {
className: cn(config.header, "w-12 text-left font-medium glass-text-secondary"),
children: "#"
}), (data?.columns || []).map(column => jsx("th", {
className: cn(config.header, "font-medium glass-text-secondary", {
"text-left": column.align === "left" || !column.align,
"text-center": column.align === "center",
"text-right": column.align === "right",
"cursor-pointer hover:text-foreground": column.sortable || sortable
}),
style: {
width: column.width
},
onClick: e => handleSort(column.id),
children: jsxs(HStack, {
space: "xs",
align: "center",
className: "glass-justify-start",
children: [jsx("span", {
children: column.header
}), (column.sortable || sortable) && jsxs("div", {
className: "glass-flex glass-flex-col",
children: [jsx("div", {
className: cn("w-0 h-0 border-l-[3px] border-r-[3px] border-b-[4px] border-transparent", sortColumn === column.id && sortDirection === "asc" ? "border-b-primary" : "border-b-muted-foreground/30")
}), jsx("div", {
className: cn("w-0 h-0 border-l-[3px] border-r-[3px] border-t-[4px] border-transparent mt-0.5", sortColumn === column.id && sortDirection === "desc" ? "border-t-primary" : "border-t-muted-foreground/30")
})]
})]
})
}, column.id))]
})
}), jsx("tbody", {
children: displayRows.map((row, index) => jsxs("tr", {
className: cn("transition-colors animate-fade-in", {
"bg-muted/20": striped && index % 2 === 1,
"hover:bg-muted/30": hoverable,
"cursor-pointer": onRowClick
}),
style: {
animationDelay: `${Math.min(index, 15) * 50}ms`,
animationFillMode: "both"
},
onClick: e => onRowClick?.(row),
children: [showRowNumbers && jsx("td", {
className: cn(config.cell, "glass-text-secondary"),
children: index + 1
}), (data?.columns || []).map(column => jsx("td", {
className: cn(config.cell, "text-foreground", {
"text-left": column.align === "left" || !column.align,
"text-center": column.align === "center",
"text-right": column.align === "right"
}),
children: renderCellContent(column, row)
}, column.id))]
}, row.id))
})]
})
});
};
const renderContent = () => {
switch (variant) {
case "minimal":
return renderTable();
case "compact":
return jsxs(VStack, {
space: "sm",
children: [jsxs(HStack, {
space: "sm",
align: "center",
justify: "between",
children: [jsx("h3", {
className: cn("font-medium text-foreground", config.title),
children: data?.title || "Table"
}), actions]
}), renderTable()]
});
default:
return jsxs(VStack, {
space: "md",
children: [jsxs(HStack, {
space: "sm",
align: "center",
justify: "between",
children: [jsxs(VStack, {
space: "xs",
children: [jsx("h3", {
className: cn("font-medium text-foreground", config.title),
children: data?.title || "Table"
}), data?.subtitle && jsx("p", {
className: cn("glass-text-secondary", config.subtitle),
children: data?.subtitle
})]
}), actions]
}), data?.summary && jsxs(HStack, {
space: "sm",
align: "center",
children: [data?.summary.total && jsxs("span", {
className: "glass-text-sm glass-text-secondary",
children: ["Total: ", data?.summary.total.toLocaleString()]
}), data?.summary.filtered && data?.summary.filtered !== data?.summary.total && jsxs("span", {
className: "glass-text-sm glass-text-secondary",
children: ["Showing: ", data?.summary.filtered.toLocaleString()]
}), data?.summary.message && jsx(GlassBadge, {
variant: "outline",
size: "xs",
children: data?.summary.message
})]
}), jsx("div", {
className: "glass-flex-1",
children: renderTable()
}), (data?.rows?.length || 0) > maxRows && jsxs(HStack, {
space: "sm",
align: "center",
justify: "center",
children: [jsxs("span", {
className: "glass-text-xs glass-text-secondary",
children: ["Showing ", maxRows, " of ", data?.rows?.length || 0, " rows"]
}), jsx(GlassButton, {
variant: "ghost",
size: "xs",
children: "View All"
})]
})]
});
}
};
return jsx(GlassCore, {
ref: ref,
className: cn("w-full h-full glass-radius-lg", config.padding, className),
...props,
children: renderContent()
});
});
TableWidget.displayName = "TableWidget";
export { TableWidget };
//# sourceMappingURL=TableWidget.js.map