import React from "react"; // headless ui import { Listbox, Transition } from "@headlessui/react"; // icons import { ChevronDownIcon } from "@heroicons/react/20/solid"; import { CheckIcon } from "@heroicons/react/24/outline"; // types import { DropdownProps } from "./types"; export type CustomSelectProps = DropdownProps & { children: React.ReactNode; value: any; onChange: any; }; const CustomSelect = ({ buttonClassName = "", children, className = "", customButton, disabled = false, input = false, label, maxHeight = "md", noChevron = false, onChange, optionsClassName = "", position = "left", selfPositioned = false, value, verticalPosition = "bottom", width = "auto", }: CustomSelectProps) => ( <Listbox as="div" value={value} onChange={onChange} className={`${selfPositioned ? "" : "relative"} flex-shrink-0 text-left ${className}`} disabled={disabled} > <> {customButton ? ( <Listbox.Button as={React.Fragment}>{customButton}</Listbox.Button> ) : ( <Listbox.Button type="button" className={`flex items-center justify-between gap-1 w-full rounded-md border border-custom-border-300 shadow-sm duration-300 focus:outline-none ${ input ? "px-3 py-2 text-sm" : "px-2.5 py-1 text-xs" } ${ disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80" } ${buttonClassName}`} > {label} {!noChevron && !disabled && <ChevronDownIcon className="h-3 w-3" aria-hidden="true" />} </Listbox.Button> )} </> <Transition as={React.Fragment} enter="transition ease-out duration-100" enterFrom="transform opacity-0 scale-95" enterTo="transform opacity-100 scale-100" leave="transition ease-in duration-75" leaveFrom="transform opacity-100 scale-100" leaveTo="transform opacity-0 scale-95" > <Listbox.Options className={`absolute z-10 border border-custom-border-300 mt-1 origin-top-right overflow-y-auto rounded-md bg-custom-background-90 text-xs shadow-lg focus:outline-none ${ position === "left" ? "left-0 origin-top-left" : "right-0 origin-top-right" } ${verticalPosition === "top" ? "bottom-full mb-1" : "mt-1"} ${ maxHeight === "lg" ? "max-h-60" : maxHeight === "md" ? "max-h-48" : maxHeight === "rg" ? "max-h-36" : maxHeight === "sm" ? "max-h-28" : "" } ${width === "auto" ? "min-w-[8rem] whitespace-nowrap" : width} ${optionsClassName}`} > <div className="space-y-1 p-2">{children}</div> </Listbox.Options> </Transition> </Listbox> ); type OptionProps = { children: React.ReactNode; value: any; className?: string; }; const Option: React.FC<OptionProps> = ({ children, value, className }) => ( <Listbox.Option value={value} className={({ active, selected }) => `cursor-pointer select-none truncate rounded px-1 py-1.5 ${ active || selected ? "bg-custom-background-80" : "" } ${selected ? "text-custom-text-100" : "text-custom-text-200"} ${className}` } > {({ selected }) => ( <div className="flex items-center justify-between gap-2"> <div className="flex items-center gap-2">{children}</div> {selected && <CheckIcon className="h-4 w-4 flex-shrink-0" />} </div> )} </Listbox.Option> ); CustomSelect.Option = Option; export { CustomSelect };