1#![allow(missing_docs)]
2use std::sync::Arc;
3
4use gpui::{ClickEvent, CursorStyle};
5
6use crate::{prelude::*, Color, IconButton, IconButtonShape, IconName, IconSize};
7
8#[derive(IntoElement)]
9pub struct Disclosure {
10 id: ElementId,
11 is_open: bool,
12 selected: bool,
13 on_toggle: Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
14 cursor_style: CursorStyle,
15}
16
17impl Disclosure {
18 pub fn new(id: impl Into<ElementId>, is_open: bool) -> Self {
19 Self {
20 id: id.into(),
21 is_open,
22 selected: false,
23 on_toggle: None,
24 cursor_style: CursorStyle::PointingHand,
25 }
26 }
27
28 pub fn on_toggle(
29 mut self,
30 handler: impl Into<Option<Arc<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>>,
31 ) -> Self {
32 self.on_toggle = handler.into();
33 self
34 }
35}
36
37impl Toggleable for Disclosure {
38 fn toggle_state(mut self, selected: bool) -> Self {
39 self.selected = selected;
40 self
41 }
42}
43
44impl Clickable for Disclosure {
45 fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static) -> Self {
46 self.on_toggle = Some(Arc::new(handler));
47 self
48 }
49
50 fn cursor_style(mut self, cursor_style: gpui::CursorStyle) -> Self {
51 self.cursor_style = cursor_style;
52 self
53 }
54}
55
56impl RenderOnce for Disclosure {
57 fn render(self, _window: &mut Window, _cx: &mut App) -> impl IntoElement {
58 IconButton::new(
59 self.id,
60 match self.is_open {
61 true => IconName::ChevronDown,
62 false => IconName::ChevronRight,
63 },
64 )
65 .shape(IconButtonShape::Square)
66 .icon_color(Color::Muted)
67 .icon_size(IconSize::Small)
68 .toggle_state(self.selected)
69 .when_some(self.on_toggle, move |this, on_toggle| {
70 this.on_click(move |event, window, cx| on_toggle(event, window, cx))
71 })
72 }
73}