1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
import { DraggableData, DraggableEvent } from "react-draggable";
export interface DragState {
// The id of the element that is being dragged
dragSourceId: string | null;
// The id of the element that is currently being hovered over
dragTargetId: string | null;
// The position of the elements being dragged such that on drag over, we can revert the position.
initialX: number;
initialY: number;
}
export interface DragAndDropFunctions {
handleDragStart: (e: DraggableEvent, data: DraggableData) => void;
handleDrag: (e: DraggableEvent) => void;
handleDragEnd: () => void;
dragState: DragState;
}
export function useDragAndDrop(
dragSourceIdAttribute: string,
dragTargetIdAttribute: string,
callback: (dragSourceId: string, dragTargetId: string) => void,
): DragAndDropFunctions {
const initialState: DragState = {
dragSourceId: null,
dragTargetId: null,
initialX: 0,
initialY: 0,
};
let currentState: DragState = initialState;
function handleDragStart(e: DraggableEvent, data: DraggableData): void {
const { node } = data;
const id = node.getAttribute(dragSourceIdAttribute);
currentState = {
...initialState,
dragSourceId: id,
initialX: data.x,
initialY: data.y,
};
}
function handleDrag(e: DraggableEvent): void {
const { dragTargetId } = currentState;
const { target } = e;
// Important according to the sample I found
e.preventDefault();
if (target) {
const id = (target as HTMLElement).getAttribute(dragTargetIdAttribute);
if (id !== dragTargetId) {
currentState.dragTargetId = id;
}
}
}
function handleDragEnd(): void {
const { dragSourceId, dragTargetId } = currentState;
if (dragSourceId && dragTargetId && dragSourceId !== dragTargetId) {
/*
As Draggable tries to setState when the
component is unmounted, it is needed to
push onCombine to the event loop queue.
onCombine would be run after setState on
Draggable so it would fix the issue until
they fix it on their end.
*/
setTimeout(() => {
console.log(dragSourceId, dragTargetId);
callback(dragSourceId, dragTargetId);
}, 0);
}
currentState = initialState;
}
return {
dragState: currentState,
handleDragStart,
handleDrag,
handleDragEnd,
};
}
|