From a6a78ff08a31129a3a47fa55aca260d93af913a5 Mon Sep 17 00:00:00 2001 From: Brooklyn Nicholson Date: Thu, 21 May 2026 18:05:43 -0500 Subject: [PATCH] perf(desktop): use textContent for trigger precondition Replace composerPlainText() call inside refreshTrigger's no-trigger fast-bail with a textContent check. textContent is a browser-native flat traversal; composerPlainText walks recursively with chip-aware logic. We only need to know if @ or / appears; either way the trigger char will be in textContent because chips contain @ in their refText. Profile shows composerPlainText was ~18ms self over a 12s typing-during- stream window, called from refreshTrigger on every keystroke. Most of that was the precondition check (the trigger detection path is the slow path but only runs when a trigger char is present). --- apps/desktop/src/app/chat/composer/index.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/desktop/src/app/chat/composer/index.tsx b/apps/desktop/src/app/chat/composer/index.tsx index 3c58c41848f..10887fbb8d6 100644 --- a/apps/desktop/src/app/chat/composer/index.tsx +++ b/apps/desktop/src/app/chat/composer/index.tsx @@ -408,13 +408,13 @@ export function ChatBar({ } // Fast-bail: if neither `@` nor `/` appears in the current draft, there's - // nothing for `detectTrigger` to match. Skip the DOM range walk inside - // `textBeforeCaret` (which calls `range.toString()`, O(n) over the draft) - // and the regex pass that follows. Only when a relevant char is present - // do we pay the cost. - const text = composerPlainText(editor) + // nothing for `detectTrigger` to match. Use `textContent` (cheap browser- + // native walk) for the precondition check rather than `composerPlainText` + // (recursive child walk with chip-aware logic). Only when a trigger char + // is present do we pay the cost of the full walk + DOM range work. + const rawText = editor.textContent ?? '' - if (!text.includes('@') && !text.includes('/')) { + if (!rawText.includes('@') && !rawText.includes('/')) { if (trigger) { setTrigger(null) setTriggerActive(0) @@ -424,7 +424,7 @@ export function ChatBar({ } const before = textBeforeCaret(editor) - const detected = detectTrigger(before ?? text) + const detected = detectTrigger(before ?? composerPlainText(editor)) setTrigger(detected) setTriggerActive(0)