From f02a6161e4dddefb103aa05f84a98665d731d0ff Mon Sep 17 00:00:00 2001 From: cliffhall Date: Wed, 26 Aug 2026 08:46:26 -0400 Subject: [PATCH] fix(web): don't enlarge on the Enter that commits an IME composition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enter is also how a Japanese, Chinese or Korean input method commits the candidate being composed. That keystroke means "accept this word", not "new line", so the shortcut fired on every word such a user finished — enlarging the field and inserting a stray newline each time. Guard on event.nativeEvent.isComposing. The test pairs the composing case with a negative control dispatching the same event with the flag off, so a test that stopped reaching the handler cannot pass for the wrong reason. Signed-off-by: cliffhall --- .../groups/SchemaForm/SchemaForm.test.tsx | 23 +++++++++++++++++++ .../groups/SchemaForm/SchemaForm.tsx | 8 +++++++ 2 files changed, 31 insertions(+) diff --git a/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx b/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx index db3f7bbb..db245900 100644 --- a/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx +++ b/clients/web/src/components/groups/SchemaForm/SchemaForm.test.tsx @@ -2078,6 +2078,29 @@ describe("SchemaForm enlarge keyboard access (#2138)", () => { expect(noteField().tagName).toBe("INPUT"); }); + // Enter is also how an IME commits the candidate being composed, so acting on + // it there would enlarge the field and insert a newline every time a + // Japanese/Chinese/Korean user finished a word. userEvent has no composition + // mode, so the event is dispatched directly with the flag React reads. + it("ignores the Enter that commits an IME composition", () => { + renderWithMantine(); + + fireEvent.keyDown(noteField(), { key: "Enter", isComposing: true }); + + expect(noteField().tagName).toBe("INPUT"); + expect(noteField().value).toBe(""); + }); + + // Same event without the flag, to prove the guard above is what turned it + // away rather than fireEvent simply not reaching the handler. + it("still enlarges on an Enter that is not composing", () => { + renderWithMantine(); + + fireEvent.keyDown(noteField(), { key: "Enter", isComposing: false }); + + expect(noteField().tagName).toBe("TEXTAREA"); + }); + it("leaves the field alone for any other key", async () => { const user = userEvent.setup(); renderWithMantine(); diff --git a/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx b/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx index f5acc68d..ae149861 100644 --- a/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx +++ b/clients/web/src/components/groups/SchemaForm/SchemaForm.tsx @@ -758,8 +758,16 @@ export function SchemaForm({ // Ctrl/Cmd/Alt chords are deliberately left alone: those read as // "submit" in a form, and a consumer binding one (run the tool) // must not be overridden into enlarging a field instead. + // + // `isComposing` guards the IME case: Enter is also how a Japanese, + // Chinese or Korean input method commits the candidate being + // composed. That keystroke means "accept this word", not "new + // line", so acting on it would enlarge the field and insert a + // newline every time such a user finished a word — the shortcut + // would make the field unusable for them. if ( event.key !== "Enter" || + event.nativeEvent.isComposing || event.ctrlKey || event.metaKey || event.altKey