UNPKG

24.4 kBJavaScriptView Raw
1
2/*!
3 * EyzyTree v0.0.4
4 * (c) 2018 amsik
5 * Released under the MIT License.
6 */
7
8import React from 'react';
9
10/*! *****************************************************************************
11Copyright (c) Microsoft Corporation. All rights reserved.
12Licensed under the Apache License, Version 2.0 (the "License"); you may not use
13this file except in compliance with the License. You may obtain a copy of the
14License at http://www.apache.org/licenses/LICENSE-2.0
15
16THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
18WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
19MERCHANTABLITY OR NON-INFRINGEMENT.
20
21See the Apache Version 2.0 License for specific language governing permissions
22and limitations under the License.
23***************************************************************************** */
24/* global Reflect, Promise */
25
26var extendStatics = function(d, b) {
27 extendStatics = Object.setPrototypeOf ||
28 ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
29 function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
30 return extendStatics(d, b);
31};
32
33function __extends(d, b) {
34 extendStatics(d, b);
35 function __() { this.constructor = d; }
36 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
37}
38
39var __assign = function() {
40 __assign = Object.assign || function __assign(t) {
41 for (var s, i = 1, n = arguments.length; i < n; i++) {
42 s = arguments[i];
43 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
44 }
45 return t;
46 };
47 return __assign.apply(this, arguments);
48};
49
50var hasOwn = {}.hasOwnProperty;
51function cn(args) {
52 var result = [];
53 for (var key in args) {
54 if (hasOwn.call(args, key) && args[key]) {
55 result.push(key);
56 }
57 }
58 return result.join(' ');
59}
60
61function shallowEqual(objA, objB, keys) {
62 if (objA === objB) {
63 return true;
64 }
65 for (var i = 0; i < keys.length; i++) {
66 var key = keys[i];
67 var valueA = objA[key];
68 var valueB = objB[key];
69 if (valueA !== valueB) {
70 return false;
71 }
72 }
73 return true;
74}
75
76var hasChild = function (node) {
77 return node.isBatch || Array.isArray(node.child) && node.child.length > 0;
78};
79var comparingKeys = [
80 'id', 'checked', 'selected', 'child'
81];
82var TreeNode = /** @class */ (function (_super) {
83 __extends(TreeNode, _super);
84 function TreeNode() {
85 var _this = _super !== null && _super.apply(this, arguments) || this;
86 _this.handleSelect = function (event) {
87 if (_this.props.disabled) {
88 return;
89 }
90 if (_this.props.onSelect) {
91 _this.props.onSelect(_this.getNode(), event);
92 }
93 };
94 _this.handleCheck = function () {
95 if (_this.props.disabled || _this.props.disabledCheckbox) {
96 return;
97 }
98 if (_this.props.onCheck) {
99 _this.props.onCheck(_this.getNode());
100 }
101 };
102 _this.handleExpand = function () {
103 if (_this.props.onExpand) {
104 _this.props.onExpand(_this.getNode());
105 }
106 };
107 _this.handleDoubleClick = function (e) {
108 if (_this.props.onDoubleClick) {
109 _this.props.onDoubleClick(_this.getNode());
110 }
111 };
112 _this.renderCheckbox = function () {
113 if (!_this.props.checkable || _this.props.hidenCheckbox) {
114 return null;
115 }
116 var Checkbox = _this.props.checkboxRenderer;
117 if (!Checkbox) {
118 return React.createElement("span", { className: "node-checkbox", onMouseUp: _this.handleCheck });
119 }
120 return (React.createElement("span", { className: "node-checkbox-overrided", onMouseUp: _this.handleCheck },
121 React.createElement(Checkbox, { node: _this.getNode() })));
122 };
123 _this.renderArrow = function () {
124 var ArrowRenderer = _this.props.arrowRenderer;
125 if (!hasChild(_this.props)) {
126 return React.createElement("span", { className: "node-noop" });
127 }
128 if (!ArrowRenderer) {
129 return React.createElement("span", { className: "node-arrow", onMouseUp: _this.handleExpand });
130 }
131 return (React.createElement("span", { className: "node-arrow-extended", onMouseUp: _this.handleExpand },
132 React.createElement(ArrowRenderer, { node: _this.getNode() })));
133 };
134 return _this;
135 }
136 TreeNode.prototype.shouldComponentUpdate = function (nextProps) {
137 return !shallowEqual(this.props, nextProps, comparingKeys);
138 };
139 TreeNode.prototype.getNode = function () {
140 var _a = this.props, id = _a.id, checked = _a.checked, selected = _a.selected, text = _a.text, child = _a.child, expanded = _a.expanded, disabled = _a.disabled, parent = _a.parent, isBatch = _a.isBatch;
141 var node = {
142 id: id,
143 checked: checked,
144 selected: selected,
145 text: text,
146 child: child,
147 parent: parent
148 };
149 if (void 0 !== expanded) {
150 node.expanded = expanded;
151 }
152 if (void 0 !== disabled) {
153 node.disabled = disabled;
154 }
155 if (void 0 !== isBatch) {
156 node.isBatch = isBatch;
157 }
158 return node;
159 };
160 TreeNode.prototype.render = function () {
161 var _a = this.props, loading = _a.loading, checked = _a.checked, selected = _a.selected, children = _a.children, expanded = _a.expanded, disabled = _a.disabled, disabledCheckbox = _a.disabledCheckbox, indeterminate = _a.indeterminate, TextRenderer = _a.textRenderer;
162 var text = this.props.text;
163 var nodeContentClass = cn({
164 'node-content': true,
165 'has-child': hasChild(this.props),
166 'selected': selected,
167 'checked': checked,
168 'expanded': expanded,
169 'disabled': disabled,
170 'loading': loading,
171 'disabled-checkbox': disabledCheckbox,
172 'indeterminate': !checked && indeterminate
173 });
174 // console.log('RENDERING:', text)
175 return (React.createElement("li", { className: "tree-node" },
176 React.createElement("div", { className: nodeContentClass },
177 this.renderArrow(),
178 this.renderCheckbox(),
179 React.createElement("span", { className: "node-text", onMouseUp: this.handleSelect, onDoubleClick: this.handleDoubleClick }, TextRenderer ? React.createElement(TextRenderer, { node: this.getNode() }) : text)),
180 hasChild(this.props) && expanded &&
181 React.createElement("ul", { className: "node-child" }, children)));
182 };
183 return TreeNode;
184}(React.Component));
185
186function recurseDown(obj, fn, excludeSelf) {
187 var res;
188 if (Array.isArray(obj)) {
189 return obj.map(function (node) { return recurseDown(node, fn); });
190 }
191 if (obj[0]) {
192 return Object.keys(obj).map(function (key) { return recurseDown(obj[key], fn); });
193 }
194 if (!excludeSelf) {
195 res = fn(obj);
196 }
197 if (res !== false && obj.child && obj.child.length) {
198 res = recurseDown(obj.child, fn);
199 }
200 return res;
201}
202function rootElement(obj) {
203 var node = obj.parent;
204 while (node) {
205 if (!node.parent) {
206 return node;
207 }
208 node = node.parent;
209 }
210 return null;
211}
212function traverseUp(obj, fn) {
213 var node = obj.parent;
214 while (node) {
215 if (false === fn(node) || !node.parent) {
216 return;
217 }
218 node = node.parent;
219 }
220}
221
222var hasOwnProp = {}.hasOwnProperty;
223function isArray(obj) {
224 return Array.isArray(obj);
225}
226function isFunction(value) {
227 return 'function' === typeof value;
228}
229function copyArray(arr) {
230 return arr.concat([]);
231}
232function copyObject(obj) {
233 var newObj = {};
234 for (var i in obj) {
235 if (hasOwnProp.call(obj, i)) {
236 newObj[i] = isArray(obj[i]) ? copyArray(obj[i]) : obj[i];
237 }
238 }
239 return newObj;
240}
241function isRoot(node) {
242 return node && !node.parent;
243}
244function isLeaf(node) {
245 return node.child && 0 === node.child.length;
246}
247function isNodeIndeterminate(node, treeCheckedNodes, indeterminateNodes) {
248 if (!node.child.length) {
249 return false;
250 }
251 var hasIndeterminate = node.child.some(function (child) {
252 return !child.disabled && !child.disabledCheckbox && -1 !== indeterminateNodes.indexOf(child.id);
253 });
254 if (hasIndeterminate) {
255 return true;
256 }
257 var uncheckedNodes = node.child.reduce(function (count, item) {
258 if (true !== item.disabled && true !== item.disabledCheckbox && -1 === treeCheckedNodes.indexOf(item.id)) {
259 count++;
260 }
261 return count;
262 }, 0);
263 return uncheckedNodes > 0 && uncheckedNodes < node.child.length;
264}
265
266function replaceChild(node) {
267 if (!node || !node.child) {
268 return node;
269 }
270 node.child = copyArray(node.child);
271 node.child.forEach(function (child) {
272 var replaced = replaceChild(child);
273 replaced.parent = node;
274 return replaced;
275 });
276 return node;
277}
278function getItemById(id, targetState) {
279 return Object.keys(targetState)
280 .find(function (k) { return targetState[k].id === id; }) || null;
281}
282function getNodeIndex(nodeId, parent, nodesLength) {
283 if (parent.child) {
284 var childIndex_1 = null;
285 parent.child.some(function (node, i) {
286 if (nodeId === node.id) {
287 childIndex_1 = i;
288 return true;
289 }
290 return false;
291 });
292 return childIndex_1;
293 }
294 for (var i = 0; i < nodesLength; i++) {
295 if (parent[i].id === nodeId) {
296 return i;
297 }
298 }
299 return null;
300}
301function updateChildNodes(parentNode) {
302 parentNode.child.forEach(function (child) {
303 child.parent = parentNode;
304 });
305 return parentNode;
306}
307var State = /** @class */ (function () {
308 function State(state, stateLength) {
309 this.state = state;
310 this.stateLength = stateLength;
311 }
312 State.prototype.updateRootNode = function (node, key, value) {
313 var i = getItemById(node.id, this.state);
314 var newObj = copyObject(node);
315 if (key) {
316 node[key] = value;
317 newObj[key] = value;
318 }
319 if (null !== i) {
320 this.state[i] = updateChildNodes(newObj);
321 }
322 };
323 State.prototype.updateLeafNode = function (node, key, value) {
324 var root = rootElement(node);
325 var parentNode = node.parent;
326 if (!parentNode || !root || !parentNode.child) {
327 return;
328 }
329 var index = getNodeIndex(node.id, parentNode, this.stateLength);
330 if (null === index) {
331 return;
332 }
333 node[key] = value;
334 parentNode.child[index][key] = value;
335 this.updateRootNode(replaceChild(root));
336 };
337 State.prototype.set = function (id, key, value) {
338 var node = this.getNodeById(id);
339 if (!node) {
340 return this.state;
341 }
342 if (isRoot(node)) {
343 this.updateRootNode(node, key, value);
344 }
345 else {
346 this.updateLeafNode(node, key, value);
347 }
348 return this.state;
349 };
350 State.prototype.getNodeById = function (id) {
351 var node = null;
352 recurseDown(this.state, function (obj) {
353 if (obj.id === id) {
354 node = obj;
355 return false;
356 }
357 });
358 return node;
359 };
360 State.prototype.get = function () {
361 return this.state;
362 };
363 return State;
364}());
365
366function s4() {
367 return Math.floor((1 + Math.random()) * 0x10000)
368 .toString(16)
369 .substring(1);
370}
371function uuid() {
372 return s4() + '-' + s4();
373}
374
375function parseNode(data, parentNode) {
376 if (!data || !Array.isArray(data)) {
377 return [];
378 }
379 var parent = parentNode || null;
380 if ('string' === typeof data) {
381 return [
382 { text: data, id: uuid(), parent: parent, child: [] }
383 ];
384 }
385 return data.map(function (node) {
386 if ('string' === typeof node) {
387 return {
388 id: uuid(),
389 text: node,
390 parent: parent,
391 child: []
392 };
393 }
394 node.id = node.id || uuid();
395 node.child = Array.isArray(node.child)
396 ? parseNode(node.child, node)
397 : [];
398 node.parent = parent;
399 return node;
400 });
401}
402
403var EyzyTree = /** @class */ (function (_super) {
404 __extends(EyzyTree, _super);
405 function EyzyTree(props) {
406 var _this = _super.call(this, props) || this;
407 _this.stateCache = null;
408 _this.selectedNodes = [];
409 _this.checkedNodes = [];
410 _this.indeterminateNodes = [];
411 _this.refreshIndeterminateState = function (id, willBeChecked, shouldRender) {
412 var checkedNodes = copyArray(_this.checkedNodes);
413 var indeterminateNodes = copyArray(_this.indeterminateNodes);
414 var state = _this.getState();
415 var childIds = [];
416 var node = state.getNodeById(id);
417 if (!node) {
418 return;
419 }
420 recurseDown(node, function (child) {
421 if (!child.disabled && !child.disabledCheckbox && id !== child.id) {
422 childIds.push(child.id);
423 }
424 });
425 if (willBeChecked) {
426 checkedNodes.push.apply(checkedNodes, childIds);
427 }
428 else {
429 checkedNodes = checkedNodes.filter(function (nodeId) { return !~childIds.indexOf(nodeId); });
430 }
431 traverseUp(node, function (parentNode) {
432 if (parentNode.disabledCheckbox || parentNode.disabled) {
433 return false;
434 }
435 var isIndeterminate = isNodeIndeterminate(parentNode, checkedNodes, indeterminateNodes);
436 var id = parentNode.id;
437 if (isIndeterminate) {
438 !~indeterminateNodes.indexOf(id) && indeterminateNodes.push(id);
439 checkedNodes = checkedNodes.filter(function (nodeId) { return nodeId !== id; });
440 }
441 else {
442 indeterminateNodes = indeterminateNodes.filter(function (nodeId) { return nodeId !== id; });
443 if (willBeChecked) {
444 checkedNodes.push(id);
445 }
446 else {
447 checkedNodes = checkedNodes.filter(function (nodeId) { return nodeId !== id; });
448 }
449 }
450 });
451 indeterminateNodes = indeterminateNodes.filter(function (nodeId) { return !~checkedNodes.indexOf(nodeId); });
452 _this.checkedNodes.forEach(function (id) {
453 if (-1 !== _this.checkedNodes.indexOf(id)) {
454 state.set(id, 'checked', false);
455 }
456 });
457 _this.indeterminateNodes.forEach(function (id) {
458 if (-1 !== _this.indeterminateNodes.indexOf(id)) {
459 state.set(id, 'indeterminate', false);
460 }
461 });
462 checkedNodes.forEach(function (id) { return state.set(id, 'checked', true); });
463 indeterminateNodes.forEach(function (id) { return state.set(id, 'indeterminate', true); });
464 _this.checkedNodes = checkedNodes;
465 _this.indeterminateNodes = indeterminateNodes;
466 if (false !== shouldRender) {
467 _this.updateState(state, true);
468 }
469 };
470 _this.getState = function () {
471 return _this.stateCache || new State(_this.state, _this.stateLength);
472 };
473 _this.updateState = function (state, clearCache) {
474 if (clearCache) {
475 _this.setState(state);
476 _this.stateCache = null;
477 return;
478 }
479 if (_this.stateCache) {
480 return;
481 }
482 _this.setState(state);
483 };
484 _this.useState = function (state, cb) {
485 _this.stateCache = state;
486 cb();
487 };
488 _this.select = function (node, ignoreEvent) {
489 var state = _this.getState();
490 _this.selectedNodes = _this.selectedNodes.filter(function (nodeId) {
491 var node = state.getNodeById(nodeId);
492 if (node) {
493 state.set(node.id, 'selected', false);
494 if (true !== ignoreEvent && _this.props.onUnSelect) {
495 _this.props.onUnSelect(node);
496 }
497 }
498 return false;
499 });
500 state.set(node.id, 'selected', true);
501 _this.selectedNodes.push(node.id);
502 _this.updateState(state.get());
503 if (true !== ignoreEvent && _this.props.onSelect) {
504 _this.props.onSelect(node);
505 }
506 };
507 _this.check = function (node) {
508 var state = _this.getState();
509 var willBeChecked = !node.checked;
510 var id = node.id;
511 state.set(id, 'checked', willBeChecked);
512 if (willBeChecked) {
513 _this.checkedNodes = _this.checkedNodes.concat([id]);
514 }
515 else {
516 _this.checkedNodes = _this.checkedNodes.filter(function (checkedId) { return id !== checkedId; });
517 }
518 if (_this.props.selectOnCheck) {
519 _this.useState(state, function () {
520 _this.select(node);
521 });
522 }
523 if (_this.props.autoCheckChildren !== false) {
524 _this.useState(state, function () {
525 _this.refreshIndeterminateState(node.id, willBeChecked);
526 });
527 }
528 else {
529 _this.updateState(state.get(), true);
530 }
531 if (_this.props.onCheck) {
532 _this.props.onCheck(node);
533 }
534 };
535 _this.expand = function (node) {
536 if (node.isBatch) {
537 return _this.loadChild(node);
538 }
539 if (!node.child.length) {
540 return;
541 }
542 var state = _this.getState();
543 state.set(node.id, 'expanded', !node.expanded);
544 if (_this.props.selectOnExpand && !node.selected) {
545 _this.useState(state, function () {
546 _this.select(node);
547 });
548 }
549 _this.updateState(state.get(), true);
550 if (_this.props.onExpand) {
551 _this.props.onExpand(node, !!node.expanded);
552 }
553 };
554 _this.handleDoubleClick = function (node) {
555 if (node.disabled || !node.child.length || _this.props.expandOnSelect) {
556 return;
557 }
558 _this.expand(node);
559 if (_this.props.onDoubleClick) {
560 _this.props.onDoubleClick(node);
561 }
562 };
563 _this.handleSelect = function (node, event) {
564 _this.select(node);
565 var _a = _this.props, checkOnSelect = _a.checkOnSelect, expandOnSelect = _a.expandOnSelect, checkable = _a.checkable;
566 if (checkable && checkOnSelect && !node.disabledCheckbox) {
567 _this.check(node);
568 }
569 else if (expandOnSelect) {
570 _this.expand(node);
571 }
572 };
573 _this.loadChild = function (node) {
574 var fetchData = _this.props.fetchData;
575 if (!fetchData || !isFunction(fetchData)) {
576 return;
577 }
578 var result = fetchData(node);
579 if (!result || !result.then) {
580 throw new Error('`fetchData` property must return a Promise');
581 }
582 var state = _this.getState();
583 var autoCheckChildren = _this.props.autoCheckChildren;
584 var id = node.id;
585 state.set(id, 'loading', true);
586 result.then(function (nodes) {
587 var child = parseNode(nodes).map(function (obj) {
588 obj.parent = node;
589 return obj;
590 });
591 state.set(id, 'loading', false);
592 state.set(id, 'expanded', true);
593 state.set(id, 'isBatch', false);
594 state.set(id, 'child', child);
595 recurseDown(state.getNodeById(id), function (obj) {
596 if (id == obj.id || !obj.checked) {
597 return;
598 }
599 _this.checkedNodes.push(obj.id);
600 if (!isLeaf(obj) || autoCheckChildren === false) {
601 return;
602 }
603 _this.useState(state, function () {
604 _this.refreshIndeterminateState(obj.id, !!obj.checked, false);
605 });
606 });
607 _this.updateState(state.get(), true);
608 });
609 _this.updateState(state.get());
610 };
611 _this.renderNode = function (node) {
612 var treePropsKeys = [
613 'checkable', 'arrowRenderer', 'textRenderer', 'checkboxRenderer'
614 ];
615 var treeProps = treePropsKeys.reduce(function (props, key) {
616 if (_this.props[key]) {
617 props[key] = _this.props[key];
618 }
619 return props;
620 }, {});
621 return (React.createElement(TreeNode, __assign({ key: node.id, node: node, onSelect: _this.handleSelect, onDoubleClick: _this.handleDoubleClick, onCheck: _this.check, onExpand: _this.expand }, treeProps, node), node.expanded ? node.child.map(_this.renderNode) : null));
622 };
623 var data = parseNode(props.data);
624 var stateObject = {};
625 data.forEach(function (item, i) {
626 stateObject[i] = item;
627 });
628 recurseDown(stateObject, function (obj) {
629 if (obj.selected) {
630 _this.selectedNodes.push(obj.id);
631 }
632 if (obj.checked) {
633 _this.checkedNodes.push(obj.id);
634 }
635 });
636 var state = new State(stateObject, data.length);
637 _this.checkedNodes.forEach(function (id) {
638 var node = state.getNodeById(id);
639 if (node && isLeaf(node) && _this.props.autoCheckChildren !== false) {
640 _this.useState(state, function () {
641 _this.refreshIndeterminateState(id, true, false);
642 });
643 }
644 });
645 _this.stateLength = data.length;
646 _this.state = state.get();
647 _this.stateCache = null;
648 return _this;
649 }
650 EyzyTree.prototype.render = function () {
651 var nodes = [];
652 var props = this.props;
653 var treeClass = 'theme' in props
654 ? 'eyzy-tree ' + props.theme
655 : 'eyzy-tree eyzy-theme';
656 for (var i = 0; i < this.stateLength; i++) {
657 nodes.push(this.renderNode(this.state[i]));
658 }
659 return (React.createElement("ul", { className: treeClass }, nodes));
660 };
661 EyzyTree.TreeNode = TreeNode;
662 return EyzyTree;
663}(React.Component));
664
665export default EyzyTree;
666//# sourceMappingURL=eyzy-tree.esm.js.map