modal: Fix close Modal by clicking overlay to support closing layer by layer. (#771)

Fix the issue that wrongly trigger `overlay` click event for the
layer-stacked `modals`.

Fix #772 

I.E. When clicking the `overlay`, only the last modal will possibly be
hide(If the last modal is not `overlayClosable`, click the overlay, all
the modals will not be hide).


![gif](https://github.com/user-attachments/assets/96ac97fc-6b6d-463d-bce9-393e6236c5df)

I had tried another solution:

![image](https://github.com/user-attachments/assets/d9882d70-c82c-4397-a5ff-65cd49dc08ab)

![image](https://github.com/user-attachments/assets/3855fb6b-4aac-4c7c-9581-3b0843ef78dc)

If this one is better than prev, I will commit it~

---------

Co-authored-by: Jason Lee <huacnlee@gmail.com>
This commit is contained in:
王子凌 2025-04-03 13:29:31 +08:00 committed by GitHub
parent 3051b9c1c4
commit b016d9fff4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 14 additions and 3 deletions

View file

@ -420,6 +420,11 @@ impl ModalStory {
.title("Other Modal")
.child("This is another modal.")
.min_h(px(300.))
.overlay(overlay)
.keyboard(keyboard)
.show_close(modal_show_close)
.overlay_closable(overlay_closable)
.when(!modal_padding, |this| this.p(px(0.)))
});
},
),

View file

@ -12,7 +12,7 @@ use crate::{
actions::{Cancel, Confirm},
animation::cubic_bezier,
button::{Button, ButtonVariant, ButtonVariants as _},
h_flex, v_flex, ActiveTheme as _, ContextModal, IconName, Sizable as _, StyledExt,
h_flex, v_flex, ActiveTheme as _, ContextModal, IconName, Root, Sizable as _, StyledExt,
};
const CONTEXT: &str = "Modal";
@ -362,6 +362,11 @@ impl RenderOnce for Modal {
this.occlude().bg(overlay_color(self.overlay, window, cx))
})
.when(self.overlay_closable, |this| {
// Only the last modal owns the `mouse down - close modal` event.
if (self.layer_ix + 1) != Root::read(window, cx).active_modals.len() {
return this;
}
this.on_mouse_down(MouseButton::Left, {
let on_cancel = on_cancel.clone();
let on_close = on_close.clone();

View file

@ -34,6 +34,7 @@ pub trait ContextModal: Sized {
fn open_modal<F>(&mut self, cx: &mut App, build: F)
where
F: Fn(Modal, &mut Window, &mut App) -> Modal + 'static;
/// Return true, if there is an active Modal.
fn has_active_modal(&mut self, cx: &mut App) -> bool;
@ -241,7 +242,7 @@ pub struct Root {
/// When the Modal, Drawer closes, we will focus back to the previous view.
previous_focus_handle: Option<FocusHandle>,
active_drawer: Option<ActiveDrawer>,
active_modals: Vec<ActiveModal>,
pub(crate) active_modals: Vec<ActiveModal>,
pub(super) focused_input: Option<Entity<TextInput>>,
pub notification: Entity<NotificationList>,
drawer_size: Option<DefiniteLength>,
@ -256,7 +257,7 @@ struct ActiveDrawer {
}
#[derive(Clone)]
struct ActiveModal {
pub(crate) struct ActiveModal {
focus_handle: FocusHandle,
builder: Rc<dyn Fn(Modal, &mut Window, &mut App) -> Modal + 'static>,
}