@blocknote/react
Version:
A "Notion-style" block-based extensible text editor built on top of Prosemirror and Tiptap.
109 lines (87 loc) • 2.65 kB
text/typescript
import type { Mark } from "prosemirror-model";
import type {
EditorView,
MarkView,
ViewMutationRecord,
} from "prosemirror-view";
import type { BlockNoteEditor } from "@blocknote/core";
import type {
CoreMarkViewSpec,
CoreMarkViewUserOptions,
MarkViewDOMSpec,
} from "./CoreMarkViewOptions.js";
/* eslint-disable curly */
export class CoreMarkView<ComponentType> implements MarkView {
dom: HTMLElement;
contentDOM: HTMLElement | undefined;
mark: Mark;
view: EditorView;
inline: boolean;
options: CoreMarkViewUserOptions<ComponentType>;
editor: BlockNoteEditor<any, any, any>;
#createElement(as?: MarkViewDOMSpec) {
const { inline, mark } = this;
return as == null
? document.createElement(inline ? "span" : "div")
: as instanceof HTMLElement
? as
: as instanceof Function
? as(mark)
: document.createElement(as);
}
createDOM(as?: MarkViewDOMSpec) {
return this.#createElement(as);
}
createContentDOM(as?: MarkViewDOMSpec) {
return this.#createElement(as);
}
constructor({
mark,
view,
inline,
options,
editor, // BlockNote specific
}: CoreMarkViewSpec<ComponentType>) {
this.mark = mark;
this.view = view;
this.inline = inline;
this.options = options;
this.editor = editor;
this.dom = this.createDOM(options.as);
this.contentDOM = options.contentAs
? this.createContentDOM(options.contentAs)
: undefined;
this.dom.setAttribute("data-mark-view-root", "true");
if (this.contentDOM) {
this.contentDOM.setAttribute("data-mark-view-content", "true");
this.contentDOM.style.whiteSpace = "inherit";
}
}
get component() {
return this.options.component;
}
shouldIgnoreMutation: (mutation: ViewMutationRecord) => boolean = (
mutation,
) => {
if (!this.dom || !this.contentDOM) return true;
if (mutation.type === "selection") return false;
if (this.contentDOM === mutation.target && mutation.type === "attributes")
return true;
if (this.contentDOM.contains(mutation.target)) return false;
return true;
};
ignoreMutation: (mutation: ViewMutationRecord) => boolean = (mutation) => {
if (!this.dom || !this.contentDOM) return true;
let result;
const userIgnoreMutation = this.options.ignoreMutation;
if (userIgnoreMutation) result = userIgnoreMutation(mutation);
if (typeof result !== "boolean")
result = this.shouldIgnoreMutation(mutation);
return result;
};
public destroy() {
this.options.destroy?.();
this.dom.remove();
this.contentDOM?.remove();
}
}