@atlaskit/pragmatic-drag-and-drop 0.19.0 → 0.20.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/CHANGELOG.md CHANGED
@@ -1,5 +1,49 @@
1
1
  # @atlaskit/pragmatic-drag-and-drop
2
2
 
3
+ ## 0.20.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`554a6d8cc34`](https://bitbucket.org/atlassian/atlassian-frontend/commits/554a6d8cc34) - ### Stickiness algorithm improvement
8
+
9
+ We have made some improvements to the drop target stickiness algorithm to allow sticky drop targets that are no longer dragged over to cancel their stickiness.
10
+
11
+ Stickiness is no longer maintained when a sticky drop target states it cannot be dropped on
12
+
13
+ > Scenario: `[A(sticky)]` → `[]` + `A:canDrop()` returns `false`
14
+ > Result: `[]`
15
+
16
+ Stickiness is no longer maintained when a sticky drop start states it is no longer sticky
17
+
18
+ > Scenario: `[A(sticky)]` → `[]` + `A:getIsSticky()` returns `false`
19
+ > Result: `[]`
20
+
21
+ Stickiness is no longer maintained when a sticky drop start is unmounted
22
+
23
+ > Scenario: `[A(sticky)]` → `[]` + `A` is unmounted
24
+ > Result: `[]`
25
+
26
+ To help facilitate this change:
27
+
28
+ - `getIsSticky()` is now only called when an _drop target_ is a potential candidate for stickiness (previously it was called repeatedly)
29
+ - `getIsSticky()` and `canDrop()` are called on _drop targets_ that are no longer being dragged over, but are candidates for stickiness
30
+
31
+ ### Change to `DropTargetRecord` `type`
32
+
33
+ Previously, the `DropTargetRecord` type had a property called `sticky` which would represent whether the _drop target_ was registering itself as sticky via `getIsSticky()`. Knowing `sticky` is not overly helpful given that we now regularly recompute stickiness and a _drop target_ can change disable stickiness after it is applied.
34
+
35
+ What is helpful, is knowing whether a _drop target_ is active _because_ of stickiness. So we have removed `sticky` and added `isActiveDueToStickiness` to the `DropTargetRecord` type.
36
+
37
+ ```diff
38
+ type DropTargetRecord = {
39
+ element: Element;
40
+ data: Record<string | symbol, unknown>;
41
+ dropEffect: DataTransfer['dropEffect'];
42
+ - sticky: boolean;
43
+ + isActiveDueToStickiness: boolean;
44
+ };
45
+ ```
46
+
3
47
  ## 0.19.0
4
48
 
5
49
  ### Minor Changes
@@ -47,7 +47,7 @@ function makeDropTarget(_ref) {
47
47
  }), addToRegistry(args));
48
48
  }
49
49
  function getActualDropTargets(_ref2) {
50
- var _args$getData, _args$getData2, _args$getDropEffect, _args$getDropEffect2, _args$getIsSticky;
50
+ var _args$getData, _args$getData2, _args$getDropEffect, _args$getDropEffect2;
51
51
  var source = _ref2.source,
52
52
  target = _ref2.target,
53
53
  input = _ref2.input,
@@ -85,14 +85,17 @@ function makeDropTarget(_ref) {
85
85
  result: result
86
86
  });
87
87
  }
88
+
89
+ // calculate our new record
88
90
  var data = (_args$getData = (_args$getData2 = args.getData) === null || _args$getData2 === void 0 ? void 0 : _args$getData2.call(args, feedback)) !== null && _args$getData !== void 0 ? _args$getData : {};
89
91
  var dropEffect = (_args$getDropEffect = (_args$getDropEffect2 = args.getDropEffect) === null || _args$getDropEffect2 === void 0 ? void 0 : _args$getDropEffect2.call(args, feedback)) !== null && _args$getDropEffect !== void 0 ? _args$getDropEffect : defaultDropEffect;
90
- var sticky = Boolean((_args$getIsSticky = args.getIsSticky) === null || _args$getIsSticky === void 0 ? void 0 : _args$getIsSticky.call(args, feedback));
91
92
  var record = {
92
93
  data: data,
93
94
  element: args.element,
94
95
  dropEffect: dropEffect,
95
- sticky: sticky
96
+ // we are collecting _actual_ drop targets, so these are
97
+ // being applied _not_ due to stickiness
98
+ isActiveDueToStickiness: false
96
99
  };
97
100
  return getActualDropTargets({
98
101
  source: source,
@@ -219,6 +222,7 @@ function makeDropTarget(_ref) {
219
222
  var actualCaptureOrdered = copyReverse(actual);
220
223
  var resultCaptureOrdered = [];
221
224
  for (var index = 0; index < lastCaptureOrdered.length; index++) {
225
+ var _argsForLast$getIsSti;
222
226
  var last = lastCaptureOrdered[index];
223
227
  var fresh = actualCaptureOrdered[index];
224
228
 
@@ -232,29 +236,51 @@ function makeDropTarget(_ref) {
232
236
  // At this point we have no drop target in the old spot
233
237
  // Check to see if we can use a previous sticky drop target
234
238
 
235
- // stickiness is based on relationships to a parent
236
- // so if we hit a drop target that is not sticky we
237
- // can finish our search
238
- if (!last.sticky) {
239
- break;
240
- }
241
-
242
- // We only want the previous sticky item to 'stick' if
243
- // the parent of the sticky item is unchanged
244
-
245
239
  // The "parent" is the one inside of `resultCaptureOrdered`
246
240
  // (the parent might be a drop target that was sticky)
247
241
  var parent = resultCaptureOrdered[index - 1];
248
242
  var lastParent = lastCaptureOrdered[index - 1];
249
243
 
250
- // parents are the same (might both be undefined for index == 0)
251
- // we can add the last entry and keep searching
252
- if ((parent === null || parent === void 0 ? void 0 : parent.element) === (lastParent === null || lastParent === void 0 ? void 0 : lastParent.element)) {
253
- resultCaptureOrdered.push(last);
254
- continue;
244
+ // Stickiness is based on parent relationships, so if the parent relationship has change
245
+ // then we can stop our search
246
+ if ((parent === null || parent === void 0 ? void 0 : parent.element) !== (lastParent === null || lastParent === void 0 ? void 0 : lastParent.element)) {
247
+ break;
248
+ }
249
+
250
+ // We need to check whether the old drop target can still be dropped on
251
+
252
+ var argsForLast = registry.get(last.element);
253
+
254
+ // We cannot drop on a drop target that is no longer mounted
255
+ if (!argsForLast) {
256
+ break;
255
257
  }
256
- // parents are not the same, we can exit our search
257
- break;
258
+ var feedback = {
259
+ input: input,
260
+ source: source,
261
+ element: argsForLast.element
262
+ };
263
+
264
+ // We cannot drop on a drop target that no longer allows being dropped on
265
+ if (argsForLast.canDrop && !argsForLast.canDrop(feedback)) {
266
+ break;
267
+ }
268
+
269
+ // We cannot drop on a drop target that is no longer sticky
270
+ if (!((_argsForLast$getIsSti = argsForLast.getIsSticky) !== null && _argsForLast$getIsSti !== void 0 && _argsForLast$getIsSti.call(argsForLast, feedback))) {
271
+ break;
272
+ }
273
+
274
+ // Note: intentionally not recollecting `getData()` or `getDropEffect()`
275
+ // Previous values for `data` and `dropEffect` will be borrowed
276
+ // This is to prevent things like the 'closest edge' changing when
277
+ // no longer over a drop target.
278
+ // We could change our mind on this behaviour in the future
279
+
280
+ resultCaptureOrdered.push(_objectSpread(_objectSpread({}, last), {}, {
281
+ // making it clear to consumers this drop target is active due to stickiness
282
+ isActiveDueToStickiness: true
283
+ }));
258
284
  }
259
285
 
260
286
  // return bubble ordered result
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/pragmatic-drag-and-drop",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "sideEffects": false
5
5
  }
@@ -37,7 +37,7 @@ export function makeDropTarget({
37
37
  input,
38
38
  result = []
39
39
  }) {
40
- var _args$getData, _args$getData2, _args$getDropEffect, _args$getDropEffect2, _args$getIsSticky;
40
+ var _args$getData, _args$getData2, _args$getDropEffect, _args$getDropEffect2;
41
41
  if (!(target instanceof Element)) {
42
42
  return result;
43
43
  }
@@ -70,14 +70,17 @@ export function makeDropTarget({
70
70
  result
71
71
  });
72
72
  }
73
+
74
+ // calculate our new record
73
75
  const data = (_args$getData = (_args$getData2 = args.getData) === null || _args$getData2 === void 0 ? void 0 : _args$getData2.call(args, feedback)) !== null && _args$getData !== void 0 ? _args$getData : {};
74
76
  const dropEffect = (_args$getDropEffect = (_args$getDropEffect2 = args.getDropEffect) === null || _args$getDropEffect2 === void 0 ? void 0 : _args$getDropEffect2.call(args, feedback)) !== null && _args$getDropEffect !== void 0 ? _args$getDropEffect : defaultDropEffect;
75
- const sticky = Boolean((_args$getIsSticky = args.getIsSticky) === null || _args$getIsSticky === void 0 ? void 0 : _args$getIsSticky.call(args, feedback));
76
77
  const record = {
77
78
  data,
78
79
  element: args.element,
79
80
  dropEffect,
80
- sticky
81
+ // we are collecting _actual_ drop targets, so these are
82
+ // being applied _not_ due to stickiness
83
+ isActiveDueToStickiness: false
81
84
  };
82
85
  return getActualDropTargets({
83
86
  source,
@@ -181,6 +184,7 @@ export function makeDropTarget({
181
184
  const actualCaptureOrdered = copyReverse(actual);
182
185
  const resultCaptureOrdered = [];
183
186
  for (let index = 0; index < lastCaptureOrdered.length; index++) {
187
+ var _argsForLast$getIsSti;
184
188
  const last = lastCaptureOrdered[index];
185
189
  const fresh = actualCaptureOrdered[index];
186
190
 
@@ -194,29 +198,52 @@ export function makeDropTarget({
194
198
  // At this point we have no drop target in the old spot
195
199
  // Check to see if we can use a previous sticky drop target
196
200
 
197
- // stickiness is based on relationships to a parent
198
- // so if we hit a drop target that is not sticky we
199
- // can finish our search
200
- if (!last.sticky) {
201
- break;
202
- }
203
-
204
- // We only want the previous sticky item to 'stick' if
205
- // the parent of the sticky item is unchanged
206
-
207
201
  // The "parent" is the one inside of `resultCaptureOrdered`
208
202
  // (the parent might be a drop target that was sticky)
209
203
  const parent = resultCaptureOrdered[index - 1];
210
204
  const lastParent = lastCaptureOrdered[index - 1];
211
205
 
212
- // parents are the same (might both be undefined for index == 0)
213
- // we can add the last entry and keep searching
214
- if ((parent === null || parent === void 0 ? void 0 : parent.element) === (lastParent === null || lastParent === void 0 ? void 0 : lastParent.element)) {
215
- resultCaptureOrdered.push(last);
216
- continue;
206
+ // Stickiness is based on parent relationships, so if the parent relationship has change
207
+ // then we can stop our search
208
+ if ((parent === null || parent === void 0 ? void 0 : parent.element) !== (lastParent === null || lastParent === void 0 ? void 0 : lastParent.element)) {
209
+ break;
210
+ }
211
+
212
+ // We need to check whether the old drop target can still be dropped on
213
+
214
+ const argsForLast = registry.get(last.element);
215
+
216
+ // We cannot drop on a drop target that is no longer mounted
217
+ if (!argsForLast) {
218
+ break;
217
219
  }
218
- // parents are not the same, we can exit our search
219
- break;
220
+ const feedback = {
221
+ input,
222
+ source,
223
+ element: argsForLast.element
224
+ };
225
+
226
+ // We cannot drop on a drop target that no longer allows being dropped on
227
+ if (argsForLast.canDrop && !argsForLast.canDrop(feedback)) {
228
+ break;
229
+ }
230
+
231
+ // We cannot drop on a drop target that is no longer sticky
232
+ if (!((_argsForLast$getIsSti = argsForLast.getIsSticky) !== null && _argsForLast$getIsSti !== void 0 && _argsForLast$getIsSti.call(argsForLast, feedback))) {
233
+ break;
234
+ }
235
+
236
+ // Note: intentionally not recollecting `getData()` or `getDropEffect()`
237
+ // Previous values for `data` and `dropEffect` will be borrowed
238
+ // This is to prevent things like the 'closest edge' changing when
239
+ // no longer over a drop target.
240
+ // We could change our mind on this behaviour in the future
241
+
242
+ resultCaptureOrdered.push({
243
+ ...last,
244
+ // making it clear to consumers this drop target is active due to stickiness
245
+ isActiveDueToStickiness: true
246
+ });
220
247
  }
221
248
 
222
249
  // return bubble ordered result
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/pragmatic-drag-and-drop",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "sideEffects": false
5
5
  }
@@ -40,7 +40,7 @@ export function makeDropTarget(_ref) {
40
40
  }), addToRegistry(args));
41
41
  }
42
42
  function getActualDropTargets(_ref2) {
43
- var _args$getData, _args$getData2, _args$getDropEffect, _args$getDropEffect2, _args$getIsSticky;
43
+ var _args$getData, _args$getData2, _args$getDropEffect, _args$getDropEffect2;
44
44
  var source = _ref2.source,
45
45
  target = _ref2.target,
46
46
  input = _ref2.input,
@@ -78,14 +78,17 @@ export function makeDropTarget(_ref) {
78
78
  result: result
79
79
  });
80
80
  }
81
+
82
+ // calculate our new record
81
83
  var data = (_args$getData = (_args$getData2 = args.getData) === null || _args$getData2 === void 0 ? void 0 : _args$getData2.call(args, feedback)) !== null && _args$getData !== void 0 ? _args$getData : {};
82
84
  var dropEffect = (_args$getDropEffect = (_args$getDropEffect2 = args.getDropEffect) === null || _args$getDropEffect2 === void 0 ? void 0 : _args$getDropEffect2.call(args, feedback)) !== null && _args$getDropEffect !== void 0 ? _args$getDropEffect : defaultDropEffect;
83
- var sticky = Boolean((_args$getIsSticky = args.getIsSticky) === null || _args$getIsSticky === void 0 ? void 0 : _args$getIsSticky.call(args, feedback));
84
85
  var record = {
85
86
  data: data,
86
87
  element: args.element,
87
88
  dropEffect: dropEffect,
88
- sticky: sticky
89
+ // we are collecting _actual_ drop targets, so these are
90
+ // being applied _not_ due to stickiness
91
+ isActiveDueToStickiness: false
89
92
  };
90
93
  return getActualDropTargets({
91
94
  source: source,
@@ -212,6 +215,7 @@ export function makeDropTarget(_ref) {
212
215
  var actualCaptureOrdered = copyReverse(actual);
213
216
  var resultCaptureOrdered = [];
214
217
  for (var index = 0; index < lastCaptureOrdered.length; index++) {
218
+ var _argsForLast$getIsSti;
215
219
  var last = lastCaptureOrdered[index];
216
220
  var fresh = actualCaptureOrdered[index];
217
221
 
@@ -225,29 +229,51 @@ export function makeDropTarget(_ref) {
225
229
  // At this point we have no drop target in the old spot
226
230
  // Check to see if we can use a previous sticky drop target
227
231
 
228
- // stickiness is based on relationships to a parent
229
- // so if we hit a drop target that is not sticky we
230
- // can finish our search
231
- if (!last.sticky) {
232
- break;
233
- }
234
-
235
- // We only want the previous sticky item to 'stick' if
236
- // the parent of the sticky item is unchanged
237
-
238
232
  // The "parent" is the one inside of `resultCaptureOrdered`
239
233
  // (the parent might be a drop target that was sticky)
240
234
  var parent = resultCaptureOrdered[index - 1];
241
235
  var lastParent = lastCaptureOrdered[index - 1];
242
236
 
243
- // parents are the same (might both be undefined for index == 0)
244
- // we can add the last entry and keep searching
245
- if ((parent === null || parent === void 0 ? void 0 : parent.element) === (lastParent === null || lastParent === void 0 ? void 0 : lastParent.element)) {
246
- resultCaptureOrdered.push(last);
247
- continue;
237
+ // Stickiness is based on parent relationships, so if the parent relationship has change
238
+ // then we can stop our search
239
+ if ((parent === null || parent === void 0 ? void 0 : parent.element) !== (lastParent === null || lastParent === void 0 ? void 0 : lastParent.element)) {
240
+ break;
241
+ }
242
+
243
+ // We need to check whether the old drop target can still be dropped on
244
+
245
+ var argsForLast = registry.get(last.element);
246
+
247
+ // We cannot drop on a drop target that is no longer mounted
248
+ if (!argsForLast) {
249
+ break;
248
250
  }
249
- // parents are not the same, we can exit our search
250
- break;
251
+ var feedback = {
252
+ input: input,
253
+ source: source,
254
+ element: argsForLast.element
255
+ };
256
+
257
+ // We cannot drop on a drop target that no longer allows being dropped on
258
+ if (argsForLast.canDrop && !argsForLast.canDrop(feedback)) {
259
+ break;
260
+ }
261
+
262
+ // We cannot drop on a drop target that is no longer sticky
263
+ if (!((_argsForLast$getIsSti = argsForLast.getIsSticky) !== null && _argsForLast$getIsSti !== void 0 && _argsForLast$getIsSti.call(argsForLast, feedback))) {
264
+ break;
265
+ }
266
+
267
+ // Note: intentionally not recollecting `getData()` or `getDropEffect()`
268
+ // Previous values for `data` and `dropEffect` will be borrowed
269
+ // This is to prevent things like the 'closest edge' changing when
270
+ // no longer over a drop target.
271
+ // We could change our mind on this behaviour in the future
272
+
273
+ resultCaptureOrdered.push(_objectSpread(_objectSpread({}, last), {}, {
274
+ // making it clear to consumers this drop target is active due to stickiness
275
+ isActiveDueToStickiness: true
276
+ }));
251
277
  }
252
278
 
253
279
  // return bubble ordered result
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@atlaskit/pragmatic-drag-and-drop",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "sideEffects": false
5
5
  }
@@ -20,11 +20,9 @@ export type DropTargetRecord = {
20
20
  */
21
21
  dropEffect: DataTransfer['dropEffect'];
22
22
  /**
23
- * Whether or not the drop target is sticky
24
- *
25
- * (Collected by `getIsSticky()`)
23
+ * Whether or not the drop target is active due to _stickiness_
26
24
  */
27
- sticky: boolean;
25
+ isActiveDueToStickiness: boolean;
28
26
  };
29
27
  export type Position = {
30
28
  x: number;
@@ -20,11 +20,9 @@ export type DropTargetRecord = {
20
20
  */
21
21
  dropEffect: DataTransfer['dropEffect'];
22
22
  /**
23
- * Whether or not the drop target is sticky
24
- *
25
- * (Collected by `getIsSticky()`)
23
+ * Whether or not the drop target is active due to _stickiness_
26
24
  */
27
- sticky: boolean;
25
+ isActiveDueToStickiness: boolean;
28
26
  };
29
27
  export type Position = {
30
28
  x: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaskit/pragmatic-drag-and-drop",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "The core Pragmatic drag and drop framework, optimized for performance.",
5
5
  "repository": "https://bitbucket.org/atlassian/atlassian-frontend-mirror",
6
6
  "author": "Atlassian Pty Ltd",
@@ -56,7 +56,6 @@
56
56
  "raf-schd": "^4.0.3"
57
57
  },
58
58
  "devDependencies": {
59
- "@atlaskit/tokens": "^1.6.0",
60
59
  "@atlaskit/visual-regression": "*",
61
60
  "@atlassian/atlassian-frontend-prettier-config-1.0.0": "npm:@atlassian/atlassian-frontend-prettier-config@1.0.0",
62
61
  "@emotion/react": "^11.7.1",