Track HiveGrid Cloud planning reference
This commit is contained in:
1 parent
b3d5ea6764
commit
e341c5938a
5784 files changed
+1104929
-3
No files matched your search
@@ -0,0 +1,68 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSearchParams } from "react-router";
|
||||
import ButtonPrimary from "../buttons/ButtonPrimary";
|
||||
import clsx from "clsx";
|
||||
import { TextInput } from "~/ui/components/TextInput";
|
||||
|
||||
interface Props {
|
||||
onNew?: () => void;
|
||||
onNewRoute?: string;
|
||||
placeholder?: string;
|
||||
size?: "xs" | "sm" | "lg";
|
||||
className?: string;
|
||||
}
|
||||
|
||||
// Subframe migration (strangler shim): renders Subframe TextInput with type="search"
|
||||
// (built-in search icon) behind the original API. The debounced URL-sync logic is
|
||||
// unchanged. Subframe's own SearchInput is presentational only and cannot back a
|
||||
// controlled field. See docs/subframe/COMPONENT-MAPPING.md.
|
||||
export default function InputSearchWithURL({ onNew, onNewRoute, placeholder, size = "lg", className }: Props) {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [search, setSearch] = useState(searchParams.get("q")?.toString() ?? "");
|
||||
const [debouncedSearch, setDebouncedSearch] = useState(searchParams.get("q")?.toString() ?? "");
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => setDebouncedSearch(search), 500);
|
||||
return () => clearTimeout(timer);
|
||||
}, [search]);
|
||||
|
||||
useEffect(() => {
|
||||
const query = searchParams.get("q") ?? "";
|
||||
if (query !== debouncedSearch) {
|
||||
searchParams.set("q", debouncedSearch);
|
||||
if (searchParams.get("page")) {
|
||||
searchParams.set("page", "1");
|
||||
}
|
||||
if (searchParams.get("pageSize")) {
|
||||
// searchParams.delete("pageSize");
|
||||
}
|
||||
setSearchParams(searchParams, {
|
||||
preventScrollReset: true,
|
||||
});
|
||||
}
|
||||
}, [debouncedSearch, searchParams, setSearchParams]);
|
||||
|
||||
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" size={size === "lg" ? "medium" : "small"}>
|
||||
<TextInput.Input
|
||||
type="search"
|
||||
name="q"
|
||||
aria-label={resolvedPlaceholder}
|
||||
placeholder={resolvedPlaceholder}
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.currentTarget.value)}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</TextInput>
|
||||
|
||||
{onNew && <ButtonPrimary onClick={onNew}>{t("shared.new")}</ButtonPrimary>}
|
||||
{onNewRoute && <ButtonPrimary to={onNewRoute}>{t("shared.new")}</ButtonPrimary>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user