import React, { useEffect, useMemo, useRef, useState } from "react"; import { Text } from "../Text"; import { Popover, PopoverContent, PopoverTrigger } from "../Popover"; import { Input } from "../Input"; import { cx, focusRing } from "../../lib/utils"; import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/20/solid"; export const SearchSelect: React.FC<{ items: { value: string; label: string }[]; className?: string; defaultValue?: string; value?: string; placeholder?: string; onValueChange: (val: string) => void; }> = ({ items, className, defaultValue, value, onValueChange, placeholder, }) => { const [open, setOpen] = useState(false); const [internalValue, setInternalValue] = useState(""); const [query, setQuery] = useState(""); const ref = useRef(); const [width, setWidth] = useState(0); useEffect(() => { if (!ref.current) return; const resizeObserver = new ResizeObserver(() => { // Do what you want to do when the size of the element changes setWidth(ref.current?.offsetWidth || 0); }); resizeObserver.observe(ref.current); return () => resizeObserver.disconnect(); // clean up }, []); let data = useMemo( () => items.filter((a) => { return ( a.label.toLowerCase().search(query.toLowerCase()) >= 0 || a.value.toLowerCase().search(query.toLowerCase()) >= 0 ); }), [query, items] ); useEffect(() => { if (value && value.trim() !== "") { setInternalValue(value); return; } if (defaultValue && defaultValue.trim() !== "") { setInternalValue(defaultValue); return; } setInternalValue(""); }, [defaultValue, value]); const text = useMemo(() => { if (internalValue && internalValue.trim() !== "") { let item = items.find((a) => a.value === internalValue); return item?.label || placeholder || "Select"; } return placeholder || "Select"; }, [internalValue, placeholder]); return ( { setOpen(o); if (!o) onValueChange(internalValue); }} >
{text}
{ setQuery(e.target.value); e.preventDefault(); }} />
{data.map((item) => (
{ setInternalValue(item.value); setOpen(false); onValueChange(item.value); }} key={item.value} className={cx( // base "onvo-grid onvo-cursor-pointer onvo-grid-cols-[1fr_20px] onvo-gap-x-2 onvo-rounded onvo-px-3 onvo-py-2 onvo-outline-none onvo-transition-colors data-[state=checked]:onvo-font-semibold sm:onvo-text-sm", // text color "onvo-text-gray-900 dark:onvo-text-gray-50", // disabled "data-[disabled]:onvo-pointer-events-none data-[disabled]:onvo-text-gray-400 data-[disabled]:hover:onvo-bg-none dark:data-[disabled]:onvo-text-gray-600", // focus "focus-visible:onvo-bg-gray-100 focus-visible:dark:onvo-bg-gray-900", // hover "hover:onvo-bg-gray-100 hover:dark:onvo-bg-gray-900" )} > {item.label} {item.value === internalValue && (
))}
); };