fix(front): ignore IME composition Enter in input hotkeys (#20958)

## What

Pressing Enter to confirm an IME (CJK) composition no longer submits the
input. The Enter / Escape / Tab handlers now ignore key events fired
while a composition is in progress (`isComposing`, or the legacy
`keyCode === 229`).

Fixes #20954

## Why

`isComposing` was not checked anywhere in `twenty-front`, so the Enter
that confirms a Japanese / Chinese / Korean conversion was also consumed
as a submit / escape / tab hotkey — making it very hard to type CJK text
into any input that submits on Enter.

## Changes

- `useHotkeysOnFocusedElement` — central guard; covers every input wired
through `useRegisterInputEvents` (~13 components) and all hotkeys routed
through this hook.
- Direct `onKeyDown` Enter handlers: `CreateWorkspace`,
`SettingsDevelopersApiKeysNew`, `SettingsAccountsBlocklistInput`.

## Notes

- No effect on non-IME (Latin) typing — `isComposing` is only true
during an active composition. It also improves accented / dead-key input
on Latin layouts.
- `react-hotkeys-hook@4` does not handle IME composition on its own, so
the guard is explicit.

## Testing

Manually verified with a Japanese IME on Chrome (macOS) against the
v2.8.3 self-hosted image: romaji + Enter now only confirms the
conversion; a second Enter on committed text submits as expected. The
GIF in #20954 shows the original buggy behavior.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
fujiwara
2026-05-27 23:09:10 +09:00
committed by GitHub
parent e79f43813b
commit 951ead5a1e
4 changed files with 13 additions and 0 deletions
@@ -74,6 +74,9 @@ export const SettingsAccountsBlocklistInput = ({
});
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.nativeEvent.isComposing || e.keyCode === 229) {
return;
}
if (e.key === Key.Enter) {
submit();
}
@@ -48,6 +48,10 @@ export const useHotkeysOnFocusedElement = ({
return useHotkeys(
keys,
(keyboardEvent, hotkeysEvent) => {
if (keyboardEvent.isComposing || keyboardEvent.keyCode === 229) {
return;
}
callScopedHotkeyCallback({
keyboardEvent,
hotkeysEvent,
@@ -141,6 +141,9 @@ export const CreateWorkspace = () => {
);
const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
if (event.nativeEvent.isComposing || event.keyCode === 229) {
return;
}
if (event.key === Key.Enter) {
event.preventDefault();
handleSubmit(onSubmit)();
@@ -159,6 +159,9 @@ export const SettingsDevelopersApiKeysNew = () => {
placeholder={t`E.g. backoffice integration`}
value={formValues.name}
onKeyDown={(e) => {
if (e.nativeEvent.isComposing || e.keyCode === 229) {
return;
}
if (e.key === Key.Enter) {
handleSave();
}