@elliemae/ds-treeview 2.2.0-alpha.2 → 2.2.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/TreeView.js +31 -49
- package/cjs/TreeViewContext.js +35 -53
- package/cjs/config/cssClassesConstants.js +13 -41
- package/cjs/config/useTreeview.js +80 -108
- package/cjs/index.js +27 -37
- package/cjs/parts/CheckboxSelectable.js +59 -70
- package/cjs/parts/ChildrenCountDisplayer.js +28 -45
- package/cjs/parts/ExpandCaret.js +83 -85
- package/cjs/parts/Icon.js +31 -46
- package/cjs/parts/NestingSpace.js +35 -43
- package/cjs/parts/RadioSelectable.js +37 -52
- package/cjs/parts/TreeItem.js +147 -128
- package/cjs/parts/TreeItemText.js +95 -88
- package/cjs/parts/TreeList.js +130 -117
- package/cjs/plugins/dnd/TreeDndPlugin.js +36 -51
- package/cjs/plugins/dnd/index.js +10 -28
- package/cjs/plugins/index.js +22 -34
- package/cjs/plugins/roving/TreeRovingPlugin.js +7 -35
- package/cjs/plugins/roving/index.js +9 -28
- package/cjs/plugins/searchable/SearchableTreePlugin.js +7 -35
- package/cjs/plugins/searchable/index.js +9 -28
- package/cjs/plugins/selectable/SelectablePluginTree.js +7 -35
- package/cjs/plugins/selectable/index.js +9 -28
- package/cjs/plugins/toolbar/TreeToolbarPlugin.js +7 -35
- package/cjs/plugins/toolbar/index.js +9 -28
- package/cjs/plugins/tree/TreeDataPlugin.js +7 -35
- package/cjs/plugins/tree/index.js +9 -28
- package/cjs/plugins/virtualization/TreeVirtualizationPlugin.js +7 -35
- package/cjs/plugins/virtualization/index.js +9 -28
- package/cjs/react-desc-prop-types.js +53 -82
- package/cjs/related-components/TreeViewSearchBar.js +40 -42
- package/cjs/sharedTypes.js +2 -27
- package/cjs/utils/array-helpers.js +11 -35
- package/cjs/utils/dnd-helpers.js +84 -90
- package/cjs/utils/group-expands-helpers.js +59 -86
- package/cjs/utils/keyboard-helpers.js +88 -84
- package/cjs/utils/object-helpers.js +36 -43
- package/cjs/utils/refs-helpers.js +22 -43
- package/cjs/utils/selectable-helper.js +53 -61
- package/cjs/utils/string-helpers.js +7 -35
- package/cjs/utils/tree-helpers.js +135 -105
- package/cjs/utils/useDnDHelpers.js +118 -97
- package/cjs/utils/useInstanceRefActions.js +43 -54
- package/cjs/utils/useTree.js +78 -76
- package/esm/TreeView.js +20 -18
- package/esm/TreeViewContext.js +29 -24
- package/esm/config/cssClassesConstants.js +6 -12
- package/esm/config/useTreeview.js +54 -61
- package/esm/index.js +9 -8
- package/esm/parts/CheckboxSelectable.js +46 -36
- package/esm/parts/ChildrenCountDisplayer.js +20 -16
- package/esm/parts/ExpandCaret.js +72 -54
- package/esm/parts/Icon.js +22 -16
- package/esm/parts/NestingSpace.js +27 -14
- package/esm/parts/RadioSelectable.js +28 -20
- package/esm/parts/TreeItem.js +127 -91
- package/esm/parts/TreeItemText.js +85 -58
- package/esm/parts/TreeList.js +117 -88
- package/esm/plugins/dnd/TreeDndPlugin.js +26 -21
- package/esm/plugins/dnd/index.js +1 -3
- package/esm/plugins/index.js +7 -9
- package/esm/plugins/roving/TreeRovingPlugin.js +3 -6
- package/esm/plugins/roving/index.js +1 -3
- package/esm/plugins/searchable/SearchableTreePlugin.js +3 -6
- package/esm/plugins/searchable/index.js +1 -3
- package/esm/plugins/selectable/SelectablePluginTree.js +3 -6
- package/esm/plugins/selectable/index.js +1 -3
- package/esm/plugins/toolbar/TreeToolbarPlugin.js +3 -6
- package/esm/plugins/toolbar/index.js +1 -3
- package/esm/plugins/tree/TreeDataPlugin.js +3 -6
- package/esm/plugins/tree/index.js +1 -3
- package/esm/plugins/virtualization/TreeVirtualizationPlugin.js +3 -6
- package/esm/plugins/virtualization/index.js +1 -3
- package/esm/react-desc-prop-types.js +43 -47
- package/esm/related-components/TreeViewSearchBar.js +32 -13
- package/esm/sharedTypes.js +1 -2
- package/esm/utils/array-helpers.js +6 -6
- package/esm/utils/dnd-helpers.js +73 -58
- package/esm/utils/group-expands-helpers.js +46 -56
- package/esm/utils/keyboard-helpers.js +72 -45
- package/esm/utils/object-helpers.js +31 -14
- package/esm/utils/refs-helpers.js +19 -15
- package/esm/utils/selectable-helper.js +43 -32
- package/esm/utils/string-helpers.js +3 -6
- package/esm/utils/tree-helpers.js +119 -74
- package/esm/utils/useDnDHelpers.js +106 -60
- package/esm/utils/useInstanceRefActions.js +35 -21
- package/esm/utils/useTree.js +57 -35
- package/package.json +10 -10
- package/types/TreeView.d.ts +1 -1
- package/cjs/TreeView.js.map +0 -7
- package/cjs/TreeViewContext.js.map +0 -7
- package/cjs/config/cssClassesConstants.js.map +0 -7
- package/cjs/config/useTreeview.js.map +0 -7
- package/cjs/index.js.map +0 -7
- package/cjs/parts/CheckboxSelectable.js.map +0 -7
- package/cjs/parts/ChildrenCountDisplayer.js.map +0 -7
- package/cjs/parts/ExpandCaret.js.map +0 -7
- package/cjs/parts/Icon.js.map +0 -7
- package/cjs/parts/NestingSpace.js.map +0 -7
- package/cjs/parts/RadioSelectable.js.map +0 -7
- package/cjs/parts/TreeItem.js.map +0 -7
- package/cjs/parts/TreeItemText.js.map +0 -7
- package/cjs/parts/TreeList.js.map +0 -7
- package/cjs/plugins/dnd/TreeDndPlugin.js.map +0 -7
- package/cjs/plugins/dnd/index.js.map +0 -7
- package/cjs/plugins/index.js.map +0 -7
- package/cjs/plugins/roving/TreeRovingPlugin.js.map +0 -7
- package/cjs/plugins/roving/index.js.map +0 -7
- package/cjs/plugins/searchable/SearchableTreePlugin.js.map +0 -7
- package/cjs/plugins/searchable/index.js.map +0 -7
- package/cjs/plugins/selectable/SelectablePluginTree.js.map +0 -7
- package/cjs/plugins/selectable/index.js.map +0 -7
- package/cjs/plugins/toolbar/TreeToolbarPlugin.js.map +0 -7
- package/cjs/plugins/toolbar/index.js.map +0 -7
- package/cjs/plugins/tree/TreeDataPlugin.js.map +0 -7
- package/cjs/plugins/tree/index.js.map +0 -7
- package/cjs/plugins/virtualization/TreeVirtualizationPlugin.js.map +0 -7
- package/cjs/plugins/virtualization/index.js.map +0 -7
- package/cjs/react-desc-prop-types.js.map +0 -7
- package/cjs/related-components/TreeViewSearchBar.js.map +0 -7
- package/cjs/sharedTypes.js.map +0 -7
- package/cjs/utils/array-helpers.js.map +0 -7
- package/cjs/utils/dnd-helpers.js.map +0 -7
- package/cjs/utils/group-expands-helpers.js.map +0 -7
- package/cjs/utils/keyboard-helpers.js.map +0 -7
- package/cjs/utils/object-helpers.js.map +0 -7
- package/cjs/utils/refs-helpers.js.map +0 -7
- package/cjs/utils/selectable-helper.js.map +0 -7
- package/cjs/utils/string-helpers.js.map +0 -7
- package/cjs/utils/tree-helpers.js.map +0 -7
- package/cjs/utils/useDnDHelpers.js.map +0 -7
- package/cjs/utils/useInstanceRefActions.js.map +0 -7
- package/cjs/utils/useTree.js.map +0 -7
- package/esm/TreeView.js.map +0 -7
- package/esm/TreeViewContext.js.map +0 -7
- package/esm/config/cssClassesConstants.js.map +0 -7
- package/esm/config/useTreeview.js.map +0 -7
- package/esm/index.js.map +0 -7
- package/esm/parts/CheckboxSelectable.js.map +0 -7
- package/esm/parts/ChildrenCountDisplayer.js.map +0 -7
- package/esm/parts/ExpandCaret.js.map +0 -7
- package/esm/parts/Icon.js.map +0 -7
- package/esm/parts/NestingSpace.js.map +0 -7
- package/esm/parts/RadioSelectable.js.map +0 -7
- package/esm/parts/TreeItem.js.map +0 -7
- package/esm/parts/TreeItemText.js.map +0 -7
- package/esm/parts/TreeList.js.map +0 -7
- package/esm/plugins/dnd/TreeDndPlugin.js.map +0 -7
- package/esm/plugins/dnd/index.js.map +0 -7
- package/esm/plugins/index.js.map +0 -7
- package/esm/plugins/roving/TreeRovingPlugin.js.map +0 -7
- package/esm/plugins/roving/index.js.map +0 -7
- package/esm/plugins/searchable/SearchableTreePlugin.js.map +0 -7
- package/esm/plugins/searchable/index.js.map +0 -7
- package/esm/plugins/selectable/SelectablePluginTree.js.map +0 -7
- package/esm/plugins/selectable/index.js.map +0 -7
- package/esm/plugins/toolbar/TreeToolbarPlugin.js.map +0 -7
- package/esm/plugins/toolbar/index.js.map +0 -7
- package/esm/plugins/tree/TreeDataPlugin.js.map +0 -7
- package/esm/plugins/tree/index.js.map +0 -7
- package/esm/plugins/virtualization/TreeVirtualizationPlugin.js.map +0 -7
- package/esm/plugins/virtualization/index.js.map +0 -7
- package/esm/react-desc-prop-types.js.map +0 -7
- package/esm/related-components/TreeViewSearchBar.js.map +0 -7
- package/esm/sharedTypes.js.map +0 -7
- package/esm/utils/array-helpers.js.map +0 -7
- package/esm/utils/dnd-helpers.js.map +0 -7
- package/esm/utils/group-expands-helpers.js.map +0 -7
- package/esm/utils/keyboard-helpers.js.map +0 -7
- package/esm/utils/object-helpers.js.map +0 -7
- package/esm/utils/refs-helpers.js.map +0 -7
- package/esm/utils/selectable-helper.js.map +0 -7
- package/esm/utils/string-helpers.js.map +0 -7
- package/esm/utils/tree-helpers.js.map +0 -7
- package/esm/utils/useDnDHelpers.js.map +0 -7
- package/esm/utils/useInstanceRefActions.js.map +0 -7
- package/esm/utils/useTree.js.map +0 -7
|
@@ -1,59 +1,70 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
1
|
+
import 'core-js/modules/esnext.async-iterator.filter.js';
|
|
2
|
+
import 'core-js/modules/esnext.iterator.constructor.js';
|
|
3
|
+
import 'core-js/modules/esnext.iterator.filter.js';
|
|
4
|
+
import 'core-js/modules/esnext.async-iterator.for-each.js';
|
|
5
|
+
import 'core-js/modules/esnext.iterator.for-each.js';
|
|
6
|
+
import _defineProperty from '@babel/runtime/helpers/esm/defineProperty';
|
|
7
|
+
import { walkAllNodeChildren, walkParents } from './tree-helpers.js';
|
|
8
|
+
|
|
9
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
10
|
+
|
|
11
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
12
|
+
const getGroupCheckState = node => {
|
|
4
13
|
let childAllChecked = true;
|
|
5
14
|
let anyChildChecked = false;
|
|
6
|
-
walkAllNodeChildren(node,
|
|
15
|
+
walkAllNodeChildren(node, childNode => {
|
|
7
16
|
const {
|
|
8
|
-
model: {
|
|
17
|
+
model: {
|
|
18
|
+
isChecked
|
|
19
|
+
}
|
|
9
20
|
} = childNode;
|
|
10
|
-
if (isChecked ===
|
|
11
|
-
anyChildChecked = true;
|
|
12
|
-
else
|
|
13
|
-
childAllChecked = false;
|
|
21
|
+
if (isChecked === 'mixed' || isChecked === true) anyChildChecked = true;else childAllChecked = false;
|
|
14
22
|
});
|
|
15
|
-
if (childAllChecked)
|
|
16
|
-
|
|
17
|
-
if (anyChildChecked)
|
|
18
|
-
return "mixed";
|
|
23
|
+
if (childAllChecked) return true;
|
|
24
|
+
if (anyChildChecked) return 'mixed';
|
|
19
25
|
return false;
|
|
20
26
|
};
|
|
21
|
-
const selectCheckboxItemModelParentsTillRoot = (modelToCheck
|
|
27
|
+
const selectCheckboxItemModelParentsTillRoot = function (modelToCheck) {
|
|
28
|
+
let triggerTreeRerender = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
22
29
|
const newSelections = {};
|
|
23
|
-
const {
|
|
24
|
-
|
|
30
|
+
const {
|
|
31
|
+
nodePath
|
|
32
|
+
} = modelToCheck;
|
|
33
|
+
walkParents(nodePath, parentNode => {
|
|
25
34
|
const nextState = getGroupCheckState(parentNode);
|
|
26
35
|
parentNode.model.isChecked = nextState;
|
|
27
36
|
newSelections[parentNode.model.id] = nextState;
|
|
28
37
|
});
|
|
29
|
-
if (triggerTreeRerender)
|
|
30
|
-
triggerTreeRerender();
|
|
38
|
+
if (triggerTreeRerender) triggerTreeRerender();
|
|
31
39
|
return newSelections;
|
|
32
40
|
};
|
|
33
|
-
const toggleCheckboxItem = (itemToSelect
|
|
41
|
+
const toggleCheckboxItem = function (itemToSelect) {
|
|
42
|
+
let triggerTreeRerender = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
34
43
|
const {
|
|
35
44
|
node: {
|
|
36
|
-
model: {
|
|
45
|
+
model: {
|
|
46
|
+
id,
|
|
47
|
+
isChecked,
|
|
48
|
+
children = []
|
|
49
|
+
}
|
|
37
50
|
}
|
|
38
51
|
} = itemToSelect;
|
|
39
|
-
const newSelections = {};
|
|
40
|
-
|
|
52
|
+
const newSelections = {}; // 'mixed' -> true -> false -> true [...->false -> true]
|
|
53
|
+
|
|
54
|
+
const nextState = isChecked === 'mixed' ? true : !isChecked;
|
|
41
55
|
itemToSelect.node.model.isChecked = nextState;
|
|
42
56
|
newSelections[id] = nextState;
|
|
57
|
+
|
|
43
58
|
if (children.length > 0 && (nextState === true || nextState === false)) {
|
|
44
|
-
walkAllNodeChildren(itemToSelect.node,
|
|
59
|
+
walkAllNodeChildren(itemToSelect.node, childNode => {
|
|
45
60
|
childNode.model.isChecked = nextState;
|
|
46
61
|
newSelections[childNode.model.id] = nextState;
|
|
47
62
|
});
|
|
48
63
|
}
|
|
64
|
+
|
|
49
65
|
const parentsNewSelections = selectCheckboxItemModelParentsTillRoot(itemToSelect);
|
|
50
|
-
if (triggerTreeRerender)
|
|
51
|
-
|
|
52
|
-
return { ...parentsNewSelections, ...newSelections };
|
|
53
|
-
};
|
|
54
|
-
export {
|
|
55
|
-
getGroupCheckState,
|
|
56
|
-
selectCheckboxItemModelParentsTillRoot,
|
|
57
|
-
toggleCheckboxItem
|
|
66
|
+
if (triggerTreeRerender) triggerTreeRerender();
|
|
67
|
+
return _objectSpread(_objectSpread({}, parentsNewSelections), newSelections);
|
|
58
68
|
};
|
|
59
|
-
|
|
69
|
+
|
|
70
|
+
export { getGroupCheckState, selectCheckboxItemModelParentsTillRoot, toggleCheckboxItem };
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export {
|
|
4
|
-
standardizeSearchQueryString
|
|
5
|
-
};
|
|
6
|
-
//# sourceMappingURL=string-helpers.js.map
|
|
1
|
+
const standardizeSearchQueryString = input => input.trim().toLowerCase();
|
|
2
|
+
|
|
3
|
+
export { standardizeSearchQueryString };
|
|
@@ -1,135 +1,180 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import 'core-js/modules/esnext.async-iterator.for-each.js';
|
|
2
|
+
import 'core-js/modules/esnext.iterator.constructor.js';
|
|
3
|
+
import 'core-js/modules/esnext.iterator.for-each.js';
|
|
4
|
+
import 'core-js/modules/web.dom-collections.iterator.js';
|
|
5
|
+
import 'core-js/modules/esnext.async-iterator.find.js';
|
|
6
|
+
import 'core-js/modules/esnext.iterator.find.js';
|
|
7
|
+
import 'core-js/modules/esnext.async-iterator.every.js';
|
|
8
|
+
import 'core-js/modules/esnext.iterator.every.js';
|
|
9
|
+
import { createRef } from 'react';
|
|
10
|
+
import { standardizeSearchQueryString } from './string-helpers.js';
|
|
11
|
+
|
|
12
|
+
const walkVisibles = function (node, callback) {
|
|
13
|
+
let skipRoot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
14
|
+
let highlightOnlyQuery = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
15
|
+
const {
|
|
16
|
+
children,
|
|
17
|
+
model
|
|
18
|
+
} = node;
|
|
19
|
+
const {
|
|
20
|
+
name,
|
|
21
|
+
isExpanded,
|
|
22
|
+
childrenMatchesSearchQuery,
|
|
23
|
+
matchesSearchQuery
|
|
24
|
+
} = model;
|
|
25
|
+
const shouldSkipBecauseIsRoot = skipRoot && name === '__root';
|
|
8
26
|
const queryRestrictionsPassed = !!(highlightOnlyQuery || childrenMatchesSearchQuery || matchesSearchQuery);
|
|
9
|
-
if (!shouldSkipBecauseIsRoot && queryRestrictionsPassed)
|
|
10
|
-
callback(node);
|
|
27
|
+
if (!shouldSkipBecauseIsRoot && queryRestrictionsPassed) callback(node);
|
|
11
28
|
const shouldWalkChildren = !!(children.length > 0 && isExpanded && queryRestrictionsPassed);
|
|
29
|
+
|
|
12
30
|
if (shouldWalkChildren) {
|
|
13
|
-
children.forEach(
|
|
31
|
+
children.forEach(childNode => {
|
|
14
32
|
walkVisibles(childNode, callback, skipRoot, highlightOnlyQuery);
|
|
15
33
|
});
|
|
16
34
|
}
|
|
17
35
|
};
|
|
18
|
-
const walkParents = (nodePath, callback
|
|
36
|
+
const walkParents = function (nodePath, callback) {
|
|
37
|
+
let skipRoot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
19
38
|
const parents = [...nodePath].reverse();
|
|
20
|
-
parents.shift();
|
|
21
|
-
|
|
22
|
-
|
|
39
|
+
parents.shift(); // remove current node from the parents array
|
|
40
|
+
|
|
41
|
+
if (skipRoot) parents.pop(); // remove the root from the parents if skipping root
|
|
42
|
+
|
|
23
43
|
parents.forEach(callback);
|
|
24
44
|
};
|
|
25
|
-
const walkAllNodeChildren = (node, callback
|
|
26
|
-
|
|
45
|
+
const walkAllNodeChildren = function (node, callback) {
|
|
46
|
+
let isFirst = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
47
|
+
const {
|
|
48
|
+
children = []
|
|
49
|
+
} = node;
|
|
27
50
|
const shouldWalkChildren = children.length;
|
|
28
|
-
if (!isFirst)
|
|
29
|
-
|
|
51
|
+
if (!isFirst) callback(node);
|
|
52
|
+
|
|
30
53
|
if (shouldWalkChildren) {
|
|
31
|
-
children.forEach(
|
|
54
|
+
children.forEach(childNode => {
|
|
32
55
|
walkAllNodeChildren(childNode, callback, false);
|
|
33
56
|
});
|
|
34
57
|
}
|
|
35
58
|
};
|
|
36
59
|
const getNodeById = (treeRoot, id) => {
|
|
37
|
-
const nodes = treeRoot.all(
|
|
60
|
+
const nodes = treeRoot.all(node => node.model.id === id);
|
|
38
61
|
return nodes[0];
|
|
39
62
|
};
|
|
40
63
|
const cloneNode = (tree, node) => tree.parse(node.model);
|
|
41
|
-
const itemsShareSameParent = (
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (items.length === 1)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const firstExistingItemPath = firstExistingItem.node.getPath();
|
|
64
|
+
const itemsShareSameParent = function () {
|
|
65
|
+
let items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
66
|
+
if (items.length === 0) throw new Error('Received empty items for comparison');
|
|
67
|
+
if (items.length === 1) return true; // when moving in first position we receive [undefined,...{items}]
|
|
68
|
+
// when moving in last position we receive [...{items}, undefined]
|
|
69
|
+
|
|
70
|
+
const firstExistingItem = items.find(item => !!item);
|
|
71
|
+
if (!firstExistingItem) throw new Error("Received no items, can't retrieve parent");
|
|
72
|
+
const firstExistingItemPath = firstExistingItem.node.getPath(); // path is like [rootParent, ...[parentsNodes], currentNode]
|
|
73
|
+
// length -1 is the current-node
|
|
74
|
+
// length -2 is the parent-node
|
|
75
|
+
// root node is not printed and is always present so minimum path length is 2 (root + currentNode)
|
|
76
|
+
|
|
50
77
|
const directParentNode = firstExistingItemPath[firstExistingItemPath.length - 2];
|
|
51
|
-
return items.every(
|
|
52
|
-
|
|
53
|
-
|
|
78
|
+
return items.every(item => {
|
|
79
|
+
// undefined nodes count as having the same parent
|
|
80
|
+
if (!item) return true;
|
|
54
81
|
const itemPath = item.node.getPath();
|
|
55
82
|
const itemDirectParent = itemPath[itemPath.length - 2];
|
|
56
83
|
return directParentNode === itemDirectParent;
|
|
57
84
|
});
|
|
58
85
|
};
|
|
59
|
-
const getItemsParentNode = (
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
const getItemsParentNode = function () {
|
|
87
|
+
let items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
|
|
88
|
+
let skipSameParentCheck = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
89
|
+
if (items.length === 0) throw new Error("Received empty items, can't retrieve parent"); // in case we already know the items compared shares the same parent
|
|
90
|
+
|
|
91
|
+
if (!skipSameParentCheck) if (!itemsShareSameParent(items)) // if we don't know (default, we don't) check if they share the parent
|
|
92
|
+
throw new Error("Received items don't share the same parent, can't retrieve parent"); // when moving in first position we receive [undefined,...{items}]
|
|
93
|
+
// when moving in last position we receive [...{items}, undefined]
|
|
94
|
+
|
|
95
|
+
const firstExistingItem = items.find(item => !!item);
|
|
96
|
+
if (!firstExistingItem) throw new Error("Received no items, can't retrieve parent");
|
|
97
|
+
const firstExistingItemPath = firstExistingItem.node.getPath(); // path is like [rootParent, ...[parentsNodes], currentNode]
|
|
98
|
+
// length -1 is the current-node
|
|
99
|
+
// length -2 is the parent-node
|
|
100
|
+
// root node is not printed and is always present so minimum path length is 2 (root + currentNode)
|
|
101
|
+
|
|
70
102
|
const directParentNode = firstExistingItemPath[firstExistingItemPath.length - 2];
|
|
71
103
|
return directParentNode;
|
|
72
104
|
};
|
|
73
|
-
const getNodeMatchesSearchQuery = (node
|
|
105
|
+
const getNodeMatchesSearchQuery = function (node) {
|
|
106
|
+
let searchQuery = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
|
|
74
107
|
const standardizedName = standardizeSearchQueryString(node.model.name);
|
|
75
108
|
const standardizedSearchQuery = standardizeSearchQueryString(searchQuery);
|
|
76
109
|
return standardizedName.includes(standardizedSearchQuery);
|
|
77
110
|
};
|
|
78
|
-
const getChildrenMatchesSearchQuery = (parentNode
|
|
111
|
+
const getChildrenMatchesSearchQuery = function (parentNode) {
|
|
112
|
+
let searchQuery = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
|
|
79
113
|
let anyChildMatch = false;
|
|
80
|
-
walkAllNodeChildren(parentNode,
|
|
81
|
-
if (getNodeMatchesSearchQuery(node, searchQuery))
|
|
82
|
-
anyChildMatch = true;
|
|
114
|
+
walkAllNodeChildren(parentNode, node => {
|
|
115
|
+
if (getNodeMatchesSearchQuery(node, searchQuery)) anyChildMatch = true;
|
|
83
116
|
});
|
|
84
117
|
return anyChildMatch;
|
|
85
118
|
};
|
|
86
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Mutate in place a node from tree-model normalizing object properties like "isGroup" even if user didn't specify it explicitly,
|
|
121
|
+
* after execution the node will have "nodePath" "treeDepth" "nodeItemRef" "isGroup" "isExpanded"
|
|
122
|
+
* (optionally, based on the provided arguments) "matchesSearchQuery" "childrenMatchesSearchQuery" "isChecked"
|
|
123
|
+
*
|
|
124
|
+
* @param {Object} node - node (based on 'tree-model' lib) that you wish to mutate with extra props
|
|
125
|
+
* @param {string} [searchQuery=''] - optional string used to parse "matchesSearchQuery"/"childrenMatchesSearchQuery" properties
|
|
126
|
+
* @param {Object} [selection=null] - optional selection hashmap used to parse "isChecked" properties
|
|
127
|
+
* @param {Object} [expanded=null] - optional expanded hashmap used to parse "isExpanded" properties
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
const enrichNodeModelInPlace = function (node) {
|
|
131
|
+
var _node$model, _node$model$children;
|
|
132
|
+
|
|
133
|
+
let searchQuery = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
|
|
134
|
+
let selection = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
|
|
135
|
+
let expanded = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
|
|
87
136
|
const path = node.getPath();
|
|
88
137
|
const depth = path.length - 1;
|
|
89
138
|
node.model.nodePath = path;
|
|
90
139
|
node.model.treeDepth = depth;
|
|
140
|
+
|
|
91
141
|
if (!node.model.nodeItemRef) {
|
|
92
|
-
node.model.nodeItemRef = createRef();
|
|
93
|
-
}
|
|
94
|
-
|
|
142
|
+
node.model.nodeItemRef = /*#__PURE__*/createRef();
|
|
143
|
+
} // if a node has children but was not marked as isGroup, force-mark as group
|
|
144
|
+
// this is useful to avoid having to always check both the flag and the children.length...
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
if (typeof node.model.isGroup !== 'boolean' && ((_node$model = node.model) === null || _node$model === void 0 ? void 0 : (_node$model$children = _node$model.children) === null || _node$model$children === void 0 ? void 0 : _node$model$children.length) > 0) {
|
|
95
148
|
node.model.isGroup = true;
|
|
96
149
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
else if (typeof node.model.isExpanded !== "boolean") {
|
|
150
|
+
|
|
151
|
+
if (node.model.isGroup && node.model.id !== '__ds_tree_root') {
|
|
152
|
+
if (expanded) node.model.isExpanded = !!expanded[node.model.id];else if (typeof node.model.isExpanded !== 'boolean') {
|
|
101
153
|
node.model.isExpanded = false;
|
|
102
154
|
}
|
|
103
155
|
}
|
|
156
|
+
|
|
104
157
|
node.model.matchesSearchQuery = true;
|
|
105
158
|
node.model.childrenMatchesSearchQuery = false;
|
|
106
159
|
const partiallyEnrichedNode = node;
|
|
160
|
+
|
|
107
161
|
if (searchQuery) {
|
|
108
162
|
partiallyEnrichedNode.model.matchesSearchQuery = getNodeMatchesSearchQuery(partiallyEnrichedNode, searchQuery);
|
|
163
|
+
|
|
109
164
|
if (partiallyEnrichedNode.model.isGroup === true) {
|
|
110
165
|
partiallyEnrichedNode.model.childrenMatchesSearchQuery = getChildrenMatchesSearchQuery(partiallyEnrichedNode, searchQuery);
|
|
111
|
-
if (partiallyEnrichedNode.model.childrenMatchesSearchQuery)
|
|
112
|
-
partiallyEnrichedNode.model.isExpanded = true;
|
|
166
|
+
if (partiallyEnrichedNode.model.childrenMatchesSearchQuery) partiallyEnrichedNode.model.isExpanded = true;
|
|
113
167
|
}
|
|
114
168
|
}
|
|
169
|
+
|
|
115
170
|
if (selection && selection[partiallyEnrichedNode.model.id]) {
|
|
116
171
|
partiallyEnrichedNode.model.isChecked = selection[partiallyEnrichedNode.model.id];
|
|
117
172
|
}
|
|
118
173
|
};
|
|
119
|
-
const focusItem =
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
cloneNode,
|
|
124
|
-
enrichNodeModelInPlace,
|
|
125
|
-
focusItem,
|
|
126
|
-
getChildrenMatchesSearchQuery,
|
|
127
|
-
getItemsParentNode,
|
|
128
|
-
getNodeById,
|
|
129
|
-
getNodeMatchesSearchQuery,
|
|
130
|
-
itemsShareSameParent,
|
|
131
|
-
walkAllNodeChildren,
|
|
132
|
-
walkParents,
|
|
133
|
-
walkVisibles
|
|
174
|
+
const focusItem = item => {
|
|
175
|
+
var _item$nodeItemRef, _item$nodeItemRef$cur;
|
|
176
|
+
|
|
177
|
+
item === null || item === void 0 ? void 0 : (_item$nodeItemRef = item.nodeItemRef) === null || _item$nodeItemRef === void 0 ? void 0 : (_item$nodeItemRef$cur = _item$nodeItemRef.current) === null || _item$nodeItemRef$cur === void 0 ? void 0 : _item$nodeItemRef$cur.focus();
|
|
134
178
|
};
|
|
135
|
-
|
|
179
|
+
|
|
180
|
+
export { cloneNode, enrichNodeModelInPlace, focusItem, getChildrenMatchesSearchQuery, getItemsParentNode, getNodeById, getNodeMatchesSearchQuery, itemsShareSameParent, walkAllNodeChildren, walkParents, walkVisibles };
|
|
@@ -1,13 +1,22 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
1
|
+
import 'core-js/modules/esnext.async-iterator.constructor.js';
|
|
2
|
+
import 'core-js/modules/esnext.async-iterator.drop.js';
|
|
3
|
+
import 'core-js/modules/esnext.iterator.constructor.js';
|
|
4
|
+
import 'core-js/modules/esnext.iterator.drop.js';
|
|
5
|
+
import 'core-js/modules/web.dom-collections.iterator.js';
|
|
6
|
+
import { useContext, useCallback } from 'react';
|
|
7
|
+
import { cloneDeep } from 'lodash';
|
|
8
|
+
import TreeViewContext, { defaultRelativeMouseCoord } from '../TreeViewContext.js';
|
|
9
|
+
import { getNodeById, focusItem } from './tree-helpers.js';
|
|
10
|
+
import { inferKeyboardKinshipDrop, inferHoverItemKinshipDrop, isDropValid } from './dnd-helpers.js';
|
|
11
|
+
|
|
7
12
|
const useDnDHelpers = () => {
|
|
8
13
|
const ctx = useContext(TreeViewContext);
|
|
9
14
|
const {
|
|
10
|
-
props: {
|
|
15
|
+
props: {
|
|
16
|
+
data,
|
|
17
|
+
onOrderChange,
|
|
18
|
+
restrictDragAndDrop
|
|
19
|
+
},
|
|
11
20
|
relativeMouseCord,
|
|
12
21
|
setRelativeMouseCord,
|
|
13
22
|
visibleItems,
|
|
@@ -22,19 +31,36 @@ const useDnDHelpers = () => {
|
|
|
22
31
|
treeRoot,
|
|
23
32
|
draggedItem
|
|
24
33
|
} = ctx;
|
|
25
|
-
const onSortEnd = useCallback(
|
|
26
|
-
|
|
34
|
+
const onSortEnd = useCallback(_ref => {
|
|
35
|
+
let {
|
|
36
|
+
oldIndex,
|
|
37
|
+
newIndex,
|
|
38
|
+
isKeySorting
|
|
39
|
+
} = _ref;
|
|
40
|
+
const {
|
|
41
|
+
isBefore,
|
|
42
|
+
isAfter,
|
|
43
|
+
item: overItem,
|
|
44
|
+
isValid
|
|
45
|
+
} = relativeMouseCord;
|
|
46
|
+
|
|
27
47
|
if (draggedItem && tree && treeRoot && overItem) {
|
|
28
|
-
let newItems = cloneDeep(data);
|
|
48
|
+
let newItems = cloneDeep(data); // if dropping in same position do nothing
|
|
49
|
+
// if the drop is not allowed do nothing
|
|
50
|
+
|
|
29
51
|
if (oldIndex === newIndex || !isValid) {
|
|
52
|
+
// onOrderChange(newItems, data);
|
|
30
53
|
setIsDragging(false);
|
|
31
54
|
setDraggedItem(null);
|
|
32
55
|
triggerTreeRerender();
|
|
33
56
|
return;
|
|
34
|
-
}
|
|
35
|
-
|
|
57
|
+
} // if we are moving from topToBottom the offset changes
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
const movementDirection = newIndex > oldIndex ? 'topToBottom' : 'bottomToTop';
|
|
36
61
|
let newNestedIndex;
|
|
37
62
|
let newParentNode;
|
|
63
|
+
|
|
38
64
|
if (isKeySorting) {
|
|
39
65
|
const kinship = inferKeyboardKinshipDrop({
|
|
40
66
|
items: visibleItems,
|
|
@@ -53,76 +79,94 @@ const useDnDHelpers = () => {
|
|
|
53
79
|
newNestedIndex = kinship.newNestedIndex;
|
|
54
80
|
newParentNode = kinship.newParentNode;
|
|
55
81
|
}
|
|
82
|
+
|
|
56
83
|
const newMovedItemNode = tree.parse(draggedItem.node.model);
|
|
57
84
|
getNodeById(treeRoot, draggedItem.id).drop();
|
|
58
|
-
|
|
85
|
+
|
|
86
|
+
if (newParentNode && typeof newNestedIndex === 'number') {
|
|
59
87
|
newParentNode.addChildAtIndex(newMovedItemNode, newNestedIndex);
|
|
88
|
+
|
|
60
89
|
if (newParentNode.isRoot()) {
|
|
61
90
|
newItems = [...newParentNode.model.children];
|
|
62
91
|
} else {
|
|
63
92
|
newItems = [...treeRoot.model.children];
|
|
64
93
|
}
|
|
65
94
|
}
|
|
95
|
+
|
|
66
96
|
onOrderChange(newItems, data, draggedItem);
|
|
67
97
|
setIsDragging(false);
|
|
68
98
|
setDraggedItem(null);
|
|
69
99
|
triggerTreeRerender();
|
|
70
100
|
}
|
|
71
|
-
}, [
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const { index, isKeySorting } = beforeStartArgs;
|
|
101
|
+
}, [data, draggedItem, relativeMouseCord, visibleItems, tree, treeRoot, onOrderChange, triggerTreeRerender, setIsDragging, setDraggedItem]);
|
|
102
|
+
const onSortStart = useCallback(() => {}, // ({ node, index, collection, isKeySorting }, event) => {
|
|
103
|
+
// console.log('node :>> ', node);
|
|
104
|
+
// console.log('isKeySorting :>> ', isKeySorting);
|
|
105
|
+
// console.log('event :>> ', event);
|
|
106
|
+
// const item = collection?.[index] || visibleItems[index];
|
|
107
|
+
// setIsDragging(true);
|
|
108
|
+
// setDraggedItem(item);
|
|
109
|
+
// },
|
|
110
|
+
[]);
|
|
111
|
+
const updateBeforeSortStart = useCallback(beforeStartArgs => new Promise(resolve => {
|
|
112
|
+
const {
|
|
113
|
+
index,
|
|
114
|
+
isKeySorting
|
|
115
|
+
} = beforeStartArgs;
|
|
87
116
|
const item = visibleItems[index];
|
|
88
|
-
const {
|
|
117
|
+
const {
|
|
118
|
+
isExpanded
|
|
119
|
+
} = item.node.model;
|
|
120
|
+
|
|
89
121
|
if (isExpanded) {
|
|
90
122
|
item.node.model.isExpanded = false;
|
|
91
123
|
triggerTreeRerender();
|
|
92
124
|
}
|
|
125
|
+
|
|
93
126
|
setRelativeMouseCord(defaultRelativeMouseCoord);
|
|
94
127
|
setIsKeyboardDragging(isKeySorting);
|
|
95
128
|
setIsDragging(true);
|
|
96
129
|
setDraggedItem(item);
|
|
97
130
|
focusItem(null);
|
|
98
131
|
setFocusedItem(null);
|
|
99
|
-
if (document.activeElement && typeof document.activeElement.blur ===
|
|
100
|
-
document.activeElement.blur();
|
|
132
|
+
if (document.activeElement && typeof document.activeElement.blur === 'function') document.activeElement.blur();
|
|
101
133
|
resolve(true);
|
|
102
|
-
}), [
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
134
|
+
}), [visibleItems, setRelativeMouseCord, setIsKeyboardDragging, setIsDragging, setDraggedItem, setFocusedItem, triggerTreeRerender]); // tracks mouse coords relative to an element to check if the drop happens
|
|
135
|
+
// at the top/center/bottom of an element to choose where to move the element
|
|
136
|
+
// requested in the specs
|
|
137
|
+
|
|
138
|
+
const onMouseDragOverItem = useCallback(_ref2 => {
|
|
139
|
+
let {
|
|
140
|
+
event,
|
|
141
|
+
item,
|
|
142
|
+
itemIndex,
|
|
143
|
+
setIsDraggingOverThis,
|
|
144
|
+
openFolderOnHoverTimeout
|
|
145
|
+
} = _ref2;
|
|
146
|
+
const {
|
|
147
|
+
node
|
|
148
|
+
} = item;
|
|
149
|
+
const {
|
|
150
|
+
nodeItemRef
|
|
151
|
+
} = node.model;
|
|
152
|
+
|
|
120
153
|
if (isDragging && !isKeyboardDragging && draggedItem) {
|
|
121
|
-
|
|
154
|
+
var _nodeItemRef$current;
|
|
155
|
+
|
|
156
|
+
const rect = nodeItemRef === null || nodeItemRef === void 0 ? void 0 : (_nodeItemRef$current = nodeItemRef.current) === null || _nodeItemRef$current === void 0 ? void 0 : _nodeItemRef$current.getBoundingClientRect();
|
|
157
|
+
|
|
122
158
|
if (rect) {
|
|
123
|
-
const x = event.clientX - rect.left;
|
|
124
|
-
|
|
125
|
-
const
|
|
159
|
+
const x = event.clientX - rect.left; // x position within the element.
|
|
160
|
+
|
|
161
|
+
const y = event.clientY - rect.top; // y position within the element.
|
|
162
|
+
// by spec we need to track where the drop will happens
|
|
163
|
+
// if drop happens on top 25% drop before
|
|
164
|
+
// if drop happens on bottom of 25% drop after
|
|
165
|
+
// if drop happens in the middle 50% either invalid or drop into children
|
|
166
|
+
|
|
167
|
+
const {
|
|
168
|
+
height: elementHeight
|
|
169
|
+
} = rect;
|
|
126
170
|
const dropBeforeMaxY = elementHeight * 0.25;
|
|
127
171
|
const dropAfterMinY = elementHeight - elementHeight * 0.25;
|
|
128
172
|
const isBefore = y < dropBeforeMaxY;
|
|
@@ -145,12 +189,16 @@ const useDnDHelpers = () => {
|
|
|
145
189
|
relativeElementIndex: itemIndex
|
|
146
190
|
});
|
|
147
191
|
setIsDraggingOverThis(true);
|
|
148
|
-
|
|
192
|
+
|
|
193
|
+
if (!(openFolderOnHoverTimeout !== null && openFolderOnHoverTimeout !== void 0 && openFolderOnHoverTimeout.current) && // only set the interval if it wasn't set already once
|
|
194
|
+
(draggedItem === null || draggedItem === void 0 ? void 0 : draggedItem.id) !== (item === null || item === void 0 ? void 0 : item.id) && ( // don't open ghost element
|
|
195
|
+
item.isGroup || item.children.length > 0) && // only open groups
|
|
196
|
+
!restrictDragAndDrop) {
|
|
149
197
|
openFolderOnHoverTimeout.current = setTimeout(() => {
|
|
150
198
|
item.node.model.isExpanded = true;
|
|
151
199
|
openFolderOnHoverTimeout.current = null;
|
|
152
200
|
triggerTreeRerender();
|
|
153
|
-
},
|
|
201
|
+
}, 1000);
|
|
154
202
|
}
|
|
155
203
|
}
|
|
156
204
|
} else {
|
|
@@ -164,7 +212,5 @@ const useDnDHelpers = () => {
|
|
|
164
212
|
onMouseDragOverItem
|
|
165
213
|
};
|
|
166
214
|
};
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
};
|
|
170
|
-
//# sourceMappingURL=useDnDHelpers.js.map
|
|
215
|
+
|
|
216
|
+
export { useDnDHelpers };
|