Mail · a focused star keeps Space and Enter; so does Unpin

A button in a SelectableList row now stops Space and Enter at its box
on key down, so the list no longer toggles its selection before the
button acts. The mail star and the pinned messages' Unpin, which had
the same fault, both do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZacharyZhang-NYandClaude Opus 5.5 committed 2026-09-26 23:45:22 -04:00
1 parent b6b1224c27
commit 0a281d91ab
5 files changed
+38 -1

No files matched your search

+1 -1
View File
@@ -73,7 +73,7 @@ Ely GPUI Component. A component library for GPUI, in light and dark.
- 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.
- 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, and a button in a `SelectableList` row stops Space and Enter at its box (`mail::MailItem`'s star, `messaging::PinnedMessages`' Unpin).
- 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.
- A dialog goes through `overlays::Dialog`: scrim, focus trap, Escape and focus return live there. Its close runs on every way out, so a dialog with two answers marks the chosen one before it closes (`messaging::IncomingCallDialog`). AlertDialog, ConfirmDialog and PromptDialog build on it; a fullscreen dialog fills the window below its title bar. A dialog's card fits the window, a title bar's height clear at each end; its body scrolls and its actions stay.
- Controls on a dark layer over pictures are `overlays::media_button`, light icons that dim when they have nowhere to go, for the lightbox and a video player's bar alike.
+8
View File
@@ -166,6 +166,14 @@ impl MailItem {
window.prevent_default();
cx.stop_propagation();
})
.on_key_down(|event, _, cx| {
let key = event.keystroke.key.as_str();
if matches!(key, "space" | "enter")
&& !event.keystroke.modifiers.modified()
{
cx.stop_propagation();
}
})
.on_click(move |_, window, cx| {
log::info!("mail {key}: star {}", !starred);
set(!starred, window, cx)
+10
View File
@@ -187,6 +187,16 @@ fn a_star_toggles_and_leaves_the_selection(cx: &mut TestAppContext) {
assert_eq!(heard(&host, cx), ["star m3 false"]);
}
#[gpui::test]
fn space_on_a_star_stars_and_leaves_the_selection(cx: &mut TestAppContext) {
let (host, cx) = mailing(mails, cx);
tab_to(2, cx);
press("space", cx);
tab_to(2, cx);
press("enter", cx);
assert_eq!(heard(&host, cx), ["star m1 true", "star m1 true"]);
}
#[gpui::test]
fn no_mail_says_so_and_takes_no_tab_stop(cx: &mut TestAppContext) {
let (_, cx) = mailing(
+8
View File
@@ -90,6 +90,14 @@ impl RenderOnce for PinnedMessages {
div()
.debug_selector(move || format!("unpin {named}"))
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
.on_key_down(|event, _, cx| {
let key = event.keystroke.key.as_str();
if matches!(key, "space" | "enter")
&& !event.keystroke.modifiers.modified()
{
cx.stop_propagation();
}
})
.child(
IconButton::new(
(self.id.clone(), format!("unpin-{key}")),
+11
View File
@@ -221,6 +221,17 @@ fn a_press_on_unpin_unpins_and_opens_nothing(cx: &mut TestAppContext) {
);
}
#[gpui::test]
fn space_on_unpin_unpins_and_opens_nothing(cx: &mut TestAppContext) {
let (host, cx) = pinning(cx);
tab_to(2, cx);
press("space", cx);
assert_eq!(
host.read_with(cx, |host, _| host.asked.clone()),
["unpin newer"]
);
}
#[test]
#[should_panic(expected = "pin a twice")]
fn a_message_is_pinned_once() {