Major Changes
-
- Remove
slate,slate-dom,slate-react,slate-historyandslate-hyperscriptfrom your dependencies. It's now part of this package and@udecode/plate. All exports remain the same or have equivalents (see below). - Renamed
createTEditortocreateEditor. createEditornow returns an editor (Editor) with all queries undereditor.apiand transforms undereditor.tf. You can see or override them at a glance. For example, we now useeditor.tf.setNodesinstead of importingsetNodes. This marks the completion of generic typing and the removal of error throws fromslate,slate-dom, andslate-historyqueries/transforms, without forking implementations. We’ve also reduced the number of queries/transforms by merging a bunch of them.
The following interfaces from
slateandslate-domare now part ofEditor:-
Editor,EditorInterface -
Transforms -
HistoryEditor(noop, unchanged),HistoryEditorInterface -
DOMEditor(noop, unchanged),DOMEditorInterface -
editor.findPathnow returnsDOMEditor.findPath(memo) and falls back tofindNodePath(traversal, less performant) if not found. -
Removed the first parameter (
editor) from:editor.hasEditableTargeteditor.hasSelectableTargeteditor.isTargetInsideNonReadonlyVoideditor.hasRangeeditor.hasTarget
-
editor.api.node(options)(previouslyfindNode)atoption is nowat ?? editor.selectioninstead ofat ?? editor.selection ?? []. That means if you want to lookup the entire document, you need to pass[]explicitly. -
Removed
setNodein favor ofsetNodes(you can now pass aTNodetoatdirectly). -
Removed
setElementsin favor ofsetNodes. -
Removed unused
isWordAfterTrigger,setBlockAboveNode,setBlockAboveTexts,setBlockNodes,getPointNextToVoid. -
Replaced
Pathfrom slate withPath(type) andPathApi(static methods). -
Replaced
Operationfrom slate withOperation(type) andOperationApi(static methods). -
Replaced
Pointfrom slate withPoint(type) andPointApi(static methods). -
Replaced
Textfrom slate withTText(type) andTextApi(static methods). We also exportTexttype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Replaced
Rangefrom slate withTRange(type) andRangeApi(static methods). We also exportRangetype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Replaced
Locationfrom slate withTLocation(type) andLocationApi(static methods). We also exportLocationtype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Replaced
Spanfrom slate withSpan(type) andSpanApi(static methods). -
Replaced
Nodefrom slate withTNode(type) andNodeApi(static methods). We also exportNodetype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Replaced
Elementfrom slate withTElement(type) andElementApi(static methods). We also exportElementtype likeslatebut we don't recommend it as it's conflicting with the DOM type. -
Signature change:
editor.tf.toggle.block({ type, ...options })->editor.tf.toggleBlock(type, options)editor.tf.toggle.mark({ key, clear })->editor.tf.toggleMark(key, { remove: clear })
-
Moved editor functions:
addMark->editor.tf.addMarkaddRangeMarks->editor.tf.setNodes(props, { at, marks: true })blurEditor->editor.tf.blurcollapseSelection->editor.tf.collapsecreateDocumentNode->editor.api.create.value(core)createNode->editor.api.create.blockcreatePathRef->editor.api.pathRefcreatePointRef->editor.api.pointRefcreateRangeRef->editor.api.rangeRefdeleteBackward({ unit })->editor.tf.deleteBackward(unit)deleteForward({ unit })->editor.tf.deleteForward(unit)deleteFragment->editor.tf.deleteFragmentdeleteText->editor.tf.deletedeselect->editor.tf.deselectdeselectEditor->editor.tf.deselectDOMduplicateBlocks->editor.tf.duplicateNodes({ nodes })findDescendant->editor.api.descendantfindEditorDocumentOrShadowRoot->editor.api.findDocumentOrShadowRootfindEventRange->editor.api.findEventRangefindNode(options)->editor.api.node(options)findNodeKey->editor.api.findKeyfindNodePath->editor.api.findPathfindPath->editor.api.findPathfocusEditor->editor.tf.focus({ at })focusEditorEdge->editor.tf.focus({ at, edge: 'startEditor' | 'endEditor' })getAboveNode->editor.api.abovegetAncestorNode->editor.api.block({ highest: true })getBlockAbove->editor.api.block({ at, above: true })oreditor.api.block()ifatis not a pathgetBlocks->editor.api.blocksgetEdgeBlocksAbove->editor.api.edgeBlocksgetEdgePoints->editor.api.edgesgetEditorString->editor.api.stringgetEditorWindow->editor.api.getWindowgetEndPoint->editor.api.endgetFirstNode->editor.api.firstgetFragment->editor.api.fragmentgetFragmentProp(fragment, options)->editor.api.prop({ nodes, ...options})getLastNode->editor.api.lastgetLastNodeByLevel(level)->editor.api.last([], { level })getLeafNode->editor.api.leafgetLevels->editor.api.levelsgetMark->editor.api.markgetMarks->editor.api.marksgetNextNode->editor.api.nextgetNextNodeStartPoint->editor.api.start(at, { next: true })getNodeEntries->editor.api.nodesgetNodeEntry->editor.api.node(at, options)getNodesRange->editor.api.nodesRangegetParentNode->editor.api.parentgetPath->editor.api.pathgetPathRefs->editor.api.pathRefsgetPoint->editor.api.pointgetPointAfter->editor.api.aftergetPointBefore->editor.api.beforegetPointBeforeLocation->editor.api.beforegetPointRefs->editor.api.pointRefsgetPositions->editor.api.positionsgetPreviousBlockById->editor.api.previous({ id, block: true })getPreviousNode->editor.api.previousgetPreviousNodeEndPoint->editor.api.end({ previous: true })getPreviousSiblingNode->editor.api.previous({ at, sibling: true })getRange->editor.api.rangegetRangeBefore->editor.api.range('before', to, { before })getRangeFromBlockStart->editor.api.range('start', to)getRangeRefs->editor.api.rangeRefsgetSelectionFragment->editor.api.fragment(editor.selection, { structuralTypes })getSelectionText->editor.api.string()getStartPoint->editor.api.startgetVoidNode->editor.api.voidhasBlocks->editor.api.hasBlockshasEditorDOMNode->editor.api.hasDOMNodehasEditorEditableTarget->editor.api.hasEditableTargethasEditorSelectableTarget->editor.api.hasSelectableTargethasEditorTarget->editor.api.hasTargethasInlines->editor.api.hasInlineshasTexts->editor.api.hasTextsinsertBreak->editor.tf.insertBreakinsertData->editor.tf.insertDatainsertElements->editor.tf.insertNodes<TElement>insertEmptyElement->editor.tf.insertNodes(editor.api.create.block({ type }))insertFragment->editor.tf.insertFragmentinsertNode->editor.tf.insertNodeinsertNodes->editor.tf.insertNodesinsertText->editor.tf.insertTextisAncestorEmpty->editor.api.isEmptyisBlock->editor.api.isBlockisBlockAboveEmpty->editor.api.isEmpty(editor.selection, { block: true })isBlockTextEmptyAfterSelection->editor.api.isEmpty(editor.selection, { after: true })isCollapsed(editor.selection)->editor.api.isCollapsed()isComposing->editor.api.isComposingisDocumentEnd->editor.api.isEditorEndisEdgePoint->editor.api.isEdgeisEditor->editor.api.isEditorisEditorEmpty->editor.api.isEmpty()isEditorFocused->editor.api.isFocusedisEditorNormalizing->editor.api.isNormalizingisEditorReadOnly->editor.api.isReadOnlyisElementEmpty->editor.api.isEmptyisElementReadOnly->editor.api.elementReadOnlyisEndPoint->editor.api.isEndisExpanded(editor.selection)->editor.api.isCollapsed()isInline->editor.api.isInlineisMarkableVoid->editor.api.markableVoidisMarkActive->editor.api.hasMark(key)isPointAtWordEnd->editor.api.isAt({ at, word: true, end: true })isRangeAcrossBlocks->editor.api.isAt({ at, blocks: true })isRangeInSameBlock->editor.api.isAt({ at, block: true })isRangeInSingleText->editor.api.isAt({ at, text: true })isSelectionAtBlockEnd->editor.api.isAt({ end: true })isSelectionAtBlockStart->editor.api.isAt({ start: true })isSelectionCoverBlock->editor.api.isAt({ block: true, start: true, end: true })isSelectionExpanded->editor.api.isExpanded()isStartPoint->editor.api.isStartisTargetinsideNonReadonlyVoidEditor->editor.api.isTargetInsideNonReadonlyVoidisTextByPath->editor.api.isText(at)isVoid->editor.api.isVoidliftNodes->editor.tf.liftNodesmergeNodes->editor.tf.mergeNodesmoveChildren->editor.tf.moveNodes({ at, to, children: true, fromIndex, match: (node, path) => boolean })moveNodes->editor.tf.moveNodesmoveSelection->editor.tf.movenormalizeEditor->editor.tf.normalizeremoveEditorMark->editor.tf.removeMarkremoveEditorText->editor.tf.removeNodes({ text: true, empty: false })removeEmptyPreviousBlock->editor.tf.removeNodes({ previousEmptyBlock: true })removeMark(options)->editor.tf.removeMarks(keys, options)removeNodeChildren->editor.tf.removeNodes({ at, children: true })removeNodes->editor.tf.removeNodesremoveSelectionMark->editor.tf.removeMarks()replaceNode(editor, { nodes, insertOptions, removeOptions })->editor.tf.replaceNodes(nodes, { removeNodes, ...insertOptions })select->editor.tf.selectselectEndOfBlockAboveSelection->editor.tf.select(editor.selection, { edge: 'end' })selectNodes->editor.tf.select(editor.api.nodesRange(nodes))setFragmentData->editor.tf.setFragmentDatasetMarks(marks, clear)->editor.tf.addMarks(marks, { remove: string | string[] })setNodes->editor.tf.setNodessetPoint->editor.tf.setPointsetSelection->editor.tf.setSelectionsomeNode->editor.api.some(options)splitNodes->editor.tf.splitNodestoDOMNode->editor.api.toDOMNodetoDOMPoint->editor.api.toDOMPointtoDOMRange->editor.api.toDOMRangetoggleWrapNodes->editor.tf.toggleBlock(type, { wrap: true })toSlateNode->editor.api.toSlateNodetoSlatePoint->editor.api.toSlatePointtoSlateRange->editor.api.toSlateRangeunhangCharacterRange->editor.api.unhangRange(range, { character: true })unhangRange->editor.api.unhangRangeunsetNodes->editor.tf.unsetNodesunwrapNodes->editor.tf.unwrapNodeswithoutNormalizing->editor.tf.withoutNormalizingwrapNodeChildren->editor.tf.wrapNodes(element, { children: true })wrapNodes->editor.tf.wrapNodesresetEditor->editor.tf.resetresetEditorChildren->editor.tf.reset({ children: true })selectEditor->editor.tf.select([], { focus, edge })selectSiblingNodePoint->editor.tf.select(at, { next, previous })
-
Moved to
NodeApi.:getNextSiblingNodes(parentEntry, path)->NodeApi.children(editor, path, { from: path.at(-1) + 1 })getFirstNodeText->NodeApi.firstTextgetFirstChild([node, path])->NodeApi.firstChild(editor, path)getLastChild([node, path])->NodeApi.lastChild(editor, path)getLastChildPath([node, path])->NodeApi.lastChild(editor, path)isLastChild([node, path], childPath)->NodeApi.isLastChild(editor, childPath)getChildren([node, path])->Array.from(NodeApi.children(editor, path))getCommonNode->NodeApi.commongetNode->NodeApi.getgetNodeAncestor->NodeApi.ancestorgetNodeAncestors->NodeApi.ancestorsgetNodeChild->NodeApi.childgetNodeChildren->NodeApi.childrengetNodeDescendant->NodeApi.descendantgetNodeDescendants->NodeApi.descendantsgetNodeElements->NodeApi.elementsgetNodeFirstNode->NodeApi.firstgetNodeFragment->NodeApi.fragmentgetNodeLastNode->NodeApi.lastgetNodeLeaf->NodeApi.leafgetNodeLevels->NodeApi.levelsgetNodeParent->NodeApi.parentgetNodeProps->NodeApi.extractPropsgetNodes->NodeApi.nodesgetNodeString->NodeApi.stringgetNodeTexts->NodeApi.textshasNode->NodeApi.hashasSingleChild->NodeApi.hasSingleChildisAncestor->NodeApi.isAncestorisDescendant->NodeApi.isDescendantisNode->NodeApi.isNodeisNodeList->NodeApi.isNodeListnodeMatches->NodeApi.matches
-
Moved to
ElementApi.:elementMatches->ElementApi.matchesisElement->ElementApi.isElementisElementList->ElementApi.isElementList
-
Moved to
TextApi.:isText->TextApi.isText(at)
-
Moved to
RangeApi.:isCollapsed->RangeApi.isCollapsedisExpanded->RangeApi.isExpanded
-
Moved to
PathApi.:isFirstChild->!PathApi.hasPreviousgetPreviousPath->PathApi.previous
-
Moved to
PointApi.:getPointFromLocation({ at, focus })->PointApi.get(at, { focus })
-
Moved from
@udecode/plate/reactto@udecode/plate:Hotkeys
-
Upgraded to
zustand@5andzustand-x@5:- Replace
createZustandStore('name')(initialState)withcreateZustandStore(initialState, { mutative: true, name: 'name' }) - All plugin stores now use zustand-mutative for immutable state updates, which is faster than
immer.
- Replace
Types:
- Rename the following types:
TEditor->EditorTOperation->OperationTPath->PathTNodeProps->NodePropsTNodeChildEntry->NodeChildEntryTNodeEntry->NodeEntryTDescendant->DescendantTDescendantEntry->DescendantEntryTAncestor->AncestorTAncestorEntry->AncestorEntryTElementEntry->ElementEntryTTextEntry->TextEntry
- Query/transform options now use generic
V extends Valueinstead ofE extends Editor. getEndPoint,getEdgePoints,getFirstNode,getFragment,getLastNode,getLeafNode,getPath,getPoint,getStartPointcan returnundefinedif not found (suppressing error throws).NodeApi.ancestor,NodeApi.child,NodeApi.common,NodeApi.descendant,NodeApi.first,NodeApi.get,NodeApi.last,NodeApi.leaf,NodeApi.parent,NodeApi.getIf,PathApi.previousreturnundefinedif not found instead of throwing- Replace
NodeOftype withDescendantOfineditor.tf.setNodeseditor.tf.unsetNodes,editor.api.previous,editor.api.node,editor.api.nodes,editor.api.last - Enhanced
editor.tf.setNodes:- Added
marksoption to handle mark-specific operations - When
marks: true:- Only applies to text nodes in non-void nodes or markable void nodes
- Automatically sets
split: trueandvoids: true - Handles both expanded ranges and collapsed selections in markable voids
- Replaces
addRangeMarksfunctionality
- Added
- Remove
Minor Changes
- #3920 by @zbeyens –
- Merged
@udecode/slate-reactand@udecode/slate-utilsqueries and transforms into this package. editor.insertNode: added anoptionsparameter.- Added
| TNodeto theattype 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 matchquery option: Addedtextandemptyoptions.- Added
idoption to query options for finding nodes by id. - Added
text?: booleanoption to match only text nodes. - Added
empty?: booleanoption to match only empty nodes.
- Added
- Merged