@react-aria/dnd 3.7.4 → 3.8.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.
Files changed (139) hide show
  1. package/dist/DragManager.main.js +25 -13
  2. package/dist/DragManager.main.js.map +1 -1
  3. package/dist/DragManager.mjs +25 -13
  4. package/dist/DragManager.module.js +25 -13
  5. package/dist/DragManager.module.js.map +1 -1
  6. package/dist/DragPreview.main.js +7 -1
  7. package/dist/DragPreview.main.js.map +1 -1
  8. package/dist/DragPreview.mjs +8 -2
  9. package/dist/DragPreview.module.js +8 -2
  10. package/dist/DragPreview.module.js.map +1 -1
  11. package/dist/ListDropTargetDelegate.main.js +5 -4
  12. package/dist/ListDropTargetDelegate.main.js.map +1 -1
  13. package/dist/ListDropTargetDelegate.mjs +5 -4
  14. package/dist/ListDropTargetDelegate.module.js +5 -4
  15. package/dist/ListDropTargetDelegate.module.js.map +1 -1
  16. package/dist/ar-AE.main.js.map +1 -1
  17. package/dist/ar-AE.module.js.map +1 -1
  18. package/dist/bg-BG.main.js.map +1 -1
  19. package/dist/bg-BG.module.js.map +1 -1
  20. package/dist/constants.main.js +3 -3
  21. package/dist/constants.main.js.map +1 -1
  22. package/dist/constants.mjs +3 -3
  23. package/dist/constants.module.js +3 -3
  24. package/dist/constants.module.js.map +1 -1
  25. package/dist/cs-CZ.main.js.map +1 -1
  26. package/dist/cs-CZ.module.js.map +1 -1
  27. package/dist/da-DK.main.js.map +1 -1
  28. package/dist/da-DK.module.js.map +1 -1
  29. package/dist/de-DE.main.js.map +1 -1
  30. package/dist/de-DE.module.js.map +1 -1
  31. package/dist/el-GR.main.js.map +1 -1
  32. package/dist/el-GR.module.js.map +1 -1
  33. package/dist/en-US.main.js.map +1 -1
  34. package/dist/en-US.module.js.map +1 -1
  35. package/dist/es-ES.main.js.map +1 -1
  36. package/dist/es-ES.module.js.map +1 -1
  37. package/dist/et-EE.main.js.map +1 -1
  38. package/dist/et-EE.module.js.map +1 -1
  39. package/dist/fi-FI.main.js.map +1 -1
  40. package/dist/fi-FI.module.js.map +1 -1
  41. package/dist/fr-FR.main.js.map +1 -1
  42. package/dist/fr-FR.module.js.map +1 -1
  43. package/dist/he-IL.main.js.map +1 -1
  44. package/dist/he-IL.module.js.map +1 -1
  45. package/dist/hr-HR.main.js.map +1 -1
  46. package/dist/hr-HR.module.js.map +1 -1
  47. package/dist/hu-HU.main.js.map +1 -1
  48. package/dist/hu-HU.module.js.map +1 -1
  49. package/dist/it-IT.main.js.map +1 -1
  50. package/dist/it-IT.module.js.map +1 -1
  51. package/dist/ja-JP.main.js.map +1 -1
  52. package/dist/ja-JP.module.js.map +1 -1
  53. package/dist/ko-KR.main.js.map +1 -1
  54. package/dist/ko-KR.module.js.map +1 -1
  55. package/dist/lt-LT.main.js.map +1 -1
  56. package/dist/lt-LT.module.js.map +1 -1
  57. package/dist/lv-LV.main.js.map +1 -1
  58. package/dist/lv-LV.module.js.map +1 -1
  59. package/dist/nb-NO.main.js.map +1 -1
  60. package/dist/nb-NO.module.js.map +1 -1
  61. package/dist/nl-NL.main.js.map +1 -1
  62. package/dist/nl-NL.module.js.map +1 -1
  63. package/dist/pl-PL.main.js.map +1 -1
  64. package/dist/pl-PL.module.js.map +1 -1
  65. package/dist/pt-BR.main.js.map +1 -1
  66. package/dist/pt-BR.module.js.map +1 -1
  67. package/dist/pt-PT.main.js.map +1 -1
  68. package/dist/pt-PT.module.js.map +1 -1
  69. package/dist/ro-RO.main.js.map +1 -1
  70. package/dist/ro-RO.module.js.map +1 -1
  71. package/dist/ru-RU.main.js.map +1 -1
  72. package/dist/ru-RU.module.js.map +1 -1
  73. package/dist/sk-SK.main.js.map +1 -1
  74. package/dist/sk-SK.module.js.map +1 -1
  75. package/dist/sl-SI.main.js.map +1 -1
  76. package/dist/sl-SI.module.js.map +1 -1
  77. package/dist/sr-SP.main.js.map +1 -1
  78. package/dist/sr-SP.module.js.map +1 -1
  79. package/dist/sv-SE.main.js.map +1 -1
  80. package/dist/sv-SE.module.js.map +1 -1
  81. package/dist/tr-TR.main.js.map +1 -1
  82. package/dist/tr-TR.module.js.map +1 -1
  83. package/dist/types.d.ts +4 -4
  84. package/dist/types.d.ts.map +1 -1
  85. package/dist/uk-UA.main.js.map +1 -1
  86. package/dist/uk-UA.module.js.map +1 -1
  87. package/dist/useAutoScroll.main.js +5 -5
  88. package/dist/useAutoScroll.main.js.map +1 -1
  89. package/dist/useAutoScroll.mjs +5 -5
  90. package/dist/useAutoScroll.module.js +5 -5
  91. package/dist/useAutoScroll.module.js.map +1 -1
  92. package/dist/useClipboard.main.js +13 -7
  93. package/dist/useClipboard.main.js.map +1 -1
  94. package/dist/useClipboard.mjs +13 -7
  95. package/dist/useClipboard.module.js +13 -7
  96. package/dist/useClipboard.module.js.map +1 -1
  97. package/dist/useDrag.main.js +2 -2
  98. package/dist/useDrag.main.js.map +1 -1
  99. package/dist/useDrag.mjs +2 -2
  100. package/dist/useDrag.module.js +2 -2
  101. package/dist/useDrag.module.js.map +1 -1
  102. package/dist/useDrop.main.js +5 -4
  103. package/dist/useDrop.main.js.map +1 -1
  104. package/dist/useDrop.mjs +5 -4
  105. package/dist/useDrop.module.js +5 -4
  106. package/dist/useDrop.module.js.map +1 -1
  107. package/dist/useDropIndicator.main.js +3 -2
  108. package/dist/useDropIndicator.main.js.map +1 -1
  109. package/dist/useDropIndicator.mjs +3 -2
  110. package/dist/useDropIndicator.module.js +3 -2
  111. package/dist/useDropIndicator.module.js.map +1 -1
  112. package/dist/useDroppableCollection.main.js +33 -19
  113. package/dist/useDroppableCollection.main.js.map +1 -1
  114. package/dist/useDroppableCollection.mjs +33 -19
  115. package/dist/useDroppableCollection.module.js +33 -19
  116. package/dist/useDroppableCollection.module.js.map +1 -1
  117. package/dist/useVirtualDrop.main.js.map +1 -1
  118. package/dist/useVirtualDrop.module.js.map +1 -1
  119. package/dist/utils.main.js +5 -3
  120. package/dist/utils.main.js.map +1 -1
  121. package/dist/utils.mjs +5 -3
  122. package/dist/utils.module.js +5 -3
  123. package/dist/utils.module.js.map +1 -1
  124. package/dist/zh-CN.main.js.map +1 -1
  125. package/dist/zh-CN.module.js.map +1 -1
  126. package/dist/zh-TW.main.js.map +1 -1
  127. package/dist/zh-TW.module.js.map +1 -1
  128. package/package.json +13 -13
  129. package/src/DragManager.ts +26 -24
  130. package/src/DragPreview.tsx +17 -8
  131. package/src/ListDropTargetDelegate.ts +8 -5
  132. package/src/useAutoScroll.ts +6 -6
  133. package/src/useClipboard.ts +12 -6
  134. package/src/useDrag.ts +5 -2
  135. package/src/useDrop.ts +17 -9
  136. package/src/useDropIndicator.ts +10 -4
  137. package/src/useDroppableCollection.ts +62 -39
  138. package/src/useVirtualDrop.ts +3 -2
  139. package/src/utils.ts +16 -10
package/src/useDrop.ts CHANGED
@@ -15,13 +15,13 @@ import {DragEvent, HTMLAttributes, useRef, useState} from 'react';
15
15
  import * as DragManager from './DragManager';
16
16
  import {DragTypes, globalAllowedDropOperations, globalDndState, readFromDataTransfer, setGlobalDnDState, setGlobalDropEffect} from './utils';
17
17
  import {DROP_EFFECT_TO_DROP_OPERATION, DROP_OPERATION, DROP_OPERATION_ALLOWED, DROP_OPERATION_TO_DROP_EFFECT} from './constants';
18
- import {DropActivateEvent, DropEnterEvent, DropEvent, DropExitEvent, DropMoveEvent, DropOperation, DragTypes as IDragTypes, RefObject} from '@react-types/shared';
18
+ import {DropActivateEvent, DropEnterEvent, DropEvent, DropExitEvent, DropMoveEvent, DropOperation, FocusableElement, DragTypes as IDragTypes, RefObject} from '@react-types/shared';
19
19
  import {isIPad, isMac, useEffectEvent, useLayoutEffect} from '@react-aria/utils';
20
20
  import {useVirtualDrop} from './useVirtualDrop';
21
21
 
22
22
  export interface DropOptions {
23
23
  /** A ref for the droppable element. */
24
- ref: RefObject<HTMLElement | null>,
24
+ ref: RefObject<FocusableElement | null>,
25
25
  /**
26
26
  * A function returning the drop operation to be performed when items matching the given types are dropped
27
27
  * on the drop target.
@@ -72,13 +72,20 @@ const DROP_ACTIVATE_TIMEOUT = 800;
72
72
  export function useDrop(options: DropOptions): DropResult {
73
73
  let {hasDropButton, isDisabled} = options;
74
74
  let [isDropTarget, setDropTarget] = useState(false);
75
- let state = useRef({
75
+ let state = useRef<{
76
+ x: number,
77
+ y: number,
78
+ dragOverElements: Set<Element>,
79
+ dropEffect: DataTransfer['dropEffect'],
80
+ allowedOperations: DROP_OPERATION,
81
+ dropActivateTimer: ReturnType<typeof setTimeout> | undefined
82
+ }>({
76
83
  x: 0,
77
84
  y: 0,
78
85
  dragOverElements: new Set<Element>(),
79
- dropEffect: 'none' as DataTransfer['dropEffect'],
86
+ dropEffect: 'none',
80
87
  allowedOperations: DROP_OPERATION.all,
81
- dropActivateTimer: null
88
+ dropActivateTimer: undefined
82
89
  }).current;
83
90
 
84
91
  let fireDropEnter = (e: DragEvent) => {
@@ -164,10 +171,11 @@ export function useDrop(options: DropOptions): DropResult {
164
171
 
165
172
  clearTimeout(state.dropActivateTimer);
166
173
 
167
- if (typeof options.onDropActivate === 'function' && state.dropEffect !== 'none') {
174
+ if (options.onDropActivate && typeof options.onDropActivate === 'function' && state.dropEffect !== 'none') {
175
+ let onDropActivateOptions = options.onDropActivate;
168
176
  let rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
169
177
  state.dropActivateTimer = setTimeout(() => {
170
- options.onDropActivate({
178
+ onDropActivateOptions({
171
179
  type: 'dropactivate',
172
180
  x: state.x - rect.x,
173
181
  y: state.y - rect.y
@@ -315,7 +323,7 @@ export function useDrop(options: DropOptions): DropResult {
315
323
 
316
324
  let {ref} = options;
317
325
  useLayoutEffect(() => {
318
- if (isDisabled) {
326
+ if (isDisabled || !ref.current) {
319
327
  return;
320
328
  }
321
329
  return DragManager.registerDropTarget({
@@ -415,7 +423,7 @@ function getAllowedOperations(e: DragEvent) {
415
423
  }
416
424
 
417
425
  function allowedOperationsToArray(allowedOperationsBits: DROP_OPERATION) {
418
- let allowedOperations = [];
426
+ let allowedOperations: Array<DropOperation> = [];
419
427
  if (allowedOperationsBits & DROP_OPERATION.move) {
420
428
  allowedOperations.push('move');
421
429
  }
@@ -49,10 +49,16 @@ export function useDropIndicator(props: DropIndicatorProps, state: DroppableColl
49
49
  let dragSession = DragManager.useDragSession();
50
50
  let {dropProps} = useDroppableItem(props, state, ref);
51
51
  let id = useId();
52
- let getText = (key: Key) => collection.getTextValue?.(key) ?? collection.getItem(key)?.textValue;
52
+ let getText = (key: Key | null) => {
53
+ if (key == null) {
54
+ return '';
55
+ } else {
56
+ return collection.getTextValue?.(key) ?? collection.getItem(key)?.textValue ?? '';
57
+ }
58
+ };
53
59
 
54
60
  let label = '';
55
- let labelledBy: string;
61
+ let labelledBy: string | undefined;
56
62
  if (target.type === 'root') {
57
63
  label = stringFormatter.format('dropOnRoot');
58
64
  labelledBy = `${id} ${getDroppableCollectionId(state)}`;
@@ -61,8 +67,8 @@ export function useDropIndicator(props: DropIndicatorProps, state: DroppableColl
61
67
  itemText: getText(target.key)
62
68
  });
63
69
  } else {
64
- let before: Key | null;
65
- let after: Key | null;
70
+ let before: Key | null | undefined;
71
+ let after: Key | null | undefined;
66
72
  if (collection.getFirstKey() === target.key && target.dropPosition === 'before') {
67
73
  before = null;
68
74
  } else {
@@ -56,12 +56,12 @@ export interface DroppableCollectionResult {
56
56
 
57
57
  interface DroppingState {
58
58
  collection: Collection<Node<unknown>>,
59
- focusedKey: Key,
59
+ focusedKey: Key | null,
60
60
  selectedKeys: Set<Key>,
61
61
  target: DropTarget,
62
- draggingKeys: Set<Key>,
62
+ draggingKeys: Set<Key | null | undefined>,
63
63
  isInternal: boolean,
64
- timeout: ReturnType<typeof setTimeout>
64
+ timeout: ReturnType<typeof setTimeout> | undefined
65
65
  }
66
66
 
67
67
  const DROP_POSITIONS: DropPosition[] = ['before', 'on', 'after'];
@@ -72,7 +72,12 @@ const DROP_POSITIONS_RTL: DropPosition[] = ['after', 'on', 'before'];
72
72
  * based drag and drop, in addition to full parity for keyboard and screen reader users.
73
73
  */
74
74
  export function useDroppableCollection(props: DroppableCollectionOptions, state: DroppableCollectionState, ref: RefObject<HTMLElement | null>): DroppableCollectionResult {
75
- let localState = useRef({
75
+ let localState = useRef<{
76
+ props: DroppableCollectionOptions,
77
+ state: DroppableCollectionState,
78
+ nextTarget: DropTarget | null,
79
+ dropOperation: DropOperation | null
80
+ }>({
76
81
  props,
77
82
  state,
78
83
  nextTarget: null,
@@ -149,10 +154,14 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
149
154
  let {dropProps} = useDrop({
150
155
  ref,
151
156
  onDropEnter() {
152
- state.setTarget(localState.nextTarget);
157
+ if (localState.nextTarget != null) {
158
+ state.setTarget(localState.nextTarget);
159
+ }
153
160
  },
154
161
  onDropMove(e) {
155
- state.setTarget(localState.nextTarget);
162
+ if (localState.nextTarget != null) {
163
+ state.setTarget(localState.nextTarget);
164
+ }
156
165
  autoScroll.move(e.x, e.y);
157
166
  },
158
167
  getDropOperationForPoint(types, allowedOperations, x, y) {
@@ -228,7 +237,7 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
228
237
  isInternal,
229
238
  draggingKeys
230
239
  } = droppingState.current;
231
-
240
+
232
241
  // If an insert occurs during a drop, we want to immediately select these items to give
233
242
  // feedback to the user that a drop occurred. Only do this if the selection didn't change
234
243
  // since the drop started so we don't override if the user or application did something.
@@ -264,6 +273,7 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
264
273
  }
265
274
  }
266
275
  } else if (
276
+ prevFocusedKey != null &&
267
277
  state.selectionManager.focusedKey === prevFocusedKey &&
268
278
  isInternal &&
269
279
  target.type === 'item' &&
@@ -271,12 +281,12 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
271
281
  draggingKeys.has(state.collection.getItem(prevFocusedKey)?.parentKey)
272
282
  ) {
273
283
  // Focus row instead of cell when reordering.
274
- state.selectionManager.setFocusedKey(state.collection.getItem(prevFocusedKey).parentKey);
284
+ state.selectionManager.setFocusedKey(state.collection.getItem(prevFocusedKey)?.parentKey ?? null);
275
285
  setInteractionModality('keyboard');
276
286
  } else if (
277
287
  state.selectionManager.focusedKey === prevFocusedKey &&
278
- target.type === 'item' &&
279
- target.dropPosition === 'on' &&
288
+ target.type === 'item' &&
289
+ target.dropPosition === 'on' &&
280
290
  state.collection.getItem(target.key) != null
281
291
  ) {
282
292
  // If focus didn't move already (e.g. due to an insert), and the user dropped on an item,
@@ -284,7 +294,7 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
284
294
  // Also show the focus ring if the focused key is not selected, e.g. in case of a reorder.
285
295
  state.selectionManager.setFocusedKey(target.key);
286
296
  setInteractionModality('keyboard');
287
- } else if (!state.selectionManager.isSelected(state.selectionManager.focusedKey)) {
297
+ } else if (state.selectionManager.focusedKey != null && !state.selectionManager.isSelected(state.selectionManager.focusedKey)) {
288
298
  setInteractionModality('keyboard');
289
299
  }
290
300
 
@@ -294,10 +304,10 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
294
304
 
295
305
  let onDrop = useCallback((e: DropEvent, target: DropTarget) => {
296
306
  let {state} = localState;
297
-
307
+
298
308
  // Save some state of the collection/selection before the drop occurs so we can compare later.
299
309
  droppingState.current = {
300
- timeout: null,
310
+ timeout: undefined,
301
311
  focusedKey: state.selectionManager.focusedKey,
302
312
  collection: state.collection,
303
313
  selectedKeys: state.selectionManager.selectedKeys,
@@ -325,7 +335,7 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
325
335
  }, 50);
326
336
  }, [localState, defaultOnDrop, ref, updateFocusAfterDrop]);
327
337
 
328
- // eslint-disable-next-line arrow-body-style
338
+
329
339
  useEffect(() => {
330
340
  return () => {
331
341
  if (droppingState.current) {
@@ -343,7 +353,11 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
343
353
 
344
354
  let {direction} = useLocale();
345
355
  useEffect(() => {
346
- let getNextTarget = (target: DropTarget, wrap = true, horizontal = false): DropTarget => {
356
+ if (!ref.current) {
357
+ return;
358
+ }
359
+
360
+ let getNextTarget = (target: DropTarget | null | undefined, wrap = true, horizontal = false): DropTarget | null => {
347
361
  if (!target) {
348
362
  return {
349
363
  type: 'root'
@@ -351,11 +365,11 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
351
365
  }
352
366
 
353
367
  let {keyboardDelegate} = localState.props;
354
- let nextKey: Key;
368
+ let nextKey: Key | null | undefined;
355
369
  if (target?.type === 'item') {
356
- nextKey = horizontal ? keyboardDelegate.getKeyRightOf(target.key) : keyboardDelegate.getKeyBelow(target.key);
370
+ nextKey = horizontal ? keyboardDelegate.getKeyRightOf?.(target.key) : keyboardDelegate.getKeyBelow?.(target.key);
357
371
  } else {
358
- nextKey = horizontal && direction === 'rtl' ? keyboardDelegate.getLastKey() : keyboardDelegate.getFirstKey();
372
+ nextKey = horizontal && direction === 'rtl' ? keyboardDelegate.getLastKey?.() : keyboardDelegate.getFirstKey?.();
359
373
  }
360
374
  let dropPositions = horizontal && direction === 'rtl' ? DROP_POSITIONS_RTL : DROP_POSITIONS;
361
375
  let dropPosition: DropPosition = dropPositions[0];
@@ -403,13 +417,13 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
403
417
  };
404
418
  };
405
419
 
406
- let getPreviousTarget = (target: DropTarget, wrap = true, horizontal = false): DropTarget => {
420
+ let getPreviousTarget = (target: DropTarget | null | undefined, wrap = true, horizontal = false): DropTarget | null => {
407
421
  let {keyboardDelegate} = localState.props;
408
- let nextKey: Key;
422
+ let nextKey: Key | null | undefined;
409
423
  if (target?.type === 'item') {
410
- nextKey = horizontal ? keyboardDelegate.getKeyLeftOf(target.key) : keyboardDelegate.getKeyAbove(target.key);
424
+ nextKey = horizontal ? keyboardDelegate.getKeyLeftOf?.(target.key) : keyboardDelegate.getKeyAbove?.(target.key);
411
425
  } else {
412
- nextKey = horizontal && direction === 'rtl' ? keyboardDelegate.getFirstKey() : keyboardDelegate.getLastKey();
426
+ nextKey = horizontal && direction === 'rtl' ? keyboardDelegate.getFirstKey?.() : keyboardDelegate.getLastKey?.();
413
427
  }
414
428
  let dropPositions = horizontal && direction === 'rtl' ? DROP_POSITIONS_RTL : DROP_POSITIONS;
415
429
  let dropPosition: DropPosition = !target || target.type === 'root' ? dropPositions[2] : 'on';
@@ -458,12 +472,12 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
458
472
  };
459
473
 
460
474
  let nextValidTarget = (
461
- target: DropTarget,
475
+ target: DropTarget | null | undefined,
462
476
  types: Set<string>,
463
477
  allowedDropOperations: DropOperation[],
464
- getNextTarget: (target: DropTarget, wrap: boolean) => DropTarget,
478
+ getNextTarget: (target: DropTarget | null | undefined, wrap: boolean) => DropTarget | null,
465
479
  wrap = true
466
- ): DropTarget => {
480
+ ): DropTarget | null => {
467
481
  let seenRoot = 0;
468
482
  let operation: DropOperation;
469
483
  let {draggingKeys} = globalDndState;
@@ -509,18 +523,18 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
509
523
  onDropEnter(e, drag) {
510
524
  let types = getTypes(drag.items);
511
525
  let selectionManager = localState.state.selectionManager;
512
- let target: DropTarget;
526
+ let target: DropTarget | null = null;
513
527
  // Update the drop collection ref tracker for useDroppableItem's getDropOperation isInternal check
514
528
  setDropCollectionRef(ref);
515
529
 
516
530
  // When entering the droppable collection for the first time, the default drop target
517
531
  // is after the focused key.
518
- let key = selectionManager.focusedKey;
532
+ let key: Key | null | undefined = selectionManager.focusedKey;
519
533
  let dropPosition: DropPosition = 'after';
520
534
 
521
535
  // If the focused key is a cell, get the parent item instead.
522
536
  // For now, we assume that individual cells cannot be dropped on.
523
- let item = localState.state.collection.getItem(key);
537
+ let item = key != null ? localState.state.collection.getItem(key) : null;
524
538
  if (item?.type === 'cell') {
525
539
  key = item.parentKey;
526
540
  }
@@ -529,7 +543,7 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
529
543
  // But if the focused key is the first selected item, then default to before the first selected item.
530
544
  // This is to make reordering lists slightly easier. If you select top down, we assume you want to
531
545
  // move the items down. If you select bottom up, we assume you want to move the items up.
532
- if (selectionManager.isSelected(key)) {
546
+ if (key != null && selectionManager.isSelected(key)) {
533
547
  if (selectionManager.selectedKeys.size > 1 && selectionManager.firstSelectedKey === key) {
534
548
  dropPosition = 'before';
535
549
  } else {
@@ -640,19 +654,25 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
640
654
  target = nextValidTarget(null, types, drag.allowedDropOperations, getNextTarget);
641
655
  } else {
642
656
  // If on the root, go to the item a page below the top. Otherwise a page below the current item.
643
- let nextKey = keyboardDelegate.getKeyPageBelow(
644
- target.type === 'item'
645
- ? target.key
646
- : keyboardDelegate.getFirstKey()
647
- );
657
+ let targetKey = keyboardDelegate.getFirstKey?.();
658
+ if (target.type === 'item') {
659
+ targetKey = target.key;
660
+ }
661
+ let nextKey: Key | null = null;
662
+ if (targetKey != null) {
663
+ nextKey = keyboardDelegate.getKeyPageBelow(targetKey);
664
+ }
648
665
  let dropPosition = target.type === 'item' ? target.dropPosition : 'after';
649
666
 
650
667
  // If there is no next key, or we are starting on the last key, jump to the last possible position.
651
- if (nextKey == null || (target.type === 'item' && target.key === keyboardDelegate.getLastKey())) {
652
- nextKey = keyboardDelegate.getLastKey();
668
+ if (nextKey == null || (target.type === 'item' && target.key === keyboardDelegate.getLastKey?.())) {
669
+ nextKey = keyboardDelegate.getLastKey?.() ?? null;
653
670
  dropPosition = 'after';
654
671
  }
655
672
 
673
+ if (nextKey == null) {
674
+ break;
675
+ }
656
676
  target = {
657
677
  type: 'item',
658
678
  key: nextKey,
@@ -684,18 +704,21 @@ export function useDroppableCollection(props: DroppableCollectionOptions, state:
684
704
  target = nextValidTarget(null, types, drag.allowedDropOperations, getPreviousTarget);
685
705
  } else if (target.type === 'item') {
686
706
  // If at the top already, switch to the root. Otherwise navigate a page up.
687
- if (target.key === keyboardDelegate.getFirstKey()) {
707
+ if (target.key === keyboardDelegate.getFirstKey?.()) {
688
708
  target = {
689
709
  type: 'root'
690
710
  };
691
711
  } else {
692
- let nextKey = keyboardDelegate.getKeyPageAbove(target.key);
712
+ let nextKey: Key | null | undefined = keyboardDelegate.getKeyPageAbove(target.key);
693
713
  let dropPosition = target.dropPosition;
694
714
  if (nextKey == null) {
695
- nextKey = keyboardDelegate.getFirstKey();
715
+ nextKey = keyboardDelegate.getFirstKey?.();
696
716
  dropPosition = 'before';
697
717
  }
698
718
 
719
+ if (nextKey == null) {
720
+ break;
721
+ }
699
722
  target = {
700
723
  type: 'item',
701
724
  key: nextKey,
@@ -10,7 +10,8 @@
10
10
  * governing permissions and limitations under the License.
11
11
  */
12
12
 
13
- import {DOMAttributes} from '@react-types/shared';
13
+ import {AriaButtonProps} from '@react-types/button';
14
+ import {DOMAttributes} from 'react';
14
15
  import * as DragManager from './DragManager';
15
16
  // @ts-ignore
16
17
  import intlMessages from '../intl/*.json';
@@ -19,7 +20,7 @@ import {useDragModality} from './utils';
19
20
  import {useLocalizedStringFormatter} from '@react-aria/i18n';
20
21
 
21
22
  interface VirtualDropResult {
22
- dropProps: DOMAttributes
23
+ dropProps: AriaButtonProps & DOMAttributes<HTMLDivElement>
23
24
  }
24
25
 
25
26
  const MESSAGES = {
package/src/utils.ts CHANGED
@@ -24,7 +24,7 @@ export const droppableCollectionMap = new WeakMap<DroppableCollectionState, Drop
24
24
  export const DIRECTORY_DRAG_TYPE = Symbol();
25
25
 
26
26
  export function getDroppableCollectionId(state: DroppableCollectionState) {
27
- let {id} = droppableCollectionMap.get(state);
27
+ let {id} = droppableCollectionMap.get(state) || {};
28
28
  if (!id) {
29
29
  throw new Error('Droppable item outside a droppable collection');
30
30
  }
@@ -33,7 +33,7 @@ export function getDroppableCollectionId(state: DroppableCollectionState) {
33
33
  }
34
34
 
35
35
  export function getDroppableCollectionRef(state: DroppableCollectionState) {
36
- let {ref} = droppableCollectionMap.get(state);
36
+ let {ref} = droppableCollectionMap.get(state) || {};
37
37
  if (!ref) {
38
38
  throw new Error('Droppable item outside a droppable collection');
39
39
  }
@@ -52,7 +52,7 @@ export function getTypes(items: DragItem[]): Set<string> {
52
52
  return types;
53
53
  }
54
54
 
55
- function mapModality(modality: string) {
55
+ function mapModality(modality: string | null) {
56
56
  if (!modality) {
57
57
  modality = 'virtual';
58
58
  }
@@ -91,7 +91,7 @@ export function writeToDataTransfer(dataTransfer: DataTransfer, items: DragItem[
91
91
  // See e.g. https://bugs.chromium.org/p/chromium/issues/detail?id=438479.
92
92
  let groupedByType = new Map<string, string[]>();
93
93
  let needsCustomData = false;
94
- let customData = [];
94
+ let customData: Array<{}> = [];
95
95
  for (let item of items) {
96
96
  let types = Object.keys(item);
97
97
  if (types.length > 1) {
@@ -177,6 +177,9 @@ export class DragTypes implements IDragTypes {
177
177
 
178
178
  export function readFromDataTransfer(dataTransfer: DataTransfer) {
179
179
  let items: DropItem[] = [];
180
+ if (!dataTransfer) {
181
+ return items;
182
+ }
180
183
 
181
184
  // If our custom drag type is available, use that. This is a JSON serialized
182
185
  // representation of all items in the drag, set when there are multiple items
@@ -195,7 +198,7 @@ export function readFromDataTransfer(dataTransfer: DataTransfer) {
195
198
  }
196
199
 
197
200
  hasCustomType = true;
198
- } catch (e) {
201
+ } catch {
199
202
  // ignore
200
203
  }
201
204
  }
@@ -214,7 +217,7 @@ export function readFromDataTransfer(dataTransfer: DataTransfer) {
214
217
  // In the future, we may use getAsFileSystemHandle instead, but that's currently
215
218
  // only implemented in Chrome.
216
219
  if (typeof item.webkitGetAsEntry === 'function') {
217
- let entry: FileSystemEntry = item.webkitGetAsEntry();
220
+ let entry: FileSystemEntry | null = item.webkitGetAsEntry();
218
221
  // eslint-disable-next-line max-depth
219
222
  if (!entry) {
220
223
  // For some reason, Firefox includes an item with type image/png when copy
@@ -269,7 +272,10 @@ function blobToString(blob: Blob): Promise<string> {
269
272
  });
270
273
  }
271
274
 
272
- function createFileItem(file: File): FileDropItem {
275
+ function createFileItem(file: File | null): FileDropItem {
276
+ if (!file) {
277
+ throw new Error('No file provided');
278
+ }
273
279
  return {
274
280
  kind: 'file',
275
281
  type: file.type || GENERIC_TYPE,
@@ -348,7 +354,7 @@ export function setDraggingKeys(keys: Set<Key>) {
348
354
  globalDndState.draggingKeys = keys;
349
355
  }
350
356
 
351
- export function setDropCollectionRef(ref: RefObject<HTMLElement | null>) {
357
+ export function setDropCollectionRef(ref?: RefObject<HTMLElement | null>) {
352
358
  globalDndState.dropCollectionRef = ref;
353
359
  }
354
360
 
@@ -368,8 +374,8 @@ export function isInternalDropOperation(ref?: RefObject<HTMLElement | null>) {
368
374
  }
369
375
 
370
376
  type DropEffect = 'none' | 'copy' | 'link' | 'move';
371
- export let globalDropEffect: DropEffect;
372
- export function setGlobalDropEffect(dropEffect: DropEffect) {
377
+ export let globalDropEffect: DropEffect | undefined;
378
+ export function setGlobalDropEffect(dropEffect: DropEffect | undefined) {
373
379
  globalDropEffect = dropEffect;
374
380
  }
375
381