0152b3f58edf
fix: split OTP input groups — export isSplitOtpGroup(field) from detect.ts (3+ maxlength=1 numeric inputs, numeric guard rejects 3-letter initials forms); activates T-DT18/20/21 skipIf spec. Export-only: every injectFieldIcon path already excludes maxLength===1 upstream, so a call-site guard would be unreachable (v3.9.9)
- time
- 2026-06-12 13:54 UTC · 4 months ago
- machine
- koh2
- agent
- claude-opus-4-8
- session
- autofill tests integration
- parent
- 649e78412625
↓ peach-browser-0152b3f5.tar.gzatlas at this save
files changed1 file
src/content/detect.ts+28 −0src/content/detect.ts+28 −0
@@ -295,6 +295,34 @@295295 return digitBoxes;296296 }297297 298+// Addendum 1: true when `field` belongs to a split single-character OTP group —299+// 3+ maxlength=1 inputs in the same form that each carry a numeric signal300+// (inputmode=numeric, type=tel, pattern=[0-9]*/\d*, or autocomplete=one-time-code).301+// Distinct from findOTPDigitBoxGroup, which gates on a 4–10 box count and accepts302+// any text/number/tel box: this drops the floor to 3 but adds the numeric guard,303+// so a 3-letter "initials" form is never mistaken for OTP entry.304+//305+// No icon-suppression guard is wired at the injection sites: every injectFieldIcon306+// path already filters maxLength===1 fields upstream (detectLoginFields skips them,307+// isTOTPField rejects them), so a split-OTP box never reaches icon injection. This308+// export is the numeric-guarded classifier the T-DT18–21 spec pins and a shared309+// seam for any future gate that needs it.310+export function isSplitOtpGroup(field: HTMLInputElement): boolean {311+ if (field.maxLength !== 1) return false;312+ const form = field.form;313+ if (!form) return false;314+ const siblings = Array.from(form.querySelectorAll<HTMLInputElement>("input")).filter(315+ (el) =>316+ el.maxLength === 1 &&317+ (el.inputMode === "numeric" ||318+ el.type === "tel" ||319+ el.pattern === "[0-9]*" ||320+ el.pattern === "\\d*" ||321+ el.autocomplete === "one-time-code")322+ );323+ return siblings.length >= 3 && siblings.includes(field);324+}325+298326 export function isVisible(el: HTMLElement): boolean {299327 const s = getComputedStyle(el);300328 const r = el.getBoundingClientRect();