Files: a press on a download's button stays with the button

gpui runs the click of every pressed element under the pointer, so a
press on a finished download's Show button also opened the file through
the pressable row. The actions' box stops the press on mouse down, so
the row starts no click of its own.
This commit is contained in:
ZacharyZhang-NY committed 2026-09-26 21:12:38 -04:00
1 parent 4ef9830def
commit 85df47fd5c
4 files changed
+25 -4

No files matched your search

+1
View File
@@ -70,6 +70,7 @@ Ely GPUI Component. A component library for GPUI, in light and dark.
- A palette goes through `navigation::palette::Palette`: query field, grouped rows, cursor, keys and focus live there. CommandPalette, QuickOpen, QuickSwitcher, SearchPalette and QuickLauncher only build rows.
- A menu goes through `menus::menu`: rows, submenus, keys, focus and presses outside live there, for DropdownMenu, OverflowMenu, SplitButton, ContextMenu, SearchableMenu and MenuBar. A press on the host's own box is the host's to handle, so a trigger toggles and a right click moves a context menu without a close and reopen in one event.
- gpui focuses the nearest focusable ancestor on mouse down, and apps wrap everything in a `FocusScope`. A press that must leave focus alone calls `prevent_default`, as buttons and context regions do.
- gpui runs the click of every pressed element under the pointer, a row's with its button's. A pressable row that holds buttons stops their press at their box on mouse down (`files::transfer`), as `overlays::media_button` stops its own.
- gpui draws a window's first frame inside `open_window`. State the first frame reads, such as `cx.set_menus`, is set before it opens.
- gpui clicks a focused element when Enter or Space is released. An overlay that hands focus back picks on release too; a pick on press returns focus first, and the release clicks the opener again. An edit in place that hands focus back keeps its text on Enter's release (`forms::InlineEdit`). The press itself bubbles, so a container that takes Space leaves a focused button its own: `overlays::media_button` stops it.
- A focus handle a component hands back lives across all its modes: take it with `tab_stop` before any early return, or keyed state drops it while the other mode draws and the handed-back focus lands nowhere.
+1
View File
@@ -327,3 +327,4 @@ Per-component lines live in `tasks/`. Tags there:
| T27b | 2 | PASS | |
| T27c | 1 | FAIL | recent and found files were keyed by their place, so the cursor left a file an open moved |
| T27c | 2 | PASS | |
| T27d | 1 | FAIL | a press on a finished download's Show button also opened the file through its row |
+19 -2
View File
@@ -1,6 +1,6 @@
use gpui::{
Context, Entity, IntoElement, ParentElement, Render, SharedString, Styled, TestAppContext,
VisualTestContext, Window, div, px,
Context, Entity, IntoElement, Modifiers, ParentElement, Render, SharedString, Styled,
TestAppContext, VisualTestContext, Window, div, px,
};
use super::{press, settle, setup};
@@ -255,3 +255,20 @@ fn a_download_comes_down() {
up.upload = true;
let _ = DownloadManager::new("downloads", [up]);
}
#[gpui::test]
fn a_press_on_show_shows_and_opens_nothing(cx: &mut TestAppContext) {
setup(cx);
let (host, cx) = cx.add_window_view(|_, _| Downloading { asked: Vec::new() });
cx.update(|window, _| window.activate_window());
settle(cx);
let actions = cx
.debug_bounds("transfer-actions done")
.expect("the finished row's actions draw");
cx.simulate_click(actions.center(), Modifiers::none());
settle(cx);
assert_eq!(
host.read_with(cx, |host, _| host.asked.clone()),
["show done"]
);
}
+4 -2
View File
@@ -1,8 +1,8 @@
use std::rc::Rc;
use gpui::{
AnyElement, App, ElementId, InteractiveElement, IntoElement, ParentElement, SharedString,
StatefulInteractiveElement, Styled, Window, div, prelude::*,
AnyElement, App, ElementId, InteractiveElement, IntoElement, MouseButton, ParentElement,
SharedString, StatefulInteractiveElement, Styled, Window, div, prelude::*,
};
use super::FileIcon;
@@ -201,8 +201,10 @@ pub(super) fn row(id: ElementId, transfer: &Transfer, asks: &Asks, cx: &App) ->
)
.child(
div()
.debug_selector(move || format!("transfer-actions {key}"))
.flex_none()
.flex()
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
.children(actions.into_iter().flatten()),
)
.into_any_element()