1
- import React , { ChangeEvent , MouseEvent , useCallback , useState } from 'react' ;
2
- import { closeSearchPanel } from '@codemirror/search' ;
1
+ import React , {
2
+ ChangeEvent ,
3
+ FormEvent ,
4
+ MouseEvent ,
5
+ useCallback ,
6
+ useEffect ,
7
+ useState ,
8
+ } from 'react' ;
9
+ import {
10
+ closeSearchPanel ,
11
+ findNext ,
12
+ findPrevious ,
13
+ SearchQuery ,
14
+ selectMatches ,
15
+ setSearchQuery ,
16
+ } from '@codemirror/search' ;
3
17
4
18
import Button from '@leafygreen-ui/button' ;
5
19
import IconButton from '@leafygreen-ui/icon-button' ;
@@ -27,6 +41,8 @@ import { SearchFormProps } from './SearchForm.types';
27
41
28
42
export function SearchForm ( { view } : SearchFormProps ) {
29
43
const [ isOpen , setIsOpen ] = useState ( false ) ;
44
+ const [ searchString , setSearchString ] = useState ( '' ) ;
45
+ const [ findCount , setFindCount ] = useState ( 0 ) ;
30
46
const { theme } = useDarkMode ( ) ;
31
47
32
48
const handleToggleButtonClick = useCallback (
@@ -43,24 +59,45 @@ export function SearchForm({ view }: SearchFormProps) {
43
59
[ view ] ,
44
60
) ;
45
61
46
- const handleFindInputChange = useCallback (
62
+ const handleSearchQueryChange = useCallback (
47
63
( _e : ChangeEvent < HTMLInputElement > ) => {
48
- // const newQuery = new SearchQuery({
49
- // search: 'test',
50
- // caseSensitive: true,
51
- // regexp: false,
52
- // wholeWord: false,
53
- // replace: '',
54
- // });
55
- // view.dispatch({ effects: setSearchQuery.of(newQuery) });
56
- // if (!query || !query.eq(newQuery)) {
57
- // setQuery(newQuery);
58
- // view.dispatch({ effects: setSearchQuery.of(newQuery) });
59
- // }
64
+ setSearchString ( _e . target . value ) ;
60
65
} ,
61
66
[ ] ,
62
67
) ;
63
68
69
+ useEffect ( ( ) => {
70
+ const query = new SearchQuery ( {
71
+ search : searchString ,
72
+ caseSensitive : true ,
73
+ regexp : false ,
74
+ wholeWord : false ,
75
+ replace : '' ,
76
+ } ) ;
77
+
78
+ view . dispatch ( { effects : setSearchQuery . of ( query ) } ) ;
79
+
80
+ const cursor = query . getCursor ( view . state . doc ) ;
81
+ let count = 0 ;
82
+
83
+ let result = cursor . next ( ) ;
84
+
85
+ while ( ! result . done ) {
86
+ count ++ ;
87
+ result = cursor . next ( ) ;
88
+ }
89
+
90
+ setFindCount ( count ) ;
91
+ } , [ searchString , view ] ) ;
92
+
93
+ const handleFindFormSubmit = useCallback (
94
+ ( e : FormEvent < HTMLFormElement > ) => {
95
+ e . preventDefault ( ) ;
96
+ findNext ( view ) ;
97
+ } ,
98
+ [ view ] ,
99
+ ) ;
100
+
64
101
return (
65
102
< div
66
103
className = { getContainerStyles ( { theme, isOpen } ) }
@@ -76,28 +113,45 @@ export function SearchForm({ view }: SearchFormProps) {
76
113
< Icon glyph = "ChevronDown" className = { getToggleIconStyles ( isOpen ) } />
77
114
</ IconButton >
78
115
< div className = { findInputContainerStyles } >
79
- < TextInput
80
- placeholder = "Find"
81
- aria-labelledby = "find"
82
- onChange = { handleFindInputChange }
83
- className = { findInputStyles }
84
- // eslint-disable-next-line jsx-a11y/no-autofocus
85
- autoFocus
86
- />
116
+ < form onSubmit = { handleFindFormSubmit } >
117
+ < TextInput
118
+ placeholder = "Find"
119
+ aria-labelledby = "find"
120
+ onChange = { handleSearchQueryChange }
121
+ className = { findInputStyles }
122
+ // eslint-disable-next-line jsx-a11y/no-autofocus
123
+ autoFocus
124
+ value = { searchString }
125
+ />
126
+ </ form >
87
127
< IconButton
88
128
className = { findInputIconButtonStyles }
89
129
aria-label = "filter button"
90
130
>
91
131
< Icon glyph = "Filter" />
92
132
</ IconButton >
93
133
</ div >
94
- < IconButton aria-label = "next item button" >
134
+ < IconButton
135
+ aria-label = "previous item button"
136
+ disabled = { ! searchString || findCount === 0 }
137
+ onClick = { ( ) => findPrevious ( view ) }
138
+ >
95
139
< Icon glyph = "ArrowUp" />
96
140
</ IconButton >
97
- < IconButton aria-label = "previous item button" >
141
+ < IconButton
142
+ aria-label = "next item button"
143
+ disabled = { ! searchString || findCount === 0 }
144
+ onClick = { ( ) => findNext ( view ) }
145
+ >
98
146
< Icon glyph = "ArrowDown" />
99
147
</ IconButton >
100
- < Button className = { allButtonStyles } > All</ Button >
148
+ < Button
149
+ className = { allButtonStyles }
150
+ disabled = { ! searchString || findCount === 0 }
151
+ onClick = { ( ) => selectMatches ( view ) }
152
+ >
153
+ All
154
+ </ Button >
101
155
< IconButton
102
156
aria-label = "close find menu button"
103
157
onClick = { handleCloseButtonClick }
0 commit comments