UNPKG

@bee-design/bee-design-ui

Version:

Bee Design React UI Library.

362 lines (361 loc) 18.6 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.DefaultFieldNames = void 0; var react_1 = __importStar(require("react")); var is_1 = require("../_util/is"); var Trigger_1 = __importDefault(require("../Trigger")); var list_1 = __importDefault(require("./panel/list")); var search_panel_1 = __importDefault(require("./panel/search-panel")); var ConfigProvider_1 = require("../ConfigProvider"); var select_view_1 = __importDefault(require("../_class/select-view")); var classNames_1 = __importDefault(require("../_util/classNames")); var useMergeValue_1 = __importDefault(require("../_util/hooks/useMergeValue")); var useUpdate_1 = __importDefault(require("../_util/hooks/useUpdate")); var keycode_1 = require("../_util/keycode"); var useRefCurrent_1 = __importDefault(require("./hook/useRefCurrent")); var useMergeProps_1 = __importDefault(require("../_util/hooks/useMergeProps")); var util_1 = require("./util"); var useForceUpdate_1 = __importDefault(require("../_util/hooks/useForceUpdate")); var useId_1 = __importDefault(require("../_util/hooks/useId")); exports.DefaultFieldNames = { label: 'label', value: 'value', isLeaf: 'isLeaf', children: 'children', disabled: 'disabled', }; var defaultProps = { options: [], bordered: true, fieldNames: exports.DefaultFieldNames, trigger: 'click', expandTrigger: 'click', checkedStrategy: util_1.SHOW_CHILD, defaultActiveFirstOption: true, }; function Cascader(baseProps, ref) { var _a = (0, react_1.useContext)(ConfigProvider_1.ConfigContext), getPrefixCls = _a.getPrefixCls, renderEmpty = _a.renderEmpty, componentConfig = _a.componentConfig, rtl = _a.rtl; var props = (0, useMergeProps_1.default)(baseProps, defaultProps, componentConfig === null || componentConfig === void 0 ? void 0 : componentConfig.Cascader); var disabled = props.disabled, renderFormat = props.renderFormat, getPopupContainer = props.getPopupContainer, children = props.children, triggerProps = props.triggerProps, expandTrigger = props.expandTrigger; var prefixCls = getPrefixCls('cascader'); var isMultiple = props.mode === 'multiple'; var timerRef = (0, react_1.useRef)(null); var forceUpdate = (0, useForceUpdate_1.default)(); var store = (0, useRefCurrent_1.default)(function () { return (0, util_1.getStore)(props, (0, util_1.formatValue)('value' in props ? props.value : props.defaultValue, isMultiple)); }, [JSON.stringify((0, util_1.getConfig)(props)), props.options]); var _b = __read((0, react_1.useState)(function () { return 'value' in props ? (0, util_1.formatValue)(props.value, isMultiple, store) : 'defaultValue' in props ? (0, util_1.formatValue)(props.defaultValue, isMultiple, store) : []; }), 2), stateValue = _b[0], setValue = _b[1]; var mergeValue = 'value' in props ? (0, util_1.formatValue)(props.value, isMultiple, store) : stateValue; var _c = __read((0, useMergeValue_1.default)(false, { value: props.popupVisible, defaultValue: props.defaultPopupVisible, }), 2), popupVisible = _c[0], setPopupVisible = _c[1]; var _d = __read((0, useMergeValue_1.default)('', { value: 'inputValue' in props ? props.inputValue || '' : undefined, }), 3), inputValue = _d[0], setInputValue = _d[1], stateInputValue = _d[2]; // 触发 onInputValueChange 回调的值 var refOnInputChangeCallbackValue = (0, react_1.useRef)(inputValue); // 触发 onInputValueChange 回调的原因 var refOnInputChangeCallbackReason = (0, react_1.useRef)(null); var selectRef = (0, react_1.useRef)(null); // 暂存被选中的值对应的节点。仅在onSearch的时候用到 // 避免出现下拉列表改变,之前选中的option找不到对应的节点,展示上会出问题。 var stashNodes = (0, react_1.useRef)((store === null || store === void 0 ? void 0 : store.getCheckedNodes()) || []); // Unique ID of this instance var instancePopupID = (0, useId_1.default)(prefixCls + "-popup-"); // 尝试更新 inputValue,触发 onInputValueChange var tryUpdateInputValue = function (value, reason) { if (value !== refOnInputChangeCallbackValue.current) { setInputValue(value); refOnInputChangeCallbackValue.current = value; refOnInputChangeCallbackReason.current = reason; props.onInputValueChange && props.onInputValueChange(value, reason); } }; // 在 inputValue 变化时,适时触发 onSearch (0, react_1.useEffect)(function () { var reason = refOnInputChangeCallbackReason.current; if (stateInputValue === inputValue && (reason === 'manual' || reason === 'optionListHide')) { props.onSearch && props.onSearch(inputValue, reason); } if (inputValue !== refOnInputChangeCallbackValue.current) { refOnInputChangeCallbackValue.current = inputValue; } }, [inputValue]); (0, react_1.useEffect)(function () { var clearTimer = function () { clearTimeout(timerRef.current); timerRef.current = null; }; if (!popupVisible && inputValue) { if (timerRef.current) { clearTimer(); } timerRef.current = setTimeout(function () { tryUpdateInputValue('', 'optionListHide'); timerRef.current = null; }, 200); } return function () { clearTimer(); }; }, [popupVisible]); (0, useUpdate_1.default)(function () { if ('value' in props && props.value !== stateValue) { // don't to use formatValue(x, y, store) // we just need to get the value in a valid format, and update it to store nodes var newValue = (0, util_1.formatValue)(props.value, isMultiple); store.setNodeCheckedByValue(newValue); setValue(newValue); } }, [props.value, isMultiple]); (0, react_1.useImperativeHandle)(ref, function () { return selectRef.current; }, []); var updateStashNodes = function (nodes) { stashNodes.current = Array.from(new Set([].concat(nodes, stashNodes.current))); }; var getSelectedOptionsByValue = function (values) { var result = []; var valuesSet = (0, util_1.transformValuesToSet)(values); var findValue = function (nodes) { nodes.some(function (node) { if ((0, util_1.valueInSet)(valuesSet, node.pathValue)) { result.push(node.getPathNodes().map(function (x) { return x._data; })); (0, util_1.removeValueFromSet)(valuesSet, node.pathValue); } if (!valuesSet.size) { return true; } }); }; findValue(store.getCheckedNodes()); if (valuesSet.size) { findValue(stashNodes.current); } return result; }; var handleVisibleChange = (0, react_1.useCallback)(function (newVisible) { if (newVisible !== popupVisible) { props.onVisibleChange && props.onVisibleChange(newVisible); if (!('popupVisible' in props)) { setPopupVisible(newVisible); } } }, [props.onVisibleChange, popupVisible]); var renderText = (0, react_1.useCallback)(function (value) { var _a; // store 中不存在时,从stashNodes.current中找一下对应节点 var options = getSelectedOptionsByValue([value])[0] || []; var text; var valueShow = (0, is_1.isArray)(value) ? value.map(function (x) { return String(x); }) : []; if (options.length) { valueShow = options.map(function (x) { return x.label; }); } if ((0, is_1.isFunction)(renderFormat)) { text = renderFormat(valueShow); } else if (valueShow.every(function (v) { return (0, is_1.isString)(v); })) { text = valueShow.join(' / '); } else { text = valueShow.reduce(function (total, item, index) { return total.concat(index === 0 ? [item] : [' / ', item]); }, []); } return { text: text || '', disabled: (_a = options[options.length - 1]) === null || _a === void 0 ? void 0 : _a.disabled, }; }, [store, renderFormat]); var handleChange = function (newValue, trigger) { var _a; if (trigger === 'panel' && (0, is_1.isObject)(props.showSearch) && !props.showSearch.retainInputValueWhileSelect && isMultiple) { tryUpdateInputValue('', 'optionChecked'); } var onChange = props.onChange, changeOnSelect = props.changeOnSelect, expandTrigger = props.expandTrigger; var isSame = mergeValue === newValue; if (isSame) { return; } if (!isMultiple) { store.setNodeCheckedByValue(newValue); } updateStashNodes(store.getCheckedNodes()); var selectedOptions = getSelectedOptionsByValue(newValue); var _value = isMultiple ? newValue : newValue[0]; var _selectedOptions = isMultiple ? selectedOptions : selectedOptions[0]; if (!isMultiple) { if (inputValue) { // 单选时选择搜索项,直接关闭面板 handleVisibleChange(false); } else if ((selectedOptions[0] && ((_a = selectedOptions[0][selectedOptions[0].length - 1]) === null || _a === void 0 ? void 0 : _a.isLeaf)) || (changeOnSelect && expandTrigger === 'hover')) { handleVisibleChange(false); } } if ('value' in props) { store.setNodeCheckedByValue(mergeValue); // 受控触发更新,回到选中前的状态。 forceUpdate(); } else { setValue(newValue); } onChange && onChange(_value, _selectedOptions, { dropdownVisible: popupVisible, }); }; var onRemoveCheckedItem = function (item, index, e) { e.stopPropagation(); if (item.disabled) { return; } var newValue = mergeValue.filter(function (_, i) { return i !== index; }); store.setNodeCheckedByValue(newValue); handleChange(newValue); }; var renderEmptyEle = function (width) { var wd = width || (selectRef.current && selectRef.current.getWidth()); return (react_1.default.createElement("div", { className: prefixCls + "-list-empty", style: { width: wd } }, props.notFoundContent || renderEmpty('Cascader'))); }; var renderPopup = function () { var _a; // 远程搜索时是否以搜索面板展示搜索结果 var panelMode = (0, is_1.isObject)(props.showSearch) ? props.showSearch.panelMode : undefined; var showSearchPanel = panelMode === util_1.PANEL_MODE.select ? true : panelMode === util_1.PANEL_MODE.cascader ? false : !(0, is_1.isFunction)(props.onSearch) && !!inputValue; var width = selectRef.current && selectRef.current.getWidth(); var dropdownRender = (0, is_1.isFunction)(props.dropdownRender) ? props.dropdownRender : function (menu) { return menu; }; return (react_1.default.createElement("div", { id: instancePopupID, className: (0, classNames_1.default)(prefixCls + "-popup", props.dropdownMenuClassName, (_a = {}, _a[prefixCls + "-popup-trigger-hover"] = props.expandTrigger === 'hover', _a)) }, dropdownRender(react_1.default.createElement("div", { className: prefixCls + "-popup-inner", onMouseDown: function (e) { return e.preventDefault(); } }, showSearchPanel ? (react_1.default.createElement(search_panel_1.default, { style: { minWidth: width }, store: store, inputValue: inputValue, renderEmpty: function () { return renderEmptyEle(width); }, multiple: isMultiple, onChange: function (value) { handleChange(value, 'panel'); }, prefixCls: prefixCls, rtl: rtl, onEsc: function () { handleVisibleChange(false); }, renderOption: ((0, is_1.isObject)(props.showSearch) && props.showSearch.renderOption) || undefined, value: mergeValue, virtualListProps: props.virtualListProps, defaultActiveFirstOption: props.defaultActiveFirstOption })) : (react_1.default.createElement(list_1.default, { dropdownMenuColumnStyle: props.dropdownMenuColumnStyle, virtualListProps: props.virtualListProps, expandTrigger: expandTrigger, store: store, dropdownColumnRender: props.dropdownColumnRender, renderOption: props.renderOption, changeOnSelect: props.changeOnSelect, showEmptyChildren: props.showEmptyChildren || !!props.loadMore, multiple: isMultiple, onChange: function (value) { handleChange(value, 'panel'); }, loadMore: props.loadMore, prefixCls: prefixCls, rtl: rtl, renderEmpty: renderEmptyEle, popupVisible: popupVisible, value: mergeValue, renderFooter: props.renderFooter, onEsc: function () { handleVisibleChange(false); }, onDoubleClickOption: function () { if (props.changeOnSelect && !isMultiple) { handleVisibleChange(false); } } })))))); }; var updateSelectedValues = function (value) { setValue(value); }; var renderView = function (eleView) { return (react_1.default.createElement(Trigger_1.default, __assign({ popup: renderPopup, trigger: props.trigger, disabled: disabled, getPopupContainer: getPopupContainer, position: rtl ? 'br' : 'bl', classNames: "slideDynamicOrigin", popupAlign: { bottom: 4 }, // 动态加载时,unmountOnExit 默认为false。 unmountOnExit: 'unmountOnExit' in props ? props.unmountOnExit : !(0, is_1.isFunction)(props.loadMore), popupVisible: popupVisible }, triggerProps, { onVisibleChange: handleVisibleChange }), eleView)); }; return children ? (renderView(children)) : (react_1.default.createElement(select_view_1.default, __assign({}, props, { ref: selectRef, ariaControls: instancePopupID, popupVisible: popupVisible, value: isMultiple ? mergeValue : mergeValue && mergeValue[0], inputValue: inputValue, rtl: rtl, // other isEmptyValue: (0, util_1.isEmptyValue)(mergeValue), prefixCls: prefixCls, isMultiple: isMultiple, renderText: renderText, onRemoveCheckedItem: onRemoveCheckedItem, onSort: updateSelectedValues, renderView: renderView, onClear: function (e) { var _a; e.stopPropagation(); if (!isMultiple) { handleChange([]); } else { var nodes = store.getCheckedNodes(); var newValue = nodes.filter(function (x) { return x.disabled; }).map(function (x) { return x.pathValue; }); store.setNodeCheckedByValue(newValue); handleChange(newValue); } (_a = props.onClear) === null || _a === void 0 ? void 0 : _a.call(props, !!popupVisible); }, onKeyDown: function (e) { var _a; if (disabled) { return; } e.stopPropagation(); var keyCode = e.keyCode || e.which; if (keyCode === keycode_1.Enter.code && !popupVisible) { handleVisibleChange(true); e.preventDefault(); } if (keyCode === keycode_1.Tab.code && popupVisible) { handleVisibleChange(false); } (_a = props.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(props, e); }, // onFocus={this.onFocusInput} onChangeInputValue: function (v) { tryUpdateInputValue(v, 'manual'); // tab键 focus 到输入框,此时下拉框未显示。如果输入值,展示下拉框 if (!popupVisible) { handleVisibleChange(true); } } }))); } var CascaderComponent = (0, react_1.forwardRef)(Cascader); CascaderComponent.displayName = 'Cascader'; exports.default = CascaderComponent;