bonree-cascader
Version:
cascade select ui component for react
404 lines (316 loc) • 13.3 kB
JavaScript
"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;