yew_toastify_js/
lib.rs

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    /// Add a style property to the toast
88    /// Style properties match HTML DOM styles
89    ///
90    /// # Errors
91    ///
92    /// Returns an error if the style property is not a valid HTML DOM style
93    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}