Skip to content

Releases: kindintelligence/dioxus-dnd

dioxus-dnd 3.1.0

Choose a tag to compare

@github-actions github-actions released this 30 Aug 10:42
324fd80

Added

  • Stable-ID sortable kernel. SortableProvider, SortableGroup,
    SortableCollection, and SortableItem build 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_layout derives
    variable-size previews from measured slots, while the index-based list and
    grid APIs remain available.
  • Checked model helpers. try_apply_clone_or_move and
    try_apply_list_clone_or_move reject unsupported effects without mutation,
    while the unprefixed helpers retain their existing 3.x signatures.
  • Composable activation. ActivationPolicy combines handle, surface, or
    manual activation with distance, delay, or either constraints.
    DragHandle supplies an accessible activator and NoDrag protects 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 negotiate DropEffects through a
    rich DropQuery. Stable DragId values and use_dnd_monitor expose the
    Started, Moved, TargetChanged, Dropped, and Cancelled lifecycle without
    changing DropOutcome. Custom sources can start identified drags with
    DragStart and DndContext::start_with_id, inspect active snapshots, and
    cancel with monitor-visible reasons.
  • Selection ranges. Selection now supports anchored Shift ranges,
    additive ranges, and keyboard range movement.
  • Click-to-upload file drop zones. Clicking FileDropZone opens the
    native multi-file picker. Picker selections share the existing filtering,
    rejection, and on_files path with OS drops, while the wrapper remains
    headless and receives no library-owned visual styles.
  • Multi-window ownership and wiring primitives. use_dnd_model creates
    app-wide state under process-lived unsynchronized and synchronized owners;
    DndScope gives reclaimable dynamic state the same correct owner pair.
    With the desktop feature, MultiWindowProvider structurally 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::vdom pre-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
    protected main head 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 exact speed_px_per_second; the 3.x
    speed prop retains its nominal-per-frame contract.
  • Accessible file zones. FileDropZone has button semantics, Enter and
    Space activation, an accessible label, a configurable multiple picker,
    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-util 0.3.34, Serde 1.0.229, serde_json 1.0.151, Tokio
    1.53.1, webbrowser 1.2.2, and the direct Linux integration against
    x11rb 0.14. The root lockfile also selects non-yanked chacha20 0.10.2
    and spin 0.9.9. The browser suite uses Playwright 1.62.1 and 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 successful main CI. 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 against development. cargo-deny enforces
    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
    GridSwap intent 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's mounted capability 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 an item_key callback. 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_signal remains a
    non-hook wrapper for existing callers; persistent range-anchor state is
    opt-in through use_selection_from_signal or from_signals.

  • Clean release publishing. The crates.io existence probe writes its
    response outside the checkout, so Cargo receives the clean tagged payload
    required by cargo publish. Tag workflows reuse the successful CI run for
    the same main commit instead of compiling the full matrix a second time.

  • Owner restoration and lifetime precision. DndScope::with now 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 emit trace events under dioxus_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...
Read more

dioxus-dnd 3.0.1 — corrected release links

Choose a tag to compare

@kindintelligence kindintelligence released this 11 Jul 04:41
57c7c8a

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

Choose a tag to compare

@kindintelligence kindintelligence released this 11 Jul 04:19
9a47a91

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 shared DndContext<T> and joined-window table.
  • The desktop feature adds use_window_geometry_feed() and DragBridge<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 DragOverlay per 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 with bridging_enabled().
  • Set DIOXUS_DND_NO_BRIDGE=1 before 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:

  • GestureEvent
  • FileRejection
  • DragMode
  • PointerKind

Use .. when destructuring:

  • CanvasDrop
  • SortEvent
  • MoveEvent
  • TreeDropEvent

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> and TypedDropZone<T> under the serde feature, with a text/plain fallback for non-typed consumers.
  • PointerKind is recorded for every pointer drag and exposes implicitly_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 main cross-VirtualDom contracts.
  • 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-VirtualDom seam 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 desktop and warnings denied.
  • Rustdoc with all features and warnings denied.
  • Markdown linting through pinned rumdl 0.2.30.
  • cargo-semver-checks against 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

Choose a tag to compare

@kindintelligence kindintelligence released this 08 Jul 22:43

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, honoring prefers-reduced-motion. The core gains a settling phase where dragging() is false but payload() stays readable, so the ghost keeps its content.
  • Closest-edge primitive - pure edge_of(point, rect, EdgeSet) -> Edge, an opt-in edge prop on DropZone rendering live data-edge="top|right|bottom|left" for insertion indicators, and the edge held at release delivered in the new DropOutcome::edge. Gallery: Itinerary.
  • Localizable announcements - every phrase the crate voices reads a DndStrings context (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::test runs whole drag interactions inside a VirtualDom in CI, no browser: place the rects, pick_up, move_to, release, or one-line simulate_drag. Drops run the production delivery path, shared with Draggable itself.
  • 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, AutoScroll gains on_scroll, and the README documents the onvisible row-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.
  • DropOutcome and DragState each gained a field; code constructing them as struct literals (typically hand-rolled tests) adds edge: 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

Choose a tag to compare

@kindintelligence kindintelligence released this 08 Jul 13:07
f5ef685

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

Choose a tag to compare

@kindintelligence kindintelligence released this 08 Jul 12:49
d145b0d

Tier-1 correctness release: drags now survive scrolling, and two accessibility gaps are closed.

Added

  • RTL keyboard navigation. Direction::Rtl on DndProvider (or ZoneRegistry::set_direction for 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-motion support. SortableList's live preview and FlipItem's glide mark their moving elements with data-dnd-motion and 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, so transitionend still 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 AutoScroll moves the zones mid-drag - so hover and drops targeted where zones sat at pickup. A new payload-type-erased RectRefresh channel (one per provider tree; thunks self-gate on having a drag in flight) fixes it: AutoScroll pings after every scroll it performs and on any other scroll of its container, and the new use_rect_refresh() hook lets custom layout mutators ping too.
  • Sortables and grids track scrolling too. AutoScroll anchors the channel when it's the outermost participant, so the provider-less SortableList/SortableGrid join 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

Choose a tag to compare

@kindintelligence kindintelligence released this 08 Jul 11:43
79f245a

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) and ZoneRegistry::ascend(current). The ParentZone context is shared across payload types, so a DropZone<A> nested inside a DropZone<B> records B's id as its parent - an id that only resolves in B's registry. ascend returns a zone's parent only when it's registered in the same registry.
  • ParentZone is 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 shared mounted/rect signals. 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

Choose a tag to compare

@kindintelligence kindintelligence released this 08 Jul 10:46
13d4f32

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

Choose a tag to compare

@kindintelligence kindintelligence released this 08 Jul 09:38

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, the input
    props on sortable/grid/board/multiselect components, and every in-app
    native ondrag* branch (DropZone, SortableList, SortableGrid,
    BoardSlot, TreeNodeTarget, CanvasDropZone). Draggable is now the
    one in-app drag source, and there is no mode to choose.
  • Native DataTransfer remains exactly where the app boundary requires it:
    FileDropZone, ExternalDropZone, ExternalDragSource,
    external::typed, and AutoScroll's dragover listener.
  • DropOutcome gained two fields: mode: DragMode (Pointer or
    Keyboard) and grab: Point (the pointer offset inside the element at
    pickup; element - grab is the landing top-left). Manual DropOutcome
    literals must add both.
  • ZoneId::auto and DragId::auto now start at 2^32 so auto-generated ids
    can never collide with explicit u32-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 like data-dragging:opacity-50
    and CSS [data-over] selectors match only active elements: data-over +
    data-active on DropZone, FileDropZone and ExternalDropZone,
    data-dragging + data-disabled on Draggable, data-dragging +
    data-drop-target on sortable/grid items, data-active + data-over on
    BoardSlot, data-selected on SelectableDraggable, data-intent on
    TreeNodeTarget, data-active on CanvasDropZone, and
    data-sort-handle on touch grips.
  • Forwarded style props merge after functional inline styles instead of
    replacing them, so touch-action, overlay positioning and the grid's
    display: grid survive while your declarations win per property.
  • New item_class prop on SortableGrid for the library-rendered tile
    wrappers; DragOverlay forwards class and friends to the ghost.

Pointer path

  • New web feature: real pointer capture via web-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::overlay prop: 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.
  • AutoScroll follows default mouse pointer drags via held-button state,
    never scrolls on passive hover, stops when the pointer leaves the
    container, and takes an optional active gate.
  • Ctrl/Cmd at release resolves pointer drops to Copy and Alt to
    Link (effective_effect is public); keyboard drops report the selected
    zone's center in DropOutcome::element and honor
    CanvasKeyboardPlacement (Center, Origin, Fixed).
  • BoardSlot registers as a real zone (pointer, touch and keyboard can
    target it) and apply_move adjusts same-column forward insertions.
  • TreeNodeTarget, BoardSlot and CanvasDropZone mirror changing props
    through signals so their one-time registry callbacks always read current
    values.
  • FileFilter::content_types gained a real MIME matcher (exact types,
    type/*, */*, structured *+json suffixes, parameters and case
    ignored, malformed patterns rejected), and extensions normalizes 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.rs and
    examples/canvas.rs. The Playwright suite now drives headless fixtures
    in examples/regressions.rs on 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

v1.0.0: Pick it up. Put it anywhere.

Choose a tag to compare

@kindintelligence kindintelligence released this 05 Jul 03:43

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.
  • BoardItem and SelectableDraggable wrap PointerDraggable, so board cards and multi-select boxes respond to touch, pen, mouse and keyboard out of the box.
  • SortableList and SortableGrid run a pointer-event gesture path alongside the native one, driven by the same gesture state machine as PointerDraggable and hit-tested against per-row rects measured at drag start (stable pre-displacement slots, so the preview never oscillates).
  • New SortableList prop touch_handle: confines touch drags to a leading grip ([data-sort-handle]) so rows inside scrollable lists keep finger-scrolling. Default remains whole-row, which sets touch-action: none on rows.
  • New pure function sortable::pointer_target (the hit-test plus midpoint hysteresis logic), unit tested.
  • New model helpers core::apply_clone_or_move and core::apply_list_clone_or_move: apply move-vs-copy drops to HashMap<ZoneId, Vec<T>> zone models or two plain Vec<T> lists, with key-based source removal and a clone hook for assigning fresh ids on copy.
  • TreeNodeTarget registers itself in the zone registry: tree rows are now reachable by touch hit-testing and keyboard navigation. Keyboard drops land with Into intent. New label prop feeds screen-reader announcements. Touch hovers show the same live data-intent bands as mouse hovers.
  • Pointer paths listen to lostpointercapture as a cancel signal, so a drag aborts cleanly if the browser revokes capture mid-gesture.
  • Fixed sortable::displacement leaving 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
    tested transition function. PointerDraggable drives 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: false restores
    the highlight-only behavior. Pure math exposed as sortable::displacement.
  • Forgiving touch drops: PointerDraggable now 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 with apply_modifiers — the generalized form of
    canvas snapping, usable in custom interactions.
  • a11y::ReorderButtons: headless move-up/move-down buttons emitting
    the same SortEvent as dragging — reordering with no drag gesture at
    all, the most robust accessibility fallback.
  • dragoutExternalDragSource / OutboundContent: drag text, links and
    HTML out of your app into other tabs and applications.
  • gridSortableGrid: 2D tile reorder (insert-and-reflow) or swap
    (dashboard) over CSS grid, plus cell_of/index_of coordinate helpers.
  • multiselectuse_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 in dropEffect feedback 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, SortableList and SortableGrid
    stop propagation on drag start/drop, so sortables inside sortables
    (and boards inside boards) each own their gestures.
  • DropZone labels re-sync when the prop changes across renders.
  • sortable: ReorderMode (Insert/Swap) and apply_swap.
  • Ported to Dioxus 0.8.0-alpha.0 (also compiles on 0.7.9).
  • State moved from Signal<DragState<T>> to Store<DragState<T>> for
    per-field reactivity: reading dnd.over() in render no longer reruns on
    pointer moves; enter/leave/update_pointer write through field lenses.
  • Zone registry (use_zone_registry): every DropZone registers 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) with a11y::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, external modules; optional
    serde feature for typed DataTransfer interop.