import { useCallback, useState, } from 'react' import { useTranslation } from 'react-i18next' import { RiArrowDownSLine, RiCheckLine, } from '@remixicon/react' import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, } from '@/app/components/base/portal-to-follow-elem' import type { PortalToFollowElemOptions, } from '@/app/components/base/portal-to-follow-elem' import cn from '@/utils/classnames' export type Option = { label: string value: string } export type CustomSelectProps = { options: T[] value?: string onChange?: (value: string) => void containerProps?: PortalToFollowElemOptions & { open?: boolean onOpenChange?: (open: boolean) => void } triggerProps?: { className?: string }, popupProps?: { wrapperClassName?: string className?: string itemClassName?: string title?: string }, CustomTrigger?: (option: T | undefined, open: boolean) => React.JSX.Element CustomOption?: (option: T, selected: boolean) => React.JSX.Element } const CustomSelect = ({ options, value, onChange, containerProps, triggerProps, popupProps, CustomTrigger, CustomOption, }: CustomSelectProps) => { const { t } = useTranslation() const { open, onOpenChange, placement, offset, } = containerProps || {} const { className: triggerClassName, } = triggerProps || {} const { wrapperClassName: popupWrapperClassName, className: popupClassName, itemClassName: popupItemClassName, } = popupProps || {} const [localOpen, setLocalOpen] = useState(false) const mergedOpen = open ?? localOpen const handleOpenChange = useCallback((openValue: boolean) => { onOpenChange?.(openValue) setLocalOpen(openValue) }, [onOpenChange]) const selectedOption = options.find(option => option.value === value) const triggerText = selectedOption?.label || t('common.placeholder.select') return ( handleOpenChange(!mergedOpen)} asChild >
{CustomTrigger ? CustomTrigger(selectedOption, mergedOpen) : ( <>
{triggerText}
)}
{ options.map((option) => { const selected = value === option.value return (
{ onChange?.(option.value) handleOpenChange(false) }} > {CustomOption ? CustomOption(option, selected) : ( <>
{option.label}
{ selected && } )}
) }) }
) } export default CustomSelect