diff --git a/src/lib/editor/imagePreviewPlugin.ts b/src/lib/editor/imagePreviewPlugin.ts index 2af91c5..5bd6739 100644 --- a/src/lib/editor/imagePreviewPlugin.ts +++ b/src/lib/editor/imagePreviewPlugin.ts @@ -1,7 +1,7 @@ -import { WidgetType, EditorView, ViewPlugin, Decoration, ViewUpdate } from '@codemirror/view'; +import { WidgetType, EditorView, Decoration } from '@codemirror/view'; import type { DecorationSet } from '@codemirror/view'; +import { StateField, type Transaction, type EditorState, Range } from '@codemirror/state'; import { syntaxTree } from '@codemirror/language'; -import { Range } from '@codemirror/state'; class ImagePreviewWidget extends WidgetType { constructor(readonly url: string) { @@ -35,57 +35,51 @@ class ImagePreviewWidget extends WidgetType { } } -function getImageDecorations(view: EditorView) { + +function getImageDecorationsForState(state: EditorState) { const widgets: Range[] = []; - const { state } = view; - for (const { from, to } of view.visibleRanges) { - syntaxTree(state).iterate({ - from, - to, - enter: (node: { name: string; from: number; to: number; node: { getChild: (type: string) => any } }) => { - if (node.name === 'Image') { - // 查找图片语法中的 URL 节点 - const urlNode = node.node.getChild('URL'); - if (urlNode) { - let url = state.doc.sliceString(urlNode.from, urlNode.to); - // 处理可能的带尖括号的 URL - if (url.startsWith('<') && url.endsWith('>')) { - url = url.slice(1, -1); - } - - const deco = Decoration.widget({ - widget: new ImagePreviewWidget(url), - block: true, // 作为块级元素显示在下方 - side: 1 // 插入在节点之后 - }); - - widgets.push(deco.range(node.to)); + syntaxTree(state).iterate({ + enter: (node: { + name: string; + from: number; + to: number; + node: { getChild: (type: string) => any }; + }) => { + if (node.name === 'Image') { + // 查找图片语法中的 URL 节点 + const urlNode = node.node.getChild('URL'); + if (urlNode) { + let url = state.doc.sliceString(urlNode.from, urlNode.to); + // 处理可能的带尖括号的 URL + if (url.startsWith('<') && url.endsWith('>')) { + url = url.slice(1, -1); } + + const deco = Decoration.widget({ + widget: new ImagePreviewWidget(url), + block: true, // 作为块级元素显示在下方 + side: 1 // 插入在节点之后 + }); + + widgets.push(deco.range(node.to)); } } - }); - } + } + }); return Decoration.set(widgets.sort((a, b) => a.from - b.from)); } -export const imagePreviewPlugin = ViewPlugin.fromClass( - class { - decorations: DecorationSet; - - constructor(view: EditorView) { - this.decorations = getImageDecorations(view); - } - - update(update: ViewUpdate) { - // 文档改变或视口改变时重新计算 - if (update.docChanged || update.viewportChanged) { - this.decorations = getImageDecorations(update.view); - } - } +export const imagePreviewPlugin = StateField.define({ + create(state) { + return getImageDecorationsForState(state); }, - { - decorations: (v) => v.decorations - } -); + update(value, tr: Transaction) { + if (tr.docChanged) { + return getImageDecorationsForState(tr.state); + } + return value; + }, + provide: (f) => EditorView.decorations.from(f) +});