@@ -22,18 +22,15 @@ import {
2222import type { MarkdownEditorMode } from 'src/bundle' ;
2323import type { EventMap } from 'src/bundle/Editor' ;
2424import type { RendererItem } from 'src/extensions' ;
25- import { debounce } from 'src/lodash ' ;
25+ import { renderSearchPopup } from 'src/modules/search ' ;
2626import type { Receiver } from 'src/utils' ;
2727
2828import { ReactRendererFacet } from '../react-facet' ;
2929
3030import { searchTheme } from './theme' ;
31- import { renderSearchPopup } from './view/SearchPopup' ;
3231
3332type SearchQueryConfig = ConstructorParameters < typeof SearchQuery > [ 0 ] ;
3433
35- const INPUT_DELAY = 200 ;
36-
3734export interface SearchPanelPluginParams {
3835 anchorSelector : string ;
3936 inputDelay ?: number ;
@@ -46,85 +43,70 @@ export const SearchPanelPlugin = (params: SearchPanelPluginParams) =>
4643 readonly view : EditorView ;
4744 readonly params : SearchPanelPluginParams ;
4845
49- anchor : HTMLElement | null ;
50- renderer : RendererItem | null ;
51- searchConfig : SearchQueryConfig = {
52- search : '' ,
53- caseSensitive : false ,
54- wholeWord : false ,
55- replace : '' ,
56- } ;
46+ renderer : RendererItem ;
5747 receiver : Receiver < EventMap > | undefined ;
5848
59- setViewSearchWithDelay : ( config : Partial < SearchQueryConfig > ) => void ;
49+ panelOpened : boolean ;
50+ searchState : SearchQuery | null ;
6051
6152 constructor ( view : EditorView ) {
6253 this . view = view ;
63- this . anchor = null ;
64- this . renderer = null ;
6554 this . params = params ;
6655 this . receiver = params . receiver ;
6756
57+ this . panelOpened = searchPanelOpen ( view . state ) ;
58+ this . searchState = getSearchQuery ( view . state ) ;
59+ this . renderer = this . createRenderer ( ) ;
60+
6861 this . handleClose = this . handleClose . bind ( this ) ;
6962 this . handleChange = this . handleChange . bind ( this ) ;
7063 this . handleSearchNext = this . handleSearchNext . bind ( this ) ;
7164 this . handleSearchPrev = this . handleSearchPrev . bind ( this ) ;
7265 this . handleReplaceNext = this . handleReplaceNext . bind ( this ) ;
7366 this . handleReplaceAll = this . handleReplaceAll . bind ( this ) ;
74- this . handleSearchConfigChange = this . handleSearchConfigChange . bind ( this ) ;
7567 this . handleEditorModeChange = this . handleEditorModeChange . bind ( this ) ;
7668
77- this . setViewSearchWithDelay = debounce (
78- this . setViewSearch ,
79- this . params . inputDelay ?? INPUT_DELAY ,
80- ) ;
8169 this . receiver ?. on ( 'change-editor-mode' , this . handleEditorModeChange ) ;
8270 }
8371
8472 update ( update : ViewUpdate ) : void {
8573 const isPanelOpen = searchPanelOpen ( update . state ) ;
74+ const searchQuery = getSearchQuery ( update . state ) ;
8675
87- if ( isPanelOpen && ! this . renderer ) {
88- const initial = getSearchQuery ( update . state ) ;
89- this . anchor = document . querySelector ( this . params . anchorSelector ) ;
90- this . renderer = this . view . state
91- . facet ( ReactRendererFacet )
92- . createItem ( 'cm-search' , ( ) =>
93- renderSearchPopup ( {
94- initial,
95- open : true ,
96- anchor : this . anchor ,
97- onChange : this . handleChange ,
98- onClose : this . handleClose ,
99- onSearchNext : this . handleSearchNext ,
100- onSearchPrev : this . handleSearchPrev ,
101- onReplaceNext : this . handleReplaceNext ,
102- onReplaceAll : this . handleReplaceAll ,
103- onConfigChange : this . handleSearchConfigChange ,
104- } ) ,
105- ) ;
106- } else if ( ! isPanelOpen && this . renderer ) {
107- this . renderer ?. remove ( ) ;
108- this . renderer = null ;
76+ if ( isPanelOpen !== this . panelOpened || searchQuery !== this . searchState ) {
77+ this . panelOpened = isPanelOpen ;
78+ this . searchState = searchQuery ;
79+ this . renderer . rerender ( ) ;
10980 }
11081 }
11182
11283 destroy ( ) {
113- this . renderer ?. remove ( ) ;
114- this . renderer = null ;
84+ this . renderer . remove ( ) ;
11585 this . receiver ?. off ( 'change-editor-mode' , this . handleEditorModeChange ) ;
11686 }
11787
118- setViewSearch ( config : Partial < SearchQueryConfig > ) {
119- this . searchConfig = {
120- ...this . searchConfig ,
121- ...config ,
122- } ;
123- const searchQuery = new SearchQuery ( {
124- ...this . searchConfig ,
88+ createRenderer ( ) {
89+ return this . view . state . facet ( ReactRendererFacet ) . createItem ( 'cm-search' , ( ) => {
90+ if ( ! this . panelOpened || ! this . searchState ) return null ;
91+
92+ const anchor = this . view . dom . ownerDocument . querySelector (
93+ this . params . anchorSelector ,
94+ ) ;
95+
96+ if ( ! anchor ) return null ;
97+
98+ return renderSearchPopup ( {
99+ open : true ,
100+ anchor : anchor ,
101+ state : this . searchState ,
102+ onClose : this . handleClose ,
103+ onChange : this . handleChange ,
104+ onSearchNext : this . handleSearchNext ,
105+ onSearchPrev : this . handleSearchPrev ,
106+ onReplaceNext : this . handleReplaceNext ,
107+ onReplaceAll : this . handleReplaceAll ,
108+ } ) ;
125109 } ) ;
126-
127- this . view . dispatch ( { effects : setSearchQuery . of ( searchQuery ) } ) ;
128110 }
129111
130112 handleEditorModeChange ( { mode} : { mode : MarkdownEditorMode } ) {
@@ -133,13 +115,23 @@ export const SearchPanelPlugin = (params: SearchPanelPluginParams) =>
133115 }
134116 }
135117
136- handleChange ( search : string ) {
137- this . setViewSearchWithDelay ( { search} ) ;
118+ handleChange ( config : SearchQueryConfig ) {
119+ this . view . dispatch ( {
120+ effects : setSearchQuery . of (
121+ new SearchQuery ( {
122+ search : config . search ,
123+ replace : config . replace ,
124+ caseSensitive : config . caseSensitive ,
125+ wholeWord : config . wholeWord ,
126+ } ) ,
127+ ) ,
128+ } ) ;
138129 }
139130
140131 handleClose ( ) {
141- this . setViewSearch ( { search : '' } ) ;
132+ this . handleChange ( { search : '' } ) ;
142133 closeSearchPanel ( this . view ) ;
134+ this . view . focus ( ) ;
143135 }
144136
145137 handleSearchNext ( ) {
@@ -150,17 +142,11 @@ export const SearchPanelPlugin = (params: SearchPanelPluginParams) =>
150142 findPrevious ( this . view ) ;
151143 }
152144
153- handleSearchConfigChange ( config : Partial < SearchQueryConfig > ) {
154- this . setViewSearch ( config ) ;
155- }
156-
157- handleReplaceNext ( query : string , replacement : string ) {
158- this . setViewSearch ( { search : query , replace : replacement } ) ;
145+ handleReplaceNext ( ) {
159146 replaceNext ( this . view ) ;
160147 }
161148
162- handleReplaceAll ( query : string , replacement : string ) {
163- this . setViewSearch ( { search : query , replace : replacement } ) ;
149+ handleReplaceAll ( ) {
164150 replaceAll ( this . view ) ;
165151 }
166152 } ,
0 commit comments