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
+98
View File
@@ -0,0 +1,98 @@
use std::{cell::RefCell, rc::Rc};
use gpui::{
Context, IntoElement, MouseButton, ParentElement as _, Render, Styled as _, TestAppContext,
VisualTestContext, Window, div, point, px,
};
use gpui_native_core::select::Select;
use gpui_native_theme::Theme;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Level {
Low,
Mid,
High,
}
const LEVELS: [(Level, &str); 3] = [
(Level::Low, "Low"),
(Level::Mid, "Mid"),
(Level::High, "High"),
];
type Changes = Rc<RefCell<Vec<Option<Level>>>>;
struct Harness {
value: Option<Level>,
changes: Changes,
}
impl Render for Harness {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let changes = self.changes.clone();
let view = cx.entity();
div().size_full().p_4().child(
Select::new("level")
.options(LEVELS)
.selected(self.value)
.on_change(move |next, _window, cx| {
changes.borrow_mut().push(next);
view.update(cx, |harness, cx| {
harness.value = next;
cx.notify();
});
}),
)
}
}
fn level_window() -> (TestAppContext, VisualTestContext, Changes) {
let mut cx = TestAppContext::single();
cx.update(Theme::init);
let changes = Rc::new(RefCell::new(Vec::new()));
let harness_changes = changes.clone();
let window = cx.add_window(move |_, _| Harness {
value: None,
changes: harness_changes,
});
let mut visual = VisualTestContext::from_window(window.into(), &cx);
visual.update(|window, cx| {
window.draw(cx).clear(cx);
});
(cx, visual, changes)
}
fn click(visual: &mut VisualTestContext, position: gpui::Point<gpui::Pixels>) {
visual.simulate_mouse_down(position, MouseButton::Left, gpui::Modifiers::default());
visual.simulate_mouse_up(position, MouseButton::Left, gpui::Modifiers::default());
}
/// The trigger band is `16..46`; the panel hangs 4 px below it with a 4 px
/// inner padding, so the three rows ride `~58..90`, `~90..122`, `~122..154`.
/// Every option must answer a pointer press — a popup that clips its last
/// item never does.
#[test]
fn every_option_row_answers_the_pointer() {
let (_cx, mut visual, changes) = level_window();
let expected = [
(px(74.), Level::Low),
(px(106.), Level::Mid),
(px(138.), Level::High),
];
for (y, value) in expected {
click(&mut visual, point(px(100.), px(31.)));
visual.update(|window, cx| {
window.draw(cx).clear(cx);
});
click(&mut visual, point(px(100.), y));
visual.update(|window, cx| {
window.draw(cx).clear(cx);
});
assert_eq!(
changes.borrow().last(),
Some(&Some(value)),
"pressing {value:?}'s row must choose it"
);
}
}