Compare commits

...

2 commits

Author SHA1 Message Date
Yann Dirson
50bd30de1d
OverlayDrawer: only set aria-modal to true when modal (#275)
Some checks failed
Deploy demo / deploy (push) Has been cancelled
2024-10-07 14:26:08 +08:00
kandrelczyk
f9d0fdc2ab
Feature/toast on status change (#274)
* toast status change

* toast status change

* toast status change

* dismiss all
2024-10-07 14:13:13 +08:00
5 changed files with 103 additions and 13 deletions

View file

@ -113,7 +113,7 @@ pub fn OverlayDrawer(
}
node_ref=drawer_ref
role="dialog"
aria-modal="true"
aria-modal={if modal_type == DrawerModalType::Modal {"true"} else {"false"}}
>
{children()}
</div>

View file

@ -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

View file

@ -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,

View file

@ -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
}
}

View file

@ -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! {