@cainiaofe/cn-ui-m
Version:
262 lines (261 loc) • 13.9 kB
JavaScript
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;