fix: prevent Enter from sending message during IME composition#63
fix: prevent Enter from sending message during IME composition#63zzzhizhia wants to merge 2 commits intoSamuelZ12:mainfrom
Conversation
When using a Chinese IME to type English, pressing Enter to confirm the composition was incorrectly sending the chat message. This happened because some browsers fire compositionend before keydown, resetting the isComposing ref before the keydown handler could check it. - Add e.nativeEvent.isComposing check as a secondary guard - Delay resetting isComposingRef in onCompositionEnd via setTimeout(0) so the keydown handler for the same keystroke still sees it as true - Apply the same IME guard to note-editor and transcript-viewer
|
@zzzhizhia is attempting to deploy a commit to the samuelz12's projects Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Pull request overview
Prevents Enter from triggering “send” / “next” behaviors while the user is confirming IME (e.g., Chinese Pinyin) composition, addressing Chrome’s compositionend → keydown ordering edge case.
Changes:
- Add
e.nativeEvent.isComposingguards to Enter key handlers across chat, note editor, and transcript search. - In chat input, delay resetting
isComposingRefoncompositionendto ensure the subsequent Enterkeydownis still treated as composing.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| components/ai-chat.tsx | Adds nativeEvent.isComposing guard and delays isComposingRef reset after composition ends. |
| components/note-editor.tsx | Prevents Cmd/Ctrl+Enter save from firing during IME composition. |
| components/transcript-viewer.tsx | Prevents Enter-based search navigation from firing during IME composition. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| onCompositionEnd={() => { | ||
| isComposingRef.current = false; | ||
| // Delay resetting the flag so the keydown handler for the | ||
| // same Enter keystroke still sees isComposing as true. | ||
| // In some browsers (e.g. Chrome with Chinese IME), | ||
| // compositionend fires before keydown for the Enter key | ||
| // that confirms the composition. | ||
| setTimeout(() => { | ||
| isComposingRef.current = false; | ||
| }, 0); |
There was a problem hiding this comment.
onCompositionEnd schedules a setTimeout(0) that unconditionally sets isComposingRef.current = false. If a new composition starts before the timeout fires (e.g., user immediately continues composing), the pending timeout can incorrectly flip the flag to false while composition is active. Consider storing the timeout id (or a monotonically increasing composition sequence) in a ref and cancelling/invalidating it in onCompositionStart (and on unmount) before scheduling a new reset.
Summary
e.nativeEvent.isComposingas secondary guard alongside the existingisComposingRefisComposingRefreset inonCompositionEndviasetTimeout(0)to handle browsers wherecompositionendfires beforekeydownRoot cause
In Chrome with Chinese IME, when typing English letters and pressing Enter to confirm, the event order can be
compositionend→keydown. The existingonCompositionEndhandler immediately setisComposingRef.current = false, so by the timekeydownfired, the ref was already reset and the message was sent.Changes
components/ai-chat.tsx: AddisComposingcheck + delay ref resetcomponents/note-editor.tsx: AddisComposingguardcomponents/transcript-viewer.tsx: AddisComposingguardTest plan