preact-arco-design
Version:
Arco Design React UI Library.
627 lines (532 loc) • 17.5 kB
JavaScript
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 __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) {
function adopt(value) {
return value instanceof P ? value : new P(function (resolve) {
resolve(value);
});
}
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
}
function rejected(value) {
try {
step(generator["throw"](value));
} catch (e) {
reject(e);
}
}
function step(result) {
result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
}
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = this && this.__generator || function (thisArg, body) {
var _ = {
label: 0,
sent: function sent() {
if (t[0] & 1) throw t[1];
return t[1];
},
trys: [],
ops: []
},
f,
y,
t,
g;
return g = {
next: verb(0),
"throw": verb(1),
"return": verb(2)
}, typeof Symbol === "function" && (g[Symbol.iterator] = function () {
return this;
}), g;
function verb(n) {
return function (v) {
return step([n, v]);
};
}
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) {
try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0:
case 1:
t = op;
break;
case 4:
_.label++;
return {
value: op[1],
done: false
};
case 5:
_.label++;
y = op[1];
op = [0];
continue;
case 7:
op = _.ops.pop();
_.trys.pop();
continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
_ = 0;
continue;
}
if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
_.label = op[1];
break;
}
if (op[0] === 6 && _.label < t[1]) {
_.label = t[1];
t = op;
break;
}
if (t && _.label < t[2]) {
_.label = t[2];
_.ops.push(op);
break;
}
if (t[2]) _.ops.pop();
_.trys.pop();
continue;
}
op = body.call(thisArg, _);
} catch (e) {
op = [6, e];
y = 0;
} finally {
f = t = 0;
}
}
if (op[0] & 5) throw op[1];
return {
value: op[0] ? op[1] : void 0,
done: true
};
}
};
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;
};
import React, { useState, useEffect, useCallback } from "preact/compat";
import scrollIntoView from 'scroll-into-view-if-needed';
import isEqualWith from 'lodash/isEqualWith';
import { CSSTransition, TransitionGroup } from "preact-transition-group-4";
import cs from "../../_util/classNames";
import Option from "./option";
import { isFunction, isObject } from "../../_util/is";
import useRefs from "../../_util/hooks/useRefs";
import useForceUpdate from "../../_util/hooks/useForceUpdate";
import { ArrowDown, Esc, Enter, ArrowUp, ArrowRight, ArrowLeft } from "../../_util/keycode";
import useUpdate from "../../_util/hooks/useUpdate";
import { getMultipleCheckValue } from "../util";
import VirtualList from "../../_class/VirtualList";
var getLegalActiveNode = function getLegalActiveNode(options) {
for (var index = 0; index < options.length; index++) {
if (!options[index].disabled) {
return options[index];
}
}
};
var getBaseActiveNode = function getBaseActiveNode(currentNode) {
if (currentNode && currentNode.disabled) {
var node = currentNode;
while (node.parent) {
if (node.parent.disabled) {
node = node.parent;
} else {
break;
}
}
return node;
}
return currentNode;
};
export var getLegalIndex = function getLegalIndex(currentIndex, maxIndex) {
if (currentIndex < 0) {
return maxIndex;
}
if (currentIndex > maxIndex) {
return 0;
}
return currentIndex;
};
var ListPanel = function ListPanel(props) {
var _a;
var _b = __read(useRefs(), 2),
activeOptionList = _b[0],
setActiveOptionList = _b[1];
var _c = __read(useRefs(), 2),
refWrapper = _c[0],
setRefWrapper = _c[1];
var forceUpdate = useForceUpdate();
var store = props.store,
prefixCls = props.prefixCls,
value = props.value,
multiple = props.multiple,
renderFooter = props.renderFooter,
renderOption = props.renderOption,
showEmptyChildren = props.showEmptyChildren,
loadMore = props.loadMore,
renderEmpty = props.renderEmpty,
rtl = props.rtl;
var _d = __read(useState(store.findNodeByValue(value && value[value.length - 1]) || null), 2),
activeNode = _d[0],
setActiveNode = _d[1];
var options = store.getOptions();
var triggerChange = function triggerChange(newValue) {
props.onChange && props.onChange(newValue);
};
var loadData = function loadData(option) {
return __awaiter(void 0, void 0, void 0, function () {
var options_1, e_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!(!option.isLeaf && isFunction(loadMore) && !option.children)) return [3
/*break*/
, 5];
option.setLoading(true);
forceUpdate();
_a.label = 1;
case 1:
_a.trys.push([1, 3,, 4]);
return [4
/*yield*/
, loadMore(option.pathValue, option.pathValue.length)];
case 2:
options_1 = _a.sent();
store.appendOptionChildren(option, options_1);
store.setNodeCheckedByValue(props.value);
return [3
/*break*/
, 4];
case 3:
e_1 = _a.sent();
console.error(e_1);
return [3
/*break*/
, 4];
case 4:
option.setLoading(false);
forceUpdate();
_a.label = 5;
case 5:
return [2
/*return*/
];
}
});
});
};
var _onClickOption = function onClickOption(option, isEnterClick) {
if (isEnterClick === void 0) {
isEnterClick = true;
}
return __awaiter(void 0, void 0, void 0, function () {
return __generator(this, function (_a) {
if (!option || option.disabled) {
return [2
/*return*/
];
}
setActiveNode(option);
loadData(option); // 在键盘上下左右键操作时,isEnterClick 是false,不触发triggerChange
if (!multiple && isEnterClick) {
if (props.changeOnSelect || option.isLeaf) {
triggerChange([option.pathValue]);
}
}
return [2
/*return*/
];
});
});
};
var _onMultipleChecked = function onMultipleChecked(option, checked) {
var newValue = getMultipleCheckValue(props.value, store, option, checked);
if (option === activeNode) {
// setActiveNode 不会执行rerender,需要forceupdate
forceUpdate();
}
setActiveNode(option);
if (!props.changeOnSelect) {
// 父子节点关联,选中复选框时执行loadMore,否则直接选中父节点
loadData(option);
}
triggerChange(newValue);
};
var handleKeyDown = useCallback(function (e) {
e.stopPropagation(); // 使用keycode,避免中文输入法输入时,触发enter,space等事件。
// p.s 中文输入时,keycode 都是229
var keyCode = e.keyCode || e.which;
var nextActiveNode;
switch (keyCode) {
case Esc.code:
{
e.preventDefault();
props.onEsc();
break;
}
case ArrowDown.code:
case ArrowUp.code:
{
if (!activeNode) {
nextActiveNode = getLegalActiveNode(options);
} else {
var baseActiveNode = getBaseActiveNode(activeNode);
var list = baseActiveNode.parent && baseActiveNode.parent.children || options;
var diff = keyCode === ArrowDown.code ? 1 : -1;
var nextIndex = getLegalIndex(baseActiveNode._index + diff, list.length - 1);
while (nextIndex !== baseActiveNode._index) {
nextActiveNode = list[nextIndex];
if (nextActiveNode.disabled) {
nextIndex = getLegalIndex(nextIndex + diff, list.length - 1);
} else {
break;
}
}
}
_onClickOption(nextActiveNode, false);
e.preventDefault();
return false;
}
case ArrowRight.code:
{
if (activeNode && !activeNode.disabled) {
var list = activeNode.children || [];
nextActiveNode = list[0] || activeNode;
_onClickOption(nextActiveNode, false);
}
e.preventDefault();
return false;
}
case ArrowLeft.code:
{
if (activeNode) {
var baseActiveNode = getBaseActiveNode(activeNode);
nextActiveNode = baseActiveNode.parent || baseActiveNode;
}
_onClickOption(nextActiveNode, false);
e.preventDefault();
return false;
}
case Enter.code:
if (activeNode) {
if (multiple) {
_onMultipleChecked(activeNode, !activeNode._checked);
} else {
_onClickOption(activeNode);
}
}
e.preventDefault();
return false;
default:
break;
}
}, [activeNode]);
useUpdate(function () {
setActiveNode(function (activeNode) {
// store 改变时候,更新下activeNode.如果当前activeNode不存在于store里了,就设置为null
var newActiveNode;
if (activeNode && activeNode.pathValue && activeNode.pathValue.length) {
var values = activeNode.pathValue;
var parent_1 = {
children: options
};
values.map(function (value) {
var list = parent_1.children || [];
var item = list.find(function (x) {
return x.value === value;
});
if (item) {
parent_1 = item;
newActiveNode = item;
}
});
}
return newActiveNode;
});
}, [store]);
useEffect(function () {
if (props.popupVisible && options.length) {
var scrollTo_1 = function scrollTo_1() {
activeOptionList.forEach(function (activeOption, i) {
activeOption && scrollIntoView(activeOption, {
block: 'nearest',
boundary: refWrapper[i]
});
});
};
setTimeout(function () {
scrollTo_1();
});
}
}, [props.popupVisible, activeNode]);
useEffect(function () {
if (props.popupVisible) {
document.addEventListener('keydown', handleKeyDown);
} else {
document.removeEventListener('keydown', handleKeyDown);
}
return function () {
document.removeEventListener('keydown', handleKeyDown);
};
}, [props.popupVisible, handleKeyDown]);
var menus = function () {
var list = [options];
var pathNodes = activeNode ? activeNode.getPathNodes() : [];
pathNodes.forEach(function (option) {
option && option.children && list.push(option.children);
});
return list;
}();
var dropdownColumnRender = isFunction(props.dropdownColumnRender) ? props.dropdownColumnRender : function (menu) {
return menu;
};
return !menus.length || !((_a = menus[0]) === null || _a === void 0 ? void 0 : _a.length) ? React.createElement(React.Fragment, null, renderEmpty()) : React.createElement(TransitionGroup, {
component: React.Fragment
}, menus.map(function (list, level) {
var _a, _b, _c;
var footer = renderFooter ? renderFooter(level, activeNode || null) : null;
return list.length === 0 && !showEmptyChildren ? null : React.createElement(CSSTransition, {
key: level,
timeout: {
enter: 300,
exit: 0
},
classNames: "cascaderSlide",
onEnter: function onEnter(e) {
e.style.marginLeft = "-".concat(e.scrollWidth, "px");
},
onEntering: function onEntering(e) {
e.style.marginLeft = "0px";
},
onEntered: function onEntered(e) {
e.style.marginLeft = '';
}
}, React.createElement("div", {
className: cs("".concat(prefixCls, "-list-column"), (_a = {}, _a["".concat(prefixCls, "-list-column-virtual")] = props.virtualListProps && props.virtualListProps.threshold !== null, _a["".concat(prefixCls, "-list-column-rtl")] = rtl, _a)),
style: __assign({
zIndex: menus.length - level
}, props.dropdownMenuColumnStyle)
}, dropdownColumnRender(React.createElement("div", {
className: cs("".concat(prefixCls, "-list-wrapper"), (_b = {}, _b["".concat(prefixCls, "-list-wrapper-with-footer")] = footer !== null, _b))
}, list.length === 0 ? renderEmpty && renderEmpty(props.virtualListProps ? '100%' : 120) : React.createElement(VirtualList, __assign({
needFiller: false,
threshold: props.virtualListProps ? 100 : null,
data: list,
isStaticItemHeight: true,
itemKey: "value"
}, isObject(props.virtualListProps) ? props.virtualListProps : {}, {
wrapper: "ul",
role: "menu",
ref: function ref(node) {
return setRefWrapper(node === null || node === void 0 ? void 0 : node.dom, level);
},
className: cs("".concat(prefixCls, "-list"), "".concat(prefixCls, "-list-select"), (_c = {}, _c["".concat(prefixCls, "-list-multiple")] = multiple, _c["".concat(prefixCls, "-list-rtl")] = rtl, _c))
}), function (option) {
var _a;
var isActive = false;
if (activeNode) {
isActive = activeNode.pathValue[level] === option.value;
}
return React.createElement("li", {
tabIndex: 0,
role: "menuitem",
"aria-haspopup": !option.isLeaf,
"aria-expanded": isActive && !option.isLeaf,
"aria-disabled": option.disabled,
key: option.value,
title: option.label,
className: cs("".concat(prefixCls, "-list-item"), (_a = {}, _a["".concat(prefixCls, "-list-item-active")] = isActive, _a["".concat(prefixCls, "-list-item-disabled")] = option.disabled, _a)),
ref: function ref(_ref) {
if (isActive) {
setActiveOptionList(_ref, level);
}
}
}, React.createElement(Option, {
prefixCls: prefixCls,
rtl: rtl,
multiple: multiple,
option: option,
// 叶子节点被选中
selected: !multiple && option.isLeaf && isEqualWith(props.value, option.pathValue),
onMouseEnter: function onMouseEnter() {
if (option.disabled) {
return;
}
if (props.expandTrigger === 'hover') {
setActiveNode(option);
!option.isLeaf && loadData(option);
}
},
renderOption: renderOption && function () {
return renderOption(option._data, level);
},
onClickOption: function onClickOption() {
if (option.isLeaf && multiple && !option.disableCheckbox) {
_onMultipleChecked(option, !option._checked);
} else {
_onClickOption(option);
}
},
onMultipleChecked: function onMultipleChecked(checked) {
_onMultipleChecked(option, checked);
},
onDoubleClickOption: props.onDoubleClickOption
}));
}), footer && React.createElement("div", {
className: "".concat(prefixCls, "-list-footer"),
onMouseDown: function onMouseDown(e) {
// 这里是为了阻止冒泡到面板节点的onMousedown事件。因为弹出层会阻止默认行为,避免选择框失去焦点
// 如果这里不阻止冒泡,footer里如果渲染了input标签,将无法被focus
e.stopPropagation();
}
}, footer)), level)));
}));
};
export default ListPanel;