Expand description
DropTarget — a transparent wrapping drop container.
Where DropZone is a standalone “drop files
here” placeholder with its own label / icon / Browse button, DropTarget is
a wrapping container: it turns any existing widget subtree into a drop
target without replacing its visual identity. The wrapped child fills the
bounds and is always visible; the widget adds a reactive highlight border +
tint while a drag hovers and, if a hint slot is set, fades in a centered
popup card (“Drop your image here”).
It reacts to both internal drags (typed [DragPayload]) and external
(OS) drops (files / text / URIs), through the framework’s normal drag
pipeline (on_drag_hover / on_drag_leave / on_drop).
// Wrap a panel; accept image files; show a hint while hovering.
DropTarget::new()
.child(my_panel)
.hint(TextWidget::new(lit!("Drop your image here")))
.accept_external_extensions(["png", "jpg", "jpeg"])
.on_drop(|payload, _pos, _ctx| { import(payload.files()); true });
// Typed internal drag — recovers the value even after an OS round-trip
// or across windows (the framework's typed re-entry).
DropTarget::new()
.child(project_card)
.on_drop_typed::<ProjectRef>(|project, _pos, ctx| {
ctx.send_intent(AppIntent::Link(project));
true
});§Multi-zone drops
Beyond the single whole-bounds target, a DropTarget can expose up to five
independently enable-able DropRegions — Center / Top / Bottom /
Leading / Trailing — each with its own optional hint, and route the drop
by which zone the pointer released over. This is the VS Code-style
“drop on the centre to add, drop on an edge to split” affordance
(DockingLayout’s pane split/stack zones are built on it). Declare regions with
DropTarget::region; the side zones share one DropTarget::zone_size_factor
(0.1..=1.0, the fraction of the axis each edge strip occupies — 0.2 is the
default fifth, 0.5 bisects) so you size them to the context. Route with
DropTarget::on_region_drop (or observe DropTarget::active_region_signal).
DropTarget::new()
.child(editor_pane)
.zone_size_factor(0.25)
.region(DropRegion::Center, |z| z.hint(TextWidget::new(lit!("Add as tab"))))
.region(DropRegion::Leading, |z| z.hint(TextWidget::new(lit!("Split left"))))
.region(DropRegion::Trailing, |z| z.hint(TextWidget::new(lit!("Split right"))))
.on_region_drop(|region, payload, _pos, ctx| { route(region, payload); true });Declaring any region switches the target to exactly the declared regions;
declaring none keeps the Center-only whole-bounds default (.hint(w) is
sugar for .region(DropRegion::Center, |z| z.hint(w))). Leading / Trailing
map to left / right — this widget does not yet consult
LayoutContext::layout_direction, so RTL mirroring is a follow-up.
Each zone can be reactively enabled with z.enabled(signal) (default
true): a bound Signal<bool> disables the zone live — no rebuild — and its
strip then falls through to the next-priority enabled zone (or Center, or
rejects). A drop landing in a middle covered by no enabled zone is rejected;
on_region_drop therefore only ever receives an enabled region.
§Styling
The per-zone highlight overlay + hint chrome is a Tier-3 DropTargetStyle;
the default RecipeDropTargetStyle
paints the active zone (centre → frame only, so the wrapped content shows
through; an edge strip → translucent fill + accent frame) and a full-bounds
error border on reject. Override per-call with DropTarget::style or
theme-wide via theme.style_slots.drop_target.
§Accessibility
The wrapper is a Role::Group. Live is intentionally not set on the
group (that would announce every change to the wrapped child); instead the
recipe scopes Live::Polite to each hint card so a screen reader announces
the active zone’s hint appearing. Each hint is gated by visible_when, so a
non-active zone’s hint leaves the AT tree entirely.
§Keyboard accessibility is the caller’s responsibility
An OS drag cannot be initiated from the keyboard, and — unlike
DropZone, which ships a keyboard-operable
Browse… button as its WCAG 2.1.1 equivalent — DropTarget adds no
keyboard affordance of its own. That is by design: DropTarget wraps
existing content that is expected to already offer a keyboard path to the
same outcome (e.g. a card you can drop a project onto or open with a
context-menu “Link…” command). The drop is an enhancement, not the sole
path.
If you use DropTarget for an action that has no other affordance, you
must add a keyboard equivalent yourself (a button, menu item, or shortcut) —
otherwise the action is unreachable for keyboard-only users, and entirely
unavailable on any target with no external-DnD backend (all four desktop
backends are real — OLE on Windows, NSDraggingDestination on macOS,
wl_data_device on Wayland, XDND on X11). DropZone is the better choice
when the drop is the primary action.
§Touch and pen
An edge zone’s depth is zone_size_factor of the axis, floored per axis to
the density’s target size: the fraction is the shape the caller asked for and
wins wherever it already conforms, and below that the floor takes over. Without
it a fifth of a small pane is a band no finger can land in, and the drop it
swallows goes to the neighbouring zone with no warning.
The floor is itself capped at a third of the extent, for the reason
partition_targets splits evenly
when its own floor cannot be met: on a target too small for
leading | centre | trailing at the floor, three equal bands keep every zone
reachable and visibly sub-floor, where an uncapped floor would let two opposing
bands meet and delete the centre.
One function answers both the hit test and the highlight
(band_depth), so the zone a user sees stays the zone that drops. A
custom DropTargetStyle that calls core’s region_rect directly paints the
unfloored band; call region_rect_floored instead.
Structs§
- Drop
Region Spec - Per-region configuration for a multi-zone
DropTarget: an optional hint plus a reactive enabled flag. Kept as a struct so more per-zone knobs can land without a signature churn. - Drop
Target - A transparent container that turns its child into a drop target. See the module docs.
Functions§
- band_
depth - The depth of one edge band along the axis it is measured on: the caller’s
fraction of the extent, raised to
floorwhen that fraction does not reach it. - region_
at_ floored region_atwithband_depth’s floor applied per axis.- region_
rect_ floored region_rectwithband_depth’s floor applied per axis — the paint side ofregion_at_floored, so the zone a user sees stays the zone that drops.