fix(tiptap): slash 命令创建可运行代码块时模态框被立即关闭

斜杠菜单中按 Enter 选择「可运行代码块」时,openRunnableModal 在
同一个 keydown 事件处理中同步调用。模态框的 document keydown 监听
立即注册后,该 Enter 事件继续冒泡到 document 触发模态框的 Enter
处理——insert() → close(),模态框在同一 tick 内创建又销毁,用户
看不到配置弹框。

将 document.addEventListener("keydown", ...) 延迟到 setTimeout(0)
注册,确保触发事件完成传播后才开始监听。
This commit is contained in:
xfy 2026-07-07 17:51:06 +08:00
parent 1fa1984703
commit 82315853a2
2 changed files with 8 additions and 2 deletions

View File

@ -142,9 +142,11 @@ describe('openRunnableModal', () => {
expect(document.querySelector('.tiptap-runnable-modal')).toBeNull();
});
it('Esc 关闭弹框(不插入)', () => {
it('Esc 关闭弹框(不插入)', async () => {
const { editor, calls } = mockEditor();
openRunnableModal(editor);
// keydown 监听延迟注册setTimeout(0)),需先 flush timer
await new Promise((r) => setTimeout(r, 0));
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }));
expect(calls).toHaveLength(0);
expect(document.querySelector('.tiptap-runnable-modal')).toBeNull();

View File

@ -680,8 +680,12 @@ export function openRunnableModal(editor: Editor, editPos?: number, currentInfo?
}
}
document.addEventListener('keydown', onKeydown);
document.body.appendChild(mask);
// 延迟注册 keydown 监听openRunnableModal 可能在 slash 命令的 Enter keydown 事件处理中
// 同步调用。若立即注册,该 Enter 事件继续冒泡到 document 时会被模态框的 onKeydown 捕获,
// 触发 insert() → close()——模态框在同一 tick 内被创建又被销毁,用户看不到。
// setTimeout(0) 推迟到下一个宏任务,确保触发事件已完成传播。
setTimeout(() => document.addEventListener('keydown', onKeydown), 0);
updatePreview();
updateInsertEnabled();
langSelect.focus();