refactor(tiptap): move coordinator to editor.storage, drop dead Markdown html option

This commit is contained in:
xfy 2026-06-23 18:39:38 +08:00
parent 6b44a9c036
commit d099db4140
3 changed files with 17 additions and 22 deletions

View File

@ -5,8 +5,8 @@ import { TableKit } from '@tiptap/extension-table'
import { TaskList, TaskItem } from '@tiptap/extension-list'
import { FileHandler } from '@tiptap/extension-file-handler'
import { SlashCommand } from './slash-command'
import { UploadCoordinator, type UploadEvent } from './upload-coordinator'
import { UploadImage, setUploadCoordinator } from './upload-image'
import { UploadCoordinator, UPLOAD_COORDINATOR_STORAGE_KEY, type UploadEvent } from './upload-coordinator'
import { UploadImage } from './upload-image'
import './style.css'
export interface EditorOptions {
@ -82,9 +82,7 @@ class TiptapEditorInstance {
HTMLAttributes: { rel: 'noopener noreferrer', target: '_blank' },
},
}),
Markdown.configure({
html: false,
}),
Markdown,
TableKit,
UploadImage,
TaskList,
@ -131,15 +129,16 @@ class TiptapEditorInstance {
},
})
// 创建上传协调器,注入给 NodeView 的 onRetry/onRemove
// onUploadEvent 透传给 coordinator.emit未提供时空操作兜底
// 创建上传协调器,挂到 editor.storage 供 NodeView 按实例读取(支持多编辑器实例)。
// onUploadEvent 透传给 coordinator.emit未提供时空操作兜底
if (this.options.onImageUpload) {
this.coordinator = new UploadCoordinator(
this.editor,
this.options.onImageUpload,
this.options.onUploadEvent ?? (() => {}),
)
setUploadCoordinator(this.coordinator)
// editor.storage 是开放式索引签名;自定义 key 需绕过严格检查Tiptap 官方扩展 storage 模式)。
;(this.editor.storage as unknown as Record<string, unknown>)[UPLOAD_COORDINATOR_STORAGE_KEY] = this.coordinator
}
// 通知宿主编辑器已就绪(替代 window.__tiptap_ready 轮询)
@ -245,9 +244,8 @@ class TiptapEditorInstance {
destroy(): void {
this.editor?.destroy()
this.editor = null
// coordinator 通过 editor.storage 访问,随 editor 实例一同回收,无需显式清除引用。
this.coordinator = null
// 清除 NodeView 的 coordinator 引用,避免指向已销毁的实例
setUploadCoordinator(null)
// 清理源码模式相关引用(容器 innerHTML 已清空DOM 会随之移除)
this.sourceTextarea = null
this.toggleButton = null

View File

@ -1,5 +1,8 @@
import type { Editor } from '@tiptap/core'
/** editor.storage 上挂载 coordinator 的 key。NodeView 通过此 key 拿到当前编辑器实例的 coordinator。 */
export const UPLOAD_COORDINATOR_STORAGE_KEY = 'uploadCoordinator'
/** pending 上传条目:保留 File 供重试blobUrl 供本地预览state 跟踪当前态。 */
interface UploadEntry {
file: File

View File

@ -1,6 +1,6 @@
import { Image } from '@tiptap/extension-image'
import type { Node as PMNode } from '@tiptap/pm/model'
import type { UploadCoordinator } from './upload-coordinator'
import { UPLOAD_COORDINATOR_STORAGE_KEY, type UploadCoordinator } from './upload-coordinator'
/** NodeView 按钮点击 / destroy 回调注入接口。 */
export interface UploadNodeViewCallbacks {
@ -146,14 +146,6 @@ class UploadImageNodeView {
}
}
/** coordinator 引用(由 index.ts 在创建 editor 前注入)。 */
let coordinatorRef: Pick<UploadCoordinator, 'retryUpload' | 'removeUpload'> | null = null
/** index.ts 注入 coordinator供 NodeView 的 onRetry/onRemove 调用。 */
export function setUploadCoordinator(c: typeof coordinatorRef): void {
coordinatorRef = c
}
/**
* Image NodeView
*/
@ -189,13 +181,15 @@ export const UploadImage = Image.configure({ allowBase64: true }).extend({
},
addNodeView() {
return ({ node, HTMLAttributes }) => {
return ({ node, HTMLAttributes, editor }) => {
const coordinator = (editor.storage as unknown as Record<string, unknown>)[UPLOAD_COORDINATOR_STORAGE_KEY] as UploadCoordinator | undefined
return new UploadImageNodeView({
node,
HTMLAttributes,
callbacks: {
onRetry: (id) => coordinatorRef?.retryUpload(id),
onRemove: (id) => coordinatorRef?.removeUpload(id),
onRetry: (id) => coordinator?.retryUpload(id),
onRemove: (id) => coordinator?.removeUpload(id),
onDestroyed: (id) => coordinator?.handleNodeDestroyed(id),
},
})
}