"use client"; import { ColumnDef, Row, SortDirection, SortingState, flexRender, getCoreRowModel, getSortedRowModel, useReactTable, } from "@tanstack/react-table"; import { TableCell, TableHead, TableRow } from "@/components/ui/table"; import { HTMLAttributes, forwardRef, useState, useRef, useEffect } from "react"; import { TableVirtuoso } from "react-virtuoso"; import { cn } from "@/lib/utils" import { ScrollArea } from "@/components/ui/scroll-area"; import { useMediaQuery } from "@/hooks/useMediaQuery"; // Original Table is wrapped with a
(see https://ui.shadcn.com/docs/components/table#radix-:r24:-content-manual), // but here we don't want it, so let's use a new component with only tag const TableComponent = forwardRef< HTMLTableElement, React.HTMLAttributes >(({ className, ...props }, ref) => (
)); TableComponent.displayName = "TableComponent"; const TableRowComponent = (rows: Row[]) => function getTableRow(props: HTMLAttributes) { // @ts-expect-error data-index is a valid attribute const index = props["data-index"]; const row = rows[index]; if (!row) return null; return ( {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} ); }; function SortingIndicator({ isSorted }: { isSorted: SortDirection | false }) { if (!isSorted) return null; return (
{ { asc: "↑", desc: "↓", }[isSorted] }
); } interface DataTableProps { columns: ColumnDef[]; data: TData[]; rowComponent?: (rows: Row[]) => (props: HTMLAttributes) => JSX.Element | null, } export function DataTable({ columns, data, rowComponent, }: DataTableProps) { const [sorting, setSorting] = useState([{ id: 'type', desc: true, }]); const table = useReactTable({ data, columns, state: { sorting, }, onSortingChange: setSorting, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), }); const { rows } = table.getRowModel(); const [heightState, setHeight] = useState(0) const ref = useRef(null); const isDesktop = useMediaQuery("(min-width: 640px)"); useEffect(() => { const calculateHeight = () => { if (ref.current) { const virtuosoElement = ref.current; let topOffset = 0; let currentElement = virtuosoElement as any; // Calculate the total offset from the top of the document while (currentElement) { topOffset += currentElement.offsetTop || 0; currentElement = currentElement.offsetParent as HTMLElement; } const totalHeight = window.innerHeight; const calculatedHeight = totalHeight - topOffset; setHeight(calculatedHeight); } }; calculateHeight(); // Initial calculation if (isDesktop) { window.addEventListener('resize', calculateHeight); } return () => { if (isDesktop) window.removeEventListener('resize', calculateHeight); } }, [isDesktop]); return (
table.getHeaderGroups().map((headerGroup) => ( // Change header background color to non-transparent {headerGroup.headers.map((header) => { return ( {header.isPlaceholder ? null : (
{flexRender( header.column.columnDef.header, header.getContext(), )}
)}
); })}
)) } />
); }