1use crate::prelude::*;
2
3#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
4pub enum ToastOrigin {
5 #[default]
6 Bottom,
7 BottomRight,
8}
9
10#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
11pub enum ToastVariant {
12 #[default]
13 Toast,
14 Status,
15}
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(Element)]
25pub struct Toast<S: 'static + Send + Sync> {
26 origin: ToastOrigin,
27 children: HackyChildren<S>,
28 payload: HackyChildrenPayload,
29}
30
31impl<S: 'static + Send + Sync> Toast<S> {
32 pub fn new(
33 origin: ToastOrigin,
34 children: HackyChildren<S>,
35 payload: HackyChildrenPayload,
36 ) -> Self {
37 Self {
38 origin,
39 children,
40 payload,
41 }
42 }
43
44 fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
45 let color = ThemeColor::new(cx);
46
47 let mut div = div();
48
49 if self.origin == ToastOrigin::Bottom {
50 div = div.right_1_2();
51 } else {
52 div = div.right_4();
53 }
54
55 div.z_index(5)
56 .absolute()
57 .bottom_4()
58 .flex()
59 .py_2()
60 .px_1p5()
61 .min_w_40()
62 .rounded_md()
63 .fill(color.elevated_surface)
64 .max_w_64()
65 .children_any((self.children)(cx, self.payload.as_ref()))
66 }
67}
68
69#[cfg(feature = "stories")]
70pub use stories::*;
71
72#[cfg(feature = "stories")]
73mod stories {
74 use std::marker::PhantomData;
75
76 use crate::{Label, Story};
77
78 use super::*;
79
80 #[derive(Element)]
81 pub struct ToastStory<S: 'static + Send + Sync + Clone> {
82 state_type: PhantomData<S>,
83 }
84
85 impl<S: 'static + Send + Sync + Clone> ToastStory<S> {
86 pub fn new() -> Self {
87 Self {
88 state_type: PhantomData,
89 }
90 }
91
92 fn render(&mut self, cx: &mut ViewContext<S>) -> impl Element<State = S> {
93 Story::container(cx)
94 .child(Story::title_for::<_, Toast<S>>(cx))
95 .child(Story::label(cx, "Default"))
96 .child(Toast::new(
97 ToastOrigin::Bottom,
98 |_, _| vec![Label::new("label").into_any()],
99 Box::new(()),
100 ))
101 }
102 }
103}