dock: Report where a host drag item landed in the dock (#2661)
## Description
`DockEvent::DragDrop` told hosts that an `AnyDrag` had been dropped, but
not where. On a canvas that is enough — the landing position is the
cursor position, which the host reads itself. A split layout has no free
coordinates: the meaningful position is a panel and an edge, derived
from the panel's bounds, the 35%/65% thresholds and the panel tree.
`TabPanel` matched none of the drop handlers, so no split preview
appeared and the drop bubbled out of the dock.
The event now carries a `DropTarget` saying how much the container can
tell you: `Canvas`, or `Panel { tab_panel, placement }`. `TabPanel`
paints the same left/right/top/bottom preview for a drag item as it
already does for a panel drag and reports the edge it resolved; dropping
on the tab bar reports `placement: None`, meaning merge into that tab
group.
Folding this into the existing variant rather than adding a second one
is deliberate: a host handling only the old `DragDrop` would silently
swallow split drops, because gpui takes the active drag whether or not
anyone listens. One variant makes that a compile error instead.
## Screenshot
No story covers this: the story crate has no host-owned drag source, so
there is nothing to drag into a dock. Happy to add a draggable chip to
the dock story if you would like the demo in-tree.
## Break Changes
- `DockEvent::DragDrop` becomes a struct variant carrying the landing
target.
```diff
- DockEvent::DragDrop(item) => { ... }
+ DockEvent::DragDrop { item, target } => { ... }
```
Consumers that only care about the old canvas behaviour can ignore the
new field with `DockEvent::DragDrop { item, .. }`.
## How to Test
```sh
cargo test -p gpui-component dock::tab_panel # 15 passed
cargo check --workspace --all-targets
cargo fmt --check
```
Three of those tests are new and cover `split_placement_at`: the five
cursor zones, the corner precedence (x is tested before y), and that the
thresholds themselves fall into the centre zone.
Manually, in an application that drags a host payload into a `DockArea`:
1. Drag over a panel's edge — the split preview appears and animates,
same as a panel drag.
2. Release on an edge — the host receives `Panel { placement: Some(..)
}`.
3. Release in the centre, on a tab, or on the empty part of the tab bar
— the host receives `Panel { placement: None }`.
4. Canvas (`Tiles`) drops still arrive as `Canvas`, unchanged.
5. Panel-to-panel dragging is unaffected.
## Checklist
- [x] I have read the [CONTRIBUTING](../CONTRIBUTING.md) document and
followed the guidelines.
- [x] Reviewed the changes in this PR and confirmed AI generated code
(If any) is accurate.
- [ ] Passed `cargo run` for story tests related to the changes — see
Screenshot above.
- [ ] Tested macOS, Windows and Linux platforms performance (if the
change is platform-specific)
AI assistance: written with Claude Code. The design (folding into
`DragDrop` rather than adding a variant), the naming, and the threshold
tests were reviewed and adjusted by hand. C
Cookie committed
7aed6dfabfbf2fe95080a815a80d76c0abde0c4f
Parent: 9aedbb8
Committed by GitHub <noreply@github.com>
on 8/11/2026, 9:18:48 AM