Table Sortable Columns
src / Demo.tsx
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111import React, { ReactElement, useState } from "react";
import { upperFirst } from "lodash";
import {
TableContainer,
Table,
TableHeader,
TableRow,
TableCell,
TableBody,
} from "@react-md/table";
import desserts, { Dessert } from "./desserts";
type DessertKey = keyof Dessert;
type SortOrder = "ascending" | "descending";
interface SortState {
data: readonly Dessert[];
sortKey: DessertKey;
sortOrder: SortOrder;
}
const columns = Object.keys(desserts[0]) as DessertKey[];
const sort = (key: DessertKey, ascending: boolean): readonly Dessert[] => {
const sorted = desserts.slice();
sorted.sort((a, b) => {
const aValue = a[key];
const bValue = b[key];
const value =
typeof aValue === "number"
? aValue - (bValue as number)
: aValue.localeCompare(bValue as string);
return value * (ascending ? 1 : -1);
});
return sorted;
};
export default function Demo(): ReactElement {
const [state, setState] = useState<SortState>(() => ({
data: sort("name", true),
sortKey: "name",
sortOrder: "ascending",
}));
const update = (sortKey: DessertKey): void => {
setState((prevState) => {
const prevSortKey = prevState.sortKey;
const prevSortOrder = prevState.sortOrder;
let sortOrder: SortOrder;
if (sortKey === prevSortKey) {
sortOrder = prevSortOrder === "ascending" ? "descending" : "ascending";
} else {
sortOrder = sortKey === "name" ? "ascending" : "descending";
}
return {
data: sort(sortKey, sortOrder === "ascending"),
sortKey,
sortOrder,
};
});
};
const { data, sortKey, sortOrder } = state;
return (
<TableContainer>
<Table fullWidth>
<TableHeader>
<TableRow>
{columns.map((name) => (
<TableCell
key={name}
aria-sort={name === sortKey ? sortOrder : "none"}
onClick={() => update(name)}
>
{upperFirst(name)}
</TableCell>
))}
</TableRow>
</TableHeader>
<TableBody>
{data.map((dessert) => (
<TableRow key={dessert.name}>
{columns.map((key) => (
<TableCell
key={key}
grow={key === "name"}
hAlign={
typeof dessert[key] === "number" ? "right" : undefined
}
>
{dessert[key]}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}