UNPKG

@cainiaofe/cn-ui-m

Version:
262 lines (261 loc) 13.9 kB
import { __assign, __rest } from "tslib"; import $i18n from "../../locales/i18n"; import React, { forwardRef, Fragment, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react'; import classNames from 'classnames'; import { BottomButton } from './bottom-button'; import { SelectDrawer } from "../select-drawer"; import { useValue } from "../../hooks/use-value"; import { findInArray, getDataSource, isValidArray } from "../../utils/func"; import isFunction from 'lodash/isFunction'; import isString from 'lodash/isString'; import SelectBody from './section/select-body'; import SelectSearch from './section/select-search'; import SelectedListDrawer from './section/selected-list-drawer'; import SelectContext from './context'; import { getValidEvtValues, innerRenderSelection, isEqualItems } from './util'; // 自动关闭时的等待时间 var AUTO_CLOSE_WAITING_TIME = 300; // 判断两个值是否相等 var compare = function (a, b) { return isEqualItems(a, b, true); }; var BaseSelect = function (props, ref) { var _a; var _b = props.prefix, prefix = _b === void 0 ? 'cn-ui-m-' : _b, placeholder = props.placeholder, _value = props.value, type = props.type, defaultValue = props.defaultValue, className = props.className, mode = props.mode, hasSearch = props.hasSearch, children = props.children, _dataSource = props.dataSource, displayType = props.displayType, disabled = props.disabled, autoConfirm = props.autoConfirm, hasClear = props.hasClear, filterLocal = props.filterLocal, transferSearchToOption = props.transferSearchToOption, renderSelection = props.renderSelection, useDetailValue = props.useDetailValue, _locale = props.locale, size = props.size, _c = props.notFoundContent, notFoundContent = _c === void 0 ? $i18n.get({ id: 'NoOptions', dm: '无选项' }) : _c, onVisibleChange = props.onVisibleChange, _d = props.onChange, onChange = _d === void 0 ? function () { } : _d, _e = props.onClear, onClear = _e === void 0 ? function () { } : _e, _f = props.onCancel, onCancel = _f === void 0 ? function () { } : _f, _g = props.onOk, onOk = _g === void 0 ? function () { } : _g, onSearch = props.onSearch, drawerClassName = props.drawerClassName, others = __rest(props, ["prefix", "placeholder", "value", "type", "defaultValue", "className", "mode", "hasSearch", "children", "dataSource", "displayType", "disabled", "autoConfirm", "hasClear", "filterLocal", "transferSearchToOption", "renderSelection", "useDetailValue", "locale", "size", "notFoundContent", "onVisibleChange", "onChange", "onClear", "onCancel", "onOk", "onSearch", "drawerClassName"]); var _h = useState(''), searchVal = _h[0], setSearchVal = _h[1]; var _j = useState(false), drawerVisible = _j[0], setDrawerVisible = _j[1]; var _k = useState({}), valueItemCache = _k[0], setValueItemCache = _k[1]; var clsPrefix = "".concat(prefix, "select"); var baseSelectRef = useRef(null); var realHasSearch = props.hasSearch || props.showSearch; var dataSource = useMemo(function () { return getDataSource(props.dataSource, props.children); }, [props.dataSource, props.children]); var fitValue = function (v) { if (v === '' || v === null) { return []; } var x = Array.isArray(v) ? v : [v]; if (useDetailValue) { return x; } else if (isValidArray(x)) { return x.map(function (item) { var realItem = // eslint-disable-next-line typeof item === 'object' && item.hasOwnProperty('value') ? item.value : item; var tmp = findInArray(dataSource, function (d) { return d.value === realItem; }); // 当找到了匹配的值,且非本地搜索时,缓存一下找到的值,避免重新搜索后,在受控模式下重新调用fitValue导致数据丢失的问题 if (tmp && realHasSearch && !filterLocal) { setValueItemCache(function (cur) { var _a; return (__assign(__assign({}, cur), (_a = {}, _a[realItem] = tmp, _a))); }); } return (tmp || valueItemCache[realItem] || { label: realItem, value: realItem, }); }); } else { return []; } }; var _l = useValue(props, [], { fitValue: fitValue, compare: compare, }), value = _l[0], setValue = _l[1], isControlled = _l[2]; var _m = useState(value), innerValue = _m[0], setInnerValue = _m[1]; var _o = useState(false), confirmVisible = _o[0], setConfirmVisible = _o[1]; var isSingle = mode === 'single'; var searchRef = useRef(null); useMemo(function () { if (isControlled && !compare(value, innerValue)) { setInnerValue(value); } }, [value]); // 删除(顶部删除按钮, 自定义删除, mask) var handleCancel = useCallback(function (reason) { // 情况搜索内容 if (searchRef && searchRef.current) { searchRef.current.setValue(''); } if (isFunction(onCancel)) { onCancel(reason); } setTimeout(function () { setInnerValue(value); }, 300); }, [value]); // 确认 (顶部确认,自定义确认按钮,或自动触发) var handleOk = function () { if (!isControlled) { setValue(innerValue); } // 判断前后两次选择是否有差异 var changed = !isEqualItems(value, innerValue); if (isFunction(onOk)) { onOk(); } if (changed && isFunction(onChange)) { var _a = getValidEvtValues({ selectedItems: innerValue, isSingle: isSingle, useDetailValue: useDetailValue, }), val = _a.value, items = _a.items; onChange(val, 'change', items); } if (searchRef === null || searchRef === void 0 ? void 0 : searchRef.current) { searchRef.current.setValue(''); } }; var handleTotalClick = function () { if (contextValue.innerValue.length > 0) { setConfirmVisible(true); } }; // 清空时 var handleClear = function () { if (!isControlled) { setValue([]); setInnerValue([]); if (searchRef === null || searchRef === void 0 ? void 0 : searchRef.current) { searchRef.current.setValue(''); } } if (isFunction(onClear)) { onClear(); } if (isFunction(onChange)) { var _a = getValidEvtValues({ selectedItems: [], useDetailValue: useDetailValue, isSingle: isSingle, }), val = _a.value, items = _a.items; onChange(val, 'clear', items); } }; // 二次确认完成 var handleConfirmDone = function (items) { setInnerValue(items); setConfirmVisible(false); }; var handleConfirmCancel = function () { setConfirmVisible(false); }; // 底部确定按钮点击 var handleBottomOk = function () { var _a; if ((_a = baseSelectRef === null || baseSelectRef === void 0 ? void 0 : baseSelectRef.current) === null || _a === void 0 ? void 0 : _a.ok) { baseSelectRef.current.ok(); } }; // 底部删除按钮点击 var handleBottomCancel = function () { var _a; if ((_a = baseSelectRef === null || baseSelectRef === void 0 ? void 0 : baseSelectRef.current) === null || _a === void 0 ? void 0 : _a.cancel) { baseSelectRef.current.cancel('cancel-button'); } }; // 弹窗开启或关闭 var handleVisibleChange = function (visible, reason) { setDrawerVisible(visible); if (isFunction(onVisibleChange)) { onVisibleChange(visible, reason); } }; var contextValue = useMemo(function () { return __assign(__assign({}, props), { hasSearch: realHasSearch, dataSource: dataSource, type: type, mode: mode, size: size, prefix: prefix, value: value, innerValue: innerValue, displayType: displayType, // notice: 默认直接更新 inner value, 外部更新,此组件处理 onChange: function (v) { // 根据当前innerValue构建缓存,避免在实时搜索模式下丢失选项数据的问题 if (realHasSearch && !filterLocal) { setValueItemCache(function (cur) { var res = {}; if (Array.isArray(v)) { v.forEach(function (item) { res[item.value] = item; }); return res; } return cur; }); } setInnerValue(v); }, searchValue: searchVal, setSearchValue: setSearchVal }); }, [ props, realHasSearch, filterLocal, dataSource, type, mode, size, prefix, value, innerValue, displayType, searchVal, ]); // 单选+自动确认模式, 选项切换,自动触发确认 useEffect(function () { if (drawerVisible && isSingle && autoConfirm === true) { setTimeout(function () { var _a; // 手动触发 select 的 ok 操作 if ((_a = baseSelectRef === null || baseSelectRef === void 0 ? void 0 : baseSelectRef.current) === null || _a === void 0 ? void 0 : _a.ok) { baseSelectRef.current.ok(); } }, AUTO_CLOSE_WAITING_TIME); } }, [innerValue]); useImperativeHandle(ref, function () { return Object.assign(baseSelectRef.current); }); return (React.createElement(Fragment, null, React.createElement(SelectDrawer, __assign({}, others, { hideButton: isSingle && autoConfirm === true, size: size, ref: baseSelectRef, showToolbar: !realHasSearch, type: type, disabled: disabled, placeholder: placeholder, hasClear: hasClear, className: classNames(clsPrefix, className), content: renderSelection ? renderSelection(value) : innerRenderSelection(value, contextValue), buttonPosition: "bottom", onClear: handleClear, onCancel: handleCancel, onOk: handleOk, onVisibleChange: handleVisibleChange, // @ts-ignore drawerClassName: classNames(drawerClassName, (_a = {}, _a["".concat(clsPrefix, "--searchable")] = realHasSearch, _a)) }), React.createElement(SelectContext.Provider, { value: contextValue }, React.createElement(React.Fragment, null, realHasSearch && React.createElement(SelectSearch, { ref: searchRef }), dataSource.length === 0 && !realHasSearch ? ( // 因 Provider 导致 select-drawer 空选项判断失败 React.createElement("div", { className: "".concat(clsPrefix, "-drawer-content ").concat(clsPrefix, "drawer-drawer--empty") }, isString(notFoundContent) ? (React.createElement("span", { className: "".concat(clsPrefix, "drawer-drawer-empty-text") }, notFoundContent)) : (React.createElement("div", { className: "".concat(clsPrefix, "drawer-drawer-empty-text") }, notFoundContent)))) : (React.createElement("div", { className: "".concat(clsPrefix, "-option-list") }, React.createElement(SelectBody, { emptySearchText: notFoundContent || $i18n.get({ id: 'NoOptionsFoundForSearchVal', dm: '找不到关于 “${searchVal}” 的选项', }), searchToOptionBtnText: $i18n.get({ id: 'AddAsOption', dm: '添加为选项', }) }))), realHasSearch && !isSingle && (React.createElement("div", { className: "".concat(clsPrefix, "-drawer-footer") }, React.createElement(BottomButton, { okText: $i18n.get({ id: 'OK', dm: '确定' }), cancelText: $i18n.get({ id: 'Cancel', dm: '取消' }), onOk: handleBottomOk, onCancel: handleBottomCancel }, !isSingle && (React.createElement("div", { className: "".concat(clsPrefix, "-footer-counter"), onClick: handleTotalClick }, React.createElement("span", null, $i18n.get({ id: 'CurrentlySelected', dm: '当前已选中', })), React.createElement("span", { className: "".concat(clsPrefix, "-total-num") }, innerValue.length), React.createElement("span", null, $i18n.get({ id: 'Item', dm: '项' })))))))))), !isSingle && contextValue.innerValue.length > 0 ? (React.createElement(SelectedListDrawer, { prefix: contextValue.prefix, innerValue: contextValue.innerValue, locale: contextValue.locale, visible: confirmVisible, onOk: handleConfirmDone, onCancel: handleConfirmCancel, renderItem: contextValue.renderItem })) : null)); }; var RefBaseSelect = forwardRef(BaseSelect); RefBaseSelect.displayName = 'BaseSelect'; RefBaseSelect.defaultProps = { mode: 'single', size: 'medium', type: 'normal', displayType: 'normal', disabled: false, hideButton: false, transferSearchToOption: false, hasClear: false, autoConfirm: true, stickyOnTop: false, }; export default RefBaseSelect;