sendou.ink/app/components/Input.tsx
Kalle 5a73adea97 Add ArrowDown shortcut to jump from search input to results in CommandPalette
Instead of requiring users to Tab through all radio buttons to reach
search results, ArrowDown now jumps directly from the input to the
ListBox. This matches the UX of other command palettes like VS Code
and Spotlight.

- Add onKeyDown prop to Input component
- Replace Enter→input handler with ArrowDown→results handler
- Remove unnecessary wrapper div with biome-ignore comment

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 20:57:20 +02:00

87 lines
1.6 KiB
TypeScript

import clsx from "clsx";
import styles from "./Input.module.css";
export function Input({
name,
id,
className,
minLength,
maxLength,
required,
defaultValue,
leftAddon,
icon,
type,
min,
max,
pattern,
list,
testId,
"aria-label": ariaLabel,
value,
placeholder,
onChange,
onKeyDown,
disableAutoComplete = false,
readOnly,
ref,
}: {
name?: string;
id?: string;
className?: string;
minLength?: number;
maxLength?: number;
required?: boolean;
defaultValue?: string;
leftAddon?: string;
icon?: React.ReactNode;
type?: "number" | "date";
min?: number;
max?: number | string;
pattern?: string;
list?: string;
testId?: string;
"aria-label"?: string;
value?: string;
placeholder?: string;
onChange?: (e: React.ChangeEvent<HTMLInputElement>) => void;
onKeyDown?: (e: React.KeyboardEvent<HTMLInputElement>) => void;
disableAutoComplete?: boolean;
readOnly?: boolean;
ref?: React.Ref<HTMLInputElement>;
}) {
return (
<div
className={clsx(styles.container, className, {
[styles.readOnly]: readOnly,
})}
>
{leftAddon ? <div className={styles.addon}>{leftAddon}</div> : null}
<input
ref={ref}
className="in-container"
name={name}
id={id}
minLength={minLength}
maxLength={maxLength}
min={min}
max={max}
defaultValue={defaultValue}
pattern={pattern}
list={list}
data-testid={testId}
value={value}
onChange={onChange}
onKeyDown={onKeyDown}
aria-label={ariaLabel}
required={required}
placeholder={placeholder}
type={type}
autoComplete={disableAutoComplete ? "one-time-code" : undefined}
readOnly={readOnly}
/>
{icon}
</div>
);
}