mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-11 08:42:11 +00:00
fix(desktop): flush committed IME text on compositionend so the send button appears
Typing committed multi-character IME text (e.g. Chinese "你好", and equally Japanese/Korean or any IME-composed script) left the send button hidden until an unrelated edit. Input events during composition carry uncommitted preedit text and are intentionally skipped; the code assumed a trailing input event after compositionend would deliver the finalized text, but Chromium does not reliably emit one on Windows IMEs. The committed text therefore never reached composer state, so `hasComposerPayload` stayed false and the send button stayed hidden (deleting a char fired a non-composition input that finally synced it). Flush the live editor text into composer state in onCompositionEnd. Extract the shared sync into flushEditorToDraft so input and compositionend both update state. Fixes #39614
This commit is contained in:
parent
be2c64be02
commit
8e629b9f38
1 changed files with 25 additions and 11 deletions
|
|
@ -549,16 +549,10 @@ export function ChatBar({
|
|||
}
|
||||
}, [trigger])
|
||||
|
||||
const handleEditorInput = (event: FormEvent<HTMLDivElement>) => {
|
||||
// During IME composition the DOM contains uncommitted preedit text
|
||||
// mixed with real content. Skip state writes — compositionend will
|
||||
// deliver the finalized text via a clean input event.
|
||||
if (composingRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
const editor = event.currentTarget
|
||||
|
||||
// Pull the live contentEditable text into draftRef + the AUI composer state
|
||||
// (which drives `hasComposerPayload` → the send button). Shared by the input
|
||||
// and compositionend paths so committed IME text reaches state through either.
|
||||
const flushEditorToDraft = (editor: HTMLDivElement) => {
|
||||
if (editor.childNodes.length === 1 && editor.firstChild?.nodeName === 'BR') {
|
||||
editor.replaceChildren()
|
||||
}
|
||||
|
|
@ -573,6 +567,17 @@ export function ChatBar({
|
|||
window.setTimeout(refreshTrigger, 0)
|
||||
}
|
||||
|
||||
const handleEditorInput = (event: FormEvent<HTMLDivElement>) => {
|
||||
// During IME composition the DOM contains uncommitted preedit text
|
||||
// mixed with real content. Skip state writes — compositionend flushes
|
||||
// the finalized text (see onCompositionEnd).
|
||||
if (composingRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
flushEditorToDraft(event.currentTarget)
|
||||
}
|
||||
|
||||
const triggerAdapter: Unstable_TriggerAdapter | null =
|
||||
trigger?.kind === '@' ? at.adapter : trigger?.kind === '/' ? slash.adapter : null
|
||||
|
||||
|
|
@ -1208,8 +1213,17 @@ export function ChatBar({
|
|||
data-placeholder={placeholder}
|
||||
data-slot={RICH_INPUT_SLOT}
|
||||
onBlur={() => window.setTimeout(closeTrigger, 80)}
|
||||
onCompositionEnd={() => {
|
||||
onCompositionEnd={event => {
|
||||
composingRef.current = false
|
||||
|
||||
// The input events fired *during* composition were skipped (they
|
||||
// carried uncommitted preedit text), and Chromium does NOT reliably
|
||||
// emit a trailing input event after compositionend on Windows IMEs.
|
||||
// Without flushing here, committed multi-character IME input (e.g.
|
||||
// Chinese "你好", Japanese, Korean) never reaches composer state, so
|
||||
// `hasComposerPayload` stays false and the send button stays hidden
|
||||
// until an unrelated edit forces a sync (#39614).
|
||||
flushEditorToDraft(event.currentTarget)
|
||||
}}
|
||||
onCompositionStart={() => {
|
||||
composingRef.current = true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue