import type { ReactNode } from "react"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableCell from "@mui/material/TableCell"; import TableContainer from "@mui/material/TableContainer"; import TableHead from "@mui/material/TableHead"; import TableRow from "@mui/material/TableRow"; import TableSortLabel from "@mui/material/TableSortLabel"; export interface DataColumn { key: string; header: string; align?: "left" | "right"; /** Render the cell with the DM Mono numeric face. */ mono?: boolean; /** Emphasize the cell (font-weight 500). */ bold?: boolean; /** If set, the header becomes a clickable sort control (requires onSort). */ sortKey?: string; render: (row: T) => ReactNode; } export interface DataTableProps { columns: DataColumn[]; rows: T[]; rowKey: (row: T) => string | number; rowInactive?: (row: T) => boolean; empty?: ReactNode; /** Server-sort wiring: active key (matches a column's sortKey), direction, handler. */ sortBy?: string; sortDir?: "asc" | "desc"; onSort?: (key: string) => void; } /** Dense, Soft-SaaS-styled data table. Styling only — never re-formats values. */ export default function DataTable({ columns, rows, rowKey, rowInactive, empty, sortBy, sortDir, onSort, }: DataTableProps) { if (import.meta.env.DEV && columns.some((c) => c.sortKey) && !onSort) { console.warn("DataTable: columns with sortKey require an onSort prop."); } if (rows.length === 0 && empty) return <>{empty}; return ( {columns.map((c) => ( {c.sortKey && onSort ? ( onSort(c.sortKey!)} > {c.header} ) : ( c.header )} ))} {rows.map((row) => ( {columns.map((c) => ( {c.render(row)} ))} ))}
); }