refactor(tiptap): move coordinator to editor.storage, drop dead Markdown html option
This commit is contained in:
parent
6b44a9c036
commit
d099db4140
@ -5,8 +5,8 @@ import { TableKit } from '@tiptap/extension-table'
|
|||||||
import { TaskList, TaskItem } from '@tiptap/extension-list'
|
import { TaskList, TaskItem } from '@tiptap/extension-list'
|
||||||
import { FileHandler } from '@tiptap/extension-file-handler'
|
import { FileHandler } from '@tiptap/extension-file-handler'
|
||||||
import { SlashCommand } from './slash-command'
|
import { SlashCommand } from './slash-command'
|
||||||
import { UploadCoordinator, type UploadEvent } from './upload-coordinator'
|
import { UploadCoordinator, UPLOAD_COORDINATOR_STORAGE_KEY, type UploadEvent } from './upload-coordinator'
|
||||||
import { UploadImage, setUploadCoordinator } from './upload-image'
|
import { UploadImage } from './upload-image'
|
||||||
import './style.css'
|
import './style.css'
|
||||||
|
|
||||||
export interface EditorOptions {
|
export interface EditorOptions {
|
||||||
@ -82,9 +82,7 @@ class TiptapEditorInstance {
|
|||||||
HTMLAttributes: { rel: 'noopener noreferrer', target: '_blank' },
|
HTMLAttributes: { rel: 'noopener noreferrer', target: '_blank' },
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Markdown.configure({
|
Markdown,
|
||||||
html: false,
|
|
||||||
}),
|
|
||||||
TableKit,
|
TableKit,
|
||||||
UploadImage,
|
UploadImage,
|
||||||
TaskList,
|
TaskList,
|
||||||
@ -131,15 +129,16 @@ class TiptapEditorInstance {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// 创建上传协调器,注入给 NodeView 的 onRetry/onRemove
|
// 创建上传协调器,挂到 editor.storage 供 NodeView 按实例读取(支持多编辑器实例)。
|
||||||
// onUploadEvent 透传给 coordinator.emit,未提供时空操作兜底
|
// onUploadEvent 透传给 coordinator.emit,未提供时空操作兜底。
|
||||||
if (this.options.onImageUpload) {
|
if (this.options.onImageUpload) {
|
||||||
this.coordinator = new UploadCoordinator(
|
this.coordinator = new UploadCoordinator(
|
||||||
this.editor,
|
this.editor,
|
||||||
this.options.onImageUpload,
|
this.options.onImageUpload,
|
||||||
this.options.onUploadEvent ?? (() => {}),
|
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 轮询)
|
// 通知宿主编辑器已就绪(替代 window.__tiptap_ready 轮询)
|
||||||
@ -245,9 +244,8 @@ class TiptapEditorInstance {
|
|||||||
destroy(): void {
|
destroy(): void {
|
||||||
this.editor?.destroy()
|
this.editor?.destroy()
|
||||||
this.editor = null
|
this.editor = null
|
||||||
|
// coordinator 通过 editor.storage 访问,随 editor 实例一同回收,无需显式清除引用。
|
||||||
this.coordinator = null
|
this.coordinator = null
|
||||||
// 清除 NodeView 的 coordinator 引用,避免指向已销毁的实例
|
|
||||||
setUploadCoordinator(null)
|
|
||||||
// 清理源码模式相关引用(容器 innerHTML 已清空,DOM 会随之移除)
|
// 清理源码模式相关引用(容器 innerHTML 已清空,DOM 会随之移除)
|
||||||
this.sourceTextarea = null
|
this.sourceTextarea = null
|
||||||
this.toggleButton = null
|
this.toggleButton = null
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
import type { Editor } from '@tiptap/core'
|
import type { Editor } from '@tiptap/core'
|
||||||
|
|
||||||
|
/** editor.storage 上挂载 coordinator 的 key。NodeView 通过此 key 拿到当前编辑器实例的 coordinator。 */
|
||||||
|
export const UPLOAD_COORDINATOR_STORAGE_KEY = 'uploadCoordinator'
|
||||||
|
|
||||||
/** pending 上传条目:保留 File 供重试,blobUrl 供本地预览,state 跟踪当前态。 */
|
/** pending 上传条目:保留 File 供重试,blobUrl 供本地预览,state 跟踪当前态。 */
|
||||||
interface UploadEntry {
|
interface UploadEntry {
|
||||||
file: File
|
file: File
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Image } from '@tiptap/extension-image'
|
import { Image } from '@tiptap/extension-image'
|
||||||
import type { Node as PMNode } from '@tiptap/pm/model'
|
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 回调注入接口。 */
|
/** NodeView 按钮点击 / destroy 回调注入接口。 */
|
||||||
export interface UploadNodeViewCallbacks {
|
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。
|
* 自定义 Image 扩展:继承父类属性,加三个上传状态属性,用自定义 NodeView。
|
||||||
*/
|
*/
|
||||||
@ -189,13 +181,15 @@ export const UploadImage = Image.configure({ allowBase64: true }).extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addNodeView() {
|
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({
|
return new UploadImageNodeView({
|
||||||
node,
|
node,
|
||||||
HTMLAttributes,
|
HTMLAttributes,
|
||||||
callbacks: {
|
callbacks: {
|
||||||
onRetry: (id) => coordinatorRef?.retryUpload(id),
|
onRetry: (id) => coordinator?.retryUpload(id),
|
||||||
onRemove: (id) => coordinatorRef?.removeUpload(id),
|
onRemove: (id) => coordinator?.removeUpload(id),
|
||||||
|
onDestroyed: (id) => coordinator?.handleNodeDestroyed(id),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user