UNPKG

bonree-cascader

Version:

cascade select ui component for react

404 lines (316 loc) 13.3 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); 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 React = _interopRequireWildcard(require("react")); var _classnames = _interopRequireDefault(require("classnames")); var _KeyCode = _interopRequireDefault(require("rc-util/lib/KeyCode")); var _Context = require("bonree-tree-select/lib/Context"); var _Column = _interopRequireDefault(require("./Column")); var _util = require("../util"); var _context = _interopRequireDefault(require("../context")); var _useSearchResult = _interopRequireDefault(require("../hooks/useSearchResult")); /* eslint-disable default-case */ var RefOptionList = /*#__PURE__*/React.forwardRef(function (props, ref) { var _optionColumns$, _optionColumns$$optio, _classNames; var prefixCls = props.prefixCls, options = props.options, onSelect = props.onSelect, multiple = props.multiple, open = props.open, flattenOptions = props.flattenOptions, searchValue = props.searchValue, onToggleOpen = props.onToggleOpen, notFoundContent = props.notFoundContent, direction = props.direction; var containerRef = React.useRef(); var rtl = direction === 'rtl'; var _React$useContext = React.useContext(_Context.SelectContext), checkedKeys = _React$useContext.checkedKeys, halfCheckedKeys = _React$useContext.halfCheckedKeys; var _React$useContext2 = React.useContext(_context.default), changeOnSelect = _React$useContext2.changeOnSelect, expandTrigger = _React$useContext2.expandTrigger, fieldNames = _React$useContext2.fieldNames, loadData = _React$useContext2.loadData, search = _React$useContext2.search, dropdownPrefixCls = _React$useContext2.dropdownPrefixCls; var mergedPrefixCls = dropdownPrefixCls || prefixCls; // ========================= loadData ========================= // const [loadingKeys, setLoadingKeys] = React.useState([]); var internalLoadData = function internalLoadData(pathValue) { // Do not load when search if (!loadData || searchValue) { return; } var entity = flattenOptions.find(function (flattenOption) { return flattenOption.data.value === pathValue; }); if (entity && !(0, _util.isLeaf)(entity.data.node)) { var _restoreCompatibleVal = (0, _util.restoreCompatibleValue)(entity, fieldNames), optionList = _restoreCompatibleVal.options; var rawOptionList = optionList.map(function (opt) { return opt.node; }); // setLoadingKeys(keys => [...keys, entity.key]); loadData(rawOptionList); } }; // zombieJ: This is bad. We should make this same as `rc-tree` to use Promise instead. // React.useEffect(() => { // if (loadingKeys.length) { // loadingKeys.forEach(loadingKey => { // const option = flattenOptions.find(opt => opt.value === loadingKey); // if (option.data.children || option.data.isLeaf === true) { // setLoadingKeys(keys => keys.filter(key => key !== loadingKey)); // } // }); // } // }, [flattenOptions, loadingKeys]); // ========================== Values ========================== var checkedSet = React.useMemo(function () { return new Set(checkedKeys); }, [checkedKeys]); var halfCheckedSet = React.useMemo(function () { return new Set(halfCheckedKeys); }, [halfCheckedKeys]); // =========================== Open =========================== var _React$useState = React.useState(null), _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2), openFinalValue = _React$useState2[0], setOpenFinalValue = _React$useState2[1]; var mergedOpenPath = React.useMemo(function () { if (searchValue) { return openFinalValue !== undefined && openFinalValue !== null ? [openFinalValue] : []; } var entity = flattenOptions.find(function (flattenOption) { return flattenOption.data.value === openFinalValue; }); if (entity) { var _restoreCompatibleVal2 = (0, _util.restoreCompatibleValue)(entity, fieldNames), path = _restoreCompatibleVal2.path; return path; } return []; }, [openFinalValue, flattenOptions, searchValue]); React.useEffect(function () { if (open) { var nextOpenPath = null; if (!multiple && checkedKeys.length) { var entity = flattenOptions.find(function (flattenOption) { return flattenOption.data.value === checkedKeys[0]; }); if (entity) { nextOpenPath = entity.data.value; } } setOpenFinalValue(nextOpenPath); } }, [open]); // =========================== Path =========================== var onPathOpen = function onPathOpen(index, pathValue) { setOpenFinalValue(pathValue); // Trigger loadData internalLoadData(pathValue); }; var onPathSelect = function onPathSelect(pathValue, leaf) { onSelect(pathValue, { selected: !checkedSet.has(pathValue) }); if (!multiple && (leaf || changeOnSelect && expandTrigger === 'hover')) { onToggleOpen(false); } }; var getPathList = function getPathList(pathList) { var currentOptions = options; var _loop = function _loop(i) { currentOptions = (currentOptions || []).find(function (option) { return option.value === pathList[i]; }).children; }; for (var i = 0; i < pathList.length; i += 1) { _loop(i); } return currentOptions; }; // ========================== Search ========================== var searchOptions = (0, _useSearchResult.default)((0, _objectSpread2.default)((0, _objectSpread2.default)({}, props), {}, { prefixCls: mergedPrefixCls, fieldNames: fieldNames, changeOnSelect: changeOnSelect, searchConfig: search })); // ========================== Column ========================== var optionColumns = React.useMemo(function () { if (searchValue) { return [{ options: searchOptions }]; } var rawOptionColumns = []; for (var i = 0; i <= mergedOpenPath.length; i += 1) { var subOptions = getPathList(mergedOpenPath.slice(0, i)); if (subOptions) { rawOptionColumns.push({ options: subOptions }); } else { break; } } return rawOptionColumns; }, [searchValue, searchOptions, mergedOpenPath]); // ========================= Keyboard ========================= var getActiveOption = function getActiveOption(activeColumnIndex, offset) { var _optionColumns$active; var pathActiveValue = mergedOpenPath[activeColumnIndex]; var currentOptions = ((_optionColumns$active = optionColumns[activeColumnIndex]) === null || _optionColumns$active === void 0 ? void 0 : _optionColumns$active.options) || []; var activeOptionIndex = currentOptions.findIndex(function (opt) { return opt.value === pathActiveValue; }); var len = currentOptions.length; // Last one is special since -1 may back 2 offset if (offset === -1 && activeOptionIndex === -1) { activeOptionIndex = len; } for (var i = 1; i <= len; i += 1) { var current = (activeOptionIndex + i * offset + len) % len; var option = currentOptions[current]; if (!option.disabled) { return option; } } return null; }; var prevColumn = function prevColumn() { if (mergedOpenPath.length <= 1) { onToggleOpen(false); } setOpenFinalValue(mergedOpenPath[mergedOpenPath.length - 2]); }; var nextColumn = function nextColumn() { var nextColumnIndex = mergedOpenPath.length; var nextActiveOption = getActiveOption(nextColumnIndex, 1); if (nextActiveOption) { onPathOpen(nextColumnIndex, nextActiveOption.value); } }; React.useImperativeHandle(ref, function () { return { // scrollTo: treeRef.current?.scrollTo, onKeyDown: function onKeyDown(event) { var which = event.which; switch (which) { // >>> Arrow keys case _KeyCode.default.UP: case _KeyCode.default.DOWN: { var offset = 0; if (which === _KeyCode.default.UP) { offset = -1; } else if (which === _KeyCode.default.DOWN) { offset = 1; } if (offset !== 0) { var activeColumnIndex = Math.max(mergedOpenPath.length - 1, 0); var nextActiveOption = getActiveOption(activeColumnIndex, offset); if (nextActiveOption) { var _containerRef$current, _ele$scrollIntoView; var ele = (_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.querySelector("li[data-value=\"".concat(nextActiveOption.value, "\"]")); ele === null || ele === void 0 ? void 0 : (_ele$scrollIntoView = ele.scrollIntoView) === null || _ele$scrollIntoView === void 0 ? void 0 : _ele$scrollIntoView.call(ele, { block: 'nearest' }); onPathOpen(activeColumnIndex, nextActiveOption.value); } } break; } case _KeyCode.default.LEFT: { if (rtl) { nextColumn(); } else { prevColumn(); } break; } case _KeyCode.default.RIGHT: { if (rtl) { prevColumn(); } else { nextColumn(); } break; } case _KeyCode.default.BACKSPACE: { if (!searchValue) { prevColumn(); } break; } // >>> Select case _KeyCode.default.ENTER: { var _optionColumns, _optionColumns$option; var lastValue = mergedOpenPath[mergedOpenPath.length - 1]; var option = (_optionColumns = optionColumns[mergedOpenPath.length - 1]) === null || _optionColumns === void 0 ? void 0 : (_optionColumns$option = _optionColumns.options) === null || _optionColumns$option === void 0 ? void 0 : _optionColumns$option.find(function (opt) { return opt.value === lastValue; }); // Skip when no select if (option) { var leaf = (0, _util.isLeaf)(option); if (multiple || changeOnSelect || leaf) { onPathSelect(lastValue, leaf); } // Close for changeOnSelect if (changeOnSelect) { onToggleOpen(false); } } break; } // >>> Close case _KeyCode.default.ESC: { onToggleOpen(false); if (open) { event.stopPropagation(); } } } }, onKeyUp: function onKeyUp() {} }; }); // ========================== Render ========================== var columnProps = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, props), {}, { onOpen: onPathOpen, onSelect: onPathSelect, onToggleOpen: onToggleOpen, checkedSet: checkedSet, halfCheckedSet: halfCheckedSet, openFinalValue: openFinalValue // loadingKeys, }); // >>>>> Empty var isEmpty = !((_optionColumns$ = optionColumns[0]) === null || _optionColumns$ === void 0 ? void 0 : (_optionColumns$$optio = _optionColumns$.options) === null || _optionColumns$$optio === void 0 ? void 0 : _optionColumns$$optio.length); var emptyList = [{ title: notFoundContent, value: '__EMPTY__', disabled: true, node: null }]; // >>>>> Columns var mergedOptionColumns = isEmpty ? [{ options: emptyList }] : optionColumns; var columnNodes = mergedOptionColumns.map(function (col, index) { return /*#__PURE__*/React.createElement(_Column.default, (0, _extends2.default)({ key: index, index: index }, columnProps, { prefixCls: mergedPrefixCls, options: col.options, openKey: mergedOpenPath[index] })); }); // >>>>> Render return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { className: (0, _classnames.default)("".concat(mergedPrefixCls, "-menus"), (_classNames = {}, (0, _defineProperty2.default)(_classNames, "".concat(mergedPrefixCls, "-menu-empty"), isEmpty), (0, _defineProperty2.default)(_classNames, "".concat(mergedPrefixCls, "-rtl"), rtl), _classNames)), ref: containerRef }, columnNodes)); }); var _default = RefOptionList; exports.default = _default;