Skip to content

Commit af33344

Browse files
committed
fix(MessageBar): Fix IME language handling
Languages that rely on IME keyboards may use the enter key for final text selection on Mac. The MessageBar also uses enter key for submit. The result was that IME input, such as Japanese, was prematurely submitted. I added an additional check for whether the onCompositionEnd event is complete and also added some additional handling for Safari, which is a little bit of a special case. This should resolve the issue on Mac. I manually checked Edge, Chrome, Safari, and Firefox on my machine with a Japanese keyboard. Assisted-by: Cursor (used to generate boilerplate for handleCompositionStart/End, etc.)
1 parent 333d7d7 commit af33344

File tree

1 file changed

+23
-3
lines changed

1 file changed

+23
-3
lines changed

packages/module/src/MessageBar/MessageBar.tsx

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
141141
const [message, setMessage] = useState<string | number>(value ?? '');
142142
const [isListeningMessage, setIsListeningMessage] = useState<boolean>(false);
143143
const [hasSentMessage, setHasSentMessage] = useState(false);
144+
const [isComposing, setIsComposing] = useState(false);
144145
const inputRef = useRef<HTMLTextAreaElement>(null);
145146
const textareaRef = (innerRef as React.RefObject<HTMLTextAreaElement>) ?? inputRef;
146147
const attachButtonRef = useRef<HTMLButtonElement>(null);
@@ -285,21 +286,38 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
285286

286287
const handleKeyDown = useCallback(
287288
(event: ReactKeyboardEvent) => {
288-
if (event.key === 'Enter' && !event.shiftKey) {
289+
// Japanese and other languages may use IME for character input.
290+
// In these cases, enter is used to select the final input, so we need to check for composition end instead.
291+
// See more info at https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/
292+
// Chrome, Edge, and Firefox seem to work well with just the compose event.
293+
// Safari is a little bit special. We need to handle 229 as well in this case.
294+
const nativeEvent = event.nativeEvent as KeyboardEvent;
295+
const isCompositionKey = nativeEvent.which === 229;
296+
const isCurrentlyComposing = isComposing || isCompositionKey;
297+
298+
if (event.key === 'Enter' && !isCurrentlyComposing && !event.shiftKey) {
289299
event.preventDefault();
290300
if (!isSendButtonDisabled && !hasStopButton) {
291301
handleSend(message);
292302
}
293303
}
294-
if (event.key === 'Enter' && event.shiftKey) {
304+
if (event.key === 'Enter' && !isCurrentlyComposing && event.shiftKey) {
295305
if (textareaRef.current) {
296306
handleNewLine(textareaRef.current);
297307
}
298308
}
299309
},
300-
[isSendButtonDisabled, hasStopButton, handleSend, message]
310+
[isSendButtonDisabled, hasStopButton, handleSend, message, isComposing]
301311
);
302312

313+
const handleCompositionStart = useCallback(() => {
314+
setIsComposing(true);
315+
}, []);
316+
317+
const handleCompositionEnd = useCallback(() => {
318+
setIsComposing(false);
319+
}, []);
320+
303321
const handleAttachMenuToggle = () => {
304322
attachMenuProps?.setIsAttachMenuOpen && attachMenuProps?.setIsAttachMenuOpen(!attachMenuProps?.isAttachMenuOpen);
305323
attachMenuProps?.onAttachMenuToggleClick();
@@ -402,6 +420,8 @@ export const MessageBarBase: FunctionComponent<MessageBarProps> = ({
402420
placeholder={isListeningMessage ? listeningText : placeholder}
403421
ref={textareaRef}
404422
onKeyDown={handleKeyDown}
423+
onCompositionStart={handleCompositionStart}
424+
onCompositionEnd={handleCompositionEnd}
405425
{...props}
406426
/>
407427
</div>

0 commit comments

Comments
 (0)