@@ -66,6 +66,14 @@ export const useCombobox = <
66
66
altKey ?: boolean ;
67
67
}
68
68
69
+ interface ICacheState {
70
+ values : OptionValue [ ] ;
71
+ labels : Record < string , string > ;
72
+ selectedValues : OptionValue [ ] ;
73
+ disabledValues : OptionValue [ ] ;
74
+ hiddenValues : OptionValue [ ] ;
75
+ }
76
+
69
77
const [ triggerContainsInput , setTriggerContainsInput ] = useState < boolean > ( ) ;
70
78
const [ downshiftInputValue , setDownshiftInputValue ] = useState ( inputValue ) ;
71
79
const [ matchValue , setMatchValue ] = useState ( '' ) ;
@@ -83,42 +91,44 @@ export const useCombobox = <
83
91
getOptionId : ( index : number , isDisabled ?: boolean , isHidden ?: boolean ) =>
84
92
`${ prefix } --option${ isDisabled ? '-disabled' : '' } ${ isHidden ? '-hidden' : '' } -${ index } `
85
93
} ) ;
86
- const labels : Record < string , string > = useMemo ( ( ) => ( { } ) , [ ] ) ;
87
- const selectedValues : OptionValue [ ] = useMemo ( ( ) => [ ] , [ ] ) ;
88
- const disabledValues : OptionValue [ ] = useMemo ( ( ) => [ ] , [ ] ) ;
89
- const hiddenValues : OptionValue [ ] = useMemo ( ( ) => [ ] , [ ] ) ;
90
- const values = useMemo ( ( ) => {
91
- const retVal : OptionValue [ ] = [ ] ;
94
+ const cache = useMemo ( ( ) => {
95
+ const retVal : ICacheState = {
96
+ values : [ ] ,
97
+ labels : { } ,
98
+ selectedValues : [ ] ,
99
+ disabledValues : [ ] ,
100
+ hiddenValues : [ ]
101
+ } ;
92
102
const setValues = ( option : IOption ) => {
93
103
if ( option . disabled || option . hidden ) {
94
- if ( option . disabled && ! disabledValues . includes ( option . value ) ) {
95
- disabledValues . push ( option . value ) ;
104
+ if ( option . disabled && ! retVal . disabledValues . includes ( option . value ) ) {
105
+ retVal . disabledValues . push ( option . value ) ;
96
106
}
97
107
98
- if ( option . hidden && ! hiddenValues . includes ( option . value ) ) {
99
- hiddenValues . push ( option . value ) ;
108
+ if ( option . hidden && ! retVal . hiddenValues . includes ( option . value ) ) {
109
+ retVal . hiddenValues . push ( option . value ) ;
100
110
}
101
111
} else {
102
- retVal . push ( option . value ) ;
112
+ retVal . values . push ( option . value ) ;
103
113
104
- const disabledIndex = disabledValues . indexOf ( option . value ) ;
114
+ const disabledIndex = retVal . disabledValues . indexOf ( option . value ) ;
105
115
106
116
if ( disabledIndex !== - 1 ) {
107
- disabledValues . splice ( disabledIndex , 1 ) ;
117
+ retVal . disabledValues . splice ( disabledIndex , 1 ) ;
108
118
}
109
119
110
- const hiddenIndex = hiddenValues . indexOf ( option . value ) ;
120
+ const hiddenIndex = retVal . hiddenValues . indexOf ( option . value ) ;
111
121
112
122
if ( hiddenIndex !== - 1 ) {
113
- hiddenValues . splice ( hiddenIndex , 1 ) ;
123
+ retVal . hiddenValues . splice ( hiddenIndex , 1 ) ;
114
124
}
115
125
}
116
126
117
- if ( option . selected && ! selectedValues . includes ( option . value ) ) {
118
- selectedValues . push ( option . value ) ;
127
+ if ( option . selected && ! retVal . selectedValues . includes ( option . value ) ) {
128
+ retVal . selectedValues . push ( option . value ) ;
119
129
}
120
130
121
- labels [ option . value ] = option . label || option . value ;
131
+ retVal . labels [ option . value ] = option . label || option . value ;
122
132
} ;
123
133
124
134
options . forEach ( option => {
@@ -130,11 +140,11 @@ export const useCombobox = <
130
140
} ) ;
131
141
132
142
return retVal ;
133
- } , [ options , disabledValues , hiddenValues , selectedValues , labels ] ) ;
134
- const initialSelectionValue = isMultiselectable ? selectedValues : selectedValues [ 0 ] ;
143
+ } , [ options ] ) ;
144
+ const initialSelectionValue = isMultiselectable ? cache . selectedValues : cache . selectedValues [ 0 ] ;
135
145
const initialInputValue = isMultiselectable
136
146
? ''
137
- : toLabel ( labels , initialSelectionValue as string ) ;
147
+ : toLabel ( cache . labels , initialSelectionValue as string ) ;
138
148
const _defaultActiveIndex = useMemo ( ( ) => {
139
149
if ( defaultActiveIndex === undefined ) {
140
150
return isAutocomplete && isEditable ? 0 : undefined ;
@@ -155,7 +165,7 @@ export const useCombobox = <
155
165
*/
156
166
157
167
if ( selectionValue === undefined || selectionValue === null ) {
158
- if ( ! isMultiselectable && selectedValues . length > 1 ) {
168
+ if ( ! isMultiselectable && cache . selectedValues . length > 1 ) {
159
169
throw new Error ( 'Error: expected useCombobox `options` to have no more than one selected.' ) ;
160
170
}
161
171
}
@@ -240,7 +250,7 @@ export const useCombobox = <
240
250
// Fix Downshift standard last option activation on listbox
241
251
// expansion. Addresses problems with initial multiselectable and
242
252
// overeager `defaultActiveIndex` comboboxes.
243
- changes . highlightedIndex = values . length - 1 ;
253
+ changes . highlightedIndex = cache . values . length - 1 ;
244
254
}
245
255
246
256
break ;
@@ -297,7 +307,7 @@ export const useCombobox = <
297
307
return changes ;
298
308
} ;
299
309
300
- const transformValue = ( value : OptionValue | null ) => ( value ? toLabel ( labels , value ) : '' ) ;
310
+ const transformValue = ( value : OptionValue | null ) => ( value ? toLabel ( cache . labels , value ) : '' ) ;
301
311
302
312
/** Hooks */
303
313
@@ -318,7 +328,7 @@ export const useCombobox = <
318
328
toggleButtonId : idRef . current . trigger ,
319
329
menuId : idRef . current . listbox ,
320
330
getItemId : idRef . current . getOptionId ,
321
- items : values ,
331
+ items : cache . values ,
322
332
inputValue : downshiftInputValue ,
323
333
initialInputValue,
324
334
itemToString : transformValue as any /* HACK around Downshift's generic type overuse */ ,
@@ -394,7 +404,7 @@ export const useCombobox = <
394
404
_selectionValue . length - 1 // multiselectable most recent
395
405
]
396
406
: _selectionValue ;
397
- const index = values . findIndex ( current => current === value ) ;
407
+ const index = cache . values . findIndex ( current => current === value ) ;
398
408
399
409
if ( index !== - 1 ) {
400
410
setActiveIndex ( index ) ;
@@ -410,7 +420,7 @@ export const useCombobox = <
410
420
_isExpanded ,
411
421
_selectionValue ,
412
422
_inputValue ,
413
- values ,
423
+ cache . values ,
414
424
_defaultActiveIndex ,
415
425
setActiveIndex
416
426
]
@@ -522,7 +532,7 @@ export const useCombobox = <
522
532
event . preventDefault ( ) ;
523
533
524
534
if ( _activeIndex !== - 1 ) {
525
- setDownshiftSelection ( values [ _activeIndex ] ) ;
535
+ setDownshiftSelection ( cache . values [ _activeIndex ] ) ;
526
536
}
527
537
528
538
if ( ! isMultiselectable ) {
@@ -551,15 +561,17 @@ export const useCombobox = <
551
561
: _selectionValue ;
552
562
553
563
if ( offsetValue !== null ) {
554
- offset = values . findIndex ( current => current === offsetValue ) ;
564
+ offset = cache . values . findIndex ( current => current === offsetValue ) ;
555
565
}
556
566
}
557
567
558
- for ( let index = 0 ; index < values . length ; index ++ ) {
559
- const valueIndex = ( index + offset ) % values . length ;
560
- const value = values [ valueIndex ] ;
568
+ for ( let index = 0 ; index < cache . values . length ; index ++ ) {
569
+ const valueIndex = ( index + offset ) % cache . values . length ;
570
+ const value = cache . values [ valueIndex ] ;
561
571
562
- if ( toLabel ( labels , value ) . toLowerCase ( ) . startsWith ( _matchValue . toLowerCase ( ) ) ) {
572
+ if (
573
+ toLabel ( cache . labels , value ) . toLowerCase ( ) . startsWith ( _matchValue . toLowerCase ( ) )
574
+ ) {
563
575
setActiveIndex ( valueIndex ) ;
564
576
break ;
565
577
}
@@ -596,8 +608,8 @@ export const useCombobox = <
596
608
setActiveIndex ,
597
609
setDownshiftSelection ,
598
610
matchValue ,
599
- values ,
600
- labels ,
611
+ cache . values ,
612
+ cache . labels ,
601
613
triggerContainsInput ,
602
614
isAutocomplete ,
603
615
isEditable ,
@@ -840,7 +852,7 @@ export const useCombobox = <
840
852
'aria-selected' : ariaSelected ,
841
853
id : option
842
854
? idRef . current . getOptionId (
843
- hiddenValues . indexOf ( option . value ) ,
855
+ cache . hiddenValues . indexOf ( option . value ) ,
844
856
option . disabled ,
845
857
option . hidden
846
858
)
@@ -858,7 +870,7 @@ export const useCombobox = <
858
870
'aria-selected' : ariaSelected ,
859
871
id : option
860
872
? idRef . current . getOptionId (
861
- disabledValues . indexOf ( option . value ) ,
873
+ cache . disabledValues . indexOf ( option . value ) ,
862
874
option . disabled ,
863
875
option . hidden
864
876
)
@@ -870,14 +882,20 @@ export const useCombobox = <
870
882
871
883
return getDownshiftOptionProps < any > ( {
872
884
item : option . value ,
873
- index : values . indexOf ( option . value ) ,
885
+ index : cache . values . indexOf ( option . value ) ,
874
886
'aria-disabled' : undefined ,
875
887
'aria-hidden' : undefined ,
876
888
'aria-selected' : ariaSelected ,
877
889
...optionProps
878
890
} as IDownshiftOptionProps < OptionValue > ) ;
879
891
} ,
880
- [ getDownshiftOptionProps , disabledValues , hiddenValues , values , _selectionValue ]
892
+ [
893
+ getDownshiftOptionProps ,
894
+ cache . disabledValues ,
895
+ cache . hiddenValues ,
896
+ cache . values ,
897
+ _selectionValue
898
+ ]
881
899
) ;
882
900
883
901
const getMessageProps = useCallback < IUseComboboxReturnValue [ 'getMessageProps' ] > (
@@ -914,21 +932,21 @@ export const useCombobox = <
914
932
if ( Array . isArray ( _selectionValue ) ) {
915
933
return _selectionValue . map ( value => ( {
916
934
value,
917
- label : labels [ value ] ,
918
- disabled : disabledValues . includes ( value ) ,
919
- hidden : hiddenValues . includes ( value )
935
+ label : cache . labels [ value ] ,
936
+ disabled : cache . disabledValues . includes ( value ) ,
937
+ hidden : cache . hiddenValues . includes ( value )
920
938
} ) ) ;
921
939
} else if ( _selectionValue ) {
922
940
return {
923
941
value : _selectionValue ,
924
- label : toLabel ( labels , _selectionValue ) ,
925
- disabled : disabledValues . includes ( _selectionValue ) ,
926
- hidden : hiddenValues . includes ( _selectionValue )
942
+ label : toLabel ( cache . labels , _selectionValue ) ,
943
+ disabled : cache . disabledValues . includes ( _selectionValue ) ,
944
+ hidden : cache . hiddenValues . includes ( _selectionValue )
927
945
} ;
928
946
}
929
947
930
948
return null ;
931
- } , [ _selectionValue , disabledValues , hiddenValues , labels ] ) ;
949
+ } , [ _selectionValue , cache . disabledValues , cache . hiddenValues , cache . labels ] ) ;
932
950
933
951
return useMemo < IUseComboboxReturnValue > (
934
952
( ) => ( {
@@ -945,13 +963,13 @@ export const useCombobox = <
945
963
/* state */
946
964
selection,
947
965
isExpanded : _isExpanded ,
948
- activeValue : values [ _activeIndex ] ,
966
+ activeValue : cache . values [ _activeIndex ] ,
949
967
inputValue : _inputValue ,
950
968
/* actions */
951
969
removeSelection
952
970
} ) ,
953
971
[
954
- values ,
972
+ cache . values ,
955
973
selection ,
956
974
_isExpanded ,
957
975
_activeIndex ,
0 commit comments