Skip to content

list: Add drag and drop support to ListItem#2553

Open
lijingrs wants to merge 8 commits into
longbridge:mainfrom
lijingrs:list-item-drag-drop
Open

list: Add drag and drop support to ListItem#2553
lijingrs wants to merge 8 commits into
longbridge:mainfrom
lijingrs:list-item-drag-drop

Conversation

@lijingrs

@lijingrs lijingrs commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Description

Add on_drag, on_drop, and on_drag_hover methods to ListItem that delegate to the underlying base Stateful<Div>.

These methods enable drag-and-drop reordering when ListItem is used inside a Tree or any custom list layout. Without them, consumers cannot attach drag/drop handlers because the base field is private and ListItem does not implement Deref<Target=Div>.

Use case

In Verve (an API co-development platform built with gpui-component), the project tree needs drag-and-drop reordering for API requests and folders. The tree() component requires its render callback to return ListItem, so consumers have no way to wrap the item in an outer div with drag handlers. These three methods solve this by forwarding to the internal base div:

tree(&state, move |ix, entry, _selected, _window, cx| {
    ListItem::new(ix)
        .child(/* row content */)
        .on_drag(drag_value, move |drag, _pos, _window, cx| {
            // Mark as dragging + return a drag-preview entity
            cx.new(|_| drag.clone())
        })
        .on_drag_hover(move |hovering, _window, cx| {
            // Highlight as a potential drop target
        })
        .on_drop(move |drag, _window, cx| {
            // Reorder: move source relative to target
        })
})

The method signatures mirror GPUI's native Div::on_drag / on_drop / on_hover APIs, so they are immediately familiar.

What each method does

  • on_drag<T, W>(value, constructor) — registers a drag value of type T. When the user drags the row, constructor builds a drag-preview entity of type W: Render. Delegates to self.base.on_drag().
  • on_drop<T>(listener) — called when a drag value of type T is dropped onto this row. Delegates to self.base.on_drop().
  • on_drag_hover(listener) — called with true when the cursor enters the row during a drag, false when it leaves. Delegates to self.base.on_hover().

Break Changes

Fully additive. No existing API changes. Existing ListItem consumers continue to work unchanged.

How to Test

cargo run

The on_drag / on_drop / on_drag_hover methods can be tested in any story that uses ListItem inside a list. The methods delegate directly to the underlying Stateful<Div>, so they inherit all of GPUI's native drag-and-drop behavior.

Checklist

  • I have read the CONTRIBUTING document and followed the guidelines.
  • Reviewed the changes in this PR and confirmed AI generated code (If any) is accurate.
  • Passed cargo fmt --check.
  • [N/A] Tested macOS, Windows and Linux platforms performance (if the change is platform-specific) — not platform specific.

AI Assistance Disclosure

🤖 Parts of this PR were generated with AI assistance and subsequently reviewed by a human to match the project's existing code style and patterns. Specifically:

  • The three method signatures were modeled after the existing on_click / on_mouse_down / on_mouse_enter builder methods and GPUI's native Div::on_drag / on_drop / on_hover APIs.
  • The doc comments follow the same style as the existing methods in list_item.rs.

Add on_drag, on_drop, and on_drag_hover methods to ListItem that delegate
to the underlying base div. This enables drag-and-drop reordering when
ListItem is used inside a Tree or custom list layout.

The methods follow the same builder pattern as the existing on_click and
on_mouse_down methods.
@huacnlee

Copy link
Copy Markdown
Member

Please at least add simple example for this API in to story.

lijingrs and others added 7 commits July 13, 2026 09:34
- Add DragPreview entity for drag preview rendering
- Add with_drag_drop method to CompanyListItem demonstrating on_drag/on_drop/on_drag_hover usage
- Add draggable checkbox to enable/disable drag-and-drop demo
- Console output shows drag-over and drop events for easy testing

This addresses the PR review request for a simple example of the drag-and-drop API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Fix type annotations for on_drag and on_drop closures
- Change method to use mutable self instead of chained calls
- Mark unused _cx parameter in render_item
- Separate clone variables for each drag handler to avoid conflicts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Fix self.base.base chain that was causing syntax error
- Properly format on_drop call as single line with correct parameter types

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Add explicit type annotations for all closure cx parameters: "&mut App"
- Fix self.base.base chain that was causing syntax error in on_drag_hover
- Ensure all drag-drop closures have proper type annotations

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The on_drag closure must borrow the drag value (&Rc<Company>) to match
ListItem::on_drag's Fn(&T, ...) bound, fixing the E0631 type mismatch
that broke compilation of the story crate.

Also wire the "Draggable" checkbox to call toggle_draggable (matching
the selectable/searchable toggle pattern) so the method is no longer
dead code, and rename the unused window parameter to _window.

Co-Authored-By: Claude <noreply@anthropic.com>
@huacnlee huacnlee self-assigned this Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants