11// @flow
22
3- import React , { useEffect } from 'react' ;
3+ import { Timer } from '@performant-software/shared-components' ;
4+ import React , {
5+ useCallback ,
6+ useEffect ,
7+ useRef ,
8+ useState
9+ } from 'react' ;
410import {
511 Checkbox ,
612 Icon ,
13+ Input ,
714 Label ,
815 List
916} from 'semantic-ui-react' ;
@@ -14,7 +21,8 @@ import LinkButton from './LinkButton';
1421import { type RefinementListProps } from '../types/InstantSearch' ;
1522
1623type Props = FacetProps & RefinementListProps & {
17- defaultValue ?: string
24+ defaultValue ?: string ,
25+ searchable ?: boolean
1826} ;
1927
2028const FacetList = ( { useRefinementList, ...props } : Props ) => {
@@ -23,9 +31,39 @@ const FacetList = ({ useRefinementList, ...props }: Props) => {
2331 refine,
2432 canToggleShowMore,
2533 isShowingMore,
34+ searchForItems,
2635 toggleShowMore,
2736 } = useRefinementList ( props ) ;
2837
38+ const ref = useRef ( ) ;
39+ const [ query , setQuery ] = useState ( '' ) ;
40+
41+ /**
42+ * Clears the current search state.
43+ *
44+ * @type {(function(): void)|* }
45+ */
46+ const onClear = useCallback ( ( ) => {
47+ // Reset the query view
48+ setQuery ( '' ) ;
49+
50+ // Reset the list of refinements
51+ searchForItems ( ) ;
52+
53+ // Refocus the input element
54+ const { current : instance } = ref ;
55+ if ( instance ) {
56+ instance . focus ( ) ;
57+ }
58+ } , [ ] ) ;
59+
60+ /**
61+ * Executes the search within the list of facet values.
62+ *
63+ * @type {function(): * }
64+ */
65+ const onSearch = useCallback ( ( ) => searchForItems ( query ) , [ query , searchForItems ] ) ;
66+
2967 /**
3068 * Sets the default value if provided.
3169 */
@@ -36,9 +74,18 @@ const FacetList = ({ useRefinementList, ...props }: Props) => {
3674 } , [ props . defaultValue ] ) ;
3775
3876 /**
39- * Do not render the component if no items are present.
77+ * Persist the facet search when a user selects or deselects items.
78+ */
79+ useEffect ( ( ) => {
80+ if ( query ) {
81+ searchForItems ( query ) ;
82+ }
83+ } , [ items ] ) ;
84+
85+ /**
86+ * Do not render the component if no items are present and no query has been entered.
4087 */
41- if ( _ . isEmpty ( items ) ) {
88+ if ( _ . isEmpty ( items ) && _ . isEmpty ( query ) ) {
4289 return null ;
4390 }
4491
@@ -48,6 +95,24 @@ const FacetList = ({ useRefinementList, ...props }: Props) => {
4895 divided = { props . divided }
4996 title = { props . title }
5097 >
98+ { props . searchable && (
99+ < Input
100+ icon = { query && (
101+ < Icon
102+ link
103+ name = 'times'
104+ onClick = { onClear }
105+ />
106+ ) }
107+ fluid
108+ onChange = { ( e , { value } ) => setQuery ( value ) }
109+ onKeyDown = { ( ) => Timer . clearSearchTimer ( ) }
110+ onKeyUp = { ( ) => Timer . setSearchTimer ( onSearch ) }
111+ placeholder = { i18n . t ( 'FacetList.labels.search' ) }
112+ ref = { ref }
113+ value = { query }
114+ />
115+ ) }
51116 < List
52117 className = 'facet-list'
53118 >
0 commit comments