summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorChris Yang <[email protected]>2026-03-12 03:40:06 +0900
committerGitHub <[email protected]>2026-03-11 13:40:06 -0500
commitcf7ca9b2f7f13fabd87e2ff41264d12ddd4f85ff (patch)
tree48c4d82c31d08a676df67466631ef841621afe04 /packages
parent981c7b9e375b7d9ac57d2d6a3179451139b2b99b (diff)
downloadopencode-cf7ca9b2f7f13fabd87e2ff41264d12ddd4f85ff.tar.gz
opencode-cf7ca9b2f7f13fabd87e2ff41264d12ddd4f85ff.zip
fix(app): skip editor reconcile during IME composition (#17041)
Diffstat (limited to 'packages')
-rw-r--r--packages/app/src/components/prompt-input.tsx47
1 files changed, 31 insertions, 16 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<PromptInputProps> = (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<PromptInputProps> = (props) => {
}
}
- createEffect(
- on(
- () => prompt.current(),
- (currentParts) => {
- const inputParts = currentParts.filter((part) => part.type !== "image")
+ const reconcile = (input: Prompt) => {
+ if (mirror.input) {
+ mirror.input = false
+ if (isNormalizedEditor()) return
- if (mirror.input) {
- mirror.input = false
- if (isNormalizedEditor()) return
+ renderEditorWithCursor(input)
+ return
+ }
- renderEditorWithCursor(inputParts)
- return
- }
+ const dom = parseFromDOM()
+ if (isNormalizedEditor() && isPromptEqual(input, dom)) return
- const domParts = parseFromDOM()
- if (isNormalizedEditor() && isPromptEqual(inputParts, domParts)) return
+ renderEditorWithCursor(input)
+ }
- renderEditorWithCursor(inputParts)
+ createEffect(
+ on(
+ () => prompt.current(),
+ (parts) => {
+ if (composing()) return
+ reconcile(parts.filter((part) => part.type !== "image"))
},
),
)
@@ -1208,8 +1223,8 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
spellcheck={store.mode === "normal"}
onInput={handleInput}
onPaste={handlePaste}
- onCompositionStart={() => setComposing(true)}
- onCompositionEnd={() => setComposing(false)}
+ onCompositionStart={handleCompositionStart}
+ onCompositionEnd={handleCompositionEnd}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
classList={{