'use client'; import { CheckIcon, ChevronDownIcon, XIcon } from 'lucide-react'; import { Fragment, MouseEventHandler, ReactNode, forwardRef, useCallback, useEffect, useId, useMemo, useState, } from 'react'; import { Button } from '@/components/ui/button'; import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, } from '@/components/ui/command'; import { Popover, PopoverContent, PopoverTrigger, } from '@/components/ui/popover'; import { cn } from '@/lib/utils'; import { t } from 'i18next'; import { RAGFlowSelectOptionType } from '../ui/select'; import { Separator } from '../ui/separator'; export type SelectWithSearchFlagOptionType = { label: ReactNode; value?: string; disabled?: boolean; options?: RAGFlowSelectOptionType[]; }; export type SelectWithSearchFlagProps = { options?: SelectWithSearchFlagOptionType[]; value?: string; onChange?(value: string): void; triggerClassName?: string; allowClear?: boolean; disabled?: boolean; placeholder?: string; emptyData?: string; }; function findLabelWithoutOptions( options: SelectWithSearchFlagOptionType[], value: string, ) { return options.find((opt) => opt.value === value)?.label || ''; } function findLabelWithOptions( options: SelectWithSearchFlagOptionType[], value: string, ) { return options .map((group) => group?.options?.find((item) => item.value === value)) .filter(Boolean)[0]?.label; } export const SelectWithSearch = forwardRef< React.ElementRef, SelectWithSearchFlagProps >( ( { value: val = '', onChange, options = [], triggerClassName, allowClear = false, disabled = false, placeholder = t('common.selectPlaceholder'), emptyData = t('common.noDataFound'), }, ref, ) => { const id = useId(); const [open, setOpen] = useState(false); const [value, setValue] = useState(''); const selectLabel = useMemo(() => { if (options.every((x) => x.options === undefined)) { return findLabelWithoutOptions(options, value); } else if (options.every((x) => Array.isArray(x.options))) { return findLabelWithOptions(options, value); } else { // Some have options, some don't const optionsWithOptions = options.filter((x) => Array.isArray(x.options), ); const optionsWithoutOptions = options.filter( (x) => x.options === undefined, ); const label = findLabelWithOptions(optionsWithOptions, value); if (label) { return label; } return findLabelWithoutOptions(optionsWithoutOptions, value); } }, [options, value]); const handleSelect = useCallback( (val: string) => { setValue(val); setOpen(false); onChange?.(val); }, [onChange], ); const handleClear: MouseEventHandler = useCallback( (e) => { e.stopPropagation(); setValue(''); onChange?.(''); }, [onChange], ); useEffect(() => { setValue(val); }, [val]); return ( {options && options.length > 0 && ( )} {emptyData} {options.map((group, idx) => { if (group.options) { return ( {group.options.map((option) => ( {option.label} {value === option.value && ( )} ))} ); } else { return ( {group.label} {value === group.value && ( )} ); } })} ); }, ); SelectWithSearch.displayName = 'SelectWithSearch';