UNPKG

bonree-cascader

Version:

cascade select ui component for react

326 lines (274 loc) 12.7 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.LOAD_STATUS = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var React = _interopRequireWildcard(require("react")); var _warning = _interopRequireDefault(require("rc-util/lib/warning")); var _useMergedState3 = _interopRequireDefault(require("rc-util/lib/hooks/useMergedState")); var _generate = _interopRequireDefault(require("bonree-tree-select/lib/generate")); var _OptionList = _interopRequireDefault(require("./OptionList")); var _context = _interopRequireDefault(require("./context")); var _util = require("./util"); var _useUpdateEffect = _interopRequireDefault(require("./hooks/useUpdateEffect")); var _useSearchConfig3 = _interopRequireDefault(require("./hooks/useSearchConfig")); var _excluded = ["checkable", "changeOnSelect", "children", "options", "onChange", "value", "defaultValue", "popupVisible", "open", "dropdownClassName", "popupClassName", "onDropdownVisibleChange", "onPopupVisibleChange", "popupPlacement", "placement", "searchValue", "onSearch", "showSearch", "expandTrigger", "expandIcon", "loadingIcon", "displayRender", "loadData", "dropdownMenuColumnStyle", "dropdownPrefixCls", "dropdownMatchSelectWidth", "requestFailureIcon", "requestFailureText", "refreshText", "empty"]; var INTERNAL_VALUE_FIELD = '__rc_cascader_value__'; /** * `rc-cascader` is much like `bonree-tree-select` but API is very different. * It's caused that component developer is not same person * and we do not rice the API naming standard at that time. * * To avoid breaking change, wrap the `bonree-tree-select` to compatible with `rc-cascader` API. * This should be better to merge to same API like `bonree-tree-select` or `bonree-select` in next major version. * * Update: * - dropdown class change to `rc-cascader-dropdown` * - direction rtl keyboard * * Deprecated: * - popupVisible * - hidePopupOnSelect * * Removed: * - builtinPlacements: Handle by select */ var RefCascader = (0, _generate.default)({ prefixCls: 'rc-cascader', optionList: _OptionList.default }); function defaultDisplayRender(labels) { return labels.join(' / '); } var LOAD_STATUS; exports.LOAD_STATUS = LOAD_STATUS; (function (LOAD_STATUS) { LOAD_STATUS["LOADING"] = "RC_LOADING_RC"; LOAD_STATUS["EMPTY"] = "RC_EMPTY_RC"; LOAD_STATUS["FAILED"] = "RC_LOADED_FAILED_RC"; })(LOAD_STATUS || (exports.LOAD_STATUS = LOAD_STATUS = {})); var Cascader = /*#__PURE__*/React.forwardRef(function (props, ref) { var checkable = props.checkable, changeOnSelect = props.changeOnSelect, children = props.children, options = props.options, onChange = props.onChange, value = props.value, defaultValue = props.defaultValue, popupVisible = props.popupVisible, open = props.open, dropdownClassName = props.dropdownClassName, popupClassName = props.popupClassName, onDropdownVisibleChange = props.onDropdownVisibleChange, onPopupVisibleChange = props.onPopupVisibleChange, popupPlacement = props.popupPlacement, placement = props.placement, searchValue = props.searchValue, onSearch = props.onSearch, showSearch = props.showSearch, expandTrigger = props.expandTrigger, _props$expandIcon = props.expandIcon, expandIcon = _props$expandIcon === void 0 ? '>' : _props$expandIcon, loadingIcon = props.loadingIcon, _props$displayRender = props.displayRender, displayRender = _props$displayRender === void 0 ? defaultDisplayRender : _props$displayRender, loadData = props.loadData, dropdownMenuColumnStyle = props.dropdownMenuColumnStyle, dropdownPrefixCls = props.dropdownPrefixCls, _props$dropdownMatchS = props.dropdownMatchSelectWidth, dropdownMatchSelectWidth = _props$dropdownMatchS === void 0 ? false : _props$dropdownMatchS, _props$requestFailure = props.requestFailureIcon, requestFailureIcon = _props$requestFailure === void 0 ? null : _props$requestFailure, requestFailureText = props.requestFailureText, refreshText = props.refreshText, empty = props.empty, restProps = (0, _objectWithoutProperties2.default)(props, _excluded); var fieldNames = restProps.fieldNames; // ============================ Ref ============================= var cascaderRef = React.useRef(); React.useImperativeHandle(ref, function () { return { focus: function focus() { cascaderRef.current.focus(); }, blur: function blur() { cascaderRef.current.blur(); } }; }); var getEntityByValue = function getEntityByValue(val) { return cascaderRef.current.getEntityByValue(val); }; // =========================== Search =========================== var _useMergedState = (0, _useMergedState3.default)(undefined, { value: searchValue, onChange: onSearch }), _useMergedState2 = (0, _slicedToArray2.default)(_useMergedState, 2), mergedSearch = _useMergedState2[0], setMergedSearch = _useMergedState2[1]; var _useSearchConfig = (0, _useSearchConfig3.default)(showSearch), _useSearchConfig2 = (0, _slicedToArray2.default)(_useSearchConfig, 2), mergedShowSearch = _useSearchConfig2[0], searchConfig = _useSearchConfig2[1]; // ========================== Options =========================== var outerFieldNames = React.useMemo(function () { return (0, _util.fillFieldNames)(fieldNames); }, [fieldNames]); var mergedFieldNames = React.useMemo(function () { return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, outerFieldNames), {}, { value: INTERNAL_VALUE_FIELD }); }, [outerFieldNames]); var mergedOptions = React.useMemo(function () { return (0, _util.convertOptions)(options, outerFieldNames, INTERNAL_VALUE_FIELD); }, [options, outerFieldNames]); // =========================== Value ============================ /** * Always pass props value to last value unit: * - single: ['light', 'little'] => ['light__little'] * - multiple: [['light', 'little'], ['bamboo']] => ['light__little', 'bamboo'] */ var parseToInternalValue = function parseToInternalValue(propValue) { var propValueList = []; if (propValue) { propValueList = checkable ? propValue : [propValue]; } return propValueList.map(_util.connectValue); }; var _React$useState = React.useState(function () { return parseToInternalValue(value || defaultValue); }), _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2), internalValue = _React$useState2[0], setInternalValue = _React$useState2[1]; (0, _useUpdateEffect.default)(function () { setInternalValue(parseToInternalValue(value)); }, [value]); // =========================== Label ============================ var labelRender = function labelRender(entity, val) { var fieldLabel = mergedFieldNames.label; if (!entity) { var valPath = (0, _util.splitValue)(val); return displayRender(valPath, []); } if (checkable) { return entity.data.node[fieldLabel]; } var _restoreCompatibleVal = (0, _util.restoreCompatibleValue)(entity, mergedFieldNames), selectedOptions = _restoreCompatibleVal.options; var rawOptions = selectedOptions.map(function (opt) { return opt.node; }); var labelList = rawOptions.map(function (opt) { return opt[fieldLabel]; }); return displayRender(labelList, rawOptions); }; // =========================== Change =========================== var onInternalChange = function onInternalChange(newValue /** Not care current type */ ) { // TODO: Need improve motion experience setMergedSearch(''); var valueList = checkable ? newValue : [newValue]; var pathList = []; var optionsList = []; var valueEntities = valueList.map(getEntityByValue).filter(function (entity) { return entity; }); valueEntities.forEach(function (entity) { var _restoreCompatibleVal2 = (0, _util.restoreCompatibleValue)(entity, mergedFieldNames), valueOptions = _restoreCompatibleVal2.options; var originOptions = valueOptions.map(function (option) { return option.node; }); pathList.push(originOptions.map(function (opt) { return (// Here we should use original FieldNames value mapping opt[outerFieldNames.value] ); })); optionsList.push(originOptions); }); // Fill state if (value === undefined) { setInternalValue(valueList); } if (onChange) { if (checkable) { onChange(pathList, optionsList); } else { // TODO: This should return null as other component. // But its a breaking change and we should keep the logic. onChange(pathList[0] || [], optionsList[0] || []); } } }; // ============================ Open ============================ if (process.env.NODE_ENV !== 'production') { (0, _warning.default)(!onPopupVisibleChange, '`onPopupVisibleChange` is deprecated. Please use `onDropdownVisibleChange` instead.'); (0, _warning.default)(popupVisible === undefined, '`popupVisible` is deprecated. Please use `open` instead.'); (0, _warning.default)(popupClassName === undefined, '`popupClassName` is deprecated. Please use `dropdownClassName` instead.'); (0, _warning.default)(popupPlacement === undefined, '`popupPlacement` is deprecated. Please use `placement` instead.'); } var mergedOpen = open !== undefined ? open : popupVisible; var mergedDropdownClassName = dropdownClassName || popupClassName; var mergedPlacement = placement || popupPlacement; var onInternalDropdownVisibleChange = function onInternalDropdownVisibleChange(nextVisible) { onDropdownVisibleChange === null || onDropdownVisibleChange === void 0 ? void 0 : onDropdownVisibleChange(nextVisible); onPopupVisibleChange === null || onPopupVisibleChange === void 0 ? void 0 : onPopupVisibleChange(nextVisible); }; // ========================== Context =========================== var context = React.useMemo(function () { return { changeOnSelect: changeOnSelect, expandTrigger: expandTrigger, fieldNames: mergedFieldNames, expandIcon: expandIcon, loadingIcon: loadingIcon, loadData: loadData, dropdownMenuColumnStyle: dropdownMenuColumnStyle, search: searchConfig, dropdownPrefixCls: dropdownPrefixCls, requestFailureIcon: requestFailureIcon, requestFailureText: requestFailureText, refreshText: refreshText, empty: empty }; }, [changeOnSelect, expandTrigger, mergedFieldNames, expandIcon, loadingIcon, loadData, dropdownMenuColumnStyle, searchConfig, dropdownPrefixCls]); // =========================== Render =========================== var dropdownStyle = // Search to match width mergedSearch && searchConfig.matchInputWidth || // Empty keep the width !mergedOptions.length ? {} : { minWidth: 'auto' }; return /*#__PURE__*/React.createElement(_context.default.Provider, { value: context }, /*#__PURE__*/React.createElement(RefCascader, (0, _extends2.default)({ ref: cascaderRef }, restProps, { fieldNames: mergedFieldNames, value: checkable ? internalValue : internalValue[0], placement: mergedPlacement, dropdownMatchSelectWidth: dropdownMatchSelectWidth, dropdownStyle: dropdownStyle, dropdownClassName: mergedDropdownClassName, treeData: mergedOptions, treeCheckable: checkable, treeNodeFilterProp: "label", onChange: onInternalChange, showCheckedStrategy: RefCascader.SHOW_PARENT, open: mergedOpen, onDropdownVisibleChange: onInternalDropdownVisibleChange, searchValue: mergedSearch // Customize filter logic in OptionList , filterTreeNode: function filterTreeNode() { return true; }, showSearch: mergedShowSearch, onSearch: setMergedSearch, labelRender: labelRender, getRawInputElement: function getRawInputElement() { return children; } }))); }); Cascader.displayName = 'Cascader'; var _default = Cascader; exports.default = _default;