import { useRef } from 'react'; import { ColumnDef, flexRender, Row, Table as TableType, } from '@tanstack/react-table'; import { useVirtualizer, VirtualItem, Virtualizer } from '@tanstack/react-virtual'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; interface DataTableProps { table: TableType; columns: ColumnDef[]; emptyMessage?: string; renderRow?: (row: Row, virtualRow: VirtualItem, rowVirtualizer: Virtualizer) => React.ReactNode; } export function DataTable({ table, columns, emptyMessage = 'No results found.', renderRow, }: DataTableProps) { const tableContainerRef = useRef(null); const rows = table.getRowModel().rows; const rowVirtualizer = useVirtualizer({ count: rows.length, getScrollElement: () => tableContainerRef.current, estimateSize: () => 56, overscan: 12, }); const virtualRows = rowVirtualizer.getVirtualItems(); const totalSize = rowVirtualizer.getTotalSize(); const paddingTop = virtualRows.length > 0 ? virtualRows[0].start : 0; const paddingBottom = virtualRows.length > 0 ? totalSize - virtualRows[virtualRows.length - 1].end : 0; const visibleColumnCount = table.getVisibleLeafColumns().length || columns.length || 1; return (
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => { return ( {header.isPlaceholder ? null : flexRender( header.column.columnDef .header, header.getContext(), )} ); })} ))} {rows.length ? ( <> {paddingTop > 0 && ( )} {virtualRows.map((virtualRow) => { const row = rows[virtualRow.index]; if (renderRow) { return renderRow(row, virtualRow, rowVirtualizer); } return ( {row .getVisibleCells() .map((cell) => ( {flexRender( cell.column.columnDef .cell, cell.getContext(), )} ))} ); })} {paddingBottom > 0 && ( )} ) : ( {emptyMessage} )}
); }