aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/editor/SearchPanelStore.ts
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-17 21:43:29 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-17 21:43:29 +0200
commitbb900e1bd40a6b7efd7a538114d985ea7f7e3e88 (patch)
treebb15a937ade92313dc654a640bc1de925442eff2 /subprojects/frontend/src/editor/SearchPanelStore.ts
parentrefactor(frondend): improve editor store and theme (diff)
downloadrefinery-bb900e1bd40a6b7efd7a538114d985ea7f7e3e88.tar.gz
refinery-bb900e1bd40a6b7efd7a538114d985ea7f7e3e88.tar.zst
refinery-bb900e1bd40a6b7efd7a538114d985ea7f7e3e88.zip
feat(frontend): custom search panel
Also improves editor styling (to enable panel styling).
Diffstat (limited to 'subprojects/frontend/src/editor/SearchPanelStore.ts')
-rw-r--r--subprojects/frontend/src/editor/SearchPanelStore.ts108
1 files changed, 108 insertions, 0 deletions
diff --git a/subprojects/frontend/src/editor/SearchPanelStore.ts b/subprojects/frontend/src/editor/SearchPanelStore.ts
new file mode 100644
index 00000000..43a571e5
--- /dev/null
+++ b/subprojects/frontend/src/editor/SearchPanelStore.ts
@@ -0,0 +1,108 @@
1import {
2 closeSearchPanel,
3 findNext,
4 findPrevious,
5 getSearchQuery,
6 openSearchPanel,
7 replaceAll,
8 replaceNext,
9 SearchQuery,
10 selectMatches,
11 setSearchQuery,
12} from '@codemirror/search';
13import { action, computed, makeObservable, observable, override } from 'mobx';
14
15import type EditorStore from './EditorStore';
16import PanelStore from './PanelStore';
17
18export default class SearchPanelStore extends PanelStore {
19 searchField: HTMLInputElement | undefined;
20
21 constructor(store: EditorStore) {
22 // Use a custom class name to avoid specificity issues with
23 // CodeMirror `.cm-search.cm-panel` CSS styles.
24 super('refinery-cm-search', openSearchPanel, closeSearchPanel, store);
25 makeObservable(this, {
26 searchField: observable.ref,
27 query: computed,
28 invalidRegexp: computed,
29 open: override,
30 setSearchField: action,
31 updateQuery: action,
32 findNext: action,
33 findPrevious: action,
34 selectMatches: action,
35 });
36 }
37
38 setSearchField(newSearchField: HTMLInputElement | undefined): void {
39 this.searchField = newSearchField;
40 if (this.state) {
41 this.selectSearchField();
42 }
43 }
44
45 get query(): SearchQuery {
46 return getSearchQuery(this.store.state);
47 }
48
49 get invalidRegexp(): boolean {
50 const { search, valid } = this.query;
51 return !valid && search !== '';
52 }
53
54 updateQuery(newQueryOptions: {
55 search?: string;
56 caseSensitive?: boolean;
57 literal?: boolean;
58 regexp?: boolean;
59 replace?: string;
60 }): void {
61 const { search, caseSensitive, literal, regexp, replace } = this.query;
62 const newQuery = new SearchQuery({
63 search,
64 caseSensitive,
65 literal,
66 regexp,
67 replace,
68 ...newQueryOptions,
69 ...(newQueryOptions.regexp === true && { literal: false }),
70 ...(newQueryOptions.literal === true && { regexp: false }),
71 });
72 this.store.dispatch({
73 effects: [setSearchQuery.of(newQuery)],
74 });
75 }
76
77 findNext(): void {
78 this.store.doCommand(findNext);
79 }
80
81 findPrevious(): void {
82 this.store.doCommand(findPrevious);
83 }
84
85 selectMatches(): void {
86 this.store.doCommand(selectMatches);
87 }
88
89 replaceNext(): void {
90 this.store.doCommand(replaceNext);
91 }
92
93 replaceAll(): void {
94 this.store.doCommand(replaceAll);
95 }
96
97 override open(): boolean {
98 return super.open() || this.selectSearchField();
99 }
100
101 private selectSearchField(): boolean {
102 if (this.searchField === undefined) {
103 return false;
104 }
105 this.searchField.select();
106 return true;
107 }
108}