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