1#![warn(
2 clippy::all,
3 clippy::missing_errors_doc,
4 clippy::style,
5 clippy::unseparated_literal_suffix,
6 clippy::pedantic,
7 clippy::nursery
8)]
9
10use serde::Serialize;
11use wasm_bindgen::prelude::*;
12
13#[derive(Debug, Clone, Serialize, Copy, Default)]
14#[serde(rename_all = "lowercase")]
15pub enum Gravity {
16 #[default]
17 Top,
18 Bottom,
19}
20impl AsRef<str> for Gravity {
21 fn as_ref(&self) -> &str {
22 match self {
23 Self::Top => "top",
24 Self::Bottom => "bottom",
25 }
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Copy, Default)]
30#[serde(rename_all = "lowercase")]
31pub enum Position {
32 Left,
33 #[default]
34 Right,
35 Center,
36}
37impl AsRef<str> for Position {
38 fn as_ref(&self) -> &str {
39 match self {
40 Self::Left => "left",
41 Self::Right => "right",
42 Self::Center => "center",
43 }
44 }
45}
46
47#[derive(Debug, Clone, Serialize)]
48pub struct ToastifyOptions {
49 pub text: String,
50 pub duration: u32,
51 pub destination: Option<String>,
52 pub close: bool,
53 pub gravity: Gravity,
54 pub position: Position,
55 #[serde(rename = "newWindow")]
56 pub new_window: bool,
57 #[serde(rename = "stopOnFocus")]
58 pub stop_on_focus: bool,
59 #[serde(rename = "className")]
60 #[serde(skip_serializing_if = "Option::is_none")]
61 pub class_name: Option<String>,
62 #[serde(with = "serde_wasm_bindgen::preserve")]
63 pub style: js_sys::Object,
64 #[serde(with = "serde_wasm_bindgen::preserve")]
65 #[serde(rename = "onClick")]
66 pub on_click: JsValue,
67}
68impl Default for ToastifyOptions {
69 fn default() -> Self {
70 Self {
71 text: String::new(),
72 duration: 3000,
73 destination: None,
74 close: true,
75 gravity: Gravity::Top,
76 position: Position::Right,
77 new_window: false,
78 stop_on_focus: true,
79 class_name: None,
80 style: js_sys::Object::new(),
81 on_click: JsValue::NULL,
82 }
83 }
84}
85
86impl ToastifyOptions {
87 pub fn add_style(self, style_property: &str, value: &str) -> Result<Self, JsValue> {
94 js_sys::Reflect::set(
95 &self.style,
96 &JsValue::from_str(style_property),
97 &JsValue::from_str(value),
98 )?;
99 Ok(self)
100 }
101 #[must_use]
102 pub fn add_on_click<T>(self, callback: T) -> Self
103 where
104 T: Fn(),
105 {
106 let callback = Closure::wrap(Box::new(callback) as Box<dyn Fn()>);
107 let mut this = self;
108 this.on_click = callback.into_js_value();
109 this
110 }
111 pub fn show(self) {
112 let options: JsValue = self.into();
113 toasts(&options).show_toast();
114 }
115}
116
117impl From<ToastifyOptions> for JsValue {
118 fn from(val: ToastifyOptions) -> Self {
119 serde_wasm_bindgen::to_value(&val).expect("Failed to serialize Toast")
120 }
121}
122
123#[wasm_bindgen]
124extern "C" {
125 #[derive(Debug, Clone)]
126 pub type Toastify;
127 #[wasm_bindgen(js_namespace = window, js_name = Toastify)]
128 pub fn toasts(options: &JsValue) -> Toastify;
129 #[wasm_bindgen(method, js_name = showToast)]
130 pub fn show_toast(this: &Toastify);
131}