feat(find-replace): enhance SearchInput component with keyboard navigation (#5589)

This commit is contained in:
白熱
2025-07-25 21:25:54 +08:00
committed by GitHub
parent 6595c020e5
commit 1d5df3d68b
3 changed files with 33 additions and 16 deletions
@@ -18,7 +18,6 @@ import type { IDisposable, Nullable } from '@univerjs/core';
import {
ICommandService,
Inject,
Injector,
IUniverInstanceService,
LocaleService,
RxDisposable,
@@ -63,8 +62,7 @@ export class FindReplaceController extends RxDisposable {
@IDialogService private readonly _dialogService: IDialogService,
@ILayoutService private readonly _layoutService: ILayoutService,
@Inject(LocaleService) private readonly _localeService: LocaleService,
@Inject(ComponentManager) private readonly _componentManager: ComponentManager,
@Inject(Injector) private readonly _injector: Injector
@Inject(ComponentManager) private readonly _componentManager: ComponentManager
) {
super();
@@ -74,7 +74,6 @@ export const FindDialog = forwardRef(function FindDialogImpl(_props, ref) {
<>
<SearchInput
findCompleted={findCompleted}
className="univer-find-input"
matchesCount={matchesCount}
matchesPosition={matchesPosition}
findReplaceService={findReplaceService}
@@ -16,6 +16,7 @@
import type { LocaleService } from '@univerjs/core';
import type { IInputProps } from '@univerjs/design';
import type { KeyboardEvent } from 'react';
import type { IFindReplaceService } from '../../services/find-replace.service';
import { Input, Pager } from '@univerjs/design';
import { useState } from 'react';
@@ -30,7 +31,17 @@ export interface ISearchInputProps extends Pick<IInputProps, 'onFocus' | 'onBlur
}
export function SearchInput(props: ISearchInputProps) {
const { findCompleted: findComplete, localeService, matchesCount, matchesPosition, initialFindString, findReplaceService, onChange, ...rest } = props;
const {
findCompleted: findComplete,
localeService,
matchesCount,
matchesPosition,
initialFindString,
findReplaceService,
onChange,
...rest
} = props;
const [value, setValue] = useState(initialFindString);
const noResult = findComplete && matchesCount === 0;
const text = noResult
@@ -39,6 +50,24 @@ export function SearchInput(props: ISearchInputProps) {
? ' '
: undefined;
function handleChangePosition(newIndex: number) {
if (matchesPosition === matchesCount && newIndex === 1) {
findReplaceService.moveToNextMatch();
} else if (matchesPosition === 1 && newIndex === matchesCount) {
findReplaceService.moveToPreviousMatch();
} else if (newIndex < matchesPosition) {
findReplaceService.moveToPreviousMatch();
} else {
findReplaceService.moveToNextMatch();
}
}
function handleEnter(event: KeyboardEvent<HTMLInputElement>) {
if (event.key === 'Enter') {
handleChangePosition(matchesPosition + 1);
}
}
return (
<div className="univer-relative univer-flex univer-items-center univer-gap-2" onDrag={(e) => e.stopPropagation()}>
<Input
@@ -50,23 +79,14 @@ export function SearchInput(props: ISearchInputProps) {
setValue(value);
onChange?.(value);
}}
onKeyDown={handleEnter}
slot={(
<Pager
loop
text={text}
value={matchesPosition}
total={matchesCount}
onChange={(newIndex) => {
if (matchesPosition === matchesCount && newIndex === 1) {
findReplaceService.moveToNextMatch();
} else if (matchesPosition === 1 && newIndex === matchesCount) {
findReplaceService.moveToPreviousMatch();
} else if (newIndex < matchesPosition) {
findReplaceService.moveToPreviousMatch();
} else {
findReplaceService.moveToNextMatch();
}
}}
onChange={handleChangePosition}
/>
)}
{...rest}