import { Cell, ColumnSort, createColumnHelper, flexRender, getCoreRowModel, getPaginationRowModel, getSortedRowModel, Header, HeaderGroup, PaginationState, Row, RowData, type RowSelectionState, SortingState, TableOptions, useReactTable, type VisibilityState } from '@tanstack/react-table'; import { useState } from 'react'; import DefaultNoData from './DefaultNoData'; import PaginationTools from './PaginationTools'; import SelectAll from './SelectAll'; import SelectRow from './SelectRow'; import SortingIcon from './SortingIcon'; export { createColumnHelper, type ColumnSort, type RowSelectionState, type VisibilityState }; export interface IConditionalStyle { when: (rowData: TData) => boolean style: React.CSSProperties } export interface DataTableProps extends Pick, 'data' | 'columns' | 'onRowSelectionChange' | 'onColumnVisibilityChange' > { dense?: boolean headPosition?: string noHeader?: boolean noFooter?: boolean conditionalRowStyles?: IConditionalStyle[] onRowClicked?: (rowData: TData, event: React.MouseEvent) => void onRowDoubleClicked?: (rowData: TData, event: React.MouseEvent) => void noDataComponent?: React.ReactNode enableRowSelection?: boolean rowSelection?: RowSelectionState enableHiding?: boolean columnVisibility?: VisibilityState enablePagination?: boolean paginationPerPage?: number paginationOptions?: number[] onChangePaginationOption?: (newValue: number) => void enableSorting?: boolean initialSorting?: ColumnSort } /** * UI element: data representation as a table. * * @param headPosition - Top position of sticky header (0 if no other sticky elements are present). * No sticky header if omitted */ export default function DataTable({ dense, headPosition, conditionalRowStyles, noFooter, noHeader, onRowClicked, onRowDoubleClicked, noDataComponent, enableRowSelection, rowSelection, enableHiding, columnVisibility, enableSorting, initialSorting, enablePagination, paginationPerPage=10, paginationOptions=[10, 20, 30, 40, 50], onChangePaginationOption, ...options }: DataTableProps) { const [sorting, setSorting] = useState(initialSorting ? [initialSorting] : []); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: paginationPerPage, }); const tableImpl = useReactTable({ getCoreRowModel: getCoreRowModel(), getSortedRowModel: enableSorting ? getSortedRowModel() : undefined, getPaginationRowModel: enablePagination ? getPaginationRowModel() : undefined, state: { pagination: pagination, sorting: sorting, rowSelection: rowSelection ?? {}, columnVisibility: columnVisibility ?? {} }, enableHiding: enableHiding, onPaginationChange: enablePagination ? setPagination : undefined, onSortingChange: enableSorting ? setSorting : undefined, enableMultiRowSelection: enableRowSelection, ...options }); const isEmpty = tableImpl.getRowModel().rows.length === 0; function getRowStyles(row: Row) { return {...conditionalRowStyles! .filter(item => item.when(row.original)) .reduce((prev, item) => ({...prev, ...item.style}), {}) }; } return (
{ !noHeader && {tableImpl.getHeaderGroups().map( (headerGroup: HeaderGroup) => ( {enableRowSelection && } {headerGroup.headers.map( (header: Header) => ( ))} ))} } {tableImpl.getRowModel().rows.map( (row: Row, index) => ( {enableRowSelection && } {row.getVisibleCells().map( (cell: Cell) => ( ))} ))} {!noFooter && {tableImpl.getFooterGroups().map( (footerGroup: HeaderGroup) => ( {footerGroup.headers.map( (header: Header) => ( ))} ))} }
100 ? 'left': 'center', width: header.getSize(), cursor: enableSorting && header.column.getCanSort() ? 'pointer': 'auto', }} onClick={enableSorting ? header.column.getToggleSortingHandler() : undefined} > {header.isPlaceholder ? null : (
{flexRender(header.column.columnDef.header, header.getContext())} {enableSorting && header.column.getCanSort() && }
)}
onRowClicked && onRowClicked(row.original, event)} onDoubleClick={event => onRowDoubleClicked && onRowDoubleClicked(row.original, event)} > {flexRender(cell.column.columnDef.cell, cell.getContext())}
{header.isPlaceholder ? null : flexRender(header.column.columnDef.footer, header.getContext()) }
{enablePagination && !isEmpty && }
{isEmpty && (noDataComponent ?? )}
); }