From 010c4263bac39200a77bd64748a8e323bfd6eded Mon Sep 17 00:00:00 2001 From: adlee-was-taken Date: Sat, 25 Apr 2026 00:36:10 -0400 Subject: [PATCH] fix(ext/popup): stop Escape from leaking past the generator panel Two related bugs from the gen-panel rewrite (ac15f06): 1. Escape key was bubbling to view-level keydown handlers in login.ts and settings-vault.ts, causing the press that closed the panel to also navigate the user away from the form/settings. Fix: call e.stopPropagation() in the panel's escHandler before closing. 2. settings-vault.teardown() didn't close any open generator panel, leaving the panel's escHandler registered and activePanel state stale across view transitions. Fix: call closeGeneratorPanel() first in teardown. Plus a configure-defaults context test for the action-row composition (no use/cancel buttons in that context). Co-Authored-By: Claude Opus 4.7 (1M context) --- .../popup/components/__tests__/generator-panel.test.ts | 9 +++++++++ extension/src/popup/components/generator-panel.ts | 5 ++++- extension/src/popup/components/settings-vault.ts | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/extension/src/popup/components/__tests__/generator-panel.test.ts b/extension/src/popup/components/__tests__/generator-panel.test.ts index ab2c7a4..3c26d5a 100644 --- a/extension/src/popup/components/__tests__/generator-panel.test.ts +++ b/extension/src/popup/components/__tests__/generator-panel.test.ts @@ -157,4 +157,13 @@ describe('generator-panel', () => { expect(isGeneratorPanelOpen()).toBe(false); expect(document.querySelector('.gen-panel')).toBeNull(); }); + + it("configure-defaults context renders only the save-default action (no use/cancel)", async () => { + const { parent, trigger } = setupMount(); + openGeneratorPanel({ parent, trigger, initial: DEFAULT_REQ, context: 'configure-defaults' }); + await new Promise((r) => setTimeout(r, 50)); + expect(document.querySelector('#gen-save-default')).not.toBeNull(); + expect(document.querySelector('#gen-use')).toBeNull(); + expect(document.querySelector('#gen-cancel')).toBeNull(); + }); }); diff --git a/extension/src/popup/components/generator-panel.ts b/extension/src/popup/components/generator-panel.ts index 51f716e..afcb1d4 100644 --- a/extension/src/popup/components/generator-panel.ts +++ b/extension/src/popup/components/generator-panel.ts @@ -106,7 +106,10 @@ export function openGeneratorPanel(opts: OpenPanelOpts): void { opts.trigger.setAttribute('aria-expanded', 'true'); const escHandler = (e: KeyboardEvent): void => { - if (e.key === 'Escape') closeGeneratorPanel(); + if (e.key === 'Escape') { + e.stopPropagation(); + closeGeneratorPanel(); + } }; document.addEventListener('keydown', escHandler); diff --git a/extension/src/popup/components/settings-vault.ts b/extension/src/popup/components/settings-vault.ts index e819567..e1ee961 100644 --- a/extension/src/popup/components/settings-vault.ts +++ b/extension/src/popup/components/settings-vault.ts @@ -12,6 +12,7 @@ let pendingSettings: VaultSettings | null = null; let activeKeyHandler: ((e: KeyboardEvent) => void) | null = null; export function teardown(): void { + closeGeneratorPanel(); if (activeKeyHandler) { document.removeEventListener('keydown', activeKeyHandler); activeKeyHandler = null;