Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.
Releases
@udecode/[email protected]
Major Changes
@udecode/[email protected]
Major Changes
#3920 by @zbeyens – This package is now deprecated and will be renamed to
@udecode/plate
. Migration:@udecode/plate-common
and install@udecode/plate
'@udecode/plate-common'
with'@udecode/plate'
,@udecode/[email protected]
Major Changes
#3920 by @zbeyens –
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: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:
editor.redecorate
toeditor.api.redecorate
Types:
TRenderElementProps
toRenderElementProps
TRenderLeafProps
toRenderLeafProps
TEditableProps
toEditableProps
Minor Changes
#3920 by @zbeyens –
@udecode/plate-core/react
(or@udecode/plate/react
) instead ofslate-react
:RenderPlaceholderProps
,DefaultElement
,DefaultPlaceholder
,Editable
,Slate
,useComposing
,useFocused
,useReadOnly
,useSelected
,withReact
.useNodePath
is now memoized: it will re-render only when the actual path changes (PathApi.equals
). This includesusePath
andpath
element prop.useElementSelector(([node, path]) => selector(node, path), deps, { equalityFn, key })
: re-render only when the selector result changes. We highly recommend using this hook over useElement(key) when subscribing to an ancestor element (e.g. table element from a cell element). For example, subscribe to the row size from a cell element without affecting the re-rendering of all row cells:SlatePlugin.node.isSelectable
. If set tofalse
, the node cannot be selected.tf
andapi
now includeEditor
methods.@udecode/[email protected]
Major Changes
#3920 by @zbeyens – This package is now the new common package, so all plugin packages are being removed. Migration:
@udecode/plate
imports with the individual package imports, or export the following in a new file (e.g.src/plate.ts
):'@udecode/plate'
and'@udecode/plate/react'
with'@/plate'
in your codebase.@udecode/[email protected]
Major Changes
moveSelectionByOffset
,getLastBlockDOMNode
,useLastBlock
,useLastBlockDOMNode
@udecode/[email protected]
Major Changes
@udecode/[email protected]
Major Changes
#3920 by @zbeyens –
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).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
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
isEditor
->editor.api.isEditor
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
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
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
:createZustandStore('name')(initialState)
withcreateZustandStore(initialState, { mutative: true, name: 'name' })
immer
.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
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 throwingNodeOf
type withDescendantOf
ineditor.tf.setNodes
editor.tf.unsetNodes
,editor.api.previous
,editor.api.node
,editor.api.nodes
,editor.api.last
editor.tf.setNodes
:marks
option to handle mark-specific operationsmarks: true
:split: true
andvoids: true
addRangeMarks
functionalityMinor Changes
@udecode/slate-react
and@udecode/slate-utils
queries and transforms into this package.editor.insertNode
: added anoptions
parameter.| TNode
to theat
type of the following methods’ options:editor.api.above
,editor.api.edges
,editor.api.string
,editor.api.end
,editor.api.first
,editor.api.fragment
,editor.api.last
,editor.api.leaf
,editor.api.levels
,editor.api.next
,editor.api.nodes
,editor.api.node
,editor.api.parent
,editor.api.path
,editor.api.point
,editor.api.after
,editor.api.before
,editor.api.positions
,editor.api.previous
,editor.api.range
,editor.api.start
,editor.api.void
,editor.tf.insertNode
,editor.tf.delete
,editor.tf.focus
,editor.tf.insertFragment
,editor.tf.insertNodes
,editor.tf.insertText
,editor.tf.liftNodes
,editor.tf.mergeNodes
,editor.tf.moveNodes
,editor.tf.removeNodes
,editor.tf.select
,editor.tf.setNodes
,editor.tf.splitNodes
,editor.tf.unsetNodes
,editor.tf.unwrapNodes
,editor.tf.wrapNodes
match
query option: Addedtext
andempty
options.id
option to query options for finding nodes by id.text?: boolean
option to match only text nodes.empty?: boolean
option to match only empty nodes.@udecode/[email protected]
Major Changes
@udecode/slate
or@udecode/plate
instead.@udecode/[email protected]
Major Changes
@udecode/slate
or@udecode/plate
instead.@udecode/[email protected]
Major Changes
#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
.enableMerging
todisableMerge
.enableMerging: true
→ remove the option.TablePlugin.configure({ options: { disableMerge: true } })
unmergeTableCells
tosplitTableCell
.editor.api.create.cell
toeditor.api.create.tableCell
.useTableMergeState
, renamedcanUnmerge
tocanSplit
.insertTableRow
andinsertTableColumn
: removeddisableSelect
in favor ofselect
. Migration: replace it with the opposite boolean.getTableCellBorders
: params(element, options)
→(editor, options)
; removedisFirstCell
andisFirstRow
.useTableCellElementState
intouseTableCellElement
:hovered
andhoveredLeft
returns (use CSS instead).rowSize
tominHeight
.width
.useTableCellElementResizableState
intouseTableCellElementResizable
:onHover
andonHoverEnd
props (use CSS instead).useTableElementState
intouseTableElement
:colSizes
,minColumnWidth
, andcolGroupProps
.Minor Changes
#3920 by @zbeyens –
TablePlugin
new api and transforms:insertTableColumn
addbefore
option to insert a column before the current column.insertTableRow
addbefore
option to insert a row before the current row.insertTable
now supports inserting a table after the current table.@udecode/[email protected]
Patch Changes
useMemoizedSelector
, which re-renders only when the selector’s result changes.@udecode/[email protected]
Patch Changes
Nullable
type@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]