feat: add sub menu and panel min width to menus

This commit is contained in:
2026-11-10 09:32:51 +07:00
parent 6ad582ba84
commit af2177c6c8
3 changed files with 934 additions and 211 deletions
+33 -19
View File
@@ -5,9 +5,9 @@ use std::rc::Rc;
use gpui::prelude::FluentBuilder as _;
use gpui::{
App, ClickEvent, DispatchPhase, ElementId, InteractiveElement as _, IntoElement, KeyDownEvent,
MouseButton, MouseDownEvent, ParentElement as _, RenderOnce, Role, SharedString,
StatefulInteractiveElement as _, Styled as _, Window, canvas, div, relative,
App, ClickEvent, DefiniteLength, DispatchPhase, ElementId, InteractiveElement as _,
IntoElement, KeyDownEvent, MouseButton, MouseDownEvent, ParentElement as _, RenderOnce, Role,
SharedString, StatefulInteractiveElement as _, Styled as _, Window, canvas, div, relative,
};
use gpui_native_icons::{Icon, IconRole, icon};
use gpui_native_theme::{ActiveTheme as _, BORDER_WIDTH, Size};
@@ -15,7 +15,9 @@ use gpui_native_utils::{focus_handle, focus_ring};
use crate::button::ButtonVariant;
use crate::common::{Sizable, h_flex};
use crate::menu::{ChangeHandler, MenuChrome, MenuItem, TriggerBoundsCell, anchored_menu_panel};
use crate::menu::{
ChangeHandler, MenuChrome, MenuItem, MenuPanelSpec, TriggerBoundsCell, anchored_menu_panel,
};
use crate::spinner::Spinner;
/// The main zone's activation handler, shared by pointer, Enter, and Space.
@@ -38,6 +40,7 @@ pub struct DropdownMenu {
on_click: Option<ClickHandler>,
on_open_change: Option<ChangeHandler>,
items: Option<ItemsFn>,
min_width: Option<DefiniteLength>,
}
impl DropdownMenu {
@@ -60,6 +63,7 @@ impl DropdownMenu {
on_click: None,
on_open_change: None,
items: None,
min_width: None,
}
}
@@ -146,6 +150,15 @@ impl DropdownMenu {
self.items = Some(Box::new(items));
self
}
/// Sets the panel's minimum width, defaults to the standard menu width.
pub fn min_width<W>(mut self, width: W) -> Self
where
W: Into<DefiniteLength>,
{
self.min_width = Some(width.into());
self
}
}
impl Sizable for DropdownMenu {
@@ -374,6 +387,21 @@ impl RenderOnce for DropdownMenu {
Rc::from([])
};
let on_close = Some(on_open.clone());
let spec = MenuPanelSpec {
open: self.open,
items,
initial_selection: None,
preselect: *keyboard_open.read(cx),
min_width: self.min_width,
label,
position: None,
trigger_bounds: trigger_bounds.clone(),
on_dismiss: on_close.clone(),
on_activate: on_close,
};
div()
.relative()
.child(
@@ -431,21 +459,7 @@ impl RenderOnce for DropdownMenu {
)
.child(trigger)
.when_some(
anchored_menu_panel(
window,
cx,
&self.id,
self.open,
items,
None,
*keyboard_open.read(cx),
Some(on_open),
label,
None,
&trigger_bounds,
&panel_chrome,
enter_duration,
),
anchored_menu_panel(window, cx, &self.id, spec, &panel_chrome, enter_duration),
|wrapper, panel| wrapper.child(panel),
)
}