platejs
Bug Fixes
- Updated
@platejs/core,@platejs/slate,@platejs/utils.
@platejs/slate
Bug Fixes
- Updated
slate-react. (ce9ec87)
@platejs/utils
Bug Fixes
- Updated
@platejs/core,@platejs/slate.
platejs
@platejs/core, @platejs/slate, @platejs/utils.@platejs/slate
slate-react. (ce9ec87)@platejs/utils
@platejs/core, @platejs/slate.@platejs/ai
@platejs/markdown.@platejs/markdown
resourceLink when serializing bare autolink literals (#4972)CHANGELOG · v53.0.3...v53.0.4 · By @ajmnz
@platejs/ai
aiChat.stop() stops generation (#4945)@platejs/link
platejs
@platejs/utils.@platejs/suggestion
@platejs/utils
@platejs/list
normalizeListStart to skip unordered list items and resume ordered list numbering past same-indent unordered siblings (#4954)CHANGELOG · v53.0.1...v53.0.2 · By @dylans
@platejs/media
CHANGELOG · v53.0.0...v53.0.1 · By @zbeyens
@platejs/autoformat
Deprecate @platejs/autoformat. Markdown shortcuts and text substitutions are now authored as inputRules on each feature plugin, and AutoformatPlugin remains only as an inert compatibility export. (#4941)
Migration:
AutoformatPlugin from your plugins and replace @platejs/autoformat after migrating rules.AutoformatRule with the matching rule factory on the plugin that owns the feature. See the table below.createTextSubstitutionInputRule registered on a local createSlatePlugin.rules[].query with enabled on the rule factory call. Replace the global code-block guard with a per-plugin enabled check.enableUndoOnDelete — undo-on-delete is the built-in behavior.AutoformatRule definitions with createRuleFactory from platejs.1// Before
2import { AutoformatPlugin } from "@platejs/autoformat";
3
4const editor = createPlateEditor({
5 plugins: [
6 AutoformatPlugin.configure({
7 options: {
8 enableUndoOnDelete: true,
9 rules: [
10 { match: "# ", mode: "block", type: KEYS.h1 },
11 { match: "**", mode: "mark", type: KEYS.bold },
12 {
13 match: "* ",
14 mode: "block",
15 type: "list",
16 format: (editor) =>
17 toggleList(editor, { listStyleType: KEYS.ul }),
18 },
19 ],
20 },
21 }),
22 ],
23});
24
25// After
26import { BoldRules } from "@platejs/basic-nodes";
27import { BoldPlugin } from "@platejs/basic-nodes/react";
28import { HeadingRules } from "@platejs/basic-nodes";
29import { H1Plugin } from "@platejs/basic-nodes/react";
30import { BulletedListRules } from "@platejs/list";
31import { ListPlugin } from "@platejs/list/react";
32
33const editor = createPlateEditor({
34 plugins: [
35 H1Plugin.configure({ inputRules: [HeadingRules.markdown()] }),
36 BoldPlugin.configure({
37 inputRules: [BoldRules.markdown({ variant: "*" })],
38 }),
39 ListPlugin.configure({
40 inputRules: [BulletedListRules.markdown({ variant: "-" })],
41 }),
42 ],
43});@platejs/basic-nodes| Old rule | New rule |
|---|---|
{ match: '# '..'###### ', mode: 'block', type: KEYS.h1..h6 } | HxPlugin.configure({ inputRules: [HeadingRules.markdown()] }) — register on each H1Plugin..H6Plugin |
{ match: '> ', mode: 'block', type: KEYS.blockquote } | BlockquotePlugin.configure({ inputRules: [BlockquoteRules.markdown()] }) |
{ match: ['---', '—-', '___ '], mode: 'block', type: KEYS.hr } | HorizontalRulePlugin.configure({ inputRules: [HorizontalRuleRules.markdown({ variant: '-' }), HorizontalRuleRules.markdown({ variant: '_' })] }) |
@platejs/basic-nodes| Old rule | New rule | Owning plugin |
|---|---|---|
{ match: '**', mode: 'mark', type: KEYS.bold } | BoldRules.markdown({ variant: '*' }) | BoldPlugin |
{ match: '__', mode: 'mark', type: KEYS.underline } | UnderlineRules.markdown() | UnderlinePlugin |
{ match: '*', mode: 'mark', type: KEYS.italic } | ItalicRules.markdown({ variant: '*' }) | ItalicPlugin |
{ match: '_', mode: 'mark', type: KEYS.italic } | ItalicRules.markdown({ variant: '_' }) | ItalicPlugin |
{ match: '`', mode: 'mark', type: KEYS.code } | CodeRules.markdown() | CodePlugin |
{ match: '~~', mode: 'mark', type: KEYS.strikethrough } | StrikethroughRules.markdown() | StrikethroughPlugin |
{ match: '~', mode: 'mark', type: KEYS.sub } | SubscriptRules.markdown() | SubscriptPlugin |
{ match: '^', mode: 'mark', type: KEYS.sup } | SuperscriptRules.markdown() | SuperscriptPlugin |
{ match: '==', mode: 'mark', type: KEYS.highlight } | HighlightRules.markdown({ variant: '==' }) | HighlightPlugin |
{ match: '≡', mode: 'mark', type: KEYS.highlight } | HighlightRules.markdown({ variant: '≡' }) | HighlightPlugin |
{ match: '***', mode: 'mark', type: [bold, italic] } | MarkComboRules.markdown({ variant: 'boldItalic' }) | BoldPlugin |
{ match: '__*', mode: 'mark', type: [underline, italic] } | MarkComboRules.markdown({ variant: 'italicUnderline' }) | BoldPlugin |
{ match: '__**', mode: 'mark', type: [underline, bold] } | MarkComboRules.markdown({ variant: 'boldUnderline' }) | BoldPlugin |
{ match: '___***', mode: 'mark', type: [underline, bold, italic] } | MarkComboRules.markdown({ variant: 'boldItalicUnderline' }) | BoldPlugin |
Register each family on its owning plugin:
1BoldPlugin.configure({
2 inputRules: [
3 BoldRules.markdown({ variant: "*" }),
4 BoldRules.markdown({ variant: "_" }),
5 MarkComboRules.markdown({ variant: "boldItalic" }),
6 MarkComboRules.markdown({ variant: "boldUnderline" }),
7 MarkComboRules.markdown({ variant: "boldItalicUnderline" }),
8 MarkComboRules.markdown({ variant: "italicUnderline" }),
9 ],
10});@platejs/code-block| Old rule | New rule |
|---|---|
{ match: '```', mode: 'block', type: KEYS.codeBlock, format: insertEmptyCodeBlock } | CodeBlockPlugin.configure({ inputRules: [CodeBlockRules.markdown({ on: 'match' })] }) |
@platejs/list and @platejs/list-classic| Old rule | New rule |
|---|---|
{ match: ['- ', '* '], mode: 'block', format: toggleList(..., { listStyleType: KEYS.ul }) } | BulletedListRules.markdown({ variant: '-' }), BulletedListRules.markdown({ variant: '*' }) |
{ match: /^\d+\.$ |^\d+\)$ /, matchByRegex: true, format: toggleList(..., { listStyleType: KEYS.ol }) } | OrderedListRules.markdown({ variant: '.' }), OrderedListRules.markdown({ variant: ')' }) |
{ match: '[] ', mode: 'block', format: toggleList(..., { listStyleType: KEYS.listTodo }) } | TaskListRules.markdown({ checked: false }) |
{ match: '[x] ', mode: 'block', format: toggleList + setNodes({ checked: true }) } | TaskListRules.markdown({ checked: true }) |
1ListPlugin.configure({
2 inputRules: [
3 BulletedListRules.markdown({ variant: "-" }),
4 BulletedListRules.markdown({ variant: "*" }),
5 OrderedListRules.markdown({ variant: "." }),
6 OrderedListRules.markdown({ variant: ")" }),
7 TaskListRules.markdown({ checked: false }),
8 TaskListRules.markdown({ checked: true }),
9 ],
10});Replace @platejs/list with @platejs/list-classic imports when using the classic list model. The factory names are identical.
@platejs/math| Old rule | New rule |
|---|---|
Inline equation $…$ | InlineEquationPlugin.configure({ inputRules: [MathRules.markdown({ variant: '$' })] }) |
Block equation $$…$$ | EquationPlugin.configure({ inputRules: [MathRules.markdown({ on: 'break', variant: '$$' })] }) |
@platejs/link| Old behavior | New rule |
|---|---|
[text](url) markdown | LinkRules.markdown() |
| Autolink on paste | LinkRules.autolink({ variant: 'paste' }) |
| Autolink on space | LinkRules.autolink({ variant: 'space' }) |
| Autolink on Enter | LinkRules.autolink({ variant: 'break' }) |
1LinkPlugin.configure({
2 inputRules: [
3 LinkRules.markdown(),
4 LinkRules.autolink({ variant: "paste" }),
5 LinkRules.autolink({ variant: "space" }),
6 LinkRules.autolink({ variant: "break" }),
7 ],
8});Move these to a local createSlatePlugin with createTextSubstitutionInputRule:
1import {
2 createSlatePlugin,
3 createTextSubstitutionInputRule,
4 KEYS,
5} from "platejs";
6
7const isTextSubstitutionBlocked = (editor) =>
8 editor.api.some({ match: { type: [editor.getType(KEYS.codeBlock)] } });
9
10const ShortcutsPlugin = createSlatePlugin({
11 key: "shortcuts",
12 inputRules: [
13 createTextSubstitutionInputRule({
14 enabled: ({ editor }) => !isTextSubstitutionBlocked(editor),
15 patterns: [
16 { format: "→", match: "->" },
17 { format: "⇒", match: "=>" },
18 { format: "½", match: "1/2" },
19 { format: "™", match: ["(tm)", "(TM)"] },
20 { format: ["“", "”"], match: '"' },
21 ],
22 }),
23 ],
24});Each pattern set is just data — autoformatArrow, autoformatLegal, autoformatMath, autoformatPunctuation, autoformatSmartQuotes, and autoformatLegalHtml from the old package map 1:1 onto patterns arrays. AutoformatKit in the Plate registry is pre-built with all of them.
Old AutoformatRule objects have no direct replacement. Build a rule family with createRuleFactory:
1import { createRuleFactory } from "platejs";
2
3const MyRules = {
4 markdown: createRuleFactory({
5 type: "blockMatch",
6 match: "!! ",
7 format: "my-block",
8 }),
9};
10
11MyPlugin.configure({ inputRules: [MyRules.markdown()] });enableUndoOnDelete — removed. Backspace on a rule-inserted node restores the source text by default.rules[].query — replaced by enabled on the rule factory call.rules[].preFormat / rules[].format — replaced by rule-family format and resolve callbacks inside createRuleFactory.rules[].trigger — rule families set their own trigger. Override it with the trigger option on a custom createRuleFactory call.See the Autoformat doc for the kit path and the Plugin Input Rules guide for the full runtime.
@platejs/basic-nodes
Store blockquotes as container blocks with block children. Lift every selected nested quoted block one level on Shift+Tab. Reset headings to paragraphs on Backspace at block start before any merge. (#4941)
Migration:
editor.tf.blockquote.toggle() to wrap or unwrap blocks instead of retagging one text block in place.Backspace instead of jumping out of the quote.Backspace at the start of a heading now resets the heading to a paragraph before any merge.1// Before
2{ type: 'blockquote', children: [{ text: 'Quote' }] }
3
4// After
5{
6 type: 'blockquote',
7 children: [{ type: 'p', children: [{ text: 'Quote' }] }],
8}@platejs/code-block
Backspace at the start of a non-empty first code line inside the code block. Merge an empty inner code line into the previous code line instead of unwrapping the block. (#4941)@platejs/markdown
Round-trip blockquotes as nested block content instead of flat newline-packed text. Serialize image titles from node.title instead of copying the caption into the markdown title slot. Preserve MDX media attribute expressions during markdown serialization instead of stringifying them into JSON text. Serialize plain URL links back to bare URL markdown instead of bracket-link form. Round-trip footnote references and definitions as dedicated footnote nodes instead of collapsing them to plain-text fallback. (#4941)
Migration:
blockquote.children to contain block nodes such as paragraphs and lists., set node.title. Images without a title now serialize as .width={640}, expect those expressions to stay as expressions instead of turning into quoted JSON.https://platejs.org now serialize as bare URLs instead of [https://platejs.org](https://platejs.org).@platejs/footnote and include BaseFootnoteReferencePlugin and BaseFootnoteDefinitionPlugin so footnote nodes have real editor semantics instead of falling back to unknown node types.1// Before
2{ type: 'blockquote', children: [{ text: 'Quote\\nNext line' }] }
3
4// After
5{
6 type: 'blockquote',
7 children: [
8 { type: 'p', children: [{ text: 'Quote' }] },
9 { type: 'p', children: [{ text: 'Next line' }] },
10 ],
11}Write canonical date nodes as <date value="..."/> and round-trip normalized media embed metadata (#4941)
Preserve unknown MDX and raw HTML block source more faithfully during markdown deserialization fallback (#4941)
@platejs/table
selectAll from the current table to the whole document. (#4941)@platejs/core
lift as a break and delete rule action for blocks that should leave one ancestor level instead of resetting or exiting. Reset the trailing block to a paragraph when splitReset handles selected heading text. (#4941)Add createRuleFactory for building input rule families with overridable defaults and required options (#4941)
Add useNavigationHighlight(path) for React node components that need the current navigation-feedback target without reading plugin options directly (#4941)
@platejs/footnote
FootnoteReferencePlugin, FootnoteDefinitionPlugin, and FootnoteInputPlugin for real footnote nodes and inline [^ combobox insertion in Plate editors. (#4941)@platejs/date
YYYY-MM-DD values and preserve unparseable legacy text as fallback data (#4941)@platejs/link
@platejs/list
variant and checked options (#4941)@platejs/list-classic
variant and checked options (#4941)@platejs/media
Support allowlisted Twitter/X embed snippet extraction in media embed URL transforms (#4941)
Normalize supported media embeds into canonical provider metadata and preserve source URLs for embed editing (#4941)
@platejs/slate
slate, slate-dom. (081cbe9)@platejs/toc
Add active section state to useTocElementState so TOC elements can mark the current heading while the document scrolls (#4941)
Fix TOC activation to navigate without entering block-selection mode (#4941)
@platejs/utils
KEYS.footnoteDefinition, KEYS.footnoteReference, and KEYS.footnoteInput (#4941)CHANGELOG · v52.3.22...v53.0.0 · By @zbeyens, @github-actions[bot]
@platejs/ai
@platejs/markdown.@platejs/markdown
CHANGELOG · v52.3.21...v52.3.22 · By @zbeyens
platejs
@platejs/core, @platejs/slate, @platejs/utils.@platejs/slate
slate, slate-dom, slate-react. (0af3236)@platejs/utils
@platejs/core, @platejs/slate.@platejs/ai
@platejs/markdown.@platejs/markdown
1 losing their numbering after editor.tf.setValue() (#4926)CHANGELOG · v52.3.18...v52.3.19 · By @zbeyens
@platejs/ai
@platejs/table.@platejs/table
ArrowUp and ArrowDown table navigation to avoid the transient caret flash when moving between table cells. (#4923)CHANGELOG · v52.3.17...v52.3.18 · By @hhhjin
@platejs/ai
@platejs/table.@platejs/link
Fixed custom isUrl handling so it can reject internal paths like /docs and anchor links like #top instead of those shortcuts always being accepted. (#4919)
Fixed link validation so text starting with // is no longer treated as an internal path. This stops comment-style paste content from being autolinked by mistake, including inside code blocks. (#4917)
@platejs/table
CHANGELOG · v52.3.16...v52.3.17 · By @zbeyens
@platejs/code-block
@platejs/code-block release metadata. (3465ee1)@platejs/core
@platejs/core to refresh the release graph for downstream packages. (#4915)@platejs/dnd
@platejs/dnd release metadata. (3465ee1)platejs
@platejs/core, @platejs/utils.@platejs/utils
@platejs/core.CHANGELOG · v52.3.15...v52.3.16 · By @zbeyens
@platejs/core
Added normalizeStaticValue to @platejs/core for normalizing example editor values with deterministic node IDs and stable numeric createdAt metadata before SSR hydration. (#4912)
1 ```ts
2 import { normalizeStaticValue } from "@platejs/core";
3
4 const value = normalizeStaticValue(exampleValue);
5 ```@platejs/dnd
@platejs/dnd by returning inert drag-and-drop connectors when DOM DnD is unavailable, preventing Expected drag drop context during SSR builds. (#4912)CHANGELOG · v52.3.14...v52.3.15 · By @zbeyens
@platejs/code-block
formatCodeBlock to rewrite formatted code into real code_line nodes and trigger a redecorate pass so syntax highlighting persists after formatting. (#4907)CHANGELOG · v52.3.13...v52.3.14 · By @zbeyens
@platejs/core
perf(static): avoid O(n²) findPath in PlateStatic by passing pre-computed path (#4903)
Pass pre-computed path through PlateStatic component tree instead of calling editor.api.findPath() per node. For 1,872 nodes: paragraph-only 593ms → 68.6ms (8.6x), full plugins 1,661ms → 892ms (1.9x).
CHANGELOG · v52.3.12...v52.3.13 · By @liangzr
@platejs/ai
@platejs/slate
CHANGELOG · v52.3.11...v52.3.12 · By @zbeyens
platejs
platejs can resolve the current @platejs/* package graph without nested stale installs. (4af5ea4)@platejs/utils
4af5ea4)CHANGELOG · v52.3.10...v52.3.11 · By @zbeyens
@platejs/ai
platejs build edge during package builds (#4897)@platejs/autoformat
platejs build edge during package builds (#4897)@platejs/basic-nodes
platejs build edge during package builds (#4897)@platejs/basic-styles
platejs build edge during package builds (#4897)@platejs/callout
platejs build edge during package builds (#4897)@platejs/caption
platejs build edge during package builds (#4897)@platejs/code-block
platejs build edge during package builds (#4897)@platejs/code-drawing
platejs build edge during package builds (#4897)@platejs/combobox
platejs build edge during package builds (#4897)@platejs/comment
platejs build edge during package builds (#4897)@platejs/csv
platejs build edge during package builds (#4897)@platejs/cursor
platejs build edge during package builds (#4897)@platejs/date
platejs build edge during package builds (#4897)@platejs/diff
platejs build edge during package builds (#4897)@platejs/dnd
platejs build edge during package builds (#4897)@platejs/docx
platejs build edge during package builds (#4897)@platejs/docx-io
platejs build edge during package builds (#4897)@platejs/emoji
platejs build edge during package builds (#4897)@platejs/excalidraw
platejs build edge during package builds (#4897)@platejs/find-replace
platejs build edge during package builds (#4897)@platejs/floating
platejs build edge during package builds (#4897)@platejs/indent
platejs build edge during package builds (#4897)@platejs/juice
platejs build edge during package builds (#4897)@platejs/layout
platejs build edge during package builds (#4897)@platejs/link
platejs build edge during package builds (#4897)@platejs/list
platejs build edge during package builds (#4897)@platejs/list-classic
platejs build edge during package builds (#4897)@platejs/markdown
platejs build edge during package builds (#4897)@platejs/math
platejs build edge during package builds (#4897)@platejs/media
platejs build edge during package builds (#4897)@platejs/mention
platejs build edge during package builds (#4897)@platejs/playwright
platejs build edge during package builds (#4897)@platejs/resizable
platejs build edge during package builds (#4897)@platejs/selection
platejs build edge during package builds (#4897)@platejs/slash-command
platejs build edge during package builds (#4897)@platejs/suggestion
platejs build edge during package builds (#4897)@platejs/tabbable
platejs build edge during package builds (#4897)@platejs/table
platejs build edge during package builds (#4897)@platejs/tag
platejs build edge during package builds (#4897)@platejs/toc
platejs build edge during package builds (#4897)@platejs/toggle
platejs build edge during package builds (#4897)@platejs/yjs
platejs build edge during package builds (#4897)CHANGELOG · v52.3.9...v52.3.10 · By @zbeyens
@platejs/code-block
@platejs/core
editor.api.redecorate() on the base slate extension API so shared plugins can call it without local casts. (d5dfd21)CHANGELOG · v52.3.8...v52.3.9 · By @hhhjin, @zbeyens
@platejs/ai
replacePlaceholders replacing only the first {prompt} and markdown placeholder occurrence in AI prompt templates (#4882)@platejs/csv
@platejs/csv without failing on a CommonJS named export. (#4890)@platejs/docx
shp inside longer tokens such as shppict (#4882)@platejs/docx-io
htmlToDocxBlob failing TypeScript 6 BlobPart checks when wrapping generated Uint8Array output. (#4891)@platejs/layout
@platejs/suggestion
CHANGELOG · v52.3.7...v52.3.8 · By @zbeyens
@platejs/markdown
CHANGELOG · v52.3.6...v52.3.7 · By @hhhjin
@platejs/docx-io
Fixed Mammoth comment preprocessing so block-level comment text keeps spacing instead of collapsing words together during DOCX import. (#4876)
Fixed decimal-bracket-end ordered lists to keep decimal DOCX numbering instead of falling back to the package default ordered style. (#4876)
Fixed HTML-to-DOCX list rendering so whitespace-only nodes around list items no longer drop visible list item text in generated documents. (#4876)
@platejs/selection
@platejs/table
set_selection. (#4872)@platejs/markdown
CHANGELOG · v52.3.4...v52.3.5 · By @zbeyens
@platejs/autoformat
match, trigger, type, and text format so as const rule definitions typecheck cleanly. (#4857)@platejs/core
Fix PlateSlate so it passes the Slate remount key directly instead of spreading key through JSX props. (#4857)
Fix usePlateStore so it no longer relies on a conditional hook path that breaks React Compiler. (#4857)
Fix usePluginOption(plugin, 'state') so it returns the plugin option state instead of reporting an undefined option. (#4857)
Update internal @udecode/* dependency ranges to workspace references. (#4857)
platejs
@platejs/* and @udecode/* dependency ranges to workspace references. (#4857)@platejs/slate
Fixed editor.tf.duplicateNodes({ block: true }) to duplicate the selected block even when nodes is omitted. (#4857)
Fixed withHistory(createEditor()) legacy method sync so editor, editor.api, and editor.tf all use the history-aware apply, undo, and redo methods. (#4857)
Fixed queryEditor, isAt, and editor.api.descendant so bottom-up location checks, point start/end checks, and non-path descendant searches behave consistently. (#4857)
Update internal @udecode/* dependency ranges to workspace references. (#4857)
@udecode/cn
@udecode/* dependency ranges to workspace references. (#4857)@udecode/react-utils
Fixed createPrimitiveComponent so setProps is applied without leaking onto DOM elements. (#4857)
Fixed createPrimitiveComponent to preserve merged hook and consumer style props instead of overwriting hook styles when a consumer passes style.
Update internal @udecode/* dependency ranges to workspace references. (#4857)
@udecode/utils
escapeRegExp() to stop escaping plain s characters and only escape actual regular-expression syntax. (#4857)@platejs/utils
@udecode/* dependency ranges to workspace references. (#4857)CHANGELOG · v52.3.3...v52.3.4 · By @zbeyens
@platejs/test-utils
2f71954)@platejs/utils
2f71954)CHANGELOG · v52.3.1...v52.3.2 · By @zbeyens
@platejs/markdown
@platejs/code-drawing
@platejs/docx-io
Add DOCX import/export package: (#4814)
Import:
importDocx: Convert DOCX files to Plate nodes with comment extractionExport:
exportToDocx: Convert Plate content to DOCX blobdownloadDocx: Download DOCX filesexportEditorToDocx: Export and download in one callDocxExportPlugin: Plugin with editor.api.docxExport and editor.tf.docxExport methodsDOCX_EXPORT_STYLES: Default CSS styles for Word renderingDOCX Static Components (in existing static files):
CalloutElementDocxCodeBlockElementDocx, CodeLineElementDocx, CodeSyntaxLeafDocxColumnElementDocx, ColumnGroupElementDocxEquationElementDocx, InlineEquationElementDocxTocElementDocx@platejs/ai
Upgraded AI SDK from v5 to v6: (#4800)
ai peer dependency to ^6.0.0@ai-sdk/react peer dependency to ^3.0.0Enhanced AI capabilities with better table cell handling:
applyTableCellSuggestion utility for handling single-cell table operationsnestedContainerUtils for managing nested containers in table cellsgetMarkdown with improved table structure handling and better cell content serializationapplyAISuggestions with more robust cell manipulation support@platejs/markdown
Enhanced table cell serialization to support multiple blocks within cells: (#4800)
<br/> separators between multiple blocks when serializing to markdown@platejs/selection
Added disableSelectAll option to BlockSelectionPlugin. Set to true to disable the plugin's custom selectAll (Cmd+A) behavior and use the editor's default behavior instead. (#4799)
1 ```ts
2 BlockSelectionPlugin.configure({
3 options: { disableSelectAll: true },
4 });
5 ```@platejs/combobox
Add userId option to editor for collaborative features (#4792)
userId option to usePlateEditor/createSlateEditor optionseditor.meta.userId for accessing the current user IDgetUserId option from TriggerComboboxPluginOptions. Use editor.meta.userId instead.Migration:
1// Before
2MentionPlugin.configure({
3 options: {
4 getUserId: (editor) => "123",
5 },
6});
7
8// After
9const editor = usePlateEditor({
10 plugins: [MentionPlugin],
11 userId: "123",
12});@platejs/core
Add userId option to editor for collaborative features (#4792)
userId option to usePlateEditor/createSlateEditor optionseditor.meta.userId for accessing the current user IDgetUserId option from TriggerComboboxPluginOptions. Use editor.meta.userId instead.Migration:
1// Before
2MentionPlugin.configure({
3 options: {
4 getUserId: (editor) => "123",
5 },
6});
7
8// After
9const editor = usePlateEditor({
10 plugins: [MentionPlugin],
11 userId: "123",
12});@platejs/combobox
Add getUserId option to TriggerComboboxPluginOptions to fix combobox popover opening for all users in Yjs collaboration mode (#4762)
When a user types a trigger character (e.g. / or @), the combobox input now stores the creator's userId. Only the creator will see the auto-focused combobox popover.
1SlashPlugin.configure({
2 options: {
3 getUserId: (editor) => editor.getOption(YjsPlugin, "userId"),
4 },
5});
6
7MentionPlugin.configure({
8 options: {
9 getUserId: (editor) => editor.getOption(YjsPlugin, "userId"),
10 },
11});@platejs/yjs
Add userId option to YjsPlugin for combobox collaboration support (#4762)
1YjsPlugin.configure({
2 options: {
3 userId: user?.id,
4 },
5});@platejs/ai
@platejs/autoformat
@platejs/basic-nodes
@platejs/basic-styles
@platejs/callout
@platejs/caption
@platejs/code-block
@platejs/combobox
@platejs/comment
@platejs/core
@platejs/csv
@platejs/cursor
@platejs/date
@platejs/diff
@platejs/dnd
@platejs/docx
@platejs/emoji
@platejs/excalidraw
@platejs/find-replace
@platejs/floating
@platejs/indent
@platejs/juice
@platejs/layout
@platejs/link
@platejs/list
@platejs/list-classic
@platejs/markdown
@platejs/math
@platejs/media
@platejs/mention
platejs
@platejs/playwright
@platejs/resizable
@platejs/selection
@platejs/slash-command
@platejs/suggestion
@platejs/tabbable
@platejs/table
@platejs/tag
@platejs/toc
@platejs/toggle
@udecode/cn
@udecode/react-hotkeys
@udecode/react-utils
@platejs/utils
@platejs/yjs
CHANGELOG · v52.0.10...v52.0.11 · By @zbeyens
@platejs/ai
@platejs/yjs
@platejs/markdown
CHANGELOG · v52.0.3...v52.0.4 · By @hhhjin
@platejs/emoji
CHANGELOG · v52.0.1...v52.0.2 · By @zbeyens
@platejs/ai
@platejs/autoformat
@platejs/basic-nodes
@platejs/basic-styles
@platejs/callout
@platejs/caption
@platejs/code-block
@platejs/combobox
@platejs/comment
@platejs/core
@platejs/csv
@platejs/cursor
@platejs/date
@platejs/diff
@platejs/dnd
@platejs/docx
@platejs/emoji
@platejs/excalidraw
@platejs/find-replace
@platejs/floating
@platejs/indent
@platejs/juice
@platejs/layout
@platejs/link
@platejs/list
@platejs/list-classic
@platejs/markdown
@platejs/math
@platejs/media
@platejs/mention
platejs
@platejs/playwright
@platejs/resizable
@platejs/selection
@platejs/slash-command
@platejs/slate
@platejs/suggestion
@platejs/tabbable
@platejs/table
@platejs/tag
@platejs/test-utils
@platejs/toc
@platejs/toggle
@udecode/cn
@udecode/react-hotkeys
@udecode/react-utils
@udecode/utils
@platejs/utils
@platejs/yjs
CHANGELOG · v52.0.0...v52.0.1 · By @zbeyens
@platejs/ai
@platejs/autoformat
@platejs/basic-nodes
@platejs/basic-styles
@platejs/callout
@platejs/caption
@platejs/code-block
@platejs/combobox
@platejs/comment
@platejs/core
@platejs/csv
@platejs/cursor
@platejs/date
@platejs/diff
@platejs/dnd
@platejs/docx
@platejs/emoji
@platejs/excalidraw
@platejs/find-replace
@platejs/floating
@platejs/indent
@platejs/juice
@platejs/layout
@platejs/link
@platejs/list
@platejs/list-classic
@platejs/markdown
@platejs/math
@platejs/media
@platejs/mention
platejs
@platejs/playwright
@platejs/resizable
@platejs/selection
@platejs/slash-command
@platejs/slate
@platejs/suggestion
@platejs/tabbable
@platejs/table
@platejs/tag
@platejs/test-utils
@platejs/toc
@platejs/toggle
@udecode/cn
@udecode/react-hotkeys
@udecode/react-utils
@udecode/utils
@platejs/utils
@platejs/yjs
CHANGELOG · v51.1.3...v52.0.0 · By @zbeyens
@platejs/cursor
@platejs/dnd
@platejs/toc
@udecode/react-hotkeys
CHANGELOG · v51.1.2...v51.1.3 · By @zbeyens
@platejs/ai
@platejs/autoformat
@platejs/basic-nodes
@platejs/basic-styles
@platejs/callout
@platejs/caption
@platejs/code-block
@platejs/combobox
@platejs/comment
@platejs/core
@platejs/csv
@platejs/cursor
@platejs/date
@platejs/diff
@platejs/dnd
@platejs/docx
@platejs/emoji
@platejs/excalidraw
@platejs/find-replace
@platejs/floating
@platejs/indent
@platejs/juice
@platejs/layout
@platejs/link
@platejs/list
@platejs/list-classic
@platejs/markdown
@platejs/math
@platejs/media
@platejs/mention
platejs
@platejs/playwright
@platejs/resizable
@platejs/selection
@platejs/slash-command
@platejs/slate
@platejs/suggestion
@platejs/tabbable
@platejs/table
@platejs/tag
@platejs/test-utils
@platejs/toc
@platejs/toggle
@udecode/cn
@udecode/react-hotkeys
@udecode/react-utils
@udecode/utils
@platejs/utils
@platejs/yjs
CHANGELOG · v51.1.1...v51.1.2 · By @zbeyens
@platejs/markdown
CHANGELOG · v51.1.0...v51.1.1 · By @tomdyqin
@platejs/core
Moved static rendering functionality to @platejs/core/static / platejs/static to make @platejs/core / platejs React-free. (#4695)
Migration
To migrate, update your imports from platejs to platejs/static for all static rendering features listed below:
createStaticEditor, CreateStaticEditorOptions - Create static editor instanceserializeHtml, SerializeHtmlOptions - Serialize editor content to HTML stringPlateStatic, PlateStaticProps - Main static editor componentSlateElement, SlateElementProps - Static element componentSlateText, SlateTextProps - Static text componentSlateLeaf, SlateLeafProps - Static leaf componentgetEditorDOMFromHtmlString@platejs/list
SlateRenderElementProps to use the new static export from platejs/static. (#4695)@platejs/core
getNodeDataAttributeKeys and keyToDataAttribute functions from static utilities to regular utilities to decouple React dependencies. (#4693)@platejs/core
editor.setOption to properly handle function values (#4691)CHANGELOG · v50.3.7...v50.3.8 · By @zbeyens
@platejs/ai
createZustandStore from platejs/react (#4689)@platejs/core
Decouple createSlateEditor from React: (#4689)
createZustandStore from @platejs/core (or platejs) is now a vanilla store without React-specific functionality (hooks).createZustandStore is now available in @platejs/core/react (or platejs/react). This is not part of our public API so it won't be a breaking change, but if you're using it, you'll need to import it from @platejs/core/react (or platejs/react) instead.@platejs/media
createZustandStore from platejs/react (#4689)@platejs/selection
onKeyDownSelecting callback to include editor parameter (#4673)@platejs/floating
Fix: Resolve infinite loop in useFloatingToolbar hook (v2) Problem: The floating toolbar was causing infinite re-renders under certain conditions, leading to performance issues and potential browser hangs. This occurred when users interacted with text selections while the toolbar was visible. (#4646)
WHY the change was made:
HOW a consumer should update their code:
CHANGELOG · v50.3.1...v50.3.2 · By @narraje
@platejs/dnd
CHANGELOG · v50.3.0...v50.3.1 · By @sneridagh
@platejs/yjs
CHANGELOG · v50.2.5...v50.2.6 · By @dpnova
@platejs/floating
CHANGELOG · v50.2.2...v50.2.3 · By @narraje
@platejs/ai
applyAISuggestions utility for applying AI-generated content as suggestions with diff tracking (#4626)replacePlaceholders template system supporting {prompt}, {block}, {blockSelection}, {editor} placeholdersacceptAIChat transform to handle transient suggestions properly_replaceIds tracking@platejs/diff
@platejs/markdown
plainMarks option to exclude specific marks from markdown serialization (#4626)@platejs/suggestion
SkipSuggestionDeletes utility to extract text while excluding removed suggestions (#4626)getTransientSuggestionKey and filtering optionsacceptSuggestion to support inline elements like linkstransient parameter to getSuggestionProps and suggestion.nodes() APIs@platejs/comment
getTransientCommentKey utility for temporary comments (#4626)@platejs/list
@platejs/selection
insertBlocksAndSelect to handle fragment insertion better (#4626)@platejs/ai
Added AI Comment functionality to provide AI-powered text feedback and suggestions.And upgrade to AI SDK 5. (#4587)
AI Comment Integration: New utilities for AI-generated comments on selected text
aiCommentToRange() - Convert AI comments to text ranges with proper block mappingfindTextRangeInBlock() - Find text ranges within blocks for accurate comment positioningEnhanced AI Chat: Improved chat functionality with comment support
toolName property in chat helpers for tracking AI toolsmode, toolName params to submitAIChattoolName plugin option.Text Matching: Advanced text matching algorithms
1// Convert AI comment to text range
2const range = aiCommentToRange(editor, {
3 blockId: 'block-1',
4 content: 'Selected text',
5 comment: 'Consider adding more detail here',
6});streamInsertChunk has been moved from @platejs/ai to @platejs/ai/react.getEditorPrompt has been moved from @platejs/ai/react to @platejs/ai.getMarkdown has been moved from @platejs/ai/react to @platejs/ai.promptTemplate and systemTemplate have been removed. They are now used directly in api/ai/command/route.ts.{selection} has been renamed to {blockSelection}.@platejs/comment
Enhanced comment plugin to support AI-generated comments. (#4587)
transient option to tf.unsetMark to allow removing all AI comments at once.@platejs/markdown
Added support for preserving block IDs in markdown serialization to enable AI comment tracking. (#4587)
serializeMd to support withBlockId option for maintaining block references1// Serialize with block IDs preserved
2const markdown = serializeMd(editor, {
3 withBlockId: true,
4});
5// Output: <block id="block-1">Content here</block>@platejs/selection
selectionFallback option to api.getNodes. (#4587)
selectionFallback is set to true, and no nodes are selected by blockSelection, the method will use the editor's original selection to retrieve blocks.@platejs/dnd
CHANGELOG · v49.2.21...v49.2.22 · By @delijah
@platejs/dnd
CHANGELOG · v49.2.19...v49.2.20 · By @delijah
@platejs/dnd
CHANGELOG · v49.2.18...v49.2.19 · By @delijah
@platejs/dnd
CHANGELOG · v49.2.17...v49.2.18 · By @delijah
@platejs/test-utils
JSX.IntrinsicElements, in order to avoid error messages on react jsx elements (#4578)CHANGELOG · v49.2.15...v49.2.16 · By @delijah
@platejs/test-utils
CHANGELOG · v49.2.12...v49.2.13 · By @delijah
@platejs/core
CHANGELOG · v49.2.10...v49.2.11 · By @delijah
@platejs/dnd
canDrop option of react-dnd (#4555)CHANGELOG · v49.2.9...v49.2.10 · By @delijah
@platejs/core
format OR mimeTypes option on ParserPlugin and also pass File mime type to parsers (#4553)CHANGELOG · v49.2.8...v49.2.9 · By @delijah
@platejs/core
Added onNodeChange and onTextChange callbacks to track editor operations: (#4549)
1 - `onNodeChange`: Called for node operations (insert, remove, set, merge, split, move)
2 - `onTextChange`: Called for text operations (insert, remove)
3
4 ```tsx
5 // Usage via Plate component
6 <Plate
7 onNodeChange={({ editor, node, operation, prevNode }) => {
8 console.log('Node changed:', { node, operation, prevNode });
9 }}
10 onTextChange={({ editor, node, operation, prevText, text }) => {
11 console.log('Text changed:', { text, prevText, operation });
12 }}
13 />;
14
15 // Usage via plugin
16 MyPlugin.configure({
17 handlers: {
18 onNodeChange: ({ node, operation, prevNode }) => {
19 // Handle node changes
20 },
21 onTextChange: ({ node, operation, prevText, text }) => {
22 // Handle text changes
23 },
24 },
25 });
26 ```CHANGELOG · v49.2.7...v49.2.8 · By @zbeyens
@platejs/dnd
CHANGELOG · v49.2.6...v49.2.7 · By @delijah
@platejs/core
inject.nodeProps from default element, preventing Error: Rendered more hooks than during the previous render.. (#4542)CHANGELOG · v49.2.5...v49.2.6 · By @zbeyens
@platejs/core
Error: Rendered more hooks than during the previous render. when updating the block type. (#4540)CHANGELOG · v49.2.4...v49.2.5 · By @zbeyens
@platejs/core
useFocusedLast hook to track the last focused editor (#4537)EventEditorPlugin to track the last focused editor in EventEditorStore@platejs/selection
duplicateBlockSelectionNodes by removing the nextBlock: true option (#4537)mod+d hotkey to duplicate selected blocks@platejs/slate
duplicateNodes to allow undefined at (#4537)nodes parameter instead of both nodes and atCHANGELOG · v49.2.3...v49.2.4 · By @zbeyens
@platejs/core
as-prop of PlateElement (#4531)CHANGELOG · v49.2.2...v49.2.3 · By @delijah
@platejs/dnd
isAboutToDrag state for better preview handling (#4528)@platejs/ai
@platejs/ai:
streamInsertChunk to only remove true empty paragraphs (no text content)SteamInsertChunkOptions → StreamInsertChunkOptions@platejs/layout:
withColumn@platejs/markdown:
customMdxDeserialize@platejs/layout
@platejs/ai:
streamInsertChunk to only remove true empty paragraphs (no text content)SteamInsertChunkOptions → StreamInsertChunkOptions@platejs/layout:
withColumn@platejs/markdown:
customMdxDeserialize@platejs/markdown
@platejs/ai:
streamInsertChunk to only remove true empty paragraphs (no text content)SteamInsertChunkOptions → StreamInsertChunkOptions@platejs/layout:
withColumn@platejs/markdown:
customMdxDeserialize@platejs/list
expandListItemsWithChildren to automatically include list item children when selecting blocks for operations like drag-and-drop. (#4514)getListChildren to get all child list items (with bigger indent) of a given list item.CHANGELOG · v49.1.13...v49.2.0 · By @zbeyens
@platejs/list
toggleList to respect list plugin's inject match when applying list transforms. (#4512)@platejs/slate
combineTransformMatchOptions utility for combining match predicates in transforms. This utility provides default matching behavior that matches the native Slate transform behavior when no match is provided. (#4512)editor.meta.isNormalizing flag to track when the editor is normalizing nodes. This flag is automatically set to true during editor.tf.normalizeNode and plugin.normalizeInitialValue and restored to its previous value when normalization completes.@platejs/table
CHANGELOG · v49.1.12...v49.1.13 · By @zbeyens
@platejs/selection
addOnContextMenu API method to BlockSelectionPlugin for cleaner context menu handling (#4508)@platejs/markdown
@platejs/markdown
@platejs/dnd
Added support for dragging multiple blocks using editor's native selection (#4481)
useDndNode hook implementation by removing complex preview logic@platejs/markdown
Add support for display text markdown format for mentions (#4468)
remarkMention plugin to only support the [display text](mention:id) format@username format@platejs/core
getSelectedDomFragment to correctly handle partial text selections at the beginning or end of selected blocks by deserializing only the selected portion instead of the entire block. (#4463)@platejs/core
Added editor.tf.nodeId.normalize() API to manually normalize node IDs in the document. (#4454)
1 ```ts
2 // Normalize all nodes in the document to ensure they have IDs
3 editor.tf.nodeId.normalize();
4 ```Added normalizeNodeId pure function to normalize node IDs in a value without using editor operations.
1import { normalizeNodeId } from '@platejs/core';
2
3// Normalize a value without editor operations
4const normalizedValue = normalizeNodeId(value, {
5 idKey: 'id',
6 idCreator: () => nanoid(10),
7 filterInline: true,
8 filterText: true,
9});This is useful when the value is passed from server to client-side editor.
Added getFragment() API method to ViewPlugin for accessing the selected DOM fragment.
usePlateViewEditor:
onReady handler support for async rendering with automatic re-render when isAsync is true1// New API usage
2const fragment = editor.getApi(ViewPlugin).getFragment();
3
4// Async rendering support
5const editor = usePlateViewEditor({
6 onReady: (ctx) => {
7 // Called when editor is ready, supports async rendering
8 },
9});@platejs/core
CHANGELOG · v49.1.1...v49.1.2 · By @delijah
@platejs/link
Fix markdown headings being incorrectly converted to links (#4452)
The LinkPlugin's validateUrl function now properly distinguishes between markdown headings and anchor links. Previously, any string starting with # was treated as a valid link, causing markdown headings like # heading1 to be converted to links when pasted. Now, the function checks for the markdown heading pattern (hash symbols followed by a space) and correctly rejects these as invalid URLs while still allowing valid anchor links like #section-name.
CHANGELOG · v49.1.0...v49.1.1 · By @zbeyens
@platejs/list-classic
Added task list functionality to @platejs/list-classic. (36211fa)
checked property to TTodoListItemElement type for tracking task completion stateuseTodoListElement and useTodoListElementState hooks for task list item managementgetPropsIfTaskList utility to check if an element is a task listchecked property statetoggleTaskList transform to convert between regular lists and task lists1// Before - only regular lists
2createListPlugin();
3
4// After - with task list support
5createListPlugin();
6
7// Toggle task list
8editor.tf.toggle.list({ listType: 'taskList' });CHANGELOG · v49.0.19...v49.1.0 · By @zbeyens
@platejs/table
@platejs/utils
taskList to KEYS constant. (#4437)CHANGELOG · v49.0.18...v49.0.19 · By @AissaSemaoui, @calebpitan
@platejs/core
getSelectedDomFragment utility function that returns Slate nodes from DOM selection. (#4447)getSelectedDomBlocks. Use getSelectedDomFragment instead.@platejs/markdown
Added spread option to control list spacing in markdown serialization. (#4440)
Added a new optional spread property to SerializeMdOptions:
spread is false (default), lists are rendered compactlyspread is true, lists have double line breaks between itemsBefore (default):
11. Item 1
22. Item 2After (with spread: true):
11. Item 1
2
32. Item 2CHANGELOG · v49.0.16...v49.0.17 · By @zbeyens
@platejs/core
Expose mimeType to plugin parser functions (#4441)
Added comprehensive copy functionality and view editor support for static rendering. (#4431)
New Components:
PlateView component for static editor rendering with copy supportusePlateViewEditor hook for creating memoized static editorsStatic Editor Enhancements:
withStatic HOC to enhance editors with static rendering capabilitiesViewPlugin that enables copy operations in static editorsgetStaticPlugins to configure plugins for static renderingonCopy handler that properly serializes content with x-slate-fragment formatNew Utilities:
getSelectedDomBlocks to extract selected DOM elements with Slate metadatagetSelectedDomNode to get DOM nodes from browser selectionisSelectOutside to check if selection is outside editor boundsgetPlainText to recursively extract plain text from DOM nodesThis enables seamless copy operations from static Plate editors, allowing content to be pasted into other Slate editors while preserving rich formatting and structure.
@platejs/core
SlateElementProps, SlateTextProps, SlateLeafProps, PlateElementProps, PlateTextProps, and PlateLeafProps to properly type the attributes property to unknown object. (#4428)@platejs/link
Improved return type of getLinkAttributes to be more specific and type-safe. (#4428)
1// The function now returns a properly typed object
2const attributes = getLinkAttributes(editor, linkElement);
3// attributes is now properly typed as Pick<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href' | 'target'> & UnknownObject@platejs/selection
@udecode/react-utils
CHANGELOG · v49.0.14...v49.0.15 · By @zbeyens
@udecode/react-utils
CHANGELOG · v49.0.12...v49.0.13 · By @yf-yang
@platejs/ai
preserveEmptyParagraphs: false to prevent zero-width space interference during real-time streaming operations. (#4416)@platejs/markdown
Fixed an issue where empty paragraphs were lost during markdown serialization and deserialization. Empty paragraphs are now preserved using zero-width spaces (\u200B) internally. (#4416)
1 ```ts
2 // Before: Empty paragraphs would disappear
3 const markdown = serializeMd(editor); // "Text\n\nMore text" → "Text\nMore text"
4
5 // After: Empty paragraphs are preserved
6 const markdown = serializeMd(editor); // "Text\n\nMore text" → "Text\n\nMore text"
7 ```preserveEmptyParagraphs option to control this behavior (defaults to true)CHANGELOG · v49.0.11...v49.0.12 · By @zbeyens
@platejs/core
CHANGELOG · v49.0.10...v49.0.11 · By @zbeyens
@platejs/core
createPlateStore on every hook call for the purposes of the fallback store (#4410)CHANGELOG · v49.0.9...v49.0.10 · By @12joan
@platejs/core
CHANGELOG · v49.0.8...v49.0.9 · By @delijah
@platejs/dnd
@platejs/selection
sort and collapseTableRows options to editor.blockSelection.getNodes() method. (#4385)editor.blockSelection.first to get the first selected node.normalize function to handle table selection logic in useSelectionArea hook for improved table row and table element selection behavior.
@platejs/core
CHANGELOG · v49.0.5...v49.0.6 · By @delijah
@platejs/core
Fixes #4374 (#4373)
Prevent rendering the editor until the value is loaded (when value is async or skipInitialization is true).
Added support for both synchronous and asynchronous functions in the value option for createPlateEditor and usePlateEditor. If async, usePlateEditor will trigger a re-render when the value is loaded.
Added onReady callback option to createPlateEditor and usePlateEditor called after (async) editor initialization.
1const editor = usePlateEditor({
2 value: async () => {
3 const response = await fetch('/api/document');
4 const data = await response.json();
5 return data.content;
6 },
7 onReady: ({ editor, value }) => {
8 console.info('Editor ready with value:', value);
9 },
10});CHANGELOG · v49.0.3...v49.0.4 · By @zbeyens
@platejs/selection
@platejs/table
CHANGELOG · v49.0.0...v49.0.1 · By @zbeyens
@udecode/plate-ai
Copilot API method changes: (#4327)
editor.api.copilot.accept is now editor.tf.copilot.accept.editor.api.copilot.acceptNextWord is now editor.tf.copilot.acceptNextWord.editor.api.copilot.reset is now editor.api.copilot.reject.Removed Default Shortcuts for Copilot:
accept (Tab) and reject (Escape) shortcuts are included by default for CopilotPlugin.acceptNextWord and triggerSuggestion shortcuts must now be configured manually using the shortcuts field when configuring the plugin.1CopilotPlugin.configure({
2 // ... other options
3 shortcuts: {
4 acceptNextWord: {
5 keys: 'mod+right',
6 },
7 triggerSuggestion: {
8 keys: 'ctrl+space',
9 },
10 },
11});Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-alignment
Package @udecode/plate-alignment has been deprecated. (#4327)
TextAlignPlugin (formerly AlignPlugin) has been moved to the @platejs/basic-styles package.
Migration:
@udecode/plate-alignment from your dependencies.@platejs/basic-styles to your dependencies if not already present.TextAlignPlugin from @platejs/basic-styles/react.Renamed AlignPlugin to TextAlignPlugin and changed plugin key from 'align' to 'textAlign'.
1// Before
2import { AlignPlugin } from '@udecode/plate-alignment/react';
3
4// After
5import { TextAlignPlugin } from '@platejs/basic-styles/react';setAlign signature change:
1// Before
2setAlign(editor, { value: 'center', setNodesOptions });
3
4// After
5setAlign(editor, 'center', setNodesOptions);useAlignDropdownMenu and useAlignDropdownMenuState. Use it in your own codebase, for example:1export function AlignToolbarButton() {
2 const editor = useEditorRef();
3 const value = useSelectionFragmentProp({
4 defaultValue: 'start',
5 structuralTypes,
6 getProp: (node) => node.align,
7 });
8
9 const onValueChange = (newValue: string) => {
10 editor.tf.textAlign.setNodes(newValue as Alignment);
11 editor.tf.focus();
12 };
13
14 // ...
15}AlignPlugin: (#4327)
editor.tf.textAlign.setNodes - Transform method for setting alignment values. Alias to setAlign@udecode/plate-autoformat
Replaced BaseAutoformatPlugin with AutoformatPlugin, which is no longer a React plugin. Migration: Replace @udecode/plate-autoformat/react import with @udecode/plate-autoformat. (#4327)
The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }). (#4327)
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-basic-elements
@udecode/plate-basic-elements has been deprecated. (#4327)BasicElementsPlugin has been renamed to BasicBlocksPlugin.@platejs/basic-nodes package.@udecode/plate-basic-elements with @platejs/basic-nodes in your dependencies.@udecode/plate-basic-elements/react to @platejs/basic-nodes/react.@platejs/basic-nodes.@udecode/plate-basic-marks
@udecode/plate-basic-marks has been deprecated. (#4327)@platejs/basic-nodes package.@udecode/plate-basic-marks with @platejs/basic-nodes in your dependencies.@udecode/plate-basic-marks/react to @platejs/basic-nodes/react.@platejs/basic-nodes.@udecode/plate-basic-nodes
@udecode/plate-basic-elements and @udecode/plate-basic-marks have been deprecated. All their plugins are now consolidated into the new @platejs/basic-nodes package. (#4327)@udecode/plate-basic-elements and @udecode/plate-basic-marks in your dependencies with @platejs/basic-nodes.@udecode/plate-basic-elements/react or @udecode/plate-basic-marks/react to @platejs/basic-nodes/react.CodeBlockPlugin is not part of @platejs/basic-nodes. Ensure it is imported from @platejs/code-block/react.SkipMarkPlugin (standalone) is removed. Its functionality is now built into the core editor. To enable boundary clearing for a specific mark, configure the mark plugin directly: plugin.configure({ rules: { selection: { affinity: 'outward' } } }).@udecode/plate-basic-nodes (e.g., BlockquotePlugin, HeadingPlugin, HorizontalRulePlugin) now default to rendering with specific HTML tags (<blockquote>, <h1>-<h6>, <hr> respectively). ParagraphPlugin still defaults to <div>. If you relied on previous defaults or need different tags, provide a custom component or use the render.as option.@udecode/plate-basic-nodes (e.g., BoldPlugin, CodePlugin, ItalicPlugin) now default to specific HTML tags (<strong>, <code>, <em> respectively). If you relied on previous defaults or need different tags, provide a custom component or use the render.as option.shortcuts field in plugin configuration.1H1Plugin.configure({ shortcuts: { toggle: { keys: 'mod+alt+1' } } });
2BlockquotePlugin.configure({
3 shortcuts: { toggle: { keys: 'mod+shift+period' } },
4});1CodePlugin.configure({ shortcuts: { toggle: { keys: 'mod+e' } } });
2StrikethroughPlugin.configure({
3 shortcuts: { toggle: { keys: 'mod+shift+x' } },
4});
5SubscriptPlugin.configure({
6 shortcuts: { toggle: { keys: 'mod+comma' } },
7});
8SuperscriptPlugin.configure({
9 shortcuts: { toggle: { keys: 'mod+period' } },
10});
11HighlightPlugin.configure({
12 shortcuts: { toggle: { keys: 'mod+shift+h' } },
13});toggle Transforms Added: (#4327)
toggle transforms: BlockquotePlugin, H1Plugin, H2Plugin, H3Plugin, H4Plugin, H5Plugin, H6Plugin.toggle transform, including: BoldPlugin, ItalicPlugin, UnderlinePlugin, CodePlugin, StrikethroughPlugin, SubscriptPlugin, SuperscriptPlugin, KbdPlugin, HighlightPlugin.H1Plugin, H2Plugin, H3Plugin, H4Plugin, H5Plugin, and H6Plugin offer a flexible alternative to the general HeadingPlugin, allowing granular control over heading level inclusion and configuration (e.g., custom components, shortcuts per level).@udecode/plate-basic-nodes:
KbdPlugin (formerly from @udecode/plate-kbd).HighlightPlugin (formerly from @udecode/plate-highlight).@udecode/plate-block-quote
@udecode/plate-block-quote has been deprecated. (#4327)BlockquotePlugin has been moved to the @platejs/basic-nodes package.@udecode/plate-block-quote from your dependencies.@platejs/basic-nodes to your dependencies if not already present.BlockquotePlugin from @platejs/basic-nodes/react.@udecode/plate-break
Package @udecode/plate-break has been deprecated. (#4327)
SoftBreakPlugin has been removed. Migration:
shift+enter rules: no migration is needed - this behavior is built into Slate by default.enter rules: use plugin.configure({ rules: { break: { default: 'lineBreak' } } }) to insert a line break instead of a hard break on Enter keydown when the selection is within the configured node type.overrideEditor to override the insertBreak transform with custom logic.ExitBreakPlugin has been moved to @platejs/utils (which is re-exported via platejs) with a simplified API and improved behavior.
1 - **Behavior Change**: Instead of always exiting to the root level of the document, exiting will now insert a block to the nearest exitable ancestor that has `isStrictSiblings: false`. This means deeply nested structures (like tables in columns) are exitable at many levels.
2 - Migration:
3
4 - Remove `@udecode/plate-break` from your dependencies.
5 - Replace `@udecode/plate-break` import with `platejs`.
6 - **Important**: If not using Plate plugins, you must set `isStrictSiblings: true` on your custom node plugins that can't have paragraph siblings for exit break to work correctly.
7 - Replace complex rule-based configuration with simple shortcuts:
8
9 ```tsx
10 // Before (old API)
11 ExitBreakPlugin.configure({
12 options: {
13 rules: [
14 { hotkey: 'mod+enter' },
15 { hotkey: 'mod+shift+enter', before: true },
16 ],
17 },
18 });
19
20 // After (new API)
21 ExitBreakPlugin.configure({
22 shortcuts: {
23 insert: { keys: 'mod+enter' },
24 insertBefore: { keys: 'mod+shift+enter' },
25 },
26 });
27 ```@udecode/plate-callout
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-caption
CaptionPlugin option options.plugins (accepting an array of PlatePlugin) has been renamed to options.query.allow (accepting an array of plugin keys). (#4327)
Migration:
1 ```tsx
2 // Before
3 CaptionPlugin.configure({
4 options: {
5 plugins: [ImagePlugin], // ImagePlugin is an example
6 },
7 });
8
9 // After
10 CaptionPlugin.configure({
11 options: {
12 query: {
13 allow: [ImagePlugin.key], // Use the plugin's key
14 },
15 },
16 });
17 ```Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-code-block
CodeBlockPlugin now defaults to rendering the code block container with a <pre> HTML tag if no custom component is provided for CodeBlockElement (or the plugin key code_block). (#4327)@udecode/plate-combobox
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-comments
CommentsPlugin has been renamed to CommentPlugin. (#4327)
Update imports and plugin configurations accordingly.
CommentsPlugin.key becomes CommentPlugin.key.Package name has been changed to @platejs/comment.
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-core
editor.getType() now takes a pluginKey: string instead of a plugin: PlatePlugin instance. (#4327)
editor.getType(ParagraphPlugin.key) instead of editor.getType(ParagraphPlugin).Plugins without a key property will not be registered into the editor.
Passing disabled: true prop to PlateContent will now also set the editor to readOnly: true state internally.
Editor DOM state properties have been moved under editor.dom namespace:
editor.currentKeyboardEvent is now editor.dom.currentKeyboardEvent.editor.prevSelection is now editor.dom.prevSelection.Editor metadata properties have been moved under editor.meta namespace:
editor.isFallback is now editor.meta.isFallbackeditor.key is now editor.meta.keyeditor.pluginList is now editor.meta.pluginListeditor.shortcuts is now editor.meta.shortcutseditor.uid is now editor.meta.uidNodeIdPlugin is now enabled by default as part of the core plugins. This automatically assigns unique IDs to block nodes.
NodeIdPlugin and wish to maintain the old behavior (no automatic IDs), explicitly disable it in your editor configuration:
1const editor = usePlateEditor({
2 // ...other options
3 nodeId: false, // Disables automatic node ID generation
4});The components prop has been removed from serializeHtml and PlateStatic.
components to createSlateEditor({ components }) or the individual plugins instead.Plugin Shortcuts System Changes:
editor.shortcuts are now namespaced by the plugin key (e.g., code.toggle for CodePlugin).priority property for shortcuts is used to resolve conflicts when multiple shortcuts share the exact same key combination, not for overriding shortcuts by name.preventDefault for plugin shortcuts now defaults to true, unless the handler returns false (i.e. not handled). This means browser default actions for these key combinations will be prevented unless explicitly allowed.
preventDefault: false in its configuration:
1MyPlugin.configure({
2 shortcuts: {
3 myAction: {
4 keys: 'mod+s',
5 preventDefault: false, // Example: Allow browser's default save dialog
6 },
7 },
8});Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
editor.dom: (#4327)
editor.dom.composing: Boolean, true if the editor is currently composing text (e.g., during IME input).editor.dom.focused: Boolean, true if the editor currently has focus.editor.dom.readOnly: Boolean, true if the editor is in read-only mode. Passing the readOnly prop to PlateContent will sync its value to this state and to the useEditorReadOnly hook.editor.meta.components - stores the plugin components by keyuseEditorComposing: Allows subscription to the editor's composing state (editor.dom.composing) outside of PlateContent.createPlateEditor and usePlateEditor now accept a readOnly option to initialize the editor in a read-only state. For dynamic read-only changes after initialization, continue to use the readOnly prop on the <Plate> or <PlateContent> component.editOnly (boolean or object).
true or when specific properties are true in the object, Plate will disable certain plugin behaviors (handlers, rendering, injections) in read-only mode and re-enable them if the editor becomes editable.render, handlers, and inject are considered edit-only (true). normalizeInitialValue defaults to always active (false).editOnly: { render: false, normalizeInitialValue: true } would make rendering active always, but normalization only in edit mode.render.as (keyof HTMLElementTagNameMap).
PlateElement (default: 'div') or PlateLeaf (default: 'span') when rendering the node, but only if no custom node.component is provided for the plugin.render: { as: 'h1' } would make the plugin render its node as an <h1> tag by default without the need to provide a custom component.node.isContainer (boolean).
true, indicates that the plugin's elements are primarily containers for other content.node.isStrictSiblings (boolean).
true, indicates that the element enforces strict sibling type constraints and only allows specific siblings (e.g., td can only have td siblings, column can only have column siblings).editor.tf.insertExitBreak functionality to determine appropriate exit points in nested structures.rules (object).
rules.break: Controls Enter key behavior (empty, default, emptyLineEnd, splitReset)rules.delete: Controls Backspace key behavior (start, empty)rules.merge: Controls block merging behavior (removeEmpty)rules.normalize: Controls normalization behavior (removeEmpty)rules.selection: Controls cursor positioning behavior (affinity)rules.match: Conditional rule application based on node propertieseditor.tf.escape: Handle Escape key events. Returns true if the event is handled.editor.tf.moveLine: Handle ArrowDown and ArrowUp key events with reverse option for direction. Returns true if the event is handled.editor.tf.selectAll: Handle Ctrl/Cmd+A key events for selecting all content. Returns true if the event is handled.editor.tf.tab: Handle Tab and Shift+Tab key events with reverse option for Shift+Tab. Returns true if the event is handled.editor.api and editor.tf (transforms) were not consistently available in the props passed to default element components when no custom component was provided for a plugin. (#4327)@udecode/plate-csv
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-cursor
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-date
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-diff
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-dnd
The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }). (#4327)
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-docx
The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }). (#4327)
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-emoji
The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }). (#4327)
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-excalidraw
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-find-replace
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-floating
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-font
Removed setBlockBackgroundColor (#4327)
Removed setFontSize – use tf.fontSize.addMark instead:
1// Before
2editor.api.fontSize.addMark('16px');
3
4// After
5editor.tf.fontSize.addMark('16px');useColorInput. Use it in your own codebase, for example:1function ColorInput() {
2 const inputRef = React.useRef<HTMLInputElement | null>(null);
3
4 const onClick = () => {
5 inputRef.current?.click();
6 };
7
8 // ...
9}useColorsCustom and useColorsCustomState. Use it in your own codebase, for example:1function ColorCustom({ color, colors, customColors, updateCustomColor }) {
2 const [customColor, setCustomColor] = React.useState<string>();
3 const [value, setValue] = React.useState<string>(color || '#000000');
4
5 React.useEffect(() => {
6 if (
7 !color ||
8 customColors.some((c) => c.value === color) ||
9 colors.some((c) => c.value === color)
10 ) {
11 return;
12 }
13
14 setCustomColor(color);
15 }, [color, colors, customColors]);
16
17 const computedColors = React.useMemo(
18 () =>
19 customColor
20 ? [
21 ...customColors,
22 {
23 isBrightColor: false,
24 name: '',
25 value: customColor,
26 },
27 ]
28 : customColors,
29 [customColor, customColors]
30 );
31
32 const updateCustomColorDebounced = React.useCallback(
33 debounce(updateCustomColor, 100),
34 [updateCustomColor]
35 );
36
37 const inputProps = {
38 value,
39 onChange: (e: React.ChangeEvent<HTMLInputElement>) => {
40 setValue(e.target.value);
41 updateCustomColorDebounced(e.target.value);
42 },
43 };
44
45 // ...
46}useColorDropdownMenu and useColorDropdownMenuState. Use it in your own codebase, for example:1export function FontColorToolbarButton({ nodeType }) {
2 const editor = useEditorRef();
3
4 const selectionDefined = useEditorSelector(
5 (editor) => !!editor.selection,
6 []
7 );
8
9 const color = useEditorSelector(
10 (editor) => editor.api.mark(nodeType) as string,
11 [nodeType]
12 );
13
14 const [selectedColor, setSelectedColor] = React.useState<string>();
15 const [open, setOpen] = React.useState(false);
16
17 const onToggle = React.useCallback(
18 (value = !open) => {
19 setOpen(value);
20 },
21 [open, setOpen]
22 );
23
24 const updateColor = React.useCallback(
25 (value: string) => {
26 if (editor.selection) {
27 setSelectedColor(value);
28 editor.tf.select(editor.selection);
29 editor.tf.focus();
30 editor.tf.addMarks({ [nodeType]: value });
31 }
32 },
33 [editor, nodeType]
34 );
35
36 const clearColor = React.useCallback(() => {
37 if (editor.selection) {
38 editor.tf.select(editor.selection);
39 editor.tf.focus();
40 if (selectedColor) {
41 editor.tf.removeMarks(nodeType);
42 }
43 onToggle();
44 }
45 }, [editor, selectedColor, onToggle, nodeType]);
46
47 React.useEffect(() => {
48 if (selectionDefined) {
49 setSelectedColor(color);
50 }
51 }, [color, selectionDefined]);
52
53 // ...
54}@udecode/plate-heading
@udecode/plate-heading has been deprecated. (#4327)
HeadingPlugin and individual heading plugins (e.g., H1Plugin) have been moved to @platejs/basic-nodes.
@platejs/basic-nodes/react (e.g., import { HeadingPlugin } from '@platejs/basic-nodes/react';).TocPlugin has been moved to @platejs/toc.
@platejs/toc to your dependencies and import TocPlugin from @platejs/toc/react.@udecode/plate-heading from your dependencies.@udecode/plate-highlight
@udecode/plate-highlight has been deprecated. (#4327)HighlightPlugin has been moved to the @platejs/basic-nodes package.@udecode/plate-highlight from your dependencies.@platejs/basic-nodes to your dependencies if not already present.HighlightPlugin from @platejs/basic-nodes/react.@udecode/plate-horizontal-rule
@udecode/plate-horizontal-rule has been deprecated. (#4327)HorizontalRulePlugin has been moved to the @platejs/basic-nodes package.@udecode/plate-horizontal-rule from your dependencies.@platejs/basic-nodes to your dependencies if not already present.HorizontalRulePlugin from @platejs/basic-nodes/react.@udecode/plate-indent
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-indent-list
@udecode/plate-indent-list has been renamed to @platejs/list. (#4327)@udecode/plate-indent-list to @platejs/list.package.json: remove @udecode/plate-indent-list and add @platejs/list.@udecode/plate-juice
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-kbd
@udecode/plate-kbd has been deprecated. (#4327)KbdPlugin has been moved to the @platejs/basic-nodes package.@udecode/plate-kbd from your dependencies.@platejs/basic-nodes to your dependencies if not already present.KbdPlugin from @platejs/basic-nodes/react.@udecode/plate-layout
Delete backward from a column start will merge into the previous column (#4327)
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-line-height
Package @udecode/plate-line-height has been deprecated. (#4327)
LineHeightPlugin has been moved to the @platejs/basic-styles package.
Migration:
@udecode/plate-line-height from your dependencies.@platejs/basic-styles to your dependencies if not already present.LineHeightPlugin from @platejs/basic-styles/react.setLineHeight signature change:
1// Before
2setLineHeight(editor, { value: 1.5, setNodesOptions });
3
4// After
5setLineHeight(editor, 1.5, setNodesOptions);useLineHeightDropdownMenu and useLineHeightDropdownMenuState. Use it in your own codebase, for example:1export function LineHeightToolbarButton() {
2 const editor = useEditorRef();
3 const { defaultNodeValue, validNodeValues: values = [] } =
4 editor.getInjectProps(LineHeightPlugin);
5
6 const value = useSelectionFragmentProp({
7 defaultValue: defaultNodeValue,
8 getProp: (node) => node.lineHeight,
9 });
10
11 const onValueChange = (newValue: string) => {
12 editor.tf.lineHeight.setNodes(Number(newValue));
13 editor.tf.focus();
14 };
15
16 // ...
17}LineHeightPlugin: (#4327)
editor.tf.lineHeight.setNodes - Transform method for setting line height values. Alias to setLineHeight@udecode/plate-link
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-list
The previous @udecode/plate-list (classic list implementation) has been moved to @platejs/list-classic. (#4327)
@udecode/plate-list to @platejs/list-classic.package.json: remove the old @udecode/plate-list (if it was a direct dependency) and add @platejs/list-classic.This package, @platejs/list, now contains the functionality previously in @udecode/plate-indent-list (indent-based list system).
IndentListPlugin is now ListPlugin, BaseIndentListPlugin is BaseListPlugin, etc. (*IndentList* -> *List*).list (e.g., ListPlugin.key) instead of listStyleType.INDENT_LIST_KEYS are now available under KEYS from platejs.
INDENT_LIST_KEYS.listStyleType -> KEYS.listTypeINDENT_LIST_KEYS.todo -> KEYS.listTodoINDENT_LIST_KEYS.checked -> KEYS.listCheckedINDENT_LIST_KEYS.* map to KEYS.* accordingly.listStyleTypes option from ListPlugin. You should control list rendering via render.belowNodes instead.renderListBelowNodes.For changelogs of the indent-based list system (now in this package) version <=48 (when it was @udecode/plate-indent-list), refer to its archived changelog.
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-list-classic
BulletedListPlugin and NumberedListPlugin. (#4327)
shortcuts field.1BulletedListPlugin.configure({
2 shortcuts: { toggle: { keys: 'mod+alt+5' } },
3});
4NumberedListPlugin.configure({
5 shortcuts: { toggle: { keys: 'mod+alt+6' } },
6});@udecode/plate-list has been moved to @platejs/list-classic.
@udecode/plate-list to @platejs/list-classic.package.json: remove @udecode/plate-list and add @platejs/list-classic.@udecode/plate-list version <=48, refer to its archived changelog.@udecode/plate-markdown
Function indentListToMdastTree has been renamed to listToMdastTree to align with the list plugin renames (IndentListPlugin -> ListPlugin). (#4327)
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-math
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-media
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-mention
The type TMentionInputElement has been removed. (#4327)
Use TComboboxInputElement from @udecode/plate instead for input elements, as mention functionality is built upon the combobox.
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-node-id
Package @udecode/plate-node-id has been deprecated. (#4327)
NodeIdPlugin functionality is now part of @platejs/core and is enabled by default.
Migration:
1 - Remove `NodeIdPlugin` from your explicit plugin list if it was added manually.
2
3 - Remove `@udecode/plate-node-id` from your dependencies.
4
5 - If you had `NodeIdPlugin` configured with options, move these options to the `nodeId` field in your main editor configuration (`createPlateEditor` or `usePlateEditor` options).
6 Example:
7
8 ```ts
9 // Before
10 // const editor = usePlateEditor({
11 // plugins: [
12 // NodeIdPlugin.configure({ /* ...your options... */ }),
13 // ],
14 // });
15
16 // After
17 const editor = usePlateEditor({
18 nodeId: {
19 /* ...your options... */
20 },
21 // ...other editor options
22 });
23 ```
24
25 - If you want to disable automatic node ID generation (to replicate behavior if you weren't using `NodeIdPlugin` before), set `nodeId: false` in your editor configuration.@udecode/plate-normalizers
@udecode/plate-normalizers has been deprecated. (#4327)platejs (which is re-exported via platejs).@udecode/plate-normalizers from your dependencies.platejs@udecode/plate
platejs: (#4327)
@udecode/plate/react with platejs/react'@udecode/plate' with 'platejs'@udecode/plate-playwright
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-reset-node
Package @udecode/plate-reset-node has been deprecated. Its functionality (e.g., ResetNodePlugin) is now exclusively configured using the rules.break and rules.delete options on plugin definitions. Migration: (#4327)
@udecode/plate-reset-node from your dependencies.ResetNodePlugin from your project.rules.break and/or rules.delete.Example: Resetting a Blockquote to a Paragraph
1ResetNodePlugin.configure({
2 options: {
3 rules: [
4 {
5 types: [BlockquotePlugin.key],
6 defaultType: ParagraphPlugin.key,
7 hotkey: 'Enter',
8 predicate: (editor) =>
9 editor.api.isEmpty(editor.selection, { block: true }),
10 },
11 ],
12 },
13});
14
15// After
16BlockquotePlugin.configure({
17 rules: {
18 break: { empty: 'reset' },
19 delete: { start: 'reset' },
20 },
21});For custom reset logic (previously onReset):
1// Before
2ResetNodePlugin.configure({
3 options: {
4 rules: [
5 {
6 types: [CodeBlockPlugin.key],
7 defaultType: ParagraphPlugin.key,
8 hotkey: 'Enter',
9 predicate: isCodeBlockEmpty,
10 onReset: unwrapCodeBlock,
11 },
12 ],
13 },
14});
15
16// After
17CodeBlockPlugin.configure({
18 rules: {
19 delete: { empty: 'reset' },
20 },
21}).overrideEditor(({ editor, tf: { resetBlock } }) => ({
22 transforms: {
23 resetBlock(options) {
24 if (
25 editor.api.block({
26 at: options?.at,
27 match: { type: editor.getType(CodeBlockPlugin.key) },
28 })
29 ) {
30 unwrapCodeBlock(editor);
31 return;
32 }
33
34 return resetBlock(options);
35 },
36 },
37}));@udecode/plate-resizable
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-select
The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }). (#4327)
Package @udecode/plate-select has been deprecated. (#4327)
SelectOnBackspacePlugin has been removed. This behavior is now built into Plate by default: delete (backward/forward) at the start of a block will select the previous/next void block instead of removing it.
DeletePlugin has been removed. This behavior is now built into Plate by default: delete (backward/forward) from an empty block will remove it instead of merging.
RemoveEmptyNodesPlugin has been removed. This behavior is now available through the rules: { normalize: { removeEmpty: true } } configuration on individual plugins.
Migration:
@udecode/plate-select from your dependencies.SelectOnBackspacePlugin, DeletePlugin from your project.RemoveEmptyNodesPlugin.configure({ options: { types: ['custom'] } }) with CustomPlugin.configure({ rules: { normalize: { removeEmpty: true } } }). This is used by our LinkPlugin.@udecode/plate-selection
The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }). (#4327)
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
@udecode/plate-slash-command
The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }). (#4327)
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
The type TSlashInputElement has been removed. (#4327)
Use TComboboxInputElement from platejs instead for Slash Command input elements, as slash command functionality is built upon the combobox.
@udecode/slate
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
Replaced editor.api.shouldMergeNodesRemovePrevNode with editor.api.shouldMergeNodes. shouldMergeNodes is now controlling the remove + merge behavior (#4327)
1 - Returns `true` if the default merging behavior should be applied.
2 - Returns `false` if the default merging behavior should not be applied. This is used by Plate to prevent void blocks deletion, and to prioritize empty block deletion over merging.
3
4 ```ts
5 // Before
6 editor.api.shouldMergeNodesRemovePrevNode(prev, current);
7
8 // After
9 editor.api.shouldMergeNodes(prev, current);
10 ```Replace editor.api.fragment option structuralTypes with unwrap.
1// Before
2editor.api.fragment(editor.selection, { structuralTypes: ['table'] });
3
4// After
5editor.api.fragment(editor.selection, { unwrap: ['table'] });editor.tf.insertSoftBreak now inserts a soft break instead of a hard break. (#4327)@udecode/plate-suggestion
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-tabbable
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-table
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-tag
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-test-utils
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-toc
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-toggle
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)@udecode/plate-trailing-block
The following plugins now default to editOnly: true. This means their core functionalities (handlers, rendering injections, etc.) will be disabled when the editor is in read-only mode. To override this behavior for a specific plugin, configure its editOnly field. For example, SomePlugin.configure({ editOnly: false }). (#4327)
Package @udecode/plate-trailing-block has been deprecated. (#4327)
Its functionality (e.g., TrailingBlockPlugin) has been moved to @platejs/utils (which is re-exported via platejs).
Migration:
@udecode/plate-trailing-block from your dependencies.platejs (e.g., import { TrailingBlockPlugin } from 'platejs';).@udecode/plate-utils
Renamed all @udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)
Node type definitions (e.g., TImageElement, TParagraphElement) previously co-located with their respective plugin packages (like @udecode/plate-media) have been centralized into @platejs/utils. These are typically re-exported via the main platejs package. (#4327)
1 - Migration: Update imports for these types to pull from `platejs`.
2
3 ```tsx
4 // Before
5 // import { TImageElement } from '@udecode/plate-media';
6
7 // After
8 import { TImageElement } from 'platejs';
9 ```Removed structuralTypes option from useSelectionFragment and useSelectionFragmentProp. These hooks now automatically use plugin.node.isContainer from enabled plugins.
Removed:
createNodesHOCcreateNodesWithHOCcreateNodeHOCRemoved usePlaceholderState hook.
BlockPlaceholderPlugin (typically from platejs) instead of the withPlaceholders HOC and usePlaceholderState. Configure placeholders directly within the BlockPlaceholderPlugin options.
1// Example BlockPlaceholderPlugin configuration
2BlockPlaceholderPlugin.configure({
3 options: {
4 className:
5 'before:absolute before:cursor-text before:opacity-30 before:content-[attr(placeholder)]',
6 placeholders: {
7 [ParagraphPlugin.key]: 'Type something...',
8 // ...other placeholders
9 },
10 query: ({ editor, path }) => {
11 // Example query: only show for top-level empty blocks
12 return (
13 path.length === 1 && editor.api.isEmpty(editor.children[path[0]])
14 );
15 },
16 },
17});New plugin SingleBlockPlugin to restrict editor content to a single block while preserving line breaks, while SingleLinePlugin prevents all line breaks. (#4327)
@platejs/utils (and by extension, platejs) now exports a comprehensive KEYS object containing all official plugin keys.
This is intended to improve decoupling and provide a centralized way to reference plugin keys.
Example Usage:
1import { KEYS } from 'platejs';
2
3// Instead of: ParagraphPlugin.key
4// Use: KEYS.pMany node type definitions (e.g., TParagraphElement, TLinkElement) are also now exported from platejs, in addition to being available from their specific plugin packages if those still exist or from @platejs/basic-nodes.
@udecode/plate-yjs
@udecode/plate-* packages to @platejs/*. Replace @udecode/plate- with @platejs/ in your code. (#4327)CHANGELOG · v48.0.6...v49.0.0 · By @zbeyens