vizia_core/views/
collapsible.rs

1use crate::{icons::ICON_CHEVRON_DOWN, prelude::*};
2
3/// Events that can be triggered by the collapsible view.
4pub enum CollapsibleEvent {
5    ToggleOpen,
6}
7
8/// A collapsible view that can be opened or closed to hide content.
9///
10/// # Example
11/// ```no_run
12/// Collapsible::new(
13///     cx,
14///     |cx| {
15///         Label::new(cx, "Click me to collapse the content").hoverable(false);
16///     },
17///     |cx| {
18///         Label::new(cx, "Line 1\nLine 2\nLine 3\nLine 4\nLine 5").hoverable(false);
19///     },
20/// )
21/// .width(Pixels(300.0));
22/// ```
23#[derive(Lens)]
24pub struct Collapsible {
25    is_open: bool,
26}
27
28impl Collapsible {
29    /// Create a new collapsible view with a header and content.
30    pub fn new(
31        cx: &mut Context,
32        header: impl Fn(&mut Context),
33        content: impl Fn(&mut Context),
34    ) -> Handle<Self> {
35        Self { is_open: false }
36            .build(cx, |cx| {
37                // Header
38                HStack::new(cx, |cx| {
39                    header(cx);
40                    Svg::new(cx, ICON_CHEVRON_DOWN)
41                        .class("expand-icon")
42                        .on_press(|cx| cx.emit(CollapsibleEvent::ToggleOpen));
43                })
44                .class("header")
45                .on_press(|cx| cx.emit(CollapsibleEvent::ToggleOpen));
46
47                // Content
48                VStack::new(cx, |cx| {
49                    content(cx);
50                })
51                .class("content");
52            })
53            .toggle_class("open", Collapsible::is_open)
54    }
55}
56
57impl View for Collapsible {
58    fn element(&self) -> Option<&'static str> {
59        Some("collapsible")
60    }
61
62    fn event(&mut self, _cx: &mut EventContext, event: &mut Event) {
63        event.map(|collapsible_event, _| match collapsible_event {
64            CollapsibleEvent::ToggleOpen => {
65                self.is_open = !self.is_open;
66            }
67        });
68    }
69}
70
71impl Handle<'_, Collapsible> {
72    /// Set the open state of the collapsible view.
73    pub fn open(self, open: impl Res<bool>) -> Self {
74        self.bind(open, |handle, open| {
75            let open = open.get(&handle);
76            handle.modify(|collapsible| collapsible.is_open = open);
77        })
78    }
79}