bazarr/frontend/src/components/SearchBar.tsx

103 lines
2.0 KiB
TypeScript

import React, {
FunctionComponent,
useCallback,
useEffect,
useMemo,
useState,
} from "react";
import { Dropdown, Form } from "react-bootstrap";
import { useHistory } from "react-router";
import { useThrottle } from "rooks";
export interface SearchResult {
id: string;
name: string;
link?: string;
}
interface Props {
className?: string;
onSearch: (text: string) => Promise<SearchResult[]>;
onFocus?: () => void;
onBlur?: () => void;
}
export const SearchBar: FunctionComponent<Props> = ({
onSearch,
onFocus,
onBlur,
className,
}) => {
const [text, setText] = useState("");
const [results, setResults] = useState<SearchResult[]>([]);
const history = useHistory();
const search = useCallback(
(value: string) => {
if (value === "") {
setResults([]);
} else {
onSearch(value).then((res) => setResults(res));
}
},
[onSearch]
);
const [debounceSearch] = useThrottle(search, 500);
useEffect(() => {
debounceSearch(text);
}, [text, debounceSearch]);
const clear = useCallback(() => {
setText("");
setResults([]);
}, []);
const items = useMemo(() => {
const its = results.map((v) => (
<Dropdown.Item
key={v.id}
eventKey={v.link}
disabled={v.link === undefined}
>
<span>{v.name}</span>
</Dropdown.Item>
));
if (its.length === 0) {
its.push(<Dropdown.Header key="notify">No Found</Dropdown.Header>);
}
return its;
}, [results]);
return (
<Dropdown
show={text.length !== 0}
className={className}
onFocus={onFocus}
onBlur={onBlur}
onSelect={(link) => {
if (link) {
clear();
history.push(link);
}
}}
>
<Form.Control
type="text"
size="sm"
placeholder="Search..."
value={text}
onChange={(e) => setText(e.currentTarget.value)}
></Form.Control>
<Dropdown.Menu style={{ maxHeight: 256, overflowY: "auto" }}>
{items}
</Dropdown.Menu>
</Dropdown>
);
};