refactor: custom search select component (#440)

This commit is contained in:
Aaryan Khandelwal 2023-03-15 10:59:43 +05:30 committed by GitHub
parent bcd2ac1317
commit 32d37ec45e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,10 +1,8 @@
import React, { useState } from "react"; import React, { useState } from "react";
// headless ui // headless ui
import { Combobox, Transition } from "@headlessui/react"; import { Combobox, Transition } from "@headlessui/react";
// icons // icons
import { CheckIcon, ChevronDownIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import { CheckIcon, ChevronDownIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline";
type CustomSearchSelectProps = { type CustomSearchSelectProps = {
value: any; value: any;
onChange: any; onChange: any;
@ -25,7 +23,6 @@ type CustomSearchSelectProps = {
multiple?: boolean; multiple?: boolean;
footerOption?: JSX.Element; footerOption?: JSX.Element;
}; };
export const CustomSearchSelect = ({ export const CustomSearchSelect = ({
label, label,
textAlignment, textAlignment,
@ -49,221 +46,119 @@ export const CustomSearchSelect = ({
? options ? options
: options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase()));
const props: any = {
value,
onChange,
disabled,
};
if (multiple) props.multiple = true;
return ( return (
<> <Combobox
{/* TODO: Improve this multiple logic */} as="div"
{multiple ? ( className={`${!selfPositioned ? "relative" : ""} flex-shrink-0 text-left`}
<Combobox {...props}
as="div" >
value={value} {({ open }: any) => (
onChange={onChange} <>
className={`${!selfPositioned ? "relative" : ""} flex-shrink-0 text-left`} {customButton ? (
disabled={disabled} <Combobox.Button as="div">{customButton}</Combobox.Button>
multiple ) : (
> <Combobox.Button
{({ open }: any) => ( className={`flex w-full ${
<> disabled ? "cursor-not-allowed" : "cursor-pointer hover:bg-gray-100"
{customButton ? ( } items-center justify-between gap-1 rounded-md border px-3 py-1.5 text-xs shadow-sm duration-300 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 ${
<Combobox.Button as="div">{customButton}</Combobox.Button> textAlignment === "right"
) : ( ? "text-right"
<Combobox.Button : textAlignment === "center"
className={`flex w-full ${ ? "text-center"
disabled ? "cursor-not-allowed" : "cursor-pointer hover:bg-gray-100" : "text-left"
} items-center justify-between gap-1 rounded-md border px-2.5 py-1 text-xs shadow-sm duration-300 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 ${ }`}
textAlignment === "right" >
? "text-right" {label}
: textAlignment === "center" {!noChevron && !disabled && (
? "text-center" <ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
: "text-left"
}`}
>
{label}
{!noChevron && !disabled && (
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
)}
</Combobox.Button>
)} )}
</Combobox.Button>
<Transition
show={open}
as={React.Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
>
<Combobox.Options
className={`${optionsClassName} absolute min-w-[10rem] p-2 ${
position === "right" ? "right-0" : "left-0"
} z-10 mt-1 origin-top-right rounded-md bg-white text-xs shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none`}
>
<div className="flex w-full items-center justify-start rounded-sm border-[0.6px] bg-gray-100 px-2">
<MagnifyingGlassIcon className="h-3 w-3 text-gray-500" />
<Combobox.Input
className="w-full bg-transparent py-1 px-2 text-xs text-gray-500 focus:outline-none"
onChange={(e) => setQuery(e.target.value)}
placeholder="Type to search..."
displayValue={(assigned: any) => assigned?.name}
/>
</div>
<div
className={`mt-2 space-y-1 ${
height === "sm"
? "max-h-28"
: height === "md"
? "max-h-44"
: height === "rg"
? "max-h-56"
: height === "lg"
? "max-h-80"
: ""
} overflow-y-scroll`}
>
{filteredOptions ? (
filteredOptions.length > 0 ? (
filteredOptions.map((option) => (
<Combobox.Option
key={option.value}
value={option.value}
className={({ active, selected }) =>
`${active || selected ? "bg-hover-gray" : ""} ${
selected ? "font-medium" : ""
} flex cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5 text-gray-500`
}
>
{({ active, selected }) => (
<>
{option.content}
<div
className={`flex items-center justify-center rounded border border-gray-500 p-0.5 ${
active || selected ? "opacity-100" : "opacity-0"
}`}
>
<CheckIcon
className={`h-3 w-3 ${selected ? "opacity-100" : "opacity-0"}`}
/>
</div>
</>
)}
</Combobox.Option>
))
) : (
<p className="text-center text-gray-500">No matching results</p>
)
) : (
<p className="text-center text-gray-500">Loading...</p>
)}
</div>
{footerOption}
</Combobox.Options>
</Transition>
</>
)} )}
</Combobox> <Transition
) : ( show={open}
<Combobox as={React.Fragment}
as="div" enter="transition ease-out duration-200"
value={value} enterFrom="opacity-0 translate-y-1"
onChange={onChange} enterTo="opacity-100 translate-y-0"
className={`${!selfPositioned ? "relative" : ""} flex-shrink-0 text-left`} leave="transition ease-in duration-150"
disabled={disabled} leaveFrom="opacity-100 translate-y-0"
> leaveTo="opacity-0 translate-y-1"
{({ open }: any) => ( >
<> <Combobox.Options
{customButton ? ( className={`${optionsClassName} absolute min-w-[10rem] p-2 ${
<Combobox.Button as="div">{customButton}</Combobox.Button> position === "right" ? "right-0" : "left-0"
) : ( } z-10 mt-1 origin-top-right rounded-md bg-white text-xs shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none`}
<Combobox.Button >
className={`flex w-full ${ <div className="flex w-full items-center justify-start rounded-sm border-[0.6px] bg-gray-100 px-2">
disabled ? "cursor-not-allowed" : "cursor-pointer hover:bg-gray-100" <MagnifyingGlassIcon className="h-3 w-3 text-gray-500" />
} items-center justify-between gap-1 rounded-md border px-2.5 py-1 text-xs shadow-sm duration-300 focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 ${ <Combobox.Input
textAlignment === "right" className="w-full bg-transparent py-1 px-2 text-xs text-gray-500 focus:outline-none"
? "text-right" onChange={(e) => setQuery(e.target.value)}
: textAlignment === "center" placeholder="Type to search..."
? "text-center" displayValue={(assigned: any) => assigned?.name}
: "text-left" />
}`} </div>
> <div
{label} className={`mt-2 space-y-1 ${
{!noChevron && !disabled && ( height === "sm"
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" /> ? "max-h-28"
)} : height === "md"
</Combobox.Button> ? "max-h-44"
)} : height === "rg"
? "max-h-56"
<Transition : height === "lg"
show={open} ? "max-h-80"
as={React.Fragment} : ""
enter="transition ease-out duration-200" } overflow-y-scroll`}
enterFrom="opacity-0 translate-y-1"
enterTo="opacity-100 translate-y-0"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 translate-y-0"
leaveTo="opacity-0 translate-y-1"
> >
<Combobox.Options {filteredOptions ? (
className={`${optionsClassName} absolute min-w-[10rem] p-2 ${ filteredOptions.length > 0 ? (
position === "right" ? "right-0" : "left-0" filteredOptions.map((option) => (
} z-10 mt-1 origin-top-right rounded-md bg-white text-xs shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none`} <Combobox.Option
> key={option.value}
<div className="flex w-full items-center justify-start rounded-sm border bg-gray-100 px-2 text-gray-500"> value={option.value}
<MagnifyingGlassIcon className="h-3 w-3" /> className={({ active, selected }) =>
<Combobox.Input `${active || selected ? "bg-hover-gray" : ""} ${
className="w-full bg-transparent py-1 px-2 text-xs focus:outline-none" selected ? "font-medium" : ""
onChange={(e) => setQuery(e.target.value)} } flex cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5 text-gray-500`
placeholder="Type to search..." }
displayValue={(assigned: any) => assigned?.name} >
/> {({ active, selected }) => (
</div> <>
<div {option.content}
className={`mt-2 space-y-1 ${ <div
height === "sm" className={`flex items-center justify-center rounded border border-gray-500 p-0.5 ${
? "max-h-28" active || selected ? "opacity-100" : "opacity-0"
: height === "md" }`}
? "max-h-44" >
: height === "rg" <CheckIcon
? "max-h-56" className={`h-3 w-3 ${selected ? "opacity-100" : "opacity-0"}`}
: height === "lg" />
? "max-h-80" </div>
: "" </>
} overflow-y-scroll`} )}
> </Combobox.Option>
{filteredOptions ? ( ))
filteredOptions.length > 0 ? ( ) : (
filteredOptions.map((option) => ( <p className="text-center text-gray-500">No matching results</p>
<Combobox.Option )
key={option.value} ) : (
value={option.value} <p className="text-center text-gray-500">Loading...</p>
className={({ active, selected }) => )}
`${active || selected ? "bg-hover-gray" : ""} ${ </div>
selected ? "font-medium" : "" {footerOption}
} flex cursor-pointer select-none items-center justify-between gap-2 truncate rounded px-1 py-1.5 text-gray-500` </Combobox.Options>
} </Transition>
> </>
{({ selected }) => (
<>
{option.content}
{selected && <CheckIcon className="h-4 w-4" />}
</>
)}
</Combobox.Option>
))
) : (
<p className="text-center text-gray-500">No matching results</p>
)
) : (
<p className="text-center text-gray-500">Loading...</p>
)}
</div>
{footerOption}
</Combobox.Options>
</Transition>
</>
)}
</Combobox>
)} )}
</> </Combobox>
); );
}; };