Created
July 28, 2022 08:41
-
-
Save muhrusdi/093f7ab703e11871bfedb7da2fa93cca to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Listbox, Transition } from "@headlessui/react" | |
import { Button } from "@nextui-org/react" | |
import { Fragment, useState } from "react" | |
import { FiChevronDown } from "react-icons/fi" | |
import cn from "classnames" | |
import { Controller, get, useFormContext } from "react-hook-form" | |
import { PatternType, RoleMapType } from "@/types" | |
import { helperText } from "@/utils/constants" | |
type LocalSelectProps = { | |
children: React.ReactNode | |
defaultValue?: string | |
label?: string | |
name?: string | |
message?: string | |
required?: boolean | |
map?: RoleMapType | |
pattern?: PatternType | |
placeholder?: string | |
fullWidth?: boolean | |
} | |
type ItemProps = { | |
children: React.ReactNode | |
value: string | number | |
} | |
const LocalSelect: React.FC<LocalSelectProps> = ({ | |
children, | |
label, | |
fullWidth, | |
message, | |
required, | |
pattern, | |
map, | |
placeholder, | |
...props | |
}) => { | |
const { control, formState } = useFormContext() | |
const error = get(formState.errors, props.name ?? "") | |
return ( | |
<Controller | |
{...props} | |
name={props.name ?? ""} | |
control={control} | |
rules={{ required: message ?? required, pattern }} | |
render={({ field }) => { | |
return ( | |
<Listbox value={field.value} onChange={field.onChange}> | |
{label ? ( | |
<label className="mb-[0.375rem] pl-[0.25rem] text-[0.875rem] block"> | |
{label} | |
</label> | |
) : null} | |
<div className="relative"> | |
<Listbox.Button | |
className={cn({ ["w-full"]: fullWidth })} | |
auto | |
color="success" | |
bordered | |
css={{ | |
borderColor: "$border", | |
justifyContent: "space-between", | |
height: 44, | |
color: "$text", | |
}} | |
iconRight={<FiChevronDown />} | |
as={Button} | |
> | |
{map | |
? map[field.value || ""] | |
? map[field.value || ""] | |
: field.value | |
: field.value || placeholder} | |
</Listbox.Button> | |
<Transition | |
as={Fragment} | |
leave="transition ease-in duration-100" | |
leaveFrom="opacity-100" | |
leaveTo="opacity-0" | |
> | |
<Listbox.Options className="absolute mt-1 max-h-60 w-full z-[999999] overflow-auto rounded-md bg-white py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"> | |
{children} | |
</Listbox.Options> | |
</Transition> | |
</div> | |
{error?.type ? ( | |
<div className="mt-[0.125rem] ml-[0.625rem] text-[#11181C] text-[0.625rem]"> | |
{error?.message || helperText} | |
</div> | |
) : null} | |
</Listbox> | |
) | |
}} | |
/> | |
) | |
} | |
const Item: React.FC<ItemProps> = ({ children, ...props }) => { | |
return ( | |
<Listbox.Option | |
className={({ active }) => | |
`relative cursor-default select-none py-2 px-4 mb-0 ${ | |
active ? "bg-amber-100 text-amber-900" : "text-gray-900" | |
}` | |
} | |
{...props} | |
> | |
{({ selected }) => ( | |
<span | |
className={`block truncate ${ | |
selected ? "font-medium" : "font-normal" | |
}`} | |
> | |
{children} | |
</span> | |
)} | |
</Listbox.Option> | |
) | |
} | |
export const Select = Object.assign(LocalSelect, { Item }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment