Skip to content

Commit 28a4699

Browse files
committed
Improved search bar behaviour
1 parent 3316ff7 commit 28a4699

File tree

1 file changed

+26
-36
lines changed

1 file changed

+26
-36
lines changed
Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,46 @@
11
import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/20/solid";
2-
import { useNavigate } from "@remix-run/react";
32
import { motion } from "framer-motion";
43
import { useCallback, useEffect, useRef, useState } from "react";
54
import { Input } from "~/components/primitives/Input";
65
import { ShortcutKey } from "~/components/primitives/ShortcutKey";
76
import { cn } from "~/utils/cn";
87
import { useOptimisticLocation } from "~/hooks/useOptimisticLocation";
8+
import { useSearchParams } from "~/hooks/useSearchParam";
99

1010
export function LogsSearchInput() {
1111
const location = useOptimisticLocation();
12-
const navigate = useNavigate();
1312
const inputRef = useRef<HTMLInputElement>(null);
1413

14+
const { value, replace, del } = useSearchParams();
15+
1516
// Get initial search value from URL
16-
const searchParams = new URLSearchParams(location.search);
17-
const initialSearch = searchParams.get("search") ?? "";
17+
const initialSearch = value("search") ?? "";
1818

1919
const [text, setText] = useState(initialSearch);
2020
const [isFocused, setIsFocused] = useState(false);
2121

2222
// Update text when URL search param changes (only when not focused to avoid overwriting user input)
2323
useEffect(() => {
24-
const params = new URLSearchParams(location.search);
25-
const urlSearch = params.get("search") ?? "";
24+
const urlSearch = value("search") ?? "";
2625
if (urlSearch !== text && !isFocused) {
2726
setText(urlSearch);
2827
}
29-
// eslint-disable-next-line react-hooks/exhaustive-deps
30-
}, [location.search]);
28+
}, [value, text, isFocused]);
3129

3230
const handleSubmit = useCallback(() => {
33-
const params = new URLSearchParams(location.search);
3431
if (text.trim()) {
35-
params.set("search", text.trim());
32+
replace({ search: text.trim() });
3633
} else {
37-
params.delete("search");
34+
del("search");
3835
}
39-
// Reset cursor when searching
40-
params.delete("cursor");
41-
params.delete("direction");
42-
navigate(`${location.pathname}?${params.toString()}`, { replace: true });
43-
}, [text, location.pathname, location.search, navigate]);
36+
}, [text, replace, del]);
4437

45-
const handleClear = useCallback(() => {
38+
const handleClear = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
39+
e.preventDefault();
40+
e.stopPropagation();
4641
setText("");
47-
const params = new URLSearchParams(location.search);
48-
params.delete("search");
49-
params.delete("cursor");
50-
params.delete("direction");
51-
navigate(`${location.pathname}?${params.toString()}`, { replace: true });
52-
}, [location.pathname, location.search, navigate]);
42+
del(["search", "cursor", "direction"]);
43+
}, []);
5344

5445
return (
5546
<div className="flex items-center gap-1">
@@ -71,7 +62,7 @@ export function LogsSearchInput() {
7162
value={text}
7263
onChange={(e) => setText(e.target.value)}
7364
fullWidth
74-
className={cn(isFocused && "placeholder:text-text-dimmed/70")}
65+
className={cn("", isFocused && "placeholder:text-text-dimmed/70")}
7566
onKeyDown={(e) => {
7667
if (e.key === "Enter") {
7768
e.preventDefault();
@@ -86,22 +77,21 @@ export function LogsSearchInput() {
8677
icon={<MagnifyingGlassIcon className="size-4" />}
8778
accessory={
8879
text.length > 0 ? (
89-
<ShortcutKey shortcut={{ key: "enter" }} variant="small" />
80+
<div className="-mr-1 flex items-center gap-1">
81+
<ShortcutKey shortcut={{ key: "enter" }} variant="small" />
82+
<button
83+
type="button"
84+
onClick={handleClear}
85+
className="flex size-4.5 items-center justify-center rounded-[2px] border border-text-dimmed/40 text-text-dimmed hover:bg-charcoal-700 hover:text-text-bright"
86+
title="Clear search"
87+
>
88+
<XMarkIcon className="size-3" />
89+
</button>
90+
</div>
9091
) : undefined
9192
}
9293
/>
9394
</motion.div>
94-
95-
{text.length > 0 && (
96-
<button
97-
type="button"
98-
onClick={handleClear}
99-
className="flex size-6 items-center justify-center rounded text-text-dimmed hover:bg-charcoal-700 hover:text-text-bright"
100-
title="Clear search"
101-
>
102-
<XMarkIcon className="size-4" />
103-
</button>
104-
)}
10595
</div>
10696
);
10797
}

0 commit comments

Comments
 (0)