Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(find-replace): use esc to focus on selection #4746

Merged
merged 3 commits into from
Feb 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/design/src/components/dialog/Dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,12 @@ export interface IDialogProps {
* whether click mask to close, default is true
*/
maskClosable?: boolean;

/**
* whether support press esc to close
* @default true
*/
keyboard?: boolean;
}

export function Dialog(props: IDialogProps) {
Expand All @@ -130,6 +136,7 @@ export function Dialog(props: IDialogProps) {
footer,
onClose,
mask,
keyboard = true,
dialogStyles,
closable,
maskClosable,
Expand Down Expand Up @@ -234,6 +241,7 @@ export function Dialog(props: IDialogProps) {
styles={dialogStyles}
closable={closable}
maskClosable={maskClosable}
keyboard={keyboard}
>
{children}
</RcDialog>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,13 @@ export const GoToPreviousMatchOperation: IOperation = {
return true;
},
};

export const FocusSelectionOperation: IOperation = {
type: CommandType.OPERATION,
id: 'ui.operation.focus-selection',
handler: (accessor) => {
const findReplaceService = accessor.get(IFindReplaceService);
findReplaceService.focusSelection();
return true;
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { takeUntil } from 'rxjs';

import { ReplaceAllMatchesCommand, ReplaceCurrentMatchCommand } from '../commands/commands/replace.command';
import {
FocusSelectionOperation,
GoToNextMatchOperation,
GoToPreviousMatchOperation,
OpenFindDialogOperation,
Expand All @@ -45,6 +46,7 @@ import {
import { IFindReplaceService } from '../services/find-replace.service';
import { FindReplaceDialog } from '../views/dialog/FindReplaceDialog';
import {
FocusSelectionShortcutItem,
GoToNextFindMatchShortcutItem,
GoToPreviousFindMatchShortcutItem,
MacOpenFindDialogShortcutItem,
Expand Down Expand Up @@ -94,6 +96,7 @@ export class FindReplaceController extends RxDisposable {
GoToPreviousMatchOperation,
ReplaceAllMatchesCommand,
ReplaceCurrentMatchCommand,
FocusSelectionOperation,
].forEach((c) => {
this.disposeWithMe(this._commandService.registerCommand(c));
});
Expand All @@ -106,6 +109,7 @@ export class FindReplaceController extends RxDisposable {
MacOpenFindDialogShortcutItem,
GoToPreviousFindMatchShortcutItem,
GoToNextFindMatchShortcutItem,
FocusSelectionShortcutItem,
].forEach((s) => this.disposeWithMe(this._shortcutService.registerShortcut(s)));
}

Expand Down
18 changes: 16 additions & 2 deletions packages/find-replace/src/controllers/find-replace.shortcut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,13 @@
* limitations under the License.
*/

import { type IShortcutItem, KeyCode, MetaKeys } from '@univerjs/ui';
import type { IContextService } from '@univerjs/core';
import type { IShortcutItem } from '@univerjs/ui';

import { EDITOR_ACTIVATED, FOCUSING_SHEET, type IContextService } from '@univerjs/core';
import { EDITOR_ACTIVATED, FOCUSING_SHEET } from '@univerjs/core';
import { KeyCode, MetaKeys } from '@univerjs/ui';
import {
FocusSelectionOperation,
GoToNextMatchOperation,
GoToPreviousMatchOperation,
OpenFindDialogOperation,
Expand Down Expand Up @@ -100,3 +103,14 @@ export const GoToPreviousFindMatchShortcutItem: IShortcutItem = {
return whenFindReplaceInputFocused(contextService) && whenFindReplaceDialogFocused(contextService);
},
};

export const FocusSelectionShortcutItem: IShortcutItem = {
id: FocusSelectionOperation.id,
description: 'find-replace.shortcut.focus-selection',
binding: KeyCode.ESC,
group: FIND_REPLACE_SHORTCUT_GROUP,
priority: 1000,
preconditions(contextService) {
return whenFindReplaceDialogFocused(contextService);
},
};
1 change: 1 addition & 0 deletions packages/find-replace/src/locale/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const locale: typeof zhCN = {
'close-dialog': 'Close Find & Replace Dialog',
'go-to-next-match': 'Go to Next Match',
'go-to-previous-match': 'Go to Previous Match',
'focus-selection': 'Focus Selection',
},
dialog: {
title: 'Find',
Expand Down
1 change: 1 addition & 0 deletions packages/find-replace/src/locale/fa-IR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const locale: typeof zhCN = {
'close-dialog': 'بستن پنجره گفتگوی یافتن و جایگزینی',
'go-to-next-match': 'رفتن به تطابق بعدی',
'go-to-previous-match': 'رفتن به تطابق قبلی',
'focus-selection': 'تمرکز بر روی انتخاب',
},
dialog: {
title: 'یافتن',
Expand Down
1 change: 1 addition & 0 deletions packages/find-replace/src/locale/fr-FR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const locale: typeof enUS = {
'close-dialog': 'Fermer la boîte de dialogue Rechercher & Remplacer',
'go-to-next-match': 'Aller à la correspondance suivante',
'go-to-previous-match': 'Aller à la correspondance précédente',
'focus-selection': 'Focus sur la sélection',
},
dialog: {
title: 'Rechercher',
Expand Down
1 change: 1 addition & 0 deletions packages/find-replace/src/locale/ru-RU.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const locale: typeof zhCN = {
'close-dialog': 'Закрыть диалог поиска и замены',
'go-to-next-match': 'Перейти к следующему совпадению',
'go-to-previous-match': 'Перейти к предыдущему совпадению',
'focus-selection': 'Фокус на выделении',
},
dialog: {
title: 'Найти',
Expand Down
1 change: 1 addition & 0 deletions packages/find-replace/src/locale/vi-VN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const locale: typeof zhCN = {
'close-dialog': 'Đóng hộp thoại tìm kiếm và thay thế',
'go-to-next-match': 'Đến mục khớp tiếp theo',
'go-to-previous-match': 'Đến mục khớp trước đó',
'focus-selection': 'Tập trung vào lựa chọn',
},
dialog: {
title: 'Tìm kiếm',
Expand Down
1 change: 1 addition & 0 deletions packages/find-replace/src/locale/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const locale = {
'close-dialog': '关闭查找替换对话框',
'go-to-next-match': '下一个匹配项',
'go-to-previous-match': '下一个匹配项',
'focus-selection': '聚焦选区',
},
dialog: {
title: '查找',
Expand Down
1 change: 1 addition & 0 deletions packages/find-replace/src/locale/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const locale: typeof zhCN = {
'close-dialog': '關閉查找替換對話框',
'go-to-next-match': '下一個匹配項',
'go-to-previous-match': '下一個匹配項',
'focus-selection': '聚焦選區',
},
dialog: {
title: '找',
Expand Down
23 changes: 18 additions & 5 deletions packages/find-replace/src/services/find-replace.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import type { IDisposable, Nullable } from '@univerjs/core';
import type { Observable } from 'rxjs';
import { createIdentifier, Disposable, DisposableCollection, IContextService, Inject, Injector, IUniverInstanceService, toDisposable } from '@univerjs/core';
import { createIdentifier, Disposable, DisposableCollection, ICommandService, IContextService, Inject, Injector, IUniverInstanceService, toDisposable } from '@univerjs/core';
import { RENDER_RAW_FORMULA_KEY } from '@univerjs/engine-render';
import { BehaviorSubject, combineLatest, debounceTime, Subject, throttleTime } from 'rxjs';
import { FIND_REPLACE_REPLACE_REVEALED } from './context-keys';
Expand Down Expand Up @@ -80,6 +80,8 @@ export abstract class FindModel extends Disposable {
* Replace all matches. This method would return how many
*/
abstract replaceAll(replaceString: string): Promise<IReplaceAllResult>;

abstract focusSelection(): void;
}

/**
Expand Down Expand Up @@ -154,6 +156,11 @@ export interface IFindReplaceService {
replace(): Promise<boolean>;
replaceAll(): Promise<IReplaceAllResult>;

/**
* Focus the selection of the current match.
*/
focusSelection(): void;

getProviders(): Set<IFindReplaceProvider>;
}
export const IFindReplaceService = createIdentifier<IFindReplaceService>('find-replace.service');
Expand Down Expand Up @@ -212,7 +219,8 @@ export class FindReplaceModel extends Disposable {
constructor(
private readonly _state: FindReplaceState,
private readonly _providers: Set<IFindReplaceProvider>,
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService,
@ICommandService private readonly _commandService: ICommandService
) {
super();

Expand Down Expand Up @@ -254,6 +262,10 @@ export class FindReplaceModel extends Disposable {
return complete;
}

focusSelection(): void {
this._matchingModel?.focusSelection();
}

/** Call this method to start a `searching`. */
private async _startSearching(): Promise<IFindComplete> {
if (!this._state.findString) {
Expand Down Expand Up @@ -502,9 +514,6 @@ export interface IFindReplaceState {
findBy: FindBy;
}

/**
*
*/
export function createInitFindReplaceState(): IFindReplaceState {
return {
caseSensitive: false,
Expand Down Expand Up @@ -813,6 +822,10 @@ export class FindReplaceService extends Disposable implements IFindReplaceServic
this._toggleRevealReplace(true);
}

focusSelection(): void {
this._model?.focusSelection();
}

start(revealReplace = false): boolean {
if (this._providers.size === 0) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,6 @@ function useFindScopeOptions(localeService: LocaleService): Array<{ label: strin
{ label: localeService.t('find-replace.dialog.find-scope.current-sheet'), value: FindScope.SUBUNIT },
{ label: localeService.t('find-replace.dialog.find-scope.workbook'), value: FindScope.UNIT },
];
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [locale]);

return options;
Expand All @@ -318,7 +317,6 @@ function useFindDirectionOptions(localeService: LocaleService): Array<{ label: s
{ label: localeService.t('find-replace.dialog.find-direction.row'), value: FindDirection.ROW },
{ label: localeService.t('find-replace.dialog.find-direction.column'), value: FindDirection.COLUMN },
];
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [locale]);

return options;
Expand All @@ -331,7 +329,6 @@ function useFindByOptions(localeService: LocaleService): Array<{ label: string;
{ label: localeService.t('find-replace.dialog.find-by.value'), value: FindBy.VALUE },
{ label: localeService.t('find-replace.dialog.find-by.formula'), value: FindBy.FORMULA },
];
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [locale]);

return options;
Expand Down
7 changes: 3 additions & 4 deletions packages/find-replace/src/views/dialog/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@

import type { LocaleService } from '@univerjs/core';
import type { IInputWithSlotProps } from '@univerjs/design';
import { InputWithSlot, Pager } from '@univerjs/design';
import React from 'react';
import type { IFindReplaceService } from '../../services/find-replace.service';
import { InputWithSlot, Pager } from '@univerjs/design';

export interface ISearchInputProps extends Pick<IInputWithSlotProps, 'onFocus' | 'onBlur' | 'className' | 'onChange'> {
findCompleted: boolean;
Expand All @@ -40,11 +39,11 @@ export function SearchInput(props: ISearchInputProps) {

return (
<InputWithSlot
autoFocus={true}
autoFocus
placeholder={localeService.t('find-replace.dialog.find-placeholder')}
slot={(
<Pager
loop={true}
loop
text={text}
value={matchesPosition}
total={matchesCount}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export class SheetsDrawingLoadController extends Disposable {
@IResourceManagerService private _resourceManagerService: IResourceManagerService
) {
super();

this._initSnapshot();

this.disposeWithMe(this._commandService.registerCommand(SetDrawingApplyMutation));
}

Expand All @@ -41,18 +43,22 @@ export class SheetsDrawingLoadController extends Disposable {
if (map) {
return JSON.stringify(map);
}

return '';
};

const parseJson = (json: string): IDrawingSubunitMap<ISheetDrawing> => {
if (!json) {
return {};
}

try {
return JSON.parse(json);
} catch (err) {
} catch {
return {};
}
};

this.disposeWithMe(
this._resourceManagerService.registerPluginResource<IDrawingSubunitMap<ISheetDrawing>>({
pluginName: SHEET_DRAWING_PLUGIN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export class SheetsFilterController extends Disposable {
this.disposeWithMe(this._sheetInterceptorService.interceptCommand({
getMutations: (command) => this._getUpdateFilter(command),
}));

this.disposeWithMe(this._commandService.onCommandExecuted((commandInfo) => {
if (commandInfo.id === SetWorksheetActiveOperation.id) {
const params = commandInfo.params as ISetWorksheetActiveOperationParams;
Expand Down Expand Up @@ -150,9 +151,11 @@ export class SheetsFilterController extends Disposable {
if (!unitId || !subUnitId || !targetSubUnitId) {
return this._handleNull();
}

return this._handleCopySheetCommand(unitId, subUnitId, targetSubUnitId);
}
}

return {
redos: [],
undos: [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

import type { ICellData, IDisposable, IObjectMatrixPrimitiveType, IRange, Nullable, Workbook, Worksheet } from '@univerjs/core';
import type { IFindComplete, IFindMatch, IFindMoveParams, IFindQuery, IFindReplaceProvider, IReplaceAllResult } from '@univerjs/find-replace';
import type { ISelectionWithStyle, ISetRangeValuesCommandParams, ISetSelectionsOperationParams, ISetWorksheetActivateCommandParams, ISheetCommandSharedParams, WorkbookSelectionModel } from '@univerjs/sheets';
import type { ISelectionWithStyle, ISelectRangeCommandParams, ISetRangeValuesCommandParams, ISetSelectionsOperationParams, ISetWorksheetActivateCommandParams, ISheetCommandSharedParams, WorkbookSelectionModel } from '@univerjs/sheets';
import type { IScrollToCellCommandParams } from '@univerjs/sheets-ui';
import type { ISheetReplaceCommandParams, ISheetReplacement } from '../commands/commands/sheet-replace.command';
import type { ISheetFindReplaceHighlightShapeProps } from '../views/shapes/find-replace-highlight.shape';
import { ColorKit, CommandType, Disposable, EDITOR_ACTIVATED, fromCallback, groupBy, ICommandService, IContextService, Inject, Injector, IUniverInstanceService, ObjectMatrix, replaceInDocumentBody, rotate, ThemeService, Tools, UniverInstanceType } from '@univerjs/core';
import { IRenderManagerService, RENDER_RAW_FORMULA_KEY } from '@univerjs/engine-render';
import { FindBy, FindDirection, FindModel, FindReplaceController, FindScope, IFindReplaceService } from '@univerjs/find-replace';
import { SetRangeValuesCommand, SetSelectionsOperation, SetWorksheetActivateCommand, SetWorksheetActiveOperation, SheetsSelectionsService } from '@univerjs/sheets';
import { SelectRangeCommand, SetRangeValuesCommand, SetSelectionsOperation, SetWorksheetActivateCommand, SetWorksheetActiveOperation, SheetsSelectionsService } from '@univerjs/sheets';

import { getCoordByCell, getSheetObject, ScrollToCellCommand, SheetSkeletonManagerService } from '@univerjs/sheets-ui';
import { debounceTime, filter, merge, skip, Subject, throttleTime } from 'rxjs';
Expand Down Expand Up @@ -164,6 +164,18 @@ export class SheetFindModel extends FindModel {
}
}

override focusSelection(): void {
const currentMatch = this.currentMatch;
if (!currentMatch) return;

this._commandService.executeCommand(SelectRangeCommand.id, {
unitId: currentMatch.unitId,
subUnit: currentMatch.range.subUnitId,
range: currentMatch.range.range,

} as ISelectRangeCommandParams);
}

private _toggleDisplayRawFormula(force: boolean): void {
this._contextService.setContextValue(RENDER_RAW_FORMULA_KEY, force);
}
Expand Down
Loading