Releases: kindintelligence/dioxus-dnd
Release list
dioxus-dnd 3.1.0
Added
- Stable-ID sortable kernel.
SortableProvider,SortableGroup,
SortableCollection, andSortableItembuild sortable collections on the
shared core. Reorder events report stable identities, source and target
groups, item-or-background targets, and placement intent. Empty groups are
keyboard reachable, background drops append, and explicit group IDs occupy
a namespace disjoint from automatic IDs.project_layoutderives
variable-size previews from measured slots, while the index-based list and
grid APIs remain available. - Checked model helpers.
try_apply_clone_or_moveand
try_apply_list_clone_or_movereject unsupported effects without mutation,
while the unprefixed helpers retain their existing 3.x signatures. - Composable activation.
ActivationPolicycombines handle, surface, or
manual activation with distance, delay, or either constraints.
DragHandlesupplies an accessible activator andNoDragprotects nested
interactive content. - Collision, effect, and lifecycle policy. Providers accept configurable
collision and release policy with ranked custom detectors, sticky hover,
and configurable recovery. Targets can negotiateDropEffectsthrough a
richDropQuery. StableDragIdvalues anduse_dnd_monitorexpose the
Started, Moved, TargetChanged, Dropped, and Cancelled lifecycle without
changingDropOutcome. Custom sources can start identified drags with
DragStartandDndContext::start_with_id, inspect active snapshots, and
cancel with monitor-visible reasons. - Selection ranges.
Selectionnow supports anchored Shift ranges,
additive ranges, and keyboard range movement. - Click-to-upload file drop zones. Clicking
FileDropZoneopens the
native multi-file picker. Picker selections share the existing filtering,
rejection, andon_filespath with OS drops, while the wrapper remains
headless and receives no library-owned visual styles. - Multi-window ownership and wiring primitives.
use_dnd_modelcreates
app-wide state under process-lived unsynchronized and synchronized owners;
DndScopegives reclaimable dynamic state the same correct owner pair.
With thedesktopfeature,MultiWindowProviderstructurally installs the
geometry feed, drag provider, and host bridge in their required order and
warns when no world is present or when it was incorrectly nested beneath
the old same-type provider.DndWorld::vdompre-seeds spawned windows with
that world while preserving ordinary root-context chaining. - Release and compatibility automation. CI now covers formatting,
documentation, the full Rust feature surface, browser regressions, the
release gallery, standalone desktop examples, the Rust 1.85 core MSRV,
Windows, macOS, packaging, dependency policy, and SemVer. A required
compatibility job runs the full Rust suite against published Dioxus
0.8.0-alpha.1, while the supported and locked release line remains Dioxus
0.7.10. Version tags validate the manifest, lockfiles, changelog, and
protectedmainhead before crates.io Trusted Publishing and GitHub Release
creation.
Changed
- Continuous coordinated auto-scroll. Auto-scroll now runs from one
elapsed-time clock, continues while the pointer rests in an edge band, and
hands nested scrolling from an inner container at its boundary to the next
containing surface. New code can set exactspeed_px_per_second; the 3.x
speedprop retains its nominal-per-frame contract. - Accessible file zones.
FileDropZonehas button semantics, Enter and
Space activation, an accessible label, a configurablemultiplepicker,
and a disabled state. - Dioxus alpha canary. CI now checks source compatibility against
0.8.0-alpha.1. - Dependency baseline. Committed lockfiles now verify Dioxus
0.7.10,
futures-util0.3.34, Serde1.0.229, serde_json1.0.151, Tokio
1.53.1, webbrowser1.2.2, and the direct Linux integration against
x11rb0.14. The root lockfile also selects non-yanked chacha200.10.2
and spin0.9.9. The browser suite uses Playwright1.62.1and Dioxus CLI
0.7.10. - CI and deployment safety. Every Cargo release check uses the committed
lockfiles, third-party actions are pinned to immutable revisions, and gallery
deployment waits for successfulmainCI. The weekly upstream canary keeps
released Dioxus 0.7 failures visible while treating Dioxus git-main churn as
an informational early warning. - Dependency maintenance policy. Dependabot groups weekly Cargo, browser,
and GitHub Actions updates againstdevelopment.cargo-denyenforces
advisory, license, duplicate, wildcard, registry, and git-source policy,
with explicit reasons for the Dioxus Desktop 0.7 GTK3 advisories that cannot
be upgraded independently.
Fixed
-
Post-review Dioxus correctness. Caller-owned
DndContext::from_parts
stores remain authoritative across direct writes and sibling wrappers.
Individual Dioxus style-property attributes can no longer replace drag,
overlay, settle, or FLIP invariants. Stable sortable keyboard drops preserve
GridSwapintent and can append to populated groups, and rejected
non-primary handle presses cannot authorize a later surface press. -
Dioxus 0.7 renderer and reactivity contracts. Production now enables
Dioxus'smountedcapability required by geometry measurement. Overlay
settle ownership, receiver-fed auto-scroll, board/bridge acceptance,
labels, and provider policy follow live props without mount-time captures
or render-time signal synchronization. -
Reactive component identity and forwarded invariants. Explicit
drag/zone/group ids replace keyed implementation instances when they change,
so cleanup and registration follow Dioxus lifecycle semantics. Stable-ID
collections require unique semantic ids and explicit Dioxus keys;
index-based adapters accept anitem_keycallback. Forwarded attributes can
no longer replace component-owned event, mounted, accessibility, state, or
behavior-critical style declarations. -
Borrow-safe callbacks and bounded async work. Registry queries snapshot
records before invoking application acceptance/collision callbacks, FLIP
and press measurements discard stale generations, and Linux X11 pointer
roundtrips run on one bounded worker instead of the Dioxus UI executor. -
Bounded refresh and sortable measurements. Rect-refresh completions use
ordinary one-shot closures rather than retaining a new scope-owned Dioxus
callback per scroll ping. List/grid DOM reads validate node identity and a
per-index generation after every await, and grid cache shrinkage cannot
leave an out-of-range drop target. -
Selection modality. Keyboard drags no longer arm browser click
suppression, and cancelled pointer drags cannot consume a later genuine
selection click. -
Auto-scroll hover reconciliation. Geometry refreshes re-resolve hover
after every completed measurement batch, so targets moving beneath a
stationary pointer stay current. Drag identity and session guards prevent a
late batch from modifying a replacement drag, including across windows. -
Single-pass target policy. Collision resolution evaluates each target's
acceptance and effect negotiation once per query, and active highlighting
uses the same live modifier-adjusted effect as final delivery. Custom
detector output is ordered by its documented score and registration
tie-break instead of callback vector order. -
Activation and selection edges. Empty or manual-only activation
disjunctions remain manual, independent delayed alternatives retain their
own clocks and tolerances, and keyboard range movement saturates safely for
extreme signed steps. -
Reentrant drag replacement. A replacement drag started synchronously by
cancellation user code is no longer overwritten when the outer start call
resumes. -
Selection constructor compatibility.
Selection::from_signalremains a
non-hook wrapper for existing callers; persistent range-anchor state is
opt-in throughuse_selection_from_signalorfrom_signals. -
Clean release publishing. The crates.io existence probe writes its
response outside the checkout, so Cargo receives the clean tagged payload
required bycargo publish. Tag workflows reuse the successful CI run for
the samemaincommit instead of compiling the full matrix a second time. -
Owner restoration and lifetime precision.
DndScope::withnow restores
both Dioxus owner overrides before resuming an initializer panic, and
process-owned model/world scopes remain deliberately non-dropping even if
their creator UI thread exits. Public docs now call out synchronous
allocation and quiescent teardown requirements. -
Zone-registry hot paths and ordering. Acceptance-aware release
hit-testing now scans the registry once without cloning every acceptable
ZoneRecord, evaluates each acceptance predicate once per query, and
consistently falls through rejecting overlaps in local, simulated,
cross-window, and host-driven release paths. Keyboard traversal groups
zone tops within one CSS pixel into the same row, preventing fractional
layout jitter from producing a zig-zag in LTR or RTL. -
Registry mutation diagnostics and structural consistency. Failed Dioxus
signal mutations emittraceevents underdioxus_dnd::registry, and
register/unregister acquire both the zone and generation stores before
mutating either so a runtime borrow collision cannot split their state.
Registry handle equality now includes all four backing signal identities.
Documented
- Overlap and reentrancy invariants. Public docs now state that overlapping
targets resolve by registry order rather than CSS stacking/portal paint
order, and the architecture guide records the generation revalidation
protocol that pr...
dioxus-dnd 3.0.1 — corrected release links
Documentation-only patch release for the 3.0 line.
- Publishes the corrected repository-relative showcase GIF in the crates.io README.
- Extends the compatibility table through dioxus-dnd 3.0 on Dioxus 0.7.9.
- Replaces gallery deep links that report HTTP 404 with the stable gallery entry point.
- Redeploys GitHub Pages from the same release commit, including its SPA fallback.
There are no Rust API or runtime behavior changes. Multi-window desktop support is unchanged from 3.0.0. See the 3.0.0 release for the complete feature and migration notes.
dioxus-dnd 3.0.0 — multi-window desktop drag and drop
dioxus-dnd 3.0.0
Version 3.0 is the multi-window desktop release. It adds process-wide drag worlds for sibling Dioxus windows, promotes the verified desktop bridge into supported library API, hardens growing event types for future releases, and ships a complete concept-guide and API-reference documentation set.
The crate targets Dioxus 0.7 and requires Rust 1.85 or newer.
Multi-window desktop drag and drop
Enable the host integration explicitly:
dioxus-dnd = { version = "3.0.0", features = ["desktop"] }Multi-window drags carry the original Rust payload between windows of one application. They do not serialize the payload and do not use HTML5 DataTransfer.
The model has two layers:
DndWorld<T>is always available in the dependency-free core.use_dnd_world::<T>()creates a process-lived world containing the sharedDndContext<T>and joined-window table.- The
desktopfeature addsuse_window_geometry_feed()andDragBridge<T>, backed by dioxus-desktop, Tao, a time-only Tokio runtime, tracing, and x11rb on Linux.
Create one world and pass it to each sibling VirtualDom with VirtualDom::with_root_context. In every window, call use_window_geometry_feed() above DndProvider<T> and render one DragBridge<T> inside the provider. Providers discover and join the world automatically; nested providers keep their normal shadowing behavior.
What is coordinated across windows
- Window-qualified zone registration and hit testing.
- Live Rust payload delivery into a zone owned by another
VirtualDom. - Global-physical-pixel to per-window CSS-pixel conversion, including scale factors.
- Exactly one presenting
DragOverlayper frame. - Drop-settle animation in the receiving window, including when the origin window closes during settlement.
- Modifier-aware Move, Copy, and Link effects at host-side release.
- Window visibility, minimization, resize, scale-factor changes, focus order, close, and reopen.
- Safe close ordering: the window that created the world may close first; surviving windows keep dragging.
The host-drive surface is public for non-Tao integrations: begin_from, track_global, drop_at_global, cancel_drag, update_modifiers, window lookup, geometry lookup, and active drag metadata.
Why DragBridge exists
Webviews do not provide one portable event shape outside their viewport. The bridge supplies the missing host-side observations while binding every poller and callback to the originating world/session generation. A delayed callback from drag N cannot drive drag N+1, duplicate reports are idempotent, and an event arriving after completion cannot resurrect a drag.
Bridging is pointer-aware:
- Mouse and pen need host bridging when webview pointer capture is unavailable.
- Touch is implicitly captured by the browser and is never bridged. This avoids double-driving a gesture with Windows' touch-synthesized mouse stream.
- Keyboard drags stay on the normal keyboard path and cannot be hijacked by host pointer input.
Platform support and verified boundaries
Windows 11 / WebView2: verified. WebView2 consumes the window mouse messages Tao would otherwise see, so the Windows leg uses WM_INPUT device events for raw movement, button release, and modifier keys. It enables Tao's DeviceEventFilter::Never once per process. The bridge includes a warning tripwire if a future Tao/WebView2 update begins delivering the supposedly absent window mouse events, while leaving raw input as sole owner to prevent double delivery.
The Windows ARM64 runtime matrix covered cross-window mouse and injected-touch drags, generation-bound raw tracking, desktop-dead-space cancellation and immediate restart, live target resizing, minimized-window exclusion, hovered/origin window closure, close/reopen churn, touch/mouse interleaving, and clean process exit. The tested machine was single-monitor, so mixed-DPI behavior is covered by coordinate tests but has not yet been exercised on a physical mixed-DPI rig.
Linux X11: verified under WSLg forced to X11. The origin polls the global cursor, foreign-window events reconcile release, and an x11rb root-pointer query detects button release over desktop dead space. A transient query miss skips one sample instead of killing the bridge.
Linux Wayland: explicit graceful degradation. Tao's live event-loop backend decision is authoritative. Wayland exposes neither global window placement nor a global cursor, so global geometry and every cross-window bridge leg remain disabled. Local, per-window drag and drop continues normally.
macOS: implemented but not runtime-verified. The current policy uses the portable cursor-poller and release legs. Treat macOS multi-window support as provisional until it receives an AppKit/WKWebView runtime pass.
See the multi-window guide, API reference, platform evidence, and working two-window example.
Operational controls
Cross-window bridging can be disabled without removing local drag behavior:
- Call
DndWorld::set_bridging(false)and inspect it withbridging_enabled(). - Set
DIOXUS_DND_NO_BRIDGE=1before process launch to start with bridging disabled. cancel_drag()remains available while bridging is disabled as an emergency escape hatch.
With tracing at debug, bridge engagement identifies the active leg as cursor-poller, release, x11-deadspace, or raw-input.
Breaking changes and migration
Growing public event types are now #[non_exhaustive] so adding context in future releases does not repeatedly break downstream code.
Add wildcard arms when matching:
GestureEventFileRejectionDragModePointerKind
Use .. when destructuring:
CanvasDropSortEventMoveEventTreeDropEvent
Replace literal construction with:
SortEvent::new(from, to)MoveEvent::new(item, from, to)TreeDropEvent::new(payload, target, intent)
DropEffect, DropIntent, and DropOutcome remain exhaustive by design.
GestureEvent::Hold is also part of the 3.0 input vocabulary. Custom state-machine drivers must handle it or use a wildcard arm.
Other major additions
- Typed JSON transport:
TypedDragSource<T>andTypedDropZone<T>under theserdefeature, with atext/plainfallback for non-typed consumers. PointerKindis recorded for every pointer drag and exposesimplicitly_captured()for safe host-bridge policy.- Runtime bridge diagnostics and a platform-model warning tripwire.
- Scheduled compatibility canaries for the latest published Dioxus 0.7 patch and Dioxus git
maincross-VirtualDomcontracts. - A complete
docs/tree: 22 concept guides and 19 API references. API Markdown is included directly as module Rustdoc, packaged with the crate, and built on docs.rs with all features. - CI Markdown linting, semver reporting, and a guard preventing Tao/Wry implementation types from leaking into the public desktop API.
Verification
The release commit passed both local and GitHub gates:
- Core plus serde tests: 103 unit tests, 28 multi-window tests, 2 cross-
VirtualDomseam tests, 60 runtime tests, and 5 typed-transport tests. - Desktop-feature tests: 115 unit tests plus the same integration suites.
- Strict Clippy across all targets with
serde desktopand warnings denied. - Rustdoc with all features and warnings denied.
- Markdown linting through pinned rumdl 0.2.30.
cargo-semver-checksagainst 2.4.0.- Packaged-crate build verification.
The complete change inventory is in the 3.0.0 changelog.
v2.4.0 - Drop-settle, closest edge, localization, devtools, headless testing, 10k-row lists
The world-class roadmap, shipped. Seven features and three fixes, one commit per item.
Added
- Drop-settle animation -
DragOverlay { settle: true }glides the ghost from the release point into the receiving zone instead of vanishing, honoringprefers-reduced-motion. The core gains a settling phase wheredragging()is false butpayload()stays readable, so the ghost keeps its content. - Closest-edge primitive - pure
edge_of(point, rect, EdgeSet) -> Edge, an opt-inedgeprop onDropZonerendering livedata-edge="top|right|bottom|left"for insertion indicators, and the edge held at release delivered in the newDropOutcome::edge. Gallery: Itinerary. - Localizable announcements - every phrase the crate voices reads a
DndStringscontext (whole sentences as functions, English defaults, struct-update to override). A live language switch takes effect on the very next announcement. Gallery: Packing list, wiring dioxus-i18n with an English/Spanish toggle. - Debug overlay (dev-only) -
DndDebugOverlay<T>draws every registered zone as a tinted, labeled outline with live hover and per-zone acceptance during drags, plus a census of unmeasured zones. - Headless test driver -
dioxus_dnd::testruns whole drag interactions inside aVirtualDomin CI, no browser:placethe rects,pick_up,move_to,release, or one-linesimulate_drag. Drops run the production delivery path, shared withDraggableitself. BridgeDropZone<A, B>- the cross-type bridge promoted from documented recipe to crate component: one element registered in two providers' worlds, per-world acceptance, every drop typed. Gallery: Standup.- Virtualized lists, proven at 10,000 rows - zones now measure on mount so rows recycled in mid-drag are droppable,
AutoScrollgainson_scroll, and the README documents theonvisiblerow-sentinel windowing pattern. Gallery: Archive.
Fixed
- The 48px near-miss snap measured to the zone's center, silently disabling it for zones larger than ~96px; it now measures to the nearest edge. Found by dogfooding the test driver.
- Zones mounting mid-drag were invisible to hit-testing (rects only filled at drag start and on scroll pings); they now measure on mount.
- Documented findings: dioxus-web 0.7 delivers no element scroll events, so 2.3.0's "onscroll covers wheel mid-drag" was never true on web; the dead handler is gone and the working patterns are documented.
Notes
- README gains dedicated Accessibility (with a WCAG 2.2 compliance mapping) and Localization sections.
DropOutcomeandDragStateeach gained a field; code constructing them as struct literals (typically hand-rolled tests) addsedge: None/..Default::default(). The new test driver removes the need to construct outcomes by hand.- Verified by 156 tests: 83 unit, 52 runtime, 2 doc, 19 Playwright browser regressions.
Full changelog: CHANGELOG.md · Live gallery: https://kindintelligence.github.io/dioxus-dnd/
v2.3.1 — Fix visible reduced-motion CSS
Patch: the reduced-motion <style> override from 2.3.0 could render its CSS source as visible text at the top of sortable lists. The UA stylesheet's style { display: none } has zero specificity, so any app rule like .list > * { display: flex } overrode it. The element now carries an inline display: none, which outranks any selector. An SSR test pins the inline-hidden form. Upgrade recommended if you're on 2.3.0 with reduced-motion-aware components (SortableList, SortableGrid, FlipItem).
v2.3.0 — Scroll-proof drags, RTL, reduced motion
Tier-1 correctness release: drags now survive scrolling, and two accessibility gaps are closed.
Added
- RTL keyboard navigation.
Direction::RtlonDndProvider(orZoneRegistry::set_directionfor hook users) mirrors the keyboard experience: spatial zone ordering runs right-to-left within a row, and the descend/ascend arrows swap so "into" is always the arrow pointing along reading order - the WAI-ARIA tree convention. LTR unchanged and default. prefers-reduced-motionsupport.SortableList's live preview andFlipItem's glide mark their moving elements withdata-dnd-motionand ship a media-query override, so drags snap instead of gliding when the user asks the OS for less motion. Near-zero duration rather than zero, sotransitionendstill fires. Mark your own animated elements with the same attribute to opt them in.
Fixed
- Stale hit-test rects while auto-scrolling. Zone rects were cached at drag start, but
AutoScrollmoves the zones mid-drag - so hover and drops targeted where zones sat at pickup. A new payload-type-erasedRectRefreshchannel (one per provider tree; thunks self-gate on having a drag in flight) fixes it:AutoScrollpings after every scroll it performs and on any other scroll of its container, and the newuse_rect_refresh()hook lets custom layout mutators ping too. - Sortables and grids track scrolling too.
AutoScrollanchors the channel when it's the outermost participant, so the provider-lessSortableList/SortableGridjoin it. The grid re-measures plainly; the list re-anchors - its rows carry live-preview transforms (often mid-transition, unreadable exactly), but the wrapper never transforms, so one wrapper measurement per ping shifts every cached base slot by the exact scroll distance.
Tests
134 passing: 78 unit, 40 runtime, 2 doctests, 14 Playwright browser regressions - including two new scroll regressions (drop zones and sortable slots that auto-scrolled into place), each verified red without its fix.
v2.2.0 — Cross-type bridges
Cross-type drops, documented and de-trapped. Providers stay monomorphic - that's the crate's core guarantee - but two things now make living next to a second provider first-class.
Added
ZoneRegistry::contains(id)andZoneRegistry::ascend(current). TheParentZonecontext is shared across payload types, so aDropZone<A>nested inside aDropZone<B>records B's id as its parent - an id that only resolves in B's registry.ascendreturns a zone's parent only when it's registered in the same registry.ParentZoneis exported from the prelude, completing the public kit (use_zone_registry,use_zone_id,ZoneRecord) for building custom zones - including bridge zones registered in two type-worlds at once.- README section Mixing payload types: when one provider with an enum payload is the answer, and when to bridge two providers by registering the same
ZoneId(ids are process-global) in both registries with sharedmounted/rectsignals. Every drop stays typed; no erased channel. - Gallery page Standup: tickets and teammates drag in separate providers; a shared agenda tray built from double registration (in ~40 lines of user-land code) accepts both.
Fixed
- Keyboard navigation could dead-end across type-worlds: ArrowLeft from a zone nested under a foreign-type zone entered the foreign parent's id, which this world's registry can't resolve - announcements degraded to "zone N" and Enter silently did nothing while the payload stayed held. Ascend now skips unresolvable parents (falling back to the previous sibling), and Enter's target resolution skips a hovered id that isn't in the registry (falling back to the first acceptable zone).
- The Playwright web server command used
--interactive false-style flags, which dx 0.7 parses as a subcommand; switched to the=form. - Zero clippy warnings again under Rust 1.96.
Tests
125 passing: 76 unit, 35 runtime, 2 doctests, and 12 Playwright browser regressions - including a new one driving real pointer drags from two payload worlds onto one shared bridge zone.
v2.1.0 — Dioxus 0.7 stable
Retargeted to Dioxus 0.7 stable. 2.0 depended on the 0.8.0-alpha.0 pre-release, which Cargo won't unify with 0.7.x — making the crate unusable in projects on shipped 0.7. The code needed no changes; only the dependency requirement moved.
Verified against 0.7.9: library (all features), the wasm32 web build, every gallery example, and 109 tests (76 lib + 33 runtime) plus doc-tests compile and pass with zero warnings.
The crate still declares dioxus with default-features = false, features = ["minimal"], so it pulls in no renderer of its own. Stores, which back the in-app drag state, have been part of Dioxus since 0.7.0.
Full diff: #11
v2.0.1: The pointer-first release
The pointer-first release. In-app drag and drop now runs entirely on pointer
events and keyboard input with typed Rust payloads; native browser drag is
reserved for the app boundary, where DataTransfer is the only transport.
Styling is Tailwind-ready through presence-based data attributes, and the
project website is a new multi-page gallery that teaches every pattern.
Breaking: one input model
- In-app components are pointer + keyboard only. Removed
PointerDraggable,
DragInputMode,DragMode::Native,Draggable::native, theinput
props on sortable/grid/board/multiselect components, and every in-app
nativeondrag*branch (DropZone,SortableList,SortableGrid,
BoardSlot,TreeNodeTarget,CanvasDropZone).Draggableis now the
one in-app drag source, and there is no mode to choose. - Native
DataTransferremains exactly where the app boundary requires it:
FileDropZone,ExternalDropZone,ExternalDragSource,
external::typed, andAutoScroll's dragover listener. DropOutcomegained two fields:mode: DragMode(Pointeror
Keyboard) andgrab: Point(the pointer offset inside the element at
pickup;element - grabis the landing top-left). ManualDropOutcome
literals must add both.ZoneId::autoandDragId::autonow start at 2^32 so auto-generated ids
can never collide with explicitu32-range ids and silently replace a
neighboring zone in the registry (previously dependent on mount order).
Styling: presence-based data attributes
- Drag state is exposed as attributes that are present while active and
absent otherwise, so Tailwind variants likedata-dragging:opacity-50
and CSS[data-over]selectors match only active elements:data-over+
data-activeonDropZone,FileDropZoneandExternalDropZone,
data-dragging+data-disabledonDraggable,data-dragging+
data-drop-targeton sortable/grid items,data-active+data-overon
BoardSlot,data-selectedonSelectableDraggable,data-intenton
TreeNodeTarget,data-activeonCanvasDropZone, and
data-sort-handleon touch grips. - Forwarded
styleprops merge after functional inline styles instead of
replacing them, sotouch-action, overlay positioning and the grid's
display: gridsurvive while your declarations win per property. - New
item_classprop onSortableGridfor the library-rendered tile
wrappers;DragOverlayforwardsclassand friends to the ghost.
Pointer path
- New
webfeature: real pointer capture viaweb-sys, so a mouse drag
stays glued to its source when the cursor leaves it. Off by default; the
core stays dependency-free with a held-button recovery fallback, and a
formal gesture state machine (transition,GesturePhase,
GestureEvent,GestureEffect) drives every drag. - New
SortableList::overlayprop: a fixed-position ghost sized from the
measured source row while the in-flow row becomes the live gap. - Live preview translates rows by the measured slot pitch (margins and gaps
included) so spacing never squashes mid-drag; hover hit-tests client
coordinates against rects measured at drag start. - A release outside a list or grid commits no reorder, and a drop over a
rejecting zone falls through to an accepting zone stacked beneath it.
Missed drops re-measure zones and retry within 48px for touch. AutoScrollfollows default mouse pointer drags via held-button state,
never scrolls on passive hover, stops when the pointer leaves the
container, and takes an optionalactivegate.Ctrl/Cmdat release resolves pointer drops toCopyandAltto
Link(effective_effectis public); keyboard drops report the selected
zone's center inDropOutcome::elementand honor
CanvasKeyboardPlacement(Center,Origin,Fixed).BoardSlotregisters as a real zone (pointer, touch and keyboard can
target it) andapply_moveadjusts same-column forward insertions.TreeNodeTarget,BoardSlotandCanvasDropZonemirror changing props
through signals so their one-time registry callbacks always read current
values.FileFilter::content_typesgained a real MIME matcher (exact types,
type/*,*/*, structured*+jsonsuffixes, parameters and case
ignored, malformed patterns rejected), andextensionsnormalizes dots,
case and whitespace.
The gallery website
examples/gallery/replaces the showcase, tailwind and canvas examples:
a multi-page site with one page per pattern (fourteen in all), each
pairing a live demo with a numbered walkthrough, an annotated snippet, a
"New to Dioxus?" callout and a real API reference. Deployed to GitHub
Pages by CI.- The design follows the KI-U paper system: paper and ink scales, one
forest-green accent, earth tones used sparingly, Poppins for UI text and
Geist Mono for code, no glow shadows. Code panels are inverse-ink with a
homegrown Rust/rsx highlighter (no JavaScript highlighter). - The landing page hero is itself a demo: draggable paper scraps on a
CanvasDropZone. - Removed
examples/showcase.rs,examples/tailwind.rsand
examples/canvas.rs. The Playwright suite now drives headless fixtures
inexamples/regressions.rson a single dev server, covering overlay
geometry and cleanup, outside-release cancellation for lists and grids,
autoscroll edge behavior, canvas grab-offset placement, drop
fall-through, the Ctrl-drag copy convention, reorder buttons inside
sortable rows, and the native boundary paths.
2.0.1 docs patch
Docs-only patch. The README packaged into 2.0.0 still carried a stale
pre-release warning line and a malformed crates.io badge link, which
rendered on crates.io and the docs.rs front page. This release ships the
refreshed README: fixed badges, the 2.0 compatibility table, a prominent
link to the live gallery, highlighted code fences, and a precise claim
about JavaScript (the library ships none of its own; the optional web
feature uses web-sys bindings for pointer capture).
Links
- Live gallery: https://kindintelligence.github.io/dioxus-dnd/
- crates.io: https://crates.io/crates/dioxus-dnd
- docs.rs: https://docs.rs/dioxus-dnd
- Full changelog: v1.0.0...v2.0.1
v1.0.0: Pick it up. Put it anywhere.
Changelog
v1.0.0
Stable release. Carries the full feature set, the model helper APIs,
the docs.rs example cleanup, and the public repository metadata.
- Universal touch. Every interaction pattern now works with fingers and pens in every browser, not just the ones whose native HTML5 drag happens to support touch.
BoardItemandSelectableDraggablewrapPointerDraggable, so board cards and multi-select boxes respond to touch, pen, mouse and keyboard out of the box.SortableListandSortableGridrun a pointer-event gesture path alongside the native one, driven by the same gesture state machine asPointerDraggableand hit-tested against per-row rects measured at drag start (stable pre-displacement slots, so the preview never oscillates).- New
SortableListproptouch_handle: confines touch drags to a leading grip ([data-sort-handle]) so rows inside scrollable lists keep finger-scrolling. Default remains whole-row, which setstouch-action: noneon rows. - New pure function
sortable::pointer_target(the hit-test plus midpoint hysteresis logic), unit tested. - New model helpers
core::apply_clone_or_moveandcore::apply_list_clone_or_move: apply move-vs-copy drops toHashMap<ZoneId, Vec<T>>zone models or two plainVec<T>lists, with key-based source removal and a clone hook for assigning fresh ids on copy. TreeNodeTargetregisters itself in the zone registry: tree rows are now reachable by touch hit-testing and keyboard navigation. Keyboard drops land withIntointent. Newlabelprop feeds screen-reader announcements. Touch hovers show the same livedata-intentbands as mouse hovers.- Pointer paths listen to
lostpointercaptureas a cancel signal, so a drag aborts cleanly if the browser revokes capture mid-gesture. - Fixed
sortable::displacementleaving a phantom gap: the source row
now translates toward its landing slot while neighbors make room —
previously the shifted neighbors overlapped the source (which still
occupies its slot during a native drag), leaving a gap at the target.
Offsets now conserve slot occupancy (they sum to zero). - Showcase rework: drops are visibly stateful everywhere (crates land in
bays and can be dragged onward, keyboard moves render, the tree really
restructures, received links and loaded boxes stay visible), the
FLIP-plus-displacement double animation is gone, and the layout gains a
white workbench surface so the taupe reads as the floor around it. - Formal gesture state machine (
core::machine): the pointer drag
lifecycle (Idle → Pressed → Dragging, threshold promotion, tap vs drop,
foreign-pointer rejection, cancellation) is now a pure, exhaustively
testedtransitionfunction.PointerDraggabledrives it; you can too,
for custom pointer interactions. - Nested keyboard traversal:
DropZones nested inside other
DropZones discover their parents automatically (via context — zero
configuration). Keyboard drags follow the WAI-ARIA tree convention:
Up/Down cycle siblings at the current level, Right descends into a
zone's children, Left ascends — falling back to plain next/previous in
flat apps. Announcements gain nesting context ("Over Column 2, inside
Board A."). Registry API:ZoneRecord::parent,parent_of,
children_of,step_sibling,first_child. - Live drop preview in
SortableList: rows translate out of the way so
a gap opens where the drop would land, with midpoint hysteresis to keep
the gap from oscillating. On by default;live_preview: falserestores
the highlight-only behavior. Pure math exposed assortable::displacement. - Forgiving touch drops:
PointerDraggablenow re-measures zone rects
on a missed drop (stale after mid-drag scroll/resize) and retries with a
closest-center fallback (ZoneRegistry::hit_test_closest,
ZoneRegistry::measure_all). - Composable drag modifiers (
core::modifiers):LockAxis,Snap,
KeepInside, chained withapply_modifiers— the generalized form of
canvas snapping, usable in custom interactions. a11y::ReorderButtons: headless move-up/move-down buttons emitting
the sameSortEventas dragging — reordering with no drag gesture at
all, the most robust accessibility fallback.dragout—ExternalDragSource/OutboundContent: drag text, links and
HTML out of your app into other tabs and applications.grid—SortableGrid: 2D tile reorder (insert-and-reflow) or swap
(dashboard) over CSS grid, pluscell_of/index_ofcoordinate helpers.multiselect—use_selection,SelectableDraggable,SelectionCount:
select several items (click / Ctrl+click) and drag them as one
Vec<K>payload.animate(experimental) —FlipItem: FLIP glide transitions on
reorder, driven by an epoch counter.- Modifier-key drop effects: Ctrl/Cmd forces Copy, Alt forces Link
(file-manager convention), reflected indropEffectfeedback and
DropOutcome::effect. Pure helper:effective_effect. - Keyboard zone navigation is now spatial (top-to-bottom,
left-to-right by measured rects) instead of registration order. - Nested drag scopes:
Draggable,SortableListandSortableGrid
stop propagation on drag start/drop, so sortables inside sortables
(and boards inside boards) each own their gestures. DropZonelabels re-sync when the prop changes across renders.sortable:ReorderMode(Insert/Swap) andapply_swap.- Ported to Dioxus
0.8.0-alpha.0(also compiles on 0.7.9). - State moved from
Signal<DragState<T>>toStore<DragState<T>>for
per-field reactivity: readingdnd.over()in render no longer reruns on
pointer moves;enter/leave/update_pointerwrite through field lenses. - Zone registry (
use_zone_registry): everyDropZoneregisters id, label,
drop callback, acceptance filter and mounted element. - Keyboard accessibility built into
Draggable(Space/Enter pick up and
drop, arrows choose a zone, Escape cancels) witha11y::LiveRegion
screen-reader announcements. - Touch/pen support:
pointer::PointerDraggable(native HTML5 path for
mouse, pointer-event hit-testing for touch). autoscroll::AutoScroll: edge-scrolling containers during drags, pure
MountedData(no JS eval).Core(DndProvider,Draggable,
DropZone,DragOverlay, store-context payload transport),files,
sortable,board,tree,canvas,externalmodules; optional
serdefeature for typedDataTransferinterop.