@elliemae/ds-treeview 2.2.0-next.6 → 2.2.1

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.
Files changed (61) hide show
  1. package/cjs/TreeView.js +6 -2
  2. package/cjs/TreeViewContext.js +8 -2
  3. package/cjs/config/useTreeview.js +13 -3
  4. package/cjs/index.js +1 -0
  5. package/cjs/parts/TreeItem.js +68 -43
  6. package/cjs/parts/TreeList.js +17 -15
  7. package/cjs/plugins/dnd/TreeDndPlugin.js +37 -0
  8. package/cjs/plugins/dnd/index.js +1 -0
  9. package/cjs/plugins/index.js +1 -0
  10. package/cjs/react-desc-prop-types.js +0 -1
  11. package/cjs/utils/dnd-helpers.js +140 -0
  12. package/cjs/utils/keyboard-helpers.js +5 -6
  13. package/cjs/utils/tree-helpers.js +2 -28
  14. package/cjs/utils/useDnDHelpers.js +220 -0
  15. package/cjs/utils/useTree.js +2 -4
  16. package/esm/TreeView.js +6 -2
  17. package/esm/TreeViewContext.js +8 -2
  18. package/esm/config/useTreeview.js +14 -4
  19. package/esm/index.js +1 -1
  20. package/esm/parts/TreeItem.js +67 -42
  21. package/esm/parts/TreeList.js +17 -16
  22. package/esm/plugins/dnd/TreeDndPlugin.js +33 -1
  23. package/esm/plugins/dnd/index.js +1 -1
  24. package/esm/plugins/index.js +1 -1
  25. package/esm/react-desc-prop-types.js +0 -1
  26. package/esm/utils/dnd-helpers.js +132 -0
  27. package/esm/utils/keyboard-helpers.js +5 -6
  28. package/esm/utils/tree-helpers.js +3 -28
  29. package/esm/utils/useDnDHelpers.js +216 -0
  30. package/esm/utils/useTree.js +3 -5
  31. package/package.json +19 -35
  32. package/types/TreeView.d.ts +1 -1
  33. package/types/parts/TreeItem.d.ts +11 -4
  34. package/types/parts/TreeList.d.ts +4 -0
  35. package/types/plugins/dnd/TreeDndPlugin.d.ts +2 -0
  36. package/types/react-desc-prop-types.d.ts +3 -17
  37. package/types/sharedTypes.d.ts +8 -1
  38. package/types/utils/dnd-helpers.d.ts +39 -0
  39. package/types/utils/keyboard-helpers.d.ts +1 -2
  40. package/types/utils/refs-helpers.d.ts +1 -1
  41. package/types/utils/tree-helpers.d.ts +1 -4
  42. package/types/utils/useDnDHelpers.d.ts +26 -0
  43. package/types/utils/useTree.d.ts +0 -1
  44. package/cjs/hoc/DnDTreeContext.js +0 -18
  45. package/cjs/hoc/SortableItemContext.js +0 -21
  46. package/cjs/hoc/WithConditionalDnDContext.js +0 -138
  47. package/cjs/hoc/WithDnDSortableItemContext.js +0 -70
  48. package/cjs/parts/DnDHandle.js +0 -46
  49. package/cjs/parts/DropIndicator.js +0 -75
  50. package/esm/hoc/DnDTreeContext.js +0 -14
  51. package/esm/hoc/SortableItemContext.js +0 -17
  52. package/esm/hoc/WithConditionalDnDContext.js +0 -128
  53. package/esm/hoc/WithDnDSortableItemContext.js +0 -61
  54. package/esm/parts/DnDHandle.js +0 -38
  55. package/esm/parts/DropIndicator.js +0 -68
  56. package/types/hoc/DnDTreeContext.d.ts +0 -14
  57. package/types/hoc/SortableItemContext.d.ts +0 -19
  58. package/types/hoc/WithConditionalDnDContext.d.ts +0 -4
  59. package/types/hoc/WithDnDSortableItemContext.d.ts +0 -4
  60. package/types/parts/DnDHandle.d.ts +0 -6
  61. package/types/parts/DropIndicator.d.ts +0 -10
@@ -8,13 +8,12 @@ import 'core-js/modules/esnext.iterator.filter.js';
8
8
  import 'core-js/modules/esnext.async-iterator.for-each.js';
9
9
  import 'core-js/modules/esnext.iterator.for-each.js';
10
10
  import { useContext } from 'react';
11
+ import { SortableContainer } from '@elliemae/react-sortable-hoc';
11
12
  import { aggregatedClasses } from '@elliemae/ds-classnames';
12
13
  import { DSCircularProgressIndicator } from '@elliemae/ds-circular-progress-indicator';
13
14
  import TreeViewContext from '../TreeViewContext.js';
14
15
  import { treeListBlockName, DSTreeViewPrefix } from '../config/cssClassesConstants.js';
15
- import TreeItem from './TreeItem.js';
16
- import { withConditionalDnDRowContext } from '../hoc/WithConditionalDnDContext.js';
17
- import { DnDTreeContext } from '../hoc/DnDTreeContext.js';
16
+ import { DragAndDropTreeItem, TreeItem } from './TreeItem.js';
18
17
  import { jsxs, jsx } from 'react/jsx-runtime';
19
18
 
20
19
  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; }
@@ -39,13 +38,16 @@ const TreeListWrapper = aggregatedClasses('ul', {
39
38
  });
40
39
  const compactRowClass = "".concat(DSTreeViewPrefix, "-tv-row-size-compact");
41
40
  const normaRowClass = "".concat(DSTreeViewPrefix, "-tv-row-size-normal");
42
-
43
- const TreeListComp = () => {
41
+ const TreeList = props => {
42
+ const {
43
+ onMouseDragOverItem
44
+ } = props;
44
45
  const ctx = useContext(TreeViewContext);
45
46
  const {
46
47
  virtualListRef,
47
48
  virtualListHelpers,
48
- visibleItems: flattenedVisibleItems,
49
+ visibleItems,
50
+ withDragAndDrop,
49
51
  props: {
50
52
  width,
51
53
  height,
@@ -59,9 +61,6 @@ const TreeListComp = () => {
59
61
  virtualItems
60
62
  } = virtualListHelpers;
61
63
  const className = "".concat(rowSize === 'compact' ? "".concat(compactRowClass) : "".concat(normaRowClass));
62
- const {
63
- visibleItems
64
- } = useContext(DnDTreeContext);
65
64
  return /*#__PURE__*/jsxs(TreeListWrapper, {
66
65
  ref: virtualListRef,
67
66
  className: className,
@@ -96,17 +95,17 @@ const TreeListComp = () => {
96
95
  measureRef,
97
96
  start
98
97
  } = virtualItem;
99
- const item = (visibleItems || flattenedVisibleItems)[index];
100
- if (!item) return null;
98
+ const item = visibleItems[index];
101
99
  item.virtualIndex = index;
102
100
  const {
103
101
  id
104
102
  } = item;
105
103
  const style = {
106
104
  position: 'absolute',
107
- top: "".concat(start, "px"),
105
+ top: 0,
108
106
  left: 0,
109
- width: '100%'
107
+ width: '100%',
108
+ transform: "translateY(".concat(start, "px)")
110
109
  };
111
110
  const listItemProps = {
112
111
  key: "DS-TreeView-List-Item-".concat(id),
@@ -117,11 +116,13 @@ const TreeListComp = () => {
117
116
  item,
118
117
  itemWrapperStyle: style
119
118
  };
119
+ if (withDragAndDrop) return /*#__PURE__*/jsx(DragAndDropTreeItem, _objectSpread(_objectSpread({}, listItemProps), {}, {
120
+ onMouseDragOverItem: onMouseDragOverItem
121
+ }));
120
122
  return /*#__PURE__*/jsx(TreeItem, _objectSpread({}, listItemProps));
121
123
  })) : null]
122
124
  });
123
125
  };
126
+ const DragAndDropTreeList = SortableContainer(TreeList);
124
127
 
125
- const TreeList = withConditionalDnDRowContext(TreeListComp);
126
-
127
- export { TreeList, TreeListNoItems, TreeListWrapper, treeListNoItemsBn };
128
+ export { DragAndDropTreeList, TreeList, TreeListNoItems, TreeListWrapper, treeListNoItemsBn };
@@ -1,3 +1,35 @@
1
+ import _jsx from '@babel/runtime/helpers/esm/jsx';
2
+ import { useContext } from 'react';
3
+ import { DragAndDropTreeList } from '../../parts/TreeList.js';
4
+ import { useDnDHelpers } from '../../utils/useDnDHelpers.js';
5
+ import { keyCodes } from '../../utils/dnd-helpers.js';
6
+ import TreeViewContext from '../../TreeViewContext.js';
7
+
8
+ const TreeDnD = () => {
9
+ const {
10
+ updateBeforeSortStart,
11
+ onSortStart,
12
+ onMouseDragOverItem,
13
+ onSortEnd
14
+ } = useDnDHelpers();
15
+ const ctx = useContext(TreeViewContext);
16
+ const {
17
+ virtualListRef
18
+ } = ctx;
19
+ return /*#__PURE__*/_jsx(DragAndDropTreeList, {
20
+ useDragHandle: true,
21
+ transitionDuration: 0,
22
+ keyboardSortingTransitionDuration: 0,
23
+ hideSortableGhost: false,
24
+ disableAnimation: true,
25
+ updateBeforeSortStart: updateBeforeSortStart,
26
+ onSortStart: onSortStart,
27
+ onMouseDragOverItem: onMouseDragOverItem,
28
+ onSortEnd: onSortEnd,
29
+ getContainer: () => virtualListRef === null || virtualListRef === void 0 ? void 0 : virtualListRef.current,
30
+ keyCodes: keyCodes
31
+ });
32
+ };
1
33
  const TreeDndPlugin = 'tree-dnd';
2
34
 
3
- export { TreeDndPlugin };
35
+ export { TreeDnD, TreeDndPlugin };
@@ -1 +1 @@
1
- export { TreeDndPlugin } from './TreeDndPlugin.js';
1
+ export { TreeDnD, TreeDndPlugin } from './TreeDndPlugin.js';
@@ -1,4 +1,4 @@
1
- export { TreeDndPlugin } from './dnd/TreeDndPlugin.js';
1
+ export { TreeDnD, TreeDndPlugin } from './dnd/TreeDndPlugin.js';
2
2
  export { TreeRovingPlugin } from './roving/TreeRovingPlugin.js';
3
3
  export { SelectablePluginTree } from './selectable/SelectablePluginTree.js';
4
4
  export { TreeToolbarPlugin } from './toolbar/TreeToolbarPlugin.js';
@@ -26,7 +26,6 @@ const TreeViewPropTypes = {
26
26
  isMultiSelect: PropTypes.bool.description('whether the tree view is multi select or not').defaultValue(false),
27
27
  isSingleSelect: PropTypes.bool.description('wheter the tree view is single select or not').defaultValue(false),
28
28
  isLoading: PropTypes.bool.description('wheter the tree should show the loading state or not').defaultValue(false),
29
- getIsDropValid: PropTypes.func.description("Function that returns true if the drop is valid and false if it's not").defaultValue('() => true'),
30
29
  restrictDragAndDrop: PropTypes.bool.description('whether to restrict DnD functionality or not').defaultValue(false),
31
30
  showChildrenAmount: PropTypes.bool.description('whether to show the amount of children or not').defaultValue(false),
32
31
  sortable: PropTypes.bool.description('whether the sortable functionality is active or not').defaultValue(false),
@@ -0,0 +1,132 @@
1
+ import { getItemsParentNode, itemsShareSameParent } from './tree-helpers.js';
2
+
3
+ /* eslint-disable max-lines */
4
+ const keyCodes = {
5
+ lift: [32, 13],
6
+ drop: [32, 13],
7
+ cancel: [27],
8
+ up: [38, 37],
9
+ down: [40, 39]
10
+ };
11
+ const sameParentAsHoverItemDrop = _ref => {
12
+ let {
13
+ isBefore,
14
+ isAfter,
15
+ draggedItem,
16
+ overItem,
17
+ movementDirection
18
+ } = _ref;
19
+ const hoveredItemNodeNestedIndex = overItem.node.getIndex();
20
+ let newParentNode = getItemsParentNode([overItem], true);
21
+ const {
22
+ treeDepth: draggedItemTreeDepth
23
+ } = draggedItem;
24
+ const {
25
+ treeDepth: overItemTreeDepth
26
+ } = overItem;
27
+ const directionOffset = // we don't apply the offset for direction
28
+ // if moving from less nested to more nested
29
+ // or moving bottom to top
30
+ // the offset is required when moving elemnts down in their nest level
31
+ draggedItemTreeDepth <= overItemTreeDepth && movementDirection === 'topToBottom' ? -1 : 0;
32
+ let newNestedIndex;
33
+ if (isBefore) newNestedIndex = hoveredItemNodeNestedIndex + directionOffset;else if (isAfter) newNestedIndex = hoveredItemNodeNestedIndex + 1 + directionOffset;else {
34
+ newNestedIndex = overItem.children.length; // append as last child of the group
35
+
36
+ newParentNode = overItem.node;
37
+ }
38
+ if (newNestedIndex < 0) newNestedIndex = 0;
39
+ return {
40
+ newNestedIndex,
41
+ newParentNode
42
+ };
43
+ };
44
+ const inferHoverItemKinshipDrop = _ref2 => {
45
+ let {
46
+ isBefore,
47
+ isAfter,
48
+ draggedItem,
49
+ overItem,
50
+ movementDirection
51
+ } = _ref2;
52
+ const hoverItemModel = overItem.node.model;
53
+ const isGroupAndIsExpanded = hoverItemModel.isExpanded && hoverItemModel.children.length > 0;
54
+
55
+ if (isAfter && isGroupAndIsExpanded) {
56
+ return {
57
+ newNestedIndex: 0,
58
+ // append after the group, so basically as first child
59
+ newParentNode: overItem.node
60
+ };
61
+ }
62
+
63
+ if (isBefore || isAfter && !isGroupAndIsExpanded) {
64
+ return sameParentAsHoverItemDrop({
65
+ isBefore,
66
+ isAfter,
67
+ draggedItem,
68
+ overItem,
69
+ movementDirection
70
+ });
71
+ } // drop inside
72
+
73
+
74
+ return {
75
+ newNestedIndex: overItem.children.length,
76
+ // append as last child of the group
77
+ newParentNode: overItem.node
78
+ };
79
+ };
80
+ const isDropValid = _ref3 => {
81
+ let {
82
+ isBefore,
83
+ isAfter,
84
+ draggedItem,
85
+ overItem,
86
+ restrictDragAndDrop
87
+ } = _ref3;
88
+ const {
89
+ id: movedId
90
+ } = draggedItem;
91
+ const {
92
+ id: hoverId
93
+ } = overItem;
94
+ const isInside = !isBefore && !isAfter;
95
+ if (movedId === hoverId) return false;
96
+
97
+ if (isInside && !overItem.isGroup) {
98
+ return false; // we can't drop inside an item that isn't a group
99
+ }
100
+
101
+ if (restrictDragAndDrop) {
102
+ if (isInside) return false; // in this mode we can't drop inside another element
103
+
104
+ const sameParent = itemsShareSameParent([draggedItem, overItem]);
105
+ if (overItem.node.model.isExpanded && isAfter) return false;
106
+ if (!sameParent) return false;
107
+ }
108
+
109
+ return true;
110
+ };
111
+ const inferKeyboardKinshipDrop = _ref4 => {
112
+ let {
113
+ items,
114
+ newIndex
115
+ } = _ref4;
116
+ const kinship = {};
117
+ const itemBefore = items[newIndex];
118
+ const itemBeforeModel = itemBefore.node.model;
119
+ const isGroupAndIsExpanded = itemBeforeModel.isExpanded && itemBeforeModel.children.length > 0;
120
+
121
+ if (isGroupAndIsExpanded) {
122
+ kinship.newParentNode = itemBefore.node;
123
+ kinship.newNestedIndex = 0;
124
+ } else {
125
+ kinship.newParentNode = getItemsParentNode([itemBefore], true);
126
+ kinship.newNestedIndex = itemBefore.node.getIndex();
127
+ }
128
+
129
+ return kinship;
130
+ };
131
+
132
+ export { inferHoverItemKinshipDrop, inferKeyboardKinshipDrop, isDropValid, keyCodes, sameParentAsHoverItemDrop };
@@ -15,13 +15,14 @@ import { toggleItemExpand, toggleExpandAllHelper } from './group-expands-helpers
15
15
  // 36 home
16
16
  // 56 number 8
17
17
  // 106 (NumPad) *
18
- const useOnItemKeyDown = (item, draggableProps) => {
18
+ const useOnItemKeyDown = item => {
19
19
  const ctx = useContext(TreeViewContext);
20
20
  const {
21
21
  props: {
22
22
  onItemFocus
23
23
  },
24
24
  triggerTreeRerender,
25
+ isDragging,
25
26
  visibleItems,
26
27
  setFocusedItem,
27
28
  setSelectedItem,
@@ -50,12 +51,10 @@ const useOnItemKeyDown = (item, draggableProps) => {
50
51
  keyCode
51
52
  } = e;
52
53
 
53
- if (!(draggableProps && draggableProps.active)) {
54
+ if (!isDragging) {
54
55
  if (keyCode !== 9) e.preventDefault(); // allow tab/shift+tab
55
56
 
56
- if ((keyCode === 13 || keyCode === 32) && e.target.tagName === 'LI') {
57
- setSelectedItem(item);
58
- }
57
+ if (keyCode === 13 || keyCode === 32) setSelectedItem(item);
59
58
 
60
59
  if (keyCode === 37) {
61
60
  if (isGroup && isExpanded) {
@@ -143,7 +142,7 @@ const useOnItemKeyDown = (item, draggableProps) => {
143
142
  }
144
143
  }
145
144
  }
146
- }, [draggableProps, setSelectedItem, item, isGroup, isExpanded, triggerTreeRerender, updateUserExpandedState, scrollToIndex, setLatestToggledItem, visibleItems, setFocusedItem, onItemFocusCurry]);
145
+ }, [isDragging, setSelectedItem, item, isGroup, isExpanded, triggerTreeRerender, scrollToIndex, setLatestToggledItem, visibleItems, setFocusedItem, onItemFocusCurry, updateUserExpandedState]);
147
146
  return onItemKeyDown;
148
147
  };
149
148
  const useGlobalKeyboardListener = func => {
@@ -128,7 +128,7 @@ const getChildrenMatchesSearchQuery = function (parentNode) {
128
128
  */
129
129
 
130
130
  const enrichNodeModelInPlace = function (node) {
131
- var _node$model$children$, _node$model, _node$model$children;
131
+ var _node$model, _node$model$children;
132
132
 
133
133
  let searchQuery = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
134
134
  let selection = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
@@ -144,7 +144,7 @@ const enrichNodeModelInPlace = function (node) {
144
144
  // this is useful to avoid having to always check both the flag and the children.length...
145
145
 
146
146
 
147
- if (typeof node.model.isGroup !== 'boolean' && ((_node$model$children$ = (_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) !== null && _node$model$children$ !== void 0 ? _node$model$children$ : 0) > 0) {
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) {
148
148
  node.model.isGroup = true;
149
149
  }
150
150
 
@@ -176,30 +176,5 @@ const focusItem = item => {
176
176
 
177
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();
178
178
  };
179
- const flattenTreeForDnD = function (data) {
180
- let shouldDescend = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : () => true;
181
- const flattenedTree = [];
182
- let index = 0;
183
-
184
- const doit = function (node) {
185
- var _node$children$length, _node$children, _node$children2;
186
-
187
- let depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
188
- let parentId = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
189
- flattenedTree.push({
190
- uid: node.id.toString(),
191
- depth,
192
- realIndex: index,
193
- childrenCount: (_node$children$length = (_node$children = node.children) === null || _node$children === void 0 ? void 0 : _node$children.length) !== null && _node$children$length !== void 0 ? _node$children$length : 0,
194
- parentId: parentId !== null ? parentId.toString() : null,
195
- original: node
196
- });
197
- index += 1;
198
- if (shouldDescend(node)) (_node$children2 = node.children) === null || _node$children2 === void 0 ? void 0 : _node$children2.forEach(child => doit(child, depth + 1, node.id.toString()));
199
- };
200
-
201
- data.forEach(datum => doit(datum));
202
- return flattenedTree;
203
- };
204
179
 
205
- export { cloneNode, enrichNodeModelInPlace, flattenTreeForDnD, focusItem, getChildrenMatchesSearchQuery, getItemsParentNode, getNodeById, getNodeMatchesSearchQuery, itemsShareSameParent, walkAllNodeChildren, walkParents, walkVisibles };
180
+ export { cloneNode, enrichNodeModelInPlace, focusItem, getChildrenMatchesSearchQuery, getItemsParentNode, getNodeById, getNodeMatchesSearchQuery, itemsShareSameParent, walkAllNodeChildren, walkParents, walkVisibles };
@@ -0,0 +1,216 @@
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
+
12
+ const useDnDHelpers = () => {
13
+ const ctx = useContext(TreeViewContext);
14
+ const {
15
+ props: {
16
+ data,
17
+ onOrderChange,
18
+ restrictDragAndDrop
19
+ },
20
+ relativeMouseCord,
21
+ setRelativeMouseCord,
22
+ visibleItems,
23
+ isDragging,
24
+ setIsDragging,
25
+ isKeyboardDragging,
26
+ setIsKeyboardDragging,
27
+ setDraggedItem,
28
+ setFocusedItem,
29
+ triggerTreeRerender,
30
+ tree,
31
+ treeRoot,
32
+ draggedItem
33
+ } = ctx;
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
+
47
+ if (draggedItem && tree && treeRoot && overItem) {
48
+ let newItems = cloneDeep(data); // if dropping in same position do nothing
49
+ // if the drop is not allowed do nothing
50
+
51
+ if (oldIndex === newIndex || !isValid) {
52
+ // onOrderChange(newItems, data);
53
+ setIsDragging(false);
54
+ setDraggedItem(null);
55
+ triggerTreeRerender();
56
+ return;
57
+ } // if we are moving from topToBottom the offset changes
58
+
59
+
60
+ const movementDirection = newIndex > oldIndex ? 'topToBottom' : 'bottomToTop';
61
+ let newNestedIndex;
62
+ let newParentNode;
63
+
64
+ if (isKeySorting) {
65
+ const kinship = inferKeyboardKinshipDrop({
66
+ items: visibleItems,
67
+ newIndex
68
+ });
69
+ newNestedIndex = kinship.newNestedIndex;
70
+ newParentNode = kinship.newParentNode;
71
+ } else {
72
+ const kinship = inferHoverItemKinshipDrop({
73
+ isBefore,
74
+ isAfter,
75
+ overItem,
76
+ movementDirection,
77
+ draggedItem
78
+ });
79
+ newNestedIndex = kinship.newNestedIndex;
80
+ newParentNode = kinship.newParentNode;
81
+ }
82
+
83
+ const newMovedItemNode = tree.parse(draggedItem.node.model);
84
+ getNodeById(treeRoot, draggedItem.id).drop();
85
+
86
+ if (newParentNode && typeof newNestedIndex === 'number') {
87
+ newParentNode.addChildAtIndex(newMovedItemNode, newNestedIndex);
88
+
89
+ if (newParentNode.isRoot()) {
90
+ newItems = [...newParentNode.model.children];
91
+ } else {
92
+ newItems = [...treeRoot.model.children];
93
+ }
94
+ }
95
+
96
+ onOrderChange(newItems, data, draggedItem);
97
+ setIsDragging(false);
98
+ setDraggedItem(null);
99
+ triggerTreeRerender();
100
+ }
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;
116
+ const item = visibleItems[index];
117
+ const {
118
+ isExpanded
119
+ } = item.node.model;
120
+
121
+ if (isExpanded) {
122
+ item.node.model.isExpanded = false;
123
+ triggerTreeRerender();
124
+ }
125
+
126
+ setRelativeMouseCord(defaultRelativeMouseCoord);
127
+ setIsKeyboardDragging(isKeySorting);
128
+ setIsDragging(true);
129
+ setDraggedItem(item);
130
+ focusItem(null);
131
+ setFocusedItem(null);
132
+ if (document.activeElement && typeof document.activeElement.blur === 'function') document.activeElement.blur();
133
+ resolve(true);
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
+
153
+ if (isDragging && !isKeyboardDragging && draggedItem) {
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
+
158
+ if (rect) {
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;
170
+ const dropBeforeMaxY = elementHeight * 0.25;
171
+ const dropAfterMinY = elementHeight - elementHeight * 0.25;
172
+ const isBefore = y < dropBeforeMaxY;
173
+ const isAfter = y > dropAfterMinY;
174
+ const isValid = isDropValid({
175
+ isBefore,
176
+ isAfter,
177
+ draggedItem,
178
+ overItem: item,
179
+ restrictDragAndDrop
180
+ });
181
+ setRelativeMouseCord({
182
+ isBefore,
183
+ isAfter,
184
+ isValid,
185
+ item,
186
+ x,
187
+ y,
188
+ relativeElementDOMRect: rect,
189
+ relativeElementIndex: itemIndex
190
+ });
191
+ setIsDraggingOverThis(true);
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) {
197
+ openFolderOnHoverTimeout.current = setTimeout(() => {
198
+ item.node.model.isExpanded = true;
199
+ openFolderOnHoverTimeout.current = null;
200
+ triggerTreeRerender();
201
+ }, 1000);
202
+ }
203
+ }
204
+ } else {
205
+ setRelativeMouseCord(defaultRelativeMouseCoord);
206
+ }
207
+ }, [isDragging, isKeyboardDragging, draggedItem, restrictDragAndDrop, setRelativeMouseCord, triggerTreeRerender]);
208
+ return {
209
+ updateBeforeSortStart,
210
+ onSortStart,
211
+ onSortEnd,
212
+ onMouseDragOverItem
213
+ };
214
+ };
215
+
216
+ export { useDnDHelpers };
@@ -8,7 +8,7 @@ import 'core-js/modules/web.dom-collections.iterator.js';
8
8
  import { useMemo, useState, useEffect, useCallback } from 'react';
9
9
  import TreeModel from 'tree-model';
10
10
  import { cloneDeep } from 'lodash';
11
- import { enrichNodeModelInPlace, walkVisibles, flattenTreeForDnD } from './tree-helpers.js';
11
+ import { enrichNodeModelInPlace, walkVisibles } from './tree-helpers.js';
12
12
  import { updateExpandedState } from './group-expands-helpers.js';
13
13
 
14
14
  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; }
@@ -67,9 +67,9 @@ const useTree = (data, props, states) => {
67
67
  useEffect(() => {
68
68
  const parsedVisibleItems = [];
69
69
  const newExpandedHashMap = {};
70
- const shouldContinueWalking = true; // tree-model ask we return true if we want to continue walking
71
-
72
70
  treeRoot.walk(node => {
71
+ const shouldContinueWalking = true; // tree-model ask we return true if we want to continue walking
72
+
73
73
  enrichNodeModelInPlace(node, searchQuery, selection, expanded);
74
74
  if (node.model.id && node.model.isGroup && node.model.isExpanded) newExpandedHashMap[node.model.id] = true;
75
75
  return shouldContinueWalking;
@@ -84,10 +84,8 @@ const useTree = (data, props, states) => {
84
84
  setExpandedGroups(newExpandedHashMap); // eslint-disable-next-line react-hooks/exhaustive-deps
85
85
  }, [treeRoot, rerenderItems, searchQuery, highlightOnlyQuery, selection, expanded, setExpandedGroups // onVisibleItemsChange // evaluate potential performance hit?
86
86
  ]);
87
- const flattenedItems = useMemo(() => flattenTreeForDnD(data), [data]);
88
87
  return {
89
88
  visibleItems,
90
- flattenedItems,
91
89
  tree,
92
90
  treeRoot,
93
91
  rerenderItems,