This page covers major breaking changes for Plate up to v48. For the latest migration guide, see Latest Migration. For patch and minor changes, refer to the individual package CHANGELOG.md files or visit the GitHub Releases page.
48.0.0
@udecode/[email protected]
-
PlateElement,PlateLeafandPlateTextHTML attributes are moved from top-level props toattributesprop, exceptclassName,styleandas. Migration:
// From <PlateElement {...props} ref={ref} contentEditable={false} > {children} </PlateElement> // To <PlateElement {...props} ref={ref} attributes={{ ...props.attributes, contentEditable: false, }} > {children} </PlateElement>- Remove
nodePropsprop fromPlateElement,PlateLeaf,PlateText. It has been merged intoattributesprop. - Plugin
node.propsshould return the props directly instead of insidenodePropsobject. Migration:
// From node: { props: ({ element }) => ({ nodeProps: { colSpan: element?.attributes?.colspan, rowSpan: element?.attributes?.rowspan, }, }); } // To node: { props: ({ element }) => ({ colSpan: element?.attributes?.colspan, rowSpan: element?.attributes?.rowspan, }); }- Remove
asChildprop fromPlateElement,PlateLeaf,PlateText. Useasprop instead. - Remove
elementToAttributes,leafToAttributes,textToAttributesprops fromPlateElement,PlateLeaf,PlateText. - Remove
DefaultElement,DefaultLeaf,DefaultText. UsePlateElement,PlateLeaf,PlateTextinstead. - Types: remove
PlateRenderElementProps,PlateRenderLeafProps,PlateRenderTextProps. UsePlateElementProps,PlateLeafProps,PlateTextPropsinstead.
@udecode/[email protected]
- #4281 by @zbeyens –
- Moved
PlateElement,PlateLeaf,PlateTextto@udecode/plate-core. No migration needed if you're importing from@udecode/plate.
- Moved
@udecode/[email protected]
-
#4225 by @bbyiringiro –
- Add multi-provider support for improved collaboration: now supports both Hocuspocus and WebRTC simultaneously using a shared Y.Doc.
- Migration: Replace
hocuspocusProviderOptionswith the newprovidersarray. See examples below.
- Migration: Replace
Before:
YjsPlugin.configure({ options: { cursorOptions: { /* ... */ }, hocuspocusProviderOptions: { url: 'wss://hocuspocus.example.com', name: 'document-1', // ... other Hocuspocus options }, }, });After (Hocuspocus only):
YjsPlugin.configure({ options: { cursors: { /* ... */ }, providers: [ { type: 'hocuspocus', options: { url: 'wss://hocuspocus.example.com', name: 'document-1', // ... other Hocuspocus options }, }, ], }, });After (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'], // Optional }, }, ], }, });- Introduces
UnifiedProviderinterface that enables custom provider implementations (e.g., IndexedDB for offline persistence). - Renamed
cursorOptionstocursors. - Merged
yjsOptionsintooptions.- Migration: Move options previously under
yjsOptionsdirectly into the mainoptionsobject.
- Migration: Move options previously under
- Removed
YjsAboveEditable. You should now callinitanddestroymanually:
React.useEffect(() => { if (!mounted) return; // Initialize Yjs connection and sync editor.getApi(YjsPlugin).yjs.init({ id: roomName, // Or your document identifier value: INITIAL_VALUE, // Your initial editor content }); // Destroy connection on component unmount return () => { editor.getApi(YjsPlugin).yjs.destroy(); }; }, [editor, mounted, roomName]); // Add relevant dependencies - Add multi-provider support for improved collaboration: now supports both Hocuspocus and WebRTC simultaneously using a shared Y.Doc.
47.0.0
@udecode/plate-markdown
-
#4174 by @felixfeng33 – #### New Features
- Added support for math type deserialization
- Added default underline mark serialization as
<u>underline</u> - Improved serialization process:
- Now uses a two-step process:
slate nodes => MDAST nodes => markdown string - Previously: direct conversion from Slate nodes to markdown string
- Results in more reliable and robust serialization
- Now uses a two-step process:
- New node filtering options:
allowedNodes: Whitelist specific nodesdisallowedNodes: Blacklist specific nodesallowNode: Custom function to filter nodes
- New
rulesoption for customizing serialization and deserialization rules, including custom mdx support - New
remarkPluginsoption to use remark plugins
Breaking Changes
Plugin Options
Removed options:
elementRulesuserulesinsteadtextRulesuserulesinsteadindentListnow automatically detects if the IndentList plugin is usedsplitLineBreaksdeserialize only
Deserialization
- Removed
elementRulesandtextRulesoptions- Use
rules.key.deserializeinstead - See nodes documentation
- Use
Example migration:
export const markdownPlugin = MarkdownPlugin.configure({ options: { disallowedNodes: [SuggestionPlugin.key], rules: { // For textRules [BoldPlugin.key]: { mark: true, deserialize: (mdastNode) => ({ bold: true, text: node.value || '', }), }, // For elementRules [EquationPlugin.key]: { deserialize: (mdastNode, options) => ({ children: [{ text: '' }], texExpression: node.value, type: EquationPlugin.key, }), }, }, remarkPlugins: [remarkMath, remarkGfm], }, });- Removed processor in
editor.api.markdown.deserialize- Use
remarkPluginsinstead
- Use
Serialization
- Removed
serializeMdNodes- Use
editor.markdown.serialize({ value: nodes })instead
- Use
- Removed
SerializeMdOptionsdue to new serialization process- Previous process:
slate nodes => md - New process:
slate nodes => md-ast => md
- Previous process:
- Removed options:
nodesbreakTagcustomNodesignoreParagraphNewlinelistDepthmarkFormatsulListStyleTypesignoreSuggestionType
Migration example for
SerializeMdOptions.customNodesandSerializeMdOptions.nodes:export const markdownPlugin = MarkdownPlugin.configure({ options: { rules: { // Ignore all `insert` type suggestions [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 }; }, }, // For elementRules [EquationPlugin.key]: { serialize: (slateNode) => ({ type: 'math', value: node.texExpression, }), }, }, remarkPlugins: [remarkMath, remarkGfm], }, });
46.0.0
@udecode/[email protected]
-
#4122 by @zbeyens – Migrated from
prismjstohighlight.js+lowlightfor syntax highlighting.- Fix highlighting multi-lines tokens. Before, line tokens were computed line by line. Now, it's computed once for the whole block.
- Bundle size much lower.
CodeBlockPlugin: removeprismoption. Uselowlightoption instead:
import { all, createLowlight } from 'lowlight'; const lowlight = createLowlight(all); CodeBlockPlugin.configure({ options: { lowlight, }, });- New option:
defaultLanguage - Remove
syntaxoption. Just omitlowlightoption to disable syntax highlighting. - Remove
syntaxPopularFirstoption. Control this behavior in your own components. - Fix pasting code inside code blocks.
- Remove
useCodeBlockCombobox,useCodeBlockElement,useCodeSyntaxLeaf,useToggleCodeBlockButton. The logic has been moved to the components.
45.0.0
@udecode/[email protected]
-
#4064 by @felixfeng33 – This is a rewrite of the comments plugin removing UI logic (headless).
Plugin Options
- Removed configuration options from plugin options in favor of component-level control:
options.commentsoptions.myUserIdoptions.users
Components
- Removed legacy components:
CommentDeleteButtonCommentEditActionsCommentEditButtonCommentEditCancelButtonCommentEditSaveButtonCommentEditTextareaCommentNewSubmitButtonCommentNewTextareaCommentResolveButtonCommentsPositionerCommentUserName
API
- Removed functions in favor of new API methods:
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 })
- Removed unused functions:
getCommentFragmentgetCommentUrlgetElementAbsolutePositiongetCommentPosition
- Updated
getCommentCountto exclude draft comments
State Management
- Removed
CommentProvider- users should implement their own state management –block-discussion.tsx - Moved
useHooksCommentsto UI registry –comments-plugin.tsx - Removed hooks no longer needed with new UI:
useActiveCommentNodeuseCommentsResolveduseCommentAddButtonuseCommentItemContentuseCommentLeafuseCommentsShowResolvedButtonuseFloatingCommentsContentStateuseFloatingCommentsState
Types
- Removed
CommentUser - Moved
TCommentto UI registry –comment.tsx
- Removed configuration options from plugin options in favor of component-level control:
@udecode/[email protected]
-
#4064 by @felixfeng33 – Note: This plugin is currently in an experimental phase and breaking changes may be introduced without a major version bump.
- Add Suggestion UI
- Remove:
findSuggestionNodeusefindSuggestionProps.tsinstead - Remove
addSuggestionMark.ts - Remove
useHooksSuggestion.tsas we've updated the activeId logic to no longer depend on useEditorSelector
44.0.1
@udecode/[email protected]
-
- Support React 19
- Upgraded to
zustand-x@6eventEditorSelectors->EventEditorStore.geteventEditorActions->EventEditorStore.setuseEventEditorSelectors->useEventEditorValue(key)
- Upgraded to
jotai-x@2usePlateEditorStore->usePlateStoreusePlateActions->usePlateSet- Remove
editor.setPlateState, useusePlateSetinstead usePlateSelectors->usePlateValueusePlateStates->usePlateState
- Moving plugin options hooks into standalone hooks to be compatible with React Compiler
editor.useOption,ctx.useOption->usePluginOption(plugin, key, ...args)editor.useOptions,ctx.useOptions->usePluginOption(plugin, 'state')- New hook
usePluginOptions(plugin, selector)to select plugin options (Zustand way).
- We were supporting adding selectors to plugins using
extendOptions. Those were mixed up with the options state, leading to potential conflicts and confusion.- The plugin method is renamed to
extendSelectors - Selectors are now internally stored in
plugin.selectorsinstead ofplugin.options, but this does not change how you access those: usingeditor.getOption(plugin, 'selectorName'),ctx.getOption('selectorName')or above hooks. - Selector types are no longer in the 2nd generic type of
PluginConfig, we're adding a 5th generic type for it.
- The plugin method is renamed to
// Before: export type BlockSelectionConfig = PluginConfig< 'blockSelection', { selectedIds?: Set<string>; } & BlockSelectionSelectors, >; // After: export type BlockSelectionConfig = PluginConfig< 'blockSelection', { selectedIds?: Set<string>; }, {}, // API {}, // Transforms BlockSelectionSelectors, // Selectors }>
@udecode/[email protected]
@udecode/[email protected]
-
#4048 by @zbeyens – Upgrade to
zustand-x@2. Migration needed only if you use one of these stores:ImagePreviewStoreFloatingMediaStore
-
#4048 by @zbeyens – Upgrade to
jotai-x@2. Migration needed only if you useusePlaceholderStore
@udecode/[email protected]
@udecode/[email protected]
-
#4048 by @zbeyens – Move store state
selectedCellsandselectedTablesfromuseTableStoretoTablePluginoptions store. This fixes the issue to get access to those state outside a table element (e.g. the toolbar) -
#4048 by @zbeyens – Upgrade to
jotai-x@2. Migration needed only if you useuseTableStore
43.0.0
No breaking changes. Upgraded all dependencies to the latest version.
42.0.1
@udecode/[email protected]
- #3920 by @zbeyens – AI plugins are now experimental: pin the dependency to avoid breaking changes. No breaking changes for this release.
@udecode/[email protected]
-
#3920 by @zbeyens – This package is now deprecated and will be renamed to
@udecode/plate. Migration:- Remove
@udecode/plate-commonand install@udecode/plate - Replace all
'@udecode/plate-common'with'@udecode/plate',
- Remove
@udecode/[email protected]
-
-
Plugin
normalizeInitialValuenow returnsvoidinstead ofValue. When mutating nodes, keep their references (e.g., useObject.assigninstead of spread). -
Editor methods have moved to
editor.tfandeditor.api. They still exist at the top level for slate backward compatibility, but are no longer redundantly typed. If you truly need the top-level method types, extend your editor type withLegacyEditorMethods(e.g.editor as Editor & LegacyEditorMethods). Since these methods can be overridden byextendEditor,with..., or slate plugins, consider migrating to the following approaches:// For overriding existing methods only: overrideEditor(({ editor, tf: { deleteForward }, api: { isInline } }) => ({ transforms: { deleteForward(options) { // ...conditional override deleteForward(options); }, }, api: { isInline(element) { // ...conditional override return isInline(element); }, }, }));
This was previously done in
extendEditorusing top-level methods, which still works but now throws a type error due to the move toeditor.tf/editor.api. A workaround is to extend your editor withLegacyEditorMethods.Why? Having all methods at the top-level (next to
children,marks, etc.) would clutter the editor interface. Slate splits transforms in three places (editor,Editor, andTransforms), which is also confusing. We've reorganized them intotfandapifor better DX, but also to support transform-only middlewares in the future. This also lets us leverageextendEditorTransforms,extendEditorApi, andoverrideEditorto modify those methods.Migration example:
// From: export const withInlineVoid: ExtendEditor = ({ editor }) => { const { isInline, isSelectable, isVoid, markableVoid } = editor; const voidTypes: string[] = []; const inlineTypes: string[] = []; editor.pluginList.forEach((plugin) => { if (plugin.node.isInline) { inlineTypes.push(plugin.node.type); } if (plugin.node.isVoid) { voidTypes.push(plugin.node.type); } }); editor.isInline = (element) => { return inlineTypes.includes(element.type as any) ? true : isInline(element); }; editor.isVoid = (element) => { return voidTypes.includes(element.type as any) ? true : isVoid(element); }; return editor; }; export const InlineVoidPlugin = createSlatePlugin({ key: 'inlineVoid', extendEditor: withInlineVoid, }); // After (using overrideEditor since we're only overriding existing methods): export const withInlineVoid: OverrideEditor = ({ api: { isInline, isSelectable, isVoid, markableVoid }, editor, }) => { const voidTypes: string[] = []; const inlineTypes: string[] = []; editor.pluginList.forEach((plugin) => { if (plugin.node.isInline) { inlineTypes.push(plugin.node.type); } if (plugin.node.isVoid) { voidTypes.push(plugin.node.type); } }); return { api: { isInline(element) { return inlineTypes.includes(element.type as any) ? true : isInline(element); }, isVoid(element) { return voidTypes.includes(element.type as any) ? true : isVoid(element); }, }, }; }; export const InlineVoidPlugin = createSlatePlugin({ key: 'inlineVoid', }).overrideEditor(withInlineVoid);- Move
editor.redecoratetoeditor.api.redecorate
Types:
- Rename
TRenderElementPropstoRenderElementProps - Rename
TRenderLeafPropstoRenderLeafProps - Rename
TEditablePropstoEditableProps
-
@udecode/[email protected]
-
#3920 by @zbeyens – This package is now the new common package, so all plugin packages are being removed. Migration:
- Add the following dependencies:
"@udecode/plate-alignment": "42.0.0", "@udecode/plate-autoformat": "42.0.0", "@udecode/plate-basic-elements": "42.0.0", "@udecode/plate-basic-marks": "42.0.0", "@udecode/plate-block-quote": "42.0.0", "@udecode/plate-break": "42.0.0", "@udecode/plate-code-block": "42.0.0", "@udecode/plate-combobox": "42.0.0", "@udecode/plate-comments": "42.0.0", "@udecode/plate-csv": "42.0.0", "@udecode/plate-diff": "42.0.0", "@udecode/plate-docx": "42.0.0", "@udecode/plate-find-replace": "42.0.0", "@udecode/plate-floating": "42.0.0", "@udecode/plate-font": "42.0.0", "@udecode/plate-heading": "42.0.0", "@udecode/plate-highlight": "42.0.0", "@udecode/plate-horizontal-rule": "42.0.0", "@udecode/plate-indent": "42.0.0", "@udecode/plate-indent-list": "42.0.0", "@udecode/plate-kbd": "42.0.0", "@udecode/plate-layout": "42.0.0", "@udecode/plate-line-height": "42.0.0", "@udecode/plate-link": "42.0.0", "@udecode/plate-list": "42.0.0", "@udecode/plate-markdown": "42.0.0", "@udecode/plate-media": "42.0.0", "@udecode/plate-mention": "42.0.0", "@udecode/plate-node-id": "42.0.0", "@udecode/plate-normalizers": "42.0.0", "@udecode/plate-reset-node": "42.0.0", "@udecode/plate-resizable": "42.0.0", "@udecode/plate-select": "42.0.0", "@udecode/plate-selection": "42.0.0", "@udecode/plate-slash-command": "42.0.0", "@udecode/plate-suggestion": "42.0.0", "@udecode/plate-tabbable": "42.0.0", "@udecode/plate-table": "42.0.0", "@udecode/plate-toggle": "42.0.0", "@udecode/plate-trailing-block": "42.0.0"- Either replace all
@udecode/plateimports with the individual package imports, or export the following in a new file (e.g.src/plate.ts):
export * from '@udecode/plate-alignment'; export * from '@udecode/plate-autoformat'; export * from '@udecode/plate-basic-elements'; export * from '@udecode/plate-basic-marks'; export * from '@udecode/plate-block-quote'; export * from '@udecode/plate-break'; export * from '@udecode/plate-code-block'; export * from '@udecode/plate-combobox'; export * from '@udecode/plate-comments'; export * from '@udecode/plate-diff'; export * from '@udecode/plate-find-replace'; export * from '@udecode/plate-font'; export * from '@udecode/plate-heading'; export * from '@udecode/plate-highlight'; export * from '@udecode/plate-horizontal-rule'; export * from '@udecode/plate-indent'; export * from '@udecode/plate-indent-list'; export * from '@udecode/plate-kbd'; export * from '@udecode/plate-layout'; export * from '@udecode/plate-line-height'; export * from '@udecode/plate-link'; export * from '@udecode/plate-list'; export * from '@udecode/plate-media'; export * from '@udecode/plate-mention'; export * from '@udecode/plate-node-id'; export * from '@udecode/plate-normalizers'; export * from '@udecode/plate-reset-node'; export * from '@udecode/plate-select'; export * from '@udecode/plate-csv'; export * from '@udecode/plate-docx'; export * from '@udecode/plate-markdown'; export * from '@udecode/plate-slash-command'; export * from '@udecode/plate-suggestion'; export * from '@udecode/plate-tabbable'; export * from '@udecode/plate-table'; export * from '@udecode/plate-toggle'; export * from '@udecode/plate-trailing-block'; export * from '@udecode/plate-alignment/react'; export * from '@udecode/plate-autoformat/react'; export * from '@udecode/plate-basic-elements/react'; export * from '@udecode/plate-basic-marks/react'; export * from '@udecode/plate-block-quote/react'; export * from '@udecode/plate-break/react'; export * from '@udecode/plate-code-block/react'; export * from '@udecode/plate-combobox/react'; export * from '@udecode/plate-comments/react'; export * from '@udecode/plate-floating'; export * from '@udecode/plate-font/react'; export * from '@udecode/plate-heading/react'; export * from '@udecode/plate-highlight/react'; export * from '@udecode/plate-layout/react'; export * from '@udecode/plate-slash-command/react'; export * from '@udecode/plate-indent/react'; export * from '@udecode/plate-indent-list/react'; export * from '@udecode/plate-kbd/react'; export * from '@udecode/plate-line-height/react'; export * from '@udecode/plate-link/react'; export * from '@udecode/plate-list/react'; export * from '@udecode/plate-media/react'; export * from '@udecode/plate-reset-node/react'; export * from '@udecode/plate-selection'; export * from '@udecode/plate-suggestion/react'; export * from '@udecode/plate-tabbable/react'; export * from '@udecode/plate-table/react'; export * from '@udecode/plate-toggle/react'; export * from '@udecode/plate-resizable';- Replace all
'@udecode/plate'and'@udecode/plate/react'with'@/plate'in your codebase.
@udecode/[email protected]
- #3920 by @zbeyens –
- Removed unused
moveSelectionByOffset,getLastBlockDOMNode,useLastBlock,useLastBlockDOMNode
- Removed unused
@udecode/[email protected]
@udecode/[email protected]
-
- Remove
slate,slate-dom,slate-react,slate-historyandslate-hyperscriptfrom your dependencies. It's now part of this package and@udecode/plate. All exports remain the same or have equivalents (see below). - Renamed
createTEditortocreateEditor. createEditornow returns an editor (Editor) with all queries undereditor.apiand transforms undereditor.tf. You can see or override them at a glance. For example, we now useeditor.tf.setNodesinstead of importingsetNodes. This marks the completion of generic typing and the removal of error throws fromslate,slate-dom, andslate-historyqueries/transforms, without forking implementations. We’ve also reduced the number of queries/transforms by merging a bunch of them.
The following interfaces from
slateandslate-domare now part ofEditor:-
Editor,EditorInterface -
Transforms -
HistoryEditor(noop, unchanged),HistoryEditorInterface -
DOMEditor(noop, unchanged),DOMEditorInterface -
editor.findPathnow returnsDOMEditor.findPath(memo) and falls back tofindNodePath(traversal, less performant) if not found. -
Removed the first parameter (
editor) from:editor.hasEditableTargeteditor.hasSelectableTargeteditor.isTargetInsideNonReadonlyVoideditor.hasRangeeditor.hasTarget
-
editor.api.node(options)(previouslyfindNode)atoption is nowat ?? editor.selectioninstead ofat ?? editor.selection ?? []. That means if you want to lookup the entire document, you need to pass[]explicitly. -
Removed
setNodein favor ofsetNodes(you can now pass aTNodetoatdirectly). -
Removed
setElementsin favor ofsetNodes. -
Removed unused
isWordAfterTrigger,setBlockAboveNode,setBlockAboveTexts,setBlockNodes,getPointNextToVoid. -
Replaced
Pathfrom slate withPath(type) andPathApi(static methods). -
Replaced
Operationfrom slate withOperation(type) andOperationApi(static methods). -
Replaced
Pointfrom slate withPoint(type) andPointApi(static methods). -
Replaced
Textfrom slate withTText(type) andTextApi(static methods). We also exportTexttype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Replaced
Rangefrom slate withTRange(type) andRangeApi(static methods). We also exportRangetype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Replaced
Locationfrom slate withTLocation(type) andLocationApi(static methods). We also exportLocationtype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Replaced
Spanfrom slate withSpan(type) andSpanApi(static methods). -
Replaced
Nodefrom slate withTNode(type) andNodeApi(static methods). We also exportNodetype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Replaced
Elementfrom slate withTElement(type) andElementApi(static methods). We also exportElementtype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Signature change:
editor.tf.toggle.block({ type, ...options })->editor.tf.toggleBlock(type, options)editor.tf.toggle.mark({ key, clear })->editor.tf.toggleMark(key, { remove: clear })
-
Moved editor functions:
addMark->editor.tf.addMarkaddRangeMarks->editor.tf.setNodes(props, { at, marks: true })blurEditor->editor.tf.blurcollapseSelection->editor.tf.collapsecreateDocumentNode->editor.api.create.value(core)createNode->editor.api.create.blockcreatePathRef->editor.api.pathRefcreatePointRef->editor.api.pointRefcreateRangeRef->editor.api.rangeRefdeleteBackward({ unit })->editor.tf.deleteBackward(unit)deleteForward({ unit })->editor.tf.deleteForward(unit)deleteFragment->editor.tf.deleteFragmentdeleteText->editor.tf.deletedeselect->editor.tf.deselectdeselectEditor->editor.tf.deselectDOMduplicateBlocks->editor.tf.duplicateNodes({ nodes })findDescendant->editor.api.descendantfindEditorDocumentOrShadowRoot->editor.api.findDocumentOrShadowRootfindEventRange->editor.api.findEventRangefindNode(options)->editor.api.node(options)findNodeKey->editor.api.findKeyfindNodePath->editor.api.findPathfindPath->editor.api.findPathfocusEditor->editor.tf.focus({ at })focusEditorEdge->editor.tf.focus({ at, edge: 'startEditor' | 'endEditor' })getAboveNode->editor.api.abovegetAncestorNode->editor.api.block({ highest: true })getBlockAbove->editor.api.block({ at, above: true })oreditor.api.block()ifatis not a pathgetBlocks->editor.api.blocksgetEdgeBlocksAbove->editor.api.edgeBlocksgetEdgePoints->editor.api.edgesgetEditorString->editor.api.stringgetEditorWindow->editor.api.getWindowgetEndPoint->editor.api.endgetFirstNode->editor.api.firstgetFragment->editor.api.fragmentgetFragmentProp(fragment, options)->editor.api.prop({ nodes, ...options})getLastNode->editor.api.lastgetLastNodeByLevel(level)->editor.api.last([], { level })getLeafNode->editor.api.leafgetLevels->editor.api.levelsgetMark->editor.api.markgetMarks->editor.api.marksgetNextNode->editor.api.nextgetNextNodeStartPoint->editor.api.start(at, { next: true })getNodeEntries->editor.api.nodesgetNodeEntry->editor.api.node(at, options)getNodesRange->editor.api.nodesRangegetParentNode->editor.api.parentgetPath->editor.api.pathgetPathRefs->editor.api.pathRefsgetPoint->editor.api.pointgetPointAfter->editor.api.aftergetPointBefore->editor.api.beforegetPointBeforeLocation->editor.api.beforegetPointRefs->editor.api.pointRefsgetPositions->editor.api.positionsgetPreviousBlockById->editor.api.previous({ id, block: true })getPreviousNode->editor.api.previousgetPreviousNodeEndPoint->editor.api.end({ previous: true })getPreviousSiblingNode->editor.api.previous({ at, sibling: true })getRange->editor.api.rangegetRangeBefore->editor.api.range('before', to, { before })getRangeFromBlockStart->editor.api.range('start', to)getRangeRefs->editor.api.rangeRefsgetSelectionFragment->editor.api.fragment(editor.selection, { structuralTypes })getSelectionText->editor.api.string()getStartPoint->editor.api.startgetVoidNode->editor.api.voidhasBlocks->editor.api.hasBlockshasEditorDOMNode->editor.api.hasDOMNodehasEditorEditableTarget->editor.api.hasEditableTargethasEditorSelectableTarget->editor.api.hasSelectableTargethasEditorTarget->editor.api.hasTargethasInlines->editor.api.hasInlineshasTexts->editor.api.hasTextsinsertBreak->editor.tf.insertBreakinsertData->editor.tf.insertDatainsertElements->editor.tf.insertNodes<TElement>insertEmptyElement->editor.tf.insertNodes(editor.api.create.block({ type }))insertFragment->editor.tf.insertFragmentinsertNode->editor.tf.insertNodeinsertNodes->editor.tf.insertNodesinsertText->editor.tf.insertText({ at })oreditor.tf.insertText({ marks: false })withoutatisAncestorEmpty->editor.api.isEmptyisBlock->editor.api.isBlockisBlockAboveEmpty->editor.api.isEmpty(editor.selection, { block: true })isBlockTextEmptyAfterSelection->editor.api.isEmpty(editor.selection, { after: true })isCollapsed(editor.selection)->editor.api.isCollapsed()isComposing->editor.api.isComposingisDocumentEnd->editor.api.isEditorEndisEdgePoint->editor.api.isEdgeisEditorEmpty->editor.api.isEmpty()isEditorFocused->editor.api.isFocusedisEditorNormalizing->editor.api.isNormalizingisEditorReadOnly->editor.api.isReadOnlyisElementEmpty->editor.api.isEmptyisElementReadOnly->editor.api.elementReadOnlyisEndPoint->editor.api.isEndisExpanded(editor.selection)->editor.api.isCollapsed()isInline->editor.api.isInlineisMarkableVoid->editor.api.markableVoidisMarkActive->editor.api.hasMark(key)isPointAtWordEnd->editor.api.isAt({ at, word: true, end: true })isRangeAcrossBlocks->editor.api.isAt({ at, blocks: true })isRangeInSameBlock->editor.api.isAt({ at, block: true })isRangeInSingleText->editor.api.isAt({ at, text: true })isSelectionAtBlockEnd->editor.api.isAt({ end: true })isSelectionAtBlockStart->editor.api.isAt({ start: true })isSelectionCoverBlock->editor.api.isAt({ block: true, start: true, end: true })isSelectionExpanded->editor.api.isExpanded()isStartPoint->editor.api.isStartisTargetinsideNonReadonlyVoidEditor->editor.api.isTargetInsideNonReadonlyVoidisTextByPath->editor.api.isText(at)isVoid->editor.api.isVoidliftNodes->editor.tf.liftNodesmergeNodes->editor.tf.mergeNodesmoveChildren->editor.tf.moveNodes({ at, to, children: true, fromIndex, match: (node, path) => boolean })moveNodes->editor.tf.moveNodesmoveSelection->editor.tf.movenormalizeEditor->editor.tf.normalizeremoveEditorMark->editor.tf.removeMarkremoveEditorText->editor.tf.removeNodes({ text: true, empty: false })removeEmptyPreviousBlock->editor.tf.removeNodes({ previousEmptyBlock: true })removeMark(options)->editor.tf.removeMarks(keys, options)removeNodeChildren->editor.tf.removeNodes({ at, children: true })removeNodes->editor.tf.removeNodesremoveSelectionMark->editor.tf.removeMarks()replaceNode(editor, { nodes, insertOptions, removeOptions })->editor.tf.replaceNodes(nodes, { removeNodes, ...insertOptions })select->editor.tf.selectselectEndOfBlockAboveSelection->editor.tf.select(editor.selection, { edge: 'end' })selectNodes->editor.tf.select(editor.api.nodesRange(nodes))setFragmentData->editor.tf.setFragmentDatasetMarks(marks, clear)->editor.tf.addMarks(marks, { remove: string | string[] })setNodes->editor.tf.setNodessetPoint->editor.tf.setPointsetSelection->editor.tf.setSelectionsomeNode->editor.api.some(options)splitNodes->editor.tf.splitNodestoDOMNode->editor.api.toDOMNodetoDOMPoint->editor.api.toDOMPointtoDOMRange->editor.api.toDOMRangetoggleWrapNodes->editor.tf.toggleBlock(type, { wrap: true })toSlateNode->editor.api.toSlateNodetoSlatePoint->editor.api.toSlatePointtoSlateRange->editor.api.toSlateRangeunhangCharacterRange->editor.api.unhangRange(range, { character: true })unhangRange->editor.api.unhangRangeunsetNodes->editor.tf.unsetNodesunwrapNodes->editor.tf.unwrapNodeswithoutNormalizing->editor.tf.withoutNormalizingwrapNodeChildren->editor.tf.wrapNodes(element, { children: true })wrapNodes->editor.tf.wrapNodesreplaceNodeChildren->editor.tf.replaceNodes({ at, children: true })resetEditor->editor.tf.resetresetEditorChildren->editor.tf.reset({ children: true })selectEditor->editor.tf.select([], { focus, edge })selectSiblingNodePoint->editor.tf.select(at, { next, previous })
-
Moved to
NodeApi.:getNextSiblingNodes(parentEntry, path)->NodeApi.children(editor, path, { from: path.at(-1) + 1 })getFirstNodeText->NodeApi.firstTextgetFirstChild([node, path])->NodeApi.firstChild(editor, path)getLastChild([node, path])->NodeApi.lastChild(editor, path)getLastChildPath([node, path])->NodeApi.lastChild(editor, path)isLastChild([node, path], childPath)->NodeApi.isLastChild(editor, childPath)getChildren([node, path])->Array.from(NodeApi.children(editor, path))getCommonNode->NodeApi.commongetNode->NodeApi.getgetNodeAncestor->NodeApi.ancestorgetNodeAncestors->NodeApi.ancestorsgetNodeChild->NodeApi.childgetNodeChildren->NodeApi.childrengetNodeDescendant->NodeApi.descendantgetNodeDescendants->NodeApi.descendantsgetNodeElements->NodeApi.elementsgetNodeFirstNode->NodeApi.firstgetNodeFragment->NodeApi.fragmentgetNodeLastNode->NodeApi.lastgetNodeLeaf->NodeApi.leafgetNodeLevels->NodeApi.levelsgetNodeParent->NodeApi.parentgetNodeProps->NodeApi.extractPropsgetNodes->NodeApi.nodesgetNodeString->NodeApi.stringgetNodeTexts->NodeApi.textshasNode->NodeApi.hashasSingleChild->NodeApi.hasSingleChildisAncestor->NodeApi.isAncestorisDescendant->NodeApi.isDescendantisEditor->NodeApi.isEditorisNode->NodeApi.isNodeisNodeList->NodeApi.isNodeListnodeMatches->NodeApi.matches
-
Moved to
ElementApi.:elementMatches->ElementApi.matchesisElement->ElementApi.isElementisElementList->ElementApi.isElementList
-
Moved to
TextApi.:isText->TextApi.isText(at)
-
Moved to
RangeApi.:isCollapsed->RangeApi.isCollapsedisExpanded->RangeApi.isExpanded
-
Moved to
PathApi.:isFirstChild->!PathApi.hasPreviousgetPreviousPath->PathApi.previous
-
Moved to
PointApi.:getPointFromLocation({ at, focus })->PointApi.get(at, { focus })
-
Moved from
@udecode/plate/reactto@udecode/plate:Hotkeys
-
Upgraded to
zustand@5andzustand-x@5:- Replace
createZustandStore('name')(initialState)withcreateZustandStore(initialState, { mutative: true, name: 'name' }) - All plugin stores now use zustand-mutative for immutable state updates, which is faster than
immer.
- Replace
Types:
- Rename the following types:
TEditor->EditorTOperation->OperationTPath->PathTNodeProps->NodePropsTNodeChildEntry->NodeChildEntryTNodeEntry->NodeEntryTDescendant->DescendantTDescendantEntry->DescendantEntryTAncestor->AncestorTAncestorEntry->AncestorEntryTElementEntry->ElementEntryTTextEntry->TextEntry
- Query/transform options now use generic
V extends Valueinstead ofE extends Editor. getEndPoint,getEdgePoints,getFirstNode,getFragment,getLastNode,getLeafNode,getPath,getPoint,getStartPointcan returnundefinedif not found (suppressing error throws).NodeApi.ancestor,NodeApi.child,NodeApi.common,NodeApi.descendant,NodeApi.first,NodeApi.get,NodeApi.last,NodeApi.leaf,NodeApi.parent,NodeApi.getIf,PathApi.previousreturnundefinedif not found instead of throwing- Replace
NodeOftype withDescendantOfineditor.tf.setNodeseditor.tf.unsetNodes,editor.api.previous,editor.api.node,editor.api.nodes,editor.api.last - Enhanced
editor.tf.setNodes:- Added
marksoption to handle mark-specific operations - When
marks: true:- Only applies to text nodes in non-void nodes or markable void nodes
- Automatically sets
split: trueandvoids: true - Handles both expanded ranges and collapsed selections in markable voids
- Replaces
addRangeMarksfunctionality
- Added
- Remove
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
-
#3920 by @zbeyens – Major performance improvement: all table cells were re-rendering when a single cell changed. This is now fixed.
TablePluginnow depends onNodeIdPlugin.- Table merging is now enabled by default:
- Renamed
enableMergingtodisableMerge. - Migration:
enableMerging: true→ remove the option.- otherwise →
TablePlugin.configure({ options: { disableMerge: true } })
- Renamed
- Renamed
unmergeTableCellstosplitTableCell. - Renamed
editor.api.create.celltoeditor.api.create.tableCell. - In
useTableMergeState, renamedcanUnmergetocanSplit. insertTableRowandinsertTableColumn: removeddisableSelectin favor ofselect. Migration: replace it with the opposite boolean.getTableCellBorders: params(element, options)→(editor, options); removedisFirstCellandisFirstRow.- Merged
useTableCellElementStateintouseTableCellElement:- Removed its parameter.
- Removed
hoveredandhoveredLeftreturns (use CSS instead). - Renamed
rowSizetominHeight. - Computes column sizes and returns
width.
- Merged
useTableCellElementResizableStateintouseTableCellElementResizable:- Removed
onHoverandonHoverEndprops (use CSS instead).
- Removed
- Merged
useTableElementStateintouseTableElement:- Removed its parameter.
- No longer computes and returns
colSizes,minColumnWidth, andcolGroupProps.
41.0.2
@udecode/[email protected]
-
#3830 by @felixfeng33 – Rename
findNodePathtofindPathsince the addition offindNodePathin the headless lib.We recommend using
findPathmostly when subscribing to its value (e.g. in a React component) as it has O(path.length) complexity, compared to O(n) for the traversal-basedfindNodePath. This optimization is particularly important in:- Render functions of Plate components where using
findNodePathwould increase the initial render time by O(n²) - Key press handlers where using
findNodePathwould increase the handling time by O(n)
where n is the number of nodes in the editor.
- Render functions of Plate components where using
@udecode/[email protected]
-
- Removed
useDndBlock,useDragBlock, anduseDropBlockhooks in favor ofuseDndNode,useDragNode, anduseDropNode. - Removed
DndProvideranduseDraggableStore. Drop line state is now managed byDndPluginas a single state objectdropTargetcontaining bothidandline. useDropNode: removedonChangeDropLineanddropLineoptions
Migration steps:
- Remove
DndProviderfrom your draggable component (e.g.draggable.tsx) - Replace
useDraggableStorewithuseEditorPlugin(DndPlugin).useOption - Remove
useDraggableState. Useconst { isDragging, previewRef, handleRef } = useDraggable - Remove
useDraggableGutter. SetcontentEditable={false}to your gutter element - Remove
propsfromuseDropLine. SetcontentEditable={false}to your drop line element - Remove
withDraggable,useWithDraggable. UseDraggableAboveNodesinstead
- Removed
@udecode/[email protected]
- #3830 by @felixfeng33 –
- Move
render.belowNodesfromIndentListPlugintoBaseIndentListPlugin. Props type forlistStyleTypes.liComponentandlistStyleTypes.markerComponentoptions is nowSlateRenderElementPropsinstead ofPlateRenderElementProps - Move
someIndentList,someIndentTodofrom@udecode/plate-indent-list/reactto@udecode/plate-indent-list
- Move
@udecode/[email protected]
-
insertColumnGroup: renamelayouttocolumns- Remove
setColumnWidth,useColumnState. UsesetColumnsinstead
@udecode/[email protected]
-
#3830 by @felixfeng33 – Move from
@udecode/plate-table/reactto@udecode/plate-table:deleteColumndeleteColumnWhenExpandeddeleteRowdeleteRowWhenExpandedgetTableColumngetTableGridAbovegetTableGridByRangegetTableRowinsertTablemergeTableCellsmoveSelectionFromCelloverrideSelectionFromCellunmergeTableCellswithDeleteTablewithGetFragmentlablewithInsertFragmentTablewithInsertTextTablewithMarkTablewithSelectionTablewithSetFragmentDataTablewithTable
40.0.0
@udecode/[email protected]
- #3744 by @zbeyens –
- Add
slate-domas a peer dependency. - Update
slate-reactpeer dependency to>=0.111.0
- Add
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3744 by @zbeyens –
- Remove
toggleColumnsin favor oftoggleColumnGroup - Remove
insertEmptyColumnin favor ofinsertColumn
- Remove
39.0.0
@udecode/[email protected]
-
#3597 by @zbeyens – The following changes were made to improve performance:
- Refactored
useDraggablehook to focus on core dragging functionality:- Removed
dropLine. UseuseDropLine().dropLineinstead. - Removed
groupPropsfrom the returned object –isHovered, andsetIsHoveredfrom the returned state. Use CSS instead. - Removed
droplineProps, andgutterLeftPropsfrom the returned object. UseuseDropLine().props,useDraggableGutter().propsinstead.
- Removed
- Refactored
@udecode/[email protected]
-
#3597 by @zbeyens – The following changes were made to improve performance:
- Removed
useHooksBlockSelectionin favor ofBlockSelectionAfterEditable - Removed
slate-selectedclass fromBlockSelectable. You can do it on your components usinguseBlockSelected()instead, or by using our newblock-selection.tsxcomponent. - Introduced
useBlockSelectableStorefor managing selectable state.
- Removed
38.0.1
@udecode/[email protected]
-
- Change
plugin.optionsmerging behavior from deep merge to shallow merge. - This affects
.extend(),.configure(), and other methods that modify plugin options. - This update addresses a performance regression introduced in v37 that affected editor creation.
Before:
const plugin = createSlatePlugin({ key: 'test', options: { nested: { a: 1 } }, }).extend({ options: { nested: { b: 1 } }, }); // Result: { nested: { a: 1, b: 1 } }After:
const plugin = createSlatePlugin({ key: 'test', options: { nested: { a: 1 } }, }).extend(({ getOptions }) => ({ options: { ...getOptions(), nested: { ...getOptions().nested, b: 1 }, }, })); // Result: { nested: { a: 1, b: 1 } }Migration:
- If you're using nested options and want to preserve the previous behavior, you need to manually spread both the top-level options and the nested objects.
- If you're not using nested options, no changes are required.
- Change
-
Rename all base plugins that have a React plugin counterpart to be prefixed with
Base. This change improves clarity and distinguishes base implementations from potential React extensions. Use base plugins only for server-side environments or to extend your own DOM layer. -
Import the following plugins from
/reactentry:AlignPlugin,CalloutPlugin,EquationPlugin,FontBackgroundColorPlugin,FontColorPlugin,FontFamilyPlugin,FontSizePlugin,FontWeightPlugin,InlineEquationPlugin,LineHeightPlugin,TextIndentPlugin,TocPlugin
37.0.0
Migration example: https://github.com/udecode/plate/pull/3480
We recommend to upgrade to @udecode/[email protected] in one-go.
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createBasicElementPlugins->BasicElementsPlugincreateBlockquotePlugin->BlockquotePlugincreateCodeBlockPlugin->CodeBlockPlugincreateHeadingPlugin->HeadingPlugin- Move paragraph plugin to
@udecode/plate-core
@udecode/[email protected]
- #3420 by @zbeyens –
createBasicMarksPlugins->BasicMarksPlugincreateBoldPlugin->BoldPlugincreateCodePlugin->CodePlugincreateItalicPlugin->ItalicPlugincreateStrikethroughPlugin->StrikethroughPlugincreateSubscriptPlugin->SubscriptPlugincreateSuperscriptPlugin->SuperscriptPlugincreateUnderlinePlugin->UnderlinePlugin- All mark plugins removed
hotkeyoption. Useplugin.shortcutsinstead (see plate-core)
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createSoftBreakPlugin->SoftBreakPlugincreateExitBreakPlugin->ExitBreakPlugincreateSingleLinePlugin->SingleLinePlugin
@udecode/[email protected]
- #3420 by @zbeyens –
createCaptionPlugin->CaptionPluginCaptionPluginoptions:- Rename
pluginKeystoplugins - Rename
focusEndCaptionPathtofocusEndPath - Rename
focusStartCaptionPathtofocusStartPath - Rename
showCaptionIdtovisibleId - Rename
isShowtoisVisible
- Rename
- Move
captionGlobalStoretoCaptionPlugin
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createCodeBlockPlugin->CodeBlockPlugin- NEW
CodeLinePlugin - NEW
CodeSyntaxPlugin - Remove
getCodeLineType, useeditor.getType(CodeLinePlugin)instead
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createCommentsPlugin->CommentsPlugin- Move
commentsStoretoCommentsPlugin - Remove
CommentsProviderand its hooks - Remove
useCommentsStates(replaced by direct option access) - Remove
useCommentsSelectors(replaced by option selectors) - Remove
useCommentsActions(replaced by api methods) - Replace
useUpdateCommentwithapi.comment.updateComment - Replace
useAddRawCommentwithapi.comment.addRawComment - Replace
useAddCommentwithapi.comment.addComment - Replace
useRemoveCommentwithapi.comment.removeComment - Replace
useResetNewCommentValuewithapi.comment.resetNewCommentValue - Replace
useNewCommentTextwithoptions.newText - Replace
useMyUserwithoptions.myUser - Replace
useUserByIdwithoptions.userById - Replace
useCommentByIdwithoptions.commentById - Replace
useActiveCommentwithoptions.activeComment - Replace
useAddCommentMarkwithinsert.comment
@udecode/[email protected]
- #3420 by @zbeyens –
- Split build into
@udecode/plate-commonand@udecode/plate-common/react. - NEW
/reactexports@udecode/react-hotkeys
- Split build into
@udecode/[email protected]
-
#3420 by @zbeyens – Plugin System:
Decoupling React in all packages:
- Split build into
@udecode/plate-coreand@udecode/plate-core/react - NEW
SlatePluginas the foundation for all plugins PlatePluginextendsSlatePluginwith React-specific plugin features
Plugin Creation:
- Remove
createPluginFactory - NEW
createSlatePlugin: vanilla - NEW
createTSlatePlugin: vanilla explicitly typed - NEW
createPlatePlugin: React - NEW
createTPlatePlugin: React explicitly typed - NEW
toPlatePlugin: extend a vanilla plugin into a React plugin - NEW
toTPlatePlugin: extend a vanilla plugin into a React plugin explicitly typed - Rename all plugins starting with
createNamePlugin()toNamePlugin
Before:
const MyPluginFactory = createPluginFactory({ key: 'myPlugin', isElement: true, component: MyComponent, }); const plugin = MyPluginFactory();After:
const plugin = createSlatePlugin({ key: 'myPlugin', node: { isElement: true, component: MyComponent, }, }); const reactPlugin = toPlatePlugin(plugin);Plugin Configuration:
- Remove all
NamePluginoption types, useNameConfiginstead. NameConfigas the new naming convention for plugin configurations.
Before:
createPluginFactory<HotkeyPlugin>({ handlers: { onKeyDown: onKeyDownToggleElement, }, options: { hotkey: ['mod+opt+0', 'mod+shift+0'], }, });After:
export const ParagraphPlugin = createPlatePlugin({ key: 'p', node: { isElement: true }, }).extend({ editor, type }) => ({ shortcuts: { toggleParagraph: { handler: () => { editor.tf.toggle.block({ type }); }, keys: [ [Key.Mod, Key.Alt, '0'], [Key.Mod, Key.Shift, '0'], ], preventDefault: true, }, }, })toggleParagraphis now a shortcut foreditor.tf.toggle.block({ type: 'p' })for the given keys- Multiple shortcuts can be defined per plugin, and any shortcut can be disabled by setting
shortcuts.toggleParagraph = null - Note the typing support using
Key
Plugin Properties:
Rename
SlatePlugin/PlatePluginproperties:type->node.typeisElement->node.isElementisLeaf->node.isLeafisInline->node.isInlineisMarkableVoid->node.isMarkableVoidisVoid->node.isVoidcomponent->node.componentorrender.nodeprops->node.propsoverrideByKey->override.pluginsrenderAboveEditable->render.aboveEditablerenderAboveSlate->render.aboveSlaterenderAfterEditable->render.afterEditablerenderBeforeEditable->render.beforeEditableinject.props->inject.nodePropsinject.props.validTypes->inject.targetPluginsinject.aboveComponent->render.aboveNodesinject.belowComponent->render.belowNodesinject.pluginsByKey->inject.pluginseditor.insertData->parser- NEW
parser.formatnow supportsstring[] - NEW
parser.mimeTypes: string[]
- NEW
deserializeHtml->parsers.html.deserializerdeserializeHtml.getNode->parsers.html.deserializer.parseserializeHtml->parsers.htmlReact.serializerwithOverride->extendEditor- All methods now have a single parameter:
SlatePluginContext<C>orPlatePluginContext<C>, in addition to the method specific options. Some of the affected methods are:decoratehandlers, includingonChange. Returns({ event, ...ctx }) => voidinstead of(editor, plugin) => (event) => voidhandlers.onChange:({ value, ...ctx }) => voidinstead of(editor, plugin) => (value) => voidnormalizeInitialValueeditor.insertData.preInserteditor.insertData.transformDataeditor.insertData.transformFragmentdeserializeHtml.getNodedeserializeHtml.queryinject.props.queryinject.props.transformPropsuseHookswithOverrides
NEW
SlatePluginproperties:api: API methods provided by this plugindependencies: An array of plugin keys that this plugin depends onnode: Node-specific configuration for this pluginparsers: Now acceptstringkeys to add custom parserspriority: Plugin priority for registration and execution ordershortcuts: Plugin-specific hotkeysinject.targetPluginToInject: Function to inject plugin config into other plugins specified byinject.targetPlugins
Before:
export const createAlignPlugin = createPluginFactory({ key: KEY_ALIGN, inject: { props: { defaultNodeValue: 'start', nodeKey: KEY_ALIGN, styleKey: 'textAlign', validNodeValues: ['start', 'left', 'center', 'right', 'end', 'justify'], validTypes: ['p'], }, }, then: (_, plugin) => mapInjectPropsToPlugin(editor, plugin, { deserializeHtml: { getNode: (el, node) => { if (el.style.textAlign) { node[plugin.key] = el.style.textAlign; } }, }, }), });After:
export const AlignPlugin = createSlatePlugin({ inject: { nodeProps: { defaultNodeValue: 'start', nodeKey: 'align', styleKey: 'textAlign', validNodeValues: ['start', 'left', 'center', 'right', 'end', 'justify'], }, targetPluginToInject: ({ editor, plugin }) => ({ parsers: { html: { deserializer: { parse: ({ element, node }) => { if (element.style.textAlign) { node[editor.getType(plugin)] = element.style.textAlign; } }, }, }, }, }), targetPlugins: [ParagraphPlugin.key], }, key: 'align', });Plugin Shortcuts:
- NEW
shortcutsto add custom hotkeys to a plugin. - Remove
hotkeyoption from all plugins
Before:
type LinkPlugin = { hotkey?: string; };After:
type LinkConfig = PluginConfig< // key 'p', // options { defaultLinkAttributes?: any }, // api { link: { getAttributes: (editor: PlateEditor) => LinkAttributes } }, // transforms { floatingLink: { hide: () => void } } >;Shortcuts API:
handleris called with the editor, event, and event details.keysis an array of keys to trigger the shortcut.priorityis the priority of the shortcut over other shortcuts....HotkeysOptionsfrom@udecode/react-hotkeys
Plugin Types:
- Update
SlatePlugin,PlatePlugingenerics.P, V, E->C extends AnyPluginConfig = PluginConfig - Remove
PluginOptions - Remove
PlatePluginKey - Remove
HotkeyPlugin,ToggleMarkPluginin favor ofplugin.shortcuts WithPlatePlugin->EditorPlugin,EditorPlatePluginPlatePluginComponent->NodeComponentInjectComponent*->NodeWrapperComponent*PlatePluginInsertData->ParserPlatePluginProps->NodePropsRenderAfterEditable->EditableSiblingComponentWithOverride->ExtendEditorSerializeHtml->HtmlReactSerializer
Plugin Store:
- NEW each plugin has its own store, accessible via
plugin.optionsStoreandplugin.useOptionsStore editorhas many methods to get, set and subscribe to plugin options
Plugin Methods:
- All plugin methods return a new plugin instance with the extended types.
- Remove
then, useextendinstead - NEW
extendmethod to deep merge a plugin configuration- If you pass an object, it will be directly merged with the plugin config.
- If you pass a function, it will be called with the plugin config once the editor is resolved and should return the new plugin config.
- Object extensions always have the priority over function extensions.
- Extend multiple times to derive from the result of the previous extension.
- NEW
configuremethod to configure the properties of existing plugins. The difference withextendis thatconfigurewith not add new properties to the plugin, it will only modify existing ones. - NEW
extendPluginmethod to extend a nested plugin configuration. - NEW
configurePluginmethod to configure the properties of a nested plugin. - NEW
extendApimethod to extend the plugin API. The API is then merged intoeditor.api[plugin.key]. - NEW
extendTransformsmethod to extend the plugin transforms. The transforms is then merged intoeditor.transforms[plugin.key]. - NEW
extendEditorApimethod to extend the editor API. The API is then merged intoeditor.api. Use this to add or override top-level methods to the editor. - NEW
extendEditorTransformsmethod to extend the editor transforms. The transforms is then merged intoeditor.transforms. - NEW
extendOptionsmethod to extend the plugin options with selectors. Useeditor.useOption(plugin, 'optionKey')to subscribe to an (extended) option. - NEW
withComponentto replaceplugin.node.component
Plugin Context
Each plugin method now receive the plugin context created with
getEditorPlugin(editor, plugin)as parameter:apieditorgetOptiongetOptionspluginsetOptionsetOptionstftypeuseOption
Core Plugins:
- NEW
ParagraphPluginis now part ofcore - NEW
DebugPluginis now part ofcore- NEW
api.debug.log,api.debug.info,api.debug.warn,api.debug.errormethods options.isProductionto control logging in production environmentsoptions.logLevelto set the minimum log leveloptions.loggerto customize logging behavioroptions.throwErrorsto control error throwing behavior, by default aPlateErrorwill be thrown onapi.debug.error
- NEW
- NEW - You can now override a core plugin by adding it to
editor.plugins. Last plugin wins. createDeserializeHtmlPlugin->HtmlPlugin- NEW
api.html.deserialize
- NEW
createEventEditorPlugin->EventEditorPlugineventEditorStore->EventEditorStore
createDeserializeAstPlugin->AstPlugincreateEditorProtocolPlugin->SlateNextPlugin- NEW
editor.tf.toggle.block - NEW
editor.tf.toggle.mark - Remove
createNodeFactoryPlugin, included inSlateNextPlugin. - Remove
createPrevSelectionPlugin, included inSlateNextPlugin.
- NEW
createHistoryPlugin->HistoryPlugincreateInlineVoidPlugin->InlineVoidPlugincreateInsertDataPlugin->ParserPlugincreateLengthPlugin->LengthPlugincreateReactPlugin->ReactPlugin
Editor Creation:
NEW
withSlate:- Extends an editor into a vanilla Plate editor
- NEW
rootPluginoption for configuring the root plugin
NEW
withPlate:- Extends an editor into a React Plate editor
- Now extends
withSlatewith React-specific enhancements - NEW
useOptionsanduseOptionmethods to the editor
NEW
createSlateEditor:- Create a vanilla Plate editor with server-side support
createPlateEditor:-
Plugin replacement mechanism: using
plugins, any plugin with the same key that a previous plugin will replace it. That means you can now override core plugins that way, likeReactPlugin -
rootplugin is now created fromcreatePlateEditoroption as a quicker way to configure the editor than passingplugins. Since plugins can have nested plugins (think as a recursive tree),pluginsoption will be passed torootpluginpluginsoption. -
Centralized editor resolution. Before, both
createPlateEditorandPlatecomponent were resolving the editor. Now, onlycreatePlateEditortakes care of that. That meansid,value, and other options are now controlled bycreatePlateEditor. -
Remove
createPlugins, pass plugins directly:components->override.componentsoverrideByKey->override.plugins
createPlateEditoroptions:- Rename
normalizeInitialValueoption toshouldNormalizeEditor - Move
componentstooverride.componentsto override components by key - Move
overrideByKeytooverride.pluginsto override plugins by key - Remove
disableCorePlugins, useoverride.enabledinstead - NEW
valueto set the initial value of the editor. - NEW
autoSelect?: 'end' | 'start' | booleanto auto select the start of end of the editor. This is decoupled fromautoFocus. - NEW
selectionto control the initial selection. - NEW
override.enabledto disable plugins by key - NEW
rootPlugin?: (plugin: AnyPlatePlugin) => AnyPlatePluginto configure the root plugin. From here, you can for example callconfigurePluginto configure any plugin. - NEW
api,decorate,extendEditor,handlers,inject,normalizeInitialValue,options,override,priority,render,shortcuts,transforms,useHooks. These options will be passed to the very firstrootPlugin.
NEW
usePlateEditor()hook to create aPlateEditorin a React component:- Uses
createPlateEditoranduseMemoto avoid re-creating the editor on every render. - Dependencies can be added to the hook to re-create the editor on demand.
idoption is always used as dependency.
Editor Methods:
editor: PlateEditor:- Move
redecoratetoeditor.api.redecorate - Move
resettoeditor.tf.reset - Move
plate.settoeditor.setPlateState - Move
blockFactorytoeditor.api.create.block - Move
childrenFactorytoeditor.api.create.value - Rename
pluginstopluginList - Rename
pluginsByKeytoplugins - NEW
getApi()to get the editor API - NEW
getTransforms()to get the editor transforms - Remove
getPlugin(editor, key), useeditor.getPlugin(plugin) or editor.getPlugin({ key }) - Remove
getPluginType, useeditor.getType(plugin)to get node type - Remove
getPluginInjectProps(editor, key), useeditor.getPlugin(plugin).inject.props - NEW
getOptionsStore()to get a plugin options store - Remove
getPluginOptions, usegetOptions() - NEW
getOption()to get a plugin option - NEW
setOption()to set a plugin option - NEW
setOptions()to set multiple plugin options. Pass a function to use Immer. Pass an object to merge the options. - NEW
useOptionto subscribe to a plugin option in a React component - NEW
useOptionsto subscribe to a plugin options store in a React component - Remove
getPlugins, useeditor.pluginList - Remove
getPluginsByKey, useeditor.plugins - Remove
mapInjectPropsToPlugin
Editor Types:
The new generic types are:
V extends Value = Value,P extends AnyPluginConfig = PlateCorePlugin- That means this function will infer all plugin configurations from the options passed to it:
keyoptionsapitransforms
- Can't infer for some reason? Use
createTPlateEditorfor explicit typing.
const editor = createPlateEditor({ plugins: [TablePlugin] }); editor.api.htmlReact.serialize(); // core plugin is automatically inferred editor.tf.insert.tableRow(); // table plugin is automatically inferredPlate Component
PlateProps:editoris now required. Ifnull,Platewill not render anything. As before,Plateremounts onidchange.- Remove
id,plugins,maxLength, pass these tocreatePlateEditorinstead - Remove
initialValue,value, passvaluetocreatePlateEditorinstead - Remove
editorRef - Remove
disableCorePlugins, overridepluginsincreatePlateEditorinstead
Utils:
- Remove
useReplaceEditorsinceeditoris now always controlled - NEW
useEditorPluginto get the editor and the plugin context.
Types:
PlateRenderElementProps,PlateRenderLeafPropsgenerics:V, N->N, C
Plate Store:
- Remove
pluginsandrawPlugins, useuseEditorRef().pluginsinstead, or listen to plugin changes witheditor.useOption(plugin, <optionKey>) - Remove
value, useuseEditorValue()instead - Remove
editorRef, useuseEditorRef()instead
Miscellaneous Changes
slate >=0.103.0peer dependencyslate-react >=0.108.0peer dependency- New dependency
@udecode/react-hotkeys - Remove
ELEMENT_,MARK_andKEY_constants. UseNamePlugin.keyinstead. - Replace
ELEMENT_DEFAULTwithParagraphPlugin.key. - Remove
getTEditor - Rename
withTReacttowithPlateReact - Rename
withTHistorytowithPlateHistory - Rename
usePlateIdtouseEditorId - Remove
usePlateSelectors().id(),usePlateSelectors().value(),usePlateSelectors().plugins(), use insteaduseEditorRef().<key> - Rename
toggleNodeTypetotoggleBlock toggleBlockoptions:- Rename
activeTypetotype - Rename
inactiveTypetodefaultType
- Rename
- Remove
react-hotkeys-hookre-exports. Use@udecode/react-hotkeysinstead.
Types:
- Move
TEditableProps,TRenderElementPropsto@udecode/slate-react - Remove
<V extends Value>generic in all functions where not used - Remove
PlatePluginKey - Remove
OverrideByKey - Remove
PlateId
- Split build into
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createDndPlugin->DndPlugin- Remove
editor.isDragging, useeditor.getOptions(DndPlugin).isDragginginstead - Move
dndStoretoDndPlugin
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createFontBackgroundColorPlugin->FontBackgroundColorPlugincreateFontColorPlugin->FontColorPlugincreateFontSizePlugin->FontSizePlugincreateFontFamilyPlugin->FontFamilyPlugincreateFontWeightPlugin->FontWeightPlugin
@udecode/[email protected]
- #3420 by @zbeyens –
createHeadingPlugin->HeadingPlugin- Replace
ELEMENT_H1withHEADING_KEYS.H1 - Replace
KEYS_HEADINGwithHEADING_LEVELS
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createDeserializeHtmlPlugin->HtmlPlugin- Rename
deserializeHtmlplugin tohtml - Rename
deserializeHtml.getNodetoparse
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createIndentListPlugin->IndentListPlugin- Rename
injectIndentListComponenttorenderIndentListBelowNodes - Replace
normalizeIndentListwithwithNormalizeIndentList - Replace
deleteBackwardIndentListwithwithDeleteBackwardIndentList - Replace
insertBreakIndentListwithwithInsertBreakIndentList - Remove types:
LiFC(usePlateRenderElementProps),MarkerFC(useOmit<PlateRenderElementProps, 'children'>)
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createListPlugin->ListPlugin- NEW
BulletedListPlugin - NEW
NumberedListPlugin - NEW
ListItemPlugin - NEW
ListItemContentPlugin - NEW list transforms:
toggle.list,toggle.bulletedList,toggle.numberedList - Remove type utils:
getListItemType,getUnorderedListType,getOrderedListType,getListItemContentType - Replace
insertBreakList(editor)withwithInsertBreakList(ctx) - Replace
insertFragmentList(editor)withwithInsertFragmentList(ctx) - Replace
insertBreakTodoList(editor)withwithInsertBreakTodoList(ctx) - Replace
deleteForwardList(editor)withwithdeleteForwardList(ctx) - Replace
deleteBackwardList(editor)withwithdeleteBackwardList(ctx) - Move list options from
ulandoltolistplugin toggleListoptions are now{ type: string }
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createMediaPlugin->MediaPluginFloatingMediaUrlInput,submitFloatingMediarename optionpluginKey->plugininsertMediaEmbedremovekeyoption
@udecode/[email protected]
- #3420 by @zbeyens –
createMentionPlugin->MentionPlugin- NEW
MentionInputPlugin - Remove
createMentionNodeoption, overrideapi.insert.mentioninstead
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
- NEW
@udecode/plate-layout - NEW
/reactexports@udecode/react-hotkeys - Split build into
@udecode/plateand@udecode/plate/react. - Remove
@udecode/plate-paragraph - All stores now start with a capital letter
- NEW
@udecode/[email protected]
- #3420 by @zbeyens –
- Remove
onKeyDownToggleElement, use shortcuts instead. - Remove
onKeyDownToggleMark, use shortcuts instead.
- Remove
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createSelectOnBackspacePlugin->SelectOnBackspacePlugincreateDeletePlugin->DeletePlugin
@udecode/[email protected]
- #3420 by @zbeyens –
- Rename
createSelectionPlugintoBlockSelectionPlugin - Remove
isNodeBlockSelected,isBlockSelected,hasBlockSelected,useBlockSelectedfunctions- Use
editor.getOptions(BlockSelectionPlugin)oreditor.useOptions(BlockSelectionPlugin)instead
- Use
- Remove
addSelectedRowfunction- Use
editor.api.blockSelection.addSelectedRowinstead
- Use
- Remove
withSelectionHOC - Rename
onCloseBlockSelectiontoonChangeBlockSelection - Moved
blockSelectionStoretoBlockSelectionPlugin - Moved
blockContextMenuStoretoBlockContextMenuPlugin - Remove
BlockStartAreaandBlockSelectionAreacomponents- Use
areaOptionsinBlockSelectionPluginfor configuration instead
- Use
- Remove dependency on
@viselect/vanillapackage- Forked and integrated selection functionality locally
- Add
BlockContextMenuPlugin, which is now used byBlockSelectionPlugin- No need to add it manually
- Fix scroll-related bugs in the selection functionality
- Improve performance and reliability of block selection
- Rename
@udecode/[email protected]
@udecode/[email protected]
-
#3420 by @zbeyens –
createTEditor:- Implement default methods for
slate-reactandslate-historyincreateTEditor - Add
noopfunction to provide default implementations for unimplemented editor methods
Types:
- Merge
ReactEditorandHistoryEditorinterfaces intoTEditor, removingTReactEditorandTHistoryEditor - Remove
Valuegeneric type parameter from function signatures and type definitions - Replace
V extends ValuewithE extends TEditorfor improved type inference - Simplify
TEditor<V>toTEditorin many places - Refactor element-related types, where
E extends TEditorin all cases:EElement<V>toElementOf<E>EText<V>toTextOf<E>ENode<V>toNodeOf<E>EDescendant<V>toDescendantOf<E>EAncestor<V>toAncestorOf<E>EElementOrText<V>toElementOrTextOf<E>
- Update
TNodeEntryrelated types:ENodeEntry<V>toNodeEntryOf<E>EElementEntry<V>toElementEntryOf<E>ETextEntry<V>toTextEntryOf<E>EAncestorEntry<V>toAncestorEntryOf<E>EDescendantEntry<V>toDescendantEntryOf<E>
- Remove unused types:
EElementEntry<V>ETextEntry<V>EDescendantEntry<V>
- Implement default methods for
@udecode/[email protected]
-
- Remove
TReactEditortype, as it's now integrated into the mainTEditortype in@udecode/slate. UseTEditorinstead. - Replace
V extends ValuewithE extends TEditorfor improved type inference - NEW
TEditableProps,TRenderElementProps
- Remove
@udecode/[email protected]
-
- Replace
V extends ValuewithE extends TEditorfor improved type inference
- Replace
@udecode/[email protected]
- #3420 by @zbeyens –
createSuggestionPlugin->SuggestionPlugin- Move
suggestionStoretoSuggestionPlugin - Remove
SuggestionProviderand its hooks - Remove
useSuggestionStates(replaced by direct option access) - Remove
useSuggestionSelectors(replaced by option selectors) - Remove
useSuggestionActions(replaced by api methods) - Replace
useUpdateSuggestionwithapi.suggestion.updateSuggestion - Replace
useAddSuggestionwithapi.suggestion.addSuggestion - Replace
useRemoveSuggestionwithapi.suggestion.removeSuggestion - Replace
useSuggestionByIdwithoptions.suggestionById - Replace
useSuggestionUserByIdwithoptions.suggestionUserById - Replace
useCurrentSuggestionUserwithoptions.currentSuggestionUser - Remove
editor.activeSuggestionId, use plugin option - Remove
useSetIsSuggesting, useeditor.setOption - Remove
useSetActiveSuggestionId, useeditor.setOption - Remove
editor.isSuggesting, use plugin option - Remove
SuggestionEditorPropstype
@udecode/[email protected]
- #3420 by @zbeyens –
createTabbablePlugin->TabbablePluginTabbablePluginoptionisTabbable: remove firsteditorparameter
@udecode/[email protected]
- #3420 by @zbeyens –
createTablePlugin->TablePlugin- NEW
TableRowPlugin,TableCellPlugin,TableCellHeaderPlugin - Replace
insertTableColumnwitheditor.insert.tableColumn - Replace
insertTableRowwitheditor.insert.tableRow - Move
cellFactoryoption tocreate.cellapi - Move
getCellChildrenoption totable.getCellChildrenapi
@udecode/[email protected]
- #3420 by @zbeyens –
createTogglePlugin->TogglePlugin- Move
toggleControllerStoretoTogglePlugin - Remove
setOpenIdsoption - Replace
isToggleOpenwith optionisOpen - Rename
injectToggletorenderToggleAboveNodes
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createYjsPlugin->YjsPlugin- Move
yjsStoretoYjsPlugin - Move
editor.yjs.providertooptions.provider - Rename
RenderAboveEditableYjstoYjsAboveEditable
36.0.0
No breaking changes
35.0.0
@udecode/[email protected]
-
#3282 by @12joan – Make the dependency on prismjs optional
New usage:
// Import Prism with your supported languages import Prism from 'prismjs'; import 'prismjs/components/prism-antlr4.js'; import 'prismjs/components/prism-bash.js'; import 'prismjs/components/prism-c.js'; // ... const plugins = createPlugins([ createCodeBlockPlugin({ options: { prism: Prism, }, }), ]);
34.0.0
@udecode/[email protected]
-
Breaking Change: The
selectedColoroption forBlockSelectablehas been deprecated. Please useuseBlockSelectedto customize the style of each node component. -
#3241 by @felixfeng33 – Add logic for the
block-context-menuand improved the user experience forblock-selection, such as interactions related to keyboard shortcuts, bug fixes. -
Starting from this version, a single Cmd+A will no longer select the entire document but will select the entire block instead. Double Cmd+A will use the blockSelection plugin to select all blocks. To disable this behavior, pass handlers:
{ onKeyDown: null }.
33.0.0
@udecode/[email protected]
32.0.0
None (CI release issue)
31.0.0
None (CI release issue)
30.0.0
@udecode/[email protected]
- #2867 by @12joan – Fix: in v28,
TableProviderwas incorrectly shared by all tables in the editor.TableProvidermust now be rendered as part ofTableElement.
29.0.0
@udecode/[email protected]
- #2829 by @zbeyens –
- Moved
withPropsto@udecode/cn - Moved
PortalBody,Text,Box,createPrimitiveComponent,createSlotComponent,withProvidersto@udecode/react-utils - Removed
getRootProps(unused)
- Moved
28.0.0
@udecode/[email protected]
822f6f56bby @12joan –- Remove
{ fn: ... }workaround for jotai stores that contain functions - Breaking change:
usePlateSelectors,usePlateActionsandusePlateStatesno longer accept generic type arguments. If custom types are required, cast the resulting values at the point of use, or use hooks likeuseEditorRefthat still provide generics.
- Remove
27.0.0
@udecode/[email protected]
- #2763 by @12joan –
- Migrate store to
jotai@2 - Revert the breaking changes to
@udecode/plate-commentsmade in 26.0.0
- Migrate store to
@udecode/[email protected]
- #2763 by @12joan –
- Migrate store from
jotai@1tojotai@2- New dependency:
jotai-x. See https://github.com/udecode/jotai-x - Accessing a store without an explicit provider component is no longer supported. Attempting to do so will result in a warning in the console:
Tried to access jotai store '${storeName}' outside of a matching provider.
- New dependency:
- Upgraded from
zustand@3tozustand@4 - Rename
zustand-xexportsStateActions->ZustandStateActionsStoreApi->ZustandStoreApicreateStore->createZustandStore- Note that these exports are deprecated and should not be used in new code. They may be removed in a future version of Plate.
- Migrate store from
@udecode/[email protected]
- #2763 by @12joan –
- Migrate store to
jotai@2 - Resizable components must now be wrapped inside a
ResizableProvider
- Migrate store to
26.0.0
@udecode/[email protected]
- #2760 by @12joan –
- Renamed the
commentsprop on CommentsProvider toinitialCommentsto reflect the fact that updating its value after the initial render has no effect - Removed the following props from CommentsProvider, since they represent the internal state of the comments plugin and should not be controlled externally:
activeCommentIdaddingCommentIdnewValuefocusTextarea
- The following props on CommentsProvider can now be updated after the initial render (whereas prior to this version, doing so had no effect):
myUserIdusersonCommentAddonCommentUpdateonCommentDelete
- Renamed the
@udecode/[email protected]
25.0.1
@udecode/[email protected]
- #2729 by @12joan – This is a breaking change meant to be part of v25, hence the patch.
On
deserializeHtml, replacestripWhitespacewithcollapseWhiteSpace, defaulting to true. ThecollapseWhiteSpaceoption aims to parse white space in HTML according to the HTML specification, ensuring greater accuracy when pasting HTML from browsers.
@udecode/[email protected]
- #2725 by @EandrewJones – Remove
useCommentValue, which was redundant with the hooks applied automatically inCommentEditTextarea.tsx.
24.0.0
@udecode/[email protected]
-
- [Breaking] Rename
PlatetoPlateContent. - [Breaking] Rename
PlateProvidertoPlate. - [Breaking] Rendering
PlateContentis now required inPlate. This allows you to choose where to render the editor next to other components like toolbar. Example:
// Before <Plate /> // or <PlateProvider> <Plate /> </PlateProvider> // After <Plate> <PlateContent /> </Plate>- [Breaking] Remove provider props such as
pluginsfromPlateContent. These props should be passed toPlate. - [Breaking] Remove
editablePropsprop fromPlateContent. Move these asPlateContentprops. - [Breaking] Remove
childrenprop fromPlateContent. Render instead these components afterPlateContent. - [Breaking] Remove
firstChildrenprop fromPlateContent. Render instead these components beforePlateContent. - [Breaking] Remove
editableRefprop fromPlateContent. Userefinstead. - [Breaking] Remove
withPlateProvider. - [Breaking] Rename
usePlateEditorReftouseEditorRef. - [Breaking] Rename
usePlateEditorStatetouseEditorState. - [Breaking] Rename
usePlateReadOnlytouseEditorReadOnly. This hook can be used belowPlatewhileuseReadOnlycan only be used in node components. - [Breaking] Rename
usePlateSelectiontouseEditorSelection. - [Breaking] Rename store attributes
keyDecorate,keyEditorandkeySelectiontoversionDecorate,versionEditorandversionSelection. These are now numbers incremented on each change. - [Breaking] Rename store attribute
isRenderedtoisMounted.
- [Breaking] Rename
23.0.0
@udecode/[email protected]
-
#2537 by @haydencarlson –
MediaEmbedElementis now more headless with a smaller bundle size. Update the following components:npx shadcn@canary add media-embed-element- now uses
react-lite-youtube-embedfor YouTube videos. - now uses
react-tweetfor Twitter tweets.
- now uses
npx shadcn@canary add image-element
Breaking changes:
- Moved
Resizableto@udecode/plate-resizable - Moved
Caption,CaptionTextareato@udecode/plate-caption - Removed
useMediaEmbed,MediaEmbedVideo,MediaEmbedTweet,Tweet,parseMediaUrl,mediaStore - Removed
@udecode/resizable,scriptjs,react-textarea-autosizedependencies MediaPlugin- removed
rules. Useparsersoption instead. - removed
disableCaption. UsecreateCaptionPlugininstead.
- removed
- Caption is now a separate plugin. Install
@udecode/plate-captionand add it to your plugins:
import { ELEMENT_IMAGE, ELEMENT_MEDIA_EMBED } from '@udecode/plate-media'; createCaptionPlugin({ options: { pluginKeys: [ELEMENT_IMAGE, ELEMENT_MEDIA_EMBED] }, });
@udecode/[email protected]
- #2541 by @zbeyens –
- Package renamed to
@udecode/plate-resizable. ResizeHandleis now fully headless: no style is applied by default. Add your ownResizable,ResizeHandlecomponents:npx shadcn@canary add resizable
- Package renamed to
@udecode/[email protected]
- Removed
TableCellElementResizable. UseuseTableCellElementResizableStateanduseTableCellElementResizableinstead.
22.0.0
Headless UI.
@udecode/[email protected]
- #2471 by @zbeyens – This package is now a CLI to generate components. Install it as a dev dependency. See https://platejs.org/docs/components/cli.
Migration:
- Manual installation.
- For each unresolved import not listed in the following major changes (components from
@udecode/plate-ui-x), generate the component using the CLI.
@udecode/[email protected]
- #2471 by @zbeyens – Removed:
AccountCircleIconCheckIconMoreVertIconRefreshIconAvatarImageCommentLinkButtonCommentLinkDialogCommentLinkDialogCloseButtonCommentLinkDialogCopyLinkCommentLinkDialogInputPlateCommentLeafforuseCommentLeafState
@udecode/[email protected]
- #2471 by @zbeyens – Removed:
DraggableDraggableBlockDraggableBlockToolbarDraggableBlockToolbarWrapperDraggableDroplineDraggableGutterLeftPropsDraggableRootDragHandle
@udecode/[email protected]
- #2471 by @zbeyens – Removed:
FloatingLinkFloatingLinkEditButtonFloatingLinkTextInputUnlinkButtonLaunchIconLinkLinkIconLinkOffIconShortTextIcon
@udecode/[email protected]
@udecode/[email protected]
-
#2471 by @zbeyens – Plate 2.0 – Headless UI. Read the docs about the new UI pattern: https://platejs.org/docs/components.
- Removed
@udecode/plate-uidependency. - Removed
@udecode/plate-emojidependency. You can install it separately. - Removed
styled-componentspeerDependency.
Replaced
@udecode/plate-headlessdependency (deprecated) by:@udecode/plate-alignment@udecode/plate-autoformat@udecode/plate-basic-elements@udecode/plate-basic-marks@udecode/plate-block-quote@udecode/plate-break@udecode/plate-code-block@udecode/plate-combobox@udecode/plate-comments@udecode/plate-common@udecode/plate-find-replace@udecode/plate-floating@udecode/plate-font@udecode/plate-heading@udecode/plate-highlight@udecode/plate-horizontal-rule@udecode/plate-indent@udecode/plate-indent-list@udecode/plate-kbd@udecode/plate-line-height@udecode/plate-link@udecode/plate-list@udecode/plate-media@udecode/plate-mention@udecode/plate-node-id@udecode/plate-normalizers@udecode/plate-paragraph@udecode/plate-reset-node@udecode/plate-select@udecode/plate-serializer-csv@udecode/plate-serializer-docx@udecode/plate-serializer-html@udecode/plate-serializer-md@udecode/plate-suggestion@udecode/plate-tabbable@udecode/plate-table@udecode/plate-trailing-block@udecode/resizable
- Removed
@udecode/[email protected]
- #2471 by @zbeyens – Upgraded peer dependencies:
slate-react: >=0.95.0Removed:useElementPrposuseWrapElementcreateComponentAscreateElementAs
@udecode/[email protected]
- #2471 by @zbeyens – Removed:
TableCellElementTableCellElementResizableWrapperTableCellElementRootTableElementTableElementColTableElementColGroupTableElementRootTableElementTBodyTableRowElementArrowDropDownCircleIconBorderAllIconBorderBottomIconBorderLeftIconBorderNoneIconBorderOuterIconBorderRightIconBorderTopIcon
21.0.0
@udecode/[email protected]
- #2369 by @zbeyens – Support
[email protected],[email protected]and[email protected]by upgrading the peer dependencies.
20.0.0
@udecode/[email protected]
0077402by @zbeyens –- This package has been split into multiple packages for separation of concerns and decoupled versioning:
@udecode/utilsis a collection of miscellaneous utilities. Can be used by any project.@udecode/slateis a collection ofslateexperimental features and bug fixes that may be moved intoslateone day. It's essentially composed of the generic types. Can be used by vanillaslateconsumers without plate.@udecode/slate-reactis a collection ofslate-reactexperimental features and bug fixes that that may be moved intoslate-reactone day. It's essentially composed of the generic types. Can be used by vanillaslate-reactconsumers without plate.@udecode/plate-coreis the minimalistic core of plate. It essentially includesPlate,PlateProviderand their dependencies. Note this package is not dependent on the*-utilspackages.@udecode/slate-utilsis a collection of utils depending on@udecode/slate. Can be used by vanillaslateconsumers without plate.@udecode/plate-utilsis a collection of utils depending on@udecode/slate-reactand@udecode/plate-core@udecode/plate-commonre-exports the 6 previous packages and is a dependency of all the other packages. It's basically replacing@udecore/plate-coreas a bundle.
- Removed
getPreventDefaultHandlersince it is no longer needed. Migration:- If using
@udecode/plateor@udecode/plate-headless: none - Else: find & replace
@udecode/plate-coreby@udecode/plate-common
- If using
- This package has been split into multiple packages for separation of concerns and decoupled versioning:
@udecode/[email protected]
- #2240 by @OliverWales –
- Add
allowedSchemesplugin option- Any URL schemes other than
http(s),mailtoandtelmust be added toallowedSchemes, otherwise they will not be included in links
- Any URL schemes other than
- Add
@udecode/[email protected]
- #2251 by @zbeyens –
TablePluginoptiondisableUnsetSingleColSizehas been renamed and inverted intoenableUnsetSingleColSize. New default is disabled. Migration:- if using
disableUnsetSingleColSize: true, the option can be removed - if using
disableUnsetSingleColSize: false, useenableUnsetSingleColSize: true
- if using
getTableColumnIndexsecond parameter type is now:cellNode: TElement
@udecode/[email protected]
-
#2237 by @tmorane – Unstyled logic has been moved to
@udecode/plate-dnd// before import { createDndPlugin } from '@udecode/plate-ui-dnd'; // after import { createDndPlugin } from '@udecode/plate-dnd';Only
withPlateDraggable,withPlateDraggablesandPlateDraggableare left in@udecode/plate-ui-dnd. Renamed:withDraggables->withPlateDraggables. In the second parameter, draggable props options have been moved underdraggableProps:
// before { onRenderDragHandle: () => {} styles, } // after { draggableProps: { onRenderDragHandle: () => {} styles, }, }
@udecode/[email protected]
- #2251 by @zbeyens – Headless components and hooks moved to
@udecode/plate-table, so the following components have been renamed:TableElement->PlateTableElement- removed table border to set it at the cell level
margin-left: 1pxto support cell borders- if all columns have a fixed size, the table will have a dynamic width instead of always 100%
TableRowElement->PlateTableRowElementTableCellElement->PlateTableCellElement- removed td border in favor of td::before. The latter is responsible of having the border and the selected background color.
- z-index: td is 0, td::before is 10, td::before in selected state is 20, handle is 30, handle resize is 40.
- removed
selectedCelldiv in favor of::before
TablePopover->PlateTablePopoverStyled props have been removed.
19.0.0
@udecode/[email protected]
- #2097 by @zbeyens –
- upgrade deps, including typescript support for the new editor methods:
// from "slate": "0.78.0", "slate-history": "0.66.0", "slate-react": "0.79.0" // to "slate": "0.87.0", "slate-history": "0.86.0", "slate-react": "0.88.0"
@udecode/[email protected]
- #2097 by @zbeyens –
- due to esm issues, dnd plugin is not part of plate package anymore. To use it, install
@udecode/plate-ui-dnd
// before import { createDndPlugin } from '@udecode/plate'; // after import { createDndPlugin } from '@udecode/plate-ui-dnd';- upgrade peerDeps:
// from "slate": ">=0.78.0", "slate-history": ">=0.66.0", "slate-react": ">=0.79.0" // to "slate": ">=0.87.0", "slate-history": ">=0.86.0", "slate-react": ">=0.88.0" - due to esm issues, dnd plugin is not part of plate package anymore. To use it, install
18.0.0
@udecode/[email protected]
- #1889 by @zbeyens –
@udecode/plate-selectionpackage moved out from@udecode/platebecause of https://github.com/Simonwep/selection/issues/124- Migration:
- If not using
createBlockSelectionPlugin, no migration is needed. - Otherwise, install
@udecode/plate-selectionand importcreateBlockSelectionPluginfrom that package.
- If not using
17.0.0
@udecode/[email protected]
-
usePlateStore:- Plate no longer has a global store containing all the editor states (zustand). Each editor store is now defined in a React context tree (jotai). If you need to access all the editor states at once (as you could do before), you'll need to build that layer yourself.
- Plate store is now accessible only below
PlateProviderorPlate(provider-less mode). It means it's no longer accessible outside of a Plate React tree. If you have such use-case, you'll need to build your own layer to share the state between your components. - You can nest many
PlateProviderwith different scopes (idprop). Default scope isPLATE_SCOPE - Hook usage:
const value = usePlateSelectors(id).value()const setValue = usePlateActions(id).value()const [value, setValue] = usePlateStates(id).value()
- removed from the store:
editableProps, use the props insteadenabled, use conditional rendering insteadisReady, no point anymore as it's now directly ready
useEventPlateIdis still used to get the last focused editor id.- Functions are stored in an object
{ fn: <here> }const setOnChange = usePlateActions(id).onChange()setOnChange({ fn: newOnChange })
Plate- if rendered below
PlateProvider, it will renderPlateSlate > PlateEditable - if rendered without
PlateProvider, it will renderPlateProvider > PlateSlate > PlateEditable - default
idis no longermain, it's nowPLATE_SCOPE
- if rendered below
PlateProvider- Each provider has an optional
scope, so you can have multiple providers in the same React tree and use the plate hooks with the correspondingscope. - Plate effects are now run in
PlateProviderinitialValue, value, editor, normalizeInitialValue, normalizeEditorare no longer defined in an effect (SSR support)
- Props:
- now extends the previous
Plateprops - if using
PlateProvider, set the provider props on it instead ofPlate.Platewould only neededitablePropsandPlateEditableExtendedProps - if not using it, set the provider props on
Plate
- now extends the previous
- Each provider has an optional
// Before <PlateProvider> <Toolbar> <AlignToolbarButtons /> </Toolbar> <Plate<MyValue> editableProps={editableProps} <MyValue> initialValue={alignValue} plugins={plugins} /> </PlateProvider> // After <PlateProvider<MyValue> initialValue={alignValue} plugins={plugins}> <Toolbar> <AlignToolbarButtons /> </Toolbar> <Plate<MyValue> editableProps={editableProps} /> </PlateProvider> // After (provider-less mode) <Plate<MyValue> editableProps={editableProps} initialValue={alignValue} plugins={plugins} />- types:
- store
editoris no longer nullable - store
valueis no longer nullable idtype is nowPlateId
- store
- renamed:
SCOPE_PLATEtoPLATE_SCOPEgetEventEditorIdtogetEventPlateIdgetPlateActions().resetEditortouseResetPlateEditor()
- removed:
plateIdAtomusePlateIdforusePlateSelectors().id()EditablePluginsforPlateEditableSlateChildrenPlateEventProviderforPlateProviderwithPlateEventProviderforwithPlateProviderusePlateusePlatesStoreEffectuseEventEditorIdforuseEventPlateIdplatesStore, platesActions, platesSelectors, usePlatesSelectorsgetPlateActionsforusePlateActionsgetPlateSelectorsforusePlateSelectorsgetPlateEditorRefforusePlateEditorRefgetPlateStore, usePlateStoreEditorIdforPlateId
@udecode/[email protected]
- #1871 by @zbeyens –
- Removed these imports because of build errors:
prismjs/components/prism-djangoprismjs/components/prism-ejsprismjs/components/prism-php
- Removed these imports because of build errors:
@udecode/[email protected]
- #1871 by @zbeyens –
- Removed
[ELEMENT_CODE_BLOCK]: CodeBlockElementfrom Plate UI. You can define it in your app.
- Removed
16.0.0
@udecode/[email protected]
@udecode/[email protected]
- #1721 by @zbeyens –
- deprecate
@udecode/plate-imageand@udecode/plate-media-embed, those got merged into@udecode/plate-media
- deprecate
@udecode/[email protected]
- #1721 by @zbeyens –
- removed:
useImageElementforuseElementMediaEmbedUrlInputforFloatingMediaUrlInputparseEmbedUrlforparseMediaUrlEmbedProviders
- renamed:
ImageImgtoImageImageCaptionTextareatoCaptionTextareauseImageCaptionStringtouseCaptionStringImageResizabletoResizable
- removed:
@udecode/[email protected]
- #1721 by @zbeyens –
TableElementBaseprops:- replace
onRenderContainerbyfloatingOptionsor by replacingELEMENT_TABLEin thecreatePlateUIfunction.
- replace
TablePopoveris now a floating instead of tippy- deps:
- replaced
plate-ui-popoverbyplate-floating
- replaced
@udecode/[email protected]
15.0.0
@udecode/[email protected]
- #1677 by @zbeyens –
- deps:
- replaced
@udecode/plate-ui-popperby@udecode/plate-floating
- replaced
comboboxStore:- removed
popperContainer, usefloatingOptionsinstead - removed
popperOptions, usefloatingOptionsinstead
- removed
- deps:
@udecode/[email protected]
- #1677 by @zbeyens –
createLinkPlugin- removed
onKeyDownLinkfor floating link - removed
hotkeyfortriggerFloatingLinkHotkeys
- removed
- removed:
getAndUpsertLinkforupsertLinkupsertLinkAtSelectionforupsertLink
LinkToolbarButton:onClicknow callstriggerFloatingLink
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #1677 by @zbeyens –
- remove
@udecode/plate-ui-popperandreact-popperdeps for@udecode/plate-floating BalloonToolbarProps:- removed
popperOptionsforfloatingOptions
- removed
- remove
useBalloonToolbarPopperforuseFloatingToolbar
14.0.0
@udecode/[email protected]
- #1633 by @tjramage – Moved
serializeHtmland its utils to@udecode/plate-serializer-htmlas it has a new dependency: html-entities.- If you're using
@udecode/plate, no migration is needed - Otherwise, import it from
@udecode/plate-serializer-html
- If you're using
13.0.0
@udecode/[email protected]
Platechildren are now rendered as last children ofSlate(previously first children). To reproduce the previous behavior, movechildrentofirstChildren
@udecode/[email protected]
@udecode/[email protected]
- #1585 by @zbeyens – Removed
@udecode/plate-juicefrom@udecode/plate. Install it if using@udecode/plate-serializer-docx:yarn install @udecode/plate-juice
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #1585 by @zbeyens – Moved
react-dnd react-dnd-html5-backenddeps to peer-dependencies. Install these if using@udecode/plate-ui-dnd:yarn install react-dnd react-dnd-html5-backend
12.0.0
@udecode/[email protected]
- #1579 by @zbeyens – renamed:
useDndBlockoptions:blockRef->nodeRefremovePreview->preview.disable
useDropBlockOnEditor->useDropBlockuseDropBlockoptions:blockRef->nodeRefsetDropLine->onChangeDropLinesignature change:
getHoverDirection:
// before
(
dragItem: DragItemBlock,
monitor: DropTargetMonitor,
ref: any,
hoverId: string
)
// after
{
dragItem,
id,
monitor,
nodeRef,
}: GetHoverDirectionOptions11.0.0
@udecode/[email protected]
-
#1500 by @zbeyens – Thanks @ianstormtaylor for the initial work on https://github.com/ianstormtaylor/slate/pull/4177.
This release includes major changes to plate and slate types:
- Changing the
TEditortype to beTEditor<V>whereVrepresents the "value" being edited by Slate. In the most generic editor,Vwould be equivalent toTElement[](since that is what is accepted as children of the editor). But in a custom editor, you might haveTEditor<Array<Paragraph | Quote>>. - Other
TEditor-and-TNode-related methods have been also made generic, so for example if you usegetLeafNode(editor, path)it knows that the return value is aTTextnode. But more specifically, it knows that it is the text node of the type you've defined in your custom elements (with any marks you've defined). - This replaces the declaration merging approach, and provides some benefits. One of the drawbacks to declaration merging was that it was impossible to know whether you were dealing with an "unknown" or "known" element, since the underlying type was changed. Similarly, having two editors on the page with different schemas wasn't possible to represent. Hopefully this approach with generics will be able to smoothly replace the declaration merging approach. (While being easy to migrate to, since you can pass those same custom element definitions into
TEditorstill.)
- Changing the
Define your custom types
- Follow https://platejs.org/docs/typescript example.
Slate types
Those Slate types should be replaced by the new types:
Editor->TEditor<V extends Value = Value>- Note that
TEditormethods are not typed based onValueas it would introduce a circular dependency. You can usegetTEditor(editor)to get the editor with typed methods.
- Note that
ReactEditor->TReactEditor<V extends Value = Value>HistoryEditor->THistoryEditor<V extends Value = Value>EditableProps->TEditableProps<V extends Value = Value>Node->TNodeElement->TElementText->TTextNodeEntry->TNodeEntryNodeProps->TNodeProps
Slate functions
Those Slate functions should be replaced by the new typed ones:
- As the new editor type is not matching the slate ones, all
Transforms,Editor,Node,Element,Text,HistoryEditor,ReactEditorfunctions should be replaced: The whole API has been typed into Plate core. See https://github.com/udecode/plate/packages/core/src/slate createEditor->createTEditorwithReact->withTReactwithHistory->withTHistory
Generic types
-
<T = {}>could be used to extend the editor type. It is now replaced by<E extends PlateEditor<V> = PlateEditor<V>>to customize the whole editor type. -
When the plugin type is customizable, these generics are used:
<P = PluginOptions, V extends Value = Value, E extends PlateEditor<V> = PlateEditor<V>>, wherePis the plugin options type. -
Editorfunctions are using<V extends Value>generic, whereVcan be a custom editor value type used inPlateEditor<V>. -
Editorfunctions returning a node are using<N extends ENode<V>, V extends Value = Value>generics, whereNcan be a custom returned node type. -
Editorcallbacks (e.g. a plugin option) are using<V extends Value = Value, E extends PlateEditor<V> = PlateEditor<V>>generics, whereEcan be a custom editor type. -
Nodefunctions returning a node are using<N extends Node, R extends TNode = TNode>generics. -
These generics are used by
<V extends Value, K extends keyof EMarks<V>>:getMarks,isMarkActive,removeMark,setMarks,ToggleMarkPlugin,addMark,removeEditorMark -
WithOverrideis a special type case as it can return a new editor type:// before export type WithOverride<T = {}, P = {}> = ( editor: PlateEditor<T>, plugin: WithPlatePlugin<T, P> ) => PlateEditor<T>; // after - where E is the Editor type (input), and EE is the Extended Editor type (output) export type WithOverride< P = PluginOptions, V extends Value = Value, E extends PlateEditor<V> = PlateEditor<V>, EE extends E = E, > = (editor: E, plugin: WithPlatePlugin<P, V, E>) => EE; -
type TEditor<V extends Value> -
type PlateEditor<V extends Value>
Renamed functions
getAbove->getAboveNodegetParent->getParentNodegetText->getEditorStringgetLastNode->getLastNodeByLevelgetPointBefore->getPointBeforeLocationgetNodes->getNodeEntriesisStart->isStartPointisEnd->isEndPoint
Replaced types
Removing node props types in favor of element types (same props + extends TElement). You can use TNodeProps to get the node data (props).
LinkNodeData->TLinkElementImageNodeData->TImageElementTableNodeData->TTableElementMentionNodeData->TMentionElementMentionNode->TMentionElementMentionInputNodeData->TMentionInputElementMentionInputNode->TMentionInputElementCodeBlockNodeData->TCodeBlockElementMediaEmbedNodeData->TMediaEmbedElementTodoListItemNodeData->TTodoListItemElementExcalidrawNodeData->TExcalidrawElement
Utils
matchsignature change:
<T extends TNode>(
obj: T,
path: TPath,
predicate?: Predicate<T>
)
deleteFragmentis now usingEditor.deleteFragment
@udecode/[email protected]
getEmptyTableNodedefault options changed. Migration:
// From (0 row count and col count, previously it was 2)
getEmptyTableNode(editor);
// To
getEmptyTableNode(editor, { rowCount: 2, colCount: 2 });@udecode/[email protected]
Generic types
type StyledElementProps<V extends Value, N extends TElement = EElement<V>, TStyles = {}>
10.0.0
@udecode/[email protected]
- #1377 by @zbeyens – Before,
BalloonToolbarcould be outsidePlate. Now,BallonToolbarshould be a child ofPlateto support multiple editors.
9.0.0
@udecode/[email protected]
- #1303 by @zbeyens –
Plateeditorprop can now be fully controlled: Plate is not applyingwithPlateon it anymore
PlatePlugin.deserializeHtml- can't be an array anymore
- moved
validAttribute,validClassName,validNodeName,validStyletodeserializeHtml.rulesproperty
- renamed
plateStoretoplatesStore platesStoreis now a zustood storeeventEditorStoreis now a zustood storegetPlateIdnow gets the last editor id if not focused or blurred- used by
usePlateEditorRefandusePlateEditorState
- used by
- removed:
usePlateEnabledforusePlateSelectors(id).enabled()usePlateValueforusePlateSelectors(id).value()usePlateActions:resetEditorforgetPlateActions(id).resetEditor()clearStateforplatesActions.unset()setInitialStateforplatesActions.set(id)setEditorforgetPlateActions(id).editor(value)setEnabledforgetPlateActions(id).enabled(value)setValueforgetPlateActions(id).value(value)
getPlateStateusePlateStateusePlateKey
@udecode/[email protected]
- #1303 by @zbeyens –
- renamed
plate-x-uitoplate-ui-x: all packages depending onstyled-componentshasplate-uiprefix - renamed
plate-x-serializertoplate-serializer-x - is now exporting only these (new) packages:
@udecode/plate-headless: all unstyled packages@udecode/plate-ui: all styled packages
- renamed
PlateStatetoPlateStoreState
8.0.0
@udecode/[email protected]
-
IndentListPluginOptionsforPlatePlugin
Rename:
getIndentListInjectComponenttoinjectIndentListComponent
@udecode/[email protected]
-
#1234 by @zbeyens – Breaking changes:
Plate- removed
componentsprop:
// Before <Plate plugins={plugins} components={components} />; // After // option 1: use the plugin factory let plugins = [ createParagraphPlugin({ component: ParagraphElement, }), ]; // option 2: use createPlugins plugins = createPlugins(plugins, { components: { [ELEMENT_PARAGRAPH]: ParagraphElement, }, }); <Plate plugins={plugins} />;- removed
optionsprop:
// Before <Plate plugins={plugins} options={options} />; // After // option 1: use the plugin factory let plugins = [ createParagraphPlugin({ type: 'paragraph', }), ]; // option 2: use createPlugins plugins = createPlugins(plugins, { overrideByKey: { [ELEMENT_PARAGRAPH]: { type: 'paragraph', }, }, }); <Plate plugins={plugins} />;PlatePluginkey- replacing
pluginKey - is now required: each plugin needs a key to be retrieved by key.
- replacing
- all handlers have
pluginas a second parameter:
// Before export type X<T = {}> = (editor: PlateEditor<T>) => Y; // After export type X<T = {}, P = {}> = ( editor: PlateEditor<T>, plugin: WithPlatePlugin<T, P> ) => Y;serializeno longer haselementandleafproperties:
type SerializeHtml = RenderFunction< PlateRenderElementProps | PlateRenderLeafProps >;Renamed:
injectParentComponenttoinject.aboveComponentinjectChildComponenttoinject.belowComponentoverridePropstoinject.propstransformClassName,transformNodeValue,transformStylefirst parameter is no longereditoras it's provided bythenif needed.- the previously
getOverridePropsis now the core behavior ifinject.propsis defined.
serializetoserializeHtmldeserializetodeserializeHtml- can be an array
- the old deserializer options are merged to
deserializeHtml
type DeserializeHtml = { /** List of HTML attribute names to store their values in `node.attributes`. */ attributeNames?: string[]; /** * Deserialize an element. Use this instead of plugin.isElement if you don't * want the plugin to renderElement. * * @default plugin.isElement */ isElement?: boolean; /** * Deserialize a leaf. Use this instead of plugin.isLeaf if you don't want the * plugin to renderLeaf. * * @default plugin.isLeaf */ isLeaf?: boolean; /** Deserialize html element to slate node. */ getNode?: (element: HTMLElement) => AnyObject | undefined; query?: (element: HTMLElement) => boolean; /** * Deserialize an element: * * - If this option (string) is in the element attribute names. * - If this option (object) values match the element attributes. */ validAttribute?: string | { [key: string]: string | string[] }; /** Valid element `className`. */ validClassName?: string; /** Valid element `nodeName`. Set '*' to allow any node name. */ validNodeName?: string | string[]; /** * Valid element style values. Can be a list of string (only one match is * needed). */ validStyle?: Partial< Record<keyof CSSStyleDeclaration, string | string[] | undefined> >; /** Whether or not to include deserialized children on this node */ withoutChildren?: boolean; };- handlers starting by
on...are moved tohandlersproperty.
// Before onDrop: handler; // After handlers: { onDrop: handler; }Removed:
renderElementis favor of:isElementis a boolean that enables element rendering.- the previously
getRenderElementis now the core behavior.
renderLeafis favor of:isLeafis a boolean that enables leaf rendering.- the previously
getRenderLeafis now the core behavior.
inlineTypesandvoidTypesfor:isInlineis a boolean that enables inline rendering.isVoidis a boolean that enables void rendering.
General
- the following plugins are now part of the core plugins, so you need to remove these from your
pluginsprop:
const corePlugins = [ createReactPlugin(), createHistoryPlugin(), createEventEditorPlugin(), createInlineVoidPlugin(), createInsertDataPlugin(), createDeserializeAstPlugin(), createDeserializeHtmlPlugin(), ];pluginsis not a parameter anymore as it can be retrieved ineditor.pluginswithInlineVoidis now using pluginsisInlineandisVoidplugin properties.
Renamed:
getPlatePluginTypetogetPluginTypegetEditorOptionstogetPluginsgetPlatePluginOptionstogetPluginpipeOverridePropstopipeInjectPropsgetOverridePropstopluginInjectPropsserializeHTMLFromNodestoserializeHtmlgetLeaftoleafToHtmlgetNodetoelementToHtml
xDeserializerIdtoKEY_DESERIALIZE_XdeserializeHTMLToTexttohtmlTextNodeToStringdeserializeHTMLToMarkstohtmlElementToLeafandpipeDeserializeHtmlLeafdeserializeHTMLToElementtohtmlElementToElementandpipeDeserializeHtmlElementdeserializeHTMLToFragmenttohtmlBodyToFragmentdeserializeHTMLToDocumentFragmenttodeserializeHtmldeserializeHTMLToBreaktohtmlBrToNewLinedeserializeHTMLNodetodeserializeHtmlNodedeserializeHTMLElementtodeserializeHtmlElement
Removed:
usePlateKeys,getPlateKeysusePlateOptionsforgetPlugingetPlateSelectionforgetPlateEditorRef().selectionflatMapByKeygetEditableRenderElementandgetRenderElementforpipeRenderElementandpluginRenderElementgetEditableRenderLeafandgetRenderLeafforpipeRenderLeafandpluginRenderLeafgetInlineTypesgetVoidTypesgetPlatePluginTypesgetPlatePluginWithOverridesmapPlatePluginKeysToOptionswithDeserializeXforPlatePlugin.editor.insertData
Changed types:
PlateEditor:- removed
optionsforpluginsByKey
- removed
WithOverrideis not returning an extended editor anymore (input and output editors are assumed to be the same types for simplicity).PlateState- renamed
keyChangetokeyEditor - removed
pluginsforeditor.plugins - removed
pluginKeys - removed
selectionforeditor.selection - actions:
- removed
setSelection,setPlugins,setPluginKeys - removed
incrementKeyChangefor
- removed
- renamed
Renamed types:
XHTMLYtoXHtmlYDeserializetoDeseralizeHtml
Removed types:
PlatePluginOptions:typetoPlatePlugin.typecomponenttoPlatePlugin.componentdeserializetoPlatePlugin.deserializeHtmlgetNodePropstoPlatePlugin.props.nodePropshotkeytoHotkeyPlugincleartoToggleMarkPlugindefaultTypeis hardcoded top.type
OverridePropsforPlatePlugin.inject.propsSerializeforPlatePlugin.serializeHtmlNodePropsforAnyObjectOnKeyDownElementOptionsforHotkeyPluginOnKeyDownMarkOptionsforToggleMarkPluginWithInlineVoidOptionsGetNodePropsforPlatePluginPropsDeserializeOptions,GetLeafDeserializerOptions,GetElementDeserializerOptions,GetNodeDeserializerOptions,GetNodeDeserializerRule,DeserializeNodeforPlatePlugin.deserializeHtmlPlateOptionsRenderNodeOptionsDeserializedHTMLElement
- removed
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #1234 by @zbeyens – Removed:
getCodeBlockPluginOptionsforgetPlugingetCodeLinePluginOptionsforgetPlugin
@udecode/[email protected]
@udecode/[email protected]
- #1234 by @zbeyens – Removed:
getMentionInputPluginOptionsforgetPlugingetMentionInputTypeforgetPluginTypeCOMBOBOX_TRIGGER_MENTION
@udecode/[email protected]
@udecode/[email protected]
-
#1234 by @zbeyens – Breaking changes:
- all plugins options are now defined in the plugin itself
- plugins which now have nested plugins instead of array:
createBasicElementsPlugincreateCodeBlockPlugincreateHeadingPlugincreateListPlugincreateTablePlugincreateBasicMarksPlugin
Removed:
createEditorPluginsforcreatePlateEditor(without components) andcreatePlateEditorUI(with Plate components)createPlateOptionsforcreatePlugins- all
DEFAULTS_X: these are defined in the plugins - all
getXDeserialize: these are defined in the plugins - all
WithXOptionsfor extended plugins - all
getXRenderElement - some plugin option types are removed for
PlatePlugin
Renamed:
createPlateComponentstocreatePlateUI- all
getXYhandlers toyX(e.g.getXOnKeyDowntoonKeyDownX) - all
XPluginOptionstoXPlugin - all
pluginKeyparameter tokeyexcept in components
Renamed types:
DecorateSearchHighlightOptionstoFindReplacePlugin
Updated deps:
"slate": "0.70.0""slate-react": "0.70.1"
Removed deps (merged to core):
plate-commonplate-ast-serializerplate-html-serializerplate-serializer
@udecode/[email protected]
- #1234 by @zbeyens – Renamed:
createDeserializeCSVPlugintocreateDeserializeCsvPlugindeserializeCSVtodeserializeCsv
@udecode/[email protected]
-
createDeserializeMdPlugin:- is now disabled if there is html data in the data transfer.
Renamed:
createDeserializeMDPlugintocreateDeserializeMdPlugindeserializeMDtodeserializeMd
7.0.0
@udecode/plate-core
- renamed:
SPEditortoPEditor(note thatPlateEditoris the new default)SPRenderNodePropstoPlateRenderNodePropsSPRenderElementPropstoPlateRenderElementPropsSPRenderLeafPropstoPlateRenderLeafPropsuseEventEditorIdtousePlateEventIduseStoreEditorOptionstousePlateOptionsuseStoreEditorReftousePlateEditorRefuseStoreEditorSelectiontousePlateSelectionuseStoreEditorStatetousePlateEditorStateuseStoreEditorValuetousePlateValueuseStoreEnabledtousePlateEnableduseStorePlatetousePlatePluginsuseStorePlatePluginKeystousePlateKeysuseStoreStatetousePlateState
getPlateId: Get the last focused editor id, else get the last blurred editor id, else get the first editor id, elsenullgetPlateState:- removed first parameter
state - previously when giving no parameter, it was returning the first editor. Now it's returning the editor with id =
getPlateId(). It meansuseEventEditorId('focus')is no longer needed forusePlateEditorRefusePlateEditorStateusePlateX...
- removed first parameter
@udecode/plate-alignment
setAlign: optionalignrenamed tovalue- removed
getAlignOverrideProps()in favor ofgetOverrideProps(KEY_ALIGN)
@udecode/plate-indent
- removed
getIndentOverrideProps()in favor ofgetOverrideProps(KEY_INDENT) - rename
onKeyDownHandlertogetIndentOnKeyDown() IndentPluginOptions- rename
typestovalidTypes - rename
cssPropNametostyleKey - rename
transformCssValuetotransformNodeValue
- rename
@udecode/plate-line-height
setLineHeight: optionlineHeightrenamed tovalue- removed
getLineHeightOverridePropsin favor ofgetOverrideProps(KEY_LINE_HEIGHT)
@udecode/plate-mention
getMentionOnSelectItem:- removed
createMentionNodein favor of plugin options - removed
insertSpaceAfterMentionin favor of plugin options
- removed
@udecode/plate-mention-ui
MentionComboboxprops:- removed
triggerin favor of plugin options - removed
insertSpaceAfterMentionin favor of plugin options - removed
createMentionNodein favor of plugin options
- removed
@udecode/plate-x-ui
- renamed
ToolbarAligntoAlignToolbarButton - renamed
ToolbarCodeBlocktoCodeBlockToolbarButton - renamed
ToolbarElementtoBlockToolbarButton - renamed
ToolbarImagetoImageToolbarButton - renamed
ToolbarLinktoLinkToolbarButton - renamed
ToolbarListtoListToolbarButton - renamed
ToolbarLineHeighttoLineHeightToolbarDropdown - renamed
ToolbarMarktoMarkToolbarButton - renamed
ToolbarMediaEmbedtoMediaEmbedToolbarButton - renamed
ToolbarSearchHighlighttoSearchHighlightToolbar - renamed
ToolbarTabletoTableToolbarButton
6.0.0
@udecode/plate-alignment
The align plugin is no longer wrapping a block, but instead setting an align property to an existing block.
createAlignPlugin:- removed
pluginKeys,renderElementanddeserialize
- removed
- removed:
ELEMENT_ALIGN_LEFTELEMENT_ALIGN_CENTERELEMENT_ALIGN_RIGHTELEMENT_ALIGN_JUSTIFYKEYS_ALIGNin favor ofKEY_ALIGNgetAlignDeserializeupsertAlignin favor ofsetAlign
Migration (normalizer):
- for each node:
- run
parent = getParent(editor, path), ifparent[0].typeis one of the alignment values:- run
setAlign(editor, { align }, { at: path }) - run
unwrapNodes(editor, { at: path })
- run
- run
@udecode/plate-alignment-ui
ToolbarAlignProps:- removed
typein favor ofalign - removed
unwrapTypes - added
align
- removed
5.0.0
@udecode/plate-mention
The mention plugin is now using the combobox.
- removed
useMentionPluginin favor ofcreateMentionPlugin- migration: replace
useMentionPlugin().pluginbycreateMentionPlugin()
- migration: replace
- removed options:
mentionableSearchPatterninsertSpaceAfterMentionmaxSuggestions: moved tocomboboxStoretrigger: moved tocomboboxStorementionables: moved toitemsincomboboxStorementionableFilter: moved tofilterincomboboxStore
- removed
matchesTriggerAndPatternin favor ofgetTextFromTrigger - removed
MentionNodeDatain favor ofComboboxItemData
export interface ComboboxItemData {
/** Unique key. */
key: string;
/** Item text. */
text: any;
/**
* Whether the item is disabled.
*
* @default false
*/
disabled?: boolean;
/** Data available to `onRenderItem`. */
data?: unknown;
}@udecode/plate-mention-ui
- removed
MentionSelectin favor ofMentionCombobox
@udecode/plate-toolbar
- removed
setPositionAtSelectionin favor ofuseBalloonToolbarPopper - removed
useBalloonMovein favor ofuseBalloonToolbarPopper - removed
usePopupPositionin favor ofuseBalloonToolbarPopper - removed
useBalloonShowin favor ofuseBalloonToolbarPopperBalloonToolbarprops: - removed
directionin favor ofpopperOptions.placement - renamed
scrollContainertopopperContainer
4.0.0
@udecode/plate-toolbar
BalloonToolbar: removedhiddenDelayprop.
3.0.0
All UI packages
There was multiple instances of styled-components across all the packages.
So we moved styled-components from dependencies to peer dependencies.
Before
styled-components was not listed in your dependencies
After
Add styled-components to your dependencies
2.0.0
@udecode/plate-autoformat
autoformatBlock:- signatude changed
// Before
(
editor: TEditor,
type: string,
at: Location,
options: Pick<AutoformatRule, 'preFormat' | 'format'>
)// After
(editor: TEditor, options: AutoformatBlockOptions)- moved the checks from
withAutoformat autoformatInline:- renamed to
autoformatMark - signatured changed
- renamed to
// Before
(
editor: TEditor,
options: Pick<AutoformatRule, 'type' | 'between' | 'markup' | 'ignoreTrim'>
)// After
(
editor: TEditor,
options: AutoformatMarkOptions
)AutoformatRuleis nowAutoformatBlockRule | AutoformatMarkRule | AutoformatTextRule;mode: 'inline'renamed tomode: 'mark'markupandbetweenhave been replaced bymatch: string | string[] | MatchRange | MatchRange[]: The rule applies when the trigger and the text just before the cursor matches. Formode: 'block': lookup for the end match(es) before the cursor. Formode: 'text': lookup for the end match(es) before the cursor. Ifformatis an array, also lookup for the start match(es). Formode: 'mark': lookup for the start and end matches. Note:'_*',['_*']and{ start: '_*', end: '*_' }are equivalent.triggernow defaults to the last character ofmatchormatch.end(previously' ')
- the plugin now checks that there is no character before the start match to apply autoformatting. For example, nothing will happen by typing
a*text*.
On This Page
48.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]47.0.0@udecode/plate-markdown46.0.0@udecode/[email protected]45.0.0@udecode/[email protected]@udecode/[email protected]44.0.1@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]43.0.042.0.1@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]41.0.2@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]40.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]39.0.0@udecode/[email protected]@udecode/[email protected]38.0.1@udecode/[email protected]37.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]36.0.035.0.0@udecode/[email protected]34.0.0@udecode/[email protected]33.0.0@udecode/[email protected]32.0.031.0.030.0.0@udecode/[email protected]29.0.0@udecode/[email protected]28.0.0@udecode/[email protected]27.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]26.0.0@udecode/[email protected]@udecode/[email protected]25.0.1@udecode/[email protected]@udecode/[email protected]24.0.0@udecode/[email protected]23.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]22.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]21.0.0@udecode/[email protected]20.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]19.0.0@udecode/[email protected]@udecode/[email protected]18.0.0@udecode/[email protected]17.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]16.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]15.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]14.0.0@udecode/[email protected]13.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]12.0.0@udecode/[email protected]11.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]10.0.0@udecode/[email protected]9.0.0@udecode/[email protected]@udecode/[email protected]8.0.0@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]@udecode/[email protected]7.0.0@udecode/plate-core@udecode/plate-alignment@udecode/plate-indent@udecode/plate-line-height@udecode/plate-mention@udecode/plate-mention-ui@udecode/plate-x-ui6.0.0@udecode/plate-alignment@udecode/plate-alignment-ui5.0.0@udecode/plate-mention@udecode/plate-mention-ui@udecode/plate-toolbar4.0.0@udecode/plate-toolbar3.0.0All UI packagesBeforeAfter2.0.0@udecode/plate-autoformat