UNPKG

aura-glass

Version:

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

195 lines (192 loc) 9.17 kB
'use client'; import { jsxs, jsx, Fragment } from 'react/jsx-runtime'; import { useState, useMemo } 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 { cn } from '../../../lib/utilsComprehensive.js'; function GlassDataTable({ // TODO: Integrate ContrastGuard for table cells, list items, badges, card titles, and other text content for WCAG AA compliance data = [], columns = [], loading = false, searchable = true, paginated = true, pageSize = 10, emptyMessage = "No data available", loadingRows = 5, className, ...props }) { const safeData = Array.isArray(data) ? data : []; const safeColumns = Array.isArray(columns) ? columns : []; const effectivePageSize = typeof pageSize === "number" && pageSize > 0 ? pageSize : safeData.length || 1; const effectiveLoadingRows = typeof loadingRows === "number" && loadingRows > 0 ? loadingRows : 5; const [sortColumn, setSortColumn] = useState(null); const [sortDirection, setSortDirection] = useState("asc"); const [searchTerm, setSearchTerm] = useState(""); const [currentPage, setCurrentPage] = useState(1); // Filter and sort data const processedData = useMemo(() => { let result = [...safeData]; // Search if (searchTerm) { result = result.filter(item => safeColumns.some(col => col.filterable !== false && String(item[col.key]).toLowerCase().includes(searchTerm.toLowerCase()))); } // Sort if (sortColumn) { result.sort((a, b) => { const aVal = a[sortColumn]; const bVal = b[sortColumn]; if (aVal < bVal) return sortDirection === "asc" ? -1 : 1; if (aVal > bVal) return sortDirection === "asc" ? 1 : -1; return 0; }); } return result; }, [safeData, safeColumns, searchTerm, sortColumn, sortDirection]); // Pagination const totalPages = Math.max(1, Math.ceil(processedData.length / effectivePageSize)); const startIndex = (currentPage - 1) * effectivePageSize; const paginatedData = paginated ? processedData.slice(startIndex, startIndex + effectivePageSize) : processedData; const handleSort = columnKey => { const column = safeColumns.find(col => col.key === columnKey); if (!column?.sortable) return; if (sortColumn === columnKey) { setSortDirection(sortDirection === "asc" ? "desc" : "asc"); } else { setSortColumn(columnKey); setSortDirection("asc"); } }; const renderLoadingSkeleton = () => jsx(Fragment, { children: Array.from({ length: effectiveLoadingRows }).map((_, index) => jsx("tr", { className: 'animate-pulse', children: safeColumns.map((column, colIndex) => jsx("td", { className: "glass-p-4", children: jsx("div", { className: 'h-4 glass-surface-subtle glass-radius' }) }, `loading-${index}-${colIndex}`)) }, `loading-${index}`)) }); const renderEmptyState = () => jsx("tr", { children: jsx("td", { colSpan: safeColumns.length || 1, className: 'glass-p-12 text-center', children: jsxs("div", { className: "glass-flex glass-flex-col glass-items-center glass-gap-4 glass-text-secondary", children: [jsx("div", { className: 'text-6xl opacity-50', children: "\uD83D\uDCED" }), jsx("div", { className: 'font-medium', children: emptyMessage }), searchTerm && jsx("button", { onClick: () => setSearchTerm(""), className: 'glass-px-4 glass-py-2 glass-surface-primary/10 hover:glass-surface-primary/20 glass-radius-lg text-primary glass-text-sm font-medium transition-colors glass-focus glass-touch-target glass-contrast-guard', children: "Clear Search" })] }) }) }); const renderPagination = () => { if (!paginated || totalPages <= 1) return null; return jsxs("div", { "data-glass-component": true, className: "glass-flex glass-items-center glass-justify-between glass-p-4 glass-border-t glass-border-glass-border", children: [jsxs("div", { className: "glass-text-sm glass-text-secondary", children: ["Showing ", startIndex + 1, " to", " ", Math.min(startIndex + effectivePageSize, processedData.length), " of", " ", processedData.length, " results"] }), jsxs("div", { className: "glass-flex glass-items-center glass-gap-2", children: [jsx("button", { onClick: () => setCurrentPage(Math.max(1, currentPage - 1)), disabled: currentPage === 1, className: 'glass-px-3 glass-py-1 glass-radius-md glass-border glass-border-glass-border hover:glass-surface-subtle disabled:opacity-50 disabled:cursor-not-allowed transition-colors glass-focus glass-touch-target glass-contrast-guard', children: "Previous" }), Array.from({ length: Math.min(5, totalPages) }).map((_, index) => { const page = index + 1; return jsx("button", { onClick: () => setCurrentPage(page), className: cn("glass-px-3 glass-py-1 glass-radius-md border transition-colors glass-focus glass-touch-target glass-contrast-guard", currentPage === page ? "bg-primary text-primary-foreground border-primary" : "border-border hover:bg-muted"), children: page }, page); }), jsx("button", { onClick: () => setCurrentPage(Math.min(totalPages, currentPage + 1)), disabled: currentPage === totalPages, className: 'glass-px-3 glass-py-1 glass-radius-md glass-border glass-border-glass-border hover:glass-surface-subtle disabled:opacity-50 disabled:cursor-not-allowed transition-colors glass-focus glass-touch-target glass-contrast-guard', children: "Next" })] })] }); }; return jsxs(GlassCore, { className: cn("glass-radius-xl overflow-hidden", className), ...props, children: [searchable && jsx("div", { className: "glass-p-4 glass-border-b glass-border-glass-border", children: jsxs("div", { className: 'relative', children: [jsx("input", { type: "text", placeholder: "Search...", value: searchTerm, onChange: e => { setSearchTerm(e.target.value); setCurrentPage(1); }, className: 'glass-w-full glass-px-4 glass-py-2 glass-pl-10 bg-background glass-border glass-border-glass-border glass-radius-lg focus:outline-none focus:ring-2 focus:ring-primary/20 transition-colors glass-focus glass-touch-target glass-contrast-guard' }), jsx("div", { className: 'absolute left-3 glass-top-1/2 -translate-y-1/2 glass-text-secondary', children: "\uD83D\uDD0D" })] }) }), jsx("div", { className: 'overflow-x-auto', children: jsxs("table", { className: "glass-w-full", children: [jsx("thead", { className: "glass-surface-subtle", children: jsx("tr", { children: columns.map(column => jsx("th", { className: cn("glass-px-4 glass-py-3 text-left text-sm font-medium glass-text-secondary", column.sortable && "cursor-pointer hover:bg-muted/80 transition-colors select-none", column.width && `w-${column.width}`), onClick: () => handleSort(column.key), children: jsxs("div", { className: "glass-flex glass-items-center glass-gap-2", children: [column.label, column.sortable && jsxs("div", { className: "glass-flex glass-flex-col", children: [jsx("div", { className: cn("text-xs transition-colors", sortColumn === column.key && sortDirection === "asc" ? "text-primary" : "glass-text-secondary/50"), children: "\u25B2" }), jsx("div", { className: cn("text-xs transition-colors -mt-1", sortColumn === column.key && sortDirection === "desc" ? "text-primary" : "glass-text-secondary/50"), children: "\u25BC" })] })] }) }, String(column.key))) }) }), jsx("tbody", { children: loading ? renderLoadingSkeleton() : paginatedData.length === 0 ? renderEmptyState() : paginatedData.map((item, index) => jsx("tr", { className: 'hover:glass-surface-subtle transition-colors glass-border-b glass-border-glass-border last:border-b-0', children: columns.map(column => jsx("td", { className: "glass-px-4 glass-py-3 glass-text-sm", children: column.render ? column.render(item[column.key], item) : String(item[column.key]) }, String(column.key))) }, index)) })] }) }), renderPagination()] }); } GlassDataTable.displayName = "GlassDataTable"; export { GlassDataTable }; //# sourceMappingURL=GlassDataTable.js.map