Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DragOverlay misplaced when sorting multiple elements #901

Open
tozz opened this issue Sep 30, 2022 · 12 comments
Open

DragOverlay misplaced when sorting multiple elements #901

tozz opened this issue Sep 30, 2022 · 12 comments

Comments

@tozz
Copy link

tozz commented Sep 30, 2022

I've used the multi column multi sort example (#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.

Screen.Recording.2022-09-30.at.16.54.04.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.

@carlosloureda
Copy link

I am having the same problem. Were you able to solve this issue?

@tozz
Copy link
Author

tozz commented Dec 6, 2022

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 :)

@carlosloureda
Copy link

@tozz Thanks. I just found that the example at #588 was using outdated versions of the packages:

@dnd-kit/core@5.0.1 @dnd-kit/sortable@6.0.0 @dnd-kit/utilities@3.1.0

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).

@megos
Copy link

megos commented Jan 21, 2023

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)
}}

@kamilkazmierczakMtab
Copy link

kamilkazmierczakMtab commented Apr 5, 2023

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

@maloguertin
Copy link

it would be nice to have a onBeforeDragStart where it is safe to cause rerenders without messing with the position.

@linxianxi
Copy link

same. I don't think the cursor position is wrong, the overlay should be at the current mouse dragging location.

@williamisnotdefined
Copy link

I'm facing the same problem, fortunately the setTimeout did work for me.

@x-Foz3R-x
Copy link

x-Foz3R-x commented Jan 19, 2024

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>
  );
}

@ricardomejiasilva
Copy link

I'm facing the same problem, fortunately the setTimeout did work for me.
@williamisnotdefined williamisnotdefined
could you provide your example?

@williamisnotdefined
Copy link

@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);
      }}
      ...
>

@williamisnotdefined
Copy link

williamisnotdefined commented Jul 4, 2024

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants