@univerjs/find-replace 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.css CHANGED
@@ -1 +1 @@
1
- .univer-find-replace-expand-container{margin-top:16px;text-align:center}
1
+ .univer-find-replace-dialog-container{display:block}.univer-find-replace-expand-container{margin-top:16px;text-align:center}.univer-find-replace-expand-container .univer-button-text{color:rgb(var(--primary-color))}.univer-find-replace-buttons-group{display:flex;justify-content:space-between;margin-top:24px}.univer-find-replace-buttons-group-right>button:not(:first-child){margin-left:8px}
@@ -13,5 +13,6 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import React from 'react';
17
- export declare function FindReplaceDialog(): React.JSX.Element;
16
+ import type { ICommand } from '@univerjs/core';
17
+ export declare const ReplaceCurrentMatchCommand: ICommand;
18
+ export declare const ReplaceAllMatchesCommand: ICommand;
@@ -16,7 +16,5 @@
16
16
  import type { IOperation } from '@univerjs/core';
17
17
  export declare const OpenFindDialogOperation: IOperation;
18
18
  export declare const OpenReplaceDialogOperation: IOperation;
19
- export declare const ToggleReplaceDialogOperation: IOperation;
20
- export declare const CloseFindReplaceDialogOperation: IOperation;
21
19
  export declare const GoToNextMatchOperation: IOperation;
22
20
  export declare const GoToPreviousMatchOperation: IOperation;
@@ -13,25 +13,27 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { ICommandService, IContextService, LocaleService, RxDisposable } from '@univerjs/core';
16
+ import { ICommandService, IContextService, ILogService, IUniverInstanceService, LocaleService, RxDisposable } from '@univerjs/core';
17
17
  import { ComponentManager, IDialogService, ILayoutService, IMenuService, IShortcutService } from '@univerjs/ui';
18
18
  import { Injector } from '@wendellhu/redi';
19
19
  import { IFindReplaceService } from '../services/find-replace.service';
20
20
  export declare class FindReplaceController extends RxDisposable {
21
+ private readonly _univerInstanceService;
21
22
  private readonly _menuService;
22
23
  private readonly _shortcutService;
23
24
  private readonly _commandService;
24
25
  private readonly _findReplaceService;
26
+ private readonly _logService;
25
27
  private readonly _dialogService;
26
28
  private readonly _contextService;
27
29
  private readonly _layoutService;
28
30
  private readonly _localeService;
29
31
  private readonly _componentManager;
30
32
  private readonly _injector;
31
- constructor(_menuService: IMenuService, _shortcutService: IShortcutService, _commandService: ICommandService, _findReplaceService: IFindReplaceService, _dialogService: IDialogService, _contextService: IContextService, _layoutService: ILayoutService, _localeService: LocaleService, _componentManager: ComponentManager, _injector: Injector);
32
- private _initOperations;
33
- private _initUI;
33
+ constructor(_univerInstanceService: IUniverInstanceService, _menuService: IMenuService, _shortcutService: IShortcutService, _commandService: ICommandService, _findReplaceService: IFindReplaceService, _logService: ILogService, _dialogService: IDialogService, _contextService: IContextService, _layoutService: ILayoutService, _localeService: LocaleService, _componentManager: ComponentManager, _injector: Injector);
34
+ private _initCommands;
34
35
  private _initShortcuts;
36
+ private _initUI;
35
37
  private _openPanel;
36
- private _closePanel;
38
+ closePanel(): void;
37
39
  }
@@ -15,7 +15,7 @@
15
15
  */
16
16
  import { type IShortcutItem } from '@univerjs/ui';
17
17
  export declare const OpenFindDialogShortcutItem: IShortcutItem;
18
+ export declare const MacOpenFindDialogShortcutItem: IShortcutItem;
18
19
  export declare const OpenReplaceDialogShortcutItem: IShortcutItem;
19
- export declare const CloseFRDialogShortcutItem: IShortcutItem;
20
20
  export declare const GoToNextFindMatchShortcutItem: IShortcutItem;
21
21
  export declare const GoToPreviousFindMatchShortcutItem: IShortcutItem;
@@ -14,5 +14,6 @@
14
14
  * limitations under the License.
15
15
  */
16
16
  export { UniverFindReplacePlugin } from './plugin';
17
- export type { IFindComplete, IFindMatch, IFindQuery, IFindReplaceProvider } from './services/find-replace.service';
18
- export { FindModel, IFindReplaceService } from './services/find-replace.service';
17
+ export { FindReplaceController } from './controllers/find-replace.controller';
18
+ export type { IFindComplete, IFindMoveParams, IFindMatch, IFindQuery, IFindReplaceProvider, IReplaceAllResult, } from './services/find-replace.service';
19
+ export { FindModel, IFindReplaceService, FindBy, FindScope, FindDirection } from './services/find-replace.service';
@@ -13,6 +13,52 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import type zhCN from './zh-CN';
17
- declare const locale: typeof zhCN;
16
+ declare const locale: {
17
+ 'find-replace': {
18
+ toolbar: string;
19
+ shortcut: {
20
+ 'open-find-dialog': string;
21
+ 'open-replace-dialog': string;
22
+ 'close-dialog': string;
23
+ 'go-to-next-match': string;
24
+ 'go-to-previous-match': string;
25
+ };
26
+ dialog: {
27
+ title: string;
28
+ find: string;
29
+ replace: string;
30
+ 'replace-all': string;
31
+ 'case-sensitive': string;
32
+ 'find-placeholder': string;
33
+ 'advanced-finding': string;
34
+ 'replace-placeholder': string;
35
+ 'match-the-whole-cell': string;
36
+ 'find-direction': {
37
+ title: string;
38
+ row: string;
39
+ column: string;
40
+ };
41
+ 'find-scope': {
42
+ title: string;
43
+ 'current-sheet': string;
44
+ workbook: string;
45
+ };
46
+ 'find-by': {
47
+ title: string;
48
+ value: string;
49
+ formula: string;
50
+ };
51
+ 'no-match': string;
52
+ 'no-result': string;
53
+ };
54
+ replace: {
55
+ 'all-success': string;
56
+ 'all-failure': string;
57
+ confirm: {
58
+ title: string;
59
+ };
60
+ };
61
+ };
62
+ 'find-replace-shortcuts': string;
63
+ };
18
64
  export default locale;
@@ -13,20 +13,6 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- declare const locale: {
17
- univer: {
18
- 'find-replace': {
19
- dialog: {
20
- title: string;
21
- find: string;
22
- replace: string;
23
- 'replace-all': string;
24
- 'find-range': string;
25
- 'find-placeholder': string;
26
- 'advanced-finding': string;
27
- 'replace-placeholder': string;
28
- };
29
- };
30
- };
31
- };
16
+ import type enUS from './en-US';
17
+ declare const locale: typeof enUS;
32
18
  export default locale;
@@ -13,7 +13,12 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
+ export declare const FIND_REPLACE_INPUT_FOCUS = "FIND_REPLACE_INPUT_FOCUS";
16
17
  /**
17
- * If find replace feature is activated.
18
+ * If find replace panel is focused.
18
19
  */
19
- export declare const FIND_REPLACE_ACTIVATED = "FIND_REPLACE_ACTIVATED";
20
+ export declare const FIND_REPLACE_DIALOG_FOCUS = "FIND_REPLACE_DIALOG_FOCUS";
21
+ /**
22
+ * If the find replace feature is activated and the replace is revealed.
23
+ */
24
+ export declare const FIND_REPLACE_REPLACE_REVEALED = "FIND_REPLACE_REPLACE_REVEALED";
@@ -13,10 +13,12 @@
13
13
  * See the License for the specific language governing permissions and
14
14
  * limitations under the License.
15
15
  */
16
- import { Disposable, ILogService, IUniverInstanceService } from '@univerjs/core';
16
+ import type { Nullable } from '@univerjs/core';
17
+ import { Disposable, IContextService, ILogService, IUniverInstanceService } from '@univerjs/core';
17
18
  import type { IDisposable } from '@wendellhu/redi';
18
19
  import { Injector } from '@wendellhu/redi';
19
20
  import type { Observable } from 'rxjs';
21
+ import { BehaviorSubject } from 'rxjs';
20
22
  export type FindProgressFn = () => void;
21
23
  export interface IFindComplete<T extends IFindMatch = IFindMatch> {
22
24
  results: T[];
@@ -25,26 +27,64 @@ export interface IFindMatch<T = unknown> {
25
27
  provider: string;
26
28
  unitId: string;
27
29
  range: T;
30
+ /** Indicates if the match could be replaced. */
31
+ replaceable?: boolean;
32
+ }
33
+ export interface IFindMoveParams {
34
+ /** Go to next (previous) matching in a loop. */
35
+ loop?: boolean;
36
+ /** If the the selection is on the match and then should stay on the match. */
37
+ stayIfOnMatch?: boolean;
38
+ /**
39
+ * If this param is true, we should only change matching position without performing focusing.
40
+ * This usually happens when "moving" is triggered when a document's content changes.
41
+ */
42
+ noFocus?: boolean;
43
+ }
44
+ export interface IReplaceAllResult {
45
+ success: number;
46
+ failure: number;
28
47
  }
29
48
  export declare abstract class FindModel extends Disposable {
30
49
  abstract readonly unitId: string;
50
+ /**
51
+ * Find model should emit new matches from this observable if they changed no matter due to incremental
52
+ * or document's content changes.
53
+ */
54
+ abstract readonly matchesUpdate$: Observable<IFindMatch[]>;
55
+ abstract readonly activelyChangingMatch$: Observable<IFindMatch>;
31
56
  abstract getMatches(): IFindMatch[];
32
- abstract moveToNextMatch(loop?: boolean): IFindMatch | null;
33
- abstract moveToPreviousMatch(loop?: boolean): IFindMatch | null;
57
+ abstract moveToNextMatch(params?: IFindMoveParams): IFindMatch | null;
58
+ abstract moveToPreviousMatch(params?: IFindMoveParams): IFindMatch | null;
59
+ /** Replace the currently focused matching if there is one. */
60
+ abstract replace(replaceString: string): Promise<boolean>;
61
+ /**
62
+ * Replace all matches. This method would return how many
63
+ */
64
+ abstract replaceAll(replaceString: string): Promise<IReplaceAllResult>;
34
65
  }
35
66
  /**
36
67
  * A provider should be implemented by a business to provide the find results.
37
68
  */
38
69
  export interface IFindReplaceProvider {
39
70
  find(query: IFindQuery): Promise<FindModel[]>;
40
- cancel(): void;
71
+ terminate(): void;
41
72
  }
73
+ type IReplaceableMatch = IFindMatch & {
74
+ replaceable: boolean;
75
+ };
42
76
  /**
43
77
  * This service works as a core of the find & replace feature.
44
78
  */
45
79
  export interface IFindReplaceService {
46
80
  readonly stateUpdates$: Observable<Partial<IFindReplaceState>>;
47
81
  readonly state$: Observable<IFindReplaceState>;
82
+ readonly currentMatch$: Observable<Nullable<IFindMatch>>;
83
+ /** An observable value of all matches those could be replaced. */
84
+ readonly replaceables$: Observable<IReplaceableMatch[]>;
85
+ readonly focusSignal$: Observable<void>;
86
+ readonly revealed: boolean;
87
+ readonly replaceRevealed: boolean;
48
88
  /**
49
89
  * Register a find replace provider to the service. The provider is the actual bearer to
50
90
  * perform the find in different kinds of documents or different environments.
@@ -52,98 +92,193 @@ export interface IFindReplaceService {
52
92
  * @param provider the find replace provider
53
93
  */
54
94
  registerFindReplaceProvider(provider: IFindReplaceProvider): IDisposable;
95
+ /**
96
+ * Get find string from the internal state.
97
+ */
98
+ getFindString(): string;
55
99
  /**
56
100
  * Start a find & replace session.
57
101
  *
58
- * @returns if the find & replace session is created and user could start find replace
102
+ * @returns execution result
103
+ */
104
+ start(revealReplace?: boolean): boolean;
105
+ /**
106
+ * Terminate a find session and clear all caches.
59
107
  */
60
- start(): boolean;
61
- end(): boolean;
108
+ terminate(): void;
109
+ /**
110
+ * Start searching with the current conditions.
111
+ */
112
+ find(): void;
113
+ focusFindInput(): void;
62
114
  revealReplace(): void;
63
115
  changeFindString(value: string): void;
116
+ changeInputtingFindString(value: string): void;
117
+ changeReplaceString(value: string): void;
118
+ changeCaseSensitive(sensitive: boolean): void;
119
+ changeMatchesTheWholeCell(wholeCell: boolean): void;
120
+ changeFindScope(scope: FindScope): void;
121
+ changeFindDirection(direction: FindDirection): void;
122
+ changeFindBy(findBy: FindBy): void;
64
123
  moveToNextMatch(): void;
65
124
  moveToPreviousMatch(): void;
66
- replace(): boolean;
67
- replaceAll(): boolean;
125
+ replace(): Promise<boolean>;
126
+ replaceAll(): Promise<IReplaceAllResult>;
68
127
  }
69
128
  export declare const IFindReplaceService: import("@wendellhu/redi").IdentifierDecorator<IFindReplaceService>;
70
129
  /**
71
130
  * The find query object with finding options.
72
131
  */
73
- export interface IFindQuery {
74
- text: string;
75
- isRegex?: boolean;
76
- ignoreCase?: boolean;
77
- /** Other possible options set by business. */
78
- [key: string]: boolean | string | number | undefined;
79
- }
80
- /**
81
- * This class stores find replace options state. These state are stored
82
- * here instead of the React component so we can change state from
83
- * operations.
84
- */
85
- export declare class FindReplaceState {
86
- private readonly _stateUpdates$;
87
- readonly stateUpdates$: Observable<Partial<IFindReplaceState>>;
88
- private readonly _state$;
89
- readonly state$: Observable<IFindReplaceState>;
90
- get state(): IFindReplaceState;
91
- private _findString;
92
- private _revealed;
93
- private _replaceRevealed;
94
- private _matchesPosition;
95
- private _matchesCount;
96
- get findString(): string;
97
- changeState(changes: Partial<IFindReplaceState>): void;
132
+ export interface IFindQuery extends Pick<IFindReplaceState, 'replaceRevealed' | 'findString' | 'caseSensitive' | 'findBy' | 'findDirection' | 'findScope' | 'matchesTheWholeCell'> {
98
133
  }
99
134
  /**
100
135
  * This class stores find replace results and provides methods to perform replace or something.
136
+ *
137
+ * It **only** live through a find-replace session and would be disposed when the user
138
+ * close the find replace dialog (considered as session being terminated).
101
139
  */
102
140
  export declare class FindReplaceModel extends Disposable {
103
141
  private readonly _state;
104
142
  private readonly _providers;
105
- private readonly _logService;
106
143
  private readonly _univerInstanceService;
107
- private _matchPositionFindModel?;
144
+ private readonly _logService;
145
+ readonly currentMatch$: BehaviorSubject<Nullable<IFindMatch<unknown>>>;
146
+ readonly replaceables$: BehaviorSubject<IReplaceableMatch[]>;
147
+ /** All find models returned by providers. */
108
148
  private _findModels;
149
+ /** The find model that the current match is from. */
150
+ private _matchingModel;
109
151
  private _matches;
110
- private _positionModel;
111
- constructor(_state: FindReplaceState, _providers: Set<IFindReplaceProvider>, _logService: ILogService, _univerInstanceService: IUniverInstanceService);
112
- find(): Promise<IFindComplete>;
152
+ private _currentSearchingDisposables;
153
+ get searched(): boolean;
154
+ constructor(_state: FindReplaceState, _providers: Set<IFindReplaceProvider>, _univerInstanceService: IUniverInstanceService, _logService: ILogService);
155
+ dispose(): void;
156
+ start(): Promise<IFindComplete>;
157
+ /** Call this method to start a `searching`. */
158
+ private _startSearching;
159
+ /** Terminate the current searching session, when searching string is empty. */
160
+ private _stopSearching;
161
+ private _subscribeToModelsChanges;
162
+ replace(): Promise<boolean>;
163
+ replaceAll(): Promise<IReplaceAllResult>;
164
+ getCurrentMatch(): Nullable<IFindMatch>;
113
165
  moveToNextMatch(): void;
114
166
  moveToPreviousMatch(): void;
115
167
  private _moveToInitialMatch;
116
- private _cancelFinding;
168
+ }
169
+ export declare enum FindDirection {
170
+ /** Default. */
171
+ ROW = "row",
172
+ COLUMN = "column"
173
+ }
174
+ export declare enum FindBy {
175
+ VALUE = "value",
176
+ FORMULA = "formula"
177
+ }
178
+ export declare enum FindScope {
179
+ /** Default. */
180
+ SUBUNIT = "subunit",
181
+ /** Find the scope in the current unit. */
182
+ UNIT = "unit"
117
183
  }
118
184
  export interface IFindReplaceState {
119
185
  revealed: boolean;
120
186
  /** The string user inputs in the input box. */
121
187
  findString: string;
188
+ inputtingFindString: string;
122
189
  replaceString?: string;
123
190
  /** Indicates if is in replacing mode. */
124
191
  replaceRevealed: boolean;
125
192
  /** The currently focused match's index (1-based). */
126
193
  matchesPosition: number;
194
+ /** The number of all matches. */
127
195
  matchesCount: number;
196
+ /** Indicates if an user triggered finding process is progressed. */
197
+ findCompleted: boolean;
198
+ caseSensitive: boolean;
199
+ matchesTheWholeCell: boolean;
200
+ findDirection: FindDirection;
201
+ findScope: FindScope;
202
+ findBy: FindBy;
203
+ }
204
+ /**
205
+ * This class stores find replace options state. These state are stored
206
+ * here instead of the React component so we can change state from
207
+ * operations.
208
+ */
209
+ export declare class FindReplaceState {
210
+ private readonly _stateUpdates$;
211
+ readonly stateUpdates$: Observable<Partial<IFindReplaceState>>;
212
+ private readonly _state$;
213
+ readonly state$: Observable<IFindReplaceState>;
214
+ get state(): IFindReplaceState;
215
+ private _findString;
216
+ private _inputtingFindString;
217
+ private _replaceString;
218
+ private _revealed;
219
+ private _replaceRevealed;
220
+ private _matchesPosition;
221
+ private _matchesCount;
222
+ private _caseSensitive;
223
+ private _matchesTheWholeCell;
224
+ private _findDirection;
225
+ private _findScope;
226
+ private _findBy;
227
+ private _findCompleted;
228
+ get inputtingFindString(): string;
229
+ get findString(): string;
230
+ get revealed(): boolean;
231
+ get replaceRevealed(): boolean;
232
+ get matchesPosition(): number;
233
+ get matchesCount(): number;
234
+ get replaceString(): string;
235
+ get caseSensitive(): boolean;
236
+ get matchesTheWholeCell(): boolean;
237
+ get findDirection(): FindDirection;
238
+ get findScope(): FindScope;
239
+ get findBy(): FindBy;
240
+ get findCompleted(): boolean;
241
+ changeState(changes: Partial<IFindReplaceState>): void;
128
242
  }
129
243
  export declare class FindReplaceService extends Disposable implements IFindReplaceService {
130
244
  private readonly _injector;
131
- private readonly _univerInstanceService;
132
- private readonly _logService;
245
+ private readonly _contextService;
133
246
  private readonly _providers;
134
247
  private readonly _state;
135
248
  private _model;
249
+ private readonly _currentMatch$;
250
+ readonly currentMatch$: Observable<Nullable<IFindMatch<unknown>>>;
251
+ private readonly _replaceables$;
252
+ readonly replaceables$: Observable<IReplaceableMatch[]>;
253
+ private readonly _focusSignal$;
254
+ readonly focusSignal$: Observable<void>;
136
255
  get stateUpdates$(): Observable<Partial<IFindReplaceState>>;
137
256
  get state$(): Observable<IFindReplaceState>;
138
- constructor(_injector: Injector, _univerInstanceService: IUniverInstanceService, _logService: ILogService);
139
- changeFindString(value: string): void;
257
+ get revealed(): boolean;
258
+ get replaceRevealed(): boolean;
259
+ constructor(_injector: Injector, _contextService: IContextService);
260
+ dispose(): void;
261
+ getCurrentMatch(): Nullable<IFindMatch>;
262
+ getFindString(): string;
263
+ changeFindString(findString: string): void;
264
+ focusFindInput(): void;
265
+ changeInputtingFindString(value: string): void;
266
+ changeReplaceString(replaceString: string): void;
267
+ changeMatchesTheWholeCell(matchesTheWholeCell: boolean): void;
268
+ changeCaseSensitive(caseSensitive: boolean): void;
269
+ changeFindBy(findBy: FindBy): void;
270
+ changeFindScope(scope: FindScope): void;
271
+ changeFindDirection(direction: FindDirection): void;
140
272
  moveToNextMatch(): void;
141
273
  moveToPreviousMatch(): void;
142
- replace(): boolean;
143
- replaceAll(): boolean;
274
+ replace(): Promise<boolean>;
275
+ replaceAll(): Promise<IReplaceAllResult>;
144
276
  revealReplace(): void;
145
- disposeModel(): void;
146
- start(): boolean;
147
- end(): boolean;
277
+ start(revealReplace?: boolean): boolean;
278
+ find(): void;
279
+ terminate(): void;
148
280
  registerFindReplaceProvider(provider: IFindReplaceProvider): IDisposable;
281
+ private _toggleRevealReplace;
282
+ private _toggleDisplayRawFormula;
149
283
  }
284
+ export {};
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Copyright 2023-present DreamNum Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import React from 'react';
17
+ export declare const FindDialog: React.ForwardRefExoticComponent<React.RefAttributes<unknown>>;
18
+ export declare const ReplaceDialog: React.ForwardRefExoticComponent<React.RefAttributes<unknown>>;
19
+ export declare function FindReplaceDialog(): React.JSX.Element;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Copyright 2023-present DreamNum Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+ import type { LocaleService } from '@univerjs/core';
17
+ import type { IInputWithSlotProps } from '@univerjs/design';
18
+ import React from 'react';
19
+ import type { IFindReplaceService } from '../../services/find-replace.service';
20
+ export interface ISearchInputProps extends Pick<IInputWithSlotProps, 'onFocus' | 'onBlur' | 'className' | 'onChange'> {
21
+ findCompleted: boolean;
22
+ localeService: LocaleService;
23
+ findReplaceService: IFindReplaceService;
24
+ matchesPosition: number;
25
+ matchesCount: number;
26
+ findString: string;
27
+ }
28
+ export declare function SearchInput(props: ISearchInputProps): React.JSX.Element;