1
1
"use client" ;
2
2
3
- import { useState , useCallback } from "react" ;
3
+ import { useState , useCallback , useRef , useEffect } from "react" ;
4
4
import axios , { AxiosError } from "axios" ;
5
5
import { Search } from "lucide-react" ;
6
6
import debounce from 'debounce' ;
@@ -13,6 +13,7 @@ function SearchBar () {
13
13
const [ suggestions , setSuggestions ] = useState < string [ ] > ( [ ] ) ;
14
14
const [ error , setError ] = useState < string | null > ( null ) ;
15
15
const [ loading , setLoading ] = useState ( false ) ;
16
+ const suggestionsRef = useRef < HTMLUListElement | null > ( null ) ;
16
17
17
18
const debouncedSearch = useCallback (
18
19
debounce ( async ( text : string ) => {
@@ -56,6 +57,19 @@ function SearchBar () {
56
57
router . push ( `/catalogue?subject=${ encodeURIComponent ( suggestion ) } ` ) ;
57
58
} ;
58
59
60
+ const handleClickOutside = ( event : MouseEvent ) => {
61
+ if ( suggestionsRef . current && ! suggestionsRef . current . contains ( event . target as Node ) ) {
62
+ setSuggestions ( [ ] ) ;
63
+ }
64
+ } ;
65
+
66
+ useEffect ( ( ) => {
67
+ document . addEventListener ( "mousedown" , handleClickOutside ) ;
68
+ return ( ) => {
69
+ document . removeEventListener ( "mousedown" , handleClickOutside ) ;
70
+ } ;
71
+ } , [ ] ) ;
72
+
59
73
return (
60
74
< div className = "mx-4 md:mx-0" >
61
75
< form className = "w-full max-w-xl" >
@@ -76,24 +90,27 @@ function SearchBar () {
76
90
Loading suggestions...
77
91
</ div >
78
92
) }
79
- { suggestions . length > 0 && ! loading && (
80
- < ul className = "absolute mx-0.5 md:mx-0 md:w-full text-center max-w-xl z-20 border bg-white border-[#7480FF] dark:bg-[#030712] rounded-md mt-2" >
81
- { suggestions . map ( ( suggestion , index ) => (
82
- < li
83
- key = { index }
84
- onClick = { ( ) => handleSelectSuggestion ( suggestion ) }
85
- className = "cursor-pointer p-2 truncate hover:opacity-50"
86
- style = { { width : '100%' , overflow : 'hidden' , whiteSpace : 'nowrap' , textOverflow : 'ellipsis' } }
87
- >
88
- { suggestion }
89
- </ li >
90
- ) ) }
93
+ { ( suggestions . length > 0 || error ) && ! loading && (
94
+ < ul ref = { suggestionsRef } className = "absolute mx-0.5 md:mx-0 md:w-full text-center max-w-xl z-20 border bg-white border-[#7480FF] dark:bg-[#030712] rounded-md mt-2" >
95
+ { error ? (
96
+ < li className = "p-2 text-red" > { error } </ li >
97
+ ) : (
98
+ suggestions . map ( ( suggestion , index ) => (
99
+ < li
100
+ key = { index }
101
+ onClick = { ( ) => handleSelectSuggestion ( suggestion ) }
102
+ className = "cursor-pointer p-2 truncate hover:opacity-50"
103
+ style = { { width : '100%' , overflow : 'hidden' , whiteSpace : 'nowrap' , textOverflow : 'ellipsis' } }
104
+ >
105
+ { suggestion }
106
+ </ li >
107
+ ) )
108
+ ) }
91
109
</ ul >
92
110
) }
93
111
</ form >
94
- { error && < p className = "mt-4 text-red" > { error } </ p > }
95
112
</ div >
96
113
) ;
97
- } ;
114
+ }
98
115
99
116
export default SearchBar ;
0 commit comments