diff --git a/thaw/src/toast/docs/mod.md b/thaw/src/toast/docs/mod.md index 151717a..3cfc550 100644 --- a/thaw/src/toast/docs/mod.md +++ b/thaw/src/toast/docs/mod.md @@ -102,6 +102,12 @@ let toaster = ToasterInjection::expect_context(); let id = uuid::Uuid::new_v4(); +let mounted = RwSignal::new(false); + +let on_status_change = move |status| { + mounted.set(status == ToastStatus::Mounted); +}; + let dispatch = move |_| { toaster.dispatch_toast(move || view! { @@ -113,7 +119,7 @@ let dispatch = move |_| { - },ToastOptions::default().with_id(id)); + },ToastOptions::default().with_id(id).with_on_status_change(on_status_change)) }; let dismiss = move |_| { @@ -121,8 +127,45 @@ let dismiss = move |_| { }; view! { - - + {move || {if !mounted.get() { + view!{} + } else { + view!{} + } +}}} +``` + +### Dismiss All + +```rust demo +let toaster = ToasterInjection::expect_context(); + +fn dispatch_toast(toaster: ToasterInjection) { + toaster.dispatch_toast(move || view! { + + "Email sent" + + "This is a toast body" + + "Subtitle" + + + + "Footer" + + + }, ToastOptions::default()); +}; + +let dismiss_all = move || { + toaster.dismiss_all(); +}; + +view! { + + + + } ``` @@ -160,11 +203,12 @@ view! { ### ToastOptions Props -| Name | Type | Description | -| ------------- | --------------------------------------- | ------------------------------------- | -| with_position | `Fn(mut self, position: ToastPosition)` | The position the toast should render. | -| with_timeout | `Fn(mut self, timeout: Duration)` | Auto dismiss timeout in milliseconds. | -| with_intent | `Fn(mut self, intent: ToastIntent)` | The intent of the toast. | +| Name | Type | Description | +| --------------------- | ----------------------------------------------------- | ------------------------------------- | +| with_position | `Fn(mut self, position: ToastPosition)` | The position the toast should render. | +| with_timeout | `Fn(mut self, timeout: Duration)` | Auto dismiss timeout in milliseconds. | +| with_intent | `Fn(mut self, intent: ToastIntent)` | The intent of the toast. | +| with_on_status_change | `Fn(mut self, on_status_change: Fn(ToastStatus))` | The intent of the toast. | ### Toast & ToastFooter Props diff --git a/thaw/src/toast/mod.rs b/thaw/src/toast/mod.rs index 3014c96..73c4deb 100644 --- a/thaw/src/toast/mod.rs +++ b/thaw/src/toast/mod.rs @@ -24,6 +24,7 @@ pub struct ToasterInjection { enum ToasterMessage { Dispatch(Children, ToastOptions), Dismiss(uuid::Uuid), + DismissAll, } impl ToasterInjection { @@ -53,6 +54,15 @@ impl ToasterInjection { self.trigger.with_value(|trigger| trigger.notify()); } + pub fn dismiss_all(&self) { + self.sender.with_value(|sender| { + sender + .send(ToasterMessage::DismissAll) + .unwrap_throw() + }); + self.trigger.with_value(|trigger| trigger.notify()); + } + pub fn dispatch_toast(&self, children: C, options: ToastOptions) where C: FnOnce() -> IV + Send + 'static, diff --git a/thaw/src/toast/toast.rs b/thaw/src/toast/toast.rs index 2f7dbfb..6b93df1 100644 --- a/thaw/src/toast/toast.rs +++ b/thaw/src/toast/toast.rs @@ -1,6 +1,6 @@ use leptos::prelude::*; use std::time::Duration; -use thaw_utils::class_list; +use thaw_utils::{class_list, ArcOneCallback}; #[component] pub fn Toast( @@ -43,12 +43,19 @@ pub enum ToastIntent { Error, } +#[derive(Debug, Clone, PartialEq)] +pub enum ToastStatus { + Mounted, + Unmounted, +} + #[derive(Clone)] pub struct ToastOptions { pub(crate) id: uuid::Uuid, pub(crate) position: Option, pub(crate) timeout: Option, pub(crate) intent: Option, + pub(crate) on_status_change: Option>, } impl Default for ToastOptions { @@ -58,6 +65,7 @@ impl Default for ToastOptions { position: None, timeout: None, intent: None, + on_status_change: None, } } } @@ -86,4 +94,13 @@ impl ToastOptions { self.intent = Some(intent); self } + + /// Status change callback. + pub fn with_on_status_change( + mut self, + on_status_change: impl Fn(ToastStatus) + Send + Sync + 'static, + ) -> Self { + self.on_status_change = Some(on_status_change.into()); + self + } } diff --git a/thaw/src/toast/toaster.rs b/thaw/src/toast/toaster.rs index 2522674..012f9f7 100644 --- a/thaw/src/toast/toaster.rs +++ b/thaw/src/toast/toaster.rs @@ -1,5 +1,5 @@ use super::{ToastIntent, ToastOptions, ToastPosition, ToasterReceiver}; -use crate::{toast::ToasterMessage, ConfigInjection}; +use crate::{toast::ToasterMessage, ConfigInjection, ToastStatus}; use leptos::{context::Provider, either::Either, html, prelude::*}; use send_wrapper::SendWrapper; use std::{collections::HashMap, time::Duration}; @@ -51,10 +51,14 @@ pub fn Toaster( if options.intent.is_none() { options.intent = Some(intent); } - let list = id_list(&options.position.unwrap_throw()); let id = options.id; let is_show = owner.with(|| RwSignal::new(true)); + + if let Some(on_status_change) = options.on_status_change.clone() { + on_status_change(ToastStatus::Mounted) + } + toasts.update_value(|map| { map.insert(id, (SendWrapper::new(view), options, is_show)); }); @@ -66,7 +70,18 @@ pub fn Toaster( }); } ToasterMessage::Dismiss(toast_id) => { - toast_show_list.with_value(|map| map.get(&toast_id).unwrap_throw().set(false)); + toast_show_list.with_value(|map| { + if let Some(is_show) = map.get(&toast_id) { + is_show.set(false) + } + }); + }, + ToasterMessage::DismissAll => { + toast_show_list.with_value(|map| { + for is_show in map.values() { + is_show.set(false) + } + }); } } } @@ -238,6 +253,7 @@ fn ToasterContainer( timeout, position, intent, + on_status_change, .. } = options; @@ -266,6 +282,9 @@ fn ToasterContainer( f(id, position); } }); + if let Some(on_status_change) = on_status_change.clone() { + on_status_change(ToastStatus::Unmounted); + } }; view! {