feat: Modal adds close_on_esc prop

This commit is contained in:
luoxiao 2024-04-05 18:46:12 +08:00 committed by luoxiaozero
parent 8233ca6c6e
commit 6088447e21
2 changed files with 32 additions and 4 deletions

View file

@ -20,6 +20,7 @@ view! {
| width | `MaybeSignal<String>` | `600px` | Modal width. | | width | `MaybeSignal<String>` | `600px` | Modal width. |
| z_index | `MaybeSignal<i16>` | `2000` | z-index of the modal. | | z_index | `MaybeSignal<i16>` | `2000` | z-index of the modal. |
| mask_closeable | `MaybeSignal<bool>` | `true` | Whether to emit hide event when click mask. | | mask_closeable | `MaybeSignal<bool>` | `true` | Whether to emit hide event when click mask. |
| close_on_esc | `bool` | `true` | Whether to close modal on Esc is pressed. |
| children | `Children` | | Modal's content. | | children | `Children` | | Modal's content. |
### Modal Slots ### Modal Slots

View file

@ -1,5 +1,5 @@
use crate::{Card, CardFooter, CardHeader, CardHeaderExtra, Icon}; use crate::{Card, CardFooter, CardHeader, CardHeaderExtra, Icon};
use leptos::*; use leptos::{leptos_dom::helpers::WindowListenerHandle, *};
use thaw_components::{CSSTransition, OptionComp, Teleport}; use thaw_components::{CSSTransition, OptionComp, Teleport};
use thaw_utils::{mount_style, use_click_position, Model}; use thaw_utils::{mount_style, use_click_position, Model};
@ -12,6 +12,7 @@ pub struct ModalFooter {
pub fn Modal( pub fn Modal(
#[prop(into)] show: Model<bool>, #[prop(into)] show: Model<bool>,
#[prop(default = true.into(), into)] mask_closeable: MaybeSignal<bool>, #[prop(default = true.into(), into)] mask_closeable: MaybeSignal<bool>,
#[prop(default = true, into)] close_on_esc: bool,
#[prop(default = 2000.into(), into)] z_index: MaybeSignal<i16>, #[prop(default = 2000.into(), into)] z_index: MaybeSignal<i16>,
#[prop(default = MaybeSignal::Static("600px".to_string()), into)] width: MaybeSignal<String>, #[prop(default = MaybeSignal::Static("600px".to_string()), into)] width: MaybeSignal<String>,
#[prop(optional, into)] title: MaybeSignal<String>, #[prop(optional, into)] title: MaybeSignal<String>,
@ -21,12 +22,30 @@ pub fn Modal(
mount_style("modal", include_str!("./modal.css")); mount_style("modal", include_str!("./modal.css"));
let displayed = RwSignal::new(show.get_untracked()); let displayed = RwSignal::new(show.get_untracked());
let esc_handle = StoredValue::new(None::<WindowListenerHandle>);
Effect::new(move |prev| { Effect::new(move |prev| {
let show = show.get(); let is_show = show.get();
if prev.is_some() && show { if prev.is_some() && is_show {
displayed.set(true); displayed.set(true);
} }
show
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
}); });
let on_mask_click = move |_| { let on_mask_click = move |_| {
@ -60,6 +79,14 @@ pub fn Modal(
let _ = modal_el.attr("style", format!("transform-origin: {}px {}px", x, y)); let _ = modal_el.attr("style", format!("transform-origin: {}px {}px", x, y));
}); });
on_cleanup(move || {
esc_handle.update_value(|handle| {
if let Some(handle) = handle.take() {
handle.remove();
}
})
});
view! { view! {
<Teleport> <Teleport>
<div <div