diff --git a/src/hooks/dragAndDrop.tsx b/src/hooks/dragAndDrop.tsx new file mode 100644 index 0000000..f142e43 --- /dev/null +++ b/src/hooks/dragAndDrop.tsx @@ -0,0 +1,52 @@ +import { useState, useRef, useCallback, useEffect } from "react"; + +type Position = { + x: number; + y: number; +}; + +type DragAndDropConfig = { + longPressEnabled?: boolean; + longPressDelay?: number; + dragHandleSelector?: string; +}; + +type DragAndDropState = { + isDragging: boolean; + currentIndex: number | null; + targetIndex: number | null; +}; + +export function useDragAndDrop( + items: T[], + onReorder: (newOrder: T[]) => void, + config: DragAndDropConfig = {}, +) { + const { + longPressEnabled = false, + longPressDelay = 300, + dragHandleSelector, + } = config; + + const itemRefs = useRef<(HTMLElement | null)[]>([]); + const containerRef = useRef(null); + + const [dragState, setDragState] = useState({ + isDragging: false, + currentIndex: null, + targetIndex: null, + }); + + const getItemProps = (index: number) => { + return { style: {} }; + }; + + return { + containerRef, + itemRefs, + isDragging: dragState.isDragging, + currentIndex: dragState.currentIndex, + targetIndex: dragState.targetIndex, + getItemProps, + }; +} diff --git a/src/hooks/tests/dragAndDropTest.cy.tsx b/src/hooks/tests/dragAndDropTest.cy.tsx new file mode 100644 index 0000000..4519eef --- /dev/null +++ b/src/hooks/tests/dragAndDropTest.cy.tsx @@ -0,0 +1,122 @@ +import { useState } from "react"; +import type { RefObject } from "react"; +import { useDragAndDrop } from "../dragAndDrop"; +import styles from "./dragAndDropTest.module.css"; +import clsx from "clsx"; + +type Item = { + id: string; + content: string; + color: string; +}; + +const initialItems: Item[] = [ + { id: "1", content: "Item 1", color: "firebrick" }, + { id: "2", content: "Item 2", color: "mediumseagreen" }, + { id: "3", content: "Item 3", color: "orange" }, + { id: "4", content: "Item 4", color: "deepskyblue" }, + { id: "5", content: "Item 5", color: "mediumorchid" }, +]; + +function TestDragAndDrop() { + const [items, setItems] = useState(initialItems); + const [useLongPress, setUseLongPress] = useState(false); + const [useDragHandle, setUseDragHandle] = useState(false); + + const handleReorder = (newItems: Item[]) => { + setItems(newItems); + }; + + const { containerRef, getItemProps, isDragging, currentIndex, targetIndex } = + useDragAndDrop(items, handleReorder, { + longPressEnabled: useLongPress, + dragHandleSelector: useDragHandle ? ".drag-handle" : undefined, + }); + + return ( +
+
} + className={styles.itemsWrapper} + > + {items.map((item, index) => ( +
+ {item.content} + {useDragHandle &&
} +
+ ))} +
+ +
+ +
+ + + +
+ +
+ +
+

Dragging: {isDragging ? "True" : "False"}

+

+ Status: + {isDragging && ( +

+ Moving Item {currentIndex !== null ? items[currentIndex].id : ""} + {targetIndex !== null ? ` to position ${targetIndex}` : ""} +

+ )} +

+
+ +
+ +
+

Current order:

+
+          {JSON.stringify(
+            items.map((i) => i.id),
+            null,
+            2,
+          )}
+        
+
+
+ ); +} + +describe("Drag and Drop Component Test", () => { + beforeEach(() => { + cy.mount(); + cy.viewport(500, 600); + }); + + it("should drag and drop", () => {}); +}); diff --git a/src/hooks/tests/dragAndDropTest.module.css b/src/hooks/tests/dragAndDropTest.module.css new file mode 100644 index 0000000..ca0b5f6 --- /dev/null +++ b/src/hooks/tests/dragAndDropTest.module.css @@ -0,0 +1,43 @@ +.wrapper { +} + +.itemsWrapper { +} + +.draggableItem { + display: flex; + width: 200px; + height: 50px; + justify-content: space-between; + align-items: center; +} + +.draggableItem .content { + flex: 1; + margin-left: 20px; +} + +.draggableItem .handle { + width: 15px; + height: 30px; + background-color: rgba(0, 0, 0, 0.3); + flex-shrink: 0; + margin-right: 10px; + cursor: grab; +} + +.dragging { + opacity: 0.8; + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3); +} + +.controls { + display: flex; + gap: 25px; +} + +.status { +} + +.currentOrder { +}