48 lines
1.8 KiB
TypeScript
48 lines
1.8 KiB
TypeScript
import clsx from "clsx";
|
|
import { useTranslation } from "react-i18next";
|
|
import ButtonPrimary from "../buttons/ButtonPrimary";
|
|
import { TextInput } from "~/ui/components/TextInput";
|
|
|
|
interface Props {
|
|
value: string;
|
|
setValue: React.Dispatch<React.SetStateAction<string>>;
|
|
onNew?: () => void;
|
|
onNewRoute?: string;
|
|
placeholder?: string;
|
|
className?: string;
|
|
disabled?: boolean;
|
|
size?: "xs" | "sm" | "md";
|
|
}
|
|
|
|
// Subframe migration (strangler shim): renders Subframe TextInput with type="search"
|
|
// (built-in search icon) behind the original InputSearch API. Subframe's own SearchInput
|
|
// is purely presentational (hardcoded value="", no children/onChange/value binding) and
|
|
// cannot back a controlled field, so TextInput is the correct controlled target — mirrors
|
|
// the InputText shim. See docs/subframe/COMPONENT-MAPPING.md.
|
|
export default function InputSearch({ value, setValue, onNew, onNewRoute, placeholder, className, disabled, size = "md" }: Props) {
|
|
const { t } = useTranslation();
|
|
const resolvedPlaceholder = placeholder ?? t("shared.searchDot");
|
|
return (
|
|
<div className={clsx("flex justify-between space-x-2", className)}>
|
|
<TextInput
|
|
className="w-full max-w-none"
|
|
type="search"
|
|
disabled={disabled}
|
|
size={size === "md" ? "medium" : "small"}
|
|
>
|
|
<TextInput.Input
|
|
type="search"
|
|
value={value}
|
|
onChange={(e) => setValue(e.currentTarget.value)}
|
|
placeholder={resolvedPlaceholder}
|
|
aria-label={resolvedPlaceholder}
|
|
autoComplete="off"
|
|
disabled={disabled}
|
|
/>
|
|
</TextInput>
|
|
{onNew && <ButtonPrimary onClick={onNew}>{t("shared.new")}</ButtonPrimary>}
|
|
{onNewRoute && <ButtonPrimary to={onNewRoute}>{t("shared.new")}</ButtonPrimary>}
|
|
</div>
|
|
);
|
|
}
|