UNPKG

@rc-component/tree

Version:
257 lines (251 loc) 9.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.MotionEntity = exports.MOTION_KEY = void 0; exports.getMinimumRangeTransitionRange = getMinimumRangeTransitionRange; var _util = require("@rc-component/util"); var _virtualList = _interopRequireDefault(require("@rc-component/virtual-list")); var React = _interopRequireWildcard(require("react")); var _MotionTreeNode = _interopRequireDefault(require("./MotionTreeNode")); var _diffUtil = require("./utils/diffUtil"); var _treeUtil = require("./utils/treeUtil"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /** * Handle virtual list of the TreeNodes. */ const MOTION_KEY = exports.MOTION_KEY = `RC_TREE_MOTION_${Math.random()}`; const MotionNode = { key: MOTION_KEY }; const MotionEntity = exports.MotionEntity = { key: MOTION_KEY, level: 0, index: 0, pos: '0', node: MotionNode, nodes: [MotionNode] }; const MotionFlattenData = { parent: null, children: [], pos: MotionEntity.pos, data: MotionNode, title: null, key: MOTION_KEY, /** Hold empty list here since we do not use it */ isStart: [], isEnd: [] }; /** * We only need get visible content items to play the animation. */ function getMinimumRangeTransitionRange(list, virtual, height, itemHeight) { if (virtual === false || !height) { return list; } return list.slice(0, Math.ceil(height / itemHeight) + 1); } function itemKey(item) { const { key, pos } = item; return (0, _treeUtil.getKey)(key, pos); } const NodeList = /*#__PURE__*/React.forwardRef((props, ref) => { const { prefixCls, data, selectable, checkable, expandedKeys, selectedKeys, checkedKeys, loadedKeys, loadingKeys, halfCheckedKeys, keyEntities, disabled, dragging, dragOverNodeKey, dropPosition, motion, height, itemHeight, virtual, scrollWidth, focusable, activeItem, tabIndex, onKeyDown, onFocus, onBlur, onMouseDown, onActiveChange, onListChangeStart, onListChangeEnd, ...domProps } = props; const treeId = (0, _util.useId)(); // =============================== Ref ================================ const listRef = React.useRef(null); const indentMeasurerRef = React.useRef(null); React.useImperativeHandle(ref, () => ({ scrollTo: scroll => { listRef.current.scrollTo(scroll); }, getIndentWidth: () => indentMeasurerRef.current.offsetWidth })); // ============================== Motion ============================== const [prevExpandedKeys, setPrevExpandedKeys] = React.useState(expandedKeys); const [prevData, setPrevData] = React.useState(data); const [transitionData, setTransitionData] = React.useState(data); const [transitionRange, setTransitionRange] = React.useState([]); const [motionType, setMotionType] = React.useState(null); // When motion end but data change, this will makes data back to previous one const dataRef = React.useRef(data); dataRef.current = data; function onMotionEnd() { const latestData = dataRef.current; setPrevData(latestData); setTransitionData(latestData); setTransitionRange([]); setMotionType(null); onListChangeEnd(); } // Do animation if expanded keys changed // layoutEffect here to avoid blink of node removing (0, _util.useLayoutEffect)(() => { setPrevExpandedKeys(expandedKeys); const diffExpanded = (0, _diffUtil.findExpandedKeys)(prevExpandedKeys, expandedKeys); if (diffExpanded.key !== null) { if (diffExpanded.add) { const keyIndex = prevData.findIndex(({ key }) => key === diffExpanded.key); const rangeNodes = getMinimumRangeTransitionRange((0, _diffUtil.getExpandRange)(prevData, data, diffExpanded.key), virtual, height, itemHeight); const newTransitionData = prevData.slice(); newTransitionData.splice(keyIndex + 1, 0, MotionFlattenData); setTransitionData(newTransitionData); setTransitionRange(rangeNodes); setMotionType('show'); } else { const keyIndex = data.findIndex(({ key }) => key === diffExpanded.key); const rangeNodes = getMinimumRangeTransitionRange((0, _diffUtil.getExpandRange)(data, prevData, diffExpanded.key), virtual, height, itemHeight); const newTransitionData = data.slice(); newTransitionData.splice(keyIndex + 1, 0, MotionFlattenData); setTransitionData(newTransitionData); setTransitionRange(rangeNodes); setMotionType('hide'); } } else if (prevData !== data) { // If whole data changed, we just refresh the list setPrevData(data); setTransitionData(data); } }, [expandedKeys, data]); // We should clean up motion if is changed by dragging React.useEffect(() => { if (!dragging) { onMotionEnd(); } }, [dragging]); const mergedData = motion ? transitionData : data; const treeNodeRequiredProps = { expandedKeys, selectedKeys, loadedKeys, loadingKeys, checkedKeys, halfCheckedKeys, dragOverNodeKey, dropPosition, keyEntities }; return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", { className: `${prefixCls}-treenode`, "aria-hidden": true, style: { position: 'absolute', pointerEvents: 'none', visibility: 'hidden', height: 0, overflow: 'hidden', border: 0, padding: 0 } }, /*#__PURE__*/React.createElement("div", { className: `${prefixCls}-indent` }, /*#__PURE__*/React.createElement("div", { ref: indentMeasurerRef, className: `${prefixCls}-indent-unit` }))), /*#__PURE__*/React.createElement(_virtualList.default, _extends({}, domProps, { data: mergedData, itemKey: itemKey, height: height, fullHeight: false, virtual: virtual, itemHeight: itemHeight, scrollWidth: scrollWidth, prefixCls: `${prefixCls}-list`, ref: listRef, role: "tree", tabIndex: focusable !== false && !disabled ? tabIndex : undefined, "aria-activedescendant": activeItem ? (0, _util.getId)(treeId, activeItem.key) : undefined, onKeyDown: onKeyDown, onFocus: onFocus, onBlur: onBlur, onMouseDown: onMouseDown, onVisibleChange: originList => { // The best match is using `fullList` - `originList` = `restList` // and check the `restList` to see if has the MOTION_KEY node // but this will cause performance issue for long list compare // we just check `originList` and repeat trigger `onMotionEnd` if (originList.every(item => itemKey(item) !== MOTION_KEY)) { onMotionEnd(); } } }), treeNode => { const { pos, data: { ...restProps }, title, key, isStart, isEnd } = treeNode; const mergedKey = (0, _treeUtil.getKey)(key, pos); delete restProps.key; delete restProps.children; const treeNodeProps = (0, _treeUtil.getTreeNodeProps)(mergedKey, treeNodeRequiredProps); return /*#__PURE__*/React.createElement(_MotionTreeNode.default, _extends({}, restProps, treeNodeProps, { title: title, active: !!activeItem && key === activeItem.key, pos: pos, data: treeNode.data, isStart: isStart, isEnd: isEnd, motion: motion, motionNodes: key === MOTION_KEY ? transitionRange : null, motionType: motionType, onMotionStart: onListChangeStart, onMotionEnd: onMotionEnd, treeNodeRequiredProps: treeNodeRequiredProps, treeId: treeId, onMouseMove: () => { onActiveChange(null); } })); })); }); if (process.env.NODE_ENV !== 'production') { NodeList.displayName = 'NodeList'; } var _default = exports.default = NodeList;