0295c6a8be14
suppress autofill popup reopen on recently filled fields for 5s — fixes popup re-summoning when login button click refocuses an input (v2.0.3)
- time
- 2026-04-26 12:39 UTC · 6 months ago
- machine
- koh2
- parent
- 332398c99b82
↓ peach-browser-0295c6a8.tar.gzatlas at this save
files changed4 files
manifest.firefox.json+1 −1manifest.json+1 −1package.json+1 −1src/content/index.ts+27 −1manifest.firefox.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.0.2",4+ "version": "2.0.3",55 "description": "Zero-knowledge password manager",66 "browser_specific_settings": {77 "gecko": {manifest.json+1 −1
@@ -1,7 +1,7 @@11 {22 "manifest_version": 3,33 "name": "Peach",4- "version": "2.0.2",4+ "version": "2.0.3",55 "description": "Zero-knowledge password manager",66 "action": {77 "default_popup": "src/popup/index.html",package.json+1 −1
@@ -1,6 +1,6 @@11 {22 "name": "peach",3- "version": "2.0.2",3+ "version": "2.0.3",44 "description": "Zero-knowledge password manager",55 "type": "module",66 "scripts": {src/content/index.ts+27 −1
@@ -37,6 +37,21 @@3737 // Suppresses spurious reopens until focus moves to a different field.3838 let lastDismissedField: HTMLInputElement | null = null;3939 40+// Fields that were just autofilled — suppress popup reopens on them briefly.41+// Some sites refocus an input on form submit (validation flows, animation42+// blur/focus, framework handlers), which would otherwise re-trigger the43+// selector right as the user clicks the login button. Cleared by explicit44+// user-summon (icon click, keyboard shortcut) or after AUTOFILL_SUPPRESS_MS.45+const recentlyAutofilledFields = new WeakSet<HTMLInputElement>();46+const AUTOFILL_SUPPRESS_MS = 5000;47+function markAutofilled(...fields: (HTMLInputElement | null | undefined)[]): void {48+ for (const f of fields) {49+ if (!f) continue;50+ recentlyAutofilledFields.add(f);51+ setTimeout(() => recentlyAutofilledFields.delete(f), AUTOFILL_SUPPRESS_MS);52+ }53+}54+4055 function debounce<T extends (...args: unknown[]) => void>(4156 fn: T,4257 ms: number@@ -346,6 +361,7 @@346361 const entry = (entryResponse as { ok: boolean; data?: VaultEntry }).data;347362 if (entry) {348363 await handleAutofill(anchorField, usernameEl, passwordEl, entry);364+ markAutofilled(anchorField, usernameEl, passwordEl);349365 // Offer to remember the current site for this entry only if none of350366 // its known domains (primary + additional) match — otherwise the351367 // user already mapped it and the prompt would be noise.@@ -410,6 +426,11 @@410426 // focus has genuinely moved away and come back.411427 if (field === lastDismissedField) return;412428 429+ // Field was just autofilled — sites often refocus an input on submit click,430+ // which would otherwise re-trigger the selector right when the user is431+ // trying to log in. Bail unless the user explicitly summoned us.432+ if (recentlyAutofilledFields.has(field)) return;433+413434 // Prevent two concurrent calls for the same field (e.g. focusin + icon click414435 // firing simultaneously — the second call would dismiss the first's selector).415436 if (pendingInteractions.has(field)) return;@@ -506,6 +527,7 @@506527 currentDismiss?.();507528 currentDismiss = null;508529 lastDismissedField = null; // icon click is always an explicit user open — clear the dismiss lock530+ recentlyAutofilledFields.delete(el); // explicit summon also clears autofill suppression509531 el.focus({ preventScroll: true });510532 void handleFieldInteraction(el);511533 });@@ -561,6 +583,7 @@561583 currentDismiss?.();562584 currentDismiss = null;563585 lastDismissedField = null;586+ recentlyAutofilledFields.delete(el);564587 el.focus({ preventScroll: true });565588 void handleFieldInteraction(el);566589 });@@ -620,7 +643,10 @@620643 ? activeInput621644 : (fields.find(f => f.type === "password")?.el622645 ?? fields.find(f => f.type === "username" || f.type === "email")?.el);623- if (target) void handleFieldInteraction(target);646+ if (target) {647+ recentlyAutofilledFields.delete(target); // explicit summon clears suppression648+ void handleFieldInteraction(target);649+ }624650 } else if (isShortcut) {625651 // Shortcut on a page with no login form — show clipboard-copy search mode.626652 showSearchPalette();