1
1
import { AriaLabelingProps , GlobalDOMAttributes , HoverEvents , Key , LinkDOMProps , PressEvents , RefObject } from '@react-types/shared' ;
2
- import { BaseCollection , Collection , CollectionBuilder , CollectionNode , createBranchComponent , createLeafComponent , useCachedChildren } from '@react-aria/collections' ;
2
+ import { BaseCollection , Collection , CollectionBuilder , CollectionNode , createBranchComponent , createLeafComponent , filterChildren , useCachedChildren } from '@react-aria/collections' ;
3
3
import { buildHeaderRows , TableColumnResizeState } from '@react-stately/table' ;
4
4
import { ButtonContext } from './Button' ;
5
5
import { CheckboxContext } from './RSPContexts' ;
6
6
import { CollectionProps , CollectionRendererContext , DefaultCollectionRenderer , ItemRenderProps } from './Collection' ;
7
7
import { ColumnSize , ColumnStaticSize , TableCollection as ITableCollection , TableProps as SharedTableProps } from '@react-types/table' ;
8
8
import { ContextValue , DEFAULT_SLOT , DOMProps , Provider , RenderProps , SlotProps , StyleProps , StyleRenderProps , useContextProps , useRenderProps } from './utils' ;
9
- import { DisabledBehavior , DraggableCollectionState , DroppableCollectionState , MultipleSelectionState , Node , SelectionBehavior , SelectionMode , SortDirection , TableState , useMultipleSelectionState , useTableColumnResizeState , useTableState } from 'react-stately' ;
9
+ import { DisabledBehavior , DraggableCollectionState , DroppableCollectionState , MultipleSelectionState , Node , SelectionBehavior , SelectionMode , SortDirection , TableState , UNSTABLE_useFilteredTableState , useMultipleSelectionState , useTableColumnResizeState , useTableState } from 'react-stately' ;
10
10
import { DragAndDropContext , DropIndicatorContext , DropIndicatorProps , useDndPersistedKeys , useRenderDropIndicator } from './DragAndDrop' ;
11
11
import { DragAndDropHooks } from './useDragAndDrop' ;
12
12
import { DraggableItemResult , DragPreviewRenderer , DropIndicatorAria , DroppableCollectionResult , FocusScope , ListKeyboardDelegate , mergeProps , useFocusRing , useHover , useLocale , useLocalizedStringFormatter , useTable , useTableCell , useTableColumnHeader , useTableColumnResize , useTableHeaderRow , useTableRow , useTableRowGroup , useTableSelectAllCheckbox , useTableSelectionCheckbox , useVisuallyHidden } from 'react-aria' ;
@@ -16,6 +16,11 @@ import {GridNode} from '@react-types/grid';
16
16
import intlMessages from '../intl/*.json' ;
17
17
import React , { createContext , ForwardedRef , forwardRef , JSX , ReactElement , ReactNode , useCallback , useContext , useEffect , useMemo , useRef , useState } from 'react' ;
18
18
import ReactDOM from 'react-dom' ;
19
+ import { UNSTABLE_InternalAutocompleteContext } from './Autocomplete' ;
20
+
21
+ export type Mutable < T > = {
22
+ - readonly [ P in keyof T ] : T [ P ]
23
+ }
19
24
20
25
class TableCollection < T > extends BaseCollection < T > implements ITableCollection < T > {
21
26
headerRows : GridNode < T > [ ] = [ ] ;
@@ -160,6 +165,7 @@ class TableCollection<T> extends BaseCollection<T> implements ITableCollection<T
160
165
collection . rowHeaderColumnKeys = this . rowHeaderColumnKeys ;
161
166
collection . head = this . head ;
162
167
collection . body = this . body ;
168
+ // TODO clone updateColumns as well but it is private
163
169
return collection ;
164
170
}
165
171
@@ -190,6 +196,20 @@ class TableCollection<T> extends BaseCollection<T> implements ITableCollection<T
190
196
191
197
return text . join ( ' ' ) ;
192
198
}
199
+
200
+ filter ( filterFn : ( textValue : string ) => boolean ) : TableCollection < T > {
201
+ // TODO: ideally we wouldn't need to reimplement this but we need a TableCollection, not a BaseCollection
202
+ // Also need to handle the fact that a bunch of properites are private
203
+ let clone = this . clone ( ) as Mutable < TableCollection < T > > ;
204
+ // @ts -ignore
205
+ let [ firstKey , lastKey ] = filterChildren ( this , clone , this . firstKey , filterFn ) ;
206
+ // @ts -ignore
207
+ clone . firstKey = firstKey ;
208
+ // @ts -ignore
209
+ clone . lastKey = lastKey ;
210
+ // @ts -ignore
211
+ return clone ;
212
+ }
193
213
}
194
214
195
215
interface ResizableTableContainerContextValue {
@@ -363,23 +383,25 @@ interface TableInnerProps {
363
383
364
384
365
385
function TableInner ( { props, forwardedRef : ref , selectionState, collection} : TableInnerProps ) {
386
+ let { filter} = useContext ( UNSTABLE_InternalAutocompleteContext ) || { } ;
366
387
let tableContainerContext = useContext ( ResizableTableContainerContext ) ;
367
388
ref = useObjectRef ( useMemo ( ( ) => mergeRefs ( ref , tableContainerContext ?. tableRef ) , [ ref , tableContainerContext ?. tableRef ] ) ) ;
368
- let state = useTableState ( {
389
+ let tableState = useTableState ( {
369
390
...props ,
370
391
collection,
371
392
children : undefined ,
372
393
UNSAFE_selectionState : selectionState
373
394
} ) ;
374
395
396
+ let filteredState = UNSTABLE_useFilteredTableState ( tableState , filter ) ;
375
397
let { isVirtualized, layoutDelegate, dropTargetDelegate : ctxDropTargetDelegate , CollectionRoot} = useContext ( CollectionRendererContext ) ;
376
398
let { dragAndDropHooks} = props ;
377
399
let { gridProps} = useTable ( {
378
400
...props ,
379
401
layoutDelegate,
380
402
isVirtualized
381
- } , state , ref ) ;
382
- let selectionManager = state . selectionManager ;
403
+ } , filteredState , ref ) ;
404
+ let selectionManager = filteredState . selectionManager ;
383
405
let hasDragHooks = ! ! dragAndDropHooks ?. useDraggableCollectionState ;
384
406
let hasDropHooks = ! ! dragAndDropHooks ?. useDroppableCollectionState ;
385
407
let dragHooksProvided = useRef ( hasDragHooks ) ;
@@ -405,7 +427,7 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
405
427
406
428
if ( hasDragHooks && dragAndDropHooks ) {
407
429
dragState = dragAndDropHooks . useDraggableCollectionState ! ( {
408
- collection,
430
+ collection : filteredState . collection ,
409
431
selectionManager,
410
432
preview : dragAndDropHooks . renderDragPreview ? preview : undefined
411
433
} ) ;
@@ -419,12 +441,12 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
419
441
420
442
if ( hasDropHooks && dragAndDropHooks ) {
421
443
dropState = dragAndDropHooks . useDroppableCollectionState ! ( {
422
- collection,
444
+ collection : filteredState . collection ,
423
445
selectionManager
424
446
} ) ;
425
447
426
448
let keyboardDelegate = new ListKeyboardDelegate ( {
427
- collection,
449
+ collection : filteredState . collection ,
428
450
disabledKeys : selectionManager . disabledKeys ,
429
451
disabledBehavior : selectionManager . disabledBehavior ,
430
452
ref,
@@ -448,7 +470,7 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
448
470
isDropTarget : isRootDropTarget ,
449
471
isFocused,
450
472
isFocusVisible,
451
- state
473
+ state : filteredState
452
474
}
453
475
} ) ;
454
476
@@ -459,7 +481,7 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
459
481
if ( tableContainerContext ) {
460
482
layoutState = tableContainerContext . useTableColumnResizeState ( {
461
483
tableWidth : tableContainerContext . tableWidth
462
- } , state ) ;
484
+ } , filteredState ) ;
463
485
if ( ! isVirtualized ) {
464
486
style = {
465
487
...style ,
@@ -475,7 +497,7 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
475
497
return (
476
498
< Provider
477
499
values = { [
478
- [ TableStateContext , state ] ,
500
+ [ TableStateContext , filteredState ] ,
479
501
[ TableColumnResizeStateContext , layoutState ] ,
480
502
[ DragAndDropContext , { dragAndDropHooks, dragState, dropState} ] ,
481
503
[ DropIndicatorContext , { render : TableDropIndicatorWrapper } ]
@@ -492,7 +514,7 @@ function TableInner({props, forwardedRef: ref, selectionState, collection}: Tabl
492
514
data-focused = { isFocused || undefined }
493
515
data-focus-visible = { isFocusVisible || undefined } >
494
516
< CollectionRoot
495
- collection = { collection }
517
+ collection = { filteredState . collection }
496
518
scrollRef = { tableContainerContext ?. scrollRef ?? ref }
497
519
persistedKeys = { useDndPersistedKeys ( selectionManager , dragAndDropHooks , dropState ) } />
498
520
</ ElementType >
@@ -552,6 +574,10 @@ class TableHeaderNode extends CollectionNode<any> {
552
574
constructor ( key : Key ) {
553
575
super ( TableHeaderNode . type , key ) ;
554
576
}
577
+
578
+ filter ( ) : CollectionNode < any > | null {
579
+ return this . clone ( ) ;
580
+ }
555
581
}
556
582
557
583
/**
@@ -699,6 +725,10 @@ class TableColumnNode extends CollectionNode<any> {
699
725
constructor ( key : Key ) {
700
726
super ( TableColumnNode . type , key ) ;
701
727
}
728
+
729
+ filter ( ) : CollectionNode < any > | null {
730
+ return this . clone ( ) ;
731
+ }
702
732
}
703
733
704
734
/**
@@ -938,12 +968,17 @@ export interface TableBodyProps<T> extends Omit<CollectionProps<T>, 'disabledKey
938
968
}
939
969
940
970
// TODO: do we need this
971
+ // These should probably be expecting TableCollection, will need to update others
941
972
class TableBodyNode extends CollectionNode < any > {
942
973
static readonly type = 'tablebody' ;
943
974
944
975
constructor ( key : Key ) {
945
976
super ( TableBodyNode . type , key ) ;
946
977
}
978
+
979
+ filter ( collection : BaseCollection < any > , newCollection : BaseCollection < any > , filterFn : ( textValue : string ) => boolean ) : CollectionNode < any > | null {
980
+ return super . filter ( collection , newCollection , filterFn ) ;
981
+ }
947
982
}
948
983
949
984
/**
@@ -1054,6 +1089,19 @@ class TableRowNode extends CollectionNode<any> {
1054
1089
constructor ( key : Key ) {
1055
1090
super ( TableRowNode . type , key ) ;
1056
1091
}
1092
+
1093
+ // TODO: bug is that filtering retains all rows after before the last match
1094
+ filter ( collection : BaseCollection < any > , newCollection : BaseCollection < any > , filterFn : ( textValue : string ) => boolean ) : CollectionNode < any > | null {
1095
+ // todo walk children and if any match, just return whole thing?
1096
+ let cells = collection . getChildren ( this . key ) ;
1097
+ for ( let cell of cells ) {
1098
+ if ( filterFn ( cell . textValue ) ) {
1099
+ return this . clone ( ) ;
1100
+ }
1101
+ }
1102
+
1103
+ return null ;
1104
+ }
1057
1105
}
1058
1106
1059
1107
/**
@@ -1247,6 +1295,10 @@ class TableCellNode extends CollectionNode<any> {
1247
1295
constructor ( key : Key ) {
1248
1296
super ( TableCellNode . type , key ) ;
1249
1297
}
1298
+
1299
+ filter ( ) : CollectionNode < any > | null {
1300
+ return this . clone ( ) ;
1301
+ }
1250
1302
}
1251
1303
1252
1304
/**
@@ -1414,6 +1466,10 @@ class TableLoaderNode extends CollectionNode<any> {
1414
1466
constructor ( key : Key ) {
1415
1467
super ( TableLoaderNode . type , key ) ;
1416
1468
}
1469
+
1470
+ filter ( ) : CollectionNode < any > | null {
1471
+ return this . clone ( ) ;
1472
+ }
1417
1473
}
1418
1474
1419
1475
export const TableLoadMoreItem = createLeafComponent ( TableLoaderNode , function TableLoadingIndicator ( props : TableLoadMoreItemProps , ref : ForwardedRef < HTMLTableRowElement > , item : Node < object > ) {
0 commit comments