From b016d9fff407c3fd86b660702a5bab6df3a5346b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=AD=90=E5=87=8C?= Date: Thu, 3 Apr 2025 13:29:31 +0800 Subject: [PATCH] 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 --- crates/story/src/modal_story.rs | 5 +++++ crates/ui/src/modal.rs | 7 ++++++- crates/ui/src/root.rs | 5 +++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/story/src/modal_story.rs b/crates/story/src/modal_story.rs index 1a4f9ace..8b5a8b82 100644 --- a/crates/story/src/modal_story.rs +++ b/crates/story/src/modal_story.rs @@ -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.))) }); }, ), diff --git a/crates/ui/src/modal.rs b/crates/ui/src/modal.rs index c0ac9d7d..a2c41738 100644 --- a/crates/ui/src/modal.rs +++ b/crates/ui/src/modal.rs @@ -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(); diff --git a/crates/ui/src/root.rs b/crates/ui/src/root.rs index 17d80421..6a7cceaa 100644 --- a/crates/ui/src/root.rs +++ b/crates/ui/src/root.rs @@ -34,6 +34,7 @@ pub trait ContextModal: Sized { fn open_modal(&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, active_drawer: Option, - active_modals: Vec, + pub(crate) active_modals: Vec, pub(super) focused_input: Option>, pub notification: Entity, drawer_size: Option, @@ -256,7 +257,7 @@ struct ActiveDrawer { } #[derive(Clone)] -struct ActiveModal { +pub(crate) struct ActiveModal { focus_handle: FocusHandle, builder: Rc Modal + 'static>, }