import { createColumnHelper, FilterFn, flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable, } from '@tanstack/react-table'; import { ArrowDownIcon, ArrowUpIcon, ChevronDoubleLeftIcon, ChevronDoubleRightIcon, ChevronLeftIcon, ChevronRightIcon, } from '@heroicons/react/24/solid'; import React, { useEffect, useMemo, useState } from 'react'; import parseCsv from '../lib/parseCsv'; import DebouncedInput from './DebouncedInput'; import loadData from '../lib/loadData'; export type TableProps = { data?: Array<{ [key: string]: number | string }>; cols?: Array<{ [key: string]: string }>; csv?: string; url?: string; fullWidth?: boolean; }; export const Table = ({ data: ogData = [], cols: ogCols = [], csv = '', url = '', fullWidth = false, }: TableProps) => { if (csv) { const out = parseCsv(csv); ogData = out.rows; ogCols = out.fields; } const [data, setData] = React.useState(ogData); const [cols, setCols] = React.useState(ogCols); // const [error, setError] = React.useState(""); // TODO: add error handling const tableCols = useMemo(() => { const columnHelper = createColumnHelper(); return cols.map((c) => columnHelper.accessor(c.key, { header: () => c.name, cell: (info) => info.getValue(), }) ); }, [data, cols]); const [globalFilter, setGlobalFilter] = useState(''); const table = useReactTable({ data, columns: tableCols, getCoreRowModel: getCoreRowModel(), state: { globalFilter, }, globalFilterFn: globalFilterFn, onGlobalFilterChange: setGlobalFilter, getFilteredRowModel: getFilteredRowModel(), getPaginationRowModel: getPaginationRowModel(), getSortedRowModel: getSortedRowModel(), }); useEffect(() => { if (url) { loadData(url).then((data) => { const { rows, fields } = parseCsv(data); setData(rows); setCols(fields); }); } }, [url]); return (
setGlobalFilter(String(value))} className="p-2 text-sm shadow border border-block" placeholder="Search all columns..." /> {table.getHeaderGroups().map((hg) => ( {hg.headers.map((h) => ( ))} ))} {table.getRowModel().rows.map((r) => ( {r.getVisibleCells().map((c) => ( ))} ))}
{flexRender(h.column.columnDef.header, h.getContext())} {{ asc: ( ), desc: ( ), }[h.column.getIsSorted() as string] ?? (
)}
{flexRender(c.column.columnDef.cell, c.getContext())}
Page
{table.getState().pagination.pageIndex + 1} of{' '} {table.getPageCount()}
); }; const globalFilterFn: FilterFn = (row, columnId, filterValue: string) => { const search = filterValue.toLowerCase(); let value = row.getValue(columnId) as string; if (typeof value === 'number') value = String(value); return value?.toLowerCase().includes(search); };