feat(editor): 挂载 CodeBlockNodeView + editor.storage 注入 onRunCode

CodeBlockLowlight.extend({ addNodeView }) 接入自定义 NodeView。
EditorOptions 新增 onRunCode 字段;编辑器初始化时挂到 editor.storage,
NodeView 经 storage key 读取(仿 upload-coordinator 范式)。
This commit is contained in:
xfy 2026-07-06 18:00:15 +08:00
parent 82280e3d4f
commit 6e5ff72a29

View File

@ -5,6 +5,7 @@ import { TaskItem, TaskList } from '@tiptap/extension-list';
import { TableKit } from '@tiptap/extension-table'; import { TableKit } from '@tiptap/extension-table';
import { Markdown } from '@tiptap/markdown'; import { Markdown } from '@tiptap/markdown';
import StarterKit from '@tiptap/starter-kit'; import StarterKit from '@tiptap/starter-kit';
import { CodeBlockNodeView, ON_RUN_CODE_STORAGE_KEY } from './code-block-view';
import { lowlight } from './highlight'; import { lowlight } from './highlight';
import { SlashCommand } from './slash-command'; import { SlashCommand } from './slash-command';
import { TaskInputRule } from './task-input-rule'; import { TaskInputRule } from './task-input-rule';
@ -38,6 +39,9 @@ class EditorOptions {
onReady?: () => void; onReady?: () => void;
// 上传状态事件error/success/removed + counts替代 window.__tiptap_uploads 轮询 // 上传状态事件error/success/removed + counts替代 window.__tiptap_uploads 轮询
onUploadEvent?: (event: UploadEvent) => void; onUploadEvent?: (event: UploadEvent) => void;
// 编辑器内运行代码回调Rust 注入NodeView 点击「运行」时经 editor.storage 转发。
// opts: { language, source }返回格式化结果字符串Rust 拼好 stdout/stderr/状态)。
onRunCode?: (opts: { language: string; source: string }) => Promise<string>;
} }
// wasm-bindgen 生成的 glue 用裸标识符 `new EditorOptions()` 从全局解析, // wasm-bindgen 生成的 glue 用裸标识符 `new EditorOptions()` 从全局解析,
// IIFE 的 name 只能挂一个全局TiptapEditor这里手动把 EditorOptions 也挂到 window 上。 // IIFE 的 name 只能挂一个全局TiptapEditor这里手动把 EditorOptions 也挂到 window 上。
@ -103,7 +107,11 @@ class TiptapEditorInstance {
codeBlock: false, codeBlock: false,
}), }),
Markdown, Markdown,
CodeBlockLowlight.configure({ lowlight }), CodeBlockLowlight.configure({ lowlight }).extend({
addNodeView() {
return ({ node, editor }) => new CodeBlockNodeView({ node, editor });
},
}),
TableKit, TableKit,
UploadImage, UploadImage,
TaskList, TaskList,
@ -169,6 +177,12 @@ class TiptapEditorInstance {
this.coordinator; this.coordinator;
} }
// 把 onRunCode 回调挂到 editor.storage供 CodeBlockNodeView 读取(仿 upload-coordinator 范式)。
if (this.options.onRunCode) {
(this.editor.storage as unknown as Record<string, unknown>)[ON_RUN_CODE_STORAGE_KEY] =
this.options.onRunCode;
}
// 通知宿主编辑器已就绪(替代 window.__tiptap_ready 轮询) // 通知宿主编辑器已就绪(替代 window.__tiptap_ready 轮询)
this.options.onReady?.(); this.options.onReady?.();
} }