docs/migration/v48.cn.mdx
PlateElement、PlateLeaf 和 PlateText 的 HTML 属性从顶层 props 移至 attributes prop,除了 className、style 和 as。迁移方式:// 之前
<PlateElement
{...props}
ref={ref}
contentEditable={false}
>
{children}
</PlateElement>
// 之后
<PlateElement
{...props}
ref={ref}
attributes={{
...props.attributes,
contentEditable: false,
}}
>
{children}
</PlateElement>
PlateElement、PlateLeaf、PlateText 的 nodeProps prop,已合并至 attributes prop。node.props 应直接返回 props 而非包裹在 nodeProps 对象中。迁移方式:// 之前
node: {
props: ({ element }) => ({
nodeProps: {
colSpan: element?.attributes?.colspan,
rowSpan: element?.attributes?.rowspan,
},
});
}
// 之后
node: {
props: ({ element }) => ({
colSpan: element?.attributes?.colspan,
rowSpan: element?.attributes?.rowspan,
});
}
PlateElement、PlateLeaf、PlateText 的 asChild prop,改用 as prop。PlateElement、PlateLeaf、PlateText 的 elementToAttributes、leafToAttributes、textToAttributes props。DefaultElement、DefaultLeaf、DefaultText,改用 PlateElement、PlateLeaf、PlateText。PlateRenderElementProps、PlateRenderLeafProps、PlateRenderTextProps,改用 PlateElementProps、PlateLeafProps、PlateTextProps。PlateElement、PlateLeaf、PlateText 移至 @udecode/plate-core。若从 @udecode/plate 导入则无需迁移。#4225 by @bbyiringiro –
hocuspocusProviderOptions 替换为新的 providers 数组。示例如下。之前:
YjsPlugin.configure({
options: {
cursorOptions: {
/* ... */
},
hocuspocusProviderOptions: {
url: 'wss://hocuspocus.example.com',
name: 'document-1',
// ... 其他 Hocuspocus 选项
},
},
});
之后(仅 Hocuspocus):
YjsPlugin.configure({
options: {
cursors: {
/* ... */
},
providers: [
{
type: 'hocuspocus',
options: {
url: 'wss://hocuspocus.example.com',
name: 'document-1',
// ... 其他 Hocuspocus 选项
},
},
],
},
});
之后(Hocuspocus + WebRTC):
YjsPlugin.configure({
options: {
cursors: {
/* ... */
},
providers: [
{
type: 'hocuspocus',
options: {
url: 'wss://hocuspocus.example.com',
name: 'document-1',
},
},
{
type: 'webrtc',
options: {
roomName: 'document-1',
// signaling: ['wss://signaling.example.com'], // 可选
},
},
],
},
});
UnifiedProvider 接口,支持自定义 provider 实现(如 IndexedDB 用于离线持久化)。cursorOptions 重命名为 cursors。yjsOptions 合并至 options。
yjsOptions 下的选项直接移至主 options 对象。YjsAboveEditable。现在需要手动调用 init 和 destroy:React.useEffect(() => {
if (!mounted) return;
// 初始化 Yjs 连接和同步
editor.getApi(YjsPlugin).yjs.init({
id: roomName, // 或你的文档标识符
value: INITIAL_VALUE, // 编辑器初始内容
});
// 组件卸载时销毁连接
return () => {
editor.getApi(YjsPlugin).yjs.destroy();
};
}, [editor, mounted, roomName]); // 添加相关依赖
#4174 by @felixfeng33 – #### 新特性
<u>underline</u>slate nodes => MDAST nodes => markdown stringallowedNodes:白名单特定节点disallowedNodes:黑名单特定节点allowNode:自定义过滤函数rules 选项用于自定义序列化和反序列化规则,包括自定义 mdx 支持remarkPlugins 选项以使用 remark 插件插件选项
移除的选项:
elementRules 改用 rulestextRules 改用 rulesindentList 现自动检测是否使用了 IndentList 插件splitLineBreaks 仅用于反序列化elementRules 和 textRules 选项
rules.key.deserialize迁移示例:
export const markdownPlugin = MarkdownPlugin.configure({
options: {
disallowedNodes: [SuggestionPlugin.key],
rules: {
// 对应 textRules
[BoldPlugin.key]: {
mark: true,
deserialize: (mdastNode) => ({
bold: true,
text: node.value || '',
}),
},
// 对应 elementRules
[EquationPlugin.key]: {
deserialize: (mdastNode, options) => ({
children: [{ text: '' }],
texExpression: node.value,
type: EquationPlugin.key,
}),
},
},
remarkPlugins: [remarkMath, remarkGfm],
},
});
editor.api.markdown.deserialize 中的 processor
remarkPluginsserializeMdNodes
editor.markdown.serialize({ value: nodes })SerializeMdOptions 因采用新序列化流程
slate nodes => mdslate nodes => md-ast => mdnodesbreakTagcustomNodesignoreParagraphNewlinelistDepthmarkFormatsulListStyleTypesignoreSuggestionType迁移 SerializeMdOptions.customNodes 和 SerializeMdOptions.nodes 的示例:
export const markdownPlugin = MarkdownPlugin.configure({
options: {
rules: {
// 忽略所有 `insert` 类型的建议
[SuggestionPlugin.key]: {
mark: true,
serialize: (slateNode: TSuggestionText, options): mdast.Text => {
const suggestionData = options.editor
.getApi(SuggestionPlugin)
.suggestion.suggestionData(node);
return suggestionData?.type === 'insert'
? { type: 'text', value: '' }
: { type: 'text', value: node.text };
},
},
// 对应 elementRules
[EquationPlugin.key]: {
serialize: (slateNode) => ({
type: 'math',
value: node.texExpression,
}),
},
},
remarkPlugins: [remarkMath, remarkGfm],
},
});
#4122 by @zbeyens – 从 prismjs 迁移至 highlight.js + lowlight 实现语法高亮。
CodeBlockPlugin:移除 prism 选项,改用 lowlight 选项:import { all, createLowlight } from 'lowlight';
const lowlight = createLowlight(all);
CodeBlockPlugin.configure({
options: {
lowlight,
},
});
defaultLanguagesyntax 选项。省略 lowlight 选项即可禁用语法高亮。syntaxPopularFirst 选项。在自定义组件中控制此行为。useCodeBlockCombobox、useCodeBlockElement、useCodeSyntaxLeaf、useToggleCodeBlockButton。相关逻辑已移至组件中。#4064 by @felixfeng33 – 本次重写移除了评论插件的 UI 逻辑(无头化)。
插件选项
options.commentsoptions.myUserIdoptions.users组件
CommentDeleteButtonCommentEditActionsCommentEditButtonCommentEditCancelButtonCommentEditSaveButtonCommentEditTextareaCommentNewSubmitButtonCommentNewTextareaCommentResolveButtonCommentsPositionerCommentUserNameAPI
findCommentNode → api.comment.node()findCommentNodeById → api.comment.node({ id })getCommentNodeEntries → api.comment.nodes()getCommentNodesById → api.comment.nodes({ id })removeCommentMark → tf.comment.remove()unsetCommentNodesById → tf.comment.unsetMark({ id })getCommentFragmentgetCommentUrlgetElementAbsolutePositiongetCommentPositiongetCommentCount 以排除草稿评论状态管理
CommentProvider - 用户应自行实现状态管理 – block-discussion.tsxuseHooksComments 移至 UI 注册表 – comments-plugin.tsxuseActiveCommentNodeuseCommentsResolveduseCommentAddButtonuseCommentItemContentuseCommentLeafuseCommentsShowResolvedButtonuseFloatingCommentsContentStateuseFloatingCommentsState类型
CommentUserTComment 移至 UI 注册表 – comment.tsx#4064 by @felixfeng33 – 注意:此插件目前处于实验阶段,可能在不升级主版本的情况下引入破坏性变更。
findSuggestionNode 改用 findSuggestionProps.tsaddSuggestionMark.tsuseHooksSuggestion.ts 因我们已更新 activeId 逻辑不再依赖 useEditorSelectorzustand-x@6
eventEditorSelectors -> EventEditorStore.geteventEditorActions -> EventEditorStore.setuseEventEditorSelectors -> useEventEditorValue(key)jotai-x@2
usePlateEditorStore -> usePlateStoreusePlateActions -> usePlateSeteditor.setPlateState,改用 usePlateSetusePlateSelectors -> usePlateValueusePlateStates -> usePlateStateeditor.useOption, ctx.useOption -> usePluginOption(plugin, key, ...args)editor.useOptions, ctx.useOptions -> usePluginOption(plugin, 'state')usePluginOptions(plugin, selector) 用于选择插件选项(Zustand 方式)。extendOptions 向插件添加选择器。这些选择器与选项状态混合,可能导致冲突和混淆。
extendSelectorsplugin.selectors 而非 plugin.options 中,但访问方式不变:使用 editor.getOption(plugin, 'selectorName')、ctx.getOption('selectorName') 或上述钩子。PluginConfig 的第二个泛型参数中,我们新增第五个泛型参数用于此。// 之前:
export type BlockSelectionConfig = PluginConfig<
'blockSelection',
{ selectedIds?: Set<string>; } & BlockSelectionSelectors,
>;
// 之后:
export type BlockSelectionConfig = PluginConfig<
'blockSelection',
{ selectedIds?: Set<string>; },
{}, // API
{}, // Transforms
BlockSelectionSelectors, // Selectors
}>