From a2682de4214cd277089fbf4a4c848d57a967f76d Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 5 Mar 2026 10:43:11 -0800 Subject: [PATCH] Use mention adjacency helper in composer onChange - replace Lexical-node cursor adjacency check with text/cursor helper - prevent `@query` typing from being treated as mention-pill adjacent - add regression test for non-pill `@pac` input --- .../src/components/ComposerPromptEditor.tsx | 28 +++---------------- apps/web/src/composer-logic.test.ts | 6 ++++ 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/apps/web/src/components/ComposerPromptEditor.tsx b/apps/web/src/components/ComposerPromptEditor.tsx index 6795d0535cb1784670a24589c71a878d8f86cea4..2c089dab011e9a4ae78278363bc6f2aada7bbfc4 100644 --- a/apps/web/src/components/ComposerPromptEditor.tsx +++ b/apps/web/src/components/ComposerPromptEditor.tsx @@ -558,29 +558,6 @@ function ComposerMentionSelectionNormalizePlugin() { return null; } -function $isCursorAdjacentToMention(): boolean { - const selection = $getSelection(); - if (!$isRangeSelection(selection) || !selection.isCollapsed()) return false; - const anchorNode = selection.anchor.getNode(); - - if (anchorNode instanceof ComposerMentionNode) return true; - - if ($isElementNode(anchorNode)) { - const childIndex = selection.anchor.offset - 1; - if (childIndex >= 0) { - const child = anchorNode.getChildAtIndex(childIndex); - if (child instanceof ComposerMentionNode) return true; - } - } - - if ($isTextNode(anchorNode) && selection.anchor.offset === 0) { - const prev = anchorNode.getPreviousSibling(); - if (prev instanceof ComposerMentionNode) return true; - } - - return false; -} - function ComposerMentionBackspacePlugin() { const [editor] = useLexicalComposerContext(); @@ -756,7 +733,10 @@ function ComposerPromptEditorInner({ value: nextValue, cursor: nextCursor, }; - onChangeRef.current(nextValue, nextCursor, $isCursorAdjacentToMention()); + const cursorAdjacentToMention = + isCollapsedCursorAdjacentToMention(nextValue, nextCursor, "left") || + isCollapsedCursorAdjacentToMention(nextValue, nextCursor, "right"); + onChangeRef.current(nextValue, nextCursor, cursorAdjacentToMention); }); }, []); diff --git a/apps/web/src/composer-logic.test.ts b/apps/web/src/composer-logic.test.ts index 57e044186b464fd8df4e12047c8bda53a493e103..b9990d7fdfd3b8fd977ab761bbb39604e6ca29d1 100644 --- a/apps/web/src/composer-logic.test.ts +++ b/apps/web/src/composer-logic.test.ts @@ -85,6 +85,12 @@ describe("isCollapsedCursorAdjacentToMention", () => { expect(isCollapsedCursorAdjacentToMention("plain text", 6, "right")).toBe(false); }); + it("keeps @query typing non-adjacent while no mention pill exists", () => { + const text = "hello @pac"; + expect(isCollapsedCursorAdjacentToMention(text, text.length, "left")).toBe(false); + expect(isCollapsedCursorAdjacentToMention(text, text.length, "right")).toBe(false); + }); + it("detects left adjacency only when cursor is directly after a mention", () => { const text = "open @AGENTS.md next"; const mentionStart = "open ".length; -- 2.54.0