import { useState, useEffect, useRef, MutableRefObject, ReactNode, } from "react"; import { useShallow } from "zustand/react/shallow"; import { useHotkeys } from "react-hotkeys-hook"; import { CommandIcon, MagnifyingGlassIcon, XIcon, HourglassHighIcon, } from "@phosphor-icons/react"; import ReactGA from "react-ga4"; import { useDebounce } from "@/hooks"; import "./SearchInput.css"; import { useApplicationStore } from "@/state"; const apple = /iPhone|iPod|iPad|Macintosh|MacIntel|MacPPC/i; const isApple = apple.test(window.navigator.platform); const mobile = /Android|iPhone|iPod|iPad|Opera Mini|IEMobile/i; const isMobile = mobile.test(window.navigator.userAgent); type SearchInputProps = {}; const SearchInput = (_: SearchInputProps) => { const [value, setValue] = useState(""); const { query, setQuery } = useApplicationStore(useShallow((state) => ({ query: state.searchQuery, setQuery: state.setSearchQuery, }))); const inputRef = useRef() as MutableRefObject; useHotkeys("ctrl+k,meta+k", (e) => { e.preventDefault(); if (!e.repeat) { inputRef.current?.focus(); inputRef.current.select(); } }); /* eslint-disable react-hooks/exhaustive-deps */ useEffect(() => { let isMounted = true; if (value !== query) { isMounted && setValue(query); ReactGA.event({ category: "Search", action: "Tag", label: query }); } return () => void (isMounted = false); }, [query]); /* eslint-enable react-hooks/exhaustive-deps */ const [_isReady, _cancel] = useDebounce( () => { if (value !== query) { setQuery(value); !!value && ReactGA.event({ category: "Search", action: "Query", label: value }); } !!value && void document .getElementById("beacon") ?.scrollIntoView({ block: "start", behavior: "smooth" }); }, 500, [value] ); const handleCancelSearch = () => { setValue(""); // Should cancel pending debounce timeouts and immediately clear query // without causing lag! // setQuery(""); }; return (
setValue(currentTarget.value)} onKeyDown={({ currentTarget, key }) => (key === "Enter" || key === "Escape") && currentTarget.blur() } /> {!value && !isMobile && {isApple ? : "Ctrl + "}K} {value ? ( value === query ? ( ) : ( ) ) : null}
); }; const Keys = ({ children }: { children?: ReactNode }) => (
{children}
); export default SearchInput;