aboutsummaryrefslogtreecommitdiffstats
path: root/apps/web/lib
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/lib')
-rw-r--r--apps/web/lib/drag-and-drop.ts89
1 files changed, 89 insertions, 0 deletions
diff --git a/apps/web/lib/drag-and-drop.ts b/apps/web/lib/drag-and-drop.ts
new file mode 100644
index 00000000..03a9e7c3
--- /dev/null
+++ b/apps/web/lib/drag-and-drop.ts
@@ -0,0 +1,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,
+ };
+}