| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  | // Copyright 2025 Signal Messenger, LLC
 | 
					
						
							|  |  |  | // SPDX-License-Identifier: AGPL-3.0-only
 | 
					
						
							| 
									
										
										
										
											2025-04-29 13:27:33 -07:00
										 |  |  | import type { ChangeEvent } from 'react'; | 
					
						
							| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  | import React, { useCallback } from 'react'; | 
					
						
							| 
									
										
										
										
											2025-03-26 12:35:32 -07:00
										 |  |  | import { VisuallyHidden } from 'react-aria'; | 
					
						
							| 
									
										
										
										
											2025-04-07 12:47:38 -07:00
										 |  |  | import { getInteractionModality } from '@react-aria/interactions'; | 
					
						
							| 
									
										
										
										
											2025-03-26 12:35:32 -07:00
										 |  |  | import type { LocalizerType } from '../../../types/I18N'; | 
					
						
							| 
									
										
										
										
											2025-04-07 12:47:38 -07:00
										 |  |  | import { useFunContext } from '../FunProvider'; | 
					
						
							| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export type FunSearchProps = Readonly<{ | 
					
						
							| 
									
										
										
										
											2025-03-26 12:35:32 -07:00
										 |  |  |   i18n: LocalizerType; | 
					
						
							| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  |   'aria-label': string; | 
					
						
							|  |  |  |   placeholder: string; | 
					
						
							|  |  |  |   searchInput: string; | 
					
						
							|  |  |  |   onSearchInputChange: (newSearchInput: string) => void; | 
					
						
							|  |  |  | }>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export function FunSearch(props: FunSearchProps): JSX.Element { | 
					
						
							| 
									
										
										
										
											2025-03-26 12:35:32 -07:00
										 |  |  |   const { i18n, onSearchInputChange } = props; | 
					
						
							| 
									
										
										
										
											2025-04-07 12:47:38 -07:00
										 |  |  |   const { shouldAutoFocus, onChangeShouldAutoFocus } = useFunContext(); | 
					
						
							| 
									
										
										
										
											2025-03-26 12:35:32 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  |   const handleChange = useCallback( | 
					
						
							| 
									
										
										
										
											2025-04-29 13:27:33 -07:00
										 |  |  |     (event: ChangeEvent<HTMLInputElement>) => { | 
					
						
							|  |  |  |       onSearchInputChange(event.currentTarget.value); | 
					
						
							| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  |     }, | 
					
						
							|  |  |  |     [onSearchInputChange] | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-07 12:47:38 -07:00
										 |  |  |   const handleFocus = useCallback(() => { | 
					
						
							|  |  |  |     onChangeShouldAutoFocus(true); | 
					
						
							|  |  |  |   }, [onChangeShouldAutoFocus]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const handleBlur = useCallback(() => { | 
					
						
							|  |  |  |     if (getInteractionModality() !== 'pointer') { | 
					
						
							|  |  |  |       onChangeShouldAutoFocus(false); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }, [onChangeShouldAutoFocus]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-26 12:35:32 -07:00
										 |  |  |   const handleClear = useCallback(() => { | 
					
						
							|  |  |  |     onSearchInputChange(''); | 
					
						
							|  |  |  |   }, [onSearchInputChange]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  |   return ( | 
					
						
							|  |  |  |     <div className="FunSearch__Container"> | 
					
						
							|  |  |  |       <div className="FunSearch__Icon" /> | 
					
						
							|  |  |  |       <input | 
					
						
							|  |  |  |         className="FunSearch__Input" | 
					
						
							|  |  |  |         aria-label={props['aria-label']} | 
					
						
							|  |  |  |         type="text" | 
					
						
							|  |  |  |         value={props.searchInput} | 
					
						
							|  |  |  |         onChange={handleChange} | 
					
						
							| 
									
										
										
										
											2025-04-07 12:47:38 -07:00
										 |  |  |         onFocus={handleFocus} | 
					
						
							|  |  |  |         onBlur={handleBlur} | 
					
						
							| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  |         placeholder={props.placeholder} | 
					
						
							| 
									
										
										
										
											2025-04-07 12:47:38 -07:00
										 |  |  |         // eslint-disable-next-line jsx-a11y/no-autofocus
 | 
					
						
							|  |  |  |         autoFocus={shouldAutoFocus} | 
					
						
							| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  |       /> | 
					
						
							| 
									
										
										
										
											2025-03-26 12:35:32 -07:00
										 |  |  |       {props.searchInput !== '' && ( | 
					
						
							|  |  |  |         <button | 
					
						
							|  |  |  |           type="button" | 
					
						
							|  |  |  |           className="FunSearch__Clear" | 
					
						
							|  |  |  |           onClick={handleClear} | 
					
						
							|  |  |  |         > | 
					
						
							|  |  |  |           <span className="FunSearch__ClearButton"> | 
					
						
							|  |  |  |             <VisuallyHidden> | 
					
						
							|  |  |  |               {i18n('icu:FunSearch__ClearButtonLabel')} | 
					
						
							|  |  |  |             </VisuallyHidden> | 
					
						
							|  |  |  |           </span> | 
					
						
							|  |  |  |         </button> | 
					
						
							|  |  |  |       )} | 
					
						
							| 
									
										
										
										
											2025-02-19 17:31:33 -08:00
										 |  |  |     </div> | 
					
						
							|  |  |  |   ); | 
					
						
							|  |  |  | } |