@@ -10,17 +10,26 @@ import { removeExtraSpaces } from "../../common/utils/stringUtils";
1010import { CLASSPREFIX as eccgui } from "../../configuration/constants" ;
1111import { TestableComponent } from "../interfaces" ;
1212
13- import { ContextOverlayProps , Highlighter , IconButton , MenuItem , OverflowText , Spinner } from "./../../index" ;
13+ import {
14+ ContextOverlayProps ,
15+ Highlighter ,
16+ highlighterUtils ,
17+ IconButton ,
18+ MenuItem ,
19+ OverflowText ,
20+ Spinner
21+ } from "./../../index" ;
1422
1523export interface MultiSuggestFieldSelectionProps < T > {
1624 newlySelected ?: T ;
1725 selectedItems : T [ ] ;
1826 createdItems : Partial < T > [ ] ;
1927}
2028
21- interface MultiSuggestFieldCommonProps < T >
29+ export interface MultiSuggestFieldCommonProps < T >
2230 extends TestableComponent ,
23- Pick < BlueprintMultiSelectProps < T > , "items" | "placeholder" | "openOnKeyDown" > {
31+ Pick < BlueprintMultiSelectProps < T > , "items" | "placeholder" | "openOnKeyDown" | "noResults" | "createNewItemRenderer" > ,
32+ Partial < Pick < BlueprintMultiSelectProps < T > , "itemRenderer" > > {
2433 /**
2534 * Additional class name, space separated.
2635 */
@@ -105,9 +114,20 @@ interface MultiSuggestFieldCommonProps<T>
105114 wrapperProps ?: React . HTMLAttributes < HTMLDivElement > ;
106115 /**
107116 * Function that allows us to filter values from the option list.
108- * If not provided, values are filtered by their labels
117+ *
118+ * @deprecated (v26) use `searchListPredicate` instead.
109119 */
110120 searchPredicate ?: ( item : T , query : string ) => boolean ;
121+
122+ /**
123+ * Returns the filtered the search option list.
124+ * By default, a case-insensitive multi-word filtering is applied.
125+ *
126+ * @param items The options.
127+ * @param query The search query.
128+ */
129+ searchListPredicate ?: ( items : T [ ] , query : string ) => T [ ]
130+
111131 /**
112132 * Limits the height of the input target plus its dropdown menu when it is opened.
113133 * Need to be a `number not greater than 100` (as `vh`, a unit describing a length relative to the viewport height) or `true` (equals 100).
@@ -169,13 +189,14 @@ export function MultiSuggestField<T>({
169189 "data-testid" : dataTestid ,
170190 wrapperProps,
171191 searchPredicate,
192+ searchListPredicate,
172193 limitHeightOpened,
173194 intent,
174195 ...otherMultiSelectProps
175196} : MultiSuggestFieldProps < T > ) {
176197 // Options created by a user
177198 const createdItems = useRef < T [ ] > ( [ ] ) ;
178- // Options passed ouside (f.e. from the backend)
199+ // Options passed outside (f.e. from the backend)
179200 const [ externalItems , setExternalItems ] = React . useState < T [ ] > ( [ ...items ] ) ;
180201 // All options (created and passed) that match the query
181202 const [ filteredItems , setFilteredItems ] = React . useState < T [ ] > ( [ ] ) ;
@@ -267,9 +288,14 @@ export function MultiSuggestField<T>({
267288 setSelectedItems ( filteredItems ) ;
268289 } ;
269290
270- const defaultFilterPredicate = ( item : T , query : string ) => {
271- return itemLabel ( item ) . toLowerCase ( ) . includes ( query ) ;
272- } ;
291+ /** Does a case-insensitive multi-word search in the item label. */
292+ const defaultSearchListPredicate = ( items : T [ ] , query : string ) : T [ ] => {
293+ const searchWords = highlighterUtils . extractSearchWords ( query , true ) ;
294+ return items . filter ( item => {
295+ const searchIn = itemLabel ( item ) . toLowerCase ( )
296+ return highlighterUtils . matchesAllWords ( searchIn , searchWords ) ;
297+ } )
298+ }
273299
274300 /**
275301 * selects and deselects an item from selection list
@@ -308,10 +334,17 @@ export function MultiSuggestField<T>({
308334 if ( requestState . current . query === query ) {
309335 // Only use most recent request
310336 const outsideOptions = [ ...( resultFromQuery ?? externalItems ) ] ;
311- const filter = searchPredicate ?? defaultFilterPredicate ;
337+ let itemFilter = defaultSearchListPredicate
338+ if ( searchListPredicate ) {
339+ itemFilter = searchListPredicate
340+ } else if ( searchPredicate ) {
341+ itemFilter = ( items , query ) => {
342+ return items . filter ( ( item ) => searchPredicate ( item , query ) )
343+ }
344+ }
312345
313346 setFilteredItems (
314- [ ...outsideOptions , ...createdItems . current ] . filter ( ( item ) => filter ( item , query . toLowerCase ( ) ) )
347+ itemFilter ( [ ...outsideOptions , ...createdItems . current ] , query )
315348 ) ;
316349 setShowSpinner ( false ) ;
317350 }
@@ -468,7 +501,6 @@ export function MultiSuggestField<T>({
468501 ? "Search for item, or enter term to create new one..."
469502 : undefined
470503 }
471- { ...otherMultiSelectProps }
472504 query = { requestState . current . query }
473505 onQueryChange = { onQueryChange }
474506 items = { filteredItems }
@@ -537,6 +569,7 @@ export function MultiSuggestField<T>({
537569 : undefined ,
538570 } as BlueprintMultiSelectProps < T > [ "popoverContentProps" ]
539571 }
572+ { ...otherMultiSelectProps }
540573 />
541574 ) ;
542575
0 commit comments