@react-aria/dnd 3.0.0-alpha.11 → 3.0.0-alpha.12

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/dist/main.js CHANGED
@@ -21,6 +21,7 @@ $parcel$export(module.exports, "useDropIndicator", () => $c5557edbed563ebf$expor
21
21
  $parcel$export(module.exports, "useDraggableItem", () => $0cbbd00cda972c67$export$b35afafff42da2d9);
22
22
  $parcel$export(module.exports, "useClipboard", () => $74f3dedaa4d234b4$export$2314ca2a3e892862);
23
23
  $parcel$export(module.exports, "DragPreview", () => $2dccaca1f4baa446$export$905ab40ac2179daa);
24
+ $parcel$export(module.exports, "ListDropTargetDelegate", () => $2268795bbb597ecb$export$fbd65d14c79e28cc);
24
25
 
25
26
 
26
27
 
@@ -285,12 +286,15 @@ function $28e10663603f5ea1$export$aef80212ac99c003(item) {
285
286
  $28e10663603f5ea1$var$dropItems.delete(item.element);
286
287
  };
287
288
  }
288
- function $28e10663603f5ea1$export$549dbcf8649bf3b2(target, stringFormatter) {
289
+ function $28e10663603f5ea1$export$549dbcf8649bf3b2(target1, stringFormatter) {
289
290
  if ($28e10663603f5ea1$var$dragSession) throw new Error('Cannot begin dragging while already dragging');
290
- $28e10663603f5ea1$var$dragSession = new $28e10663603f5ea1$var$DragSession(target, stringFormatter);
291
+ $28e10663603f5ea1$var$dragSession = new $28e10663603f5ea1$var$DragSession(target1, stringFormatter);
291
292
  requestAnimationFrame(()=>{
292
293
  $28e10663603f5ea1$var$dragSession.setup();
293
- if ($4620ae0dc40f0031$export$1fb2158d224b542c() === 'keyboard' || $4620ae0dc40f0031$export$1fb2158d224b542c() === 'touch' && $4vY0V$reactariainteractions.getInteractionModality() === 'virtual') $28e10663603f5ea1$var$dragSession.next();
294
+ if ($4620ae0dc40f0031$export$1fb2158d224b542c() === 'keyboard' || $4620ae0dc40f0031$export$1fb2158d224b542c() === 'touch' && $4vY0V$reactariainteractions.getInteractionModality() === 'virtual') {
295
+ let target = $28e10663603f5ea1$var$dragSession.findNearestDropTarget();
296
+ $28e10663603f5ea1$var$dragSession.setCurrentDropTarget(target);
297
+ }
294
298
  });
295
299
  for (let cb of $28e10663603f5ea1$var$subscriptions)cb();
296
300
  }
@@ -516,6 +520,22 @@ class $28e10663603f5ea1$var$DragSession {
516
520
  } else this.setCurrentDropTarget(this.validDropTargets[this.validDropTargets.length - 1]);
517
521
  } else this.setCurrentDropTarget(this.validDropTargets[index - 1]);
518
522
  }
523
+ findNearestDropTarget() {
524
+ let dragTargetRect = this.dragTarget.element.getBoundingClientRect();
525
+ let minDistance = Infinity;
526
+ let nearest = null;
527
+ for (let dropTarget of this.validDropTargets){
528
+ let rect = dropTarget.element.getBoundingClientRect();
529
+ let dx = rect.left - dragTargetRect.left;
530
+ let dy = rect.top - dragTargetRect.top;
531
+ let dist = dx * dx + dy * dy;
532
+ if (dist < minDistance) {
533
+ minDistance = dist;
534
+ nearest = dropTarget;
535
+ }
536
+ }
537
+ return nearest;
538
+ }
519
539
  setCurrentDropTarget(dropTarget, item) {
520
540
  if (dropTarget !== this.currentDropTarget) {
521
541
  if (this.currentDropTarget && typeof this.currentDropTarget.onDropExit === 'function') {
@@ -2102,28 +2122,66 @@ function $1ca228bc9257ca16$export$ccdee5eaf73cf661(options) {
2102
2122
  let state = $4vY0V$react.useRef({
2103
2123
  x: 0,
2104
2124
  y: 0,
2105
- dragEnterCount: 0,
2125
+ dragOverElements: new Set(),
2106
2126
  dropEffect: 'none',
2127
+ effectAllowed: 'none',
2107
2128
  dropActivateTimer: null
2108
2129
  }).current;
2130
+ let fireDropEnter = (e)=>{
2131
+ setDropTarget(true);
2132
+ if (typeof options.onDropEnter === 'function') {
2133
+ let rect = e.currentTarget.getBoundingClientRect();
2134
+ options.onDropEnter({
2135
+ type: 'dropenter',
2136
+ x: e.clientX - rect.x,
2137
+ y: e.clientY - rect.y
2138
+ });
2139
+ }
2140
+ };
2141
+ let fireDropExit = (e)=>{
2142
+ setDropTarget(false);
2143
+ if (typeof options.onDropExit === 'function') {
2144
+ let rect = e.currentTarget.getBoundingClientRect();
2145
+ options.onDropExit({
2146
+ type: 'dropexit',
2147
+ x: e.clientX - rect.x,
2148
+ y: e.clientY - rect.y
2149
+ });
2150
+ }
2151
+ };
2109
2152
  let onDragOver = (e)=>{
2110
2153
  e.preventDefault();
2111
2154
  e.stopPropagation();
2112
- if (e.clientX === state.x && e.clientY === state.y) {
2155
+ if (e.clientX === state.x && e.clientY === state.y && e.dataTransfer.effectAllowed === state.effectAllowed) {
2113
2156
  e.dataTransfer.dropEffect = state.dropEffect;
2114
2157
  return;
2115
2158
  }
2116
2159
  state.x = e.clientX;
2117
2160
  state.y = e.clientY;
2161
+ let prevDropEffect = state.dropEffect;
2162
+ // Update drop effect if allowed drop operations changed (e.g. user pressed modifier key).
2163
+ if (e.dataTransfer.effectAllowed !== state.effectAllowed) {
2164
+ let allowedOperations = $1ca228bc9257ca16$var$effectAllowedToOperations(e.dataTransfer.effectAllowed);
2165
+ let dropOperation = allowedOperations[0];
2166
+ if (typeof options.getDropOperation === 'function') {
2167
+ let types = new $4620ae0dc40f0031$export$7f04ce188c91447c(e.dataTransfer);
2168
+ dropOperation = $1ca228bc9257ca16$var$getDropOperation(e.dataTransfer.effectAllowed, options.getDropOperation(types, allowedOperations));
2169
+ }
2170
+ state.dropEffect = $76b1e110a27b1ccd$export$5eacb0769d26d3b2[dropOperation] || 'none';
2171
+ }
2118
2172
  if (typeof options.getDropOperationForPoint === 'function') {
2119
2173
  let allowedOperations = $1ca228bc9257ca16$var$effectAllowedToOperations(e.dataTransfer.effectAllowed);
2120
2174
  let types = new $4620ae0dc40f0031$export$7f04ce188c91447c(e.dataTransfer);
2121
2175
  let rect = e.currentTarget.getBoundingClientRect();
2122
- let dropOperation = options.getDropOperationForPoint(types, allowedOperations, state.x - rect.x, state.y - rect.y);
2176
+ let dropOperation = $1ca228bc9257ca16$var$getDropOperation(e.dataTransfer.effectAllowed, options.getDropOperationForPoint(types, allowedOperations, state.x - rect.x, state.y - rect.y));
2123
2177
  state.dropEffect = $76b1e110a27b1ccd$export$5eacb0769d26d3b2[dropOperation] || 'none';
2124
2178
  }
2179
+ state.effectAllowed = e.dataTransfer.effectAllowed;
2125
2180
  e.dataTransfer.dropEffect = state.dropEffect;
2126
- if (typeof options.onDropMove === 'function') {
2181
+ // If the drop operation changes, update state and fire events appropriately.
2182
+ if (state.dropEffect === 'none' && prevDropEffect !== 'none') fireDropExit(e);
2183
+ else if (state.dropEffect !== 'none' && prevDropEffect === 'none') fireDropEnter(e);
2184
+ if (typeof options.onDropMove === 'function' && state.dropEffect !== 'none') {
2127
2185
  let rect = e.currentTarget.getBoundingClientRect();
2128
2186
  options.onDropMove({
2129
2187
  type: 'dropmove',
@@ -2145,46 +2203,39 @@ function $1ca228bc9257ca16$export$ccdee5eaf73cf661(options) {
2145
2203
  };
2146
2204
  let onDragEnter = (e)=>{
2147
2205
  e.stopPropagation();
2148
- state.dragEnterCount++;
2149
- if (state.dragEnterCount > 1) return;
2206
+ state.dragOverElements.add(e.target);
2207
+ if (state.dragOverElements.size > 1) return;
2150
2208
  let allowedOperations = $1ca228bc9257ca16$var$effectAllowedToOperations(e.dataTransfer.effectAllowed);
2151
2209
  let dropOperation = allowedOperations[0];
2152
2210
  if (typeof options.getDropOperation === 'function') {
2153
2211
  let types = new $4620ae0dc40f0031$export$7f04ce188c91447c(e.dataTransfer);
2154
- dropOperation = options.getDropOperation(types, allowedOperations);
2212
+ dropOperation = $1ca228bc9257ca16$var$getDropOperation(e.dataTransfer.effectAllowed, options.getDropOperation(types, allowedOperations));
2155
2213
  }
2156
- if (dropOperation !== 'cancel') setDropTarget(true);
2157
2214
  if (typeof options.getDropOperationForPoint === 'function') {
2158
2215
  let types = new $4620ae0dc40f0031$export$7f04ce188c91447c(e.dataTransfer);
2159
2216
  let rect = e.currentTarget.getBoundingClientRect();
2160
- dropOperation = options.getDropOperationForPoint(types, allowedOperations, e.clientX - rect.x, e.clientY - rect.y);
2161
- }
2162
- state.dropEffect = $76b1e110a27b1ccd$export$5eacb0769d26d3b2[dropOperation] || 'none';
2163
- e.dataTransfer.dropEffect = state.dropEffect;
2164
- if (typeof options.onDropEnter === 'function' && dropOperation !== 'cancel') {
2165
- let rect = e.currentTarget.getBoundingClientRect();
2166
- options.onDropEnter({
2167
- type: 'dropenter',
2168
- x: e.clientX - rect.x,
2169
- y: e.clientY - rect.y
2170
- });
2217
+ dropOperation = $1ca228bc9257ca16$var$getDropOperation(e.dataTransfer.effectAllowed, options.getDropOperationForPoint(types, allowedOperations, e.clientX - rect.x, e.clientY - rect.y));
2171
2218
  }
2172
2219
  state.x = e.clientX;
2173
2220
  state.y = e.clientY;
2221
+ state.effectAllowed = e.dataTransfer.effectAllowed;
2222
+ state.dropEffect = $76b1e110a27b1ccd$export$5eacb0769d26d3b2[dropOperation] || 'none';
2223
+ e.dataTransfer.dropEffect = state.dropEffect;
2224
+ if (dropOperation !== 'cancel') fireDropEnter(e);
2174
2225
  };
2175
2226
  let onDragLeave = (e)=>{
2176
2227
  e.stopPropagation();
2177
- state.dragEnterCount--;
2178
- if (state.dragEnterCount > 0) return;
2179
- if (typeof options.onDropExit === 'function' && state.dropEffect !== 'none') {
2180
- let rect = e.currentTarget.getBoundingClientRect();
2181
- options.onDropExit({
2182
- type: 'dropexit',
2183
- x: e.clientX - rect.x,
2184
- y: e.clientY - rect.y
2185
- });
2186
- }
2187
- setDropTarget(false);
2228
+ // We would use e.relatedTarget to detect if the drag is still inside the drop target,
2229
+ // but it is always null in WebKit. https://bugs.webkit.org/show_bug.cgi?id=66547
2230
+ // Instead, we track all of the targets of dragenter events in a set, and remove them
2231
+ // in dragleave. When the set becomes empty, we've left the drop target completely.
2232
+ // We must also remove any elements that are no longer in the DOM, because dragleave
2233
+ // events will never be fired for these. This can happen, for example, with drop
2234
+ // indicators between items, which disappear when the drop target changes.
2235
+ state.dragOverElements.delete(e.target);
2236
+ for (let element of state.dragOverElements)if (!e.currentTarget.contains(element)) state.dragOverElements.delete(element);
2237
+ if (state.dragOverElements.size > 0) return;
2238
+ if (state.dropEffect !== 'none') fireDropExit(e);
2188
2239
  clearTimeout(state.dropActivateTimer);
2189
2240
  };
2190
2241
  let onDrop = (e)=>{
@@ -2209,16 +2260,8 @@ function $1ca228bc9257ca16$export$ccdee5eaf73cf661(options) {
2209
2260
  options.onDrop(event);
2210
2261
  }, 0);
2211
2262
  }
2212
- if (typeof options.onDropExit === 'function') {
2213
- let rect = e.currentTarget.getBoundingClientRect();
2214
- options.onDropExit({
2215
- type: 'dropexit',
2216
- x: e.clientX - rect.x,
2217
- y: e.clientY - rect.y
2218
- });
2219
- }
2220
- state.dragEnterCount = 0;
2221
- setDropTarget(false);
2263
+ state.dragOverElements.clear();
2264
+ fireDropExit(e);
2222
2265
  clearTimeout(state.dropActivateTimer);
2223
2266
  };
2224
2267
  let optionsRef = $4vY0V$react.useRef(options);
@@ -2264,6 +2307,11 @@ function $1ca228bc9257ca16$var$effectAllowedToOperations(effectAllowed) {
2264
2307
  if (allowedOperationsBits & $76b1e110a27b1ccd$export$60b7b4bcf3903d8e.link) allowedOperations.push('link');
2265
2308
  return allowedOperations;
2266
2309
  }
2310
+ function $1ca228bc9257ca16$var$getDropOperation(effectAllowed, operation) {
2311
+ let allowedOperationsBits = $76b1e110a27b1ccd$export$9bbdfc78cf083e16[effectAllowed];
2312
+ let op = $76b1e110a27b1ccd$export$60b7b4bcf3903d8e[operation];
2313
+ return allowedOperationsBits & op ? operation : 'cancel';
2314
+ }
2267
2315
 
2268
2316
 
2269
2317
 
@@ -2341,22 +2389,23 @@ function $7f93a158ac20b90a$export$f4e2f423c21f7b04(props, state1, ref2) {
2341
2389
  let autoScroll = $12cc069a1c69155b$export$6323452ca4533ed8(ref2);
2342
2390
  let { dropProps: dropProps } = $1ca228bc9257ca16$export$ccdee5eaf73cf661({
2343
2391
  ref: ref2,
2344
- onDropEnter (e) {
2345
- let target = props.getDropTargetFromPoint(e.x, e.y);
2346
- state1.setTarget(target);
2392
+ onDropEnter () {
2393
+ state1.setTarget(localState.nextTarget);
2347
2394
  },
2348
2395
  onDropMove (e) {
2349
2396
  state1.setTarget(localState.nextTarget);
2350
2397
  autoScroll.move(e.x, e.y);
2351
2398
  },
2352
2399
  getDropOperationForPoint (types, allowedOperations, x, y) {
2353
- let target = props.getDropTargetFromPoint(x, y);
2354
- if (!target) {
2400
+ let isValidDropTarget = (target)=>state1.getDropOperation(target, types, allowedOperations) !== 'cancel'
2401
+ ;
2402
+ let target1 = props.dropTargetDelegate.getDropTargetFromPoint(x, y, isValidDropTarget);
2403
+ if (!target1) {
2355
2404
  localState.dropOperation = 'cancel';
2356
2405
  localState.nextTarget = null;
2357
2406
  return 'cancel';
2358
2407
  }
2359
- localState.dropOperation = state1.getDropOperation(target, types, allowedOperations);
2408
+ localState.dropOperation = state1.getDropOperation(target1, types, allowedOperations);
2360
2409
  // If the target doesn't accept the drop, see if the root accepts it instead.
2361
2410
  if (localState.dropOperation === 'cancel') {
2362
2411
  let rootTarget = {
@@ -2364,11 +2413,11 @@ function $7f93a158ac20b90a$export$f4e2f423c21f7b04(props, state1, ref2) {
2364
2413
  };
2365
2414
  let dropOperation = state1.getDropOperation(rootTarget, types, allowedOperations);
2366
2415
  if (dropOperation !== 'cancel') {
2367
- target = rootTarget;
2416
+ target1 = rootTarget;
2368
2417
  localState.dropOperation = dropOperation;
2369
2418
  }
2370
2419
  }
2371
- localState.nextTarget = localState.dropOperation === 'cancel' ? null : target;
2420
+ localState.nextTarget = localState.dropOperation === 'cancel' ? null : target1;
2372
2421
  return localState.dropOperation;
2373
2422
  },
2374
2423
  onDropExit () {
@@ -2729,7 +2778,8 @@ function $fc1876157e07bcec$export$f7b0c5d28b66b6a5(options, state, ref) {
2729
2778
  dropProps: {
2730
2779
  ...dropProps,
2731
2780
  'aria-hidden': !dragSession || isValidDropTarget ? undefined : 'true'
2732
- }
2781
+ },
2782
+ isDropTarget: isDropTarget
2733
2783
  };
2734
2784
  }
2735
2785
 
@@ -2773,6 +2823,8 @@ function $c5557edbed563ebf$export$8d0e41d2815afac5(props, state, ref1) {
2773
2823
  itemText: getText(after)
2774
2824
  });
2775
2825
  }
2826
+ let isDropTarget = state.isDropTarget(target);
2827
+ let ariaHidden = !dragSession ? 'true' : dropProps['aria-hidden'];
2776
2828
  return {
2777
2829
  dropIndicatorProps: {
2778
2830
  ...dropProps,
@@ -2780,9 +2832,14 @@ function $c5557edbed563ebf$export$8d0e41d2815afac5(props, state, ref1) {
2780
2832
  'aria-roledescription': stringFormatter.format('dropIndicator'),
2781
2833
  'aria-label': label,
2782
2834
  'aria-labelledby': labelledBy,
2783
- 'aria-hidden': !dragSession ? 'true' : dropProps['aria-hidden'],
2835
+ 'aria-hidden': ariaHidden,
2784
2836
  tabIndex: -1
2785
- }
2837
+ },
2838
+ isDropTarget: isDropTarget,
2839
+ // If aria-hidden, we are either not in a drag session or the drop target is invalid.
2840
+ // In that case, there's no need to render anything at all unless we need to show the indicator visually.
2841
+ // This can happen when dragging using the native DnD API as opposed to keyboard dragging.
2842
+ isHidden: !isDropTarget && !!ariaHidden
2786
2843
  };
2787
2844
  }
2788
2845
 
@@ -2797,6 +2854,7 @@ function $0cbbd00cda972c67$export$b35afafff42da2d9(props, state) {
2797
2854
  return state.getItems(props.key);
2798
2855
  },
2799
2856
  preview: state.preview,
2857
+ getAllowedDropOperations: state.getAllowedDropOperations,
2800
2858
  onDragStart (e) {
2801
2859
  state.startDrag(props.key, e);
2802
2860
  },
@@ -2947,6 +3005,80 @@ function $2dccaca1f4baa446$var$DragPreview(props, ref) {
2947
3005
  let $2dccaca1f4baa446$export$905ab40ac2179daa = /*#__PURE__*/ ($parcel$interopDefault($4vY0V$react)).forwardRef($2dccaca1f4baa446$var$DragPreview);
2948
3006
 
2949
3007
 
3008
+ class $2268795bbb597ecb$export$fbd65d14c79e28cc {
3009
+ getDropTargetFromPoint(x, y, isValidDropTarget) {
3010
+ if (this.collection.size === 0) return;
3011
+ let rect = this.ref.current.getBoundingClientRect();
3012
+ x += rect.x;
3013
+ y += rect.y;
3014
+ let elements = this.ref.current.querySelectorAll('[data-key]');
3015
+ let elementMap = new Map();
3016
+ for (let item of elements)if (item instanceof HTMLElement) elementMap.set(item.dataset.key, item);
3017
+ let items = [
3018
+ ...this.collection
3019
+ ];
3020
+ let low = 0;
3021
+ let high = items.length;
3022
+ while(low < high){
3023
+ let mid = Math.floor((low + high) / 2);
3024
+ let item = items[mid];
3025
+ let element = elementMap.get(String(item.key));
3026
+ let rect = element.getBoundingClientRect();
3027
+ if (y < rect.top) high = mid;
3028
+ else if (y > rect.bottom) low = mid + 1;
3029
+ else {
3030
+ let target = {
3031
+ type: 'item',
3032
+ key: item.key,
3033
+ dropPosition: 'on'
3034
+ };
3035
+ if (isValidDropTarget(target)) {
3036
+ // Otherwise, if dropping on the item is accepted, try the before/after positions if within 5px
3037
+ // of the top or bottom of the item.
3038
+ if (y <= rect.top + 5 && isValidDropTarget({
3039
+ ...target,
3040
+ dropPosition: 'before'
3041
+ })) target.dropPosition = 'before';
3042
+ else if (y >= rect.bottom - 5 && isValidDropTarget({
3043
+ ...target,
3044
+ dropPosition: 'after'
3045
+ })) target.dropPosition = 'after';
3046
+ } else {
3047
+ // If dropping on the item isn't accepted, try the target before or after depending on the y position.
3048
+ let midY = rect.top + rect.height / 2;
3049
+ if (y <= midY && isValidDropTarget({
3050
+ ...target,
3051
+ dropPosition: 'before'
3052
+ })) target.dropPosition = 'before';
3053
+ else if (y >= midY && isValidDropTarget({
3054
+ ...target,
3055
+ dropPosition: 'after'
3056
+ })) target.dropPosition = 'after';
3057
+ }
3058
+ return target;
3059
+ }
3060
+ }
3061
+ let item1 = items[Math.min(low, items.length - 1)];
3062
+ let element = elementMap.get(String(item1.key));
3063
+ rect = element.getBoundingClientRect();
3064
+ if (Math.abs(y - rect.top) < Math.abs(y - rect.bottom)) return {
3065
+ type: 'item',
3066
+ key: item1.key,
3067
+ dropPosition: 'before'
3068
+ };
3069
+ return {
3070
+ type: 'item',
3071
+ key: item1.key,
3072
+ dropPosition: 'after'
3073
+ };
3074
+ }
3075
+ constructor(collection, ref){
3076
+ this.collection = collection;
3077
+ this.ref = ref;
3078
+ }
3079
+ }
3080
+
3081
+
2950
3082
 
2951
3083
 
2952
3084
  //# sourceMappingURL=main.js.map