yew-toastify-js 0.1.0

A WebAssembly wrapper for the toastify.js library
Documentation
#![warn(
    clippy::all,
    clippy::missing_errors_doc,
    clippy::style,
    clippy::unseparated_literal_suffix,
    clippy::pedantic,
    clippy::nursery
)]

use serde::Serialize;
use wasm_bindgen::prelude::*;

#[derive(Debug, Clone, Serialize, Copy, Default)]
#[serde(rename_all = "lowercase")]
pub enum Gravity {
    #[default]
    Top,
    Bottom,
}
impl AsRef<str> for Gravity {
    fn as_ref(&self) -> &str {
        match self {
            Self::Top => "top",
            Self::Bottom => "bottom",
        }
    }
}

#[derive(Debug, Clone, Serialize, Copy, Default)]
#[serde(rename_all = "lowercase")]
pub enum Position {
    Left,
    #[default]
    Right,
    Center,
}
impl AsRef<str> for Position {
    fn as_ref(&self) -> &str {
        match self {
            Self::Left => "left",
            Self::Right => "right",
            Self::Center => "center",
        }
    }
}

#[derive(Debug, Clone, Serialize)]
pub struct ToastifyOptions {
    pub text: String,
    pub duration: u32,
    pub destination: Option<String>,
    pub close: bool,
    pub gravity: Gravity,
    pub position: Position,
    #[serde(rename = "newWindow")]
    pub new_window: bool,
    #[serde(rename = "stopOnFocus")]
    pub stop_on_focus: bool,
    #[serde(rename = "className")]
    #[serde(skip_serializing_if = "Option::is_none")]
    pub class_name: Option<String>,
    #[serde(with = "serde_wasm_bindgen::preserve")]
    pub style: js_sys::Object,
    #[serde(with = "serde_wasm_bindgen::preserve")]
    #[serde(rename = "onClick")]
    pub on_click: JsValue,
}
impl Default for ToastifyOptions {
    fn default() -> Self {
        Self {
            text: String::new(),
            duration: 3000,
            destination: None,
            close: true,
            gravity: Gravity::Top,
            position: Position::Right,
            new_window: false,
            stop_on_focus: true,
            class_name: None,
            style: js_sys::Object::new(),
            on_click: JsValue::NULL,
        }
    }
}

impl ToastifyOptions {
    /// Add a style property to the toast
    /// Style properties match HTML DOM styles
    ///
    /// # Errors
    ///
    /// Returns an error if the style property is not a valid HTML DOM style
    pub fn add_style(self, style_property: &str, value: &str) -> Result<Self, JsValue> {
        js_sys::Reflect::set(
            &self.style,
            &JsValue::from_str(style_property),
            &JsValue::from_str(value),
        )?;
        Ok(self)
    }
    #[must_use]
    pub fn add_on_click<T>(self, callback: T) -> Self
    where
        T: Fn(),
    {
        let callback = Closure::wrap(Box::new(callback) as Box<dyn Fn()>);
        let mut this = self;
        this.on_click = callback.into_js_value();
        this
    }
    pub fn show(self) {
        let options: JsValue = self.into();
        toasts(&options).show_toast();
    }
}

impl From<ToastifyOptions> for JsValue {
    fn from(val: ToastifyOptions) -> Self {
        serde_wasm_bindgen::to_value(&val).expect("Failed to serialize Toast")
    }
}

#[wasm_bindgen]
extern "C" {
    #[derive(Debug, Clone)]
    pub type Toastify;
    #[wasm_bindgen(js_namespace = window, js_name = Toastify)]
    pub fn toasts(options: &JsValue) -> Toastify;
    #[wasm_bindgen(method, js_name = showToast)]
    pub fn show_toast(this: &Toastify);
}