@rtdui/editor
Version:
React rich text editor based on tiptap
101 lines (98 loc) • 3.06 kB
JavaScript
import { KatexBlockPlugin } from "./math-katex-block-plugin.mjs";
import { Node, mergeAttributes, textblockTypeInputRule } from "@tiptap/core";
//#region packages/editor/src/RichTextEditor/tiptap_extensions/extension-math/math-katex-block.ts
const mathDollorBlockInputRegex = /^\$\$[\s\n]$/;
/** 处理在编辑器中的输入 */
const MathKatexBlock = Node.create({
name: "mathKatexBlock",
priority: 1e3,
addOptions() {
return {
exitOnTripleEnter: true,
exitOnArrowDown: true,
katexOptions: {},
HTMLAttributes: {}
};
},
content: "text*",
marks: "",
group: "block",
code: true,
defining: true,
parseHTML() {
return [{
tag: `div[data-type="${this.name}"]`,
preserveWhitespace: "full"
}];
},
renderHTML({ node, HTMLAttributes }) {
return [
"div",
mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { "data-type": this.name }),
0
];
},
addCommands() {
return {
setMathBlock: (attributes) => ({ commands }) => {
return commands.setNode(this.name, attributes);
},
toggleMathBlock: (attributes) => ({ commands }) => {
return commands.toggleNode(this.name, "paragraph", attributes);
}
};
},
addKeyboardShortcuts() {
return {
"Mod-Alt-m": () => this.editor.commands.toggleMathBlock(),
Backspace: () => {
const { empty, $anchor } = this.editor.state.selection;
const isAtStart = $anchor.pos === 1;
if (!empty || $anchor.parent.type.name !== this.name) return false;
if (isAtStart || !$anchor.parent.textContent.length) return this.editor.commands.clearNodes();
return false;
},
Enter: ({ editor }) => {
if (!this.options.exitOnTripleEnter) return false;
const { state } = editor;
const { selection } = state;
const { $from, empty } = selection;
if (!empty || $from.parent.type !== this.type) return false;
const isAtEnd = $from.parentOffset === $from.parent.nodeSize - 2;
const endsWithDoubleNewline = $from.parent.textContent.endsWith("\n\n");
if (!isAtEnd || !endsWithDoubleNewline) return false;
return editor.chain().command(({ tr }) => {
tr.delete($from.pos - 2, $from.pos);
return true;
}).exitCode().run();
},
ArrowDown: ({ editor }) => {
if (!this.options.exitOnArrowDown) return false;
const { state } = editor;
const { selection, doc } = state;
const { $from, empty } = selection;
if (!empty || $from.parent.type !== this.type) return false;
if (!($from.parentOffset === $from.parent.nodeSize - 2)) return false;
const after = $from.after();
if (after === void 0) return false;
if (doc.nodeAt(after)) return false;
return editor.commands.exitCode();
}
};
},
addInputRules() {
return [textblockTypeInputRule({
find: mathDollorBlockInputRegex,
type: this.type
})];
},
addProseMirrorPlugins() {
return [...this.parent?.() || [], KatexBlockPlugin({
editor: this.editor,
name: this.name,
katexOptions: this.options.katexOptions
})];
}
});
//#endregion
export { MathKatexBlock, mathDollorBlockInputRegex };