Skip to content

Commit 126ab46

Browse files
committed
feat: make header titles toggle sort
1 parent 15b9d9f commit 126ab46

File tree

2 files changed

+50
-10
lines changed

2 files changed

+50
-10
lines changed

packages/ui-react/src/components/table/table-test.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type Attendee = {
1616

1717
const defaultData: Attendee[] = [
1818
{ firstName: "Alice", lastName: "Smith", role: "scout" },
19-
{ firstName: "Bob", lastName: "Johnson", role: "leader" },
19+
{ firstName: "Bob", lastName: "Abraham", role: "leader" },
2020
{ firstName: "Charlie", lastName: "Brown", role: "volunteer" },
2121
];
2222

@@ -25,13 +25,15 @@ const columnHelper = createColumnHelper<Attendee>();
2525
const columns = [
2626
columnHelper.accessor("firstName", {
2727
header: () => "Förnamn",
28+
size: 200,
2829
}),
2930
columnHelper.accessor("lastName", {
3031
header: () => "Efternamn",
31-
enableSorting: false,
32+
size: 200,
3233
}),
3334
columnHelper.accessor("role", {
3435
header: () => "Roll",
36+
enableSorting: false,
3537
cell: (info) => {
3638
const role = info.getValue();
3739
return role.charAt(0).toUpperCase() + role.slice(1);
@@ -58,6 +60,7 @@ function TableTest() {
5860
{
5961
// columnSizing: table.getState().columnSizing,
6062
// columnSizeVars,
63+
sort: table.getState().sorting,
6164
},
6265
null,
6366
2,

packages/ui-react/src/components/table/table.tsx

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
EllipsisVerticalIcon,
1111
ListFilterIcon,
1212
} from "lucide-react";
13-
import { memo, useMemo } from "react";
13+
import { memo, useId, useMemo } from "react";
1414
import { Fragment } from "react/jsx-runtime";
1515
import { cn } from "../../lib/utils.js";
1616
import { Button } from "../button/button.js";
@@ -62,18 +62,13 @@ function Table<TData>(props: Props<TData>) {
6262
{headerGroup.headers.map((header) => (
6363
<th
6464
key={header.id}
65-
className="relative p-2 text-left"
65+
className="relative p-2 select-none"
6666
style={{
6767
width: `calc(var(--header-${header?.id}-size) * 1px)`,
6868
}}
6969
>
7070
<div className="flex justify-between pr-1">
71-
{header.isPlaceholder
72-
? null
73-
: flexRender(
74-
header.column.columnDef.header,
75-
header.getContext(),
76-
)}
71+
<HeaderTitle header={header} />
7772

7873
<div className="flex gap-0.5">
7974
<Button size="tiny-icon" variant="text" color="gray">
@@ -170,6 +165,48 @@ function ResizeHandle({
170165
);
171166
}
172167

168+
// biome-ignore lint/suspicious/noExplicitAny: We don't care about the type here
169+
function HeaderTitle({ header }: { header: Header<any, any> }) {
170+
const sortDescriptionId = useId();
171+
172+
if (header.isPlaceholder) {
173+
return null;
174+
}
175+
176+
const rendered = flexRender(
177+
header.column.columnDef.header,
178+
header.getContext(),
179+
);
180+
181+
if (!header.column.getCanSort()) {
182+
return rendered;
183+
}
184+
185+
return (
186+
<>
187+
<button
188+
type="button"
189+
className={cn("flex-1 flex items-center gap-1 cursor-pointer")}
190+
onClick={header.column.getToggleSortingHandler()}
191+
aria-describedby={sortDescriptionId}
192+
>
193+
{rendered}
194+
195+
{header.column.getIsSorted() === "asc" && (
196+
<ArrowUpIcon className="size-4" />
197+
)}
198+
{header.column.getIsSorted() === "desc" && (
199+
<ArrowDownIcon className="size-4" />
200+
)}
201+
</button>
202+
203+
<p id={sortDescriptionId} hidden>
204+
Toggle column sorting
205+
</p>
206+
</>
207+
);
208+
}
209+
173210
// biome-ignore lint/suspicious/noExplicitAny: We don't care about the type here
174211
function HeaderMenu({ header }: { header: Header<any, any> }) {
175212
const menuSections = [

0 commit comments

Comments
 (0)