mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 22:09:22 -05:00
Feature/toast on status change (#274)
* toast status change * toast status change * toast status change * dismiss all
This commit is contained in:
parent
e18bbff216
commit
f9d0fdc2ab
4 changed files with 102 additions and 12 deletions
|
@ -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! {
|
||||
<Toast>
|
||||
|
@ -113,7 +119,7 @@ let dispatch = move |_| {
|
|||
</ToastBodySubtitle>
|
||||
</ToastBody>
|
||||
</Toast>
|
||||
},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! {
|
||||
<Button on_click=dispatch>"Show toast"</Button>
|
||||
<Button on_click=dismiss>"Hide toast"</Button>
|
||||
{move || {if !mounted.get() {
|
||||
view!{<Button on_click=dispatch>"Show toast"</Button>}
|
||||
} else {
|
||||
view!{<Button on_click=dismiss>"Hide toast"</Button>}
|
||||
}
|
||||
}}}
|
||||
```
|
||||
|
||||
### Dismiss All
|
||||
|
||||
```rust demo
|
||||
let toaster = ToasterInjection::expect_context();
|
||||
|
||||
fn dispatch_toast(toaster: ToasterInjection) {
|
||||
toaster.dispatch_toast(move || view! {
|
||||
<Toast>
|
||||
<ToastTitle>"Email sent"</ToastTitle>
|
||||
<ToastBody>
|
||||
"This is a toast body"
|
||||
<ToastBodySubtitle slot>
|
||||
"Subtitle"
|
||||
</ToastBodySubtitle>
|
||||
</ToastBody>
|
||||
<ToastFooter>
|
||||
"Footer"
|
||||
</ToastFooter>
|
||||
</Toast>
|
||||
}, ToastOptions::default());
|
||||
};
|
||||
|
||||
let dismiss_all = move || {
|
||||
toaster.dismiss_all();
|
||||
};
|
||||
|
||||
view! {
|
||||
<Space>
|
||||
<Button on_click=move |_| dispatch_toast(toaster)>"Dispatch toast"</Button>
|
||||
<Button on_click=move |_| dismiss_all()>"Dismiss all"</Button>
|
||||
</Space>
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
|
|
@ -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<C, IV>(&self, children: C, options: ToastOptions)
|
||||
where
|
||||
C: FnOnce() -> IV + Send + 'static,
|
||||
|
|
|
@ -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<ToastPosition>,
|
||||
pub(crate) timeout: Option<Duration>,
|
||||
pub(crate) intent: Option<ToastIntent>,
|
||||
pub(crate) on_status_change: Option<ArcOneCallback<ToastStatus>>,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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! {
|
||||
|
|
Loading…
Add table
Reference in a new issue