I am setting up a nested drag and drop with React-DnD. The below image gives you a better idea of my approach.
All the elements are Draggable and Droppable. Example - Field one, two, Group 1, Field one Group one, and Sub Group 1 all can be draggable and droppable.
Did:
- I can sort the parent items Field one, Field two, Group 1 - drag and drop, sortable
Need help on this:
- Need to sort all the fields that are inside the group and outside the group.
- Any item can be grouped and ungrouped.
Example:
scenario 1: User will drag the Field one group one item and drop it below Field two.
scenario 2: User will drag the Field two item and drop it inside the Group 1/Sub group 1.
Whenever I drag an item that is tracked by using the below line: while hovering on the particular item ref.current will give the particular item.
import { useRef } from "react";
import { useDrag, useDrop } from "react-dnd";
import { ItemTypes } from "./ItemTypes";
const style = {
border: "1px dashed gray",
padding: "0.5rem 1rem",
marginBottom: ".5rem",
backgroundColor: "white",
cursor: "move"
};
export const Card = ({ id, text, index, moveCard, children, type }) => {
const ref = useRef(null);
const [{ handlerId }, drop] = useDrop({
accept: ItemTypes.CARD,
collect(monitor) {
return {
handlerId: monitor.getHandlerId()
};
},
hover(item, monitor) {
if (!ref.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
// Determine rectangle on screen
const hoverBoundingRect = ref.current?.getBoundingClientRect();
// Get vertical middle
const hoverMiddleY =
(hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
// Determine mouse position
const clientOffset = monitor.getClientOffset();
// Get pixels to the top
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
moveCard(dragIndex, hoverIndex);
// Note: we're mutating the monitor item here!
// Generally it's better to avoid mutations,
// but it's good here for the sake of performance
// to avoid expensive index searches.
item.index = hoverIndex;
}
});
const [{ isDragging }, drag] = useDrag({
type: ItemTypes.CARD,
item: () => {
return { id, index };
},
collect: (monitor) => ({
isDragging: monitor.isDragging()
})
});
const opacity = isDragging ? 0 : 1;
drag(drop(ref));
return (
<div
className={type}
ref={ref}
style={{ ...style, opacity }}
data-handler-id={handlerId}
>
<div style={{ paddingBottom: '15px' }}>
{text}
</div>
{children}
</div>
);
};
I tried to drag the Field one group one item from Group 1 but the ref.current shows group 1 as a dragging item.
The below image illustrates the ref.current gives Group 1 but was dragged the Field one group one item
Working demo available here. Any help on this is really helpful for me.
note: I have been using React DnD for drag and drop hence need to use this for group items and sub-group items, can't switch to other libraries which might conflict with the existing react dnd.
I can track it while sorting it by using if (!monitor.isOver({ shallow: true }))
return; and the ref.current
gives correct item while sorting. sandbox updated. The question is when I drag some new item over the already dropped item, the ref.current gives group as a drag item when hovering the fields inside the group. How to get a current item while hovering on it?