@@ -10,7 +10,7 @@ import {
10
10
EllipsisVerticalIcon ,
11
11
ListFilterIcon ,
12
12
} from "lucide-react" ;
13
- import { memo , useMemo } from "react" ;
13
+ import { memo , useId , useMemo } from "react" ;
14
14
import { Fragment } from "react/jsx-runtime" ;
15
15
import { cn } from "../../lib/utils.js" ;
16
16
import { Button } from "../button/button.js" ;
@@ -62,18 +62,13 @@ function Table<TData>(props: Props<TData>) {
62
62
{ headerGroup . headers . map ( ( header ) => (
63
63
< th
64
64
key = { header . id }
65
- className = "relative p-2 text-left "
65
+ className = "relative p-2 select-none "
66
66
style = { {
67
67
width : `calc(var(--header-${ header ?. id } -size) * 1px)` ,
68
68
} }
69
69
>
70
70
< 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 } />
77
72
78
73
< div className = "flex gap-0.5" >
79
74
< Button size = "tiny-icon" variant = "text" color = "gray" >
@@ -170,6 +165,48 @@ function ResizeHandle({
170
165
) ;
171
166
}
172
167
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
+
173
210
// biome-ignore lint/suspicious/noExplicitAny: We don't care about the type here
174
211
function HeaderMenu ( { header } : { header : Header < any , any > } ) {
175
212
const menuSections = [
0 commit comments