Files
Ely-GPUI-Components/src/lists/tests/release.rs
T
ZacharyZhang-NYandClaude Opus 5.5 e26b2d1407 Onboarding · Help: articles in a list the keyboard walks, a long address cut
HelpPanel lists its articles in lists::SelectableList: the list is one
stop whose cursor scrolls into view, and Enter or a double press opens
an article, focus going to All articles as before. SelectableList now
activates on Enter's release, armed by its own press, as the palette
and menus pick: an activation that moves focus left the release to
press what took it, here the way back. ContactSupport cuts a long
address in the middle and puts a Copy beside it. The lists tests move
into a folder, the release tests on their own.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 15:28:49 -04:00

95 lines
3.0 KiB
Rust

use gpui::{
AppContext, Context, Entity, FocusHandle, InteractiveElement, IntoElement, ParentElement,
Render, TestAppContext, Window, div,
};
use super::{enter, settle, setup};
use crate::{
buttons::Button,
forms::{Enter, Input, TextInput},
lists::{ListItem, SelectableList},
};
/// A list whose open hands focus to a button beside it, and what each heard.
struct Handoff {
button: FocusHandle,
heard: Vec<&'static str>,
}
impl Render for Handoff {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let (to, opened, clicked) = (self.button.clone(), cx.entity(), cx.entity());
div()
.child(
SelectableList::new("handoff")
.row("a", ListItem::new("handoff-a", "A"))
.on_activate(move |_, window, cx| {
window.focus(&to);
opened.update(cx, |view, _| view.heard.push("open"));
}),
)
.child(
Button::new("after", "After")
.focus_handle(&self.button)
.on_click(move |_, _, cx| {
clicked.update(cx, |view, _| view.heard.push("click"))
}),
)
}
}
/// Enter opens on its release, so an open that moves focus to a button leaves the button unpressed.
#[gpui::test]
fn an_open_that_moves_focus_leaves_the_release_alone(cx: &mut TestAppContext) {
setup(cx);
let (view, cx) = cx.add_window_view(|_, cx| Handoff {
button: cx.focus_handle().tab_stop(true),
heard: Vec::new(),
});
settle(cx);
cx.update(|window, _| window.focus_next());
settle(cx);
enter(cx);
settle(cx);
assert_eq!(view.read_with(cx, |view, _| view.heard.clone()), ["open"]);
}
/// A field whose Enter moves focus on to a list, and what the list opened.
struct Relay {
field: Entity<TextInput>,
heard: Vec<&'static str>,
}
impl Render for Relay {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let opened = cx.entity();
div()
.capture_action(|_: &Enter, window, _| window.focus_next())
.child(Input::new(&self.field))
.child(
SelectableList::new("relay")
.row("a", ListItem::new("relay-a", "A"))
.on_activate(move |_, _, cx| {
opened.update(cx, |view, _| view.heard.push("open"))
}),
)
}
}
/// A release whose press fell elsewhere opens nothing.
#[gpui::test]
fn a_release_that_began_elsewhere_opens_nothing(cx: &mut TestAppContext) {
setup(cx);
cx.update(crate::forms::bind_keys);
let (view, cx) = cx.add_window_view(|window, cx| Relay {
field: cx.new(|cx| TextInput::new(window, cx)),
heard: Vec::new(),
});
settle(cx);
cx.update(|window, _| window.focus_next());
settle(cx);
enter(cx);
settle(cx);
assert!(view.read_with(cx, |view, _| view.heard.is_empty()));
}