From 4cb45ec63a9ec34ab13cf0c3c41825d69cf7bcb1 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Tue, 30 Jun 2026 23:45:17 +0100 Subject: [PATCH] fix: Esc priority across slideover / settings / modal handlers Pressing Esc after editing a card silently failed: requestCloseSlideOver opened the discard-confirm modal, then the global Esc-fallback handler fired on the same keystroke and either closed the just-opened modal (when Esc came on a clean slideover via the modal path) or, when Settings was layered on top of a dirty slideover, opened the discard prompt in the background while Settings closed. Both panel-level Esc handlers now run in capture phase and stopPropagation: - Slideover handler stops only when it actually acts (slideover open, no modal up, Settings not on top) so a single Esc opens the discard confirm without the global fallback racing to close it. - Settings handler stops when Settings is the active panel so the global fallback's requestCloseSlideOver branch can't fire underneath and pop a discard confirm on the slideover the user left dirty. Priority order is now: open modal > Settings > slideover. First Esc on "card dirty + Settings open" closes Settings; second Esc shows the discard confirm. Clean slideover + Esc still closes directly. Co-Authored-By: Claude Opus 4.7 --- delphi-backend/assets/assets.res | Bin 625676 -> 626732 bytes js/app.js | 19 ++++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/delphi-backend/assets/assets.res b/delphi-backend/assets/assets.res index b7359cda428a99089936bb8ec604fd87feb7e83c..7a54d9600a87aa1b48d46a0269d76ad1a8c058ec 100644 GIT binary patch delta 961 zcmZ9Lzi-n(6vvfP;wXrciB6zLMSn?6%LYOMsiKt_Xc)3GaIs(FBbPgKcW%g(ZXI9) zWCjL6jEt4CAr>Tv*jboZ@(=I_@b2ui21_?s*8AS~`*~l#c(eBD-P+Mfp_8E^IJVGV;nXlaWAE_TsM2{j3{^xVEEa7-QJqh6iZ9`e_p9EmzQ> zQ(4*0e!dSNTlx^(@KDBdC&WmpjPjE`p*l>!iW~H443HHHIyg`f6DxDIvY$wyk?Yps zAUc$T{Iz!v_Mwj>W3}odPzd0I0l8)t#fV&+0XL?e-Jb@R#`G349W{%a=qnS-abgxU zK26csdyZ^d@CY9s7Uaqn3W#o>eyWr9Kwvkg;aLwkZCENeOu&@uz-YhFI zAz)+Rvd%Z-yn7TBK~g>h%ftTWc0GH1w{|^yxm>%FUHB1Po&5S5Ji0cfvg|2`Llny> zkP^{mm(=~G^PQBD88-N*a%c2hEN%@LmtRr-W?r<8W-^Rn=)0HDCW-vmv2`@dq2^%8 zzgv#8(9YWhhGwY4ncW^g07=f4xh?#+y1&CRJm~Hzh0roFjrgvI$$ZkJ+f<0Do U`ut1mitUxJ*|%4|=GeRh0JwV`g#Z8m diff --git a/js/app.js b/js/app.js index a2977ea..08ea7f7 100644 --- a/js/app.js +++ b/js/app.js @@ -10402,6 +10402,18 @@ async function init() { if (e.key !== 'Escape') return; if (!$('#slideover').classList.contains('is-open')) return; if (document.querySelector('.modal:not(.is-hidden)')) return; + // Settings panel takes priority — when both Settings AND the + // editor are open, the first Esc should close Settings (the + // thing the user just opened on top), the second Esc handles + // the editor's dirty-check. Let the Settings Esc handler run. + if ($('#settingsPanel').classList.contains('is-open')) return; + // Stop here so the global "Esc closes confirmModal" handler + // doesn't fire on the SAME keystroke and immediately dismiss + // the discard-confirm dialog that requestCloseSlideOver just + // opened — that bug left the user with no visible feedback at + // all (modal opened and closed in one tick). + e.preventDefault(); + e.stopPropagation(); requestCloseSlideOver(); }, true); // Click-outside closes too. mousedown origin is captured so a @@ -10585,8 +10597,13 @@ async function init() { if (e.key !== 'Escape') return; if (!$('#settingsPanel').classList.contains('is-open')) return; if (document.querySelector('.modal:not(.is-hidden)')) return; + // Don't let the global Esc-fallback handler fire on the same + // keystroke — its slideover-close branch would pop the discard + // confirm in the background while Settings closes, surprising + // the user who expected one Esc = close one panel. + e.stopPropagation(); closeSettings(); - }); + }, true); // Settings search box: live filter on every input. Escape clears the // query (without closing the panel — the existing Esc handler also