fix(editor): guard Mod-Enter submit against open IME composition (#5231)

The bare-Enter submit path already refuses to fire while view.composing
is true, but Mod-Enter had no such guard. Pressing ⌘↵ while a pinyin/kana
composition is still open submits the document WITHOUT the composed text
— e.g. paste a screenshot, type a Chinese sentence, hit ⌘↵ before the
buffer commits, and the submission carries only the screenshot. Apply the
same composing guard to Mod-Enter.

Co-authored-by: Lambda <lambda@multica.ai>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
Jiayuan Zhang
2026-07-10 22:44:23 +08:00
committed by GitHub
parent 06df00f414
commit 932bbf2bb5
2 changed files with 25 additions and 3 deletions

View File

@@ -25,7 +25,7 @@ describe("createSubmitExtension", () => {
isActive: () => false,
} as Partial<Editor>;
it("Mod-Enter always submits", () => {
it("Mod-Enter submits when no composition is open", () => {
const onSubmit = vi.fn(() => true);
const shortcuts = getShortcuts(
createSubmitExtension(onSubmit, { submitOnEnter: false }),
@@ -33,10 +33,24 @@ describe("createSubmitExtension", () => {
);
expect(shortcuts["Mod-Enter"]).toBeDefined();
shortcuts["Mod-Enter"]!();
expect(shortcuts["Mod-Enter"]!()).toBe(true);
expect(onSubmit).toHaveBeenCalledTimes(1);
});
it("Mod-Enter is suppressed during IME composition", () => {
const onSubmit = vi.fn(() => true);
const shortcuts = getShortcuts(
createSubmitExtension(onSubmit, { submitOnEnter: false }),
{
view: { composing: true } as unknown as Editor["view"],
isActive: () => false,
},
);
expect(shortcuts["Mod-Enter"]!()).toBe(false);
expect(onSubmit).not.toHaveBeenCalled();
});
it("bare Enter is not bound when submitOnEnter is false", () => {
const onSubmit = vi.fn(() => true);
const shortcuts = getShortcuts(

View File

@@ -16,7 +16,15 @@ export function createSubmitExtension(
name: "submitShortcut",
addKeyboardShortcuts() {
const shortcuts: Record<string, () => boolean> = {
"Mod-Enter": () => onSubmit(),
"Mod-Enter": () => {
// IME guard — same as Enter below. While a composition is open the
// composed text is not in the document yet, so submitting here
// would send the doc WITHOUT what the user just typed (e.g. paste
// a screenshot, type a pinyin sentence, hit ⌘↵ before the buffer
// commits — the submission carries only the screenshot).
if (this.editor.view.composing) return false;
return onSubmit();
},
};
if (submitOnEnter) {
shortcuts.Enter = () => {