ui: Use `PopoverMenu::new` for constructing `PopoverMenu`s (#13178)

Marshall Bowers created

This PR replaces the `popover_menu` function for constructing
`PopoverMenu`s with a `PopoverMenu::new` associated function.

This brings `PopoverMenu` in line with our other UI components.

Release Notes:

- N/A

Change summary

crates/assistant/src/assistant_panel.rs                         |  8 
crates/assistant/src/model_selector.rs                          |  4 
crates/collab_ui/src/chat_panel.rs                              |  4 
crates/collab_ui/src/collab_titlebar_item.rs                    |  8 
crates/extensions_ui/src/extensions_ui.rs                       | 37 +-
crates/inline_completion_button/src/inline_completion_button.rs |  6 
crates/language_tools/src/lsp_log.rs                            |  4 
crates/language_tools/src/syntax_tree_view.rs                   |  6 
crates/ui/src/components/popover_menu.rs                        | 26 +-
9 files changed, 53 insertions(+), 50 deletions(-)

Detailed changes

crates/assistant/src/assistant_panel.rs 🔗

@@ -56,8 +56,8 @@ use std::{
 };
 use telemetry_events::AssistantKind;
 use ui::{
-    popover_menu, prelude::*, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding,
-    ListItem, ListItemSpacing, PopoverMenuHandle, Tab, TabBar, Tooltip,
+    prelude::*, ButtonLike, ContextMenu, Disclosure, ElevationIndex, KeyBinding, ListItem,
+    ListItemSpacing, PopoverMenu, PopoverMenuHandle, Tab, TabBar, Tooltip,
 };
 use util::{paths::CONTEXTS_DIR, post_inc, ResultExt, TryFutureExt};
 use uuid::Uuid;
@@ -578,7 +578,7 @@ impl AssistantPanel {
     fn render_popover_button(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
         let assistant = cx.view().clone();
         let zoomed = self.zoomed;
-        popover_menu("assistant-popover")
+        PopoverMenu::new("assistant-popover")
             .trigger(IconButton::new("trigger", IconName::Menu))
             .menu(move |cx| {
                 let assistant = assistant.clone();
@@ -620,7 +620,7 @@ impl AssistantPanel {
             )
         });
 
-        popover_menu("inject-context-menu")
+        PopoverMenu::new("inject-context-menu")
             .trigger(IconButton::new("trigger", IconName::Quote).tooltip(|cx| {
                 Tooltip::with_meta("Insert Context", None, "Type / to insert via keyboard", cx)
             }))

crates/assistant/src/model_selector.rs 🔗

@@ -3,7 +3,7 @@ use std::sync::Arc;
 use crate::{assistant_settings::AssistantSettings, CompletionProvider, ToggleModelSelector};
 use fs::Fs;
 use settings::update_settings_file;
-use ui::{popover_menu, prelude::*, ButtonLike, ContextMenu, PopoverMenuHandle, Tooltip};
+use ui::{prelude::*, ButtonLike, ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip};
 
 #[derive(IntoElement)]
 pub struct ModelSelector {
@@ -19,7 +19,7 @@ impl ModelSelector {
 
 impl RenderOnce for ModelSelector {
     fn render(self, cx: &mut WindowContext) -> impl IntoElement {
-        popover_menu("model-switcher")
+        PopoverMenu::new("model-switcher")
             .with_handle(self.handle)
             .menu(move |cx| {
                 ContextMenu::build(cx, |mut menu, cx| {

crates/collab_ui/src/chat_panel.rs 🔗

@@ -22,7 +22,7 @@ use settings::Settings;
 use std::{sync::Arc, time::Duration};
 use time::{OffsetDateTime, UtcOffset};
 use ui::{
-    popover_menu, prelude::*, Avatar, Button, ContextMenu, IconButton, IconName, KeyBinding, Label,
+    prelude::*, Avatar, Button, ContextMenu, IconButton, IconName, KeyBinding, Label, PopoverMenu,
     TabBar, Tooltip,
 };
 use util::{ResultExt, TryFutureExt};
@@ -679,7 +679,7 @@ impl ChatPanel {
                         cx,
                         div()
                             .child(
-                                popover_menu(("menu", message_id))
+                                PopoverMenu::new(("menu", message_id))
                                     .trigger(IconButton::new(
                                         ("trigger", message_id),
                                         IconName::Ellipsis,

crates/collab_ui/src/collab_titlebar_item.rs 🔗

@@ -13,8 +13,8 @@ use rpc::proto::{self, DevServerStatus};
 use std::sync::Arc;
 use theme::ActiveTheme;
 use ui::{
-    h_flex, popover_menu, prelude::*, Avatar, AvatarAudioStatusIndicator, Button, ButtonLike,
-    ButtonStyle, ContextMenu, Icon, IconButton, IconName, Indicator, TintColor, TitleBar, Tooltip,
+    h_flex, prelude::*, Avatar, AvatarAudioStatusIndicator, Button, ButtonLike, ButtonStyle,
+    ContextMenu, Icon, IconButton, IconName, Indicator, PopoverMenu, TintColor, TitleBar, Tooltip,
 };
 use util::ResultExt;
 use vcs_menu::{BranchList, OpenRecent as ToggleVcsMenu};
@@ -739,7 +739,7 @@ impl CollabTitlebarItem {
 
     pub fn render_user_menu_button(&mut self, cx: &mut ViewContext<Self>) -> impl Element {
         if let Some(user) = self.user_store.read(cx).current_user() {
-            popover_menu("user-menu")
+            PopoverMenu::new("user-menu")
                 .menu(|cx| {
                     ContextMenu::build(cx, |menu, _| {
                         menu.action("Settings", zed_actions::OpenSettings.boxed_clone())
@@ -767,7 +767,7 @@ impl CollabTitlebarItem {
                 )
                 .anchor(gpui::AnchorCorner::TopRight)
         } else {
-            popover_menu("user-menu")
+            PopoverMenu::new("user-menu")
                 .menu(|cx| {
                     ContextMenu::build(cx, |menu, _| {
                         menu.action("Settings", zed_actions::OpenSettings.boxed_clone())

crates/extensions_ui/src/extensions_ui.rs 🔗

@@ -23,7 +23,7 @@ use std::ops::DerefMut;
 use std::time::Duration;
 use std::{ops::Range, sync::Arc};
 use theme::ThemeSettings;
-use ui::{popover_menu, prelude::*, ContextMenu, ToggleButton, Tooltip};
+use ui::{prelude::*, ContextMenu, PopoverMenu, ToggleButton, Tooltip};
 use util::ResultExt as _;
 use workspace::item::TabContentParams;
 use workspace::{
@@ -526,23 +526,26 @@ impl ExtensionsPage {
                                 .tooltip(move |cx| Tooltip::text(repository_url.clone(), cx)),
                             )
                             .child(
-                                popover_menu(SharedString::from(format!("more-{}", extension.id)))
-                                    .trigger(
-                                        IconButton::new(
-                                            SharedString::from(format!("more-{}", extension.id)),
-                                            IconName::Ellipsis,
-                                        )
-                                        .icon_color(Color::Accent)
-                                        .icon_size(IconSize::Small)
-                                        .style(ButtonStyle::Filled),
+                                PopoverMenu::new(SharedString::from(format!(
+                                    "more-{}",
+                                    extension.id
+                                )))
+                                .trigger(
+                                    IconButton::new(
+                                        SharedString::from(format!("more-{}", extension.id)),
+                                        IconName::Ellipsis,
                                     )
-                                    .menu(move |cx| {
-                                        Some(Self::render_remote_extension_context_menu(
-                                            &this,
-                                            extension_id.clone(),
-                                            cx,
-                                        ))
-                                    }),
+                                    .icon_color(Color::Accent)
+                                    .icon_size(IconSize::Small)
+                                    .style(ButtonStyle::Filled),
+                                )
+                                .menu(move |cx| {
+                                    Some(Self::render_remote_extension_context_menu(
+                                        &this,
+                                        extension_id.clone(),
+                                        cx,
+                                    ))
+                                }),
                             ),
                     ),
             )

crates/inline_completion_button/src/inline_completion_button.rs 🔗

@@ -21,7 +21,7 @@ use workspace::{
     item::ItemHandle,
     notifications::NotificationId,
     ui::{
-        popover_menu, ButtonCommon, Clickable, ContextMenu, IconButton, IconName, IconSize, Tooltip,
+        ButtonCommon, Clickable, ContextMenu, IconButton, IconName, IconSize, PopoverMenu, Tooltip,
     },
     StatusItemView, Toast, Workspace,
 };
@@ -112,7 +112,7 @@ impl Render for InlineCompletionButton {
                 let this = cx.view().clone();
 
                 div().child(
-                    popover_menu("copilot")
+                    PopoverMenu::new("copilot")
                         .menu(move |cx| {
                             Some(match status {
                                 Status::Authorized => {
@@ -161,7 +161,7 @@ impl Render for InlineCompletionButton {
                 let this = cx.view().clone();
 
                 return div().child(
-                    popover_menu("supermaven")
+                    PopoverMenu::new("supermaven")
                         .menu(move |cx| match &status {
                             SupermavenButtonStatus::NeedsActivation(activate_url) => {
                                 Some(ContextMenu::build(cx, |menu, _| {

crates/language_tools/src/lsp_log.rs 🔗

@@ -11,7 +11,7 @@ use language::{LanguageServerId, LanguageServerName};
 use lsp::{IoKind, LanguageServer};
 use project::{search::SearchQuery, Project};
 use std::{borrow::Cow, sync::Arc};
-use ui::{popover_menu, prelude::*, Button, Checkbox, ContextMenu, Label, Selection};
+use ui::{prelude::*, Button, Checkbox, ContextMenu, Label, PopoverMenu, Selection};
 use workspace::{
     item::{Item, ItemHandle, TabContentParams},
     searchable::{SearchEvent, SearchableItem, SearchableItemHandle},
@@ -821,7 +821,7 @@ impl Render for LspLogToolbarItemView {
         });
 
         let log_toolbar_view = cx.view().clone();
-        let lsp_menu = popover_menu("LspLogView")
+        let lsp_menu = PopoverMenu::new("LspLogView")
             .anchor(AnchorCorner::TopLeft)
             .trigger(Button::new(
                 "language_server_menu_header",

crates/language_tools/src/syntax_tree_view.rs 🔗

@@ -9,7 +9,7 @@ use language::{Buffer, OwnedSyntaxLayer};
 use std::{mem, ops::Range};
 use theme::ActiveTheme;
 use tree_sitter::{Node, TreeCursor};
-use ui::{h_flex, popover_menu, ButtonLike, Color, ContextMenu, Label, LabelCommon, PopoverMenu};
+use ui::{h_flex, ButtonLike, Color, ContextMenu, Label, LabelCommon, PopoverMenu};
 use workspace::{
     item::{Item, ItemHandle, TabContentParams},
     SplitDirection, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
@@ -431,7 +431,7 @@ impl SyntaxTreeToolbarItemView {
 
         let view = cx.view().clone();
         Some(
-            popover_menu("Syntax Tree")
+            PopoverMenu::new("Syntax Tree")
                 .trigger(Self::render_header(&active_layer))
                 .menu(move |cx| {
                     ContextMenu::build(cx, |mut menu, cx| {
@@ -492,7 +492,7 @@ fn format_node_range(node: Node) -> String {
 impl Render for SyntaxTreeToolbarItemView {
     fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> impl IntoElement {
         self.render_menu(cx)
-            .unwrap_or_else(|| popover_menu("Empty Syntax Tree"))
+            .unwrap_or_else(|| PopoverMenu::new("Empty Syntax Tree"))
     }
 }
 

crates/ui/src/components/popover_menu.rs 🔗

@@ -77,6 +77,19 @@ pub struct PopoverMenu<M: ManagedView> {
 }
 
 impl<M: ManagedView> PopoverMenu<M> {
+    /// Returns a new [`PopoverMenu`].
+    pub fn new(id: impl Into<ElementId>) -> Self {
+        Self {
+            id: id.into(),
+            child_builder: None,
+            menu_builder: None,
+            anchor: AnchorCorner::TopLeft,
+            attach: None,
+            offset: None,
+            trigger_handle: None,
+        }
+    }
+
     pub fn menu(mut self, f: impl Fn(&mut WindowContext) -> Option<View<M>> + 'static) -> Self {
         self.menu_builder = Some(Rc::new(f));
         self
@@ -165,19 +178,6 @@ fn show_menu<M: ManagedView>(
     cx.refresh();
 }
 
-/// Creates a [`PopoverMenu`]
-pub fn popover_menu<M: ManagedView>(id: impl Into<ElementId>) -> PopoverMenu<M> {
-    PopoverMenu {
-        id: id.into(),
-        child_builder: None,
-        menu_builder: None,
-        anchor: AnchorCorner::TopLeft,
-        attach: None,
-        offset: None,
-        trigger_handle: None,
-    }
-}
-
 pub struct PopoverMenuElementState<M> {
     menu: Rc<RefCell<Option<View<M>>>>,
     child_bounds: Option<Bounds<Pixels>>,