add select component built on menu

This commit is contained in:
2026-11-01 12:06:21 +07:00
parent ac4a0f2add
commit bbb56fdda7
8 changed files with 654 additions and 12 deletions
+18 -11
View File
@@ -7,7 +7,7 @@ use gpui::{
Entity, InteractiveElement as _, IntoElement, KeyDownEvent, MouseButton, MouseDownEvent,
ParentElement as _, Pixels, RenderOnce, Role, ScrollHandle, SharedString,
StatefulInteractiveElement as _, Styled as _, Window, anchored, canvas, deferred, div,
ease_out_quint, px, relative,
ease_out_quint, px,
};
use gpui_native_icons::{IconRole, icon as icon_glyph};
use gpui_native_theme::ActiveTheme as _;
@@ -144,6 +144,7 @@ struct MenuChrome {
pub struct Menu {
id: ElementId,
open: bool,
initial_selection: Option<usize>,
a11y_label: Option<SharedString>,
on_change: Option<ChangeHandler>,
trigger: Option<TriggerFn>,
@@ -159,6 +160,7 @@ impl Menu {
Self {
id: id.into(),
open: false,
initial_selection: None,
a11y_label: None,
on_change: None,
trigger: None,
@@ -166,6 +168,12 @@ impl Menu {
}
}
/// Sets the row keyboard-highlighted when the menu opens.
pub fn initial_selection(mut self, index: usize) -> Self {
self.initial_selection = Some(index);
self
}
/// Sets the current open state.
pub fn open(mut self, open: bool) -> Self {
self.open = open;
@@ -310,6 +318,8 @@ impl RenderOnce for Menu {
let selected = if *was_open.read(cx) {
*selection.read(cx)
} else if let Some(requested) = self.initial_selection {
requested.min(items.len().saturating_sub(1))
} else {
let first = items.iter().position(|item| item.selectable()).unwrap_or(0);
selection.update(cx, |selection, _| *selection = first);
@@ -339,7 +349,6 @@ impl RenderOnce for Menu {
.aria_label(label)
.mt_1()
.min_w_40()
.max_h(relative(0.75))
.p_1()
.bg(chrome.surface)
.text_color(chrome.foreground)
@@ -490,15 +499,6 @@ fn render_item(
}
}
})
.when_some(checked, |row, checked| {
row.child(div().flex_none().when(checked, |slot| {
slot.child(
icon_glyph(IconRole::Check)
.size(chrome.icon_size * 0.75)
.color(label_color),
)
}))
})
.when_some(icon_role, |row, role| {
row.child(icon_glyph(role).size(chrome.icon_size).color(label_color))
})
@@ -519,6 +519,13 @@ fn render_item(
.child(shortcut),
)
})
.when(checked == Some(true), |row| {
row.child(
icon_glyph(IconRole::Check)
.size(chrome.icon_size * 0.75)
.color(label_color),
)
})
.into_any_element()
}
}