import { useState, type ReactNode } from 'react'; import { Pagination } from '../Pagination/Pagination'; import styles from './Table.module.css'; export interface TableColumn { key: string; header: ReactNode; render: (row: T) => ReactNode; width?: string | number; align?: 'left' | 'center' | 'right'; } export interface TableProps { columns: TableColumn[]; data: T[]; rowKey: (row: T) => string | number; loading?: boolean; emptyMessage?: string; className?: string; /** Enable built-in client-side pagination with this default page size */ pageSize?: number; /** Offer a page-size selector when pagination is enabled */ pageSizeOptions?: number[]; } export function Table({ columns, data, rowKey, loading = false, emptyMessage = 'No data.', className, pageSize: defaultPageSize, pageSizeOptions, }: TableProps) { const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(defaultPageSize ?? 0); const paginated = defaultPageSize !== undefined && !loading; const visibleData = paginated ? data.slice((page - 1) * pageSize, page * pageSize) : data; // Reset to page 1 when data changes and current page would be empty const lastPage = pageSize > 0 ? Math.ceil(data.length / pageSize) : 1; const safePage = Math.min(page, Math.max(1, lastPage)); return (
{columns.map((col) => ( ))} {loading ? ( ) : visibleData.length === 0 ? ( ) : ( visibleData.map((row) => ( {columns.map((col) => ( ))} )) )}
{col.header}
Loading…
{emptyMessage}
{col.render(row)}
{paginated && data.length > 0 && ( { setPageSize(size); setPage(1); } : undefined } pageSizeOptions={pageSizeOptions} /> )}
); }