UNPKG

10.3 kBJavaScriptView Raw
1import _objectDestructuringEmpty from "@babel/runtime/helpers/esm/objectDestructuringEmpty";
2import _extends from "@babel/runtime/helpers/esm/extends";
3import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
4import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
5var _excluded = ["prefixCls", "data", "selectable", "checkable", "expandedKeys", "selectedKeys", "checkedKeys", "loadedKeys", "loadingKeys", "halfCheckedKeys", "keyEntities", "disabled", "dragging", "dragOverNodeKey", "dropPosition", "motion", "height", "itemHeight", "virtual", "focusable", "activeItem", "focused", "tabIndex", "onKeyDown", "onFocus", "onBlur", "onActiveChange", "onListChangeStart", "onListChangeEnd"];
6/**
7 * Handle virtual list of the TreeNodes.
8 */
9import useLayoutEffect from "rc-util/es/hooks/useLayoutEffect";
10import VirtualList from 'rc-virtual-list';
11import * as React from 'react';
12import MotionTreeNode from './MotionTreeNode';
13import { findExpandedKeys, getExpandRange } from './utils/diffUtil';
14import { getKey, getTreeNodeProps } from './utils/treeUtil';
15var HIDDEN_STYLE = {
16 width: 0,
17 height: 0,
18 display: 'flex',
19 overflow: 'hidden',
20 opacity: 0,
21 border: 0,
22 padding: 0,
23 margin: 0
24};
25var noop = function noop() {};
26export var MOTION_KEY = "RC_TREE_MOTION_".concat(Math.random());
27var MotionNode = {
28 key: MOTION_KEY
29};
30export var MotionEntity = {
31 key: MOTION_KEY,
32 level: 0,
33 index: 0,
34 pos: '0',
35 node: MotionNode,
36 nodes: [MotionNode]
37};
38var MotionFlattenData = {
39 parent: null,
40 children: [],
41 pos: MotionEntity.pos,
42 data: MotionNode,
43 title: null,
44 key: MOTION_KEY,
45 /** Hold empty list here since we do not use it */
46 isStart: [],
47 isEnd: []
48};
49/**
50 * We only need get visible content items to play the animation.
51 */
52export function getMinimumRangeTransitionRange(list, virtual, height, itemHeight) {
53 if (virtual === false || !height) {
54 return list;
55 }
56 return list.slice(0, Math.ceil(height / itemHeight) + 1);
57}
58function itemKey(item) {
59 var key = item.key,
60 pos = item.pos;
61 return getKey(key, pos);
62}
63function getAccessibilityPath(item) {
64 var path = String(item.data.key);
65 var current = item;
66 while (current.parent) {
67 current = current.parent;
68 path = "".concat(current.data.key, " > ").concat(path);
69 }
70 return path;
71}
72var NodeList = /*#__PURE__*/React.forwardRef(function (props, ref) {
73 var prefixCls = props.prefixCls,
74 data = props.data,
75 selectable = props.selectable,
76 checkable = props.checkable,
77 expandedKeys = props.expandedKeys,
78 selectedKeys = props.selectedKeys,
79 checkedKeys = props.checkedKeys,
80 loadedKeys = props.loadedKeys,
81 loadingKeys = props.loadingKeys,
82 halfCheckedKeys = props.halfCheckedKeys,
83 keyEntities = props.keyEntities,
84 disabled = props.disabled,
85 dragging = props.dragging,
86 dragOverNodeKey = props.dragOverNodeKey,
87 dropPosition = props.dropPosition,
88 motion = props.motion,
89 height = props.height,
90 itemHeight = props.itemHeight,
91 virtual = props.virtual,
92 focusable = props.focusable,
93 activeItem = props.activeItem,
94 focused = props.focused,
95 tabIndex = props.tabIndex,
96 onKeyDown = props.onKeyDown,
97 onFocus = props.onFocus,
98 onBlur = props.onBlur,
99 onActiveChange = props.onActiveChange,
100 onListChangeStart = props.onListChangeStart,
101 onListChangeEnd = props.onListChangeEnd,
102 domProps = _objectWithoutProperties(props, _excluded);
103 // =============================== Ref ================================
104 var listRef = React.useRef(null);
105 var indentMeasurerRef = React.useRef(null);
106 React.useImperativeHandle(ref, function () {
107 return {
108 scrollTo: function scrollTo(scroll) {
109 listRef.current.scrollTo(scroll);
110 },
111 getIndentWidth: function getIndentWidth() {
112 return indentMeasurerRef.current.offsetWidth;
113 }
114 };
115 });
116 // ============================== Motion ==============================
117 var _React$useState = React.useState(expandedKeys),
118 _React$useState2 = _slicedToArray(_React$useState, 2),
119 prevExpandedKeys = _React$useState2[0],
120 setPrevExpandedKeys = _React$useState2[1];
121 var _React$useState3 = React.useState(data),
122 _React$useState4 = _slicedToArray(_React$useState3, 2),
123 prevData = _React$useState4[0],
124 setPrevData = _React$useState4[1];
125 var _React$useState5 = React.useState(data),
126 _React$useState6 = _slicedToArray(_React$useState5, 2),
127 transitionData = _React$useState6[0],
128 setTransitionData = _React$useState6[1];
129 var _React$useState7 = React.useState([]),
130 _React$useState8 = _slicedToArray(_React$useState7, 2),
131 transitionRange = _React$useState8[0],
132 setTransitionRange = _React$useState8[1];
133 var _React$useState9 = React.useState(null),
134 _React$useState10 = _slicedToArray(_React$useState9, 2),
135 motionType = _React$useState10[0],
136 setMotionType = _React$useState10[1];
137 // When motion end but data change, this will makes data back to previous one
138 var dataRef = React.useRef(data);
139 dataRef.current = data;
140 function onMotionEnd() {
141 var latestData = dataRef.current;
142 setPrevData(latestData);
143 setTransitionData(latestData);
144 setTransitionRange([]);
145 setMotionType(null);
146 onListChangeEnd();
147 }
148 // Do animation if expanded keys changed
149 // layoutEffect here to avoid blink of node removing
150 useLayoutEffect(function () {
151 setPrevExpandedKeys(expandedKeys);
152 var diffExpanded = findExpandedKeys(prevExpandedKeys, expandedKeys);
153 if (diffExpanded.key !== null) {
154 if (diffExpanded.add) {
155 var keyIndex = prevData.findIndex(function (_ref) {
156 var key = _ref.key;
157 return key === diffExpanded.key;
158 });
159 var rangeNodes = getMinimumRangeTransitionRange(getExpandRange(prevData, data, diffExpanded.key), virtual, height, itemHeight);
160 var newTransitionData = prevData.slice();
161 newTransitionData.splice(keyIndex + 1, 0, MotionFlattenData);
162 setTransitionData(newTransitionData);
163 setTransitionRange(rangeNodes);
164 setMotionType('show');
165 } else {
166 var _keyIndex = data.findIndex(function (_ref2) {
167 var key = _ref2.key;
168 return key === diffExpanded.key;
169 });
170 var _rangeNodes = getMinimumRangeTransitionRange(getExpandRange(data, prevData, diffExpanded.key), virtual, height, itemHeight);
171 var _newTransitionData = data.slice();
172 _newTransitionData.splice(_keyIndex + 1, 0, MotionFlattenData);
173 setTransitionData(_newTransitionData);
174 setTransitionRange(_rangeNodes);
175 setMotionType('hide');
176 }
177 } else if (prevData !== data) {
178 // If whole data changed, we just refresh the list
179 setPrevData(data);
180 setTransitionData(data);
181 }
182 }, [expandedKeys, data]);
183 // We should clean up motion if is changed by dragging
184 React.useEffect(function () {
185 if (!dragging) {
186 onMotionEnd();
187 }
188 }, [dragging]);
189 var mergedData = motion ? transitionData : data;
190 var treeNodeRequiredProps = {
191 expandedKeys: expandedKeys,
192 selectedKeys: selectedKeys,
193 loadedKeys: loadedKeys,
194 loadingKeys: loadingKeys,
195 checkedKeys: checkedKeys,
196 halfCheckedKeys: halfCheckedKeys,
197 dragOverNodeKey: dragOverNodeKey,
198 dropPosition: dropPosition,
199 keyEntities: keyEntities
200 };
201 return /*#__PURE__*/React.createElement(React.Fragment, null, focused && activeItem && /*#__PURE__*/React.createElement("span", {
202 style: HIDDEN_STYLE,
203 "aria-live": "assertive"
204 }, getAccessibilityPath(activeItem)), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("input", {
205 style: HIDDEN_STYLE,
206 disabled: focusable === false || disabled,
207 tabIndex: focusable !== false ? tabIndex : null,
208 onKeyDown: onKeyDown,
209 onFocus: onFocus,
210 onBlur: onBlur,
211 value: "",
212 onChange: noop,
213 "aria-label": "for screen reader"
214 })), /*#__PURE__*/React.createElement("div", {
215 className: "".concat(prefixCls, "-treenode"),
216 "aria-hidden": true,
217 style: {
218 position: 'absolute',
219 pointerEvents: 'none',
220 visibility: 'hidden',
221 height: 0,
222 overflow: 'hidden',
223 border: 0,
224 padding: 0
225 }
226 }, /*#__PURE__*/React.createElement("div", {
227 className: "".concat(prefixCls, "-indent")
228 }, /*#__PURE__*/React.createElement("div", {
229 ref: indentMeasurerRef,
230 className: "".concat(prefixCls, "-indent-unit")
231 }))), /*#__PURE__*/React.createElement(VirtualList, _extends({}, domProps, {
232 data: mergedData,
233 itemKey: itemKey,
234 height: height,
235 fullHeight: false,
236 virtual: virtual,
237 itemHeight: itemHeight,
238 prefixCls: "".concat(prefixCls, "-list"),
239 ref: listRef,
240 onVisibleChange: function onVisibleChange(originList, fullList) {
241 var originSet = new Set(originList);
242 var restList = fullList.filter(function (item) {
243 return !originSet.has(item);
244 });
245 // Motion node is not render. Skip motion
246 if (restList.some(function (item) {
247 return itemKey(item) === MOTION_KEY;
248 })) {
249 onMotionEnd();
250 }
251 }
252 }), function (treeNode) {
253 var pos = treeNode.pos,
254 restProps = _extends({}, (_objectDestructuringEmpty(treeNode.data), treeNode.data)),
255 title = treeNode.title,
256 key = treeNode.key,
257 isStart = treeNode.isStart,
258 isEnd = treeNode.isEnd;
259 var mergedKey = getKey(key, pos);
260 delete restProps.key;
261 delete restProps.children;
262 var treeNodeProps = getTreeNodeProps(mergedKey, treeNodeRequiredProps);
263 return /*#__PURE__*/React.createElement(MotionTreeNode, _extends({}, restProps, treeNodeProps, {
264 title: title,
265 active: !!activeItem && key === activeItem.key,
266 pos: pos,
267 data: treeNode.data,
268 isStart: isStart,
269 isEnd: isEnd,
270 motion: motion,
271 motionNodes: key === MOTION_KEY ? transitionRange : null,
272 motionType: motionType,
273 onMotionStart: onListChangeStart,
274 onMotionEnd: onMotionEnd,
275 treeNodeRequiredProps: treeNodeRequiredProps,
276 onMouseMove: function onMouseMove() {
277 onActiveChange(null);
278 }
279 }));
280 }));
281});
282NodeList.displayName = 'NodeList';
283export default NodeList;
\No newline at end of file