Tables: focused headers scroll into view; long tables scroll sideways

A sortable header is a tracked Tab stop; once focused it sets its
table's sideways offset whole from its painted bounds and asks one
frame. The virtualized branch scrolls sideways too, and its list
keeps a plain wheel to its rows. layout::on_axis keeps a scroll box's
wheel to its axes; tables, code blocks, the thumbnail strip and the
gallery's page use it. Footer figures move to tables/foot.rs; the
profiler's ruler takes theme.chart().label. HumanInputRequest's
answered state gets a test.
This commit is contained in:
ZacharyZhang-NY committed 2026-09-26 12:00:27 -04:00
1 parent a29cc8bc45
commit 1f1166fef0
15 files changed
+405 -254

No files matched your search

+2 -2
View File
@@ -10,6 +10,7 @@ use crate::{
buttons::{ButtonVariant, IconButton},
documents::source,
forms::{Pick, Run, reveal, revealer},
layout::on_axis,
motion::{self, Spinner},
primitives::{FocusRing, Icon, IconName, Image, tab_stop},
theme::{ActiveTheme, AvatarSize, ControlSize, IconSize, Radius, TextSize},
@@ -168,8 +169,7 @@ impl RenderOnce for BrowserPreview {
let thumb = theme.avatar_size(AvatarSize::Lg);
let shown = self.shown;
let strip = (self.frames.len() > 1).then(|| {
div()
.id((self.id.clone(), "strip"))
on_axis(div().id((self.id.clone(), "strip")))
.track_scroll(&scroll)
.overflow_x_scroll()
.flex()
+22 -13
View File
@@ -11,7 +11,7 @@ use crate::{
theme::Theme,
};
/// A question with two answers to pick, and the answers given.
/// A question with two answers to pick, and the answers given; once answered, it shows the first.
struct Asked {
field: Entity<TextInput>,
answers: Vec<String>,
@@ -20,17 +20,23 @@ struct Asked {
impl Render for Asked {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let view = cx.entity();
div().w(px(420.0)).child(
HumanInputRequest::new(
"asked",
"Keep the accents?",
&self.field,
move |answer, _, cx| {
view.update(cx, |asked, _| asked.answers.push(answer.to_string()))
},
)
.choices(["Keep them", "Lift further"]),
let request = HumanInputRequest::new(
"asked",
"Keep the accents?",
&self.field,
move |answer, _, cx| {
view.update(cx, |asked, cx| {
asked.answers.push(answer.to_string());
cx.notify();
})
},
)
.choices(["Keep them", "Lift further"]);
let request = match self.answers.first() {
Some(answer) => request.answered(answer.clone()),
None => request,
};
div().w(px(420.0)).child(request)
}
}
@@ -50,14 +56,17 @@ fn asked(cx: &mut TestAppContext) -> (Entity<Asked>, &mut VisualTestContext) {
}
#[gpui::test]
fn a_pick_answers_the_question(cx: &mut TestAppContext) {
fn a_pick_answers_the_question_and_the_answer_stands_alone(cx: &mut TestAppContext) {
let (view, cx) = asked(cx);
cx.update(|window, _| window.focus_next());
cx.update(|window, _| window.focus_next());
press("enter", cx);
cx.update(|window, _| window.focus_next());
press("enter", cx);
assert_eq!(
view.read_with(cx, |asked, _| asked.answers.clone()),
["Lift further"]
["Lift further"],
"once answered, no choice is left to press"
);
}