Sortable
Sortable copied to clipboard
Incorrect returning animation
Reproduction
In the "Simple list" example https://sortablejs.github.io/sortablejs/
Steps to Reproduce
Summary of steps if applicable.
- Drag item 1 to bottom
- Keep drag state move mouse out of the list
- Release drag
- The item 1 "return to list animation" is return to the top (original item 1 position) instead of bottom (the new position)
Describe the bug
Return to list animation is incorrect
Expected behavior
The animation should return item to new position
Version
Lastest version using in the sample page
Additional Context
Same here. Any updates with this bug?
This is affecting us as well and the incorrect animation ends up confusing the user. Not a good user experience :(
If there is a way to disable the animation, that would be an acceptable workaround too but there is no way to disable the animation either.
For future visistors & googlers (like me):
The reason for this issue is how the browser-native drag&drop API handles ghost images. There are two ways to fix this.
Fix 1: Disable native drag&drop altogether
This can be done by passing the forceFallback: true
option to a Sortable instance. The fallback is probably still around from times before browsers implemented native drag&drop (which is a long time ago). Note that I'm not aware whether enforcing the fallback implementation will somehow degrade Sortable.js' performance or reliability.
Fix 2: Replace the drag image with something transparent
This can be done during the browser's dragstart
event, which can only be accessed through a plugin in Sortable.js. (Sortable's own dragstart
event gives access to the browser-native event, but fires too late to still be able to replace the drag image.)
Below is a plugin that will do so. It has to be mounted by running Sortable.mount(NoDragImagePlugin)
. When mounted, it can be activated in any Sortable.js instance by passing a noDragImage: true
option.
See the plugin in action in this Codepen.
class NoDragImagePlugin {
static pluginName = "noDragImage";
// We use a blank canvas as the replacement drag image
static _blankCanvas = document.createElement("canvas");
static {
// Make the canvas as inaccessible as possible...
this._blankCanvas.setAttribute("aria-hidden", "true");
this._blankCanvas.width = 1;
this._blankCanvas.height = 1;
this._blankCanvas.style.opacity = "0";
this._blankCanvas.style.position = "absolute";
this._blankCanvas.style.pointerEvents = "none";
// ...because we actually need to inject the placeholder somewhere
// in the DOM, or otherwise Chrome will show a fallback image
document.body.appendChild(this._blankCanvas);
}
dragStart(event) {
event.originalEvent.dataTransfer.setDragImage(
NoDragImagePlugin._blankCanvas,
0,
0
);
}
}
Alternative solution here is to make any place on the document to accept the drop (sortable handles it anyway just don't mark it as accepted for the browser).
To do this we can simply listen dragover
and call preventDefault()
on its event.
document.addEventListener('dragover', (event) => {
event.preventDefault()
})
I got this workaround after the following reading: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations#performing_a_drop
I'm not yet sure about the circumstances of doing so, but sharing with you just in case ;).
@loilo you are awesome...... thank you