From 8f6e398d6df7aa53b35fc422ec1acaab36a5bdd3 Mon Sep 17 00:00:00 2001 From: Wes Date: Fri, 17 Jul 2026 09:51:57 -0600 Subject: [PATCH] fix(desktop): close mention popup after an exact name + trailing space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since #1918 added multi-word team-name matching, typing "@Pinky " kept the mention query open because "pinky " is still a prefix of a team name like "Pinky and the Brain" — leaving the team as the only suggestion, so Enter/Tab stole the completed mention and expanded the team instead. Treat an exact known name followed by a space as a completed mention and close the query; typing further toward the longer name re-opens it. Co-authored-by: Brain <21994759fc7a6fa6b965551d35cfd7897d262f2495467f2d78694ddcfa6a5c7e@sprout-oss.stage.blox.sqprod.co> Signed-off-by: Wes --- .../src/shared/lib/detectPrefixQuery.test.mjs | 24 +++++++++++++++++++ desktop/src/shared/lib/detectPrefixQuery.ts | 9 +++++++ 2 files changed, 33 insertions(+) diff --git a/desktop/src/shared/lib/detectPrefixQuery.test.mjs b/desktop/src/shared/lib/detectPrefixQuery.test.mjs index d0ed9c4d383..4eae61f49d6 100644 --- a/desktop/src/shared/lib/detectPrefixQuery.test.mjs +++ b/desktop/src/shared/lib/detectPrefixQuery.test.mjs @@ -96,6 +96,30 @@ test("multi-word: glued-to-word prefix still rejected", () => { assert.equal(at("#", "x#buzz de", CHANNELS), null); }); +// ── Completed mention: exact name + trailing space closes the query ─────────── + +test("exact name followed by space does not stay open for a longer name", () => { + // "pinky" is complete; "pinky and the brain" sharing the prefix must not + // keep the popup open and steal Enter/Tab. + const names = ["pinky", "brain", "pinky and the brain"]; + assert.equal(at("@", "@pinky ", names), null); +}); + +test("typing past the space toward the longer name re-opens the query", () => { + const names = ["pinky", "brain", "pinky and the brain"]; + assert.deepEqual(at("@", "@pinky a", names), { + query: "pinky a", + startIndex: 0, + }); +}); + +test("multi-word name still completes word by word when no shorter exact match", () => { + assert.deepEqual(at("@", "@bob ", PEOPLE), { + query: "bob ", + startIndex: 0, + }); +}); + // ── Empty / no-match guards unchanged ───────────────────────────────────────── test("bare prefix after ( yields empty single-word query, not multi-word", () => { diff --git a/desktop/src/shared/lib/detectPrefixQuery.ts b/desktop/src/shared/lib/detectPrefixQuery.ts index e2ad768ebe6..4d227ba08b3 100644 --- a/desktop/src/shared/lib/detectPrefixQuery.ts +++ b/desktop/src/shared/lib/detectPrefixQuery.ts @@ -54,6 +54,15 @@ export function detectPrefixQuery( break; } const lowerCandidate = candidate.toLowerCase(); + // A trailing space after an exact known name means the mention is + // complete — don't keep the query open just because a longer name + // (e.g. a team) shares the prefix. + if ( + lowerCandidate.endsWith(" ") && + knownNamesLower.includes(lowerCandidate.trimEnd()) + ) { + break; + } const isPrefix = knownNamesLower.some((name) => name.startsWith(lowerCandidate), );