Setup test component for drag and drop hook.
This commit is contained in:
@@ -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,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user