UNPKG

zent

Version:

一套前端设计语言和基于React的实现

421 lines (420 loc) 19.5 kB
import { __assign, __extends } from "tslib"; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import cx from 'classnames'; import { Component, createRef } from 'react'; import Popover from '../popover'; import { I18nReceiver as Receiver } from '../i18n'; import MenuContent from './components/MenuContent'; import { union, difference, getPathValue, getPathLabel, getPathToNode, } from './path-fns'; import { getNodeKey } from './node-fns'; import { CascaderChangeAction, CascaderLoadAction, } from './types'; import SearchContent from './components/SearchContent'; import debounce from '../utils/debounce'; import TextMark from '../text-mark'; import { DisabledContext } from '../disabled'; import shallowEqual from '../utils/shallowEqual'; import { TagsTrigger } from './trigger/TagsTrigger'; import { SingleTrigger } from './trigger/SingleTrigger'; import { Forest } from './forest'; import noop from '../utils/noop'; import memorizeOne from '../utils/memorize-one'; import { simplify } from './simplify'; function isMultiple(props) { return props.multiple; } function isSingle(props) { return !props.multiple; } var FILTER_DEBOUNCE_TIME = 200; var defaultFilter = function (keyword, path) { return path.some(function (node) { return node.label.toLowerCase().includes(keyword.toLowerCase()); }); }; var defaultHighlight = function (keyword, path) { return path.map(function (node, index) { return (_jsxs("span", __assign({ "data-zv": '10.0.17' }, { children: [_jsx(TextMark, { searchWords: [keyword], textToHighlight: node.label, highlightClassName: "zent-cascader-v2--highlight", autoEscape: true }, void 0), index !== path.length - 1 && ' / '] }), getPathValue(path.slice(0, index + 1)))); }); }; function getActiveValue(props) { var activeValue = []; if (isMultiple(props) && props.value.length > 0) { activeValue = props.value[0]; } if (isSingle(props)) { activeValue = props.value; } return activeValue; } function getSelectedPaths(props, options) { var selectedPaths = isMultiple(props) ? props.value.map(function (x) { return options.getPathByValue(x); }) : [options.getPathByValue(props.value)]; return selectedPaths.filter(function (p) { return p.length !== 0; }); } function toggleLoading(loading, val, isLoading) { var contains = loading.indexOf(val) !== -1; if (isLoading && !contains) { return loading.concat(val); } if (!isLoading && contains) { return loading.filter(function (v) { return v !== val; }); } return loading; } function isControlled(props) { return ('visible' in props && 'onVisibleChange' in props && typeof props.onVisibleChange === 'function'); } function getVisible(props, state) { if (isControlled(props)) { return !!props.visible; } return state.visible; } var MenuCascader = (function (_super) { __extends(MenuCascader, _super); function MenuCascader(props) { var _this = _super.call(this, props) || this; _this.tagsTriggerRef = createRef(); _this.getSelectionMap = memorizeOne(function (selectedPaths) { return _this.getSelectionMapImpl(selectedPaths); }); _this.getSimplifySelectionMap = memorizeOne(function (selectedPaths, mode) { if (mode === void 0) { mode = 'excludeDisabled'; } return _this.getSelectionMapImpl(selectedPaths, mode); }); _this.simplify = function (options, mode) { if (mode === void 0) { mode = 'excludeDisabled'; } return simplify(options, _this.getSelectionMapImpl(options, mode)); }; _this.getSearchResultList = memorizeOne(function (options, resultList) { return resultList.map(function (path) { var values = path.map(function (x) { return x.value; }); return options.getPathByValue(values); }); }); _this.onVisibleChange = function (visible) { var keyword = _this.state.keyword; if (_this.disabled) { return; } _this.setVisible(visible); _this.setState({ keyword: visible === false ? '' : keyword, }); }; _this.onKeywordChange = function (keyword) { _this.setState({ keyword: keyword }, _this.filterOptions); }; _this.filterOptions = debounce(function () { var _a = _this.state, keyword = _a.keyword, options = _a.options; if (!keyword) { return; } var _b = _this.props, async = _b.async, asyncFilter = _b.asyncFilter, filter = _b.filter, limit = _b.limit; if (async) { _this.setState({ isSearching: true }); asyncFilter(keyword, limit) .then(function (searchList) { _this.setSearchState(searchList); }) .finally(function () { _this.setState({ isSearching: false }); }); } else { var searchList = options .reducePath(function (acc, path) { acc.push(path); return acc; }, []) .filter(function (path) { return filter(keyword, path); }); _this.setSearchState(searchList); } }, FILTER_DEBOUNCE_TIME); _this.setSearchState = function (searchList) { var limit = _this.props.limit; var size = searchList.length; _this.setState({ searchResultList: limit <= size ? searchList : searchList.slice(0, limit), }); }; _this.onMenuOptionHover = function (node) { _this.onMenuOptionSelect(node, noop, 'hover'); }; _this.onMenuOptionClick = function (node, closePopup) { _this.onMenuOptionSelect(node, closePopup, 'click'); }; _this.onMenuOptionSelect = function (node, closePopup, source) { var _a = _this.props, loadOptions = _a.loadOptions, multiple = _a.multiple; var loading = _this.state.loading; var needLoading = node.loadChildrenOnExpand && loadOptions; var selectedOptions = getPathToNode(node); var newValue = selectedOptions.map(function (n) { return n.value; }); var newState = { activeValue: newValue, keyword: '', }; var hasChildren = node.children && node.children.length > 0; var needClose = !node.loadChildrenOnExpand && !hasChildren && !multiple && source === 'click'; var nodeKey = getNodeKey(node); if (needLoading) { newState.loading = toggleLoading(loading, nodeKey, true); } _this.setState(newState, function () { if (needLoading) { loadOptions(selectedOptions, { action: CascaderLoadAction.LoadChildren, }).finally(function () { _this.setState(function (state) { return { loading: toggleLoading(state.loading, nodeKey, false), }; }); }); } if (isSingle(_this.props)) { var _a = _this.props.changeOnSelect, changeOnSelect = _a === void 0 ? false : _a; var needTriggerChange = needClose || (changeOnSelect && source === 'click'); if (needTriggerChange) { _this.props.onChange(selectedOptions.map(function (it) { return it.value; }), selectedOptions, { action: CascaderChangeAction.Change }); } } if (needClose) { closePopup(); } }); }; _this.toggleMenuOption = function (node, checked) { if (isMultiple(_this.props)) { var onChange_1 = _this.props.onChange; var _a = _this.state, options = _a.options, oldSelectedPaths = _a.selectedPaths; var affectedPaths = options.getPaths(node, function (path) { return path.every(function (node) { return !node.disabled; }); }); var selectedPaths_1 = checked ? union(oldSelectedPaths, affectedPaths) : difference(oldSelectedPaths, affectedPaths); selectedPaths_1 = options.sort(selectedPaths_1); var value_1 = selectedPaths_1.map(function (list) { return list.map(function (n) { return n.value; }); }); _this.setState({ selectedPaths: selectedPaths_1 }, function () { var _a; onChange_1(value_1, selectedPaths_1, { action: CascaderChangeAction.Change, simplify: _this.simplify, }); if (_this.props.searchable) { (_a = _this.tagsTriggerRef.current) === null || _a === void 0 ? void 0 : _a.focus(); } }); } }; _this.onSearchOptionClick = function (path, closePopup) { var activeValue = path.map(function (n) { return n.value; }); _this.setState({ activeValue: activeValue }, function () { _this.onMenuOptionClick(path[path.length - 1], closePopup); }); }; _this.toggleSearchOption = function (path, checked) { _this.toggleMenuOption(path[path.length - 1], checked); }; _this.onClear = function () { _this.setVisible(false); _this.setState({ activeValue: [], selectedPaths: [], }, function () { if (isSingle(_this.props)) { _this.props.onChange([], [], { action: CascaderChangeAction.Clear }); } else { _this.props.onChange([], [], { action: CascaderChangeAction.Clear, simplify: _this.simplify, }); } }); }; _this.scrollLoad = function (parent) { var loadOptions = _this.props.loadOptions; var currentHasMore = parent ? parent.loadChildrenOnScroll : _this.props.loadChildrenOnScroll; if (currentHasMore === false) { return Promise.resolve(); } var selectedOptions = getPathToNode(parent); return loadOptions(selectedOptions, { action: CascaderLoadAction.Scroll, }); }; _this.onRemove = function (node) { if (_this.disabled) { return; } _this.toggleMenuOption(node, false); }; _this.renderPopoverContent = function (i18n) { var _a = _this.props, expandTrigger = _a.expandTrigger, scrollable = _a.scrollable, multiple = _a.multiple, searchable = _a.searchable, highlight = _a.highlight, loadChildrenOnScroll = _a.loadChildrenOnScroll, renderItemContent = _a.renderItemContent, getItemTooltip = _a.getItemTooltip, renderList = _a.renderList, multipleType = _a.multipleType; var _b = _this.state, options = _b.options, activeValue = _b.activeValue, keyword = _b.keyword, isSearching = _b.isSearching, searchResultList = _b.searchResultList, loading = _b.loading, selectedPaths = _b.selectedPaths; var visible = _this.getVisible(); var selectionMap = _this.getSelectionMap(selectedPaths); if (searchable && visible && keyword) { return (_jsx(SearchContent, { i18n: i18n, multiple: multiple, isSearching: isSearching, searchList: _this.getSearchResultList(options, searchResultList), keyword: keyword, highlight: highlight, onOptionToggle: _this.toggleSearchOption, onOptionClick: _this.onSearchOptionClick, selectionMap: selectionMap }, void 0)); } return (_jsx(MenuContent, { value: activeValue, options: options.getTrees(), expandTrigger: expandTrigger, i18n: i18n, scrollable: scrollable, loadChildrenOnScroll: loadChildrenOnScroll, multiple: multiple, multipleType: multipleType, onOptionClick: _this.onMenuOptionClick, onOptionHover: _this.onMenuOptionHover, scrollLoad: _this.scrollLoad, onOptionToggle: _this.toggleMenuOption, loading: loading, selectionMap: selectionMap, renderItemContent: renderItemContent, getItemTooltip: getItemTooltip, renderList: renderList }, void 0)); }; var options = new Forest(props.options); _this.state = { options: options, activeValue: getActiveValue(props), visible: false, prevProps: props, selectedPaths: getSelectedPaths(props, options), keyword: '', isSearching: false, searchResultList: [], loading: [], }; return _this; } MenuCascader.getDerivedStateFromProps = function (props, state) { var prevProps = state.prevProps, options = state.options; var newState = { prevProps: props, }; var newOptions = options; var optionsChanged = false; if (prevProps.options !== props.options) { newOptions = new Forest(props.options); newState.options = newOptions; optionsChanged = true; } if (optionsChanged || prevProps.multiple !== props.multiple || !shallowEqual(prevProps.value, props.value)) { newState.selectedPaths = getSelectedPaths(props, newOptions); } var visible = getVisible(props, state); if (!visible) { newState.activeValue = getActiveValue(props); } return newState; }; Object.defineProperty(MenuCascader.prototype, "disabled", { get: function () { var _a = this.props.disabled, disabled = _a === void 0 ? this.context.value : _a; return disabled; }, enumerable: false, configurable: true }); MenuCascader.prototype.isControlled = function () { return isControlled(this.props); }; MenuCascader.prototype.getVisible = function () { return getVisible(this.props, this.state); }; MenuCascader.prototype.setVisible = function (visible) { if (this.isControlled()) { this.props.onVisibleChange(visible); } else { this.setState({ visible: visible, }); } }; MenuCascader.prototype.getSelectionMapImpl = function (selectedPaths, mode) { if (mode === void 0) { mode = 'excludeDisabled'; } return this.state.options.reduceNodeDfs(function (map, node) { var key = getNodeKey(node); var value = node.value; if (node.children.length === 0) { var selected = selectedPaths.some(function (path) { return path[path.length - 1].value === value; }); map.set(key, selected ? 'on' : 'off'); } else { var children = mode === 'excludeDisabled' ? node.children.filter(function (n) { return !n.disabled; }) : node.children; var childrenState = children.reduce(function (acc, n) { var k = getNodeKey(n); var v = map.get(k); if (v === 'on') { acc.on += 1; } else if (v === 'off') { acc.off += 1; } return acc; }, { on: 0, off: 0 }); var childrenCount = children.length; if (childrenState.on === childrenCount && childrenCount > 0) { map.set(key, 'on'); } else if (childrenState.off === childrenCount) { map.set(key, 'off'); } else { map.set(key, 'partial'); } } return map; }, new Map()); }; MenuCascader.prototype.render = function () { var _this = this; var _a = this.props, className = _a.className, popupClassName = _a.popupClassName, placeholder = _a.placeholder, searchable = _a.searchable, clearable = _a.clearable, renderValue = _a.renderValue, maxLine = _a.maxLine, lineHeight = _a.lineHeight; var _b = this.state, selectedPaths = _b.selectedPaths, keyword = _b.keyword; var visible = this.getVisible(); var hasValue = selectedPaths.length > 0; return (_jsx(Receiver, __assign({ componentName: "Cascader" }, { children: function (i18n) { var _a; var triggerCommonProps = { placeholder: placeholder, disabled: _this.disabled, className: className, clearable: clearable, visible: visible, keyword: keyword, searchable: searchable, i18n: i18n, renderValue: renderValue, maxLine: maxLine, lineHeight: lineHeight, onClear: _this.onClear, onKeywordChange: _this.onKeywordChange, }; return (_jsxs(Popover, __assign({ className: cx('zent-cascader-v2__popup', popupClassName), position: Popover.Position.CascaderAutoBottomLeft, visible: visible, onVisibleChange: _this.onVisibleChange, cushion: 4 }, { children: [_jsx(Popover.Trigger.Click, __assign({ toggle: !searchable }, { children: isMultiple(_this.props) ? (_jsx(TagsTrigger, __assign({}, triggerCommonProps, { simplifyPaths: (_a = _this.props.simplifySelection) !== null && _a !== void 0 ? _a : false, selectedPaths: selectedPaths, selectionMap: _this.getSimplifySelectionMap(selectedPaths, _this.props.simplifySelectionMode), onRemove: _this.onRemove, renderTags: _this.props.renderTags, ref: _this.tagsTriggerRef }), void 0)) : (_jsx(SingleTrigger, __assign({}, triggerCommonProps, { selectedPath: hasValue ? selectedPaths[0] : [] }), void 0)) }), void 0), _jsx(Popover.Content, { children: _this.renderPopoverContent(i18n) }, void 0)] }), void 0)); } }), void 0)); }; MenuCascader.defaultProps = { value: [], options: [], clearable: false, multiple: false, multipleType: 'checkbox', maxLine: null, lineHeight: 22, expandTrigger: 'click', scrollable: false, loadChildrenOnScroll: false, searchable: false, async: false, limit: 50, renderValue: getPathLabel, filter: defaultFilter, highlight: defaultHighlight, simplifySelectionMode: 'excludeDisabled', }; MenuCascader.contextType = DisabledContext; return MenuCascader; }(Component)); export { MenuCascader }; export default MenuCascader;