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
1 file src/content/detect.ts+28 −0
src/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();

view file