mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-25 08:34:39 +00:00
fix: prevent IME enter from submitting composer
This commit is contained in:
parent
7e9606a0b2
commit
b992196c29
2 changed files with 97 additions and 0 deletions
|
|
@ -328,6 +328,7 @@ onUnmounted(() => {
|
|||
for (const att of attachments.value) {
|
||||
revokeAttachment(att);
|
||||
}
|
||||
clearCompositionEndTimer();
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
@ -422,7 +423,36 @@ function handleSteer(): void {
|
|||
emit('steer', payload);
|
||||
}
|
||||
|
||||
let isComposingText = false;
|
||||
let compositionEndTimer: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
function clearCompositionEndTimer(): void {
|
||||
if (compositionEndTimer !== null) {
|
||||
clearTimeout(compositionEndTimer);
|
||||
compositionEndTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function handleCompositionStart(): void {
|
||||
clearCompositionEndTimer();
|
||||
isComposingText = true;
|
||||
}
|
||||
|
||||
function handleCompositionEnd(): void {
|
||||
clearCompositionEndTimer();
|
||||
compositionEndTimer = setTimeout(() => {
|
||||
compositionEndTimer = null;
|
||||
isComposingText = false;
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function isComposingKeyEvent(e: KeyboardEvent): boolean {
|
||||
return isComposingText || e.isComposing || e.keyCode === 229;
|
||||
}
|
||||
|
||||
function handleKeydown(e: KeyboardEvent): void {
|
||||
if (isComposingKeyEvent(e)) return;
|
||||
|
||||
// Close dropdowns on Escape
|
||||
if (e.key === 'Escape') {
|
||||
if (dropdownOpen.value) {
|
||||
|
|
@ -729,6 +759,8 @@ function selectModel(modelId: string): void {
|
|||
:placeholder="placeholder"
|
||||
rows="1"
|
||||
@keydown="handleKeydown"
|
||||
@compositionstart="handleCompositionStart"
|
||||
@compositionend="handleCompositionEnd"
|
||||
@input="handleInput"
|
||||
/>
|
||||
|
||||
|
|
|
|||
65
apps/kimi-web/test/composer.test.ts
Normal file
65
apps/kimi-web/test/composer.test.ts
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import Composer from '../src/components/Composer.vue';
|
||||
|
||||
function mountComposer() {
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
locale: 'en',
|
||||
messages: {
|
||||
en: {
|
||||
composer: {
|
||||
interrupt: 'Interrupt',
|
||||
interruptTitle: 'Interrupt',
|
||||
placeholder: 'Message Kimi',
|
||||
send: 'Send',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return mount(Composer, {
|
||||
global: {
|
||||
plugins: [i18n],
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function waitForCompositionEndTimer(): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, 0));
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
describe('Composer IME input', () => {
|
||||
it('does not submit when Enter confirms active composition', async () => {
|
||||
const wrapper = mountComposer();
|
||||
const textarea = wrapper.get('textarea');
|
||||
|
||||
await textarea.setValue('ni');
|
||||
await textarea.trigger('compositionstart');
|
||||
await textarea.trigger('keydown', { key: 'Enter', isComposing: true });
|
||||
|
||||
expect(wrapper.emitted('submit')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('does not submit the Enter that immediately follows compositionend', async () => {
|
||||
const wrapper = mountComposer();
|
||||
const textarea = wrapper.get('textarea');
|
||||
|
||||
await textarea.setValue('你好');
|
||||
await textarea.trigger('compositionstart');
|
||||
await textarea.trigger('compositionend');
|
||||
await textarea.trigger('keydown', { key: 'Enter', isComposing: false });
|
||||
|
||||
expect(wrapper.emitted('submit')).toBeUndefined();
|
||||
|
||||
await waitForCompositionEndTimer();
|
||||
await textarea.trigger('keydown', { key: 'Enter', isComposing: false });
|
||||
|
||||
expect(wrapper.emitted('submit')).toEqual([[{ text: '你好', attachments: [] }]]);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue