diff --git a/packages/module/src/MessageBar/MessageBar.tsx b/packages/module/src/MessageBar/MessageBar.tsx index b6a53c6ec..c79c3c70d 100644 --- a/packages/module/src/MessageBar/MessageBar.tsx +++ b/packages/module/src/MessageBar/MessageBar.tsx @@ -141,6 +141,7 @@ export const MessageBarBase: FunctionComponent = ({ const [message, setMessage] = useState(value ?? ''); const [isListeningMessage, setIsListeningMessage] = useState(false); const [hasSentMessage, setHasSentMessage] = useState(false); + const [isComposing, setIsComposing] = useState(false); const inputRef = useRef(null); const textareaRef = (innerRef as React.RefObject) ?? inputRef; const attachButtonRef = useRef(null); @@ -285,21 +286,38 @@ export const MessageBarBase: FunctionComponent = ({ const handleKeyDown = useCallback( (event: ReactKeyboardEvent) => { - if (event.key === 'Enter' && !event.shiftKey) { + // Japanese and other languages may use IME for character input. + // In these cases, enter is used to select the final input, so we need to check for composition end instead. + // See more info at https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/ + // Chrome, Edge, and Firefox seem to work well with just the compose event. + // Safari is a little bit special. We need to handle 229 as well in this case. + const nativeEvent = event.nativeEvent as KeyboardEvent; + const isCompositionKey = nativeEvent.which === 229; + const isCurrentlyComposing = isComposing || isCompositionKey; + + if (event.key === 'Enter' && !isCurrentlyComposing && !event.shiftKey) { event.preventDefault(); if (!isSendButtonDisabled && !hasStopButton) { handleSend(message); } } - if (event.key === 'Enter' && event.shiftKey) { + if (event.key === 'Enter' && !isCurrentlyComposing && event.shiftKey) { if (textareaRef.current) { handleNewLine(textareaRef.current); } } }, - [isSendButtonDisabled, hasStopButton, handleSend, message] + [isSendButtonDisabled, hasStopButton, handleSend, message, isComposing] ); + const handleCompositionStart = useCallback(() => { + setIsComposing(true); + }, []); + + const handleCompositionEnd = useCallback(() => { + setIsComposing(false); + }, []); + const handleAttachMenuToggle = () => { attachMenuProps?.setIsAttachMenuOpen && attachMenuProps?.setIsAttachMenuOpen(!attachMenuProps?.isAttachMenuOpen); attachMenuProps?.onAttachMenuToggleClick(); @@ -402,6 +420,8 @@ export const MessageBarBase: FunctionComponent = ({ placeholder={isListeningMessage ? listeningText : placeholder} ref={textareaRef} onKeyDown={handleKeyDown} + onCompositionStart={handleCompositionStart} + onCompositionEnd={handleCompositionEnd} {...props} />