@elliemae/ds-drag-and-drop 2.2.1 → 2.2.2-rc.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.
@@ -33,105 +33,109 @@ const RECT_DOWN = {
33
33
  const thresholdRatio = 0.2; // Percentage to be inside
34
34
 
35
35
  const insideThreshold = 0.7;
36
- const customCollisionDetection = (activeId, visibleItemsDictionary, setDropIndicatorPosition, maxDragAndDropLevel, lastPosition, setLastPosition) => _ref => {
37
- var _originalContainer$re;
38
-
39
- let {
40
- droppableContainers,
41
- collisionRect
42
- } = _ref;
43
- const originalContainer = droppableContainers.find(_ref2 => {
36
+ const customCollisionDetection = (activeId, visibleItemsDictionary, setDropIndicatorPosition, maxDragAndDropLevel, lastPosition, setLastPosition) => {
37
+ const func = _ref => {
38
+ var _originalContainer$re;
39
+
44
40
  let {
45
- id
46
- } = _ref2;
47
- return id === activeId;
48
- });
49
- const originalRect = originalContainer === null || originalContainer === void 0 ? void 0 : (_originalContainer$re = originalContainer.rect) === null || _originalContainer$re === void 0 ? void 0 : _originalContainer$re.current; // We first check if the item was moved up or down
50
- // This modifies how to search the matching colliding rect
51
-
52
- let isUp = lastPosition === 'up';
53
-
54
- if (originalRect) {
55
- isUp = originalRect.offsetTop > collisionRect.top;
56
- } // Threshold
57
-
58
-
59
- const threshold = collisionRect.height * thresholdRatio;
60
- let collidingContainer = null;
61
-
62
- if (isUp) {
63
- // Up -- We need to find the first rectangle downwards
64
- collidingContainer = droppableContainers.reduce((firstRectDown, container) => {
65
- const rect = container.rect.current;
66
-
67
- if (rect && firstRectDown.rect.current) {
68
- const {
69
- offsetTop: rectOffsetTop
70
- } = rect;
71
- const {
72
- offsetTop: firstRectDownOffsetTop
73
- } = firstRectDown.rect.current;
74
-
75
- if (rectOffsetTop + threshold > collisionRect.top && rectOffsetTop < firstRectDownOffsetTop) {
76
- return container;
77
- }
78
- }
79
-
80
- return firstRectDown;
81
- }, {
82
- id: DUMMY_ID,
83
- rect: {
84
- current: RECT_DOWN
85
- }
41
+ droppableContainers,
42
+ collisionRect
43
+ } = _ref;
44
+ const originalContainer = droppableContainers.find(_ref2 => {
45
+ let {
46
+ id
47
+ } = _ref2;
48
+ return id === activeId;
86
49
  });
87
- } else {
88
- // Down -- We need to find the first rectangle upwards
89
- collidingContainer = droppableContainers.reduce((firstRectUp, container) => {
90
- const rect = container.rect.current;
91
-
92
- if (rect && firstRectUp.rect.current) {
93
- const {
94
- offsetTop: rectOffsetTop
95
- } = rect;
96
- const {
97
- offsetTop: firstRectUpOffsetTop
98
- } = firstRectUp.rect.current;
99
-
100
- if (rectOffsetTop - threshold < collisionRect.top && rectOffsetTop > firstRectUpOffsetTop) {
101
- return container;
50
+ const originalRect = originalContainer === null || originalContainer === void 0 ? void 0 : (_originalContainer$re = originalContainer.rect) === null || _originalContainer$re === void 0 ? void 0 : _originalContainer$re.current; // We first check if the item was moved up or down
51
+ // This modifies how to search the matching colliding rect
52
+
53
+ let isUp = lastPosition === 'up';
54
+
55
+ if (originalRect) {
56
+ isUp = originalRect.offsetTop > collisionRect.top;
57
+ } // Threshold
58
+
59
+
60
+ const threshold = collisionRect.height * thresholdRatio;
61
+ let collidingContainer = null;
62
+
63
+ if (isUp) {
64
+ // Up -- We need to find the first rectangle downwards
65
+ collidingContainer = droppableContainers.reduce((firstRectDown, container) => {
66
+ const rect = container.rect.current;
67
+
68
+ if (rect && firstRectDown.rect.current) {
69
+ const {
70
+ offsetTop: rectOffsetTop
71
+ } = rect;
72
+ const {
73
+ offsetTop: firstRectDownOffsetTop
74
+ } = firstRectDown.rect.current;
75
+
76
+ if (rectOffsetTop + threshold > collisionRect.top && rectOffsetTop < firstRectDownOffsetTop) {
77
+ return container;
78
+ }
102
79
  }
103
- }
104
-
105
- return firstRectUp;
106
- }, {
107
- id: DUMMY_ID,
108
- rect: {
109
- current: RECT_UP
110
- }
111
- });
112
- } // If we didn't find a match, return null
113
80
 
81
+ return firstRectDown;
82
+ }, {
83
+ id: DUMMY_ID,
84
+ rect: {
85
+ current: RECT_DOWN
86
+ }
87
+ });
88
+ } else {
89
+ // Down -- We need to find the first rectangle upwards
90
+ collidingContainer = droppableContainers.reduce((firstRectUp, container) => {
91
+ const rect = container.rect.current;
92
+
93
+ if (rect && firstRectUp.rect.current) {
94
+ const {
95
+ offsetTop: rectOffsetTop
96
+ } = rect;
97
+ const {
98
+ offsetTop: firstRectUpOffsetTop
99
+ } = firstRectUp.rect.current;
100
+
101
+ if (rectOffsetTop - threshold < collisionRect.top && rectOffsetTop > firstRectUpOffsetTop) {
102
+ return container;
103
+ }
104
+ }
105
+
106
+ return firstRectUp;
107
+ }, {
108
+ id: DUMMY_ID,
109
+ rect: {
110
+ current: RECT_UP
111
+ }
112
+ });
113
+ } // If we didn't find a match, return null
114
+
115
+
116
+ if (collidingContainer.id === DUMMY_ID) {
117
+ return null;
118
+ }
114
119
 
115
- if (collidingContainer.id === DUMMY_ID) {
116
- return null;
117
- }
120
+ const collidingRect = collidingContainer.rect.current;
121
+ if (!collidingRect) return null; // Calculate the intersection interval
118
122
 
119
- const collidingRect = collidingContainer.rect.current;
120
- if (!collidingRect) return null; // Calculate the intersection interval
123
+ const [top, bottom] = [Math.max(collisionRect.top, collidingRect.offsetTop), Math.min(collisionRect.top + collisionRect.height, collidingRect.offsetTop + collidingRect.height)]; // Calculate the percentage of intersection
121
124
 
122
- const [top, bottom] = [Math.max(collisionRect.top, collidingRect.offsetTop), Math.min(collisionRect.bottom, collidingRect.offsetTop + collidingRect.height)]; // Calculate the percentage of intersection
125
+ const intersectionPercentage = Math.abs(bottom - top) / collidingRect.height;
123
126
 
124
- const intersectionPercentage = Math.abs(bottom - top) / collidingRect.height;
127
+ if (intersectionPercentage > insideThreshold && visibleItemsDictionary[collidingContainer.id].depth + 1 <= maxDragAndDropLevel && collidingContainer.id !== activeId) {
128
+ setDropIndicatorPosition(constants.DropIndicatorPosition.Inside);
129
+ } else {
130
+ setDropIndicatorPosition(isUp ? constants.DropIndicatorPosition.Before : constants.DropIndicatorPosition.After);
131
+ }
125
132
 
126
- if (intersectionPercentage > insideThreshold && visibleItemsDictionary[collidingContainer.id].depth + 1 <= maxDragAndDropLevel && collidingContainer.id !== activeId) {
127
- setDropIndicatorPosition(constants.DropIndicatorPosition.Inside);
128
- } else {
129
- setDropIndicatorPosition(isUp ? constants.DropIndicatorPosition.Before : constants.DropIndicatorPosition.After);
130
- }
133
+ if (isUp && lastPosition !== 'up') setLastPosition('up');else if (!isUp && lastPosition !== 'down') setLastPosition('down'); // Return the id of the match rectangle
131
134
 
132
- if (isUp && lastPosition !== 'up') setLastPosition('up');else if (!isUp && lastPosition !== 'down') setLastPosition('down'); // Return the id of the match rectangle
135
+ return collidingContainer.id;
136
+ };
133
137
 
134
- return collidingContainer.id;
138
+ return func;
135
139
  };
136
140
 
137
141
  exports.customCollisionDetection = customCollisionDetection;
@@ -22,7 +22,6 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
22
22
  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__default["default"](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; }
23
23
  const directions = [core.KeyboardCode.Down, core.KeyboardCode.Right, core.KeyboardCode.Up, core.KeyboardCode.Left];
24
24
  const horizontal = [core.KeyboardCode.Left, core.KeyboardCode.Right];
25
- [core.KeyboardCode.Up, core.KeyboardCode.Down];
26
25
 
27
26
  const getVerticalKeyboardCoordinates = _ref => {
28
27
  var _droppableContainers$, _droppableContainers$2;
@@ -17,7 +17,8 @@ const useTreeActionHandlers = _ref => {
17
17
  onReorder,
18
18
  flattenedItems,
19
19
  projected,
20
- dropIndicatorPosition
20
+ dropIndicatorPosition,
21
+ isDropValid
21
22
  } = _ref;
22
23
  const onDragStart = react.useCallback(e => {
23
24
  handlePreviewDragStart(e);
@@ -34,17 +35,15 @@ const useTreeActionHandlers = _ref => {
34
35
  active,
35
36
  over
36
37
  } = e;
37
- if (over === null) return;
38
+ if (over === null || !isDropValid) return;
38
39
  const activeIndex = flattenedItems.findIndex(item => item.uid === active.id);
39
40
  let considerExpanding = null;
40
41
  let overIndex = flattenedItems.findIndex(item => item.uid === over.id); // If drop indicator is inside, then put it last,
41
42
  // It will be reconstructed well later
42
43
 
43
44
  if (dropIndicatorPosition === constants.DropIndicatorPosition.Inside) {
44
- var _flattenedItems$overI, _flattenedItems$overI2;
45
-
46
45
  considerExpanding = over.id;
47
- overIndex = flattenedItems[overIndex].realIndex + ((_flattenedItems$overI = (_flattenedItems$overI2 = flattenedItems[overIndex].original.subRows) === null || _flattenedItems$overI2 === void 0 ? void 0 : _flattenedItems$overI2.length) !== null && _flattenedItems$overI !== void 0 ? _flattenedItems$overI : 0) + 1;
46
+ overIndex = flattenedItems[overIndex].realIndex + flattenedItems[overIndex].childrenCount + 1;
48
47
  } // If we are dropping the item in a new position, or new depth
49
48
 
50
49
 
@@ -59,7 +58,7 @@ const useTreeActionHandlers = _ref => {
59
58
  fromIndex: activeIndex
60
59
  }, considerExpanding || '');
61
60
  }
62
- }, [handlePreviewDragEnd, flattenedItems, projected, onReorder, dropIndicatorPosition]);
61
+ }, [handlePreviewDragEnd, isDropValid, flattenedItems, dropIndicatorPosition, projected, onReorder]);
63
62
  const onDragCancel = react.useCallback(e => {
64
63
  handlePreviewDragCancel(e);
65
64
  }, [handlePreviewDragCancel]);
@@ -13,7 +13,6 @@ require('core-js/modules/esnext.async-iterator.filter.js');
13
13
  require('core-js/modules/esnext.iterator.filter.js');
14
14
  var react = require('react');
15
15
  var core = require('@dnd-kit/core');
16
- var sortable = require('@dnd-kit/sortable');
17
16
  var useTreePreviewHandlers = require('./useTreePreviewHandlers.js');
18
17
  var getTreeKeyboardCoordinates = require('./getTreeKeyboardCoordinates.js');
19
18
  var utilities = require('./utilities.js');
@@ -31,25 +30,29 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
31
30
  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__default["default"](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; }
32
31
  // if second parameter is true, the space will be done on the horizontal axis
33
32
 
34
- const adjustTranslate = isHorizontalDnD => _ref => {
35
- let {
36
- transform
37
- } = _ref;
33
+ const adjustTranslate = isHorizontalDnD => {
34
+ const func = _ref => {
35
+ let {
36
+ transform
37
+ } = _ref;
38
38
 
39
- const newTransform = _objectSpread({}, transform);
39
+ const newTransform = _objectSpread({}, transform);
40
40
 
41
- if (isHorizontalDnD) {
42
- newTransform.x = transform.x + 25;
43
- } else {
44
- newTransform.x = transform.x + 15;
45
- }
41
+ if (isHorizontalDnD) {
42
+ newTransform.x = transform.x + 25;
43
+ } else {
44
+ newTransform.x = transform.x + 15;
45
+ }
46
46
 
47
- return newTransform;
47
+ return newTransform;
48
+ };
49
+
50
+ return func;
48
51
  };
49
52
 
50
53
  const measuring = {
51
54
  droppable: {
52
- strategy: core.MeasuringStrategy.BeforeDragging
55
+ strategy: core.MeasuringStrategy.Always
53
56
  }
54
57
  };
55
58
  const useTreeDndkitConfig = _ref2 => {
@@ -61,6 +64,7 @@ const useTreeDndkitConfig = _ref2 => {
61
64
  isHorizontalDnD = false,
62
65
  isExpandable = false,
63
66
  onReorder,
67
+ getIsDropValid = () => true,
64
68
  maxDragAndDropLevel
65
69
  } = _ref2;
66
70
  const [activeId, setActiveId] = react.useState('');
@@ -85,6 +89,10 @@ const useTreeDndkitConfig = _ref2 => {
85
89
  });
86
90
  return dictionary;
87
91
  }, [visibleItems]);
92
+ const isDropValid = react.useMemo(() => {
93
+ if (!activeId || !overId) return true;
94
+ return getIsDropValid(visibleItemsDictionary[activeId], visibleItemsDictionary[overId], ['none', 'before', 'after', 'inside'][dropIndicatorPosition]);
95
+ }, [getIsDropValid, visibleItemsDictionary, activeId, overId, dropIndicatorPosition]);
88
96
  const modifiers = react.useMemo(() => [adjustTranslate(isHorizontalDnD)], [isHorizontalDnD]);
89
97
  const sensorContext = react.useRef({
90
98
  items: visibleItems,
@@ -113,7 +121,8 @@ const useTreeDndkitConfig = _ref2 => {
113
121
  onReorder,
114
122
  projected,
115
123
  flattenedItems,
116
- dropIndicatorPosition
124
+ dropIndicatorPosition,
125
+ isDropValid
117
126
  }));
118
127
  const announcements = useTreeAnnouncements.useTreeAnnouncements(visibleItemsDictionary, dropIndicatorPosition);
119
128
  const dndContextProps = react.useMemo(() => _objectSpread({
@@ -125,11 +134,12 @@ const useTreeDndkitConfig = _ref2 => {
125
134
  }, dragActionHandlers), [announcements, modifiers, sensors, dragActionHandlers, visibleItemsDictionary, setDropIndicatorPosition, activeId, maxDragAndDropLevel, lastPosition, setLastPosition]);
126
135
  const sortableContextProps = react.useMemo(() => ({
127
136
  items: sortedIds,
128
- strategy: isHorizontalDnD ? sortable.horizontalListSortingStrategy : sortable.verticalListSortingStrategy
129
- }), [sortedIds, isHorizontalDnD]);
137
+ strategy: () => null
138
+ }), [sortedIds]);
130
139
  return {
131
140
  dndContextProps,
132
141
  sortableContextProps,
142
+ isDropValid,
133
143
  activeId,
134
144
  activeIndex: (_visibleItemsDictiona = (_visibleItemsDictiona2 = visibleItemsDictionary[activeId]) === null || _visibleItemsDictiona2 === void 0 ? void 0 : _visibleItemsDictiona2.realIndex) !== null && _visibleItemsDictiona !== void 0 ? _visibleItemsDictiona : -1,
135
145
  overId,
@@ -29,105 +29,109 @@ const RECT_DOWN = {
29
29
  const thresholdRatio = 0.2; // Percentage to be inside
30
30
 
31
31
  const insideThreshold = 0.7;
32
- const customCollisionDetection = (activeId, visibleItemsDictionary, setDropIndicatorPosition, maxDragAndDropLevel, lastPosition, setLastPosition) => _ref => {
33
- var _originalContainer$re;
34
-
35
- let {
36
- droppableContainers,
37
- collisionRect
38
- } = _ref;
39
- const originalContainer = droppableContainers.find(_ref2 => {
32
+ const customCollisionDetection = (activeId, visibleItemsDictionary, setDropIndicatorPosition, maxDragAndDropLevel, lastPosition, setLastPosition) => {
33
+ const func = _ref => {
34
+ var _originalContainer$re;
35
+
40
36
  let {
41
- id
42
- } = _ref2;
43
- return id === activeId;
44
- });
45
- const originalRect = originalContainer === null || originalContainer === void 0 ? void 0 : (_originalContainer$re = originalContainer.rect) === null || _originalContainer$re === void 0 ? void 0 : _originalContainer$re.current; // We first check if the item was moved up or down
46
- // This modifies how to search the matching colliding rect
47
-
48
- let isUp = lastPosition === 'up';
49
-
50
- if (originalRect) {
51
- isUp = originalRect.offsetTop > collisionRect.top;
52
- } // Threshold
53
-
54
-
55
- const threshold = collisionRect.height * thresholdRatio;
56
- let collidingContainer = null;
57
-
58
- if (isUp) {
59
- // Up -- We need to find the first rectangle downwards
60
- collidingContainer = droppableContainers.reduce((firstRectDown, container) => {
61
- const rect = container.rect.current;
62
-
63
- if (rect && firstRectDown.rect.current) {
64
- const {
65
- offsetTop: rectOffsetTop
66
- } = rect;
67
- const {
68
- offsetTop: firstRectDownOffsetTop
69
- } = firstRectDown.rect.current;
70
-
71
- if (rectOffsetTop + threshold > collisionRect.top && rectOffsetTop < firstRectDownOffsetTop) {
72
- return container;
73
- }
74
- }
75
-
76
- return firstRectDown;
77
- }, {
78
- id: DUMMY_ID,
79
- rect: {
80
- current: RECT_DOWN
81
- }
37
+ droppableContainers,
38
+ collisionRect
39
+ } = _ref;
40
+ const originalContainer = droppableContainers.find(_ref2 => {
41
+ let {
42
+ id
43
+ } = _ref2;
44
+ return id === activeId;
82
45
  });
83
- } else {
84
- // Down -- We need to find the first rectangle upwards
85
- collidingContainer = droppableContainers.reduce((firstRectUp, container) => {
86
- const rect = container.rect.current;
87
-
88
- if (rect && firstRectUp.rect.current) {
89
- const {
90
- offsetTop: rectOffsetTop
91
- } = rect;
92
- const {
93
- offsetTop: firstRectUpOffsetTop
94
- } = firstRectUp.rect.current;
95
-
96
- if (rectOffsetTop - threshold < collisionRect.top && rectOffsetTop > firstRectUpOffsetTop) {
97
- return container;
46
+ const originalRect = originalContainer === null || originalContainer === void 0 ? void 0 : (_originalContainer$re = originalContainer.rect) === null || _originalContainer$re === void 0 ? void 0 : _originalContainer$re.current; // We first check if the item was moved up or down
47
+ // This modifies how to search the matching colliding rect
48
+
49
+ let isUp = lastPosition === 'up';
50
+
51
+ if (originalRect) {
52
+ isUp = originalRect.offsetTop > collisionRect.top;
53
+ } // Threshold
54
+
55
+
56
+ const threshold = collisionRect.height * thresholdRatio;
57
+ let collidingContainer = null;
58
+
59
+ if (isUp) {
60
+ // Up -- We need to find the first rectangle downwards
61
+ collidingContainer = droppableContainers.reduce((firstRectDown, container) => {
62
+ const rect = container.rect.current;
63
+
64
+ if (rect && firstRectDown.rect.current) {
65
+ const {
66
+ offsetTop: rectOffsetTop
67
+ } = rect;
68
+ const {
69
+ offsetTop: firstRectDownOffsetTop
70
+ } = firstRectDown.rect.current;
71
+
72
+ if (rectOffsetTop + threshold > collisionRect.top && rectOffsetTop < firstRectDownOffsetTop) {
73
+ return container;
74
+ }
98
75
  }
99
- }
100
-
101
- return firstRectUp;
102
- }, {
103
- id: DUMMY_ID,
104
- rect: {
105
- current: RECT_UP
106
- }
107
- });
108
- } // If we didn't find a match, return null
109
76
 
77
+ return firstRectDown;
78
+ }, {
79
+ id: DUMMY_ID,
80
+ rect: {
81
+ current: RECT_DOWN
82
+ }
83
+ });
84
+ } else {
85
+ // Down -- We need to find the first rectangle upwards
86
+ collidingContainer = droppableContainers.reduce((firstRectUp, container) => {
87
+ const rect = container.rect.current;
88
+
89
+ if (rect && firstRectUp.rect.current) {
90
+ const {
91
+ offsetTop: rectOffsetTop
92
+ } = rect;
93
+ const {
94
+ offsetTop: firstRectUpOffsetTop
95
+ } = firstRectUp.rect.current;
96
+
97
+ if (rectOffsetTop - threshold < collisionRect.top && rectOffsetTop > firstRectUpOffsetTop) {
98
+ return container;
99
+ }
100
+ }
101
+
102
+ return firstRectUp;
103
+ }, {
104
+ id: DUMMY_ID,
105
+ rect: {
106
+ current: RECT_UP
107
+ }
108
+ });
109
+ } // If we didn't find a match, return null
110
+
111
+
112
+ if (collidingContainer.id === DUMMY_ID) {
113
+ return null;
114
+ }
110
115
 
111
- if (collidingContainer.id === DUMMY_ID) {
112
- return null;
113
- }
116
+ const collidingRect = collidingContainer.rect.current;
117
+ if (!collidingRect) return null; // Calculate the intersection interval
114
118
 
115
- const collidingRect = collidingContainer.rect.current;
116
- if (!collidingRect) return null; // Calculate the intersection interval
119
+ const [top, bottom] = [Math.max(collisionRect.top, collidingRect.offsetTop), Math.min(collisionRect.top + collisionRect.height, collidingRect.offsetTop + collidingRect.height)]; // Calculate the percentage of intersection
117
120
 
118
- const [top, bottom] = [Math.max(collisionRect.top, collidingRect.offsetTop), Math.min(collisionRect.bottom, collidingRect.offsetTop + collidingRect.height)]; // Calculate the percentage of intersection
121
+ const intersectionPercentage = Math.abs(bottom - top) / collidingRect.height;
119
122
 
120
- const intersectionPercentage = Math.abs(bottom - top) / collidingRect.height;
123
+ if (intersectionPercentage > insideThreshold && visibleItemsDictionary[collidingContainer.id].depth + 1 <= maxDragAndDropLevel && collidingContainer.id !== activeId) {
124
+ setDropIndicatorPosition(DropIndicatorPosition.Inside);
125
+ } else {
126
+ setDropIndicatorPosition(isUp ? DropIndicatorPosition.Before : DropIndicatorPosition.After);
127
+ }
121
128
 
122
- if (intersectionPercentage > insideThreshold && visibleItemsDictionary[collidingContainer.id].depth + 1 <= maxDragAndDropLevel && collidingContainer.id !== activeId) {
123
- setDropIndicatorPosition(DropIndicatorPosition.Inside);
124
- } else {
125
- setDropIndicatorPosition(isUp ? DropIndicatorPosition.Before : DropIndicatorPosition.After);
126
- }
129
+ if (isUp && lastPosition !== 'up') setLastPosition('up');else if (!isUp && lastPosition !== 'down') setLastPosition('down'); // Return the id of the match rectangle
127
130
 
128
- if (isUp && lastPosition !== 'up') setLastPosition('up');else if (!isUp && lastPosition !== 'down') setLastPosition('down'); // Return the id of the match rectangle
131
+ return collidingContainer.id;
132
+ };
129
133
 
130
- return collidingContainer.id;
134
+ return func;
131
135
  };
132
136
 
133
137
  export { customCollisionDetection };
@@ -14,7 +14,6 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
14
14
  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; }
15
15
  const directions = [KeyboardCode.Down, KeyboardCode.Right, KeyboardCode.Up, KeyboardCode.Left];
16
16
  const horizontal = [KeyboardCode.Left, KeyboardCode.Right];
17
- [KeyboardCode.Up, KeyboardCode.Down];
18
17
 
19
18
  const getVerticalKeyboardCoordinates = _ref => {
20
19
  var _droppableContainers$, _droppableContainers$2;
@@ -13,7 +13,8 @@ const useTreeActionHandlers = _ref => {
13
13
  onReorder,
14
14
  flattenedItems,
15
15
  projected,
16
- dropIndicatorPosition
16
+ dropIndicatorPosition,
17
+ isDropValid
17
18
  } = _ref;
18
19
  const onDragStart = useCallback(e => {
19
20
  handlePreviewDragStart(e);
@@ -30,17 +31,15 @@ const useTreeActionHandlers = _ref => {
30
31
  active,
31
32
  over
32
33
  } = e;
33
- if (over === null) return;
34
+ if (over === null || !isDropValid) return;
34
35
  const activeIndex = flattenedItems.findIndex(item => item.uid === active.id);
35
36
  let considerExpanding = null;
36
37
  let overIndex = flattenedItems.findIndex(item => item.uid === over.id); // If drop indicator is inside, then put it last,
37
38
  // It will be reconstructed well later
38
39
 
39
40
  if (dropIndicatorPosition === DropIndicatorPosition.Inside) {
40
- var _flattenedItems$overI, _flattenedItems$overI2;
41
-
42
41
  considerExpanding = over.id;
43
- overIndex = flattenedItems[overIndex].realIndex + ((_flattenedItems$overI = (_flattenedItems$overI2 = flattenedItems[overIndex].original.subRows) === null || _flattenedItems$overI2 === void 0 ? void 0 : _flattenedItems$overI2.length) !== null && _flattenedItems$overI !== void 0 ? _flattenedItems$overI : 0) + 1;
42
+ overIndex = flattenedItems[overIndex].realIndex + flattenedItems[overIndex].childrenCount + 1;
44
43
  } // If we are dropping the item in a new position, or new depth
45
44
 
46
45
 
@@ -55,7 +54,7 @@ const useTreeActionHandlers = _ref => {
55
54
  fromIndex: activeIndex
56
55
  }, considerExpanding || '');
57
56
  }
58
- }, [handlePreviewDragEnd, flattenedItems, projected, onReorder, dropIndicatorPosition]);
57
+ }, [handlePreviewDragEnd, isDropValid, flattenedItems, dropIndicatorPosition, projected, onReorder]);
59
58
  const onDragCancel = useCallback(e => {
60
59
  handlePreviewDragCancel(e);
61
60
  }, [handlePreviewDragCancel]);
@@ -9,7 +9,6 @@ import 'core-js/modules/esnext.iterator.constructor.js';
9
9
  import 'core-js/modules/esnext.iterator.for-each.js';
10
10
  import { useState, useMemo, useRef, useEffect } from 'react';
11
11
  import { MeasuringStrategy, useSensors, useSensor, PointerSensor, KeyboardSensor } from '@dnd-kit/core';
12
- import { horizontalListSortingStrategy, verticalListSortingStrategy } from '@dnd-kit/sortable';
13
12
  import { useTreePreviewHandlers } from './useTreePreviewHandlers.js';
14
13
  import { getTreeKeyboardCoordinates } from './getTreeKeyboardCoordinates.js';
15
14
  import { removeChildrenOf, getProjection } from './utilities.js';
@@ -23,25 +22,29 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
23
22
  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; }
24
23
  // if second parameter is true, the space will be done on the horizontal axis
25
24
 
26
- const adjustTranslate = isHorizontalDnD => _ref => {
27
- let {
28
- transform
29
- } = _ref;
25
+ const adjustTranslate = isHorizontalDnD => {
26
+ const func = _ref => {
27
+ let {
28
+ transform
29
+ } = _ref;
30
30
 
31
- const newTransform = _objectSpread({}, transform);
31
+ const newTransform = _objectSpread({}, transform);
32
32
 
33
- if (isHorizontalDnD) {
34
- newTransform.x = transform.x + 25;
35
- } else {
36
- newTransform.x = transform.x + 15;
37
- }
33
+ if (isHorizontalDnD) {
34
+ newTransform.x = transform.x + 25;
35
+ } else {
36
+ newTransform.x = transform.x + 15;
37
+ }
38
38
 
39
- return newTransform;
39
+ return newTransform;
40
+ };
41
+
42
+ return func;
40
43
  };
41
44
 
42
45
  const measuring = {
43
46
  droppable: {
44
- strategy: MeasuringStrategy.BeforeDragging
47
+ strategy: MeasuringStrategy.Always
45
48
  }
46
49
  };
47
50
  const useTreeDndkitConfig = _ref2 => {
@@ -53,6 +56,7 @@ const useTreeDndkitConfig = _ref2 => {
53
56
  isHorizontalDnD = false,
54
57
  isExpandable = false,
55
58
  onReorder,
59
+ getIsDropValid = () => true,
56
60
  maxDragAndDropLevel
57
61
  } = _ref2;
58
62
  const [activeId, setActiveId] = useState('');
@@ -77,6 +81,10 @@ const useTreeDndkitConfig = _ref2 => {
77
81
  });
78
82
  return dictionary;
79
83
  }, [visibleItems]);
84
+ const isDropValid = useMemo(() => {
85
+ if (!activeId || !overId) return true;
86
+ return getIsDropValid(visibleItemsDictionary[activeId], visibleItemsDictionary[overId], ['none', 'before', 'after', 'inside'][dropIndicatorPosition]);
87
+ }, [getIsDropValid, visibleItemsDictionary, activeId, overId, dropIndicatorPosition]);
80
88
  const modifiers = useMemo(() => [adjustTranslate(isHorizontalDnD)], [isHorizontalDnD]);
81
89
  const sensorContext = useRef({
82
90
  items: visibleItems,
@@ -105,7 +113,8 @@ const useTreeDndkitConfig = _ref2 => {
105
113
  onReorder,
106
114
  projected,
107
115
  flattenedItems,
108
- dropIndicatorPosition
116
+ dropIndicatorPosition,
117
+ isDropValid
109
118
  }));
110
119
  const announcements = useTreeAnnouncements(visibleItemsDictionary, dropIndicatorPosition);
111
120
  const dndContextProps = useMemo(() => _objectSpread({
@@ -117,11 +126,12 @@ const useTreeDndkitConfig = _ref2 => {
117
126
  }, dragActionHandlers), [announcements, modifiers, sensors, dragActionHandlers, visibleItemsDictionary, setDropIndicatorPosition, activeId, maxDragAndDropLevel, lastPosition, setLastPosition]);
118
127
  const sortableContextProps = useMemo(() => ({
119
128
  items: sortedIds,
120
- strategy: isHorizontalDnD ? horizontalListSortingStrategy : verticalListSortingStrategy
121
- }), [sortedIds, isHorizontalDnD]);
129
+ strategy: () => null
130
+ }), [sortedIds]);
122
131
  return {
123
132
  dndContextProps,
124
133
  sortableContextProps,
134
+ isDropValid,
125
135
  activeId,
126
136
  activeIndex: (_visibleItemsDictiona = (_visibleItemsDictiona2 = visibleItemsDictionary[activeId]) === null || _visibleItemsDictiona2 === void 0 ? void 0 : _visibleItemsDictiona2.realIndex) !== null && _visibleItemsDictiona !== void 0 ? _visibleItemsDictiona : -1,
127
137
  overId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elliemae/ds-drag-and-drop",
3
- "version": "2.2.1",
3
+ "version": "2.2.2-rc.0",
4
4
  "license": "MIT",
5
5
  "description": "ICE MT - Dimsum - Drag And Drop",
6
6
  "module": "./esm/index.js",
@@ -64,7 +64,7 @@ export declare type useHierarchyDndkitConfigReturn = {
64
64
  overId: string | null;
65
65
  activeIndex: number | undefined;
66
66
  };
67
- export declare type getKeyboardCoordinatesArgs = {
67
+ export declare type GetKeyboardCoordinatesArgs = {
68
68
  items: Item[];
69
69
  active: Active | null;
70
70
  over: Over | null;
@@ -4,12 +4,13 @@ import type { SortingStrategy } from '@dnd-kit/sortable';
4
4
  import { Coordinates } from '@dnd-kit/core/dist/types';
5
5
  import React, { MutableRefObject } from 'react';
6
6
  import { DropIndicatorPosition } from './constants';
7
- export declare type Item = {
7
+ export declare type Item<T = unknown> = {
8
8
  uid: string;
9
9
  depth: number;
10
- parentId: string;
10
+ parentId: string | null;
11
11
  realIndex: number;
12
- original: Record<string, Record<string, any>>;
12
+ childrenCount: number;
13
+ original: T;
13
14
  };
14
15
  export declare type DndContextPropsType = {
15
16
  announcements: Announcements;
@@ -27,49 +28,51 @@ export declare type SortableContextPropsType = {
27
28
  items: string[];
28
29
  strategy: SortingStrategy;
29
30
  };
30
- export declare type useTreePreviewHandlersReturn = {
31
+ export declare type UseTreePreviewHandlersReturn = {
31
32
  handlePreviewDragStart: (e: DragStartEvent) => void;
32
33
  handlePreviewDragMove: (e: DragMoveEvent) => void;
33
34
  handlePreviewDragOver: (e: DragOverEvent) => void;
34
35
  handlePreviewDragEnd: (e: DragEndEvent) => void;
35
36
  handlePreviewDragCancel: (e: DragCancelEvent) => void;
36
37
  };
37
- export declare type useTreePreviewHandlersArgs = {
38
+ export declare type UseTreePreviewHandlersArgs = {
38
39
  setOverId: React.Dispatch<React.SetStateAction<string>>;
39
40
  setActiveId: React.Dispatch<React.SetStateAction<string>>;
40
41
  setDropIndicatorPosition: React.Dispatch<React.SetStateAction<DropIndicatorPosition>>;
41
42
  };
42
- export declare type useTreeActionHandlersArgs = useTreePreviewHandlersReturn & {
43
+ export declare type UseTreeActionHandlersArgs<T = unknown> = UseTreePreviewHandlersReturn & {
43
44
  dropIndicatorPosition: DropIndicatorPosition;
44
45
  flattenedItems: Item[];
45
46
  projected: {
46
47
  depth: number;
47
48
  parentId: string;
48
49
  } | null;
49
- onReorder: (newData: Item[], indexes: {
50
+ onReorder: <S = T>(newData: Item<S>[], indexes: {
50
51
  targetIndex: number;
51
52
  fromIndex: number;
52
53
  }, considerExpanding: string) => void;
54
+ isDropValid: boolean;
53
55
  };
54
- export declare type useTreeActionHandlersReturn = {
56
+ export declare type UseTreeActionHandlersReturn = {
55
57
  onDragStart: (e: DragStartEvent) => void;
56
58
  onDragMove: (e: DragMoveEvent) => void;
57
59
  onDragOver: (e: DragOverEvent) => void;
58
60
  onDragEnd: (e: DragEndEvent) => void;
59
61
  onDragCancel: (e: DragCancelEvent) => void;
60
62
  };
61
- export declare type useTreeDndkitConfigArgs = {
63
+ export declare type UseTreeDndkitConfigArgs<T> = {
62
64
  flattenedItems: Item[];
63
65
  visibleItems: Item[];
64
66
  isHorizontalDnD?: boolean;
65
67
  isExpandable: boolean;
66
- onReorder: (newData: Item[], indexes: {
68
+ onReorder: <S = T>(newData: Item<S>[], indexes: {
67
69
  targetIndex: number;
68
70
  fromIndex: number;
69
71
  }, considerExpanding: string) => void;
72
+ getIsDropValid: <S = T>(active: Item<S>, over: Item<S>, dropIndicatorPosition: 'none' | 'before' | 'after' | 'inside') => boolean;
70
73
  maxDragAndDropLevel: number;
71
74
  };
72
- export declare type useTreeDndkitConfigReturn = {
75
+ export declare type UseTreeDndkitConfigReturn = {
73
76
  dndContextProps: DndContextPropsType;
74
77
  sortableContextProps: SortableContextPropsType;
75
78
  activeId: string;
@@ -77,10 +80,11 @@ export declare type useTreeDndkitConfigReturn = {
77
80
  overId: string;
78
81
  depth: number;
79
82
  dropIndicatorPosition: DropIndicatorPosition;
83
+ isDropValid: boolean;
80
84
  visibleItems: Item[];
81
85
  };
82
- export declare type useTreeDndkitConfigType = (args: useTreeDndkitConfigArgs) => useTreeDndkitConfigReturn;
83
- export declare type getKeyboardCoordinatesArgs = {
86
+ export declare type UseTreeDndkitConfigType = <T = unknown>(args: UseTreeDndkitConfigArgs<T>) => UseTreeDndkitConfigReturn;
87
+ export declare type GetKeyboardCoordinatesArgs = {
84
88
  items: Item[];
85
89
  active: Active;
86
90
  over: Over;
@@ -1,2 +1,2 @@
1
- import type { useTreeActionHandlersReturn, useTreeActionHandlersArgs } from './types';
2
- export declare const useTreeActionHandlers: ({ handlePreviewDragStart, handlePreviewDragMove, handlePreviewDragOver, handlePreviewDragEnd, handlePreviewDragCancel, onReorder, flattenedItems, projected, dropIndicatorPosition, }: useTreeActionHandlersArgs) => useTreeActionHandlersReturn;
1
+ import type { UseTreeActionHandlersReturn, UseTreeActionHandlersArgs } from './types';
2
+ export declare const useTreeActionHandlers: ({ handlePreviewDragStart, handlePreviewDragMove, handlePreviewDragOver, handlePreviewDragEnd, handlePreviewDragCancel, onReorder, flattenedItems, projected, dropIndicatorPosition, isDropValid, }: UseTreeActionHandlersArgs) => UseTreeActionHandlersReturn;
@@ -1,2 +1,2 @@
1
- import type { useTreeDndkitConfigType } from './types';
2
- export declare const useTreeDndkitConfig: useTreeDndkitConfigType;
1
+ import type { UseTreeDndkitConfigType } from './types';
2
+ export declare const useTreeDndkitConfig: UseTreeDndkitConfigType;
@@ -1,2 +1,2 @@
1
- import type { useTreePreviewHandlersReturn, useTreePreviewHandlersArgs } from './types';
2
- export declare const useTreePreviewHandlers: ({ setOverId, setActiveId, setDropIndicatorPosition, }: useTreePreviewHandlersArgs) => useTreePreviewHandlersReturn;
1
+ import type { UseTreePreviewHandlersReturn, UseTreePreviewHandlersArgs } from './types';
2
+ export declare const useTreePreviewHandlers: ({ setOverId, setActiveId, setDropIndicatorPosition, }: UseTreePreviewHandlersArgs) => UseTreePreviewHandlersReturn;