import React, { useMemo, useState } from "react"; import classNames from "classnames"; import { DropdownBox } from "../dropdown/Dropdown"; import { CascaderBoxProps, CascaderData, CascaderOption, } from "./CascaderProps"; import { Tabs, TabPanel } from "../tabs"; import { CascaderLoading } from "./CascaderLoading"; import { EmptyTip } from "../tips"; import { useIsomorphicLayoutEffect } from "../_util/use-isomorphic-layout-effect"; import { useConfig } from "../util"; export function getOptions( data: CascaderData, valueList: CascaderBoxProps["curValue"] ): CascaderOption[] { const options = []; let curLevel = data; valueList.forEach(value => { const option: CascaderOption = curLevel?.options?.find( option => option.value === value ) || { value, label: null }; options.push(option); if (option && option.child) { curLevel = option.child as CascaderData; } else { curLevel = {} as any; } }); return options.filter(Boolean); } export function CascaderBox({ data, curValue, onLoad, onClose, changeOnSelect, scheduleUpdate, multiple, isSelected, onSelect, onDeselect, className, style, }: CascaderBoxProps) { const { classPrefix } = useConfig(); // 面板可用值(动态加载时预先传输 value 场景,此时值无法和面板数据对应) const availableValue = useMemo(() => { const lists = [data]; const value: string[] = []; for (let i = 0; i < curValue?.length; ++i) { const option = lists[i]?.options?.find( option => option.value === curValue[i] ); if (option) { value.push(curValue[i]); } if (option && option.child) { lists.push(option.child as CascaderData); } else { break; } } return value; }, [curValue, data]); // 内部状态 const [internalValue, setInternalValue] = useState(availableValue || []); useIsomorphicLayoutEffect(() => { setInternalValue(availableValue || []); }, [curValue]); // 面板 const panels = useMemo(() => { const panels = [data]; for (let i = 0; i < internalValue.length; ++i) { const option = panels[i]?.options?.find( option => option.value === internalValue[i] ); if (option && option.child) { panels.push(option.child as CascaderData); } else { break; } } return panels; }, [data, internalValue]); const [curPanelIndex, setCurPanelIndex] = useState(panels.length - 1); useIsomorphicLayoutEffect(() => { if (scheduleUpdate) { scheduleUpdate(); } }, [curPanelIndex, scheduleUpdate]); function handleSelect(index, value, { event, hasChild }) { const newValue = [...internalValue.slice(0, index), value]; if (changeOnSelect) { onSelect(newValue, { event, options: getOptions(data, newValue) }); } else { setInternalValue(newValue); if (!hasChild) { onSelect(newValue, { event, options: getOptions(data, newValue) }); } } if (hasChild) { setCurPanelIndex(index + 1); } else if (!multiple) { onClose(); } } return (
setCurPanelIndex(+id)} tabs={panels.map(({ title }, index) => ({ id: String(index), label: title, }))} > {panels.map(({ options }, index) => { return ( {options ? (
    {options.map(({ value, label, child, disabled }) => { const optionValue = [ ...internalValue.slice(0, index), value, ]; const selected = multiple ? isSelected(optionValue) : internalValue[index] === value; return (
  • { if (disabled) { return; } if (multiple && selected) { onDeselect(optionValue, { event, options: getOptions(data, optionValue), }); return; } handleSelect(index, value, { event, hasChild: Boolean(child), }); }} > {label || value}
  • ); })} {options.length === 0 && }
) : (
    onLoad(internalValue, getOptions(data, internalValue)) } />
)}
); })}
); } CascaderBox.displayName = "CascaderBox";