|
@@ -5,6 +5,11 @@ import { Combobox, Listbox, Transition } from '@headlessui/react'
|
|
|
import classNames from 'classnames'
|
|
|
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from '@heroicons/react/20/solid'
|
|
|
import { useTranslation } from 'react-i18next'
|
|
|
+import {
|
|
|
+ PortalToFollowElem,
|
|
|
+ PortalToFollowElemContent,
|
|
|
+ PortalToFollowElemTrigger,
|
|
|
+} from '@/app/components/base/portal-to-follow-elem'
|
|
|
|
|
|
const defaultItems = [
|
|
|
{ value: 1, name: 'option1' },
|
|
@@ -222,5 +227,83 @@ const SimpleSelect: FC<ISelectProps> = ({
|
|
|
</Listbox>
|
|
|
)
|
|
|
}
|
|
|
-export { SimpleSelect }
|
|
|
+
|
|
|
+type PortalSelectProps = {
|
|
|
+ value: string | number
|
|
|
+ onSelect: (value: Item) => void
|
|
|
+ items: Item[]
|
|
|
+ placeholder?: string
|
|
|
+ popupClassName?: string
|
|
|
+}
|
|
|
+const PortalSelect: FC<PortalSelectProps> = ({
|
|
|
+ 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 (
|
|
|
+ <PortalToFollowElem
|
|
|
+ open={open}
|
|
|
+ onOpenChange={setOpen}
|
|
|
+ placement='bottom-start'
|
|
|
+ offset={4}
|
|
|
+ >
|
|
|
+ <PortalToFollowElemTrigger onClick={() => setOpen(v => !v)} className='w-full'>
|
|
|
+ <div
|
|
|
+ className={`
|
|
|
+ flex items-center justify-between px-2.5 h-9 rounded-lg border-0 bg-gray-100 text-sm cursor-pointer
|
|
|
+ `}
|
|
|
+ title={selectedItem?.name}
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ className={`
|
|
|
+ grow truncate
|
|
|
+ ${!selectedItem?.name && 'text-gray-400'}
|
|
|
+ `}
|
|
|
+ >
|
|
|
+ {selectedItem?.name ?? localPlaceholder}
|
|
|
+ </span>
|
|
|
+ <ChevronDownIcon className='shrink-0 h-4 w-4 text-gray-400' />
|
|
|
+ </div>
|
|
|
+ </PortalToFollowElemTrigger>
|
|
|
+ <PortalToFollowElemContent className={`z-20 ${popupClassName}`}>
|
|
|
+ <div
|
|
|
+ className='px-1 py-1 max-h-60 overflow-auto rounded-md bg-white text-base shadow-lg border-gray-200 border-[0.5px] focus:outline-none sm:text-sm'
|
|
|
+ >
|
|
|
+ {items.map((item: Item) => (
|
|
|
+ <div
|
|
|
+ key={item.value}
|
|
|
+ className={`
|
|
|
+ flex items-center justify-between px-2.5 h-9 cursor-pointer rounded-lg hover:bg-gray-100 text-gray-700
|
|
|
+ ${item.value === value && 'bg-gray-100'}
|
|
|
+ `}
|
|
|
+ title={item.name}
|
|
|
+ onClick={() => {
|
|
|
+ onSelect(item)
|
|
|
+ setOpen(false)
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ className='grow truncate'
|
|
|
+ title={item.name}
|
|
|
+ >
|
|
|
+ {item.name}
|
|
|
+ </span>
|
|
|
+ {item.value === value && (
|
|
|
+ <CheckIcon className='shrink-0 h-4 w-4' />
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ ))}
|
|
|
+ </div>
|
|
|
+ </PortalToFollowElemContent>
|
|
|
+ </PortalToFollowElem>
|
|
|
+ )
|
|
|
+}
|
|
|
+export { SimpleSelect, PortalSelect }
|
|
|
export default React.memo(Select)
|