'use client' import type { FC } from 'react' import React, { Fragment, useEffect, useState } from 'react' import { Combobox, Listbox, Transition } from '@headlessui/react' import { CheckIcon, ChevronDownIcon, ChevronUpIcon, XMarkIcon } from '@heroicons/react/20/solid' import { useTranslation } from 'react-i18next' import classNames from '@/utils/classnames' import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, } from '@/app/components/base/portal-to-follow-elem' const defaultItems = [ { value: 1, name: 'option1' }, { value: 2, name: 'option2' }, { value: 3, name: 'option3' }, { value: 4, name: 'option4' }, { value: 5, name: 'option5' }, { value: 6, name: 'option6' }, { value: 7, name: 'option7' }, ] export type Item = { value: number | string name: string } export type ISelectProps = { className?: string wrapperClassName?: string items?: Item[] defaultValue?: number | string disabled?: boolean onSelect: (value: Item) => void allowSearch?: boolean bgClassName?: string placeholder?: string overlayClassName?: string optionClassName?: string } const Select: FC = ({ className, items = defaultItems, defaultValue = 1, disabled = false, onSelect, allowSearch = true, bgClassName = 'bg-gray-100', overlayClassName, optionClassName, }) => { const [query, setQuery] = useState('') const [open, setOpen] = useState(false) const [selectedItem, setSelectedItem] = useState(null) useEffect(() => { let defaultSelect = null const existed = items.find((item: Item) => item.value === defaultValue) if (existed) defaultSelect = existed setSelectedItem(defaultSelect) }, [defaultValue]) const filteredItems: Item[] = query === '' ? items : items.filter((item) => { return item.name.toLowerCase().includes(query.toLowerCase()) }) return ( { if (!disabled) { setSelectedItem(value) setOpen(false) onSelect(value) } }}>
{allowSearch ? { if (!disabled) setQuery(event.target.value) }} displayValue={(item: Item) => item?.name} /> : { if (!disabled) setOpen(!open) } } className={classNames(optionClassName, `flex items-center h-9 w-full rounded-lg border-0 ${bgClassName} py-1.5 pl-3 pr-10 shadow-sm sm:text-sm sm:leading-6 focus-visible:outline-none focus-visible:bg-gray-200 group-hover:bg-gray-200`)}>
{selectedItem?.name}
} { if (!disabled) setOpen(!open) } }> {open ? : }
{filteredItems.length > 0 && ( {filteredItems.map((item: Item) => ( classNames( optionClassName, 'relative cursor-default select-none py-2 pl-3 pr-9 rounded-lg hover:bg-gray-100 text-gray-700', active ? 'bg-gray-100' : '', ) } > {({ /* active, */ selected }) => ( <> {item.name} {selected && ( )} )} ))} )}
) } const SimpleSelect: FC = ({ className, wrapperClassName = '', items = defaultItems, defaultValue = 1, disabled = false, onSelect, placeholder, }) => { const { t } = useTranslation() const localPlaceholder = placeholder || t('common.placeholder.select') const [selectedItem, setSelectedItem] = useState(null) useEffect(() => { let defaultSelect = null const existed = items.find((item: Item) => item.value === defaultValue) if (existed) defaultSelect = existed setSelectedItem(defaultSelect) }, [defaultValue]) return ( { if (!disabled) { setSelectedItem(value) onSelect(value) } }} >
{selectedItem?.name ?? localPlaceholder} {selectedItem ? ( { e.stopPropagation() setSelectedItem(null) onSelect({ name: '', value: '' }) }} className="h-5 w-5 text-gray-400 cursor-pointer" aria-hidden="false" /> ) : ( {!disabled && ( {items.map((item: Item) => ( `relative cursor-pointer select-none py-2 pl-3 pr-9 rounded-lg hover:bg-gray-100 text-gray-700 ${active ? 'bg-gray-100' : '' }` } value={item} disabled={disabled} > {({ /* active, */ selected }) => ( <> {item.name} {selected && ( )} )} ))} )}
) } type PortalSelectProps = { value: string | number onSelect: (value: Item) => void items: Item[] placeholder?: string popupClassName?: string } const PortalSelect: FC = ({ value, onSelect, items, placeholder, popupClassName, }) => { const { t } = useTranslation() const [open, setOpen] = useState(false) const localPlaceholder = placeholder || t('common.placeholder.select') const selectedItem = items.find(item => item.value === value) return ( setOpen(v => !v)} className='w-full'>
{selectedItem?.name ?? localPlaceholder}
{items.map((item: Item) => (
{ onSelect(item) setOpen(false) }} > {item.name} {item.value === value && ( )}
))}
) } export { SimpleSelect, PortalSelect } export default React.memo(Select)