gpui: Press `enter`, `space` to trigger click to focused element (#35075)

Jason Lee , Anthony , Mikayla Maki , and Umesh Yadav created

Release Notes:

- N/A

> Any user interaction that is equivalent to a click, such as pressing
the Space key or Enter key while the element is focused. Note that this
only applies to elements with a default key event handler, and
therefore, excludes other elements that have been made focusable by
setting the
[tabindex](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/tabindex)
attribute.

https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event

---------

Co-authored-by: Anthony <anthony@zed.dev>
Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
Co-authored-by: Umesh Yadav <23421535+imumesh18@users.noreply.github.com>

Change summary

crates/agent_ui/src/context_strip.rs                    |   2 
crates/collab_ui/src/collab_panel.rs                    |   2 
crates/debugger_ui/src/session/running/variable_list.rs |   2 
crates/editor/src/editor.rs                             |  10 
crates/editor/src/element.rs                            |  24 +
crates/gpui/examples/tab_stop.rs                        |  20 +
crates/gpui/examples/window_shadow.rs                   |   4 
crates/gpui/src/elements/div.rs                         |  60 ++++
crates/gpui/src/interactive.rs                          | 123 ++++++++++
crates/gpui/src/window.rs                               |   2 
crates/markdown_preview/src/markdown_preview_view.rs    |   2 
crates/outline_panel/src/outline_panel.rs               |   4 
crates/project_panel/src/project_panel.rs               |  16 
crates/recent_projects/src/remote_servers.rs            |   2 
crates/settings_ui/src/keybindings.rs                   |   2 
crates/settings_ui/src/ui_components/table.rs           |   4 
crates/title_bar/src/platform_title_bar.rs              |   4 
crates/ui/src/components/button/button_like.rs          |   7 
crates/workspace/src/pane.rs                            |   4 
19 files changed, 231 insertions(+), 63 deletions(-)

Detailed changes

crates/agent_ui/src/context_strip.rs 🔗

@@ -504,7 +504,7 @@ impl Render for ContextStrip {
                         )
                         .on_click({
                             Rc::new(cx.listener(move |this, event: &ClickEvent, window, cx| {
-                                if event.down.click_count > 1 {
+                                if event.click_count() > 1 {
                                     this.open_context(&context, window, cx);
                                 } else {
                                     this.focused_index = Some(i);

crates/collab_ui/src/collab_panel.rs 🔗

@@ -2605,7 +2605,7 @@ impl CollabPanel {
                                     let contact = contact.clone();
                                     move |this, event: &ClickEvent, window, cx| {
                                         this.deploy_contact_context_menu(
-                                            event.down.position,
+                                            event.position(),
                                             contact.clone(),
                                             window,
                                             cx,

crates/debugger_ui/src/session/running/variable_list.rs 🔗

@@ -1107,7 +1107,7 @@ impl VariableList {
                                     let variable_value = value.clone();
                                     this.on_click(cx.listener(
                                         move |this, click: &ClickEvent, window, cx| {
-                                            if click.down.click_count < 2 {
+                                            if click.click_count() < 2 {
                                                 return;
                                             }
                                             let editor = Self::create_variable_editor(

crates/editor/src/editor.rs 🔗

@@ -8183,7 +8183,7 @@ impl Editor {
                 editor.set_breakpoint_context_menu(
                     row,
                     Some(position),
-                    event.down.position,
+                    event.position(),
                     window,
                     cx,
                 );
@@ -8350,7 +8350,11 @@ impl Editor {
         .icon_color(color)
         .toggle_state(is_active)
         .on_click(cx.listener(move |editor, e: &ClickEvent, window, cx| {
-            let quick_launch = e.down.button == MouseButton::Left;
+            let quick_launch = match e {
+                ClickEvent::Keyboard(_) => true,
+                ClickEvent::Mouse(e) => e.down.button == MouseButton::Left,
+            };
+
             window.focus(&editor.focus_handle(cx));
             editor.toggle_code_actions(
                 &ToggleCodeActions {
@@ -8362,7 +8366,7 @@ impl Editor {
             );
         }))
         .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
-            editor.set_breakpoint_context_menu(row, position, event.down.position, window, cx);
+            editor.set_breakpoint_context_menu(row, position, event.position(), window, cx);
         }))
     }
 

crates/editor/src/element.rs 🔗

@@ -43,11 +43,11 @@ use gpui::{
     Bounds, ClickEvent, ContentMask, Context, Corner, Corners, CursorStyle, DispatchPhase, Edges,
     Element, ElementInputHandler, Entity, Focusable as _, FontId, GlobalElementId, Hitbox,
     HitboxBehavior, Hsla, InteractiveElement, IntoElement, IsZero, Keystroke, Length,
-    ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
-    ParentElement, Pixels, ScrollDelta, ScrollHandle, ScrollWheelEvent, ShapedLine, SharedString,
-    Size, StatefulInteractiveElement, Style, Styled, TextRun, TextStyleRefinement, WeakEntity,
-    Window, anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, point, px,
-    quad, relative, size, solid_background, transparent_black,
+    ModifiersChangedEvent, MouseButton, MouseClickEvent, MouseDownEvent, MouseMoveEvent,
+    MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta, ScrollHandle, ScrollWheelEvent,
+    ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled, TextRun,
+    TextStyleRefinement, WeakEntity, Window, anchored, deferred, div, fill, linear_color_stop,
+    linear_gradient, outline, point, px, quad, relative, size, solid_background, transparent_black,
 };
 use itertools::Itertools;
 use language::language_settings::{
@@ -949,8 +949,12 @@ impl EditorElement {
 
         let hovered_link_modifier = Editor::multi_cursor_modifier(false, &event.modifiers(), cx);
 
-        if !pending_nonempty_selections && hovered_link_modifier && text_hitbox.is_hovered(window) {
-            let point = position_map.point_for_position(event.up.position);
+        if let Some(mouse_position) = event.mouse_position()
+            && !pending_nonempty_selections
+            && hovered_link_modifier
+            && text_hitbox.is_hovered(window)
+        {
+            let point = position_map.point_for_position(mouse_position);
             editor.handle_click_hovered_link(point, event.modifiers(), window, cx);
             editor.selection_drag_state = SelectionDragState::None;
 
@@ -3735,7 +3739,7 @@ impl EditorElement {
                                 move |editor, e: &ClickEvent, window, cx| {
                                     editor.open_excerpts_common(
                                         Some(jump_data.clone()),
-                                        e.down.modifiers.secondary(),
+                                        e.modifiers().secondary(),
                                         window,
                                         cx,
                                     );
@@ -6882,10 +6886,10 @@ impl EditorElement {
                 // Fire click handlers during the bubble phase.
                 DispatchPhase::Bubble => editor.update(cx, |editor, cx| {
                     if let Some(mouse_down) = captured_mouse_down.take() {
-                        let event = ClickEvent {
+                        let event = ClickEvent::Mouse(MouseClickEvent {
                             down: mouse_down,
                             up: event.clone(),
-                        };
+                        });
                         Self::click(editor, &event, &position_map, window, cx);
                     }
                 }),

crates/gpui/examples/tab_stop.rs 🔗

@@ -111,8 +111,24 @@ impl Render for Example {
                     .flex_row()
                     .gap_3()
                     .items_center()
-                    .child(button("el1").tab_index(4).child("Button 1"))
-                    .child(button("el2").tab_index(5).child("Button 2")),
+                    .child(
+                        button("el1")
+                            .tab_index(4)
+                            .child("Button 1")
+                            .on_click(cx.listener(|this, _, _, cx| {
+                                this.message = "You have clicked Button 1.".into();
+                                cx.notify();
+                            })),
+                    )
+                    .child(
+                        button("el2")
+                            .tab_index(5)
+                            .child("Button 2")
+                            .on_click(cx.listener(|this, _, _, cx| {
+                                this.message = "You have clicked Button 2.".into();
+                                cx.notify();
+                            })),
+                    ),
             )
     }
 }

crates/gpui/examples/window_shadow.rs 🔗

@@ -165,8 +165,8 @@ impl Render for WindowShadow {
                                                     },
                                                 )
                                                 .on_click(|e, window, _| {
-                                                    if e.down.button == MouseButton::Right {
-                                                        window.show_window_menu(e.up.position);
+                                                    if e.is_right_click() {
+                                                        window.show_window_menu(e.position());
                                                     }
                                                 })
                                                 .text_color(black())

crates/gpui/src/elements/div.rs 🔗

@@ -19,10 +19,10 @@ use crate::{
     Action, AnyDrag, AnyElement, AnyTooltip, AnyView, App, Bounds, ClickEvent, DispatchPhase,
     Element, ElementId, Entity, FocusHandle, Global, GlobalElementId, Hitbox, HitboxBehavior,
     HitboxId, InspectorElementId, IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent,
-    LayoutId, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
-    Overflow, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
-    StyleRefinement, Styled, Task, TooltipId, Visibility, Window, WindowControlArea, point, px,
-    size,
+    KeyboardButton, KeyboardClickEvent, LayoutId, ModifiersChangedEvent, MouseButton,
+    MouseClickEvent, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Overflow, ParentElement, Pixels,
+    Point, Render, ScrollWheelEvent, SharedString, Size, Style, StyleRefinement, Styled, Task,
+    TooltipId, Visibility, Window, WindowControlArea, point, px, size,
 };
 use collections::HashMap;
 use refineable::Refineable;
@@ -484,10 +484,9 @@ impl Interactivity {
     where
         Self: Sized,
     {
-        self.click_listeners
-            .push(Box::new(move |event, window, cx| {
-                listener(event, window, cx)
-            }));
+        self.click_listeners.push(Rc::new(move |event, window, cx| {
+            listener(event, window, cx)
+        }));
     }
 
     /// On drag initiation, this callback will be used to create a new view to render the dragged value for a
@@ -1156,7 +1155,7 @@ pub(crate) type MouseMoveListener =
 pub(crate) type ScrollWheelListener =
     Box<dyn Fn(&ScrollWheelEvent, DispatchPhase, &Hitbox, &mut Window, &mut App) + 'static>;
 
-pub(crate) type ClickListener = Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>;
+pub(crate) type ClickListener = Rc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>;
 
 pub(crate) type DragListener =
     Box<dyn Fn(&dyn Any, Point<Pixels>, &mut Window, &mut App) -> AnyView + 'static>;
@@ -1950,6 +1949,12 @@ impl Interactivity {
         window: &mut Window,
         cx: &mut App,
     ) {
+        let is_focused = self
+            .tracked_focus_handle
+            .as_ref()
+            .map(|handle| handle.is_focused(window))
+            .unwrap_or(false);
+
         // If this element can be focused, register a mouse down listener
         // that will automatically transfer focus when hitting the element.
         // This behavior can be suppressed by using `cx.prevent_default()`.
@@ -2113,6 +2118,39 @@ impl Interactivity {
                     }
                 });
 
+                if is_focused {
+                    // Press enter, space to trigger click, when the element is focused.
+                    window.on_key_event({
+                        let click_listeners = click_listeners.clone();
+                        let hitbox = hitbox.clone();
+                        move |event: &KeyUpEvent, phase, window, cx| {
+                            if phase.bubble() && !window.default_prevented() {
+                                let stroke = &event.keystroke;
+                                let keyboard_button = if stroke.key.eq("enter") {
+                                    Some(KeyboardButton::Enter)
+                                } else if stroke.key.eq("space") {
+                                    Some(KeyboardButton::Space)
+                                } else {
+                                    None
+                                };
+
+                                if let Some(button) = keyboard_button
+                                    && !stroke.modifiers.modified()
+                                {
+                                    let click_event = ClickEvent::Keyboard(KeyboardClickEvent {
+                                        button,
+                                        bounds: hitbox.bounds,
+                                    });
+
+                                    for listener in &click_listeners {
+                                        listener(&click_event, window, cx);
+                                    }
+                                }
+                            }
+                        }
+                    });
+                }
+
                 window.on_mouse_event({
                     let mut captured_mouse_down = None;
                     let hitbox = hitbox.clone();
@@ -2138,10 +2176,10 @@ impl Interactivity {
                         // Fire click handlers during the bubble phase.
                         DispatchPhase::Bubble => {
                             if let Some(mouse_down) = captured_mouse_down.take() {
-                                let mouse_click = ClickEvent {
+                                let mouse_click = ClickEvent::Mouse(MouseClickEvent {
                                     down: mouse_down,
                                     up: event.clone(),
-                                };
+                                });
                                 for listener in &click_listeners {
                                     listener(&mouse_click, window, cx);
                                 }

crates/gpui/src/interactive.rs 🔗

@@ -1,6 +1,6 @@
 use crate::{
-    Capslock, Context, Empty, IntoElement, Keystroke, Modifiers, Pixels, Point, Render, Window,
-    point, seal::Sealed,
+    Bounds, Capslock, Context, Empty, IntoElement, Keystroke, Modifiers, Pixels, Point, Render,
+    Window, point, seal::Sealed,
 };
 use smallvec::SmallVec;
 use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf};
@@ -141,7 +141,7 @@ impl MouseEvent for MouseUpEvent {}
 
 /// A click event, generated when a mouse button is pressed and released.
 #[derive(Clone, Debug, Default)]
-pub struct ClickEvent {
+pub struct MouseClickEvent {
     /// The mouse event when the button was pressed.
     pub down: MouseDownEvent,
 
@@ -149,18 +149,119 @@ pub struct ClickEvent {
     pub up: MouseUpEvent,
 }
 
+/// A click event that was generated by a keyboard button being pressed and released.
+#[derive(Clone, Debug)]
+pub struct KeyboardClickEvent {
+    /// The keyboard button that was pressed to trigger the click.
+    pub button: KeyboardButton,
+
+    /// The bounds of the element that was clicked.
+    pub bounds: Bounds<Pixels>,
+}
+
+/// A click event, generated when a mouse button or keyboard button is pressed and released.
+#[derive(Clone, Debug)]
+pub enum ClickEvent {
+    /// A click event trigger by a mouse button being pressed and released.
+    Mouse(MouseClickEvent),
+    /// A click event trigger by a keyboard button being pressed and released.
+    Keyboard(KeyboardClickEvent),
+}
+
 impl ClickEvent {
-    /// Returns the modifiers that were held down during both the
-    /// mouse down and mouse up events
+    /// Returns the modifiers that were held during the click event
+    ///
+    /// `Keyboard`: The keyboard click events never have modifiers.
+    /// `Mouse`: Modifiers that were held during the mouse key up event.
     pub fn modifiers(&self) -> Modifiers {
-        Modifiers {
-            control: self.up.modifiers.control && self.down.modifiers.control,
-            alt: self.up.modifiers.alt && self.down.modifiers.alt,
-            shift: self.up.modifiers.shift && self.down.modifiers.shift,
-            platform: self.up.modifiers.platform && self.down.modifiers.platform,
-            function: self.up.modifiers.function && self.down.modifiers.function,
+        match self {
+            // Click events are only generated from keyboard events _without any modifiers_, so we know the modifiers are always Default
+            ClickEvent::Keyboard(_) => Modifiers::default(),
+            // Click events on the web only reflect the modifiers for the keyup event,
+            // tested via observing the behavior of the `ClickEvent.shiftKey` field in Chrome 138
+            // under various combinations of modifiers and keyUp / keyDown events.
+            ClickEvent::Mouse(event) => event.up.modifiers,
         }
     }
+
+    /// Returns the position of the click event
+    ///
+    /// `Keyboard`: The bottom left corner of the clicked hitbox
+    /// `Mouse`: The position of the mouse when the button was released.
+    pub fn position(&self) -> Point<Pixels> {
+        match self {
+            ClickEvent::Keyboard(event) => event.bounds.bottom_left(),
+            ClickEvent::Mouse(event) => event.up.position,
+        }
+    }
+
+    /// Returns the mouse position of the click event
+    ///
+    /// `Keyboard`: None
+    /// `Mouse`: The position of the mouse when the button was released.
+    pub fn mouse_position(&self) -> Option<Point<Pixels>> {
+        match self {
+            ClickEvent::Keyboard(_) => None,
+            ClickEvent::Mouse(event) => Some(event.up.position),
+        }
+    }
+
+    /// Returns if this was a right click
+    ///
+    /// `Keyboard`: false
+    /// `Mouse`: Whether the right button was pressed and released
+    pub fn is_right_click(&self) -> bool {
+        match self {
+            ClickEvent::Keyboard(_) => false,
+            ClickEvent::Mouse(event) => {
+                event.down.button == MouseButton::Right && event.up.button == MouseButton::Right
+            }
+        }
+    }
+
+    /// Returns whether the click was a standard click
+    ///
+    /// `Keyboard`: Always true
+    /// `Mouse`: Left button pressed and released
+    pub fn standard_click(&self) -> bool {
+        match self {
+            ClickEvent::Keyboard(_) => true,
+            ClickEvent::Mouse(event) => {
+                event.down.button == MouseButton::Left && event.up.button == MouseButton::Left
+            }
+        }
+    }
+
+    /// Returns whether the click focused the element
+    ///
+    /// `Keyboard`: false, keyboard clicks only work if an element is already focused
+    /// `Mouse`: Whether this was the first focusing click
+    pub fn first_focus(&self) -> bool {
+        match self {
+            ClickEvent::Keyboard(_) => false,
+            ClickEvent::Mouse(event) => event.down.first_mouse,
+        }
+    }
+
+    /// Returns the click count of the click event
+    ///
+    /// `Keyboard`: Always 1
+    /// `Mouse`: Count of clicks from MouseUpEvent
+    pub fn click_count(&self) -> usize {
+        match self {
+            ClickEvent::Keyboard(_) => 1,
+            ClickEvent::Mouse(event) => event.up.click_count,
+        }
+    }
+}
+
+/// An enum representing the keyboard button that was pressed for a click event.
+#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
+pub enum KeyboardButton {
+    /// Enter key was clicked
+    Enter,
+    /// Space key was clicked
+    Space,
 }
 
 /// An enum representing the mouse button that was pressed.

crates/gpui/src/window.rs 🔗

@@ -79,11 +79,13 @@ pub enum DispatchPhase {
 
 impl DispatchPhase {
     /// Returns true if this represents the "bubble" phase.
+    #[inline]
     pub fn bubble(self) -> bool {
         self == DispatchPhase::Bubble
     }
 
     /// Returns true if this represents the "capture" phase.
+    #[inline]
     pub fn capture(self) -> bool {
         self == DispatchPhase::Capture
     }

crates/markdown_preview/src/markdown_preview_view.rs 🔗

@@ -261,7 +261,7 @@ impl MarkdownPreviewView {
                                 .group("markdown-block")
                                 .on_click(cx.listener(
                                     move |this, event: &ClickEvent, window, cx| {
-                                        if event.down.click_count == 2 {
+                                        if event.click_count() == 2 {
                                             if let Some(source_range) = this
                                                 .contents
                                                 .as_ref()

crates/outline_panel/src/outline_panel.rs 🔗

@@ -2570,11 +2570,11 @@ impl OutlinePanel {
             .on_click({
                 let clicked_entry = rendered_entry.clone();
                 cx.listener(move |outline_panel, event: &gpui::ClickEvent, window, cx| {
-                    if event.down.button == MouseButton::Right || event.down.first_mouse {
+                    if event.is_right_click() || event.first_focus() {
                         return;
                     }
 
-                    let change_focus = event.down.click_count > 1;
+                    let change_focus = event.click_count() > 1;
                     outline_panel.toggle_expanded(&clicked_entry, window, cx);
 
                     outline_panel.scroll_editor_to_entry(

crates/project_panel/src/project_panel.rs 🔗

@@ -4157,13 +4157,12 @@ impl ProjectPanel {
             )
             .on_click(
                 cx.listener(move |this, event: &gpui::ClickEvent, window, cx| {
-                    if event.down.button == MouseButton::Right
-                        || event.down.first_mouse
+                    if event.is_right_click() || event.first_focus()
                         || show_editor
                     {
                         return;
                     }
-                    if event.down.button == MouseButton::Left {
+                    if event.standard_click() {
                         this.mouse_down = false;
                     }
                     cx.stop_propagation();
@@ -4203,7 +4202,7 @@ impl ProjectPanel {
                             this.marked_entries.insert(clicked_entry);
                         }
                     } else if event.modifiers().secondary() {
-                        if event.down.click_count > 1 {
+                        if event.click_count() > 1 {
                             this.split_entry(entry_id, cx);
                         } else {
                             this.selection = Some(selection);
@@ -4237,7 +4236,7 @@ impl ProjectPanel {
                         }
                     } else {
                         let preview_tabs_enabled = PreviewTabsSettings::get_global(cx).enabled;
-                        let click_count = event.up.click_count;
+                        let click_count = event.click_count();
                         let focus_opened_item = !preview_tabs_enabled || click_count > 1;
                         let allow_preview = preview_tabs_enabled && click_count == 1;
                         this.open_entry(entry_id, focus_opened_item, allow_preview, cx);
@@ -5138,7 +5137,10 @@ impl Render for ProjectPanel {
                         this.hide_scrollbar(window, cx);
                     }
                 }))
-                .on_click(cx.listener(|this, _event, _, cx| {
+                .on_click(cx.listener(|this, event, _, cx| {
+                    if matches!(event, gpui::ClickEvent::Keyboard(_)) {
+                        return;
+                    }
                     cx.stop_propagation();
                     this.selection = None;
                     this.marked_entries.clear();
@@ -5179,7 +5181,7 @@ impl Render for ProjectPanel {
                         .on_action(cx.listener(Self::paste))
                         .on_action(cx.listener(Self::duplicate))
                         .on_click(cx.listener(|this, event: &gpui::ClickEvent, window, cx| {
-                            if event.up.click_count > 1 {
+                            if event.click_count() > 1 {
                                 if let Some(entry_id) = this.last_worktree_root_id {
                                     let project = this.project.read(cx);
 

crates/recent_projects/src/remote_servers.rs 🔗

@@ -953,7 +953,7 @@ impl RemoteServerProjects {
                     )
                     .child(Label::new(project.paths.join(", ")))
                     .on_click(cx.listener(move |this, e: &ClickEvent, window, cx| {
-                        let secondary_confirm = e.down.modifiers.platform;
+                        let secondary_confirm = e.modifiers().platform;
                         callback(this, secondary_confirm, window, cx)
                     }))
                     .when(is_from_zed, |server_list_item| {

crates/settings_ui/src/keybindings.rs 🔗

@@ -1855,7 +1855,7 @@ impl Render for KeymapEditor {
                                         .on_click(cx.listener(
                                             move |this, event: &ClickEvent, window, cx| {
                                                 this.select_index(row_index, None, window, cx);
-                                                if event.up.click_count == 2 {
+                                                if event.click_count() == 2 {
                                                     this.open_edit_keybinding_modal(
                                                         false, window, cx,
                                                     );

crates/settings_ui/src/ui_components/table.rs 🔗

@@ -248,7 +248,7 @@ impl TableInteractionState {
                         .cursor_col_resize()
                         .when_some(columns.clone(), |this, columns| {
                             this.on_click(move |event, window, cx| {
-                                if event.down.click_count >= 2 {
+                                if event.click_count() >= 2 {
                                     columns.update(cx, |columns, _| {
                                         columns.on_double_click(
                                             column_ix,
@@ -997,7 +997,7 @@ pub fn render_header<const COLS: usize>(
                         |this, (column_widths, resizables, initial_sizes)| {
                             if resizables[header_idx].is_resizable() {
                                 this.on_click(move |event, window, cx| {
-                                    if event.down.click_count > 1 {
+                                    if event.click_count() > 1 {
                                         column_widths
                                             .update(cx, |column, _| {
                                                 column.on_double_click(

crates/title_bar/src/platform_title_bar.rs 🔗

@@ -106,14 +106,14 @@ impl Render for PlatformTitleBar {
                     // Note: On Windows the title bar behavior is handled by the platform implementation.
                     .when(self.platform_style == PlatformStyle::Mac, |this| {
                         this.on_click(|event, window, _| {
-                            if event.up.click_count == 2 {
+                            if event.click_count() == 2 {
                                 window.titlebar_double_click();
                             }
                         })
                     })
                     .when(self.platform_style == PlatformStyle::Linux, |this| {
                         this.on_click(|event, window, _| {
-                            if event.up.click_count == 2 {
+                            if event.click_count() == 2 {
                                 window.zoom_window();
                             }
                         })

crates/ui/src/components/button/button_like.rs 🔗

@@ -1,7 +1,8 @@
 use documented::Documented;
 use gpui::{
     AnyElement, AnyView, ClickEvent, CursorStyle, DefiniteLength, Hsla, MouseButton,
-    MouseDownEvent, MouseUpEvent, Rems, StyleRefinement, relative, transparent_black,
+    MouseClickEvent, MouseDownEvent, MouseUpEvent, Rems, StyleRefinement, relative,
+    transparent_black,
 };
 use smallvec::SmallVec;
 
@@ -620,7 +621,7 @@ impl RenderOnce for ButtonLike {
                         MouseButton::Right,
                         move |event, window, cx| {
                             cx.stop_propagation();
-                            let click_event = ClickEvent {
+                            let click_event = ClickEvent::Mouse(MouseClickEvent {
                                 down: MouseDownEvent {
                                     button: MouseButton::Right,
                                     position: event.position,
@@ -634,7 +635,7 @@ impl RenderOnce for ButtonLike {
                                     modifiers: event.modifiers,
                                     click_count: 1,
                                 },
-                            };
+                            });
                             (on_right_click)(&click_event, window, cx)
                         },
                     )

crates/workspace/src/pane.rs 🔗

@@ -2945,7 +2945,7 @@ impl Pane {
                                 this.handle_external_paths_drop(paths, window, cx)
                             }))
                             .on_click(cx.listener(move |this, event: &ClickEvent, window, cx| {
-                                if event.up.click_count == 2 {
+                                if event.click_count() == 2 {
                                     window.dispatch_action(
                                         this.double_click_dispatch_action.boxed_clone(),
                                         cx,
@@ -3640,7 +3640,7 @@ impl Render for Pane {
                                 .justify_center()
                                 .on_click(cx.listener(
                                     move |this, event: &ClickEvent, window, cx| {
-                                        if event.up.click_count == 2 {
+                                        if event.click_count() == 2 {
                                             window.dispatch_action(
                                                 this.double_click_dispatch_action.boxed_clone(),
                                                 cx,