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