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
,PlateLeaf
andPlateText
HTML attributes are moved from top-level props toattributes
prop, exceptclassName
,style
andas
. Migration:
// From <PlateElement {...props} ref={ref} contentEditable={false} > {children} </PlateElement> // To <PlateElement {...props} ref={ref} attributes={{ ...props.attributes, contentEditable: false, }} > {children} </PlateElement>
- Remove
nodeProps
prop fromPlateElement
,PlateLeaf
,PlateText
. It has been merged intoattributes
prop. - Plugin
node.props
should return the props directly instead of insidenodeProps
object. 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
asChild
prop fromPlateElement
,PlateLeaf
,PlateText
. Useas
prop instead. - Remove
elementToAttributes
,leafToAttributes
,textToAttributes
props fromPlateElement
,PlateLeaf
,PlateText
. - Remove
DefaultElement
,DefaultLeaf
,DefaultText
. UsePlateElement
,PlateLeaf
,PlateText
instead. - Types: remove
PlateRenderElementProps
,PlateRenderLeafProps
,PlateRenderTextProps
. UsePlateElementProps
,PlateLeafProps
,PlateTextProps
instead.
@udecode/[email protected]
- #4281 by @zbeyens –
- Moved
PlateElement
,PlateLeaf
,PlateText
to@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
hocuspocusProviderOptions
with the newproviders
array. 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
UnifiedProvider
interface that enables custom provider implementations (e.g., IndexedDB for offline persistence). - Renamed
cursorOptions
tocursors
. - Merged
yjsOptions
intooptions
.- Migration: Move options previously under
yjsOptions
directly into the mainoptions
object.
- Migration: Move options previously under
- Removed
YjsAboveEditable
. You should now callinit
anddestroy
manually:
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
rules
option for customizing serialization and deserialization rules, including custom mdx support - New
remarkPlugins
option to use remark plugins
Breaking Changes
Plugin Options
Removed options:
elementRules
userules
insteadtextRules
userules
insteadindentList
now automatically detects if the IndentList plugin is usedsplitLineBreaks
deserialize only
Deserialization
- Removed
elementRules
andtextRules
options- Use
rules.key.deserialize
instead - 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
remarkPlugins
instead
- Use
Serialization
- Removed
serializeMdNodes
- Use
editor.markdown.serialize({ value: nodes })
instead
- Use
- Removed
SerializeMdOptions
due to new serialization process- Previous process:
slate nodes => md
- New process:
slate nodes => md-ast => md
- Previous process:
- Removed options:
nodes
breakTag
customNodes
ignoreParagraphNewline
listDepth
markFormats
ulListStyleTypes
ignoreSuggestionType
Migration example for
SerializeMdOptions.customNodes
andSerializeMdOptions.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
prismjs
tohighlight.js
+lowlight
for 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
: removeprism
option. Uselowlight
option instead:
import { all, createLowlight } from 'lowlight'; const lowlight = createLowlight(all); CodeBlockPlugin.configure({ options: { lowlight, }, });
- New option:
defaultLanguage
- Remove
syntax
option. Just omitlowlight
option to disable syntax highlighting. - Remove
syntaxPopularFirst
option. 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.comments
options.myUserId
options.users
Components
- Removed legacy components:
CommentDeleteButton
CommentEditActions
CommentEditButton
CommentEditCancelButton
CommentEditSaveButton
CommentEditTextarea
CommentNewSubmitButton
CommentNewTextarea
CommentResolveButton
CommentsPositioner
CommentUserName
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:
getCommentFragment
getCommentUrl
getElementAbsolutePosition
getCommentPosition
- Updated
getCommentCount
to exclude draft comments
State Management
- Removed
CommentProvider
- users should implement their own state management –block-discussion.tsx
- Moved
useHooksComments
to UI registry –comments-plugin.tsx
- Removed hooks no longer needed with new UI:
useActiveCommentNode
useCommentsResolved
useCommentAddButton
useCommentItemContent
useCommentLeaf
useCommentsShowResolvedButton
useFloatingCommentsContentState
useFloatingCommentsState
Types
- Removed
CommentUser
- Moved
TComment
to 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:
findSuggestionNode
usefindSuggestionProps.ts
instead - Remove
addSuggestionMark.ts
- Remove
useHooksSuggestion.ts
as 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@6
eventEditorSelectors
->EventEditorStore.get
eventEditorActions
->EventEditorStore.set
useEventEditorSelectors
->useEventEditorValue(key)
- Upgraded to
jotai-x@2
usePlateEditorStore
->usePlateStore
usePlateActions
->usePlateSet
- Remove
editor.setPlateState
, useusePlateSet
instead usePlateSelectors
->usePlateValue
usePlateStates
->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.selectors
instead 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:ImagePreviewStore
FloatingMediaStore
-
#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
selectedCells
andselectedTables
fromuseTableStore
toTablePlugin
options 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-common
and install@udecode/plate
- Replace all
'@udecode/plate-common'
with'@udecode/plate'
,
- Remove
@udecode/[email protected]
-
-
Plugin
normalizeInitialValue
now returnsvoid
instead ofValue
. When mutating nodes, keep their references (e.g., useObject.assign
instead of spread). -
Editor methods have moved to
editor.tf
andeditor.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
extendEditor
using 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 intotf
andapi
for better DX, but also to support transform-only middlewares in the future. This also lets us leverageextendEditorTransforms
,extendEditorApi
, andoverrideEditor
to 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.redecorate
toeditor.api.redecorate
Types:
- Rename
TRenderElementProps
toRenderElementProps
- Rename
TRenderLeafProps
toRenderLeafProps
- Rename
TEditableProps
toEditableProps
-
@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/plate
imports 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-history
andslate-hyperscript
from your dependencies. It's now part of this package and@udecode/plate
. All exports remain the same or have equivalents (see below). - Renamed
createTEditor
tocreateEditor
. createEditor
now returns an editor (Editor
) with all queries undereditor.api
and transforms undereditor.tf
. You can see or override them at a glance. For example, we now useeditor.tf.setNodes
instead of importingsetNodes
. This marks the completion of generic typing and the removal of error throws fromslate
,slate-dom
, andslate-history
queries/transforms, without forking implementations. We’ve also reduced the number of queries/transforms by merging a bunch of them.
The following interfaces from
slate
andslate-dom
are now part ofEditor
:-
Editor
,EditorInterface
-
Transforms
-
HistoryEditor
(noop, unchanged),HistoryEditorInterface
-
DOMEditor
(noop, unchanged),DOMEditorInterface
-
editor.findPath
now returnsDOMEditor.findPath
(memo) and falls back tofindNodePath
(traversal, less performant) if not found. -
Removed the first parameter (
editor
) from:editor.hasEditableTarget
editor.hasSelectableTarget
editor.isTargetInsideNonReadonlyVoid
editor.hasRange
editor.hasTarget
-
editor.api.node(options)
(previouslyfindNode
)at
option is nowat ?? editor.selection
instead ofat ?? editor.selection ?? []
. That means if you want to lookup the entire document, you need to pass[]
explicitly. -
Removed
setNode
in favor ofsetNodes
(you can now pass aTNode
toat
directly). -
Removed
setElements
in favor ofsetNodes
. -
Removed unused
isWordAfterTrigger
,setBlockAboveNode
,setBlockAboveTexts
,setBlockNodes
,getPointNextToVoid
. -
Replaced
Path
from slate withPath
(type) andPathApi
(static methods). -
Replaced
Operation
from slate withOperation
(type) andOperationApi
(static methods). -
Replaced
Point
from slate withPoint
(type) andPointApi
(static methods). -
Replaced
Text
from slate withTText
(type) andTextApi
(static methods). We also exportText
type likeslate
but we don't recommend it as it's conflicting with the DOM type. -
Replaced
Range
from slate withTRange
(type) andRangeApi
(static methods). We also exportRange
type likeslate
but we don't recommend it as it's conflicting with the DOM type. -
Replaced
Location
from slate withTLocation
(type) andLocationApi
(static methods). We also exportLocation
type likeslate
but we don't recommend it as it's conflicting with the DOM type. -
Replaced
Span
from slate withSpan
(type) andSpanApi
(static methods). -
Replaced
Node
from slate withTNode
(type) andNodeApi
(static methods). We also exportNode
type likeslate
but we don't recommend it as it's conflicting with the DOM type. -
Replaced
Element
from slate withTElement
(type) andElementApi
(static methods). We also exportElement
type likeslate
but 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.addMark
addRangeMarks
->editor.tf.setNodes(props, { at, marks: true })
blurEditor
->editor.tf.blur
collapseSelection
->editor.tf.collapse
createDocumentNode
->editor.api.create.value
(core)createNode
->editor.api.create.block
createPathRef
->editor.api.pathRef
createPointRef
->editor.api.pointRef
createRangeRef
->editor.api.rangeRef
deleteBackward({ unit })
->editor.tf.deleteBackward(unit)
deleteForward({ unit })
->editor.tf.deleteForward(unit)
deleteFragment
->editor.tf.deleteFragment
deleteText
->editor.tf.delete
deselect
->editor.tf.deselect
deselectEditor
->editor.tf.deselectDOM
duplicateBlocks
->editor.tf.duplicateNodes({ nodes })
findDescendant
->editor.api.descendant
findEditorDocumentOrShadowRoot
->editor.api.findDocumentOrShadowRoot
findEventRange
->editor.api.findEventRange
findNode(options)
->editor.api.node(options)
findNodeKey
->editor.api.findKey
findNodePath
->editor.api.findPath
findPath
->editor.api.findPath
focusEditor
->editor.tf.focus({ at })
focusEditorEdge
->editor.tf.focus({ at, edge: 'startEditor' | 'endEditor' })
getAboveNode
->editor.api.above
getAncestorNode
->editor.api.block({ highest: true })
getBlockAbove
->editor.api.block({ at, above: true })
oreditor.api.block()
ifat
is not a pathgetBlocks
->editor.api.blocks
getEdgeBlocksAbove
->editor.api.edgeBlocks
getEdgePoints
->editor.api.edges
getEditorString
->editor.api.string
getEditorWindow
->editor.api.getWindow
getEndPoint
->editor.api.end
getFirstNode
->editor.api.first
getFragment
->editor.api.fragment
getFragmentProp(fragment, options)
->editor.api.prop({ nodes, ...options})
getLastNode
->editor.api.last
getLastNodeByLevel(level)
->editor.api.last([], { level })
getLeafNode
->editor.api.leaf
getLevels
->editor.api.levels
getMark
->editor.api.mark
getMarks
->editor.api.marks
getNextNode
->editor.api.next
getNextNodeStartPoint
->editor.api.start(at, { next: true })
getNodeEntries
->editor.api.nodes
getNodeEntry
->editor.api.node(at, options)
getNodesRange
->editor.api.nodesRange
getParentNode
->editor.api.parent
getPath
->editor.api.path
getPathRefs
->editor.api.pathRefs
getPoint
->editor.api.point
getPointAfter
->editor.api.after
getPointBefore
->editor.api.before
getPointBeforeLocation
->editor.api.before
getPointRefs
->editor.api.pointRefs
getPositions
->editor.api.positions
getPreviousBlockById
->editor.api.previous({ id, block: true })
getPreviousNode
->editor.api.previous
getPreviousNodeEndPoint
->editor.api.end({ previous: true })
getPreviousSiblingNode
->editor.api.previous({ at, sibling: true })
getRange
->editor.api.range
getRangeBefore
->editor.api.range('before', to, { before })
getRangeFromBlockStart
->editor.api.range('start', to)
getRangeRefs
->editor.api.rangeRefs
getSelectionFragment
->editor.api.fragment(editor.selection, { structuralTypes })
getSelectionText
->editor.api.string()
getStartPoint
->editor.api.start
getVoidNode
->editor.api.void
hasBlocks
->editor.api.hasBlocks
hasEditorDOMNode
->editor.api.hasDOMNode
hasEditorEditableTarget
->editor.api.hasEditableTarget
hasEditorSelectableTarget
->editor.api.hasSelectableTarget
hasEditorTarget
->editor.api.hasTarget
hasInlines
->editor.api.hasInlines
hasTexts
->editor.api.hasTexts
insertBreak
->editor.tf.insertBreak
insertData
->editor.tf.insertData
insertElements
->editor.tf.insertNodes<TElement>
insertEmptyElement
->editor.tf.insertNodes(editor.api.create.block({ type }))
insertFragment
->editor.tf.insertFragment
insertNode
->editor.tf.insertNode
insertNodes
->editor.tf.insertNodes
insertText
->editor.tf.insertText({ at })
oreditor.tf.insertText({ marks: false })
withoutat
isAncestorEmpty
->editor.api.isEmpty
isBlock
->editor.api.isBlock
isBlockAboveEmpty
->editor.api.isEmpty(editor.selection, { block: true })
isBlockTextEmptyAfterSelection
->editor.api.isEmpty(editor.selection, { after: true })
isCollapsed(editor.selection)
->editor.api.isCollapsed()
isComposing
->editor.api.isComposing
isDocumentEnd
->editor.api.isEditorEnd
isEdgePoint
->editor.api.isEdge
isEditorEmpty
->editor.api.isEmpty()
isEditorFocused
->editor.api.isFocused
isEditorNormalizing
->editor.api.isNormalizing
isEditorReadOnly
->editor.api.isReadOnly
isElementEmpty
->editor.api.isEmpty
isElementReadOnly
->editor.api.elementReadOnly
isEndPoint
->editor.api.isEnd
isExpanded(editor.selection)
->editor.api.isCollapsed()
isInline
->editor.api.isInline
isMarkableVoid
->editor.api.markableVoid
isMarkActive
->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.isStart
isTargetinsideNonReadonlyVoidEditor
->editor.api.isTargetInsideNonReadonlyVoid
isTextByPath
->editor.api.isText(at)
isVoid
->editor.api.isVoid
liftNodes
->editor.tf.liftNodes
mergeNodes
->editor.tf.mergeNodes
moveChildren
->editor.tf.moveNodes({ at, to, children: true, fromIndex, match: (node, path) => boolean })
moveNodes
->editor.tf.moveNodes
moveSelection
->editor.tf.move
normalizeEditor
->editor.tf.normalize
removeEditorMark
->editor.tf.removeMark
removeEditorText
->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.removeNodes
removeSelectionMark
->editor.tf.removeMarks()
replaceNode(editor, { nodes, insertOptions, removeOptions })
->editor.tf.replaceNodes(nodes, { removeNodes, ...insertOptions })
select
->editor.tf.select
selectEndOfBlockAboveSelection
->editor.tf.select(editor.selection, { edge: 'end' })
selectNodes
->editor.tf.select(editor.api.nodesRange(nodes))
setFragmentData
->editor.tf.setFragmentData
setMarks(marks, clear)
->editor.tf.addMarks(marks, { remove: string | string[] })
setNodes
->editor.tf.setNodes
setPoint
->editor.tf.setPoint
setSelection
->editor.tf.setSelection
someNode
->editor.api.some(options)
splitNodes
->editor.tf.splitNodes
toDOMNode
->editor.api.toDOMNode
toDOMPoint
->editor.api.toDOMPoint
toDOMRange
->editor.api.toDOMRange
toggleWrapNodes
->editor.tf.toggleBlock(type, { wrap: true })
toSlateNode
->editor.api.toSlateNode
toSlatePoint
->editor.api.toSlatePoint
toSlateRange
->editor.api.toSlateRange
unhangCharacterRange
->editor.api.unhangRange(range, { character: true })
unhangRange
->editor.api.unhangRange
unsetNodes
->editor.tf.unsetNodes
unwrapNodes
->editor.tf.unwrapNodes
withoutNormalizing
->editor.tf.withoutNormalizing
wrapNodeChildren
->editor.tf.wrapNodes(element, { children: true })
wrapNodes
->editor.tf.wrapNodes
replaceNodeChildren
->editor.tf.replaceNodes({ at, children: true })
resetEditor
->editor.tf.reset
resetEditorChildren
->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.firstText
getFirstChild([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.common
getNode
->NodeApi.get
getNodeAncestor
->NodeApi.ancestor
getNodeAncestors
->NodeApi.ancestors
getNodeChild
->NodeApi.child
getNodeChildren
->NodeApi.children
getNodeDescendant
->NodeApi.descendant
getNodeDescendants
->NodeApi.descendants
getNodeElements
->NodeApi.elements
getNodeFirstNode
->NodeApi.first
getNodeFragment
->NodeApi.fragment
getNodeLastNode
->NodeApi.last
getNodeLeaf
->NodeApi.leaf
getNodeLevels
->NodeApi.levels
getNodeParent
->NodeApi.parent
getNodeProps
->NodeApi.extractProps
getNodes
->NodeApi.nodes
getNodeString
->NodeApi.string
getNodeTexts
->NodeApi.texts
hasNode
->NodeApi.has
hasSingleChild
->NodeApi.hasSingleChild
isAncestor
->NodeApi.isAncestor
isDescendant
->NodeApi.isDescendant
isEditor
->NodeApi.isEditor
isNode
->NodeApi.isNode
isNodeList
->NodeApi.isNodeList
nodeMatches
->NodeApi.matches
-
Moved to
ElementApi.
:elementMatches
->ElementApi.matches
isElement
->ElementApi.isElement
isElementList
->ElementApi.isElementList
-
Moved to
TextApi.
:isText
->TextApi.isText(at)
-
Moved to
RangeApi.
:isCollapsed
->RangeApi.isCollapsed
isExpanded
->RangeApi.isExpanded
-
Moved to
PathApi.
:isFirstChild
->!PathApi.hasPrevious
getPreviousPath
->PathApi.previous
-
Moved to
PointApi.
:getPointFromLocation({ at, focus })
->PointApi.get(at, { focus })
-
Moved from
@udecode/plate/react
to@udecode/plate
:Hotkeys
-
Upgraded to
zustand@5
andzustand-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
->Editor
TOperation
->Operation
TPath
->Path
TNodeProps
->NodeProps
TNodeChildEntry
->NodeChildEntry
TNodeEntry
->NodeEntry
TDescendant
->Descendant
TDescendantEntry
->DescendantEntry
TAncestor
->Ancestor
TAncestorEntry
->AncestorEntry
TElementEntry
->ElementEntry
TTextEntry
->TextEntry
- Query/transform options now use generic
V extends Value
instead ofE extends Editor
. getEndPoint
,getEdgePoints
,getFirstNode
,getFragment
,getLastNode
,getLeafNode
,getPath
,getPoint
,getStartPoint
can returnundefined
if 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.previous
returnundefined
if not found instead of throwing- Replace
NodeOf
type withDescendantOf
ineditor.tf.setNodes
editor.tf.unsetNodes
,editor.api.previous
,editor.api.node
,editor.api.nodes
,editor.api.last
- Enhanced
editor.tf.setNodes
:- Added
marks
option to handle mark-specific operations - When
marks: true
:- Only applies to text nodes in non-void nodes or markable void nodes
- Automatically sets
split: true
andvoids: true
- Handles both expanded ranges and collapsed selections in markable voids
- Replaces
addRangeMarks
functionality
- 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.
TablePlugin
now depends onNodeIdPlugin
.- Table merging is now enabled by default:
- Renamed
enableMerging
todisableMerge
. - Migration:
enableMerging: true
→ remove the option.- otherwise →
TablePlugin.configure({ options: { disableMerge: true } })
- Renamed
- Renamed
unmergeTableCells
tosplitTableCell
. - Renamed
editor.api.create.cell
toeditor.api.create.tableCell
. - In
useTableMergeState
, renamedcanUnmerge
tocanSplit
. insertTableRow
andinsertTableColumn
: removeddisableSelect
in favor ofselect
. Migration: replace it with the opposite boolean.getTableCellBorders
: params(element, options)
→(editor, options)
; removedisFirstCell
andisFirstRow
.- Merged
useTableCellElementState
intouseTableCellElement
:- Removed its parameter.
- Removed
hovered
andhoveredLeft
returns (use CSS instead). - Renamed
rowSize
tominHeight
. - Computes column sizes and returns
width
.
- Merged
useTableCellElementResizableState
intouseTableCellElementResizable
:- Removed
onHover
andonHoverEnd
props (use CSS instead).
- Removed
- Merged
useTableElementState
intouseTableElement
:- Removed its parameter.
- No longer computes and returns
colSizes
,minColumnWidth
, andcolGroupProps
.
41.0.2
@udecode/[email protected]
-
#3830 by @felixfeng33 – Rename
findNodePath
tofindPath
since the addition offindNodePath
in the headless lib.We recommend using
findPath
mostly 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
findNodePath
would increase the initial render time by O(n²) - Key press handlers where using
findNodePath
would 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
, anduseDropBlock
hooks in favor ofuseDndNode
,useDragNode
, anduseDropNode
. - Removed
DndProvider
anduseDraggableStore
. Drop line state is now managed byDndPlugin
as a single state objectdropTarget
containing bothid
andline
. useDropNode
: removedonChangeDropLine
anddropLine
options
Migration steps:
- Remove
DndProvider
from your draggable component (e.g.draggable.tsx
) - Replace
useDraggableStore
withuseEditorPlugin(DndPlugin).useOption
- Remove
useDraggableState
. Useconst { isDragging, previewRef, handleRef } = useDraggable
- Remove
useDraggableGutter
. SetcontentEditable={false}
to your gutter element - Remove
props
fromuseDropLine
. SetcontentEditable={false}
to your drop line element - Remove
withDraggable
,useWithDraggable
. UseDraggableAboveNodes
instead
- Removed
@udecode/[email protected]
- #3830 by @felixfeng33 –
- Move
render.belowNodes
fromIndentListPlugin
toBaseIndentListPlugin
. Props type forlistStyleTypes.liComponent
andlistStyleTypes.markerComponent
options is nowSlateRenderElementProps
instead ofPlateRenderElementProps
- Move
someIndentList
,someIndentTodo
from@udecode/plate-indent-list/react
to@udecode/plate-indent-list
- Move
@udecode/[email protected]
-
insertColumnGroup
: renamelayout
tocolumns
- Remove
setColumnWidth
,useColumnState
. UsesetColumns
instead
@udecode/[email protected]
-
#3830 by @felixfeng33 – Move from
@udecode/plate-table/react
to@udecode/plate-table
:deleteColumn
deleteColumnWhenExpanded
deleteRow
deleteRowWhenExpanded
getTableColumn
getTableGridAbove
getTableGridByRange
getTableRow
insertTable
mergeTableCells
moveSelectionFromCell
overrideSelectionFromCell
unmergeTableCells
withDeleteTable
withGetFragmentlable
withInsertFragmentTable
withInsertTextTable
withMarkTable
withSelectionTable
withSetFragmentDataTable
withTable
40.0.0
@udecode/[email protected]
- #3744 by @zbeyens –
- Add
slate-dom
as a peer dependency. - Update
slate-react
peer dependency to>=0.111.0
- Add
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3744 by @zbeyens –
- Remove
toggleColumns
in favor oftoggleColumnGroup
- Remove
insertEmptyColumn
in favor ofinsertColumn
- Remove
39.0.0
@udecode/[email protected]
-
#3597 by @zbeyens – The following changes were made to improve performance:
- Refactored
useDraggable
hook to focus on core dragging functionality:- Removed
dropLine
. UseuseDropLine().dropLine
instead. - Removed
groupProps
from the returned object –isHovered
, andsetIsHovered
from the returned state. Use CSS instead. - Removed
droplineProps
, andgutterLeftProps
from the returned object. UseuseDropLine().props
,useDraggableGutter().props
instead.
- Removed
- Refactored
@udecode/[email protected]
-
#3597 by @zbeyens – The following changes were made to improve performance:
- Removed
useHooksBlockSelection
in favor ofBlockSelectionAfterEditable
- Removed
slate-selected
class fromBlockSelectable
. You can do it on your components usinguseBlockSelected()
instead, or by using our newblock-selection.tsx
component. - Introduced
useBlockSelectableStore
for managing selectable state.
- Removed
38.0.1
@udecode/[email protected]
-
- Change
plugin.options
merging 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
/react
entry: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
->BasicElementsPlugin
createBlockquotePlugin
->BlockquotePlugin
createCodeBlockPlugin
->CodeBlockPlugin
createHeadingPlugin
->HeadingPlugin
- Move paragraph plugin to
@udecode/plate-core
@udecode/[email protected]
- #3420 by @zbeyens –
createBasicMarksPlugins
->BasicMarksPlugin
createBoldPlugin
->BoldPlugin
createCodePlugin
->CodePlugin
createItalicPlugin
->ItalicPlugin
createStrikethroughPlugin
->StrikethroughPlugin
createSubscriptPlugin
->SubscriptPlugin
createSuperscriptPlugin
->SuperscriptPlugin
createUnderlinePlugin
->UnderlinePlugin
- All mark plugins removed
hotkey
option. Useplugin.shortcuts
instead (see plate-core)
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createSoftBreakPlugin
->SoftBreakPlugin
createExitBreakPlugin
->ExitBreakPlugin
createSingleLinePlugin
->SingleLinePlugin
@udecode/[email protected]
- #3420 by @zbeyens –
createCaptionPlugin
->CaptionPlugin
CaptionPlugin
options:- Rename
pluginKeys
toplugins
- Rename
focusEndCaptionPath
tofocusEndPath
- Rename
focusStartCaptionPath
tofocusStartPath
- Rename
showCaptionId
tovisibleId
- Rename
isShow
toisVisible
- Rename
- Move
captionGlobalStore
toCaptionPlugin
@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
commentsStore
toCommentsPlugin
- Remove
CommentsProvider
and its hooks - Remove
useCommentsStates
(replaced by direct option access) - Remove
useCommentsSelectors
(replaced by option selectors) - Remove
useCommentsActions
(replaced by api methods) - Replace
useUpdateComment
withapi.comment.updateComment
- Replace
useAddRawComment
withapi.comment.addRawComment
- Replace
useAddComment
withapi.comment.addComment
- Replace
useRemoveComment
withapi.comment.removeComment
- Replace
useResetNewCommentValue
withapi.comment.resetNewCommentValue
- Replace
useNewCommentText
withoptions.newText
- Replace
useMyUser
withoptions.myUser
- Replace
useUserById
withoptions.userById
- Replace
useCommentById
withoptions.commentById
- Replace
useActiveComment
withoptions.activeComment
- Replace
useAddCommentMark
withinsert.comment
@udecode/[email protected]
- #3420 by @zbeyens –
- Split build into
@udecode/plate-common
and@udecode/plate-common/react
. - NEW
/react
exports@udecode/react-hotkeys
- Split build into
@udecode/[email protected]
-
#3420 by @zbeyens – Plugin System:
Decoupling React in all packages:
- Split build into
@udecode/plate-core
and@udecode/plate-core/react
- NEW
SlatePlugin
as the foundation for all plugins PlatePlugin
extendsSlatePlugin
with 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
NamePlugin
option types, useNameConfig
instead. NameConfig
as 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, }, }, })
toggleParagraph
is 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
/PlatePlugin
properties:type
->node.type
isElement
->node.isElement
isLeaf
->node.isLeaf
isInline
->node.isInline
isMarkableVoid
->node.isMarkableVoid
isVoid
->node.isVoid
component
->node.component
orrender.node
props
->node.props
overrideByKey
->override.plugins
renderAboveEditable
->render.aboveEditable
renderAboveSlate
->render.aboveSlate
renderAfterEditable
->render.afterEditable
renderBeforeEditable
->render.beforeEditable
inject.props
->inject.nodeProps
inject.props.validTypes
->inject.targetPlugins
inject.aboveComponent
->render.aboveNodes
inject.belowComponent
->render.belowNodes
inject.pluginsByKey
->inject.plugins
editor.insertData
->parser
- NEW
parser.format
now supportsstring[]
- NEW
parser.mimeTypes: string[]
- NEW
deserializeHtml
->parsers.html.deserializer
deserializeHtml.getNode
->parsers.html.deserializer.parse
serializeHtml
->parsers.htmlReact.serializer
withOverride
->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:decorate
handlers
, includingonChange
. Returns({ event, ...ctx }) => void
instead of(editor, plugin) => (event) => void
handlers.onChange
:({ value, ...ctx }) => void
instead of(editor, plugin) => (value) => void
normalizeInitialValue
editor.insertData.preInsert
editor.insertData.transformData
editor.insertData.transformFragment
deserializeHtml.getNode
deserializeHtml.query
inject.props.query
inject.props.transformProps
useHooks
withOverrides
NEW
SlatePlugin
properties:api
: API methods provided by this plugindependencies
: An array of plugin keys that this plugin depends onnode
: Node-specific configuration for this pluginparsers
: Now acceptstring
keys 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
shortcuts
to add custom hotkeys to a plugin. - Remove
hotkey
option 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:
handler
is called with the editor, event, and event details.keys
is an array of keys to trigger the shortcut.priority
is the priority of the shortcut over other shortcuts....HotkeysOptions
from@udecode/react-hotkeys
Plugin Types:
- Update
SlatePlugin
,PlatePlugin
generics.P, V, E
->C extends AnyPluginConfig = PluginConfig
- Remove
PluginOptions
- Remove
PlatePluginKey
- Remove
HotkeyPlugin
,ToggleMarkPlugin
in favor ofplugin.shortcuts
WithPlatePlugin
->EditorPlugin
,EditorPlatePlugin
PlatePluginComponent
->NodeComponent
InjectComponent*
->NodeWrapperComponent*
PlatePluginInsertData
->Parser
PlatePluginProps
->NodeProps
RenderAfterEditable
->EditableSiblingComponent
WithOverride
->ExtendEditor
SerializeHtml
->HtmlReactSerializer
Plugin Store:
- NEW each plugin has its own store, accessible via
plugin.optionsStore
andplugin.useOptionsStore
editor
has 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
, useextend
instead - NEW
extend
method 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
configure
method to configure the properties of existing plugins. The difference withextend
is thatconfigure
with not add new properties to the plugin, it will only modify existing ones. - NEW
extendPlugin
method to extend a nested plugin configuration. - NEW
configurePlugin
method to configure the properties of a nested plugin. - NEW
extendApi
method to extend the plugin API. The API is then merged intoeditor.api[plugin.key]
. - NEW
extendTransforms
method to extend the plugin transforms. The transforms is then merged intoeditor.transforms[plugin.key]
. - NEW
extendEditorApi
method 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
extendEditorTransforms
method to extend the editor transforms. The transforms is then merged intoeditor.transforms
. - NEW
extendOptions
method to extend the plugin options with selectors. Useeditor.useOption(plugin, 'optionKey')
to subscribe to an (extended) option. - NEW
withComponent
to replaceplugin.node.component
Plugin Context
Each plugin method now receive the plugin context created with
getEditorPlugin(editor, plugin)
as parameter:api
editor
getOption
getOptions
plugin
setOption
setOptions
tf
type
useOption
Core Plugins:
- NEW
ParagraphPlugin
is now part ofcore
- NEW
DebugPlugin
is now part ofcore
- NEW
api.debug.log
,api.debug.info
,api.debug.warn
,api.debug.error
methods options.isProduction
to control logging in production environmentsoptions.logLevel
to set the minimum log leveloptions.logger
to customize logging behavioroptions.throwErrors
to control error throwing behavior, by default aPlateError
will 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
->EventEditorPlugin
eventEditorStore
->EventEditorStore
createDeserializeAstPlugin
->AstPlugin
createEditorProtocolPlugin
->SlateNextPlugin
- NEW
editor.tf.toggle.block
- NEW
editor.tf.toggle.mark
- Remove
createNodeFactoryPlugin
, included inSlateNextPlugin
. - Remove
createPrevSelectionPlugin
, included inSlateNextPlugin
.
- NEW
createHistoryPlugin
->HistoryPlugin
createInlineVoidPlugin
->InlineVoidPlugin
createInsertDataPlugin
->ParserPlugin
createLengthPlugin
->LengthPlugin
createReactPlugin
->ReactPlugin
Editor Creation:
NEW
withSlate
:- Extends an editor into a vanilla Plate editor
- NEW
rootPlugin
option for configuring the root plugin
NEW
withPlate
:- Extends an editor into a React Plate editor
- Now extends
withSlate
with React-specific enhancements - NEW
useOptions
anduseOption
methods 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
-
root
plugin is now created fromcreatePlateEditor
option as a quicker way to configure the editor than passingplugins
. Since plugins can have nested plugins (think as a recursive tree),plugins
option will be passed toroot
pluginplugins
option. -
Centralized editor resolution. Before, both
createPlateEditor
andPlate
component were resolving the editor. Now, onlycreatePlateEditor
takes care of that. That meansid
,value
, and other options are now controlled bycreatePlateEditor
. -
Remove
createPlugins
, pass plugins directly:components
->override.components
overrideByKey
->override.plugins
createPlateEditor
options:- Rename
normalizeInitialValue
option toshouldNormalizeEditor
- Move
components
tooverride.components
to override components by key - Move
overrideByKey
tooverride.plugins
to override plugins by key - Remove
disableCorePlugins
, useoverride.enabled
instead - NEW
value
to set the initial value of the editor. - NEW
autoSelect?: 'end' | 'start' | boolean
to auto select the start of end of the editor. This is decoupled fromautoFocus
. - NEW
selection
to control the initial selection. - NEW
override.enabled
to disable plugins by key - NEW
rootPlugin?: (plugin: AnyPlatePlugin) => AnyPlatePlugin
to configure the root plugin. From here, you can for example callconfigurePlugin
to 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 aPlateEditor
in a React component:- Uses
createPlateEditor
anduseMemo
to avoid re-creating the editor on every render. - Dependencies can be added to the hook to re-create the editor on demand.
id
option is always used as dependency.
Editor Methods:
editor: PlateEditor
:- Move
redecorate
toeditor.api.redecorate
- Move
reset
toeditor.tf.reset
- Move
plate.set
toeditor.setPlateState
- Move
blockFactory
toeditor.api.create.block
- Move
childrenFactory
toeditor.api.create.value
- Rename
plugins
topluginList
- Rename
pluginsByKey
toplugins
- 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
useOption
to subscribe to a plugin option in a React component - NEW
useOptions
to 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:
key
options
api
transforms
- Can't infer for some reason? Use
createTPlateEditor
for explicit typing.
const editor = createPlateEditor({ plugins: [TablePlugin] }); editor.api.htmlReact.serialize(); // core plugin is automatically inferred editor.tf.insert.tableRow(); // table plugin is automatically inferred
Plate Component
PlateProps
:editor
is now required. Ifnull
,Plate
will not render anything. As before,Plate
remounts onid
change.- Remove
id
,plugins
,maxLength
, pass these tocreatePlateEditor
instead - Remove
initialValue
,value
, passvalue
tocreatePlateEditor
instead - Remove
editorRef
- Remove
disableCorePlugins
, overrideplugins
increatePlateEditor
instead
Utils:
- Remove
useReplaceEditor
sinceeditor
is now always controlled - NEW
useEditorPlugin
to get the editor and the plugin context.
Types:
PlateRenderElementProps
,PlateRenderLeafProps
generics:V, N
->N, C
Plate Store:
- Remove
plugins
andrawPlugins
, useuseEditorRef().plugins
instead, or listen to plugin changes witheditor.useOption(plugin, <optionKey>)
- Remove
value
, useuseEditorValue()
instead - Remove
editorRef
, useuseEditorRef()
instead
Miscellaneous Changes
slate >=0.103.0
peer dependencyslate-react >=0.108.0
peer dependency- New dependency
@udecode/react-hotkeys
- Remove
ELEMENT_
,MARK_
andKEY_
constants. UseNamePlugin.key
instead. - Replace
ELEMENT_DEFAULT
withParagraphPlugin.key
. - Remove
getTEditor
- Rename
withTReact
towithPlateReact
- Rename
withTHistory
towithPlateHistory
- Rename
usePlateId
touseEditorId
- Remove
usePlateSelectors().id()
,usePlateSelectors().value()
,usePlateSelectors().plugins()
, use insteaduseEditorRef().<key>
- Rename
toggleNodeType
totoggleBlock
toggleBlock
options:- Rename
activeType
totype
- Rename
inactiveType
todefaultType
- Rename
- Remove
react-hotkeys-hook
re-exports. Use@udecode/react-hotkeys
instead.
Types:
- Move
TEditableProps
,TRenderElementProps
to@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).isDragging
instead - Move
dndStore
toDndPlugin
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createFontBackgroundColorPlugin
->FontBackgroundColorPlugin
createFontColorPlugin
->FontColorPlugin
createFontSizePlugin
->FontSizePlugin
createFontFamilyPlugin
->FontFamilyPlugin
createFontWeightPlugin
->FontWeightPlugin
@udecode/[email protected]
- #3420 by @zbeyens –
createHeadingPlugin
->HeadingPlugin
- Replace
ELEMENT_H1
withHEADING_KEYS.H1
- Replace
KEYS_HEADING
withHEADING_LEVELS
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createDeserializeHtmlPlugin
->HtmlPlugin
- Rename
deserializeHtml
plugin tohtml
- Rename
deserializeHtml.getNode
toparse
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createIndentListPlugin
->IndentListPlugin
- Rename
injectIndentListComponent
torenderIndentListBelowNodes
- Replace
normalizeIndentList
withwithNormalizeIndentList
- Replace
deleteBackwardIndentList
withwithDeleteBackwardIndentList
- Replace
insertBreakIndentList
withwithInsertBreakIndentList
- 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
ul
andol
tolist
plugin toggleList
options are now{ type: string }
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createMediaPlugin
->MediaPlugin
FloatingMediaUrlInput
,submitFloatingMedia
rename optionpluginKey
->plugin
insertMediaEmbed
removekey
option
@udecode/[email protected]
- #3420 by @zbeyens –
createMentionPlugin
->MentionPlugin
- NEW
MentionInputPlugin
- Remove
createMentionNode
option, overrideapi.insert.mention
instead
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
- NEW
@udecode/plate-layout
- NEW
/react
exports@udecode/react-hotkeys
- Split build into
@udecode/plate
and@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
->SelectOnBackspacePlugin
createDeletePlugin
->DeletePlugin
@udecode/[email protected]
- #3420 by @zbeyens –
- Rename
createSelectionPlugin
toBlockSelectionPlugin
- Remove
isNodeBlockSelected
,isBlockSelected
,hasBlockSelected
,useBlockSelected
functions- Use
editor.getOptions(BlockSelectionPlugin)
oreditor.useOptions(BlockSelectionPlugin)
instead
- Use
- Remove
addSelectedRow
function- Use
editor.api.blockSelection.addSelectedRow
instead
- Use
- Remove
withSelection
HOC - Rename
onCloseBlockSelection
toonChangeBlockSelection
- Moved
blockSelectionStore
toBlockSelectionPlugin
- Moved
blockContextMenuStore
toBlockContextMenuPlugin
- Remove
BlockStartArea
andBlockSelectionArea
components- Use
areaOptions
inBlockSelectionPlugin
for configuration instead
- Use
- Remove dependency on
@viselect/vanilla
package- 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-react
andslate-history
increateTEditor
- Add
noop
function to provide default implementations for unimplemented editor methods
Types:
- Merge
ReactEditor
andHistoryEditor
interfaces intoTEditor
, removingTReactEditor
andTHistoryEditor
- Remove
Value
generic type parameter from function signatures and type definitions - Replace
V extends Value
withE extends TEditor
for improved type inference - Simplify
TEditor<V>
toTEditor
in many places - Refactor element-related types, where
E extends TEditor
in 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
TNodeEntry
related 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
TReactEditor
type, as it's now integrated into the mainTEditor
type in@udecode/slate
. UseTEditor
instead. - Replace
V extends Value
withE extends TEditor
for improved type inference - NEW
TEditableProps
,TRenderElementProps
- Remove
@udecode/[email protected]
-
- Replace
V extends Value
withE extends TEditor
for improved type inference
- Replace
@udecode/[email protected]
- #3420 by @zbeyens –
createSuggestionPlugin
->SuggestionPlugin
- Move
suggestionStore
toSuggestionPlugin
- Remove
SuggestionProvider
and its hooks - Remove
useSuggestionStates
(replaced by direct option access) - Remove
useSuggestionSelectors
(replaced by option selectors) - Remove
useSuggestionActions
(replaced by api methods) - Replace
useUpdateSuggestion
withapi.suggestion.updateSuggestion
- Replace
useAddSuggestion
withapi.suggestion.addSuggestion
- Replace
useRemoveSuggestion
withapi.suggestion.removeSuggestion
- Replace
useSuggestionById
withoptions.suggestionById
- Replace
useSuggestionUserById
withoptions.suggestionUserById
- Replace
useCurrentSuggestionUser
withoptions.currentSuggestionUser
- Remove
editor.activeSuggestionId
, use plugin option - Remove
useSetIsSuggesting
, useeditor.setOption
- Remove
useSetActiveSuggestionId
, useeditor.setOption
- Remove
editor.isSuggesting
, use plugin option - Remove
SuggestionEditorProps
type
@udecode/[email protected]
- #3420 by @zbeyens –
createTabbablePlugin
->TabbablePlugin
TabbablePlugin
optionisTabbable
: remove firsteditor
parameter
@udecode/[email protected]
- #3420 by @zbeyens –
createTablePlugin
->TablePlugin
- NEW
TableRowPlugin
,TableCellPlugin
,TableCellHeaderPlugin
- Replace
insertTableColumn
witheditor.insert.tableColumn
- Replace
insertTableRow
witheditor.insert.tableRow
- Move
cellFactory
option tocreate.cell
api - Move
getCellChildren
option totable.getCellChildren
api
@udecode/[email protected]
- #3420 by @zbeyens –
createTogglePlugin
->TogglePlugin
- Move
toggleControllerStore
toTogglePlugin
- Remove
setOpenIds
option - Replace
isToggleOpen
with optionisOpen
- Rename
injectToggle
torenderToggleAboveNodes
@udecode/[email protected]
@udecode/[email protected]
- #3420 by @zbeyens –
createYjsPlugin
->YjsPlugin
- Move
yjsStore
toYjsPlugin
- Move
editor.yjs.provider
tooptions.provider
- Rename
RenderAboveEditableYjs
toYjsAboveEditable
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
selectedColor
option forBlockSelectable
has been deprecated. Please useuseBlockSelected
to customize the style of each node component. -
#3241 by @felixfeng33 – Add logic for the
block-context-menu
and 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,
TableProvider
was incorrectly shared by all tables in the editor.TableProvider
must now be rendered as part ofTableElement
.
29.0.0
@udecode/[email protected]
- #2829 by @zbeyens –
- Moved
withProps
to@udecode/cn
- Moved
PortalBody
,Text
,Box
,createPrimitiveComponent
,createSlotComponent
,withProviders
to@udecode/react-utils
- Removed
getRootProps
(unused)
- Moved
28.0.0
@udecode/[email protected]
822f6f56b
by @12joan –- Remove
{ fn: ... }
workaround for jotai stores that contain functions - Breaking change:
usePlateSelectors
,usePlateActions
andusePlateStates
no longer accept generic type arguments. If custom types are required, cast the resulting values at the point of use, or use hooks likeuseEditorRef
that 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-comments
made in 26.0.0
- Migrate store to
@udecode/[email protected]
- #2763 by @12joan –
- Migrate store from
jotai@1
tojotai@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@3
tozustand@4
- Rename
zustand-x
exportsStateActions
->ZustandStateActions
StoreApi
->ZustandStoreApi
createStore
->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
comments
prop on CommentsProvider toinitialComments
to 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:
activeCommentId
addingCommentId
newValue
focusTextarea
- The following props on CommentsProvider can now be updated after the initial render (whereas prior to this version, doing so had no effect):
myUserId
users
onCommentAdd
onCommentUpdate
onCommentDelete
- 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
, replacestripWhitespace
withcollapseWhiteSpace
, defaulting to true. ThecollapseWhiteSpace
option 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
Plate
toPlateContent
. - [Breaking] Rename
PlateProvider
toPlate
. - [Breaking] Rendering
PlateContent
is 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
plugins
fromPlateContent
. These props should be passed toPlate
. - [Breaking] Remove
editableProps
prop fromPlateContent
. Move these asPlateContent
props. - [Breaking] Remove
children
prop fromPlateContent
. Render instead these components afterPlateContent
. - [Breaking] Remove
firstChildren
prop fromPlateContent
. Render instead these components beforePlateContent
. - [Breaking] Remove
editableRef
prop fromPlateContent
. Useref
instead. - [Breaking] Remove
withPlateProvider
. - [Breaking] Rename
usePlateEditorRef
touseEditorRef
. - [Breaking] Rename
usePlateEditorState
touseEditorState
. - [Breaking] Rename
usePlateReadOnly
touseEditorReadOnly
. This hook can be used belowPlate
whileuseReadOnly
can only be used in node components. - [Breaking] Rename
usePlateSelection
touseEditorSelection
. - [Breaking] Rename store attributes
keyDecorate
,keyEditor
andkeySelection
toversionDecorate
,versionEditor
andversionSelection
. These are now numbers incremented on each change. - [Breaking] Rename store attribute
isRendered
toisMounted
.
- [Breaking] Rename
23.0.0
@udecode/[email protected]
-
#2537 by @haydencarlson –
MediaEmbedElement
is now more headless with a smaller bundle size. Update the following components:npx shadcn@canary add media-embed-element
- now uses
react-lite-youtube-embed
for YouTube videos. - now uses
react-tweet
for Twitter tweets.
- now uses
npx shadcn@canary add image-element
Breaking changes:
- Moved
Resizable
to@udecode/plate-resizable
- Moved
Caption
,CaptionTextarea
to@udecode/plate-caption
- Removed
useMediaEmbed
,MediaEmbedVideo
,MediaEmbedTweet
,Tweet
,parseMediaUrl
,mediaStore
- Removed
@udecode/resizable
,scriptjs
,react-textarea-autosize
dependencies MediaPlugin
- removed
rules
. Useparsers
option instead. - removed
disableCaption
. UsecreateCaptionPlugin
instead.
- removed
- Caption is now a separate plugin. Install
@udecode/plate-caption
and 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
. ResizeHandle
is now fully headless: no style is applied by default. Add your ownResizable
,ResizeHandle
components:npx shadcn@canary add resizable
- Package renamed to
@udecode/[email protected]
- Removed
TableCellElementResizable
. UseuseTableCellElementResizableState
anduseTableCellElementResizable
instead.
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:
AccountCircleIcon
CheckIcon
MoreVertIcon
RefreshIcon
AvatarImage
CommentLinkButton
CommentLinkDialog
CommentLinkDialogCloseButton
CommentLinkDialogCopyLink
CommentLinkDialogInput
PlateCommentLeaf
foruseCommentLeafState
@udecode/[email protected]
- #2471 by @zbeyens – Removed:
Draggable
DraggableBlock
DraggableBlockToolbar
DraggableBlockToolbarWrapper
DraggableDropline
DraggableGutterLeftProps
DraggableRoot
DragHandle
@udecode/[email protected]
- #2471 by @zbeyens – Removed:
FloatingLink
FloatingLinkEditButton
FloatingLinkTextInput
UnlinkButton
LaunchIcon
Link
LinkIcon
LinkOffIcon
ShortTextIcon
@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-ui
dependency. - Removed
@udecode/plate-emoji
dependency. You can install it separately. - Removed
styled-components
peerDependency.
Replaced
@udecode/plate-headless
dependency (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.0
Removed:useElementPrpos
useWrapElement
createComponentAs
createElementAs
@udecode/[email protected]
- #2471 by @zbeyens – Removed:
TableCellElement
TableCellElementResizableWrapper
TableCellElementRoot
TableElement
TableElementCol
TableElementColGroup
TableElementRoot
TableElementTBody
TableRowElement
ArrowDropDownCircleIcon
BorderAllIcon
BorderBottomIcon
BorderLeftIcon
BorderNoneIcon
BorderOuterIcon
BorderRightIcon
BorderTopIcon
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]
0077402
by @zbeyens –- This package has been split into multiple packages for separation of concerns and decoupled versioning:
@udecode/utils
is a collection of miscellaneous utilities. Can be used by any project.@udecode/slate
is a collection ofslate
experimental features and bug fixes that may be moved intoslate
one day. It's essentially composed of the generic types. Can be used by vanillaslate
consumers without plate.@udecode/slate-react
is a collection ofslate-react
experimental features and bug fixes that that may be moved intoslate-react
one day. It's essentially composed of the generic types. Can be used by vanillaslate-react
consumers without plate.@udecode/plate-core
is the minimalistic core of plate. It essentially includesPlate
,PlateProvider
and their dependencies. Note this package is not dependent on the*-utils
packages.@udecode/slate-utils
is a collection of utils depending on@udecode/slate
. Can be used by vanillaslate
consumers without plate.@udecode/plate-utils
is a collection of utils depending on@udecode/slate-react
and@udecode/plate-core
@udecode/plate-common
re-exports the 6 previous packages and is a dependency of all the other packages. It's basically replacing@udecore/plate-core
as a bundle.
- Removed
getPreventDefaultHandler
since it is no longer needed. Migration:- If using
@udecode/plate
or@udecode/plate-headless
: none - Else: find & replace
@udecode/plate-core
by@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
allowedSchemes
plugin option- Any URL schemes other than
http(s)
,mailto
andtel
must be added toallowedSchemes
, otherwise they will not be included in links
- Any URL schemes other than
- Add
@udecode/[email protected]
- #2251 by @zbeyens –
TablePlugin
optiondisableUnsetSingleColSize
has 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
getTableColumnIndex
second 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
,withPlateDraggables
andPlateDraggable
are 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: 1px
to support cell borders- if all columns have a fixed size, the table will have a dynamic width instead of always 100%
TableRowElement
->PlateTableRowElement
TableCellElement
->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
selectedCell
div in favor of::before
TablePopover
->PlateTablePopover
Styled 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-selection
package moved out from@udecode/plate
because of https://github.com/Simonwep/selection/issues/124- Migration:
- If not using
createBlockSelectionPlugin
, no migration is needed. - Otherwise, install
@udecode/plate-selection
and importcreateBlockSelectionPlugin
from 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
PlateProvider
orPlate
(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
PlateProvider
with different scopes (id
prop). 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
useEventPlateId
is 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
id
is 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
PlateProvider
initialValue, value, editor, normalizeInitialValue, normalizeEditor
are no longer defined in an effect (SSR support)
- Props:
- now extends the previous
Plate
props - if using
PlateProvider
, set the provider props on it instead ofPlate
.Plate
would only neededitableProps
andPlateEditableExtendedProps
- 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
editor
is no longer nullable - store
value
is no longer nullable id
type is nowPlateId
- store
- renamed:
SCOPE_PLATE
toPLATE_SCOPE
getEventEditorId
togetEventPlateId
getPlateActions().resetEditor
touseResetPlateEditor()
- removed:
plateIdAtom
usePlateId
forusePlateSelectors().id()
EditablePlugins
forPlateEditable
SlateChildren
PlateEventProvider
forPlateProvider
withPlateEventProvider
forwithPlateProvider
usePlate
usePlatesStoreEffect
useEventEditorId
foruseEventPlateId
platesStore, platesActions, platesSelectors, usePlatesSelectors
getPlateActions
forusePlateActions
getPlateSelectors
forusePlateSelectors
getPlateEditorRef
forusePlateEditorRef
getPlateStore, usePlateStore
EditorId
forPlateId
@udecode/[email protected]
- #1871 by @zbeyens –
- Removed these imports because of build errors:
prismjs/components/prism-django
prismjs/components/prism-ejs
prismjs/components/prism-php
- Removed these imports because of build errors:
@udecode/[email protected]
- #1871 by @zbeyens –
- Removed
[ELEMENT_CODE_BLOCK]: CodeBlockElement
from 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-image
and@udecode/plate-media-embed
, those got merged into@udecode/plate-media
- deprecate
@udecode/[email protected]
- #1721 by @zbeyens –
- removed:
useImageElement
foruseElement
MediaEmbedUrlInput
forFloatingMediaUrlInput
parseEmbedUrl
forparseMediaUrl
EmbedProviders
- renamed:
ImageImg
toImage
ImageCaptionTextarea
toCaptionTextarea
useImageCaptionString
touseCaptionString
ImageResizable
toResizable
- removed:
@udecode/[email protected]
- #1721 by @zbeyens –
TableElementBase
props:- replace
onRenderContainer
byfloatingOptions
or by replacingELEMENT_TABLE
in thecreatePlateUI
function.
- replace
TablePopover
is now a floating instead of tippy- deps:
- replaced
plate-ui-popover
byplate-floating
- replaced
@udecode/[email protected]
15.0.0
@udecode/[email protected]
- #1677 by @zbeyens –
- deps:
- replaced
@udecode/plate-ui-popper
by@udecode/plate-floating
- replaced
comboboxStore
:- removed
popperContainer
, usefloatingOptions
instead - removed
popperOptions
, usefloatingOptions
instead
- removed
- deps:
@udecode/[email protected]
- #1677 by @zbeyens –
createLinkPlugin
- removed
onKeyDownLink
for floating link - removed
hotkey
fortriggerFloatingLinkHotkeys
- removed
- removed:
getAndUpsertLink
forupsertLink
upsertLinkAtSelection
forupsertLink
LinkToolbarButton
:onClick
now callstriggerFloatingLink
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #1677 by @zbeyens –
- remove
@udecode/plate-ui-popper
andreact-popper
deps for@udecode/plate-floating
BalloonToolbarProps
:- removed
popperOptions
forfloatingOptions
- removed
- remove
useBalloonToolbarPopper
foruseFloatingToolbar
14.0.0
@udecode/[email protected]
- #1633 by @tjramage – Moved
serializeHtml
and its utils to@udecode/plate-serializer-html
as 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]
Plate
children are now rendered as last children ofSlate
(previously first children). To reproduce the previous behavior, movechildren
tofirstChildren
@udecode/[email protected]
@udecode/[email protected]
- #1585 by @zbeyens – Removed
@udecode/plate-juice
from@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-backend
deps 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:
useDndBlock
options:blockRef
->nodeRef
removePreview
->preview.disable
useDropBlockOnEditor
->useDropBlock
useDropBlock
options:blockRef
->nodeRef
setDropLine
->onChangeDropLine
signature change:
getHoverDirection
:
// before
(
dragItem: DragItemBlock,
monitor: DropTargetMonitor,
ref: any,
hoverId: string
)
// after
{
dragItem,
id,
monitor,
nodeRef,
}: GetHoverDirectionOptions
11.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
TEditor
type to beTEditor<V>
whereV
represents the "value" being edited by Slate. In the most generic editor,V
would 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 aTText
node. 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
TEditor
still.)
- 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
TEditor
methods are not typed based onValue
as 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
->TNode
Element
->TElement
Text
->TText
NodeEntry
->TNodeEntry
NodeProps
->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
,ReactEditor
functions should be replaced: The whole API has been typed into Plate core. See https://github.com/udecode/plate/packages/core/src/slate createEditor
->createTEditor
withReact
->withTReact
withHistory
->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>>
, whereP
is the plugin options type. -
Editor
functions are using<V extends Value>
generic, whereV
can be a custom editor value type used inPlateEditor<V>
. -
Editor
functions returning a node are using<N extends ENode<V>, V extends Value = Value>
generics, whereN
can be a custom returned node type. -
Editor
callbacks (e.g. a plugin option) are using<V extends Value = Value, E extends PlateEditor<V> = PlateEditor<V>>
generics, whereE
can be a custom editor type. -
Node
functions 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
-
WithOverride
is 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
->getAboveNode
getParent
->getParentNode
getText
->getEditorString
getLastNode
->getLastNodeByLevel
getPointBefore
->getPointBeforeLocation
getNodes
->getNodeEntries
isStart
->isStartPoint
isEnd
->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
->TLinkElement
ImageNodeData
->TImageElement
TableNodeData
->TTableElement
MentionNodeData
->TMentionElement
MentionNode
->TMentionElement
MentionInputNodeData
->TMentionInputElement
MentionInputNode
->TMentionInputElement
CodeBlockNodeData
->TCodeBlockElement
MediaEmbedNodeData
->TMediaEmbedElement
TodoListItemNodeData
->TTodoListItemElement
ExcalidrawNodeData
->TExcalidrawElement
Utils
match
signature change:
<T extends TNode>(
obj: T,
path: TPath,
predicate?: Predicate<T>
)
deleteFragment
is now usingEditor.deleteFragment
@udecode/[email protected]
getEmptyTableNode
default 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,
BalloonToolbar
could be outsidePlate
. Now,BallonToolbar
should be a child ofPlate
to support multiple editors.
9.0.0
@udecode/[email protected]
- #1303 by @zbeyens –
Plate
editor
prop can now be fully controlled: Plate is not applyingwithPlate
on it anymore
PlatePlugin.deserializeHtml
- can't be an array anymore
- moved
validAttribute
,validClassName
,validNodeName
,validStyle
todeserializeHtml.rules
property
- renamed
plateStore
toplatesStore
platesStore
is now a zustood storeeventEditorStore
is now a zustood storegetPlateId
now gets the last editor id if not focused or blurred- used by
usePlateEditorRef
andusePlateEditorState
- used by
- removed:
usePlateEnabled
forusePlateSelectors(id).enabled()
usePlateValue
forusePlateSelectors(id).value()
usePlateActions
:resetEditor
forgetPlateActions(id).resetEditor()
clearState
forplatesActions.unset()
setInitialState
forplatesActions.set(id)
setEditor
forgetPlateActions(id).editor(value)
setEnabled
forgetPlateActions(id).enabled(value)
setValue
forgetPlateActions(id).value(value)
getPlateState
usePlateState
usePlateKey
@udecode/[email protected]
- #1303 by @zbeyens –
- renamed
plate-x-ui
toplate-ui-x
: all packages depending onstyled-components
hasplate-ui
prefix - renamed
plate-x-serializer
toplate-serializer-x
- is now exporting only these (new) packages:
@udecode/plate-headless
: all unstyled packages@udecode/plate-ui
: all styled packages
- renamed
PlateState
toPlateStoreState
8.0.0
@udecode/[email protected]
-
IndentListPluginOptions
forPlatePlugin
Rename:
getIndentListInjectComponent
toinjectIndentListComponent
@udecode/[email protected]
-
#1234 by @zbeyens – Breaking changes:
Plate
- removed
components
prop:
// 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
options
prop:
// 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} />;
PlatePlugin
key
- replacing
pluginKey
- is now required: each plugin needs a key to be retrieved by key.
- replacing
- all handlers have
plugin
as 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;
serialize
no longer haselement
andleaf
properties:
type SerializeHtml = RenderFunction< PlateRenderElementProps | PlateRenderLeafProps >;
Renamed:
injectParentComponent
toinject.aboveComponent
injectChildComponent
toinject.belowComponent
overrideProps
toinject.props
transformClassName
,transformNodeValue
,transformStyle
first parameter is no longereditor
as it's provided bythen
if needed.- the previously
getOverrideProps
is now the core behavior ifinject.props
is defined.
serialize
toserializeHtml
deserialize
todeserializeHtml
- 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 tohandlers
property.
// Before onDrop: handler; // After handlers: { onDrop: handler; }
Removed:
renderElement
is favor of:isElement
is a boolean that enables element rendering.- the previously
getRenderElement
is now the core behavior.
renderLeaf
is favor of:isLeaf
is a boolean that enables leaf rendering.- the previously
getRenderLeaf
is now the core behavior.
inlineTypes
andvoidTypes
for:isInline
is a boolean that enables inline rendering.isVoid
is 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
plugins
prop:
const corePlugins = [ createReactPlugin(), createHistoryPlugin(), createEventEditorPlugin(), createInlineVoidPlugin(), createInsertDataPlugin(), createDeserializeAstPlugin(), createDeserializeHtmlPlugin(), ];
plugins
is not a parameter anymore as it can be retrieved ineditor.plugins
withInlineVoid
is now using pluginsisInline
andisVoid
plugin properties.
Renamed:
getPlatePluginType
togetPluginType
getEditorOptions
togetPlugins
getPlatePluginOptions
togetPlugin
pipeOverrideProps
topipeInjectProps
getOverrideProps
topluginInjectProps
serializeHTMLFromNodes
toserializeHtml
getLeaf
toleafToHtml
getNode
toelementToHtml
xDeserializerId
toKEY_DESERIALIZE_X
deserializeHTMLToText
tohtmlTextNodeToString
deserializeHTMLToMarks
tohtmlElementToLeaf
andpipeDeserializeHtmlLeaf
deserializeHTMLToElement
tohtmlElementToElement
andpipeDeserializeHtmlElement
deserializeHTMLToFragment
tohtmlBodyToFragment
deserializeHTMLToDocumentFragment
todeserializeHtml
deserializeHTMLToBreak
tohtmlBrToNewLine
deserializeHTMLNode
todeserializeHtmlNode
deserializeHTMLElement
todeserializeHtmlElement
Removed:
usePlateKeys
,getPlateKeys
usePlateOptions
forgetPlugin
getPlateSelection
forgetPlateEditorRef().selection
flatMapByKey
getEditableRenderElement
andgetRenderElement
forpipeRenderElement
andpluginRenderElement
getEditableRenderLeaf
andgetRenderLeaf
forpipeRenderLeaf
andpluginRenderLeaf
getInlineTypes
getVoidTypes
getPlatePluginTypes
getPlatePluginWithOverrides
mapPlatePluginKeysToOptions
withDeserializeX
forPlatePlugin.editor.insertData
Changed types:
PlateEditor
:- removed
options
forpluginsByKey
- removed
WithOverride
is not returning an extended editor anymore (input and output editors are assumed to be the same types for simplicity).PlateState
- renamed
keyChange
tokeyEditor
- removed
plugins
foreditor.plugins
- removed
pluginKeys
- removed
selection
foreditor.selection
- actions:
- removed
setSelection
,setPlugins
,setPluginKeys
- removed
incrementKeyChange
for
- removed
- renamed
Renamed types:
XHTMLY
toXHtmlY
Deserialize
toDeseralizeHtml
Removed types:
PlatePluginOptions
:type
toPlatePlugin.type
component
toPlatePlugin.component
deserialize
toPlatePlugin.deserializeHtml
getNodeProps
toPlatePlugin.props.nodeProps
hotkey
toHotkeyPlugin
clear
toToggleMarkPlugin
defaultType
is hardcoded top.type
OverrideProps
forPlatePlugin.inject.props
Serialize
forPlatePlugin.serializeHtml
NodeProps
forAnyObject
OnKeyDownElementOptions
forHotkeyPlugin
OnKeyDownMarkOptions
forToggleMarkPlugin
WithInlineVoidOptions
GetNodeProps
forPlatePluginProps
DeserializeOptions
,GetLeafDeserializerOptions
,GetElementDeserializerOptions
,GetNodeDeserializerOptions
,GetNodeDeserializerRule
,DeserializeNode
forPlatePlugin.deserializeHtml
PlateOptions
RenderNodeOptions
DeserializedHTMLElement
- removed
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
@udecode/[email protected]
- #1234 by @zbeyens – Removed:
getCodeBlockPluginOptions
forgetPlugin
getCodeLinePluginOptions
forgetPlugin
@udecode/[email protected]
@udecode/[email protected]
- #1234 by @zbeyens – Removed:
getMentionInputPluginOptions
forgetPlugin
getMentionInputType
forgetPluginType
COMBOBOX_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:
createBasicElementsPlugin
createCodeBlockPlugin
createHeadingPlugin
createListPlugin
createTablePlugin
createBasicMarksPlugin
Removed:
createEditorPlugins
forcreatePlateEditor
(without components) andcreatePlateEditorUI
(with Plate components)createPlateOptions
forcreatePlugins
- all
DEFAULTS_X
: these are defined in the plugins - all
getXDeserialize
: these are defined in the plugins - all
WithXOptions
for extended plugins - all
getXRenderElement
- some plugin option types are removed for
PlatePlugin
Renamed:
createPlateComponents
tocreatePlateUI
- all
getXY
handlers toyX
(e.g.getXOnKeyDown
toonKeyDownX
) - all
XPluginOptions
toXPlugin
- all
pluginKey
parameter tokey
except in components
Renamed types:
DecorateSearchHighlightOptions
toFindReplacePlugin
Updated deps:
"slate": "0.70.0"
"slate-react": "0.70.1"
Removed deps (merged to core):
plate-common
plate-ast-serializer
plate-html-serializer
plate-serializer
@udecode/[email protected]
- #1234 by @zbeyens – Renamed:
createDeserializeCSVPlugin
tocreateDeserializeCsvPlugin
deserializeCSV
todeserializeCsv
@udecode/[email protected]
-
createDeserializeMdPlugin
:- is now disabled if there is html data in the data transfer.
Renamed:
createDeserializeMDPlugin
tocreateDeserializeMdPlugin
deserializeMD
todeserializeMd
7.0.0
@udecode/plate-core
- renamed:
SPEditor
toPEditor
(note thatPlateEditor
is the new default)SPRenderNodeProps
toPlateRenderNodeProps
SPRenderElementProps
toPlateRenderElementProps
SPRenderLeafProps
toPlateRenderLeafProps
useEventEditorId
tousePlateEventId
useStoreEditorOptions
tousePlateOptions
useStoreEditorRef
tousePlateEditorRef
useStoreEditorSelection
tousePlateSelection
useStoreEditorState
tousePlateEditorState
useStoreEditorValue
tousePlateValue
useStoreEnabled
tousePlateEnabled
useStorePlate
tousePlatePlugins
useStorePlatePluginKeys
tousePlateKeys
useStoreState
tousePlateState
getPlateId
: Get the last focused editor id, else get the last blurred editor id, else get the first editor id, elsenull
getPlateState
:- 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 forusePlateEditorRef
usePlateEditorState
usePlateX
...
- removed first parameter
@udecode/plate-alignment
setAlign
: optionalign
renamed tovalue
- removed
getAlignOverrideProps()
in favor ofgetOverrideProps(KEY_ALIGN)
@udecode/plate-indent
- removed
getIndentOverrideProps()
in favor ofgetOverrideProps(KEY_INDENT)
- rename
onKeyDownHandler
togetIndentOnKeyDown()
IndentPluginOptions
- rename
types
tovalidTypes
- rename
cssPropName
tostyleKey
- rename
transformCssValue
totransformNodeValue
- rename
@udecode/plate-line-height
setLineHeight
: optionlineHeight
renamed tovalue
- removed
getLineHeightOverrideProps
in favor ofgetOverrideProps(KEY_LINE_HEIGHT)
@udecode/plate-mention
getMentionOnSelectItem
:- removed
createMentionNode
in favor of plugin options - removed
insertSpaceAfterMention
in favor of plugin options
- removed
@udecode/plate-mention-ui
MentionCombobox
props:- removed
trigger
in favor of plugin options - removed
insertSpaceAfterMention
in favor of plugin options - removed
createMentionNode
in favor of plugin options
- removed
@udecode/plate-x-ui
- renamed
ToolbarAlign
toAlignToolbarButton
- renamed
ToolbarCodeBlock
toCodeBlockToolbarButton
- renamed
ToolbarElement
toBlockToolbarButton
- renamed
ToolbarImage
toImageToolbarButton
- renamed
ToolbarLink
toLinkToolbarButton
- renamed
ToolbarList
toListToolbarButton
- renamed
ToolbarLineHeight
toLineHeightToolbarDropdown
- renamed
ToolbarMark
toMarkToolbarButton
- renamed
ToolbarMediaEmbed
toMediaEmbedToolbarButton
- renamed
ToolbarSearchHighlight
toSearchHighlightToolbar
- renamed
ToolbarTable
toTableToolbarButton
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
,renderElement
anddeserialize
- removed
- removed:
ELEMENT_ALIGN_LEFT
ELEMENT_ALIGN_CENTER
ELEMENT_ALIGN_RIGHT
ELEMENT_ALIGN_JUSTIFY
KEYS_ALIGN
in favor ofKEY_ALIGN
getAlignDeserialize
upsertAlign
in favor ofsetAlign
Migration (normalizer):
- for each node:
- run
parent = getParent(editor, path)
, ifparent[0].type
is one of the alignment values:- run
setAlign(editor, { align }, { at: path })
- run
unwrapNodes(editor, { at: path })
- run
- run
@udecode/plate-alignment-ui
ToolbarAlignProps
:- removed
type
in favor ofalign
- removed
unwrapTypes
- added
align
- removed
5.0.0
@udecode/plate-mention
The mention plugin is now using the combobox.
- removed
useMentionPlugin
in favor ofcreateMentionPlugin
- migration: replace
useMentionPlugin().plugin
bycreateMentionPlugin()
- migration: replace
- removed options:
mentionableSearchPattern
insertSpaceAfterMention
maxSuggestions
: moved tocomboboxStore
trigger
: moved tocomboboxStore
mentionables
: moved toitems
incomboboxStore
mentionableFilter
: moved tofilter
incomboboxStore
- removed
matchesTriggerAndPattern
in favor ofgetTextFromTrigger
- removed
MentionNodeData
in 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
MentionSelect
in favor ofMentionCombobox
@udecode/plate-toolbar
- removed
setPositionAtSelection
in favor ofuseBalloonToolbarPopper
- removed
useBalloonMove
in favor ofuseBalloonToolbarPopper
- removed
usePopupPosition
in favor ofuseBalloonToolbarPopper
- removed
useBalloonShow
in favor ofuseBalloonToolbarPopper
BalloonToolbar
props: - removed
direction
in favor ofpopperOptions.placement
- renamed
scrollContainer
topopperContainer
4.0.0
@udecode/plate-toolbar
BalloonToolbar
: removedhiddenDelay
prop.
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
)
AutoformatRule
is nowAutoformatBlockRule | AutoformatMarkRule | AutoformatTextRule;
mode: 'inline'
renamed tomode: 'mark'
markup
andbetween
have 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. Ifformat
is an array, also lookup for the start match(es). Formode: 'mark'
: lookup for the start and end matches. Note:'_*'
,['_*']
and{ start: '_*', end: '*_' }
are equivalent.trigger
now defaults to the last character ofmatch
ormatch.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