From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [IPv6:2a0f:8001:1:32::40]) by lore.proxmox.com (Postfix) with ESMTPS id 877681FF0E0 for ; Thu, 09 Jul 2026 16:14:59 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 388B021452; Thu, 09 Jul 2026 16:14:59 +0200 (CEST) From: Dominik Csapak To: yew-devel@lists.proxmox.com Subject: [PATCH yew-widget-toolkit v2] widget: dialog: prevent Escape from closing non-closable modals Date: Thu, 9 Jul 2026 16:14:38 +0200 Message-ID: <20260709141455.623886-1-d.csapak@proxmox.com> X-Mailer: git-send-email 2.47.3 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.076 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: WU4MMUDR3OICSAZ3GJI2UFFIPLGJGJOV X-Message-ID-Hash: WU4MMUDR3OICSAZ3GJI2UFFIPLGJGJOV X-MailFrom: d.csapak@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Yew framework devel list at Proxmox List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Pressing Escape on a triggers the browser's native close handling regardless of whether our code considers the dialog closable. When the dialog has no 'on_close' callback (e.g. a Login Window), this leaves our component state and the native dialog state out of sync: the browser treats the dialog as closed, while our widget is still rendered but without the corresponding 'open' CSS class (which hides the backdrop). Intercept the KeyDown event and call stop_propagation()/ prevent_default() for Escape whenever the dialog isn't closable, so the browser never fires its native close in the first place. Signed-off-by: Dominik Csapak --- changes from v1: * drop the leftover debug log::info line src/widget/dialog.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/widget/dialog.rs b/src/widget/dialog.rs index 4afecb2..c970009 100644 --- a/src/widget/dialog.rs +++ b/src/widget/dialog.rs @@ -114,6 +114,7 @@ impl Dialog { pub enum Msg { Open, + KeyDown(KeyboardEvent), Close, PointerDown(PointerEvent), PointerMove(PointerEvent), @@ -213,6 +214,13 @@ impl Component for PwtDialog { } } } + Msg::KeyDown(event) => { + // prevent autoclosing of modal windows that can't be closed + if event.key() == "Escape" && (!self.open || props.on_close.is_none()) { + event.stop_propagation(); + event.prevent_default(); + } + } Msg::Close => { if self.open { if let Some(on_close) = &props.on_close { @@ -460,6 +468,8 @@ impl Component for PwtDialog { Msg::Close }); + let onkeydown = link.callback(Msg::KeyDown); + let mut panel = Panel::new() .class("pwt-overflow-auto") .class("pwt-flex-fill") @@ -533,6 +543,7 @@ impl Component for PwtDialog { let dialog = Container::from_tag("dialog") .class("pwt-outer-dialog") .onpointerdown(onpointerdown) + .onkeydown(onkeydown) .onclose(onclose) .ontouchstart(cancel_event.clone()) .ontouchend(cancel_event.clone()) -- 2.47.3