({
value,
optionConfig,
disabled,
placeholder,
onChange,
}: {
value: string[];
optionConfig: OptionConfig;
disabled?: boolean;
placeholder?: string;
onChange: (value: string[]) => void;
})
| 434 | // ============================================================ |
| 435 | |
| 436 | function MultiSearchableSelect({ |
| 437 | value, |
| 438 | optionConfig, |
| 439 | disabled, |
| 440 | placeholder, |
| 441 | onChange, |
| 442 | }: { |
| 443 | value: string[]; |
| 444 | optionConfig: OptionConfig; |
| 445 | disabled?: boolean; |
| 446 | placeholder?: string; |
| 447 | onChange: (value: string[]) => void; |
| 448 | }) { |
| 449 | const { t } = useTranslation(); |
| 450 | const [search, setSearch] = useState(""); |
| 451 | const [open, setOpen] = useState(false); |
| 452 | const [searchOptions, setSearchOptions] = useState<SearchableSelectOption[]>( |
| 453 | [] |
| 454 | ); |
| 455 | const [loading, setLoading] = useState(false); |
| 456 | const triggerRef = useRef<HTMLDivElement>(null); |
| 457 | const dropdownRef = useRef<HTMLDivElement>(null); |
| 458 | const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null); |
| 459 | const [knownOptions, setKnownOptions] = useState<SearchableSelectOption[]>( |
| 460 | [] |
| 461 | ); |
| 462 | |
| 463 | const allOptions = useMemo(() => { |
| 464 | if (optionConfig.search) { |
| 465 | const merged = new Map<string, SearchableSelectOption>(); |
| 466 | for (const o of knownOptions) merged.set(o.value, o); |
| 467 | for (const o of searchOptions) merged.set(o.value, o); |
| 468 | return Array.from(merged.values()); |
| 469 | } |
| 470 | return optionConfig.options as SearchableSelectOption[]; |
| 471 | }, [optionConfig, knownOptions, searchOptions]); |
| 472 | |
| 473 | const getLabelForValue = useCallback( |
| 474 | (v: string) => { |
| 475 | const found = allOptions.find((o) => o.value === v); |
| 476 | if (found) return found.label; |
| 477 | if (optionConfig.fallback) return optionConfig.fallback(v)?.label ?? v; |
| 478 | return v; |
| 479 | }, |
| 480 | [allOptions, optionConfig] |
| 481 | ); |
| 482 | |
| 483 | const doSearch = useCallback( |
| 484 | async (q: string) => { |
| 485 | if (!optionConfig.search) return; |
| 486 | setLoading(true); |
| 487 | try { |
| 488 | const resp = await optionConfig.search({ |
| 489 | search: q, |
| 490 | pageToken: "", |
| 491 | pageSize: getDefaultPagination(), |
| 492 | }); |
| 493 | setSearchOptions(resp.options as SearchableSelectOption[]); |
nothing calls this directly
no test coverage detected