new-personal-site/components/lib/elements/Search.tsx

104 lines
2.7 KiB
TypeScript
Raw Normal View History

2024-12-09 15:36:17 +00:00
import { twMerge } from "tailwind-merge";
2025-01-05 06:25:38 +00:00
import Input, { InputProps } from "../form/Input";
2024-12-09 15:36:17 +00:00
import Button from "../layout/Button";
import Row from "../layout/Row";
import { Search as SearchIcon } from "lucide-react";
import React, {
DetailedHTMLProps,
InputHTMLAttributes,
TextareaHTMLAttributes,
} from "react";
let timeout: any;
2025-01-05 06:25:38 +00:00
export type SearchProps<KeyType extends string> = DetailedHTMLProps<
2024-12-09 15:36:17 +00:00
React.HTMLAttributes<HTMLDivElement>,
HTMLDivElement
> & {
dispatch?: (value?: string) => void;
delay?: number;
2025-01-05 06:25:38 +00:00
inputProps?: InputProps<KeyType>;
2024-12-09 15:36:17 +00:00
buttonProps?: DetailedHTMLProps<
React.ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
>;
};
/**
* # Search Component
* @className_wrapper twui-search-wrapper
* @className_circle twui-search-input
* @className_circle twui-search-button
*/
2025-01-05 06:25:38 +00:00
export default function Search<KeyType extends string>({
2024-12-09 15:36:17 +00:00
dispatch,
delay = 500,
inputProps,
buttonProps,
...props
2025-01-05 06:25:38 +00:00
}: SearchProps<KeyType>) {
2024-12-09 15:36:17 +00:00
const [input, setInput] = React.useState("");
React.useEffect(() => {
clearTimeout(timeout);
timeout = setTimeout(() => {
dispatch?.(input);
}, delay);
}, [input]);
const inputRef = React.useRef<HTMLInputElement>();
React.useEffect(() => {
if (props.autoFocus) {
inputRef.current?.focus();
}
}, []);
return (
<Row
{...props}
className={twMerge(
"relative xl:flex-nowrap items-stretch gap-0",
"twui-search-wrapper",
props?.className
)}
>
<Input
type="search"
placeholder="Search"
{...inputProps}
value={input}
onChange={(e) => setInput(e.target.value)}
className={twMerge(
"rounded-r-none",
"twui-search-input",
inputProps?.className
)}
wrapperProps={{
className: "rounded-r-none",
}}
componentRef={inputRef}
/>
<Button
{...buttonProps}
variant="outlined"
color="gray"
className={twMerge(
"rounded-l-none my-[1px]",
"twui-search-button",
buttonProps?.className
)}
onClick={() => {
dispatch?.(input);
}}
>
<SearchIcon
className="text-slate-800 dark:text-white"
size={20}
/>
</Button>
</Row>
);
}