dnd-kit
dnd-kit copied to clipboard
DragOverlay misplaced when sorting multiple elements
I've used the multi column multi sort example (https://github.com/clauderic/dnd-kit/pull/588) but I can't figure out how to actually get the overlay to get to the right position when removing more than one node from the list, as happens in the storybook.
https://user-images.githubusercontent.com/705677/193299052-33b7ceec-da18-4589-a25e-ea6d7c2e002e.mov
I made a minimal example here https://github.com/tozz/dnd-multisort where you can yarn start
to test in your browser, the files are in src/js/
and component.tsx
is the main entry point for the DnD stuff. I tried to keep the example as minimal as possible.
I am having the same problem. Were you able to solve this issue?
I am having the same problem. Were you able to solve this issue?
Unfortunately not, I moved on to other things but it would be great if someone has a fix :)
@tozz Thanks. I just found that the example at #588 was using outdated versions of the packages:
@dnd-kit/[email protected] @dnd-kit/[email protected] @dnd-kit/[email protected]
Using those versions seem to fix the problem of the cursor position. But now some things (like moving into another container are broken on my example).
Not so a good code, but I come up with a workaround.
It is how to delay updating the state on onDragStart
.
In this example, delay updating filteredItems
to prevent the number of items from changing.
This will help calculate the correct position.
onDragStart={e => {
setTimeout(() => {
doSomething()
}, 1)
}}
Did someone find other solution to this because using setTimeout creates a lot of other issues and wrapping it with promise does not solve problem because delaying whole events like onDragEnd
until execution of onDragStart
breaks dnd behavior and delaying only parts of it creates yet another issues. One of these issues is that user can start dragging something and drop it so quickly (very hard to reproduce) that "onDragEnd" event is not called at all
it would be nice to have a onBeforeDragStart where it is safe to cause rerenders without messing with the position.
same. I don't think the cursor position is wrong, the overlay should be at the current mouse dragging location.
I'm facing the same problem, fortunately the setTimeout did work for me.
I have pretty simple workaround that just shifts overlay to correct position :)
Keep in mind that you have to sort selectedIds from top to bottom in order for it to be correctly be calculated.
`drag-overlay.tsx`
type props = {
activeId: string | null;
selectedIds: string[];
};
export function MyDragOverlay({ activeId, selectedIds }: props) {
// Calculates offset based on witch index is active item in a selection and shifts it times items height
// ITEM_HEIGHT is height plus any gap between items
const offset = activeId && selectedIds.length > 1 ? selectedIds.indexOf(activeId) * ITEM_HEIGHT : 0;
return (
<DragOverlay style={{ translate: `0 ${offset}px` }}>
{"Your overlay"}
</DragOverlay>
);
}
I'm facing the same problem, fortunately the setTimeout did work for me. @williamisnotdefined williamisnotdefined could you provide your example?
@ricardomejiasilva omg, sorry for the late answer, i didn't see your comment!
<DndContext
...
onDragStart={(event) => {
/**
* This tricky timeout is needed
* to prevent the overlay from being misplaced
* in relation to the mouse cursor
*/
setTimeout(() => {
handleDragStart(event);
}, 1);
}}
...
>
Not so a good code, but I come up with a workaround. It is how to delay updating the state on
onDragStart
.In this example, delay updating
filteredItems
to prevent the number of items from changing. This will help calculate the correct position.onDragStart={e => { setTimeout(() => { doSomething() }, 1) }}
@megos I found a better way, we dont need and we shouldn't use setTimeout as @kamilkazmierczakMtab has mentioned, I fixed the case by adding the modifier snapCenterToCursor
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
onDragCancel={handleDragCancel}
modifiers={[snapCenterToCursor]} // << it should fix the case, if I am not mistaken
measuring={{
droppable: { strategy: MeasuringStrategy.Always },
}}
>
Plus, I had to remove the modifiers of my DragOverlay to make it work properly. Hope this help you guys!