disclosure.rs

  1use std::sync::Arc;
  2
  3use gpui::{ClickEvent, CursorStyle, SharedString};
  4
  5use crate::prelude::*;
  6
  7#[derive(IntoElement, RegisterComponent)]
  8pub struct Disclosure {
  9    id: ElementId,
 10    is_open: bool,
 11    selected: bool,
 12    disabled: bool,
 13    on_toggle_expanded: Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
 14    cursor_style: CursorStyle,
 15    opened_icon: IconName,
 16    closed_icon: IconName,
 17    visible_on_hover: Option<SharedString>,
 18}
 19
 20impl Disclosure {
 21    pub fn new(id: impl Into<ElementId>, is_open: bool) -> Self {
 22        Self {
 23            id: id.into(),
 24            is_open,
 25            selected: false,
 26            disabled: false,
 27            on_toggle_expanded: None,
 28            cursor_style: CursorStyle::PointingHand,
 29            opened_icon: IconName::ChevronDown,
 30            closed_icon: IconName::ChevronRight,
 31            visible_on_hover: None,
 32        }
 33    }
 34
 35    pub fn on_toggle_expanded(
 36        mut self,
 37        handler: impl Into<Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>>,
 38    ) -> Self {
 39        self.on_toggle_expanded = handler.into();
 40        self
 41    }
 42
 43    pub fn opened_icon(mut self, icon: IconName) -> Self {
 44        self.opened_icon = icon;
 45        self
 46    }
 47
 48    pub fn closed_icon(mut self, icon: IconName) -> Self {
 49        self.closed_icon = icon;
 50        self
 51    }
 52
 53    pub fn disabled(mut self, disabled: bool) -> Self {
 54        self.disabled = disabled;
 55        self
 56    }
 57}
 58
 59impl Toggleable for Disclosure {
 60    fn toggle_state(mut self, selected: bool) -> Self {
 61        self.selected = selected;
 62        self
 63    }
 64}
 65
 66impl Clickable for Disclosure {
 67    fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self {
 68        self.on_toggle_expanded = Some(Arc::new(handler));
 69        self
 70    }
 71
 72    fn cursor_style(mut self, cursor_style: gpui::CursorStyle) -> Self {
 73        self.cursor_style = cursor_style;
 74        self
 75    }
 76}
 77
 78impl VisibleOnHover for Disclosure {
 79    fn visible_on_hover(mut self, group_name: impl Into<SharedString>) -> Self {
 80        self.visible_on_hover = Some(group_name.into());
 81        self
 82    }
 83}
 84
 85impl RenderOnce for Disclosure {
 86    fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
 87        IconButton::new(
 88            self.id,
 89            match self.is_open {
 90                true => self.opened_icon,
 91                false => self.closed_icon,
 92            },
 93        )
 94        .icon_color(Color::Muted)
 95        .icon_size(IconSize::Small)
 96        .disabled(self.disabled)
 97        .toggle_state(self.selected)
 98        .when_some(self.visible_on_hover.clone(), |this, group_name| {
 99            this.visible_on_hover(group_name)
100        })
101        .when_some(self.on_toggle_expanded, move |this, on_toggle| {
102            this.on_click(move |event, window, cx| on_toggle(event, window, cx))
103        })
104    }
105}
106
107impl Component for Disclosure {
108    fn scope() -> ComponentScope {
109        ComponentScope::Input
110    }
111
112    fn description() -> Option<&'static str> {
113        Some(
114            "An interactive element used to show or hide content, typically used in expandable sections or tree-like structures.",
115        )
116    }
117
118    fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
119        Some(
120            v_flex()
121                .gap_6()
122                .children(vec![
123                    example_group_with_title(
124                        "Disclosure States",
125                        vec![
126                            single_example(
127                                "Closed",
128                                Disclosure::new("closed", false).into_any_element(),
129                            ),
130                            single_example(
131                                "Open",
132                                Disclosure::new("open", true).into_any_element(),
133                            ),
134                        ],
135                    ),
136                    example_group_with_title(
137                        "Interactive Example",
138                        vec![single_example(
139                            "Toggleable",
140                            v_flex()
141                                .gap_2()
142                                .child(Disclosure::new("interactive", false).into_any_element())
143                                .child(Label::new("Click to toggle"))
144                                .into_any_element(),
145                        )],
146                    ),
147                ])
148                .into_any_element(),
149        )
150    }
151}