1
1
"use client" ;
2
2
3
- import { ColumnDef , flexRender , getCoreRowModel , useReactTable } from "@tanstack/react-table" ;
4
- import React , { useState } from "react" ;
3
+ import React from "react" ;
4
+
5
+ import {
6
+ ColumnDef ,
7
+ CoreOptions ,
8
+ ExpandedState ,
9
+ flexRender ,
10
+ getCoreRowModel ,
11
+ getExpandedRowModel ,
12
+ OnChangeFn ,
13
+ RowSelectionState ,
14
+ SortingState ,
15
+ useReactTable
16
+ } from "@tanstack/react-table" ;
17
+
5
18
import { Table , TableBody , TableCell , TableHead , TableHeader , TableRow } from "./Table" ;
19
+ import { SortableHeader } from "./Sorting" ;
20
+ import { cn } from "../.." ;
6
21
7
22
interface DataTableProps < TData , TValue > {
8
23
columns : ColumnDef < TData , TValue > [ ] ;
9
24
data : TData [ ] ;
25
+ filters ?: Record < string , string > ;
26
+ resetFilters ?: ( ) => void ;
27
+ getRowId ?: CoreOptions < TData > [ "getRowId" ] ;
28
+ rowSelection ?: RowSelectionState ;
29
+ onRowSelectionChange ?: OnChangeFn < RowSelectionState > ;
30
+ sorting ?: SortingState ;
31
+ onSortingChange ?: OnChangeFn < SortingState > ;
32
+ expanded ?: ExpandedState ;
33
+ onExpandedChange ?: OnChangeFn < ExpandedState > ;
34
+ getSubRows ?: ( row : TData ) => TData [ ] ;
10
35
}
11
36
12
- export function DataTable < TData , TValue > ( { columns, data } : DataTableProps < TData , TValue > ) {
13
- const [ rowSelection , setRowSelection ] = useState ( { } ) ;
37
+ export function DataTable < TData , TValue > ( {
38
+ columns,
39
+ data,
40
+ filters,
41
+ resetFilters,
42
+ sorting,
43
+ onSortingChange,
44
+ expanded,
45
+ onExpandedChange,
46
+ getSubRows,
47
+ getRowId,
48
+ rowSelection = { } ,
49
+ onRowSelectionChange
50
+ } : DataTableProps < TData , TValue > ) {
14
51
const table = useReactTable ( {
15
52
data,
16
- columns,
17
- onRowSelectionChange : setRowSelection ,
53
+ columns : columns . map ( ( col ) => {
54
+ // if col.enableSorting is not defined, set it to false
55
+ if ( col . enableSorting === undefined ) {
56
+ col . enableSorting = false ;
57
+ }
58
+ return col ;
59
+ } ) ,
60
+ manualSorting : true ,
61
+ onRowSelectionChange,
62
+ onSortingChange,
63
+ enableSortingRemoval : false ,
64
+ enableMultiSort : false ,
65
+ enableRowSelection : true ,
66
+ onExpandedChange,
67
+ getRowId,
68
+ getSubRows,
18
69
getCoreRowModel : getCoreRowModel ( ) ,
70
+ getExpandedRowModel : getExpandedRowModel ( ) ,
19
71
state : {
20
- rowSelection
72
+ rowSelection,
73
+ sorting,
74
+ expanded
21
75
}
22
76
} ) ;
23
77
@@ -28,16 +82,29 @@ export function DataTable<TData, TValue>({ columns, data }: DataTableProps<TData
28
82
{ table . getHeaderGroups ( ) . map ( ( headerGroup ) => (
29
83
< TableRow key = { headerGroup . id } >
30
84
{ headerGroup . headers . map ( ( header ) => {
85
+ const canSort = header . column . getCanSort ( ) ;
31
86
return (
32
87
< TableHead
33
- className = "text-theme-text-secondary"
88
+ className = { cn (
89
+ header . column . columnDef . meta ?. className ,
90
+ `${
91
+ canSort ? "p-0" : ""
92
+ } bg-theme-surface-tertiary font-semibold text-theme-text-secondary`
93
+ ) }
34
94
key = { header . id }
35
- // @ts -expect-error width doesnt exist on the type, and would need a global fragmentation
36
- style = { { width : header . column . columnDef . meta ?. width || undefined } }
95
+ style = { {
96
+ width : header . column . columnDef . meta ?. width
97
+ } }
37
98
>
38
- { header . isPlaceholder
39
- ? null
40
- : flexRender ( header . column . columnDef . header , header . getContext ( ) ) }
99
+ { canSort ? (
100
+ < SortableHeader header = { header } >
101
+ { header . isPlaceholder
102
+ ? null
103
+ : flexRender ( header . column . columnDef . header , header . getContext ( ) ) }
104
+ </ SortableHeader >
105
+ ) : header . isPlaceholder ? null : (
106
+ flexRender ( header . column . columnDef . header , header . getContext ( ) )
107
+ ) }
41
108
</ TableHead >
42
109
) ;
43
110
} ) }
@@ -53,12 +120,40 @@ export function DataTable<TData, TValue>({ columns, data }: DataTableProps<TData
53
120
data-state = { row . getIsSelected ( ) && "selected" }
54
121
>
55
122
{ row . getVisibleCells ( ) . map ( ( cell ) => (
56
- < TableCell className = "font-medium text-theme-text-primary" key = { cell . id } >
123
+ < TableCell
124
+ className = { cn (
125
+ "font-medium text-theme-text-primary" ,
126
+ cell . column . columnDef . meta ?. className
127
+ ) }
128
+ key = { cell . id }
129
+ >
57
130
{ flexRender ( cell . column . columnDef . cell , cell . getContext ( ) ) }
58
131
</ TableCell >
59
132
) ) }
60
133
</ TableRow >
61
134
) )
135
+ ) : filters && Object . keys ( filters ) . length ? (
136
+ < TableRow >
137
+ < TableCell
138
+ colSpan = { columns . length }
139
+ className = "h-24 bg-theme-surface-primary p-9 text-center"
140
+ >
141
+ < p className = "text-text-lg text-theme-text-secondary" >
142
+ No items match your current selection.
143
+ </ p >
144
+ < p className = "text-text-lg text-theme-text-secondary" >
145
+ Refine your filters and try again.
146
+ </ p >
147
+ < div className = "mt-5" >
148
+ < p
149
+ className = "inline-block cursor-pointer text-text-lg text-theme-text-brand underline"
150
+ onClick = { resetFilters }
151
+ >
152
+ Clear filters
153
+ </ p >
154
+ </ div >
155
+ </ TableCell >
156
+ </ TableRow >
62
157
) : (
63
158
< TableRow >
64
159
< TableCell
0 commit comments