@@ -230,6 +230,7 @@ const FloatingPromptInputInner = (
230230 const expandedTextareaRef = useRef < HTMLTextAreaElement > ( null ) ;
231231 const unlistenDragDropRef = useRef < ( ( ) => void ) | null > ( null ) ;
232232 const [ textareaHeight , setTextareaHeight ] = useState < number > ( 48 ) ;
233+ const isIMEComposingRef = useRef ( false ) ;
233234
234235 // Expose a method to add images programmatically
235236 React . useImperativeHandle (
@@ -432,23 +433,6 @@ const FloatingPromptInputInner = (
432433 }
433434 } , [ isExpanded ] ) ;
434435
435- const handleSend = ( ) => {
436- if ( prompt . trim ( ) && ! disabled ) {
437- let finalPrompt = prompt . trim ( ) ;
438-
439- // Append thinking phrase if not auto mode
440- const thinkingMode = THINKING_MODES . find ( m => m . id === selectedThinkingMode ) ;
441- if ( thinkingMode && thinkingMode . phrase ) {
442- finalPrompt = `${ finalPrompt } .\n\n${ thinkingMode . phrase } .` ;
443- }
444-
445- onSend ( finalPrompt , selectedModel ) ;
446- setPrompt ( "" ) ;
447- setEmbeddedImages ( [ ] ) ;
448- setTextareaHeight ( 48 ) ; // Reset height after sending
449- }
450- } ;
451-
452436 const handleTextChange = ( e : React . ChangeEvent < HTMLTextAreaElement > ) => {
453437 const newValue = e . target . value ;
454438 const newCursorPosition = e . target . selectionStart || 0 ;
@@ -657,6 +641,66 @@ const FloatingPromptInputInner = (
657641 } , 0 ) ;
658642 } ;
659643
644+ const handleCompositionStart = ( ) => {
645+ isIMEComposingRef . current = true ;
646+ } ;
647+
648+ const handleCompositionEnd = ( ) => {
649+ setTimeout ( ( ) => {
650+ isIMEComposingRef . current = false ;
651+ } , 0 ) ;
652+ } ;
653+
654+ const isIMEInteraction = ( event ?: React . KeyboardEvent ) => {
655+ if ( isIMEComposingRef . current ) {
656+ return true ;
657+ }
658+
659+ if ( ! event ) {
660+ return false ;
661+ }
662+
663+ const nativeEvent = event . nativeEvent ;
664+
665+ if ( nativeEvent . isComposing ) {
666+ return true ;
667+ }
668+
669+ const key = nativeEvent . key ;
670+ if ( key === 'Process' || key === 'Unidentified' ) {
671+ return true ;
672+ }
673+
674+ const keyboardEvent = nativeEvent as unknown as KeyboardEvent ;
675+ const keyCode = keyboardEvent . keyCode ?? ( keyboardEvent as unknown as { which ?: number } ) . which ;
676+ if ( keyCode === 229 ) {
677+ return true ;
678+ }
679+
680+ return false ;
681+ } ;
682+
683+ const handleSend = ( ) => {
684+ if ( isIMEInteraction ( ) ) {
685+ return ;
686+ }
687+
688+ if ( prompt . trim ( ) && ! disabled ) {
689+ let finalPrompt = prompt . trim ( ) ;
690+
691+ // Append thinking phrase if not auto mode
692+ const thinkingMode = THINKING_MODES . find ( m => m . id === selectedThinkingMode ) ;
693+ if ( thinkingMode && thinkingMode . phrase ) {
694+ finalPrompt = `${ finalPrompt } .\n\n${ thinkingMode . phrase } .` ;
695+ }
696+
697+ onSend ( finalPrompt , selectedModel ) ;
698+ setPrompt ( "" ) ;
699+ setEmbeddedImages ( [ ] ) ;
700+ setTextareaHeight ( 48 ) ; // Reset height after sending
701+ }
702+ } ;
703+
660704 const handleKeyDown = ( e : React . KeyboardEvent ) => {
661705 if ( showFilePicker && e . key === 'Escape' ) {
662706 e . preventDefault ( ) ;
@@ -679,7 +723,16 @@ const FloatingPromptInputInner = (
679723 return ;
680724 }
681725
682- if ( e . key === "Enter" && ! e . shiftKey && ! isExpanded && ! showFilePicker && ! showSlashCommandPicker ) {
726+ if (
727+ e . key === "Enter" &&
728+ ! e . shiftKey &&
729+ ! isExpanded &&
730+ ! showFilePicker &&
731+ ! showSlashCommandPicker
732+ ) {
733+ if ( isIMEInteraction ( e ) ) {
734+ return ;
735+ }
683736 e . preventDefault ( ) ;
684737 handleSend ( ) ;
685738 }
@@ -834,6 +887,8 @@ const FloatingPromptInputInner = (
834887 ref = { expandedTextareaRef }
835888 value = { prompt }
836889 onChange = { handleTextChange }
890+ onCompositionStart = { handleCompositionStart }
891+ onCompositionEnd = { handleCompositionEnd }
837892 onPaste = { handlePaste }
838893 placeholder = "Type your message..."
839894 className = "min-h-[200px] resize-none"
@@ -1157,15 +1212,21 @@ const FloatingPromptInputInner = (
11571212 value = { prompt }
11581213 onChange = { handleTextChange }
11591214 onKeyDown = { handleKeyDown }
1215+ onCompositionStart = { handleCompositionStart }
1216+ onCompositionEnd = { handleCompositionEnd }
11601217 onPaste = { handlePaste }
1161- placeholder = { dragActive ? "Drop images here..." : "Message Claude (@ for files, / for commands)..." }
1218+ placeholder = {
1219+ dragActive
1220+ ? "Drop images here..."
1221+ : "Message Claude (@ for files, / for commands)..."
1222+ }
11621223 disabled = { disabled }
11631224 className = { cn (
11641225 "resize-none pr-20 pl-3 py-2.5 transition-all duration-150" ,
11651226 dragActive && "border-primary" ,
11661227 textareaHeight >= 240 && "overflow-y-auto scrollbar-thin"
11671228 ) }
1168- style = { {
1229+ style = { {
11691230 height : `${ textareaHeight } px` ,
11701231 overflowY : textareaHeight >= 240 ? 'auto' : 'hidden'
11711232 } }
0 commit comments