analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
128 lines (127 loc) • 3.78 kB
JavaScript
// src/components/RichEditor/components/MathNode.tsx
import { Node, mergeAttributes } from "@tiptap/core";
import { ReactNodeViewRenderer, NodeViewWrapper } from "@tiptap/react";
import katex from "katex";
import { useMemo } from "react";
import { jsx } from "react/jsx-runtime";
function MathNodeView({ node, editor, getPos }) {
const latex = typeof node.attrs.latex === "string" ? node.attrs.latex : "";
const renderedHtml = useMemo(() => {
try {
return katex.renderToString(latex, {
throwOnError: false,
displayMode: false
});
} catch {
return `<span class="text-error-600">${latex}</span>`;
}
}, [latex]);
const handleClick = () => {
const pos = getPos();
if (typeof pos !== "number" || !Number.isFinite(pos)) return;
editor.chain().focus().deleteRange({ from: pos, to: pos + node.nodeSize }).insertContent(`$${latex}$`).run();
const docSize = editor.state.doc.content.size;
const newPos = Math.min(Math.max(pos + latex.length + 1, 0), docSize);
editor.commands.setTextSelection(newPos);
};
return /* @__PURE__ */ jsx(
NodeViewWrapper,
{
as: "span",
className: "inline-math cursor-pointer hover:bg-primary-50 rounded px-0.5 transition-colors",
onClick: handleClick,
title: "Clique para editar",
children: /* @__PURE__ */ jsx(
"span",
{
dangerouslySetInnerHTML: { __html: renderedHtml },
className: "inline"
}
)
}
);
}
var MathNode = Node.create({
name: "mathInline",
group: "inline",
inline: true,
atom: true,
selectable: true,
addAttributes() {
return {
latex: {
default: ""
}
};
},
parseHTML() {
return [
{
tag: 'span[data-type="math-inline"]',
getAttrs: (dom) => {
return { latex: dom.dataset.latex ?? "" };
}
}
];
},
renderHTML({ node, HTMLAttributes }) {
return [
"span",
mergeAttributes(HTMLAttributes, {
"data-type": "math-inline",
"data-latex": node.attrs.latex
})
];
},
addNodeView() {
return ReactNodeViewRenderer(MathNodeView);
},
// Disable default input rules
addInputRules() {
return [];
},
addKeyboardShortcuts() {
return {
// When space is pressed after closing $, convert to math node
Space: ({ editor }) => {
const { state } = editor;
const { selection } = state;
const { $from } = selection;
const textBefore = $from.parent.textBetween(
Math.max(0, $from.parentOffset - 200),
$from.parentOffset,
"\n"
);
const regex = /\$([^$]+)\$$/;
const match = regex.exec(textBefore);
if (match?.[1]?.trim()) {
const latex = match[1];
const matchStart = $from.pos - match[0].length;
editor.chain().deleteRange({ from: matchStart, to: $from.pos }).insertContent([
{ type: "mathInline", attrs: { latex } },
{ type: "text", text: " " }
]).run();
return true;
}
return false;
},
// When backspace is pressed on a math node, convert it back to text for editing
Backspace: ({ editor }) => {
const { selection } = editor.state;
const { $from } = selection;
const nodeBefore = $from.nodeBefore;
if (nodeBefore?.type.name === "mathInline") {
const pos = $from.pos - nodeBefore.nodeSize;
const latex = nodeBefore.attrs.latex;
editor.chain().deleteRange({ from: pos, to: $from.pos }).insertContent(`$${latex}`).run();
return true;
}
return false;
}
};
}
});
export {
MathNode
};
//# sourceMappingURL=chunk-NVNYYFHH.mjs.map