Skip to content

Respect put: false on the revert-to-origin path#2465

Open
nandastone wants to merge 1 commit intoSortableJS:masterfrom
nandastone:fix/respect-put-false-on-revert
Open

Respect put: false on the revert-to-origin path#2465
nandastone wants to merge 1 commit intoSortableJS:masterfrom
nandastone:fix/respect-put-false-on-revert

Conversation

@nandastone
Copy link
Copy Markdown

@nandastone nandastone commented Apr 13, 2026

group.put: false is documented as preventing a sortable from receiving elements. It works correctly for cross-list drops from other sortables, but is silently ignored when a dragged item is reverted back to its own sortable.

This matters for clone-source lists (e.g. a sidebar with pull: 'clone', put: false, sort: false), items can be dragged out as clones, but nothing should be dropped back in. Currently, dragging an item out and then hovering back over the source triggers the revert branch, which bypasses checkPut entirely and reinserts dragEl into the source.

Sidebar                    Playlist

┌───────────┐              ┌───────────┐
│  Image    │              │  Scene 1  │
│  Video    │              │  Scene 2  │
│  Audio  │              │  Scene 3  │
└───────────┘              └───────────┘

1. Drag Image into Playlist (clone stays in Sidebar):

┌───────────┐              ┌───────────┐
│  Image    │              │  Scene 1  │
│  Video    │              │ [Image]   │
│  Audio  │              │  Scene 2  │
└───────────┘              │  Scene 3  │
                           └───────────┘

2. Hover cursor back over Sidebar:

┌───────────┐              ┌───────────┐
│ [Image]   │  <────────   │  Scene 1  │
│  Image    │   revert     │  Scene 2  │
│  Video    │   ignores    │  Scene 3  │
│  Audio  │   put:false  └───────────┘
└───────────┘
 ↑ dragEl forced back in,
   source now has both the
   clone AND the original

The non-owner branch of _onDragOver correctly gates on group.checkPut. The owner branch does not — it only checks canSort:

(isOwner
    ? canSort || (revert = parentEl !== rootEl)
    : putSortable === this || (checkPull(...) && group.checkPut(...))
)

The asymmetry means put: false is enforced everywhere except the one code path where the source sortable acts as its own drop target.

Proposed fix:

Add group.checkPut to the owner branch so the revert condition mirrors the non-owner branch:

? canSort || ((revert = parentEl !== rootEl) && group.checkPut(this, activeSortable, dragEl, evt))

This change only affects sortables that explicitly declare put: false. The default (put: true or unset) is unchanged because checkPut returns true.

When a dragged item has left its source sortable and the cursor hovers
back over it, _onDragOver enters the "revert" branch (line 1152) to move
dragEl back to its origin. This branch checks `canSort` but never checks
`group.checkPut`, so `put: false` is silently ignored for the owner
sortable.

The non-owner branch (line 1154-1158) already gates on `checkPut`. This
change makes the owner branch symmetric: revert only proceeds if
`checkPut` also allows it. Lists that declare `put: false` will no longer
have their own items forcibly reinserted during a cross-list drag.

Backward compatibility: only affects sortables that explicitly set
`put: false`. The default (`put: true` or unset) is unchanged, because
`checkPut` returns true.
@nandastone
Copy link
Copy Markdown
Author

Unsure if I should add a new Testcafe fixture for this. Existing tests will catch any regressions. Please advise.

nandastone added a commit to nandastone/vue-draggable-plus that referenced this pull request Apr 13, 2026
Externalize sortablejs as a peer dependency instead of bundling it into
the dist. Consumers share a single sortablejs instance, so plugin
registration via Sortable.mount() works from consumer code.

Add three SortableJS plugins (src/plugins.ts) mounted at module load:
- CloneGhost: destination-specific drag preview on cross-list entry.
- HideOnLeave: hides placeholder when cursor exits destination rect.
- BodyClass: toggles body.sortable-dragging during any drag.

Add draggedData reactive ref on UseDraggableReturn. Add cancellable
onAdd (return false to skip auto-insert for cross-type drops).

Dist is checked in so git-dep consumers get the built output.

Upstream sortablejs bug: SortableJS/Sortable#2465.
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

Successfully merging this pull request may close these issues.

1 participant