Dnd 3.0 Migration
Dnd 3.0 separates file-drop and sortable entry points, removes controller-owned rollback, and hardens DOM ownership, callback snapshots, configuration, keyboard controls, and disposal.
Use focused entry points
- import { createDropZone, createSortable } from '@vielzeug/dnd';
+ import { createDropZone } from '@vielzeug/dnd/drop';
+ import { createSortable } from '@vielzeug/dnd/sortable';The root remains available for existing imports. Focused subpaths also export their relevant errors and Disposable type and support strict NodeNext consumers.
Move rollback to application history
- onReorder: ({ ids, setRevert }) => {
- setOrder(ids);
- setRevert(() => restoreOrder());
+ onReorder: ({ before, after, item }) => {
+ history.push({ before, item });
+ setOrder(after);
}
- sortable.revert();
+ history.rollback();scope.revert(), sortable.revert(), and setRevert() are removed. Cross-container onMove events add sourceBeforeIds and targetBeforeIds so one application transaction can restore both lists.
Rename DOM reconciliation
- sortable.sync();
+ sortable.refresh();refresh() restores semantics from elements no longer returned by items() before marking the current direct-child set. Duplicate item keys are excluded, and applyReorder() throws DndError instead of silently dropping duplicate backing records.
Recheck interaction boundaries
onBeforeReordernow receives frozen order snapshots before drag or keyboard DOM mutation.- Reorder, move, and interaction snapshots are frozen; callback failures cannot interrupt Dnd state transitions.
- Keyboard sorting ignores interactive descendants unless they match the configured handle.
- Native touch scrolling is preserved unless the sortable scope enables touch input;
touch.activationDistanceconfigures Gesture's shared two-dimensional pointer recognizer. - Disposed scopes reject new sortable registrations.
maxFilesmust be a non-negative safe integer; accept patterns and auto-scroll numbers are validated during construction.paste: truelistens on the drop-zone element instead of globally onwindow.- Disposing a validating drop zone transitions
validatingtofalse.
2.0
Replace the global touch shim
createTouchDragShim() and TouchDragOptions were removed. Enable touch on each sortable scope instead.
// Before
createTouchDragShim();
const scope = createSortableScope();
// After
const scope = createSortableScope({ touch: true });Touch input now uses Gesture's Pointer Event recognizer and only accepts sortable items registered to its scope. Its default preview is an inert outline; touch.preview may return an element that Dnd clones for the transient preview.
Move cross-list persistence to the scope
Cross-container moves no longer call onReorder once for each affected list. Persist the transaction from scope.onMove, which receives the moved item and both final orders. Local keyboard and single-list drag reorders continue to call each sortable's onReorder.
const scope = createSortableScope({
onMove: ({ itemId, sourceIds, targetIds }) => {
persistMove(itemId, sourceIds, targetIds);
},
});