@react-aria/dnd 3.7.4 → 3.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/DragManager.main.js +25 -13
- package/dist/DragManager.main.js.map +1 -1
- package/dist/DragManager.mjs +25 -13
- package/dist/DragManager.module.js +25 -13
- package/dist/DragManager.module.js.map +1 -1
- package/dist/DragPreview.main.js +9 -4
- package/dist/DragPreview.main.js.map +1 -1
- package/dist/DragPreview.mjs +10 -5
- package/dist/DragPreview.module.js +10 -5
- package/dist/DragPreview.module.js.map +1 -1
- package/dist/ListDropTargetDelegate.main.js +5 -4
- package/dist/ListDropTargetDelegate.main.js.map +1 -1
- package/dist/ListDropTargetDelegate.mjs +5 -4
- package/dist/ListDropTargetDelegate.module.js +5 -4
- package/dist/ListDropTargetDelegate.module.js.map +1 -1
- package/dist/ar-AE.main.js.map +1 -1
- package/dist/ar-AE.module.js.map +1 -1
- package/dist/bg-BG.main.js.map +1 -1
- package/dist/bg-BG.module.js.map +1 -1
- package/dist/constants.main.js +3 -3
- package/dist/constants.main.js.map +1 -1
- package/dist/constants.mjs +3 -3
- package/dist/constants.module.js +3 -3
- package/dist/constants.module.js.map +1 -1
- package/dist/cs-CZ.main.js.map +1 -1
- package/dist/cs-CZ.module.js.map +1 -1
- package/dist/da-DK.main.js.map +1 -1
- package/dist/da-DK.module.js.map +1 -1
- package/dist/de-DE.main.js.map +1 -1
- package/dist/de-DE.module.js.map +1 -1
- package/dist/el-GR.main.js.map +1 -1
- package/dist/el-GR.module.js.map +1 -1
- package/dist/en-US.main.js.map +1 -1
- package/dist/en-US.module.js.map +1 -1
- package/dist/es-ES.main.js.map +1 -1
- package/dist/es-ES.module.js.map +1 -1
- package/dist/et-EE.main.js.map +1 -1
- package/dist/et-EE.module.js.map +1 -1
- package/dist/fi-FI.main.js.map +1 -1
- package/dist/fi-FI.module.js.map +1 -1
- package/dist/fr-FR.main.js.map +1 -1
- package/dist/fr-FR.module.js.map +1 -1
- package/dist/he-IL.main.js.map +1 -1
- package/dist/he-IL.module.js.map +1 -1
- package/dist/hr-HR.main.js.map +1 -1
- package/dist/hr-HR.module.js.map +1 -1
- package/dist/hu-HU.main.js.map +1 -1
- package/dist/hu-HU.module.js.map +1 -1
- package/dist/it-IT.main.js.map +1 -1
- package/dist/it-IT.module.js.map +1 -1
- package/dist/ja-JP.main.js.map +1 -1
- package/dist/ja-JP.module.js.map +1 -1
- package/dist/ko-KR.main.js.map +1 -1
- package/dist/ko-KR.module.js.map +1 -1
- package/dist/lt-LT.main.js.map +1 -1
- package/dist/lt-LT.module.js.map +1 -1
- package/dist/lv-LV.main.js.map +1 -1
- package/dist/lv-LV.module.js.map +1 -1
- package/dist/nb-NO.main.js.map +1 -1
- package/dist/nb-NO.module.js.map +1 -1
- package/dist/nl-NL.main.js.map +1 -1
- package/dist/nl-NL.module.js.map +1 -1
- package/dist/pl-PL.main.js.map +1 -1
- package/dist/pl-PL.module.js.map +1 -1
- package/dist/pt-BR.main.js.map +1 -1
- package/dist/pt-BR.module.js.map +1 -1
- package/dist/pt-PT.main.js.map +1 -1
- package/dist/pt-PT.module.js.map +1 -1
- package/dist/ro-RO.main.js.map +1 -1
- package/dist/ro-RO.module.js.map +1 -1
- package/dist/ru-RU.main.js.map +1 -1
- package/dist/ru-RU.module.js.map +1 -1
- package/dist/sk-SK.main.js.map +1 -1
- package/dist/sk-SK.module.js.map +1 -1
- package/dist/sl-SI.main.js.map +1 -1
- package/dist/sl-SI.module.js.map +1 -1
- package/dist/sr-SP.main.js.map +1 -1
- package/dist/sr-SP.module.js.map +1 -1
- package/dist/sv-SE.main.js.map +1 -1
- package/dist/sv-SE.module.js.map +1 -1
- package/dist/tr-TR.main.js.map +1 -1
- package/dist/tr-TR.module.js.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/uk-UA.main.js.map +1 -1
- package/dist/uk-UA.module.js.map +1 -1
- package/dist/useAutoScroll.main.js +5 -5
- package/dist/useAutoScroll.main.js.map +1 -1
- package/dist/useAutoScroll.mjs +5 -5
- package/dist/useAutoScroll.module.js +5 -5
- package/dist/useAutoScroll.module.js.map +1 -1
- package/dist/useClipboard.main.js +13 -7
- package/dist/useClipboard.main.js.map +1 -1
- package/dist/useClipboard.mjs +13 -7
- package/dist/useClipboard.module.js +13 -7
- package/dist/useClipboard.module.js.map +1 -1
- package/dist/useDrag.main.js +2 -2
- package/dist/useDrag.main.js.map +1 -1
- package/dist/useDrag.mjs +2 -2
- package/dist/useDrag.module.js +2 -2
- package/dist/useDrag.module.js.map +1 -1
- package/dist/useDrop.main.js +5 -4
- package/dist/useDrop.main.js.map +1 -1
- package/dist/useDrop.mjs +5 -4
- package/dist/useDrop.module.js +5 -4
- package/dist/useDrop.module.js.map +1 -1
- package/dist/useDropIndicator.main.js +3 -2
- package/dist/useDropIndicator.main.js.map +1 -1
- package/dist/useDropIndicator.mjs +3 -2
- package/dist/useDropIndicator.module.js +3 -2
- package/dist/useDropIndicator.module.js.map +1 -1
- package/dist/useDroppableCollection.main.js +33 -19
- package/dist/useDroppableCollection.main.js.map +1 -1
- package/dist/useDroppableCollection.mjs +33 -19
- package/dist/useDroppableCollection.module.js +33 -19
- package/dist/useDroppableCollection.module.js.map +1 -1
- package/dist/useVirtualDrop.main.js.map +1 -1
- package/dist/useVirtualDrop.module.js.map +1 -1
- package/dist/utils.main.js +5 -3
- package/dist/utils.main.js.map +1 -1
- package/dist/utils.mjs +5 -3
- package/dist/utils.module.js +5 -3
- package/dist/utils.module.js.map +1 -1
- package/dist/zh-CN.main.js.map +1 -1
- package/dist/zh-CN.module.js.map +1 -1
- package/dist/zh-TW.main.js.map +1 -1
- package/dist/zh-TW.module.js.map +1 -1
- package/package.json +13 -13
- package/src/DragManager.ts +26 -24
- package/src/DragPreview.tsx +18 -12
- package/src/ListDropTargetDelegate.ts +8 -5
- package/src/useAutoScroll.ts +6 -6
- package/src/useClipboard.ts +12 -6
- package/src/useDrag.ts +5 -2
- package/src/useDrop.ts +17 -9
- package/src/useDropIndicator.ts +10 -4
- package/src/useDroppableCollection.ts +62 -39
- package/src/useVirtualDrop.ts +3 -2
- 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<
|
|
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'
|
|
86
|
+
dropEffect: 'none',
|
|
80
87
|
allowedOperations: DROP_OPERATION.all,
|
|
81
|
-
dropActivateTimer:
|
|
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
|
-
|
|
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
|
}
|
package/src/useDropIndicator.ts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
157
|
+
if (localState.nextTarget != null) {
|
|
158
|
+
state.setTarget(localState.nextTarget);
|
|
159
|
+
}
|
|
153
160
|
},
|
|
154
161
|
onDropMove(e) {
|
|
155
|
-
|
|
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)
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
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,
|
package/src/useVirtualDrop.ts
CHANGED
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
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
|
|
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
|
|
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
|
|