fix(ui): reserve search clear button space

Typing the first character into the launcher search field used to insert the
clear button into the flex row, which widened the field after focus. The clear
button now stays mounted in the row so its slot is part of the empty field's
layout, while the empty state hides and disables it.

Users now get the wider steady-state search width immediately, and the control
does not jump when the clear affordance becomes visible.

Test Plan:
- git diff --check
- just frontend-test
- just build

Refs: user-reported search field jump
This commit is contained in:
2026-05-21 19:57:30 +02:00
parent debb1c0c49
commit a7d99261cf
2 changed files with 18 additions and 13 deletions
@@ -13,6 +13,7 @@ interface Props {
*/
export const SearchField = ({ value, onChange }: Props) => {
const inputRef = useRef<HTMLInputElement | null>(null);
const clearClassName = value ? 'search-clear' : 'search-clear is-hidden';
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
@@ -51,19 +52,19 @@ export const SearchField = ({ value, onChange }: Props) => {
}}
spellCheck={false}
/>
{value && (
<button
className="search-clear"
type="button"
aria-label="Clear search"
onClick={() => {
onChange('');
inputRef.current?.focus();
}}
>
<Icon.clearCircle />
</button>
)}
<button
className={clearClassName}
type="button"
aria-label="Clear search"
aria-hidden={value ? undefined : true}
disabled={!value}
onClick={() => {
onChange('');
inputRef.current?.focus();
}}
>
<Icon.clearCircle />
</button>
<span className="search-kbd">/</span>
</div>
);
@@ -304,6 +304,10 @@
color: var(--t-1);
background: rgba(255, 255, 255, 0.08);
}
.search-clear.is-hidden {
visibility: hidden;
pointer-events: none;
}
.search-kbd {
display: inline-grid;
place-items: center;