Preview Markdown
Decorate texts with markdown preview.
components/preview-markdown-demo.tsx
'use client';
/* eslint-disable prettier/prettier */
import React from 'react';
import { cn } from '@udecode/cn';
import { BasicElementsPlugin } from "@udecode/plate-basic-elements/react";
import { BasicMarksPlugin } from "@udecode/plate-basic-marks/react";
import {
type Decorate,
type TText, createSlatePlugin, isText
} from "@udecode/plate-common";
import { type TRenderLeafProps, Plate } from "@udecode/plate-common/react";
import Prism from 'prismjs';
import { useCreateEditor } from '@/components/editor/use-create-editor';
import { previewMdValue } from '@/components/values/preview-md-value';
import { Editor, EditorContainer } from '@/components/plate-ui/editor';
import 'prismjs/components/prism-markdown.js';
/**
* Decorate texts with markdown preview.
*/
const decoratePreview: Decorate =
({entry: [node, path]}) => {
const ranges: any[] = [];
if (!isText(node)) {
return ranges;
}
const getLength = (token: any) => {
if (typeof token === 'string') {
return token.length;
}
if (typeof token.content === 'string') {
return token.content.length;
}
return token.content.reduce((l: any, t: any) => l + getLength(t), 0);
};
const tokens = Prism.tokenize(node.text, Prism.languages.markdown);
let start = 0;
for (const token of tokens) {
const length = getLength(token);
const end = start + length;
if (typeof token !== 'string') {
ranges.push({
anchor: { offset: start, path },
focus: { offset: end, path },
[token.type]: true,
});
}
start = end;
}
return ranges;
};
function PreviewLeaf({
attributes,
children,
leaf,
}: TRenderLeafProps<
{
blockquote?: boolean;
bold?: boolean;
code?: boolean;
hr?: boolean;
italic?: boolean;
list?: boolean;
title?: boolean;
} & TText
>) {
const { blockquote, bold, code, hr, italic, list, title } = leaf;
return (
<span
{...attributes}
className={cn(
bold && 'font-bold',
italic && 'italic',
title && 'mx-0 mb-2.5 mt-5 inline-block text-[20px] font-bold',
list && 'pl-2.5 text-[20px] leading-[10px]',
hr && 'block border-b-2 border-[#ddd] text-center',
blockquote &&
'inline-block border-l-2 border-[#ddd] pl-2.5 italic text-[#aaa]',
code && 'bg-[#eee] p-[3px] font-mono'
)}
>
{children}
</span>
);
}
export default function PreviewMdDemo() {
const editor = useCreateEditor({
plugins: [BasicElementsPlugin, BasicMarksPlugin, createSlatePlugin({
key: 'preview-markdown',
decorate: decoratePreview,
})],
value: previewMdValue,
})
return (
<Plate editor={editor}>
<EditorContainer>
<Editor renderLeaf={PreviewLeaf} />
</EditorContainer>
</Plate>
);
}