feat(mui): kit — sortable DataTable headers (TableSortLabel), additive
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ import TableCell from "@mui/material/TableCell";
|
|||||||
import TableContainer from "@mui/material/TableContainer";
|
import TableContainer from "@mui/material/TableContainer";
|
||||||
import TableHead from "@mui/material/TableHead";
|
import TableHead from "@mui/material/TableHead";
|
||||||
import TableRow from "@mui/material/TableRow";
|
import TableRow from "@mui/material/TableRow";
|
||||||
|
import TableSortLabel from "@mui/material/TableSortLabel";
|
||||||
|
|
||||||
export interface DataColumn<T> {
|
export interface DataColumn<T> {
|
||||||
key: string;
|
key: string;
|
||||||
@@ -14,6 +15,8 @@ export interface DataColumn<T> {
|
|||||||
mono?: boolean;
|
mono?: boolean;
|
||||||
/** Emphasize the cell (font-weight 500). */
|
/** Emphasize the cell (font-weight 500). */
|
||||||
bold?: boolean;
|
bold?: boolean;
|
||||||
|
/** If set, the header becomes a clickable sort control (requires onSort). */
|
||||||
|
sortKey?: string;
|
||||||
render: (row: T) => ReactNode;
|
render: (row: T) => ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,6 +26,10 @@ export interface DataTableProps<T> {
|
|||||||
rowKey: (row: T) => string | number;
|
rowKey: (row: T) => string | number;
|
||||||
rowInactive?: (row: T) => boolean;
|
rowInactive?: (row: T) => boolean;
|
||||||
empty?: ReactNode;
|
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. */
|
/** Dense, Soft-SaaS-styled data table. Styling only — never re-formats values. */
|
||||||
@@ -32,6 +39,9 @@ export default function DataTable<T>({
|
|||||||
rowKey,
|
rowKey,
|
||||||
rowInactive,
|
rowInactive,
|
||||||
empty,
|
empty,
|
||||||
|
sortBy,
|
||||||
|
sortDir,
|
||||||
|
onSort,
|
||||||
}: DataTableProps<T>) {
|
}: DataTableProps<T>) {
|
||||||
if (rows.length === 0 && empty) return <>{empty}</>;
|
if (rows.length === 0 && empty) return <>{empty}</>;
|
||||||
return (
|
return (
|
||||||
@@ -43,6 +53,9 @@ export default function DataTable<T>({
|
|||||||
<TableCell
|
<TableCell
|
||||||
key={c.key}
|
key={c.key}
|
||||||
align={c.align}
|
align={c.align}
|
||||||
|
sortDirection={
|
||||||
|
c.sortKey && sortBy === c.sortKey ? sortDir : false
|
||||||
|
}
|
||||||
sx={{
|
sx={{
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
letterSpacing: ".05em",
|
letterSpacing: ".05em",
|
||||||
@@ -50,8 +63,20 @@ export default function DataTable<T>({
|
|||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
color: "text.secondary",
|
color: "text.secondary",
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
{c.sortKey && onSort ? (
|
||||||
|
<TableSortLabel
|
||||||
|
active={sortBy === c.sortKey}
|
||||||
|
direction={
|
||||||
|
sortBy === c.sortKey ? (sortDir ?? "asc") : "asc"
|
||||||
|
}
|
||||||
|
onClick={() => onSort(c.sortKey!)}
|
||||||
>
|
>
|
||||||
{c.header}
|
{c.header}
|
||||||
|
</TableSortLabel>
|
||||||
|
) : (
|
||||||
|
c.header
|
||||||
|
)}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
))}
|
))}
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|||||||
Reference in New Issue
Block a user