Skip to main content

vizia_core/views/
chip.rs

1use crate::{icons::ICON_X, prelude::*};
2use std::sync::Arc;
3
4/// A visual indicator such as a tag.
5pub struct Chip {
6    on_close: Option<Arc<dyn Fn(&mut EventContext) + Send + Sync>>,
7    has_close: Signal<bool>,
8}
9
10impl Chip {
11    /// Creates a new [Chip] view with the provided text.
12    ///
13    /// # Example
14    /// ```
15    /// # use vizia_core::prelude::*;
16    /// #
17    /// # let cx = &mut Context::default();
18    /// #
19    /// Chip::new(cx, "Chip");
20    /// ```
21    pub fn new<T>(cx: &mut Context, text: impl Res<T> + Clone + 'static) -> Handle<Self>
22    where
23        T: ToStringLocalized + 'static,
24    {
25        let has_close = Signal::new(false);
26        Self { on_close: None, has_close }
27            .build(cx, move |cx| {
28                Label::new(cx, text).height(Stretch(1.0)).alignment(Alignment::Left);
29                Binding::new(cx, has_close, move |cx| {
30                    if has_close.get() {
31                        let on_close = cx.data::<Chip>().on_close.clone().unwrap();
32                        Button::new(cx, |cx| Svg::new(cx, ICON_X))
33                            .class("close-icon")
34                            .height(Pixels(16.0))
35                            .width(Pixels(16.0))
36                            .alignment(Alignment::Center)
37                            .on_press(move |cx| (on_close)(cx));
38                    }
39                });
40            })
41            .toggle_class("close", has_close)
42            .layout_type(LayoutType::Row)
43    }
44}
45
46impl View for Chip {
47    fn element(&self) -> Option<&'static str> {
48        Some("chip")
49    }
50}
51
52/// Used in conjunction with the `variant` modifier for selecting the style variant of a chip.
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum ChipVariant {
55    /// A filled chip.
56    Filled,
57    /// A chip with no fill and just a border.
58    Outline,
59}
60
61impl_res_simple!(ChipVariant);
62
63impl Handle<'_, Chip> {
64    /// Set the callback triggered when the close button of the chip is pressed.
65    /// The chip close button is not displayed by default. Setting this callback causes the close button to be displayed.
66    pub fn on_close(self, callback: impl 'static + Fn(&mut EventContext) + Send + Sync) -> Self {
67        self.modify(|chip: &mut Chip| {
68            chip.on_close = Some(Arc::new(callback));
69            chip.has_close.set(true);
70        })
71    }
72
73    /// Selects the style variant to be used by the chip. Accepts a value or signal of type [ChipVariant].
74    ///
75    /// # Example
76    /// ```
77    /// # use vizia_core::prelude::*;
78    /// #
79    /// #
80    /// # let cx = &mut Context::default();
81    /// #
82    /// Chip::new(cx, "Chip")
83    ///     .variant(ChipVariant::Filled);
84    /// ```
85    pub fn variant<U: Into<ChipVariant> + Clone + 'static>(
86        self,
87        variant: impl Res<U> + 'static,
88    ) -> Self {
89        let variant = variant.to_signal(self.cx);
90        self.bind(variant, move |handle| {
91            let variant = variant.get();
92            let variant = variant.into();
93
94            match variant {
95                ChipVariant::Filled => {
96                    handle.toggle_class("outline", false);
97                }
98
99                ChipVariant::Outline => {
100                    handle.toggle_class("outline", true);
101                }
102            }
103        })
104    }
105}