From b3d6cc023ec5e8156450a2a6a3f3eca7db7a85cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Tue, 13 Oct 2026 22:22:00 -0400 Subject: [PATCH] Property grid: a group's title keys its fold, so a group put first takes no other group's fold Co-Authored-By: Claude Opus 5.5 (1M context) --- src/data_display/records.rs | 14 ++++++------ src/data_display/tests.rs | 44 +++++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/data_display/records.rs b/src/data_display/records.rs index fc48ee0..f0b1964 100644 --- a/src/data_display/records.rs +++ b/src/data_display/records.rs @@ -103,6 +103,7 @@ impl RenderOnce for DescriptionList { } /// A titled group of a `PropertyGrid`, open unless `folded`. +/// Its title keys its fold, so titles differ within a grid. pub struct PropertyGroup { title: SharedString, open: bool, @@ -157,10 +158,9 @@ impl RenderOnce for PropertyGrid { let folds: Vec<_> = self .groups .iter() - .enumerate() - .map(|(ix, group)| { + .map(|group| { use_seeded( - (self.id.clone(), format!("fold-{ix}")), + (self.id.clone(), format!("fold-{}", group.title)), group.open, window, cx, @@ -180,14 +180,14 @@ impl RenderOnce for PropertyGrid { |(ix, PropertyGroup { title, rows, .. })| { let shown = folds[ix].read(cx).value; let (toggle, key) = (folds[ix].clone(), title.clone()); - let chevron = Disclosure::new((id.clone(), format!("chevron-{ix}")), shown); + let chevron = Disclosure::new((id.clone(), format!("chevron-{title}")), shown); div() .when(ix > 0, |group| { group.border_t_1().border_color(colors.border) }) .child( div() - .id((id.clone(), format!("group-{ix}"))) + .id((id.clone(), format!("group-{title}"))) .flex() .items_center() .gap_1() @@ -208,10 +208,10 @@ impl RenderOnce for PropertyGrid { }) }) .child(chevron) - .child(title), + .child(title.clone()), ) .child( - Collapsible::new((id.clone(), format!("rows-{ix}")), shown).child( + Collapsible::new((id.clone(), format!("rows-{title}")), shown).child( div() .pb_1() .children(rows.into_iter().map(|(name, editor)| { diff --git a/src/data_display/tests.rs b/src/data_display/tests.rs index ba07428..39fb634 100644 --- a/src/data_display/tests.rs +++ b/src/data_display/tests.rs @@ -5,8 +5,8 @@ use std::{ }; use gpui::{ - AnyElement, Bounds, Context, IntoElement, Modifiers, ParentElement, Pixels, Render, Styled, - TestAppContext, VisualTestContext, Window, div, point, px, + AnyElement, Bounds, Context, InteractiveElement, IntoElement, Modifiers, ParentElement, Pixels, + Render, Styled, TestAppContext, VisualTestContext, Window, div, point, px, }; use super::{ @@ -75,6 +75,46 @@ fn a_property_group_folds_from_its_header_and_stays_folded(cx: &mut TestAppConte assert_eq!(height.get(), open, "a second press opens it"); } +/// A grid that may put a Table group first. +struct Reorder(bool); + +impl Render for Reorder { + fn render(&mut self, _: &mut Window, _: &mut Context) -> impl IntoElement { + let row = |name: &'static str| div().h(px(20.0)).debug_selector(move || name.into()); + let grid = PropertyGrid::new("grid"); + let grid = if self.0 { + grid.group(PropertyGroup::new("Table").row("Rows", row("table"))) + } else { + grid + }; + div().w(px(320.0)).child( + grid.group(PropertyGroup::new("Layout").row("Width", row("layout"))) + .group(PropertyGroup::new("Export").row("Scale", row("export"))), + ) + } +} + +#[gpui::test] +fn a_fold_stays_with_its_group_when_a_group_is_put_first(cx: &mut TestAppContext) { + cx.update(|cx| { + Theme::init(cx); + Theme::update(cx, |theme| theme.reduced_motion = true); + }); + let (view, cx) = cx.add_window_view(|_, _| Reorder(false)); + settle(cx); + cx.simulate_click(point(px(4.0), px(12.0)), Modifiers::none()); + settle(cx); + assert!(cx.debug_bounds("layout").is_none(), "Layout folds"); + view.update(cx, |view, cx| { + view.0 = true; + cx.notify(); + }); + settle(cx); + assert!(cx.debug_bounds("table").is_some(), "the new group opens"); + assert!(cx.debug_bounds("layout").is_none(), "Layout stays folded"); + assert!(cx.debug_bounds("export").is_some(), "Export stays open"); +} + /// A one-row description list, this wide, that reports where the list and its value sit. struct Facts(Pixels, fn() -> AnyElement, Rc; 2]>>);