eventx-design-system
Version:
Design System do EventX
193 lines (187 loc) • 7.44 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useState } from 'react';
import styled, { css } from 'styled-components';
import { colors, typography, spacing, borderRadius, transitions, shadows } from '../tokens/design-tokens';
// Container da tabela
const TableContainer = styled.div `
width: 100%;
overflow-x: auto;
border-radius: ${borderRadius.lg};
box-shadow: ${({ variant }) => variant === 'bordered' ? 'none' : shadows.sm};
border: ${({ variant }) => variant === 'bordered' ? `1px solid ${colors.neutral[200]}` : 'none'};
`;
// Tabela
const StyledTable = styled.table `
width: 100%;
border-collapse: collapse;
background-color: ${colors.neutral[50]};
${({ size }) => {
switch (size) {
case 'sm':
return css `
font-size: ${typography.fontSize.sm};
`;
case 'lg':
return css `
font-size: ${typography.fontSize.lg};
`;
default:
return css `
font-size: ${typography.fontSize.base};
`;
}
}}
`;
// Cabeçalho da tabela
const TableHeader = styled.thead `
background-color: ${colors.neutral[100]};
border-bottom: ${({ variant }) => variant === 'bordered' ? `1px solid ${colors.neutral[200]}` : 'none'};
`;
// Célula do cabeçalho
const HeaderCell = styled.th `
padding: ${spacing[3]} ${spacing[4]};
text-align: ${({ align }) => align};
font-family: ${typography.fontFamily.primary};
font-weight: ${typography.fontWeight.semibold};
color: ${colors.neutral[700]};
border-bottom: 1px solid ${colors.neutral[200]};
cursor: ${({ sortable }) => sortable ? 'pointer' : 'default'};
user-select: none;
transition: all ${transitions.duration[200]} ${transitions.easing.inOut};
width: ${({ width }) => width || 'auto'};
${({ sortable }) => sortable &&
css `
&:hover {
background-color: ${colors.neutral[200]};
}
`}
`;
// Ícone de ordenação
const SortIcon = styled.span `
margin-left: ${spacing[1]};
color: ${({ direction }) => direction ? colors.brand.primary[950] : colors.neutral[400]};
transition: all ${transitions.duration[200]} ${transitions.easing.inOut};
${({ direction }) => {
if (direction === 'asc') {
return css `
transform: rotate(180deg);
`;
}
return css `
transform: rotate(0deg);
`;
}}
`;
// Corpo da tabela
const TableBody = styled.tbody `
${({ variant, hoverable }) => {
if (variant === 'striped') {
return css `
tr:nth-child(even) {
background-color: ${colors.neutral[50]};
}
tr:nth-child(odd) {
background-color: ${colors.neutral[100]};
}
`;
}
return css ``;
}}
${({ hoverable }) => hoverable &&
css `
tr:hover {
background-color: ${colors.brand.primary[50]} !important;
}
`}
`;
// Linha da tabela
const TableRow = styled.tr `
border-bottom: ${({ variant }) => variant === 'bordered' ? `1px solid ${colors.neutral[200]}` : 'none'};
transition: all ${transitions.duration[200]} ${transitions.easing.inOut};
${({ selected }) => selected &&
css `
background-color: ${colors.brand.primary[50]} !important;
`}
`;
// Célula da tabela
const TableCell = styled.td `
padding: ${spacing[3]} ${spacing[4]};
text-align: ${({ align }) => align};
font-family: ${typography.fontFamily.secondary};
color: ${colors.neutral[800]};
border-bottom: 1px solid ${colors.neutral[100]};
`;
// Checkbox de seleção
const SelectionCheckbox = styled.input `
width: 16px;
height: 16px;
cursor: pointer;
`;
// Estado de carregamento
const LoadingState = styled.div `
display: flex;
align-items: center;
justify-content: center;
padding: ${spacing[12]};
color: ${colors.neutral[500]};
font-family: ${typography.fontFamily.primary};
`;
// Estado vazio
const EmptyState = styled.div `
display: flex;
align-items: center;
justify-content: center;
padding: ${spacing[12]};
color: ${colors.neutral[500]};
font-family: ${typography.fontFamily.primary};
text-align: center;
`;
export function Table({ data, columns, sortable = false, selectable = false, onRowSelect, onSort, loading = false, emptyMessage = 'Nenhum dado encontrado', size = 'md', variant = 'default', hoverable = true, className, ...props }) {
const [sortKey, setSortKey] = useState(null);
const [sortDirection, setSortDirection] = useState('asc');
const [selectedRows, setSelectedRows] = useState(new Set());
const handleSort = (key) => {
if (!sortable)
return;
const newDirection = sortKey === key && sortDirection === 'asc' ? 'desc' : 'asc';
setSortKey(key);
setSortDirection(newDirection);
onSort?.(key, newDirection);
};
const handleRowSelect = (index, checked) => {
const newSelectedRows = new Set(selectedRows);
if (checked) {
newSelectedRows.add(index);
}
else {
newSelectedRows.delete(index);
}
setSelectedRows(newSelectedRows);
onRowSelect?.(data.filter((_, i) => newSelectedRows.has(i)));
};
const handleSelectAll = (checked) => {
if (checked) {
const allIndices = new Set(data.map((_, index) => index));
setSelectedRows(allIndices);
onRowSelect?.(data);
}
else {
setSelectedRows(new Set());
onRowSelect?.([]);
}
};
const renderCell = (column, row, index) => {
if (column.render) {
return column.render(row[column.key], row, index);
}
const value = row[column.key];
return value != null ? String(value) : '';
};
if (loading) {
return (_jsx(TableContainer, { variant: variant, className: className, ...props, children: _jsx(LoadingState, { children: "Carregando..." }) }));
}
if (data.length === 0) {
return (_jsx(TableContainer, { variant: variant, className: className, ...props, children: _jsx(EmptyState, { children: emptyMessage }) }));
}
return (_jsx(TableContainer, { variant: variant, className: className, ...props, children: _jsxs(StyledTable, { variant: variant, size: size, children: [_jsx(TableHeader, { variant: variant, children: _jsxs("tr", { children: [selectable && (_jsx(HeaderCell, { align: "center", sortable: false, children: _jsx(SelectionCheckbox, { type: "checkbox", checked: selectedRows.size === data.length, onChange: (e) => handleSelectAll(e.target.checked) }) })), columns.map((column) => (_jsxs(HeaderCell, { align: column.align || 'left', sortable: column.sortable || false, width: column.width, onClick: () => handleSort(column.key), children: [column.header, (column.sortable || sortable) && (_jsx(SortIcon, { direction: sortKey === column.key ? sortDirection : null, children: "\u25BC" }))] }, column.key)))] }) }), _jsx(TableBody, { variant: variant, hoverable: hoverable, children: data.map((row, index) => (_jsxs(TableRow, { variant: variant, selected: selectedRows.has(index), children: [selectable && (_jsx(TableCell, { align: "center", children: _jsx(SelectionCheckbox, { type: "checkbox", checked: selectedRows.has(index), onChange: (e) => handleRowSelect(index, e.target.checked) }) })), columns.map((column) => (_jsx(TableCell, { align: column.align || 'left', children: renderCell(column, row, index) }, column.key)))] }, index))) })] }) }));
}