@@ -4,13 +4,15 @@ use crate::{prelude::*, Color, Icon, IconButton, IconSize};
#[derive(IntoElement)]
pub struct Disclosure {
+ id: ElementId,
is_open: bool,
on_toggle: Option<Box<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
}
impl Disclosure {
- pub fn new(is_open: bool) -> Self {
+ pub fn new(id: impl Into<ElementId>, is_open: bool) -> Self {
Self {
+ id: id.into(),
is_open,
on_toggle: None,
}
@@ -30,7 +32,7 @@ impl RenderOnce for Disclosure {
fn render(self, _cx: &mut WindowContext) -> Self::Rendered {
IconButton::new(
- "toggle",
+ self.id,
match self.is_open {
true => Icon::ChevronDown,
false => Icon::ChevronRight,
@@ -1,5 +1,6 @@
+use gpui::{AnyElement, ClickEvent, Div, Stateful};
+
use crate::{h_stack, prelude::*, Disclosure, Label};
-use gpui::{AnyElement, ClickEvent, Div};
#[derive(IntoElement)]
pub struct ListHeader {
@@ -75,48 +76,52 @@ impl Selectable for ListHeader {
}
impl RenderOnce for ListHeader {
- type Rendered = Div;
+ type Rendered = Stateful<Div>;
fn render(self, cx: &mut WindowContext) -> Self::Rendered {
- h_stack().w_full().relative().group("list_header").child(
- div()
- .h_7()
- .when(self.inset, |this| this.px_2())
- .when(self.selected, |this| {
- this.bg(cx.theme().colors().ghost_element_selected)
- })
- .flex()
- .flex_1()
- .items_center()
- .justify_between()
- .w_full()
- .gap_1()
- .child(
- h_stack()
- .gap_1()
- .children(
- self.toggle
- .map(|is_open| Disclosure::new(is_open).on_toggle(self.on_toggle)),
- )
- .child(
- div()
- .flex()
- .gap_1()
- .items_center()
- .children(self.start_slot)
- .child(Label::new(self.label.clone()).color(Color::Muted)),
- ),
- )
- .child(h_stack().children(self.end_slot))
- .when_some(self.end_hover_slot, |this, end_hover_slot| {
- this.child(
- div()
- .absolute()
- .right_0()
- .visible_on_hover("list_header")
- .child(end_hover_slot),
+ h_stack()
+ .id(self.label.clone())
+ .w_full()
+ .relative()
+ .group("list_header")
+ .child(
+ div()
+ .h_7()
+ .when(self.inset, |this| this.px_2())
+ .when(self.selected, |this| {
+ this.bg(cx.theme().colors().ghost_element_selected)
+ })
+ .flex()
+ .flex_1()
+ .items_center()
+ .justify_between()
+ .w_full()
+ .gap_1()
+ .child(
+ h_stack()
+ .gap_1()
+ .children(self.toggle.map(|is_open| {
+ Disclosure::new("toggle", is_open).on_toggle(self.on_toggle)
+ }))
+ .child(
+ div()
+ .flex()
+ .gap_1()
+ .items_center()
+ .children(self.start_slot)
+ .child(Label::new(self.label.clone()).color(Color::Muted)),
+ ),
)
- }),
- )
+ .child(h_stack().children(self.end_slot))
+ .when_some(self.end_hover_slot, |this, end_hover_slot| {
+ this.child(
+ div()
+ .absolute()
+ .right_0()
+ .visible_on_hover("list_header")
+ .child(end_hover_slot),
+ )
+ }),
+ )
}
}
@@ -193,7 +193,7 @@ impl RenderOnce for ListItem {
.absolute()
.left(rems(-1.))
.when(is_open, |this| this.visible_on_hover(""))
- .child(Disclosure::new(is_open).on_toggle(self.on_toggle))
+ .child(Disclosure::new("toggle", is_open).on_toggle(self.on_toggle))
}))
.child(
h_stack()
@@ -13,8 +13,8 @@ impl Render for DisclosureStory {
Story::container()
.child(Story::title_for::<Disclosure>())
.child(Story::label("Toggled"))
- .child(Disclosure::new(true))
+ .child(Disclosure::new("toggled", true))
.child(Story::label("Not Toggled"))
- .child(Disclosure::new(false))
+ .child(Disclosure::new("not_toggled", false))
}
}