import React, { Fragment, useEffect, useMemo, useState } from "react"; import classNames from "classnames"; import { Checkbox } from "../checkbox"; import { DropdownBox } from "../dropdown"; import { List } from "../list"; import { EmptyTip } from "../tips"; import { useConfig } from "../util"; import { getPlainText } from "../_util/getPlainText"; import { searchFilter } from "../_util/search-filter"; import { highlight } from "../_util/text-highlight"; import { CascaderData, CascaderOption, CascaderSearchProps, } from "./CascaderProps"; import { noop } from "../_util/noop"; function getOptionPaths(data: CascaderData, all: boolean): CascaderOption[][] { const optionPaths: CascaderOption[][] = []; const traverse = (data: CascaderData, optionPath: CascaderOption[] = []) => { (data.options || []).forEach(option => { const options = [...optionPath, option]; if (option.child) { if (all) { optionPaths.push(options); } traverse(option.child as CascaderData, options); } else { optionPaths.push(options); } }); }; traverse(data); return optionPaths; } function filterPaths( paths: CascaderOption[][], inputValue: string, filter: CascaderSearchProps["filter"] ): CascaderOption[][] { return paths.filter(path => path.find(option => filter(inputValue, option))); } const defaultFilter = ( inputValue: string, { label, value }: CascaderOption ) => { return searchFilter(getPlainText(label) || value, inputValue); }; export function CascaderSearch({ data, searchValue, onChange, changeOnSelect, multiple, className, style, isSelected, filter = defaultFilter, scheduleUpdate, tips, bottomTips, onScrollBottom, onSearch = noop, }: CascaderSearchProps) { const [currentIndex, setCurrentIndex] = useState(-1); useEffect(() => { setCurrentIndex(-1); }, []); const allOptionPaths = useMemo(() => getOptionPaths(data, changeOnSelect), [ data, changeOnSelect, ]); useEffect(() => { onSearch(searchValue); // eslint-disable-next-line react-hooks/exhaustive-deps }, [searchValue]); const optionPaths = useMemo( () => filterPaths(allOptionPaths, searchValue, filter), [filter, searchValue, allOptionPaths] ); useEffect(() => { if (scheduleUpdate) { scheduleUpdate(); } }, [optionPaths, scheduleUpdate]); const { classPrefix } = useConfig(); const [listTips, listBottomTips] = useMemo(() => { return [ tips ? tips(null, searchValue) : null, bottomTips ? bottomTips(null, searchValue) : null, ]; }, [bottomTips, searchValue, tips]); return (
onScrollBottom(null, searchValue)} > {!listTips && !listBottomTips && optionPaths.length === 0 && ( )} {listTips && {listTips}} {optionPaths.map((options, index) => { const valuePath = options.map(({ value }) => value); const selected = isSelected && isSelected(valuePath); const item = options.map(({ label, value }, i) => { const content = highlight(label, searchValue); if (i === 0) { return {content}; } return ( {" / "} {content} ); }); return ( !multiple && onChange(valuePath, { event, options, selected: !selected }) } > {multiple ? ( onChange(valuePath, { event, options, selected: !selected, }) } > {item} ) : ( item )} ); })} {listBottomTips && {listBottomTips}}
); } CascaderSearch.displayName = "CascaderSearch";