@devjpmoreno/mui-datatables
v1.0.31
Published
Uma biblioteca de tabelas de dados baseada em Material-UI com funcionalidades avançadas de filtragem, busca, ordenação e paginação.
Readme
MUI DataTables v2
Uma biblioteca de tabelas de dados baseada em Material-UI com funcionalidades avançadas de filtragem, busca, ordenação e paginação.
Instalação e Configuração
Para rodar o projeto localmente, é necessário realizar algumas alterações no arquivo vite.config. Adicione a propriedade minify: false para desativar a minificação do código, o que facilita o processo de depuração.
Após isso, siga os passos abaixo:
- Execute
npm installpara instalar as dependências. - Em seguida, utilize
npm linkpara criar um link simbólico. - Depois, execute
npx vite build --watchpara que o projeto seja recompilado automaticamente sempre que você salvar as alterações. - Por fim, vá até o repositório onde deseja testar a biblioteca e execute
npm link @devjpmoreno/mui-datatables.
Não se esqueça de recarregar a página após realizar essas etapas.
Uso Básico
import { MuiDataTable } from '@devjpmoreno/mui-datatables';
const columns = [
{ name: 'nome', label: 'Nome' },
{ name: 'idade', label: 'Idade' },
{ name: 'cidade', label: 'Cidade' }
];
const data = [
['João', 25, 'São Paulo'],
['Maria', 30, 'Rio de Janeiro'],
['Pedro', 28, 'Belo Horizonte']
];
const options = {
filterType: 'checkbox',
responsive: 'vertical',
rowsPerPage: 10
};
function App() {
return (
<MuiDataTable
title="Lista de Usuários"
data={data}
columns={columns}
options={options}
/>
);
}Funcionalidades Principais
🔍 Busca e Pesquisa
- Busca Global: Pesquisa em todas as colunas visíveis
- Busca Personalizada: Função
customSearchpara lógica personalizada - Placeholder Configurável: Texto personalizado no campo de busca
- Busca Sempre Visível: Opção
searchAlwaysOpenpara manter o campo sempre aberto
📊 Filtros Avançados
Tipos de Filtro:
checkbox: Seleção múltipla com checkboxesdropdown: Seleção única em dropdownmultiselect: Seleção múltipla em dropdowntextField: Campo de texto livrecustom: Filtros completamente personalizados
Chips de Filtro: Visualização e remoção rápida de filtros ativos
Confirmação de Filtros: Opção
confirmFilterspara aplicar filtros apenas após confirmaçãoReset de Filtros: Botão para limpar todos os filtros
🗂️ Ordenação
- Ordenação por Coluna: Clique nos cabeçalhos para ordenar
- Ordenação Personalizada: Função
customSortpara lógica específica - Direção Inicial: Configuração
sortDescFirstpara começar com ordem decrescente - Reset de Ordenação: Terceiro clique para remover ordenação
📄 Paginação
- Paginação Configurável: Número de linhas por página personalizável
- Opções de Linhas: Array
rowsPerPageOptionspara definir opções - Navegação: Botões de próxima/anterior página
- Labels Personalizados: Textos da paginação configuráveis
👁️ Visualização de Colunas
- Mostrar/Ocultar Colunas: Controle de visibilidade das colunas
- Ordenação de Colunas: Propriedade
columnOrderpara definir ordem - Colunas Fixas: Configurações para colunas fixas
📥 Download e Exportação
- Download CSV: Exportação dos dados em formato CSV
- Filtros de Download:
useDisplayedRowsOnly: Apenas linhas visíveisuseDisplayedColumnsOnly: Apenas colunas visíveis
- Personalização: Função
onDownloadpara controle total
🎨 Customização Visual
- Toolbar Personalizada: Adicione botões e componentes personalizados
- Renderização de Células: Controle total sobre o conteúdo das células
- Cabeçalhos Personalizados: Modificação dos cabeçalhos das colunas
- Rodapé Customizado: Adicione conteúdo personalizado no rodapé
Configuração de Opções
const options = {
// Busca
search: true,
searchAlwaysOpen: false,
searchPlaceholder: 'Buscar...',
// Filtros
filter: true,
filterType: 'checkbox',
confirmFilters: false,
// Ordenação
sort: true,
sortFilterList: true,
sortOrder: { name: 'nome', direction: 'asc' },
// Paginação
pagination: true,
rowsPerPage: 10,
rowsPerPageOptions: [10, 25, 50, 100],
// Visualização
viewColumns: true,
responsive: 'vertical',
// Download
download: true,
downloadOptions: {
filename: 'dados.csv',
separator: ',',
filterOptions: {
useDisplayedRowsOnly: true,
useDisplayedColumnsOnly: true
}
},
// Customização
customToolbar: () => <CustomButton />,
customTableBodyFooterRender: (opts) => <CustomFooter {...opts} />,
// Callbacks
onTableChange: (action, tableState) => {
console.log(action, tableState);
},
onFilterChange: (changedColumn, filterList) => {
console.log('Filtros alterados:', filterList);
},
onColumnSortChange: (columnName, direction) => {
console.log('Ordenação:', columnName, direction);
},
// Textos personalizados
textLabels: {
body: {
noMatch: 'Nenhum registro encontrado'
},
toolbar: {
search: 'Pesquisar',
downloadCsv: 'Baixar CSV',
filter: 'Filtrar',
viewColumns: 'Ver Colunas'
},
pagination: {
next: 'Próxima Página',
previous: 'Página Anterior',
rowsPerPage: 'Linhas por página:',
displayRows: 'de'
}
}
};Configuração de Colunas
const columns = [
{
name: 'nome',
label: 'Nome Completo',
options: {
// Visibilidade
display: true,
viewColumns: true,
// Filtros
filter: true,
filterType: 'textField',
filterList: ['João'], // Filtros iniciais
// Ordenação
sort: true,
sortDescFirst: false,
sortThirdClickReset: true,
// Customização
customBodyRender: (value, tableMeta) => (
<strong>{value}</strong>
),
customHeadRender: (columnMeta) => (
<CustomHeader {...columnMeta} />
),
customHeadLabelRender: (columnMeta) => (
<em>{columnMeta.label}</em>
),
// Propriedades
setCellProps: (value, tableMeta) => ({
style: { backgroundColor: value > 50 ? '#ffcccc' : '#ccffcc' }
}),
setCellHeaderProps: () => ({
style: { fontWeight: 'bold' }
}),
// Outros
hint: 'Dica sobre esta coluna',
download: true,
searchable: true
}
}
];Eventos e Callbacks
Principais Callbacks
const options = {
// Mudanças na tabela
onTableChange: (action, tableState) => {
console.log('Ação:', action); // 'search', 'filter', 'sort', 'changePage', etc.
console.log('Estado:', tableState);
},
// Filtros
onFilterChange: (changedColumn, filterList, type, changedColumnIndex) => {
console.log('Filtro alterado na coluna:', changedColumn);
console.log('Lista de filtros:', filterList);
},
onFilterChipClose: (columnIndex, removedFilter, filterList) => {
console.log('Chip removido:', removedFilter);
},
// Ordenação
onColumnSortChange: (columnName, direction) => {
console.log('Ordenação:', columnName, direction);
},
// Paginação
onChangePage: (currentPage) => {
console.log('Página atual:', currentPage);
},
onChangeRowsPerPage: (numberOfRows) => {
console.log('Linhas por página:', numberOfRows);
},
// Busca
onSearchChange: (searchText) => {
console.log('Texto da busca:', searchText);
},
// Download
onDownload: (buildHead, buildBody, columns, data) => {
console.log('Iniciando download...');
return buildHead(columns) + buildBody(data);
}
};Componentes Personalizados
Toolbar Personalizada
const CustomToolbar = () => (
<div>
<Button variant="contained" color="primary">
Ação Personalizada
</Button>
</div>
);
const options = {
customToolbar: () => <CustomToolbar />
};Rodapé Personalizado
const CustomFooter = ({ data, displayData, columns }) => (
<div style={{ padding: '10px', textAlign: 'center' }}>
<Typography>
Total de registros: {data.length}
</Typography>
</div>
);
const options = {
customTableBodyFooterRender: (opts) => <CustomFooter {...opts} />
};Responsividade
A biblioteca suporta diferentes modos de responsividade:
'vertical': Empilha dados em dispositivos móveis'standard': Comportamento padrão com scroll horizontal'simple': Versão simplificada para dispositivos móveis
Acessibilidade
A biblioteca inclui:
- Suporte completo a leitores de tela
- Navegação por teclado
- Labels ARIA apropriados
- Foco visual consistente
Tipos TypeScript
A biblioteca foi desenvolvida com PropTypes para validação de tipos em tempo de execução, garantindo maior confiabilidade no desenvolvimento.
Contribuição
Para contribuir com o projeto:
- Faça um fork do repositório
- Crie uma branch para sua feature
- Faça commit das suas alterações
- Abra um Pull Request
🌐 Personalização de Textos
A biblioteca permite personalizar todos os textos da interface através da propriedade textLabels e outras configurações específicas.
Configuração Completa de Textos
const options = {
// Placeholder do campo de busca
searchPlaceholder: "Digite para buscar...",
// Configuração de download
downloadOptions: {
filename: "meus-dados.csv",
separator: ",",
},
// Todos os textos customizáveis
textLabels: {
// Textos do corpo da tabela
body: {
noMatch: "Nenhum registro encontrado",
toolTip: "Ordenar coluna",
columnHeaderTooltip: (column) => `Clique para ordenar por ${column.label}`
},
// Textos da barra de ferramentas
toolbar: {
search: "Pesquisar",
downloadCsv: "Baixar em CSV",
filter: "Aplicar Filtros",
viewColumns: "Gerenciar Colunas",
sortAsc: "Ordem Crescente",
sortDesc: "Ordem Decrescente",
sortReset: "Limpar Ordenação"
},
// Textos da paginação
pagination: {
next: "Próxima",
previous: "Anterior",
rowsPerPage: "Registros por página:",
displayRows: "de"
},
// Textos dos filtros
filter: {
all: "Todos",
title: "FILTROS ATIVOS",
type: "Tipo",
value: "Valor",
confirmFilters: "Confirmar",
resetFilters: "Limpar Tudo",
filterList: "Filtros Aplicados"
},
// Textos da visualização de colunas
viewColumns: {
title: "Configurar Colunas",
titleAria: "Exibir/Ocultar Colunas"
}
}
};Textos por Categoria
🔍 Busca e Pesquisa
const options = {
searchPlaceholder: "Buscar dados...",
textLabels: {
toolbar: {
search: "Pesquisar" // Tooltip do botão de busca
}
}
};📊 Filtros
const options = {
textLabels: {
toolbar: {
filter: "Aplicar Filtros" // Tooltip do botão de filtro
},
filter: {
all: "Todos",
title: "FILTROS",
type: "Tipo de Filtro",
value: "Valor do Filtro",
confirmFilters: "Aplicar",
resetFilters: "Resetar",
filterList: "Lista de Filtros"
}
}
};🗂️ Ordenação
const options = {
textLabels: {
body: {
toolTip: "Ordenar",
columnHeaderTooltip: (column) => `Ordenar por ${column.label}`
},
toolbar: {
sortAsc: "Ordenar Crescente",
sortDesc: "Ordenar Decrescente",
sortReset: "Remover Ordenação"
}
}
};📄 Paginação
const options = {
textLabels: {
pagination: {
next: "Próxima Página",
previous: "Página Anterior",
rowsPerPage: "Linhas por página:",
displayRows: "de"
}
}
};👁️ Visualização de Colunas
const options = {
textLabels: {
toolbar: {
viewColumns: "Visualizar Colunas" // Tooltip do botão
},
viewColumns: {
title: "Configurar Colunas",
titleAria: "Mostrar/Ocultar Colunas"
}
}
};📥 Download
const options = {
downloadOptions: {
filename: "dados-exportados.csv",
separator: ";"
},
textLabels: {
toolbar: {
downloadCsv: "Baixar Planilha"
}
}
};📋 Corpo da Tabela
const options = {
textLabels: {
body: {
noMatch: "Nenhum registro encontrado",
toolTip: "Clique para ordenar",
columnHeaderTooltip: (column) => `Ordenar por ${column.label}`
}
}
};⚠️ Tratamento Especial do Filtro "Nenhum"
Quando um filtro do tipo dropdown contém a opção "Nenhum", ela é tratada de forma especial:
- Comportamento: Selecionar "Nenhum" remove todos os filtros daquela coluna
- Resultado: Mostra todos os registros (sem filtro aplicado)
- Compatibilidade: Funciona com
filterOptions.namescustomizados
const columns = [
{
name: 'status',
label: 'Status',
options: {
filterType: 'dropdown',
filterOptions: {
names: ['Ativo', 'Inativo', 'Pendente', 'Cancelado', 'Nenhum']
// "Nenhum" será tratado como "remover filtro"
}
}
}
];Nota: Se você usar filterOptions.names customizados, inclua "Nenhum" na lista para permitir que os usuários removam o filtro daquela coluna.
Textos Fixos (Não Customizáveis)
Alguns textos estão hardcoded nos componentes e não podem ser alterados via configuração:
| Componente | Texto Fixo | Localização | |------------|------------|-------------| | TableFilter | "Filtros" | Título do popup de filtros | | TableFilter | "Resetar" | Botão resetar no popup | | TableFilter | "X selecionados" | Texto do multiselect | | TableFilter | "Filtrar [coluna]" | Placeholder dos campos | | TableViewColumns | "Visualizar colunas" | Título do popup | | TableToolbarSelect | "10 linhas selecionadas" | Exemplo de seleção | | TableFilter | "Nenhum" | Opção padrão em dropdowns |
Exemplo de Personalização Completa
import { MuiDataTable } from '@devjpmoreno/mui-datatables';
const data = [
['João Silva', 'Desenvolvedor', 'São Paulo'],
['Maria Santos', 'Designer', 'Rio de Janeiro']
];
const columns = [
{ name: 'nome', label: 'Nome Completo' },
{ name: 'cargo', label: 'Cargo' },
{ name: 'cidade', label: 'Cidade' }
];
const options = {
searchPlaceholder: "Buscar funcionários...",
downloadOptions: {
filename: "funcionarios.csv",
separator: ";"
},
textLabels: {
body: {
noMatch: "Nenhum funcionário encontrado",
toolTip: "Clique para ordenar esta coluna"
},
toolbar: {
search: "Buscar Funcionários",
downloadCsv: "Exportar para Excel",
filter: "Filtrar Dados",
viewColumns: "Configurar Colunas Visíveis"
},
pagination: {
next: "Próxima",
previous: "Anterior",
rowsPerPage: "Funcionários por página:",
displayRows: "de"
},
filter: {
all: "Todos os Valores",
title: "FILTROS ATIVOS",
confirmFilters: "Aplicar Filtros",
resetFilters: "Limpar Filtros"
},
viewColumns: {
title: "Gerenciar Colunas",
titleAria: "Mostrar ou Ocultar Colunas"
}
}
};
function App() {
return (
<MuiDataTable
title="Lista de Funcionários"
data={data}
columns={columns}
options={options}
/>
);
}Dicas de Personalização
- Consistência: Mantenha um padrão de linguagem em todos os textos
- Contexto: Adapte os textos ao contexto da sua aplicação
- Acessibilidade: Use textos descritivos nos tooltips e labels ARIA
- Idioma: Configure todos os textos no mesmo idioma
- Brevidade: Mantenha os textos concisos, especialmente nos tooltips
🎛️ Filtros Avançados com filterOptions
A biblioteca suporta configurações avançadas de filtro através da propriedade filterOptions nas colunas, permitindo valores customizados, lógica personalizada e renderização customizada.
Valores Customizados (filterOptions.names)
const columns = [
{
name: 'status',
label: 'Status',
options: {
filterType: 'dropdown',
filterOptions: {
names: ['Ativo', 'Inativo', 'Pendente', 'Cancelado']
}
}
},
{
name: 'prioridade',
label: 'Prioridade',
options: {
filterType: 'checkbox',
filterOptions: {
names: ['Alta', 'Média', 'Baixa']
}
}
}
];Lógica Customizada de Filtro (filterOptions.logic)
const columns = [
{
name: 'idade',
label: 'Idade',
options: {
filterType: 'dropdown',
filterOptions: {
names: ['Menor que 18', '18-30', '31-50', 'Maior que 50'],
logic: (value, filters, row) => {
const idade = parseInt(value);
return filters.some(filter => {
switch (filter) {
case 'Menor que 18':
return idade < 18;
case '18-30':
return idade >= 18 && idade <= 30;
case '31-50':
return idade >= 31 && idade <= 50;
case 'Maior que 50':
return idade > 50;
default:
return false;
}
});
}
}
}
}
];Renderização Customizada (filterOptions.display)
const columns = [
{
name: 'dataVencimento',
label: 'Data de Vencimento',
options: {
filterType: 'custom',
filterOptions: {
display: (filterList, onChange, column, index) => {
const [dataInicio, dataFim] = filterList || ['', ''];
return (
<div>
<TextField
label="Data Início"
type="date"
value={dataInicio}
onChange={(e) => onChange('custom', index, [e.target.value, dataFim])}
InputLabelProps={{ shrink: true }}
/>
<TextField
label="Data Fim"
type="date"
value={dataFim}
onChange={(e) => onChange('custom', index, [dataInicio, e.target.value])}
InputLabelProps={{ shrink: true }}
style={{ marginLeft: 8 }}
/>
</div>
);
},
logic: (value, filters) => {
const [dataInicio, dataFim] = filters || ['', ''];
if (!dataInicio && !dataFim) return true;
const dataValue = new Date(value);
const inicio = dataInicio ? new Date(dataInicio) : null;
const fim = dataFim ? new Date(dataFim) : null;
if (inicio && fim) {
return dataValue >= inicio && dataValue <= fim;
} else if (inicio) {
return dataValue >= inicio;
} else if (fim) {
return dataValue <= fim;
}
return true;
}
}
}
}
];Array Simples (filterOptions como array)
const columns = [
{
name: 'categoria',
label: 'Categoria',
options: {
filterType: 'multiselect',
filterOptions: ['Eletrônicos', 'Roupas', 'Casa', 'Livros', 'Esportes']
}
}
];Exemplo Completo com Múltiplos Tipos de Filtro
import { MuiDataTable } from '@devjpmoreno/mui-datatables';
import { TextField, Slider, Typography } from '@mui/material';
const data = [
['João Silva', 25, 'Ativo', 'Alta', '2024-01-15', 'Eletrônicos'],
['Maria Santos', 32, 'Inativo', 'Média', '2024-02-20', 'Roupas'],
['Pedro Costa', 19, 'Pendente', 'Baixa', '2024-03-10', 'Casa']
];
// Exemplo com filtro "Nenhum" funcional
const columnsSimples = [
{
name: 'status',
label: 'Status',
options: {
filterType: 'dropdown',
filterOptions: {
names: ['Ativo', 'Inativo', 'Pendente', 'Nenhum'] // "Nenhum" remove o filtro
}
}
}
];
const columns = [
{
name: 'nome',
label: 'Nome',
options: {
filterType: 'textField'
}
},
{
name: 'idade',
label: 'Idade',
options: {
filterType: 'custom',
filterOptions: {
display: (filterList, onChange, column, index) => {
const [min, max] = filterList || [18, 65];
return (
<div>
<Typography>Idade: {min} - {max}</Typography>
<Slider
value={[min, max]}
onChange={(e, newValue) => onChange('custom', index, newValue)}
valueLabelDisplay="auto"
min={0}
max={100}
style={{ width: 200 }}
/>
</div>
);
},
logic: (value, filters) => {
const [min, max] = filters || [0, 100];
const idade = parseInt(value);
return idade >= min && idade <= max;
}
}
}
},
{
name: 'status',
label: 'Status',
options: {
filterType: 'dropdown',
filterOptions: {
names: ['Ativo', 'Inativo', 'Pendente', 'Cancelado']
}
}
},
{
name: 'prioridade',
label: 'Prioridade',
options: {
filterType: 'checkbox',
filterOptions: {
names: ['Alta', 'Média', 'Baixa']
}
}
},
{
name: 'dataVencimento',
label: 'Data de Vencimento',
options: {
filterType: 'custom',
filterOptions: {
display: (filterList, onChange, column, index) => {
const [dataInicio, dataFim] = filterList || ['', ''];
return (
<div>
<TextField
label="Data Início"
type="date"
value={dataInicio}
onChange={(e) => onChange('custom', index, [e.target.value, dataFim])}
InputLabelProps={{ shrink: true }}
size="small"
/>
<TextField
label="Data Fim"
type="date"
value={dataFim}
onChange={(e) => onChange('custom', index, [dataInicio, e.target.value])}
InputLabelProps={{ shrink: true }}
size="small"
style={{ marginLeft: 8 }}
/>
</div>
);
},
logic: (value, filters) => {
const [dataInicio, dataFim] = filters || ['', ''];
if (!dataInicio && !dataFim) return true;
const dataValue = new Date(value);
const inicio = dataInicio ? new Date(dataInicio) : null;
const fim = dataFim ? new Date(dataFim) : null;
if (inicio && fim) {
return dataValue >= inicio && dataValue <= fim;
} else if (inicio) {
return dataValue >= inicio;
} else if (fim) {
return dataValue <= fim;
}
return true;
}
}
}
},
{
name: 'categoria',
label: 'Categoria',
options: {
filterType: 'multiselect',
filterOptions: ['Eletrônicos', 'Roupas', 'Casa', 'Livros', 'Esportes']
}
}
];
const options = {
filterType: 'checkbox',
responsive: 'vertical',
selectableRows: 'none'
};
function App() {
return (
<MuiDataTable
title="Exemplo de Filtros Avançados"
data={data}
columns={columns}
options={options}
/>
);
}Tipos de filterOptions Suportados
| Tipo | Descrição | Exemplo |
|------|-----------|---------|
| names | Array de valores customizados para o filtro | ['Ativo', 'Inativo'] |
| logic | Função customizada para lógica de filtro | (value, filters, row) => {...} |
| display | Função para renderização customizada | (filterList, onChange, column, index) => {...} |
| Array simples | Array direto de valores | ['Valor1', 'Valor2'] |
Parâmetros das Funções
filterOptions.logic
logic: (value, filters, row) => {
// value: valor da célula atual
// filters: array de filtros ativos para esta coluna
// row: linha completa de dados
// retorna: boolean (true se deve incluir a linha)
}filterOptions.display
display: (filterList, onChange, column, index) => {
// filterList: valores atuais do filtro para esta coluna
// onChange: função para atualizar o filtro
// column: objeto da coluna
// index: índice da coluna
// retorna: JSX element
}Licença
Este projeto está licenciado sob a MIT License.
