
Plate 如何用装饰高亮预览 Markdown 语法而不反序列化为节点【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate如果你希望编辑器把**加粗**、## 标题这类 Markdown 语法原样保留为纯文本同时在视觉上做出对应的强调加粗、大字号标题、引用竖线等又不想把它们解析成 Plate 的 heading/bold 节点Plate 官方仓库里的 Preview Markdown 示例给出了一条现成的路径用 Slate 的装饰decoration机制给文本节点算出样式范围再用自定义 leaf 渲染器给这些范围上色。官方示例文档对此的描述是This example previews Markdown syntax with Slate decorations. It does not deserialize Markdown into Plate nodes; it keeps the text as text and styles matching ranges with a custom leaf renderer.也就是说装饰只标注范围 套样式内容数据始终是一段普通文本。装饰预览与反序列化是两条路官方示例文档preview-markdown.mdx在结尾给出了明确的选型判断本例的装饰预览当编辑器需要让用户看到原始 Markdown 字符时使用Use this pattern when the editor should keep raw Markdown characters visible。Markdown 插件的反序列化当编辑器需要把 Markdown 文本转换成 Plate 节点时使用Use Markdown when the editor should convert Markdown text into Plate nodes。文档的 Related 一节指向 Markdown 章节覆盖 Markdown 的反序列化与序列化。示例文档给出的运行时分工Runtime Shape如下SurfaceOwnerNotesdecoratePreviewRegistry example读取文本节点对node.text分词返回带 token 类型标志的 Slate 范围。PreviewLeafRegistry example当被装饰的 leaf 带有bold、italic、title、list、hr、blockquote或code标志时套用 CSS 类。preview-markdownpluginRegistry example本地createSlatePlugin({ decorate })插件。BasicNodesKitRegistry kit提供编辑器常规的段落和标题插件。prismjsDependency提供装饰函数使用的 Markdown 分词器。准备条件按示例源码preview-markdown-demo.tsx的依赖来看需要准备platejs提供createSlatePlugin、Decorate、RenderLeafProps、TText、TextApiplatejs/react提供Plate与usePlateEditorprismjs并且要额外加载其 Markdown 语言组件import Prism from prismjs; import prismjs/components/prism-markdown.js;一套基础节点插件。示例使用 registry 中的BasicNodesKit文档说明它 Supplies the editors normal paragraph and heading plugins用来提供常规的段落与标题行为。注意装饰函数本身只依赖platejs与prismjsregistry 专属的BasicNodesKit、cn类名合并工具、Editor/EditorContainer组件在你的项目里可以换成等价实现下文代码中会标注它们的来源。第一步写 decorate 函数给每个文本节点算出样式范围Plate 会把文档里的每个[node, path]条目传给插件的decorate属性——这是 Plate 插件的一个可选字段官方 API 文档plate-plugin.mdx描述为 Property used by Plate to decorate editor ranges.类型是DecorateWithAnyKeyC。decoratePreview的处理逻辑只处理文本节点TextApi.isText(node)不成立时直接返回空数组用 Prism 的 Markdown 语法对node.text分词Prism.tokenize(node.text, Prism.languages.markdown)逐个 token 累加偏移量对非字符串 token 生成一个 Slate 范围anchor/focus落在该 token 的起止 offset 上并附带一个以 token 类型命名的布尔标志如{ title: true }getLength负责计算 token 占用的字符数字符串 token 取lengthcontent是字符串的取content.length嵌套content数组则递归求和——这保证了范围偏移与原文本一一对应。完整实现来自示例源码import * as React from react; import { type Decorate, type RenderLeafProps, type TText, createSlatePlugin, TextApi, } from platejs; import { Plate, usePlateEditor } from platejs/react; import Prism from prismjs; import { cn } from /lib/utils; import { BasicNodesKit } from /registry/components/editor/plugins/basic-nodes-kit; import { previewMdValue } from /registry/examples/values/preview-md-value; import { Editor, EditorContainer } from /registry/ui/editor; import prismjs/components/prism-markdown.js; /** Decorate texts with markdown preview. */ const decoratePreview: Decorate ({ entry: [node, path] }) { const ranges: any[] []; if (!TextApi.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; };其中cn来自 registry 的/lib/utilsBasicNodesKit、Editor/EditorContainer来自 registry 目录换成你自己项目里的等价模块即可decoratePreview与PreviewLeaf本身不依赖这些导入。第二步用自定义 renderLeaf 给带标志的 leaf 套样式装饰范围落到渲染层后每个 leaf 会带上对应的标志。PreviewLeaf接收RenderLeafProps把标志映射成 Tailwind 类名function PreviewLeaf({ attributes, children, leaf, }: RenderLeafProps { 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 mt-5 mb-2.5 inline-block font-bold text-[20px], list pl-2.5 text-[20px] leading-[10px], hr block border-[#ddd] border-b-2 text-center, blockquote inline-block border-[#ddd] border-l-2 pl-2.5 text-[#aaa] italic, code bg-[#eee] p-[3px] font-mono )} {children} /span ); }注意attributes必须透传到span上这是 Slate 装饰范围定位所依赖的属性集合。第三步注册插件并创建编辑器把decorate挂到本地插件上与基础节点插件一起传给编辑器export default function PreviewMdDemo() { const editor usePlateEditor( { plugins: [ ...BasicNodesKit, createSlatePlugin({ key: preview-markdown, decorate: decoratePreview, }), ], value: previewMdValue, }, [] ); return ( Plate editor{editor} EditorContainer Editor renderLeaf{PreviewLeaf} / /EditorContainer /Plate ); }初始值previewMdValue见 preview-md-value.tsx就是包含 Markdown 字符的普通 Plate 段落内容没有预解析成任何 Markdown 节点/** jsxRuntime classic */ /** jsx jsx */ import { jsx } from platejs/test-utils; export const previewMdValue: any ( fragment hh2 Preview Markdown/hh2 hp Slate is flexible enough to add **decorations** that can format text based on its content. For example, this editor has **Markdown** preview decorations on it, to make it _dead_ simple to make an editor with built-in Markdown previewing. /hp hp- List item./hp hpgt; Blockquote paragraph./hp hpgt; gt; Nested blockquote./hp hpgt; - Quoted list item./hp hp---/hp hp## Try it out!/hp hpTry it out for yourself!/hp /fragment );这个 value 在仓库中是用platejs/test-utils的 jsx 编写的如果你的项目没有该依赖等价做法是直接写出对应的 Plate 节点数组只要段落文本里含有##、、-、---等 Markdown 字符即可触发装饰。验证结果示例文档提供了 Demo 预览页与完整源码ComponentPreview namepreview-markdown-demo /与ComponentSource namepreview-markdown-demo /运行示例后可以按文档描述的两点判断文本保持为文本编辑器中的## Try it out!、---、 Blockquote paragraph.等段落显示的是原始 Markdown 字符内容数据没有被转换成 heading/hr/blockquote 节点匹配范围带样式这些字符范围呈现出PreviewLeaf中定义的样式——## Try it out!是 20px 加粗的标题样式---是居中带下边框的分隔线样式 ...段落是左侧竖线、灰色斜体的引用样式。由于样式完全来自PreviewLeaf的类名映射如果某个范围没变样式先检查decorate返回的范围 offset 是否与原文本对齐getLength计算有误会导致偏移错位再检查 leaf 是否处理了对应的 token 标志。边界与限制decorate只对文本节点生效非文本条目直接返回空范围。文档列出的 token 类型有 title, bold, italic, blockquote, list, horizontal rule, and codePreviewLeaf处理的标志即title、bold、italic、list、hr、blockquote、code。分词类型由 Prism 的 Markdown 语法决定leaf 没处理的标志不会有任何样式。如果目标不再是保留原始字符而是要把 Markdown 真正转换成 Plate 节点并支持序列化回 Markdown应改用文档 Markdown 章节描述的反序列化/序列化方案本例的装饰路径不适用于该目标。延伸阅读Preview Markdown 示例文档Demo、Source、Runtime Shape 与选型判断的原始出处。示例源码decoratePreview、PreviewLeaf与插件装配的完整实现。Plate Plugin APIdecorate字段的类型定义。Slate Text API文本装饰与被装饰的 leaf 相关说明。【免费下载链接】plateRich-text editor with AI and shadcn/ui项目地址: https://gitcode.com/GitHub_Trending/pl/plate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考