Setup test component for drag and drop hook.

This commit is contained in:
Jay
2025-07-23 17:57:08 -04:00
parent 2737c6bf9e
commit bf9818a9aa
3 changed files with 217 additions and 0 deletions
+52
View File
@@ -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<T>(
items: T[],
onReorder: (newOrder: T[]) => void,
config: DragAndDropConfig = {},
) {
const {
longPressEnabled = false,
longPressDelay = 300,
dragHandleSelector,
} = config;
const itemRefs = useRef<(HTMLElement | null)[]>([]);
const containerRef = useRef<HTMLElement | null>(null);
const [dragState, setDragState] = useState<DragAndDropState>({
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,
};
}
+122
View File
@@ -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<Item[]>(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 (
<div className={styles.wrapper}>
<div
ref={containerRef as RefObject<HTMLDivElement>}
className={styles.itemsWrapper}
>
{items.map((item, index) => (
<div
key={item.id}
data-cy={`draggable-item-${item.id}`}
{...getItemProps(index)}
className={clsx(
styles.draggableItem,
isDragging && currentIndex === index && styles.dragging,
)}
style={{
...getItemProps(index).style,
backgroundColor: item.color,
}}
>
<span className={styles.content}>{item.content}</span>
{useDragHandle && <div className={styles.handle}></div>}
</div>
))}
</div>
<hr />
<div className={styles.controls}>
<label>
<input
type="checkbox"
checked={useLongPress}
onChange={() => setUseLongPress(!useLongPress)}
/>
Use Long Press
</label>
<label>
<input
type="checkbox"
checked={useDragHandle}
onChange={() => setUseDragHandle(!useDragHandle)}
/>
Use Drag Handle
</label>
</div>
<hr />
<div className={styles.status}>
<p>Dragging: {isDragging ? "True" : "False"}</p>
<p>
Status:
{isDragging && (
<p>
Moving Item {currentIndex !== null ? items[currentIndex].id : ""}
{targetIndex !== null ? ` to position ${targetIndex}` : ""}
</p>
)}
</p>
</div>
<hr />
<div className={styles.currentOrder}>
<p>Current order:</p>
<pre>
{JSON.stringify(
items.map((i) => i.id),
null,
2,
)}
</pre>
</div>
</div>
);
}
describe("Drag and Drop Component Test", () => {
beforeEach(() => {
cy.mount(<TestDragAndDrop />);
cy.viewport(500, 600);
});
it("should drag and drop", () => {});
});
@@ -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 {
}