From 951ead5a1e011ad39f097eaadb9920393d99ef08 Mon Sep 17 00:00:00 2001 From: fujiwara <67113514+fyujiwara@users.noreply.github.com> Date: Wed, 27 May 2026 23:09:10 +0900 Subject: [PATCH] fix(front): ignore IME composition Enter in input hotkeys (#20958) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 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 --- .../accounts/components/SettingsAccountsBlocklistInput.tsx | 3 +++ .../ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement.ts | 4 ++++ .../twenty-front/src/pages/onboarding/CreateWorkspace.tsx | 3 +++ .../developers/api-keys/SettingsDevelopersApiKeysNew.tsx | 3 +++ 4 files changed, 13 insertions(+) diff --git a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistInput.tsx b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistInput.tsx index c30dd5cd10..4854f74201 100644 --- a/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistInput.tsx +++ b/packages/twenty-front/src/modules/settings/accounts/components/SettingsAccountsBlocklistInput.tsx @@ -74,6 +74,9 @@ export const SettingsAccountsBlocklistInput = ({ }); const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.nativeEvent.isComposing || e.keyCode === 229) { + return; + } if (e.key === Key.Enter) { submit(); } diff --git a/packages/twenty-front/src/modules/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement.ts b/packages/twenty-front/src/modules/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement.ts index f3b3dc8a86..5b9a110271 100644 --- a/packages/twenty-front/src/modules/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement.ts +++ b/packages/twenty-front/src/modules/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement.ts @@ -48,6 +48,10 @@ export const useHotkeysOnFocusedElement = ({ return useHotkeys( keys, (keyboardEvent, hotkeysEvent) => { + if (keyboardEvent.isComposing || keyboardEvent.keyCode === 229) { + return; + } + callScopedHotkeyCallback({ keyboardEvent, hotkeysEvent, diff --git a/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx b/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx index 974899479f..324832c08b 100644 --- a/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx +++ b/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx @@ -141,6 +141,9 @@ export const CreateWorkspace = () => { ); const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.nativeEvent.isComposing || event.keyCode === 229) { + return; + } if (event.key === Key.Enter) { event.preventDefault(); handleSubmit(onSubmit)(); diff --git a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx index 3b137cf9c0..3be8dbead4 100644 --- a/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx +++ b/packages/twenty-front/src/pages/settings/developers/api-keys/SettingsDevelopersApiKeysNew.tsx @@ -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(); }