mirror of
https://github.com/adoyle0/thaw.git
synced 2025-01-22 14:09:21 -05:00
Toast intent (#269)
* add toast intent support * toast intent * toast intent * fix CI
This commit is contained in:
parent
3545744335
commit
a03226f202
10 changed files with 154 additions and 31 deletions
|
@ -79,7 +79,9 @@ pub fn SiteHeader() -> impl IntoView {
|
|||
{
|
||||
use leptos::ev;
|
||||
let handle = window_event_listener(ev::keydown, move |e| {
|
||||
if js_sys::Reflect::has(&e, &js_sys::wasm_bindgen::JsValue::from_str("key")).unwrap_or_default() {
|
||||
if js_sys::Reflect::has(&e, &js_sys::wasm_bindgen::JsValue::from_str("key"))
|
||||
.unwrap_or_default()
|
||||
{
|
||||
let key = e.key();
|
||||
if key == *"/" {
|
||||
if let Some(auto_complete_ref) = auto_complete_ref.get_untracked() {
|
||||
|
@ -88,7 +90,6 @@ pub fn SiteHeader() -> impl IntoView {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
on_cleanup(move || handle.remove());
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@ use leptos::prelude::*;
|
|||
fn main() {
|
||||
let _ = console_log::init_with_level(log::Level::Debug);
|
||||
console_error_panic_hook::set_once();
|
||||
|
||||
|
||||
mount_to_body(App)
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use crate::components::SiteHeader;
|
||||
use leptos::prelude::*;
|
||||
use leptos_meta::Style;
|
||||
use leptos_router::hooks::{use_navigate, use_query_map};
|
||||
use thaw::*;
|
||||
use leptos_meta::Style;
|
||||
|
||||
#[component]
|
||||
pub fn Home() -> impl IntoView {
|
||||
|
|
|
@ -158,7 +158,7 @@ fn iter_nodes<'a>(
|
|||
NodeValue::Superscript => quote!("Superscript todo!!!"),
|
||||
NodeValue::Link(node_link) => {
|
||||
let NodeLink { url, title } = node_link;
|
||||
|
||||
|
||||
quote!(
|
||||
<Link href=#url attr:title=#title>
|
||||
#(#children)*
|
||||
|
|
|
@ -63,11 +63,67 @@ view! {
|
|||
}
|
||||
```
|
||||
|
||||
### Toast Intent
|
||||
|
||||
```rust demo
|
||||
let toaster = ToasterInjection::expect_context();
|
||||
|
||||
fn dispatch_toast(toaster: ToasterInjection, intent: ToastIntent) {
|
||||
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().with_intent(intent));
|
||||
};
|
||||
|
||||
view! {
|
||||
<Space>
|
||||
<Button on_click=move |_| dispatch_toast(toaster, ToastIntent::Info)>"Info"</Button>
|
||||
<Button on_click=move |_| dispatch_toast(toaster, ToastIntent::Success)>"Success"</Button>
|
||||
<Button on_click=move |_| dispatch_toast(toaster, ToastIntent::Warning)>"Warning"</Button>
|
||||
<Button on_click=move |_| dispatch_toast(toaster, ToastIntent::Error)>"Error"</Button>
|
||||
</Space>
|
||||
}
|
||||
```
|
||||
|
||||
### Toast Title Media
|
||||
|
||||
```rust demo
|
||||
let toaster = ToasterInjection::expect_context();
|
||||
|
||||
let on_click = move |_| {
|
||||
toaster.dispatch_toast(move || view! {
|
||||
<Toast>
|
||||
<ToastTitle>
|
||||
"Loading"
|
||||
<ToastTitleMedia slot>
|
||||
<Spinner size=SpinnerSize::Tiny/>
|
||||
</ToastTitleMedia>
|
||||
</ToastTitle>
|
||||
</Toast>
|
||||
}, Default::default());
|
||||
};
|
||||
|
||||
view! {
|
||||
<Button on_click=on_click>"Make toast"</Button>
|
||||
}
|
||||
```
|
||||
|
||||
### ToasterProvider Props
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| -------- | --------------- | -------------------------- | ------------------------------------- |
|
||||
| position | `ToastPosition` | `ToastPosition::BottomEnd` | The position the toast should render. |
|
||||
| intent | `ToastIntent ` | `ToastPosition::Info` | The intent of the toast. |
|
||||
| children | `Children` | | |
|
||||
|
||||
### ToastOptions Props
|
||||
|
@ -76,7 +132,7 @@ view! {
|
|||
| ------------- | --------------------------------------- | ------------------------------------- |
|
||||
| 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)` | Intent. |
|
||||
| with_intent | `Fn(mut self, intent: ToastIntent)` | The intent of the toast. |
|
||||
|
||||
### Toast & ToastFooter Props
|
||||
|
||||
|
|
|
@ -34,9 +34,10 @@ impl ToastPosition {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub enum ToastIntent {
|
||||
Success,
|
||||
#[default]
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
use leptos::{either::Either, prelude::*};
|
||||
use thaw_components::OptionComp;
|
||||
use thaw_utils::class_list;
|
||||
|
||||
use crate::ToastIntent;
|
||||
|
||||
#[component]
|
||||
pub fn ToastTitle(
|
||||
|
@ -7,27 +10,63 @@ pub fn ToastTitle(
|
|||
children: Children,
|
||||
#[prop(optional)] toast_title_action: Option<ToastTitleAction>,
|
||||
) -> impl IntoView {
|
||||
let intent: ToastIntent = expect_context();
|
||||
|
||||
view! {
|
||||
<div class="thaw-toast-title__media">
|
||||
<div class=class_list![
|
||||
"thaw-toast-title__media", format!("thaw-toast-title__{:?}", intent).to_lowercase()
|
||||
]>
|
||||
{if let Some(media) = toast_title_media {
|
||||
Either::Left((media.children)())
|
||||
} else {
|
||||
Either::Right(
|
||||
view! {
|
||||
<svg
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
<path
|
||||
d="M18 10a8 8 0 1 0-16 0 8 8 0 0 0 16 0ZM9.5 8.91a.5.5 0 0 1 1 0V13.6a.5.5 0 0 1-1 0V8.9Zm-.25-2.16a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0Z"
|
||||
{
|
||||
Either::Right(
|
||||
view! {
|
||||
<svg
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
},
|
||||
)
|
||||
aria-hidden="true"
|
||||
width="1em"
|
||||
height="1em"
|
||||
viewBox="0 0 20 20"
|
||||
>
|
||||
{match intent {
|
||||
ToastIntent::Info => {
|
||||
view! {
|
||||
<path
|
||||
d="M18 10a8 8 0 1 0-16 0 8 8 0 0 0 16 0ZM9.5 8.91a.5.5 0 0 1 1 0V13.6a.5.5 0 0 1-1 0V8.9Zm-.25-2.16a.75.75 0 1 1 1.5 0 .75.75 0 0 1-1.5 0Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
}.into_any()
|
||||
},
|
||||
ToastIntent::Success => {
|
||||
view! {
|
||||
<path
|
||||
d="M10 2a8 8 0 1 1 0 16 8 8 0 0 1 0-16Zm3.36 5.65a.5.5 0 0 0-.64-.06l-.07.06L9 11.3 7.35 9.65l-.07-.06a.5.5 0 0 0-.7.7l.07.07 2 2 .07.06c.17.11.4.11.56 0l.07-.06 4-4 .07-.08a.5.5 0 0 0-.06-.63Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
}.into_any()
|
||||
},
|
||||
ToastIntent::Warning => {
|
||||
view! {
|
||||
<path
|
||||
d="M8.68 2.79a1.5 1.5 0 0 1 2.64 0l6.5 12A1.5 1.5 0 0 1 16.5 17h-13a1.5 1.5 0 0 1-1.32-2.21l6.5-12ZM10.5 7.5a.5.5 0 0 0-1 0v4a.5.5 0 0 0 1 0v-4Zm.25 6.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
}.into_any()
|
||||
},
|
||||
ToastIntent::Error => {
|
||||
view! {
|
||||
<path
|
||||
d="M10 2a8 8 0 1 1 0 16 8 8 0 0 1 0-16ZM7.8 7.11a.5.5 0 0 0-.63.06l-.06.07a.5.5 0 0 0 .06.64L9.3 10l-2.12 2.12-.06.07a.5.5 0 0 0 .06.64l.07.06c.2.13.47.11.64-.06L10 10.7l2.12 2.12.07.06c.2.13.46.11.64-.06l.06-.07a.5.5 0 0 0-.06-.64L10.7 10l2.12-2.12.06-.07a.5.5 0 0 0-.06-.64l-.07-.06a.5.5 0 0 0-.64.06L10 9.3 7.88 7.17l-.07-.06Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
}.into_any()
|
||||
}
|
||||
}}
|
||||
</svg>
|
||||
},
|
||||
)
|
||||
}
|
||||
}}
|
||||
</div>
|
||||
<div class="thaw-toast-title">{children()}</div>
|
||||
|
|
|
@ -108,10 +108,25 @@ div.thaw-toaster-wrapper {
|
|||
grid-column-end: 2;
|
||||
padding-right: 8px;
|
||||
font-size: 16px;
|
||||
color: var(--colorNeutralForeground1);
|
||||
color: var(--colorNeutralForeground2);
|
||||
}
|
||||
|
||||
.thaw-toast-title__info {
|
||||
color: var(--colorNeutralForeground2);
|
||||
}
|
||||
|
||||
.thaw-toast-title__success {
|
||||
color: var(--colorStatusSuccessForeground1);
|
||||
}
|
||||
|
||||
.thaw-toast-title__warning {
|
||||
color: var(--colorStatusWarningForeground3);
|
||||
}
|
||||
|
||||
.thaw-toast-title__error {
|
||||
color: var(--colorStatusDangerForeground1);
|
||||
}
|
||||
|
||||
.thaw-toast-title__media > svg {
|
||||
display: inline;
|
||||
line-height: 0;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{ToastOptions, ToastPosition, ToasterReceiver};
|
||||
use super::{ToastIntent, ToastOptions, ToastPosition, ToasterReceiver};
|
||||
use crate::ConfigInjection;
|
||||
use leptos::{either::Either, html, prelude::*};
|
||||
use leptos::{context::Provider, either::Either, html, prelude::*};
|
||||
use send_wrapper::SendWrapper;
|
||||
use std::{collections::HashMap, time::Duration};
|
||||
use thaw_components::{CSSTransition, Teleport};
|
||||
|
@ -11,6 +11,7 @@ use wasm_bindgen::UnwrapThrowExt;
|
|||
pub fn Toaster(
|
||||
receiver: ToasterReceiver,
|
||||
#[prop(optional)] position: ToastPosition,
|
||||
#[prop(optional)] intent: ToastIntent,
|
||||
#[prop(default = Duration::from_secs(3))] timeout: Duration,
|
||||
) -> impl IntoView {
|
||||
mount_style("toaster", include_str!("./toaster.css"));
|
||||
|
@ -42,6 +43,9 @@ pub fn Toaster(
|
|||
if options.timeout.is_none() {
|
||||
options.timeout = Some(timeout);
|
||||
}
|
||||
if options.intent.is_none() {
|
||||
options.intent = Some(intent);
|
||||
}
|
||||
|
||||
let list = id_list(&options.position.unwrap_throw());
|
||||
let id = options.id;
|
||||
|
@ -171,10 +175,12 @@ fn ToasterContainer(
|
|||
id,
|
||||
timeout,
|
||||
position,
|
||||
intent,
|
||||
..
|
||||
} = options;
|
||||
let timeout = timeout.unwrap_throw();
|
||||
let position = position.unwrap_throw();
|
||||
let intent = intent.unwrap_throw();
|
||||
|
||||
if !timeout.is_zero() {
|
||||
set_timeout(
|
||||
|
@ -209,9 +215,11 @@ fn ToasterContainer(
|
|||
on_after_leave=on_after_leave
|
||||
let:_
|
||||
>
|
||||
<div class="thaw-toaster-container" node_ref=container_ref>
|
||||
{children()}
|
||||
</div>
|
||||
<Provider value=intent>
|
||||
<div class="thaw-toaster-container" node_ref=container_ref>
|
||||
{children()}
|
||||
</div>
|
||||
</Provider>
|
||||
</CSSTransition>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::{toaster::Toaster, ToastPosition, ToasterInjection};
|
||||
use super::{toaster::Toaster, ToastIntent, ToastPosition, ToasterInjection};
|
||||
use leptos::{context::Provider, prelude::*};
|
||||
|
||||
#[component]
|
||||
|
@ -6,11 +6,14 @@ pub fn ToasterProvider(
|
|||
/// The position the toast should render.
|
||||
#[prop(optional)]
|
||||
position: ToastPosition,
|
||||
/// The intent of the toasts
|
||||
#[prop(optional)]
|
||||
intent: ToastIntent,
|
||||
children: Children,
|
||||
) -> impl IntoView {
|
||||
let (injection, receiver) = ToasterInjection::channel();
|
||||
view! {
|
||||
<Toaster receiver position />
|
||||
<Toaster receiver position intent />
|
||||
<Provider value=injection>{children()}</Provider>
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue