From cf7ca9b2f7f13fabd87e2ff41264d12ddd4f85ff Mon Sep 17 00:00:00 2001 From: Chris Yang <18487241+ysm-dev@users.noreply.github.com> Date: Thu, 12 Mar 2026 03:40:06 +0900 Subject: [PATCH] fix(app): skip editor reconcile during IME composition (#17041) --- packages/app/src/components/prompt-input.tsx | 49 +++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 532edd3bc..3ee8f4351 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -490,6 +490,18 @@ export const PromptInput: Component = (props) => { setComposing(false) } + const handleCompositionStart = () => { + setComposing(true) + } + + const handleCompositionEnd = () => { + setComposing(false) + requestAnimationFrame(() => { + if (composing()) return + reconcile(prompt.current().filter((part) => part.type !== "image")) + }) + } + const agentList = createMemo(() => sync.data.agent .filter((agent) => !agent.hidden && agent.mode !== "primary") @@ -680,24 +692,27 @@ export const PromptInput: Component = (props) => { } } + const reconcile = (input: Prompt) => { + if (mirror.input) { + mirror.input = false + if (isNormalizedEditor()) return + + renderEditorWithCursor(input) + return + } + + const dom = parseFromDOM() + if (isNormalizedEditor() && isPromptEqual(input, dom)) return + + renderEditorWithCursor(input) + } + createEffect( on( () => prompt.current(), - (currentParts) => { - const inputParts = currentParts.filter((part) => part.type !== "image") - - if (mirror.input) { - mirror.input = false - if (isNormalizedEditor()) return - - renderEditorWithCursor(inputParts) - return - } - - const domParts = parseFromDOM() - if (isNormalizedEditor() && isPromptEqual(inputParts, domParts)) return - - renderEditorWithCursor(inputParts) + (parts) => { + if (composing()) return + reconcile(parts.filter((part) => part.type !== "image")) }, ), ) @@ -1208,8 +1223,8 @@ export const PromptInput: Component = (props) => { spellcheck={store.mode === "normal"} onInput={handleInput} onPaste={handlePaste} - onCompositionStart={() => setComposing(true)} - onCompositionEnd={() => setComposing(false)} + onCompositionStart={handleCompositionStart} + onCompositionEnd={handleCompositionEnd} onBlur={handleBlur} onKeyDown={handleKeyDown} classList={{