feat: Drawer adds mask_closeable and close_on_esc prop

This commit is contained in:
luoxiao 2024-04-07 22:38:18 +08:00 committed by luoxiaozero
parent 70b243ae0d
commit d5410375bb
2 changed files with 48 additions and 6 deletions

View file

@ -45,6 +45,8 @@ view! {
| --- | --- | --- | --- | | --- | --- | --- | --- |
| class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Addtional classes for the drawer element. | | class | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Addtional classes for the drawer element. |
| show | `Model<bool>` | | Whether to show drawer. | | show | `Model<bool>` | | Whether to show drawer. |
| mask_closeable | `MaybeSignal<bool>` | `true` | Whether to emit hide event when click mask. |
| close_on_esc | `bool` | `true` | Whether to close drawer on Esc is pressed. |
| title | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Drawer title. | | title | `OptionalProp<MaybeSignal<String>>` | `Default::default()` | Drawer title. |
| placement | `MaybeSignal<DrawerPlacement>` | `DrawerPlacement::Right` | Drawer placement. | | placement | `MaybeSignal<DrawerPlacement>` | `DrawerPlacement::Right` | Drawer placement. |
| width | `MaybeSignal<String>` | `520px` | Drawer width. | | width | `MaybeSignal<String>` | `520px` | Drawer width. |

View file

@ -1,11 +1,13 @@
use crate::Card; use crate::Card;
use leptos::*; use leptos::{leptos_dom::helpers::WindowListenerHandle, *};
use thaw_components::{CSSTransition, Teleport}; use thaw_components::{CSSTransition, Teleport};
use thaw_utils::{class_list, mount_style, use_lock_html_scroll, Model, OptionalProp}; use thaw_utils::{class_list, mount_style, use_lock_html_scroll, Model, OptionalProp};
#[component] #[component]
pub fn Drawer( pub fn Drawer(
#[prop(into)] show: Model<bool>, #[prop(into)] show: Model<bool>,
#[prop(default = true.into(), into)] mask_closeable: MaybeSignal<bool>,
#[prop(default = true, into)] close_on_esc: bool,
#[prop(optional, into)] title: OptionalProp<MaybeSignal<String>>, #[prop(optional, into)] title: OptionalProp<MaybeSignal<String>>,
#[prop(optional, into)] placement: MaybeSignal<DrawerPlacement>, #[prop(optional, into)] placement: MaybeSignal<DrawerPlacement>,
#[prop(default = MaybeSignal::Static("520px".to_string()), into)] width: MaybeSignal<String>, #[prop(default = MaybeSignal::Static("520px".to_string()), into)] width: MaybeSignal<String>,
@ -29,6 +31,8 @@ pub fn Drawer(
#[component] #[component]
fn DrawerInnr( fn DrawerInnr(
show: Model<bool>, show: Model<bool>,
mask_closeable: MaybeSignal<bool>,
close_on_esc: bool,
title: OptionalProp<MaybeSignal<String>>, title: OptionalProp<MaybeSignal<String>>,
placement: MaybeSignal<DrawerPlacement>, placement: MaybeSignal<DrawerPlacement>,
class: OptionalProp<MaybeSignal<String>>, class: OptionalProp<MaybeSignal<String>>,
@ -56,11 +60,31 @@ pub fn Drawer(
}; };
let is_lock = RwSignal::new(show.get_untracked()); let is_lock = RwSignal::new(show.get_untracked());
Effect::new(move |_| { let esc_handle = StoredValue::new(None::<WindowListenerHandle>);
if show.get() { Effect::new(move |prev| {
let is_show = show.get();
if is_show {
is_lock.set(true); is_lock.set(true);
is_css_transition.set(true); is_css_transition.set(true);
} }
if close_on_esc {
if is_show && !prev.unwrap_or(false) {
let handle = window_event_listener(ev::keydown, move |e| {
if &e.code() == "Escape" {
show.set(false);
}
});
esc_handle.set_value(Some(handle));
} else {
esc_handle.update_value(|handle| {
if let Some(handle) = handle.take() {
handle.remove();
}
})
}
}
is_show
}); });
use_lock_html_scroll(is_lock.into()); use_lock_html_scroll(is_lock.into());
let on_after_leave = move |_| { let on_after_leave = move |_| {
@ -68,6 +92,20 @@ pub fn Drawer(
is_css_transition.set(false); is_css_transition.set(false);
}; };
let on_mask_click = move |_| {
if mask_closeable.get_untracked() {
show.set(false);
}
};
on_cleanup(move || {
esc_handle.update_value(|handle| {
if let Some(handle) = handle.take() {
handle.remove();
}
})
});
view! { view! {
<div class="thaw-drawer-container" style=move || style.get()> <div class="thaw-drawer-container" style=move || style.get()>
<CSSTransition <CSSTransition
@ -79,7 +117,7 @@ pub fn Drawer(
<div <div
class="thaw-drawer-mask" class="thaw-drawer-mask"
style=move || display.get() style=move || display.get()
on:click=move |_| show.set(false) on:click=on_mask_click
ref=mask_ref ref=mask_ref
></div> ></div>
</CSSTransition> </CSSTransition>
@ -113,10 +151,12 @@ pub fn Drawer(
} }
match mount { match mount {
DrawerMount::None => view! { <DrawerInnr show title placement class style children/> }, DrawerMount::None => {
view! { <DrawerInnr show mask_closeable close_on_esc title placement class style children/> }
}
DrawerMount::Body => view! { DrawerMount::Body => view! {
<Teleport> <Teleport>
<DrawerInnr show title placement class style children/> <DrawerInnr show mask_closeable close_on_esc title placement class style children/>
</Teleport> </Teleport>
}, },
} }