@@ -32,11 +32,16 @@ import { createTheme } from '@uiw/codemirror-themes';
3232import CodeMirror , { Annotation , EditorView , KeyBinding , keymap , ReactCodeMirrorRef } from "@uiw/react-codemirror" ;
3333import { cva } from "class-variance-authority" ;
3434import { useRouter } from "next/navigation" ;
35- import { useCallback , useMemo , useRef , useState } from "react" ;
35+ import { useCallback , useEffect , useMemo , useRef , useState } from "react" ;
3636import { useHotkeys } from 'react-hotkeys-hook' ;
37- import { SearchSuggestionsBox , SuggestionMode } from "./searchSuggestionsBox" ;
37+ import { SearchSuggestionsBox } from "./searchSuggestionsBox" ;
3838import { useSuggestionsData } from "./useSuggestionsData" ;
3939import { zoekt } from "./zoektLanguageExtension" ;
40+ import { CounterClockwiseClockIcon } from "@radix-ui/react-icons" ;
41+ import { useSuggestionModeAndQuery } from "./useSuggestionModeAndQuery" ;
42+ import { Separator } from "@/components/ui/separator" ;
43+ import { Tooltip , TooltipTrigger , TooltipContent } from "@/components/ui/tooltip" ;
44+ import { Toggle } from "@/components/ui/toggle" ;
4045
4146interface SearchBarProps {
4247 className ?: string ;
@@ -66,7 +71,7 @@ const searchBarKeymap: readonly KeyBinding[] = ([
6671] as KeyBinding [ ] ) . concat ( historyKeymap ) ;
6772
6873const searchBarContainerVariants = cva (
69- "search-bar-container flex items-center p -0.5 border rounded-md relative" ,
74+ "search-bar-container flex items-center py -0.5 px-1 border rounded-md relative" ,
7075 {
7176 variants : {
7277 size : {
@@ -91,13 +96,12 @@ export const SearchBar = ({
9196 const suggestionBoxRef = useRef < HTMLDivElement > ( null ) ;
9297 const editorRef = useRef < ReactCodeMirrorRef > ( null ) ;
9398 const [ cursorPosition , setCursorPosition ] = useState ( 0 ) ;
94- const [ isSuggestionsBoxEnabled , setIsSuggestionsBoxEnabled ] = useState ( false ) ;
99+ const [ isSuggestionsEnabled , setIsSuggestionsEnabled ] = useState ( false ) ;
95100 const [ isSuggestionsBoxFocused , setIsSuggestionsBoxFocused ] = useState ( false ) ;
96-
101+ const [ isHistorySearchEnabled , setIsHistorySearchEnabled ] = useState ( false ) ;
102+
97103 const focusEditor = useCallback ( ( ) => editorRef . current ?. view ?. focus ( ) , [ ] ) ;
98104 const focusSuggestionsBox = useCallback ( ( ) => suggestionBoxRef . current ?. focus ( ) , [ ] ) ;
99- const [ suggestionMode , setSuggestionMode ] = useState < SuggestionMode > ( "refine" ) ;
100- const [ suggestionQuery , setSuggestionQuery ] = useState ( "" ) ;
101105
102106 const [ _query , setQuery ] = useState ( defaultQuery ?? "" ) ;
103107 const query = useMemo ( ( ) => {
@@ -106,6 +110,22 @@ export const SearchBar = ({
106110 return _query . replaceAll ( / \n / g, " " ) ;
107111 } , [ _query ] ) ;
108112
113+ // When the user navigates backwards/forwards while on the
114+ // search page (causing the `query` search param to change),
115+ // we want to update what query is displayed in the search bar.
116+ useEffect ( ( ) => {
117+ if ( defaultQuery ) {
118+ setQuery ( defaultQuery ) ;
119+ }
120+ } , [ defaultQuery ] )
121+
122+ const { suggestionMode, suggestionQuery } = useSuggestionModeAndQuery ( {
123+ isSuggestionsEnabled,
124+ isHistorySearchEnabled,
125+ cursorPosition,
126+ query,
127+ } ) ;
128+
109129 const suggestionData = useSuggestionsData ( {
110130 suggestionMode,
111131 suggestionQuery,
@@ -152,7 +172,7 @@ export const SearchBar = ({
152172 useHotkeys ( '/' , ( event ) => {
153173 event . preventDefault ( ) ;
154174 focusEditor ( ) ;
155- setIsSuggestionsBoxEnabled ( true ) ;
175+ setIsSuggestionsEnabled ( true ) ;
156176 if ( editorRef . current ?. view ) {
157177 cursorDocEnd ( {
158178 state : editorRef . current . view . state ,
@@ -164,37 +184,40 @@ export const SearchBar = ({
164184 // Collapse the suggestions box if the user clicks outside of the search bar container.
165185 useClickListener ( '.search-bar-container' , ( isElementClicked ) => {
166186 if ( ! isElementClicked ) {
167- setIsSuggestionsBoxEnabled ( false ) ;
187+ setIsSuggestionsEnabled ( false ) ;
168188 } else {
169- setIsSuggestionsBoxEnabled ( true ) ;
189+ setIsSuggestionsEnabled ( true ) ;
170190 }
171191 } ) ;
172192
173- const onSubmit = ( ) => {
193+ const onSubmit = useCallback ( ( query : string ) => {
194+ setIsSuggestionsEnabled ( false ) ;
195+ setIsHistorySearchEnabled ( false ) ;
196+
174197 const url = createPathWithQueryParams ( '/search' ,
175198 [ SearchQueryParams . query , query ] ,
176- )
199+ ) ;
177200 router . push ( url ) ;
178- }
201+ } , [ router ] ) ;
179202
180203 return (
181204 < div
182205 className = { cn ( searchBarContainerVariants ( { size, className } ) ) }
183206 onKeyDown = { ( e ) => {
184207 if ( e . key === 'Enter' ) {
185208 e . preventDefault ( ) ;
186- setIsSuggestionsBoxEnabled ( false ) ;
187- onSubmit ( ) ;
209+ setIsSuggestionsEnabled ( false ) ;
210+ onSubmit ( query ) ;
188211 }
189212
190213 if ( e . key === 'Escape' ) {
191214 e . preventDefault ( ) ;
192- setIsSuggestionsBoxEnabled ( false ) ;
215+ setIsSuggestionsEnabled ( false ) ;
193216 }
194217
195218 if ( e . key === 'ArrowDown' ) {
196219 e . preventDefault ( ) ;
197- setIsSuggestionsBoxEnabled ( true ) ;
220+ setIsSuggestionsEnabled ( true ) ;
198221 focusSuggestionsBox ( ) ;
199222 }
200223
@@ -203,16 +226,29 @@ export const SearchBar = ({
203226 }
204227 } }
205228 >
229+ < SearchHistoryButton
230+ isToggled = { isHistorySearchEnabled }
231+ onClick = { ( ) => {
232+ setQuery ( "" ) ;
233+ setIsHistorySearchEnabled ( ! isHistorySearchEnabled ) ;
234+ setIsSuggestionsEnabled ( true ) ;
235+ focusEditor ( ) ;
236+ } }
237+ />
238+ < Separator
239+ className = "mx-1 h-6"
240+ orientation = "vertical"
241+ />
206242 < CodeMirror
207243 ref = { editorRef }
208244 className = "overflow-x-auto scrollbar-hide w-full"
209- placeholder = { "Search..." }
245+ placeholder = { isHistorySearchEnabled ? "Filter history..." : "Search..." }
210246 value = { query }
211247 onChange = { ( value ) => {
212248 setQuery ( value ) ;
213249 // Whenever the user types, we want to re-enable
214250 // the suggestions box.
215- setIsSuggestionsBoxEnabled ( true ) ;
251+ setIsSuggestionsEnabled ( true ) ;
216252 } }
217253 theme = { theme }
218254 basicSetup = { false }
@@ -223,7 +259,9 @@ export const SearchBar = ({
223259 < SearchSuggestionsBox
224260 ref = { suggestionBoxRef }
225261 query = { query }
226- onCompletion = { ( newQuery : string , newCursorPosition : number ) => {
262+ suggestionQuery = { suggestionQuery }
263+ suggestionMode = { suggestionMode }
264+ onCompletion = { ( newQuery : string , newCursorPosition : number , autoSubmit = false ) => {
227265 setQuery ( newQuery ) ;
228266
229267 // Move the cursor to it's new position.
@@ -242,8 +280,12 @@ export const SearchBar = ({
242280
243281 // Re-focus the editor since suggestions cause focus to be lost (both click & keyboard)
244282 editorRef . current ?. view ?. focus ( ) ;
283+
284+ if ( autoSubmit ) {
285+ onSubmit ( newQuery ) ;
286+ }
245287 } }
246- isEnabled = { isSuggestionsBoxEnabled }
288+ isEnabled = { isSuggestionsEnabled }
247289 onReturnFocus = { ( ) => {
248290 focusEditor ( ) ;
249291 } }
@@ -255,17 +297,40 @@ export const SearchBar = ({
255297 setIsSuggestionsBoxFocused ( document . activeElement === suggestionBoxRef . current ) ;
256298 } }
257299 cursorPosition = { cursorPosition }
258- onSuggestionModeChanged = { ( newSuggestionMode ) => {
259- if ( suggestionMode !== newSuggestionMode ) {
260- console . debug ( `Suggestion mode changed: ${ suggestionMode } -> ${ newSuggestionMode } ` ) ;
261- }
262- setSuggestionMode ( newSuggestionMode ) ;
263- } }
264- onSuggestionQueryChanged = { ( suggestionQuery ) => {
265- setSuggestionQuery ( suggestionQuery ) ;
266- } }
267300 { ...suggestionData }
268301 />
269302 </ div >
270303 )
304+ }
305+
306+ const SearchHistoryButton = ( {
307+ isToggled,
308+ onClick,
309+ } : {
310+ isToggled : boolean ,
311+ onClick : ( ) => void
312+ } ) => {
313+ return (
314+ < Tooltip >
315+ < TooltipTrigger
316+ asChild = { true }
317+ >
318+ { /* @see : https://github.com/shadcn-ui/ui/issues/1988#issuecomment-1980597269 */ }
319+ < div >
320+ < Toggle
321+ pressed = { isToggled }
322+ className = "h-6 w-6 min-w-6 px-0 p-1 cursor-pointer"
323+ onClick = { onClick }
324+ >
325+ < CounterClockwiseClockIcon />
326+ </ Toggle >
327+ </ div >
328+ </ TooltipTrigger >
329+ < TooltipContent
330+ side = "bottom"
331+ >
332+ Search history
333+ </ TooltipContent >
334+ </ Tooltip >
335+ )
271336}
0 commit comments