toast.rs

  1use gpui3::AnyElement;
  2use smallvec::SmallVec;
  3
  4use crate::prelude::*;
  5
  6#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
  7pub enum ToastOrigin {
  8    #[default]
  9    Bottom,
 10    BottomRight,
 11}
 12
 13/// Don't use toast directly:
 14///
 15/// - For messages with a required action, use a `NotificationToast`.
 16/// - For messages that convey information, use a `StatusToast`.
 17///
 18/// A toast is a small, temporary window that appears to show a message to the user
 19/// or indicate a required action.
 20///
 21/// Toasts should not persist on the screen for more than a few seconds unless
 22/// they are actively showing the a process in progress.
 23///
 24/// Only one toast may be visible at a time.
 25#[derive(Element)]
 26pub struct Toast<S: 'static + Send + Sync> {
 27    origin: ToastOrigin,
 28    children: SmallVec<[AnyElement<S>; 2]>,
 29}
 30
 31impl<S: 'static + Send + Sync> Toast<S> {
 32    pub fn new(origin: ToastOrigin) -> Self {
 33        Self {
 34            origin,
 35            children: SmallVec::new(),
 36        }
 37    }
 38
 39    fn render(&mut self, _view: &mut S, cx: &mut ViewContext<S>) -> impl Element<ViewState = S> {
 40        let color = ThemeColor::new(cx);
 41
 42        let mut div = div();
 43
 44        if self.origin == ToastOrigin::Bottom {
 45            div = div.right_1_2();
 46        } else {
 47            div = div.right_2();
 48        }
 49
 50        div.z_index(5)
 51            .absolute()
 52            .bottom_9()
 53            .flex()
 54            .py_1()
 55            .px_1p5()
 56            .rounded_lg()
 57            .shadow_md()
 58            .overflow_hidden()
 59            .fill(color.elevated_surface)
 60            .children(self.children.drain(..))
 61    }
 62}
 63
 64impl<S: 'static + Send + Sync> ParentElement for Toast<S> {
 65    type State = S;
 66
 67    fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
 68        &mut self.children
 69    }
 70}
 71
 72#[cfg(feature = "stories")]
 73pub use stories::*;
 74
 75#[cfg(feature = "stories")]
 76mod stories {
 77    use std::marker::PhantomData;
 78
 79    use crate::{Label, Story};
 80
 81    use super::*;
 82
 83    #[derive(Element)]
 84    pub struct ToastStory<S: 'static + Send + Sync + Clone> {
 85        state_type: PhantomData<S>,
 86    }
 87
 88    impl<S: 'static + Send + Sync + Clone> ToastStory<S> {
 89        pub fn new() -> Self {
 90            Self {
 91                state_type: PhantomData,
 92            }
 93        }
 94
 95        fn render(
 96            &mut self,
 97            _view: &mut S,
 98            cx: &mut ViewContext<S>,
 99        ) -> impl Element<ViewState = S> {
100            Story::container(cx)
101                .child(Story::title_for::<_, Toast<S>>(cx))
102                .child(Story::label(cx, "Default"))
103                .child(Toast::new(ToastOrigin::Bottom).child(Label::new("label")))
104        }
105    }
106}