import React, { forwardRef, ForwardRefRenderFunction, Fragment, useCallback, useContext, useMemo, useRef, useState, useImperativeHandle, } from 'react'; import classNames from 'classnames'; import View from '@alifd/meet-react/es/view'; import { ItemContext } from '@alifd/meet-react/es/form'; import BottomButton from '@alifd/meet-react/es/bottom-button'; import SelectDrawer, { LocaleType as SelectDrawerLocalType } from '@alifd/meet-react/es/select-drawer'; import { useLocale } from '@alifd/meet-react/es/locale'; import defaultLang from '@alifd/meet-react/es/locale/lang/zh-cn'; import { useValue } from '@alifd/meet-react/es/utils/hooks'; import { findInArray, getDataSource, isFunction, isString, isValidArray } from '@alifd/meet-react/es/utils'; // import SelectBody from '@alifd/meet-react/es/select/section/select-body'; import SelectSearch from '@alifd/meet-react/es/select/section/select-search'; import SelectedListDrawer from '@alifd/meet-react/es/select/section/selected-list-drawer'; import { defaultLocalFilter, getValidEvtValues, innerRenderSelection, isEqualItems, } from '@alifd/meet-react/es/select/util'; import SelectContext from '@alifd/meet-react/es/select/context'; import { LocaleType } from '@alifd/meet-react/es/select/types'; import { ExtraSelectProps } from './type'; const BaseSelect: ForwardRefRenderFunction = (props, ref) => { const { prefix = 'mt-', placeholder, value: _value, type = 'normal', defaultValue, className, mode = 'single', hasSearch, children, dataSource: _dataSource, disabled = false, hasClear, onSearch, displayType = 'normal', filterLocal = true, filter = defaultLocalFilter, renderSelection, useDetailValue, onChange = () => {}, onClear = () => {}, onCancel = () => {}, onOk = () => {}, locale: _locale, size: sizeProp, notFoundContent = '', popupContent, // 自定义弹窗内容 ...others } = props; const { isInsideForm, size: contextSize } = useContext(ItemContext); const size = sizeProp || (isInsideForm ? contextSize : 'medium'); const [searchVal, setSearchVal] = useState(''); const selectLocale = useLocale('Select', props, defaultLang.Select); const selectDrawerLocal = useLocale('SelectDrawer', {}, defaultLang.SelectDrawer); const clsPrefix = `${prefix}select`; const baseSelectRef = useRef(null); const dataSource = useMemo(() => { return getDataSource(props.dataSource, props.children); }, [props.dataSource, props.children]); const fitValue = (v: any) => { if (v === '' || v === null) { return []; } const x = Array.isArray(v) ? v : [v]; if (useDetailValue) { return x; } else if (isValidArray(x)) { return x.map((item) => { const tmp = findInArray(dataSource, (d: any) => d.value === item); return ( tmp || { label: item, value: item, } ); }); } else { return []; } }; const compare = (a: any, b: any) => isEqualItems(a, b, true); const [value, setValue, isControlled] = useValue(props, [], { fitValue, compare, }); const [innerValue, setInnerValue] = useState(value); const [confirmVisible, setConfirmVisible] = useState(false); const isSingle = mode === 'single'; const searchRef = useRef(null); const realHasSearch = props.hasSearch || props.showSearch; useMemo(() => { if (isControlled && !compare(value, innerValue)) { setInnerValue(value); } }, [value]); const handleCancel = useCallback( (reason) => { setInnerValue(value); if (searchRef && searchRef.current) { searchRef.current.setValue(''); } if (baseSelectRef && baseSelectRef.current) { baseSelectRef.current.hide(); } if (isFunction(onCancel)) { onCancel(reason); } }, [value], ); const handleOk = () => { if (!isControlled) { setValue(innerValue); } // 判断前后两次选择是否有差异 const changed = !isEqualItems(value, innerValue); if (isFunction(onOk)) { onOk(); } if (changed && isFunction(onChange)) { const { value: val, items } = getValidEvtValues({ selectedItems: innerValue, isSingle, useDetailValue, }); onChange(val, 'change', items); } if (searchRef && searchRef.current) { searchRef.current.setValue(''); } if (baseSelectRef && baseSelectRef.current) { baseSelectRef.current.hide(); } }; const handleTotalClick = () => { setConfirmVisible(true); }; const handleClear = () => { if (!isControlled) { setValue([]); setInnerValue([]); if (searchRef && searchRef.current) { searchRef.current.setValue(''); } } if (isFunction(onClear)) { onClear(); } if (isFunction(onChange)) { const { value: val, items } = getValidEvtValues({ selectedItems: [], useDetailValue, isSingle, }); onChange(val, 'clear', items); } }; const handleConfirmDone = (items: any[]) => { setInnerValue(items); setConfirmVisible(false); }; const handleConfirmCancel = () => { setConfirmVisible(false); }; const contextValue = useMemo(() => { return { ...props, hasSearch: realHasSearch, dataSource, type, mode, size, prefix, value, innerValue, displayType, locale: selectLocale, onChange: (v: any) => setInnerValue(v), searchValue: searchVal, setSearchValue: setSearchVal, }; }, [ props, realHasSearch, dataSource, type, mode, size, prefix, value, innerValue, displayType, selectLocale, searchVal, ]); useImperativeHandle(ref, () => Object.assign(baseSelectRef.current)); return ( {realHasSearch && } {/* {dataSource.length === 0 && !realHasSearch ? ( // 因 Provider 导致 select-drawer 空选项判断失败 {isString(notFoundContent) ? (
{notFoundContent}
) : ( {notFoundContent} )}
) : ( )} */} {popupContent} {realHasSearch && ( handleCancel('cancel-button')} > {!isSingle && ( {selectLocale.totalPrefixText} {innerValue.length} {selectLocale.totalSuffixText} )} )}
{!isSingle && ( )}
); }; BaseSelect.displayName = 'SelectDrawer'; export default forwardRef(BaseSelect);