Cargo.lock 🔗
@@ -14551,6 +14551,7 @@ dependencies = [
  "menu",
  "node_runtime",
  "paths",
+ "pretty_assertions",
  "project",
  "serde",
  "session",
  Ben Kunkle created
Closes #ISSUE
Release Notes:
- N/A *or* Added/Fixed/Improved ...
  
  
  
Cargo.lock                                   |   1 
crates/settings_ui/Cargo.toml                |   1 
crates/settings_ui/src/settings_ui.rs        | 328 ++++++++++-----------
crates/ui/src/components/disclosure.rs       |  12 
crates/ui/src/components/list/list_header.rs |   3 
crates/ui/src/components/list/list_item.rs   |   5 
crates/ui/src/components/tree_view_item.rs   |  14 
7 files changed, 183 insertions(+), 181 deletions(-)
@@ -14551,6 +14551,7 @@ dependencies = [
  "menu",
  "node_runtime",
  "paths",
+ "pretty_assertions",
  "project",
  "serde",
  "session",
  @@ -46,6 +46,7 @@ paths.workspace = true
 session.workspace = true
 settings.workspace = true
 zlog.workspace = true
+pretty_assertions.workspace = true
 
 [[example]]
 name = "ui"
  @@ -144,7 +144,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
     vec![
         SettingsPage {
             title: "General Page",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("General"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -303,7 +302,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Appearance & Behavior",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Theme"),
                 // todo(settings_ui): Figure out how we want to add these
@@ -663,7 +661,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Editor",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Indentation"),
                 // todo(settings_ui): Needs numeric stepper
@@ -1360,7 +1357,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Languages & Frameworks",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("General"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -1393,7 +1389,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Workbench & Window",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Workbench"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -1495,7 +1490,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Panels & Tools",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Project Panel"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -1700,7 +1694,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Version Control",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Git"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -1863,7 +1856,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "System & Network",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Network"),
                 // todo(settings_ui): Proxy needs a default
@@ -1903,7 +1895,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Diagnostics & Errors",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Display"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -2121,7 +2112,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Collaboration",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Calls"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -2201,7 +2191,6 @@ fn user_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "AI",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("General"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -2224,7 +2213,6 @@ fn project_settings_data() -> Vec<SettingsPage> {
     vec![
         SettingsPage {
             title: "Project",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Worktree Settings Content"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -2244,7 +2232,6 @@ fn project_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Appearance & Behavior",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Guides"),
                 SettingsPageItem::SettingItem(SettingItem {
@@ -2316,7 +2303,6 @@ fn project_settings_data() -> Vec<SettingsPage> {
         },
         SettingsPage {
             title: "Editing",
-            expanded: false,
             items: vec![
                 SettingsPageItem::SectionHeader("Indentation"),
                 // todo(settings_ui): Needs numeric stepper
@@ -2788,12 +2774,13 @@ struct SubPage {
 struct NavBarEntry {
     title: &'static str,
     is_root: bool,
+    expanded: bool,
     page_index: usize,
+    item_index: Option<usize>,
 }
 
 struct SettingsPage {
     title: &'static str,
-    expanded: bool,
     items: Vec<SettingsPageItem>,
 }
 
@@ -3058,66 +3045,80 @@ impl SettingsWindow {
         let toggle_page_index = self.page_index_from_navbar_index(ix);
         let selected_page_index = self.page_index_from_navbar_index(self.navbar_entry);
 
-        let expanded = &mut self.page_for_navbar_index(ix).expanded;
+        let expanded = &mut self.navbar_entries[ix].expanded;
         *expanded = !*expanded;
-        let expanded = *expanded;
         // if currently selected page is a child of the parent page we are folding,
         // set the current page to the parent page
-        if selected_page_index == toggle_page_index {
+        if !*expanded && selected_page_index == toggle_page_index {
             self.navbar_entry = ix;
-        } else if selected_page_index > toggle_page_index {
-            let sub_items_count = self.pages[toggle_page_index]
-                .items
-                .iter()
-                .filter(|item| matches!(item, SettingsPageItem::SectionHeader(_)))
-                .count();
-            if expanded {
-                self.navbar_entry += sub_items_count;
-            } else {
-                self.navbar_entry -= sub_items_count;
-            }
         }
-
-        self.build_navbar();
     }
 
     fn build_navbar(&mut self) {
         let mut navbar_entries = Vec::with_capacity(self.navbar_entries.len());
         for (page_index, page) in self.pages.iter().enumerate() {
-            if !self.search_matches[page_index]
-                .iter()
-                .any(|is_match| *is_match)
-                && !self.search_matches[page_index].is_empty()
-            {
-                continue;
-            }
             navbar_entries.push(NavBarEntry {
                 title: page.title,
                 is_root: true,
+                expanded: false,
                 page_index,
+                item_index: None,
             });
-            if !page.expanded {
-                continue;
-            }
 
             for (item_index, item) in page.items.iter().enumerate() {
                 let SettingsPageItem::SectionHeader(title) = item else {
                     continue;
                 };
-                if !self.search_matches[page_index][item_index] {
-                    continue;
-                }
-
                 navbar_entries.push(NavBarEntry {
                     title,
                     is_root: false,
+                    expanded: false,
                     page_index,
+                    item_index: Some(item_index),
                 });
             }
         }
         self.navbar_entries = navbar_entries;
     }
 
+    fn visible_navbar_entries(&self) -> impl Iterator<Item = (usize, &NavBarEntry)> {
+        let mut index = 0;
+        let entries = &self.navbar_entries;
+        let search_matches = &self.search_matches;
+        std::iter::from_fn(move || {
+            while index < entries.len() {
+                let entry = &entries[index];
+                let included_in_search = if let Some(item_index) = entry.item_index {
+                    search_matches[entry.page_index][item_index]
+                } else {
+                    search_matches[entry.page_index].iter().any(|b| *b)
+                        || search_matches[entry.page_index].is_empty()
+                };
+                if included_in_search {
+                    break;
+                }
+                index += 1;
+            }
+            if index >= self.navbar_entries.len() {
+                return None;
+            }
+            let entry = &entries[index];
+            let entry_index = index;
+
+            index += 1;
+            if entry.is_root && !entry.expanded {
+                while index < entries.len() {
+                    if entries[index].is_root {
+                        break;
+                    }
+                    index += 1;
+                }
+            }
+
+            return Some((entry_index, entry));
+        })
+    }
+
     fn update_matches(&mut self, cx: &mut Context<SettingsWindow>) {
         self.search_task.take();
         let query = self.search_bar.read(cx).text(cx);
@@ -3125,7 +3126,6 @@ impl SettingsWindow {
             for page in &mut self.search_matches {
                 page.fill(true);
             }
-            self.build_navbar();
             cx.notify();
             return;
         }
@@ -3169,7 +3169,7 @@ impl SettingsWindow {
                 candidates.as_slice(),
                 &query,
                 false,
-                false,
+                true,
                 candidates.len(),
                 &atomic_bool,
                 cx.background_executor().clone(),
@@ -3191,21 +3191,29 @@ impl SettingsWindow {
                     page[header_index] = true;
                     page[item_index] = true;
                 }
-                this.build_navbar();
-                this.navbar_entry = 0;
+                let first_navbar_entry_index = this
+                    .visible_navbar_entries()
+                    .next()
+                    .map(|e| e.0)
+                    .unwrap_or(0);
+                this.navbar_entry = first_navbar_entry_index;
                 cx.notify();
             })
             .ok();
         }));
     }
 
-    fn build_ui(&mut self, cx: &mut Context<SettingsWindow>) {
-        self.pages = self.current_file.pages();
+    fn build_search_matches(&mut self) {
         self.search_matches = self
             .pages
             .iter()
             .map(|page| vec![true; page.items.len()])
             .collect::<Vec<_>>();
+    }
+
+    fn build_ui(&mut self, cx: &mut Context<SettingsWindow>) {
+        self.pages = self.current_file.pages();
+        self.build_search_matches();
         self.build_navbar();
 
         if !self.search_bar.read(cx).is_empty(cx) {
@@ -3283,25 +3291,20 @@ impl SettingsWindow {
                     "settings-ui-nav-bar",
                     self.navbar_entries.len(),
                     cx.processor(|this, range: Range<usize>, _, cx| {
-                        range
-                            .into_iter()
-                            .map(|ix| {
-                                let entry = &this.navbar_entries[ix];
-
+                        this.visible_navbar_entries()
+                            .skip(range.start.saturating_sub(1))
+                            .take(range.len())
+                            .map(|(ix, entry)| {
                                 TreeViewItem::new(("settings-ui-navbar-entry", ix), entry.title)
                                     .root_item(entry.is_root)
                                     .toggle_state(this.is_navbar_entry_selected(ix))
                                     .when(entry.is_root, |item| {
-                                        item.toggle(
-                                            this.pages[this.page_index_from_navbar_index(ix)]
-                                                .expanded,
-                                        )
-                                        .on_toggle(
-                                            cx.listener(move |this, _, _, cx| {
+                                        item.expanded(entry.expanded).on_toggle(cx.listener(
+                                            move |this, _, _, cx| {
                                                 this.toggle_navbar_entry(ix);
                                                 cx.notify();
-                                            }),
-                                        )
+                                            },
+                                        ))
                                     })
                                     .on_click(cx.listener(move |this, _, _, cx| {
                                         this.navbar_entry = ix;
@@ -3423,11 +3426,6 @@ impl SettingsWindow {
         self.navbar_entries[index].page_index
     }
 
-    fn page_for_navbar_index(&mut self, index: usize) -> &mut SettingsPage {
-        let index = self.page_index_from_navbar_index(index);
-        &mut self.pages[index]
-    }
-
     fn is_navbar_entry_selected(&self, ix: usize) -> bool {
         ix == self.navbar_entry
     }
@@ -3626,10 +3624,6 @@ mod test {
     use super::*;
 
     impl SettingsWindow {
-        fn navbar(&self) -> &[NavBarEntry] {
-            self.navbar_entries.as_slice()
-        }
-
         fn navbar_entry(&self) -> usize {
             self.navbar_entry
         }
@@ -3642,6 +3636,7 @@ mod test {
         }
 
         fn build(mut self) -> Self {
+            self.build_search_matches();
             self.build_navbar();
             self
         }
@@ -3653,7 +3648,6 @@ mod test {
         ) -> Self {
             let page = SettingsPage {
                 title,
-                expanded: false,
                 items: Vec::default(),
             };
 
@@ -3671,13 +3665,25 @@ mod test {
 
         fn assert_search_results(&self, other: &Self) {
             // page index could be different because of filtered out pages
-            assert!(
-                self.navbar_entries
-                    .iter()
-                    .zip(other.navbar_entries.iter())
-                    .all(|(entry, other)| {
-                        entry.is_root == other.is_root && entry.title == other.title
+            #[derive(Debug, PartialEq)]
+            struct EntryMinimal {
+                is_root: bool,
+                title: &'static str,
+            }
+            pretty_assertions::assert_eq!(
+                other
+                    .visible_navbar_entries()
+                    .map(|(_, entry)| EntryMinimal {
+                        is_root: entry.is_root,
+                        title: entry.title,
+                    })
+                    .collect::<Vec<_>>(),
+                self.visible_navbar_entries()
+                    .map(|(_, entry)| EntryMinimal {
+                        is_root: entry.is_root,
+                        title: entry.title,
                     })
+                    .collect::<Vec<_>>(),
             );
             assert_eq!(
                 self.current_page().items.iter().collect::<Vec<_>>(),
@@ -3719,55 +3725,50 @@ mod test {
 
     fn parse(input: &'static str, window: &mut Window, cx: &mut App) -> SettingsWindow {
         let mut pages: Vec<SettingsPage> = Vec::new();
-        let mut current_page = None;
+        let mut expanded_pages = Vec::new();
         let mut selected_idx = None;
-        let mut ix = 0;
-        let mut in_closed_subentry = false;
+        let mut index = 0;
+        let mut in_expanded_section = false;
 
         for mut line in input
             .lines()
             .map(|line| line.trim())
             .filter(|line| !line.is_empty())
         {
-            let mut is_selected = false;
-            if line.ends_with("*") {
-                assert!(
-                    selected_idx.is_none(),
-                    "Can only have one selected navbar entry at a time"
-                );
-                selected_idx = Some(ix);
-                line = &line[..line.len() - 1];
-                is_selected = true;
+            if let Some(pre) = line.strip_suffix('*') {
+                assert!(selected_idx.is_none(), "Only one selected entry allowed");
+                selected_idx = Some(index);
+                line = pre;
             }
-
-            if line.starts_with("v") || line.starts_with(">") {
-                if let Some(current_page) = current_page.take() {
-                    pages.push(current_page);
-                }
-
-                let expanded = line.starts_with("v");
-                in_closed_subentry = !expanded;
-                ix += 1;
-
-                current_page = Some(SettingsPage {
-                    title: line.split_once(" ").unwrap().1,
-                    expanded,
-                    items: Vec::default(),
+            let (kind, title) = line.split_once(" ").unwrap();
+            assert_eq!(kind.len(), 1);
+            let kind = kind.chars().next().unwrap();
+            if kind == 'v' {
+                let page_idx = pages.len();
+                expanded_pages.push(page_idx);
+                pages.push(SettingsPage {
+                    title,
+                    items: vec![],
+                });
+                index += 1;
+                in_expanded_section = true;
+            } else if kind == '>' {
+                pages.push(SettingsPage {
+                    title,
+                    items: vec![],
                 });
-            } else if line.starts_with("-") {
-                if !in_closed_subentry {
-                    ix += 1;
-                } else if is_selected && in_closed_subentry {
-                    panic!("Can't select sub entry if it's parent is closed");
+                index += 1;
+                in_expanded_section = false;
+            } else if kind == '-' {
+                pages
+                    .last_mut()
+                    .unwrap()
+                    .items
+                    .push(SettingsPageItem::SectionHeader(title));
+                if selected_idx == Some(index) && !in_expanded_section {
+                    panic!("Items in unexpanded sections cannot be selected");
                 }
-
-                let Some(current_page) = current_page.as_mut() else {
-                    panic!("Sub entries must be within a page");
-                };
-
-                current_page.items.push(SettingsPageItem::SectionHeader(
-                    line.split_once(" ").unwrap().1,
-                ));
+                index += 1;
             } else {
                 panic!(
                     "Entries must start with one of 'v', '>', or '-'\n line: {}",
@@ -3776,15 +3777,6 @@ mod test {
             }
         }
 
-        if let Some(current_page) = current_page.take() {
-            pages.push(current_page);
-        }
-
-        let search_matches = pages
-            .iter()
-            .map(|page| vec![true; page.items.len()])
-            .collect::<Vec<_>>();
-
         let mut settings_window = SettingsWindow {
             files: Vec::default(),
             current_file: crate::SettingsUiFile::User,
@@ -3793,43 +3785,70 @@ mod test {
             navbar_entry: selected_idx.expect("Must have a selected navbar entry"),
             navbar_entries: Vec::default(),
             list_handle: UniformListScrollHandle::default(),
-            search_matches,
+            search_matches: vec![],
             search_task: None,
             sub_page_stack: vec![],
         };
 
+        settings_window.build_search_matches();
         settings_window.build_navbar();
+        for expanded_page_index in expanded_pages {
+            for entry in &mut settings_window.navbar_entries {
+                if entry.page_index == expanded_page_index && entry.is_root {
+                    entry.expanded = true;
+                }
+            }
+        }
         settings_window
     }
 
     #[track_caller]
     fn check_navbar_toggle(
         before: &'static str,
-        toggle_idx: usize,
+        toggle_page: &'static str,
         after: &'static str,
         window: &mut Window,
         cx: &mut App,
     ) {
         let mut settings_window = parse(before, window, cx);
+        let toggle_page_idx = settings_window
+            .pages
+            .iter()
+            .position(|page| page.title == toggle_page)
+            .expect("page not found");
+        let toggle_idx = settings_window
+            .navbar_entries
+            .iter()
+            .position(|entry| entry.page_index == toggle_page_idx)
+            .expect("page not found");
         settings_window.toggle_navbar_entry(toggle_idx);
 
         let expected_settings_window = parse(after, window, cx);
 
-        assert_eq!(settings_window.navbar(), expected_settings_window.navbar());
-        assert_eq!(
-            settings_window.navbar_entry(),
-            expected_settings_window.navbar_entry()
+        pretty_assertions::assert_eq!(
+            settings_window
+                .visible_navbar_entries()
+                .map(|(_, entry)| entry)
+                .collect::<Vec<_>>(),
+            expected_settings_window
+                .visible_navbar_entries()
+                .map(|(_, entry)| entry)
+                .collect::<Vec<_>>(),
+        );
+        pretty_assertions::assert_eq!(
+            settings_window.navbar_entries[settings_window.navbar_entry()],
+            expected_settings_window.navbar_entries[expected_settings_window.navbar_entry()],
         );
     }
 
     macro_rules! check_navbar_toggle {
-        ($name:ident, before: $before:expr, toggle_idx: $toggle_idx:expr, after: $after:expr) => {
+        ($name:ident, before: $before:expr, toggle_page: $toggle_page:expr, after: $after:expr) => {
             #[gpui::test]
             fn $name(cx: &mut gpui::TestAppContext) {
                 let window = cx.add_empty_window();
                 window.update(|window, cx| {
                     register_settings(cx);
-                    check_navbar_toggle($before, $toggle_idx, $after, window, cx);
+                    check_navbar_toggle($before, $toggle_page, $after, window, cx);
                 });
             }
         };
@@ -3844,7 +3863,7 @@ mod test {
         v Project
         - Project Settings
         ",
-        toggle_idx: 0,
+        toggle_page: "General",
         after: r"
         > General*
         v Project
@@ -3861,7 +3880,7 @@ mod test {
         v Project
         - Project Settings
         ",
-        toggle_idx: 0,
+        toggle_page: "General",
         after: r"
         v General*
         - General
@@ -3880,7 +3899,7 @@ mod test {
         v Project
         - Project Settings*
         ",
-        toggle_idx: 1,
+        toggle_page: "Project",
         after: r"
         > General
         > Project*
@@ -3899,7 +3918,7 @@ mod test {
         - General
         > Appearance & Behavior
         ",
-        toggle_idx: 3,
+        toggle_page: "Project",
         after: r"
         v General Page
         - General
@@ -3923,7 +3942,7 @@ mod test {
         - General*
         > Appearance & Behavior
         ",
-        toggle_idx: 0,
+        toggle_page: "General Page",
         after: r"
         > General Page
         v Project
@@ -3946,7 +3965,7 @@ mod test {
         - General*
         > Appearance & Behavior
         ",
-        toggle_idx: 0,
+        toggle_page: "General Page",
         after: r"
         v General Page
         - General
@@ -3959,31 +3978,6 @@ mod test {
         "
     );
 
-    check_navbar_toggle!(
-        navbar_toggle_sub_entry_does_nothing,
-        before: r"
-        > General Page
-        - General
-        - Privacy
-        v Project
-        - Worktree Settings Content
-        v AI
-        - General*
-        > Appearance & Behavior
-        ",
-        toggle_idx: 4,
-        after: r"
-        > General Page
-        - General
-        - Privacy
-        v Project
-        - Worktree Settings Content
-        v AI
-        - General*
-        > Appearance & Behavior
-        "
-    );
-
     #[gpui::test]
     fn test_basic_search(cx: &mut gpui::TestAppContext) {
         let cx = cx.add_empty_window();
  @@ -10,7 +10,7 @@ pub struct Disclosure {
     is_open: bool,
     selected: bool,
     disabled: bool,
-    on_toggle: Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
+    on_toggle_expanded: Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
     cursor_style: CursorStyle,
     opened_icon: IconName,
     closed_icon: IconName,
@@ -24,7 +24,7 @@ impl Disclosure {
             is_open,
             selected: false,
             disabled: false,
-            on_toggle: None,
+            on_toggle_expanded: None,
             cursor_style: CursorStyle::PointingHand,
             opened_icon: IconName::ChevronDown,
             closed_icon: IconName::ChevronRight,
@@ -32,11 +32,11 @@ impl Disclosure {
         }
     }
 
-    pub fn on_toggle(
+    pub fn on_toggle_expanded(
         mut self,
         handler: impl Into<Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>>,
     ) -> Self {
-        self.on_toggle = handler.into();
+        self.on_toggle_expanded = handler.into();
         self
     }
 
@@ -65,7 +65,7 @@ impl Toggleable for Disclosure {
 
 impl Clickable for Disclosure {
     fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self {
-        self.on_toggle = Some(Arc::new(handler));
+        self.on_toggle_expanded = Some(Arc::new(handler));
         self
     }
 
@@ -99,7 +99,7 @@ impl RenderOnce for Disclosure {
         .when_some(self.visible_on_hover.clone(), |this, group_name| {
             this.visible_on_hover(group_name)
         })
-        .when_some(self.on_toggle, move |this, on_toggle| {
+        .when_some(self.on_toggle_expanded, move |this, on_toggle| {
             this.on_click(move |event, window, cx| on_toggle(event, window, cx))
         })
     }
  @@ -107,7 +107,8 @@ impl RenderOnce for ListHeader {
                         h_flex()
                             .gap(DynamicSpacing::Base04.rems(cx))
                             .children(self.toggle.map(|is_open| {
-                                Disclosure::new("toggle", is_open).on_toggle(self.on_toggle.clone())
+                                Disclosure::new("toggle", is_open)
+                                    .on_toggle_expanded(self.on_toggle.clone())
                             }))
                             .child(
                                 div()
  @@ -308,7 +308,10 @@ impl RenderOnce for ListItem {
                             .when(is_open && !self.always_show_disclosure_icon, |this| {
                                 this.visible_on_hover("")
                             })
-                            .child(Disclosure::new("toggle", is_open).on_toggle(self.on_toggle))
+                            .child(
+                                Disclosure::new("toggle", is_open)
+                                    .on_toggle_expanded(self.on_toggle),
+                            )
                     }))
                     .child(
                         h_flex()
  @@ -9,7 +9,7 @@ pub struct TreeViewItem {
     id: ElementId,
     group_name: Option<SharedString>,
     label: SharedString,
-    toggle: bool,
+    expanded: bool,
     selected: bool,
     disabled: bool,
     focused: bool,
@@ -28,7 +28,7 @@ impl TreeViewItem {
             id: id.into(),
             group_name: None,
             label: label.into(),
-            toggle: false,
+            expanded: false,
             selected: false,
             disabled: false,
             focused: false,
@@ -73,8 +73,8 @@ impl TreeViewItem {
         self
     }
 
-    pub fn toggle(mut self, toggle: bool) -> Self {
-        self.toggle = toggle;
+    pub fn expanded(mut self, toggle: bool) -> Self {
+        self.expanded = toggle;
         self
     }
 
@@ -161,10 +161,12 @@ impl RenderOnce for TreeViewItem {
                                 })
                                 .hover(|s| s.bg(cx.theme().colors().element_hover))
                                 .child(
-                                    Disclosure::new("toggle", self.toggle)
+                                    Disclosure::new("toggle", self.expanded)
                                         .when_some(
                                             self.on_toggle.clone(),
-                                            |disclosure, on_toggle| disclosure.on_toggle(on_toggle),
+                                            |disclosure, on_toggle| {
+                                                disclosure.on_toggle_expanded(on_toggle)
+                                            },
                                         )
                                         .opened_icon(IconName::ChevronDown)
                                         .closed_icon(IconName::ChevronRight),