Closed shivaydv closed 4 months ago
I understand the usefulness of MDX for static pages. However, for projects that incorporate this type of editor, using MDX doesn't seem necessary. The editor already provides us with HTML, which we can directly use. Could you please share more about why you need MDX in this context? @shivaydv
As @k61b mentioned, this minimal-tiptap-editor mean to demonstrates how to set up the Tiptap editor for Shadcn/ui in the most minimal way possible.
Also Tiptap Editor has recently released new documentation, including advanced templates. You can check their docs here.
Hello @shivaydv, I recently tried this out w/ Next.js 14 using next-mdx + remarkgfm, and I had some hacky success. We're parsing HTML with regex which is a notorious anti-pattern, but it's a start:
import * as React from "react";
import { Content } from "@tiptap/core";
export default function MdxEditor() {
const [editorContent, setEditorContent] = React.useState<Content>("");
const [processedContent, setProcessedContent] = React.useState<string>("");
const handleEditorChange = (content: Content) => {
setEditorContent(content);
if (typeof content === "string") {
setProcessedContent(processTipTapHtmlOutput(content));
} else {
console.warn("Editor content is not a string, cannot process.");
setProcessedContent("");
}
};
return (
<MinimalTiptapEditor
{...}
output="html"
onChange={handleEditorChange}
/>
)
}
and the hacky util function:
export const processTipTapHtmlOutput = (html: string): string => {
const parser = new DOMParser();
const doc = parser.parseFromString(html, "text/html");
const processElement = (element: Element): void => {
// Remove all attributes except href, src, and target, rel
Array.from(element.attributes).forEach((attr) => {
if (["href", "src", "target", "rel"].includes(attr.name) === false) {
element.removeAttribute(attr.name);
}
});
// Process children
element.childNodes.forEach((child) => {
if (child.nodeType === Node.ELEMENT_NODE) {
processElement(child as Element);
}
});
};
processElement(doc.body);
// Convert the processed HTML back to a string
let processedHtml = doc.body.innerHTML;
// Tiptap doesn't self-close these tags :(
const selfClosingTags = ["br", "hr", "img"];
selfClosingTags.forEach((tag) => {
const regex = new RegExp(`<${tag}([^>]*)>`, "g");
processedHtml = processedHtml.replace(regex, `<${tag}$1 />`);
});
// Replace escaped HTML lt/gt chars
processedHtml = processedHtml.replace(/</g, "<").replace(/>/g, ">");
// Remove parent <p> tags around custom components to avoid hydration errors in Next.js
processedHtml = processedHtml.replace(
/<p>\s*(<[A-Z][^>]*>[\s\S]*?<\/[A-Z][^>]*>|<[A-Z][^/>]*\/>)\s*<\/p>/g,
"$1"
);
return processedHtml;
};
Most of the modern blog website use mdx to render the blog content. It would be great to have the mdx format in the text editor.