Files
lanspread/crates/lanspread-tauri-deno-ts/src/components/topbar/SearchField.tsx
T
ddidderr 50698f9a7d feat(ui): add search clear button
Search now exposes a small icon-only clear button whenever a query is present.
Clicking it clears the term in one step and returns focus to the input so users
can immediately type a replacement.

The button uses the existing topbar styling language and a compact circled-x
icon alongside the keyboard hint.

Test Plan:
- git diff --check

Refs: user redesign nitpick about one-click search clearing
2026-05-19 20:48:46 +02:00

69 lines
2.1 KiB
TypeScript

import { useEffect, useRef } from 'react';
import { Icon } from '../Icon';
interface Props {
value: string;
onChange: (value: string) => void;
}
/**
* Search input with a `/` keyboard shortcut for focus. Ignores the shortcut
* when the user is already typing into another input or textarea.
*/
export const SearchField = ({ value, onChange }: Props) => {
const inputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if (e.key !== '/') return;
const target = e.target as HTMLElement | null;
if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')) return;
e.preventDefault();
inputRef.current?.focus();
};
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, []);
const blurInput = () => inputRef.current?.blur();
return (
<div className="search">
<Icon.search />
<input
ref={inputRef}
type="text"
placeholder="Search games"
value={value}
onChange={(e) => onChange(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
blurInput();
} else if (e.key === 'Escape') {
e.preventDefault();
onChange('');
blurInput();
}
}}
spellCheck={false}
/>
{value && (
<button
className="search-clear"
type="button"
aria-label="Clear search"
onClick={() => {
onChange('');
inputRef.current?.focus();
}}
>
<Icon.clearCircle />
</button>
)}
<span className="search-kbd">/</span>
</div>
);
};