@@ -20,6 +20,7 @@ import type { ThemeProps } from "../types/theme";
20
20
import type {
21
21
Column ,
22
22
DataItem ,
23
+ SelectionState ,
23
24
TableInstanceWithHooks ,
24
25
TableStateWithPagination ,
25
26
} from "../types/types" ;
@@ -43,6 +44,8 @@ export interface MultiLevelTableProps {
43
44
ascendingIcon ?: React . ReactNode ;
44
45
descendingIcon ?: React . ReactNode ;
45
46
expandIcon ?: React . ReactNode ;
47
+ selectable ?: boolean ;
48
+ onSelectionChange ?: ( selectedRows : Set < string | number > ) => void ;
46
49
}
47
50
48
51
/**
@@ -61,9 +64,48 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
61
64
ascendingIcon,
62
65
descendingIcon,
63
66
expandIcon,
67
+ selectable = false ,
68
+ onSelectionChange,
64
69
} ) => {
65
70
const mergedTheme = mergeThemeProps ( defaultTheme , theme ) ;
66
71
const [ filterInput , setFilterInput ] = useState ( "" ) ;
72
+ const [ selectionState , setSelectionState ] = useState < SelectionState > ( {
73
+ selectedRows : new Set ( ) ,
74
+ isAllSelected : false ,
75
+ } ) ;
76
+
77
+ // Get all parent row IDs (level 0)
78
+ const parentRowIds = useMemo ( ( ) => data . map ( item => item . id ) , [ data ] ) ;
79
+
80
+ const handleSelectAll = ( ) => {
81
+ const newIsAllSelected = ! selectionState . isAllSelected ;
82
+ const newSelectedRows = new Set < string | number > ( ) ;
83
+
84
+ if ( newIsAllSelected ) parentRowIds . forEach ( id => newSelectedRows . add ( id ) ) ;
85
+
86
+ setSelectionState ( {
87
+ selectedRows : newSelectedRows ,
88
+ isAllSelected : newIsAllSelected ,
89
+ } ) ;
90
+
91
+ onSelectionChange ?.( newSelectedRows ) ;
92
+ } ;
93
+
94
+ const handleRowSelect = ( rowId : string | number ) => {
95
+ const newSelectedRows = new Set ( selectionState . selectedRows ) ;
96
+
97
+ if ( newSelectedRows . has ( rowId ) ) newSelectedRows . delete ( rowId ) ;
98
+ else newSelectedRows . add ( rowId ) ;
99
+
100
+ const newIsAllSelected = newSelectedRows . size === parentRowIds . length ;
101
+
102
+ setSelectionState ( {
103
+ selectedRows : newSelectedRows ,
104
+ isAllSelected : newIsAllSelected ,
105
+ } ) ;
106
+
107
+ onSelectionChange ?.( newSelectedRows ) ;
108
+ } ;
67
109
68
110
/**
69
111
* Prepares columns configuration for react-table
@@ -84,7 +126,7 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
84
126
value : string | number ;
85
127
} ) => {
86
128
const item = row . original ;
87
-
129
+
88
130
return (
89
131
< div > { col . render ? col . render ( value , item ) : value ?. toString ( ) } </ div >
90
132
) ;
@@ -146,7 +188,7 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
146
188
) as TableInstanceWithHooks < DataItem > ;
147
189
148
190
const rowsMap = useMemo ( ( ) => {
149
- const map = new Map < number , DataItem [ ] > ( ) ;
191
+ const map = new Map < string | number , DataItem [ ] > ( ) ;
150
192
151
193
const processItem = ( item : DataItem ) => {
152
194
if ( item . children ) {
@@ -160,9 +202,9 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
160
202
return map ;
161
203
} , [ data ] ) ;
162
204
163
- const [ expandedRows , setExpandedRows ] = useState < Set < number > > ( new Set ( ) ) ;
205
+ const [ expandedRows , setExpandedRows ] = useState < Set < string | number > > ( new Set ( ) ) ;
164
206
165
- const toggleRow = ( rowId : number ) => {
207
+ const toggleRow = ( rowId : string | number ) => {
166
208
setExpandedRows ( ( prev ) => {
167
209
const newSet = new Set ( prev ) ;
168
210
@@ -175,9 +217,8 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
175
217
} ) ;
176
218
} ;
177
219
178
- const renderNestedRows = ( parentId : number , level = 1 ) => {
220
+ const renderNestedRows = ( parentId : string | number , level = 1 ) => {
179
221
if ( ! expandedRows . has ( parentId ) ) return null ;
180
-
181
222
const children = rowsMap . get ( parentId ) || [ ] ;
182
223
183
224
return children . map ( ( child ) => {
@@ -194,6 +235,8 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
194
235
level = { level }
195
236
theme = { mergedTheme }
196
237
expandIcon = { expandIcon }
238
+ selectable = { false }
239
+ isRowSelected = { false }
197
240
/>
198
241
{ renderNestedRows ( child . id , level + 1 ) }
199
242
</ React . Fragment >
@@ -251,8 +294,12 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
251
294
hasChildren = { hasChildren }
252
295
isExpanded = { expandedRows . has ( parentId ) }
253
296
onToggle = { ( ) => hasChildren && toggleRow ( parentId ) }
297
+ level = { 0 }
254
298
theme = { mergedTheme }
255
299
expandIcon = { expandIcon }
300
+ selectable = { true }
301
+ isRowSelected = { selectionState . selectedRows . has ( row . original . id ) }
302
+ onRowSelect = { handleRowSelect }
256
303
/>
257
304
{ renderNestedRows ( parentId ) }
258
305
</ React . Fragment >
@@ -276,6 +323,9 @@ export const MultiLevelTable: React.FC<MultiLevelTableProps> = ({
276
323
sortable = { sortable }
277
324
ascendingIcon = { ascendingIcon }
278
325
descendingIcon = { descendingIcon }
326
+ selectable = { selectable }
327
+ isAllSelected = { selectionState . isAllSelected }
328
+ onSelectAll = { handleSelectAll }
279
329
/>
280
330
{ renderTableBody ( ) }
281
331
</ table >
0 commit comments