Skip to content

Commit

Permalink
chore: add shouldMergeNodesRemovePrevNode (#5621)
Browse files Browse the repository at this point in the history
* chore: add shouldMergeNodesRemovePrevNode

* fix: typo
  • Loading branch information
felixfeng33 authored Apr 1, 2024
1 parent 4470f37 commit d271c4b
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-mayflies-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'slate': minor
---

Add a `shouldMergeNodesRemovePrevNode` editor method to control when `Transforms.mergeNodes` should remove the previous node rather than carrying out a merge operation.
3 changes: 3 additions & 0 deletions packages/slate/src/create-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import {
rangeRef,
rangeRefs,
setNormalizing,
shouldMergeNodesRemovePrevNode,
start,
string,
unhangRange,
Expand Down Expand Up @@ -181,6 +182,8 @@ export const createEditor = (): Editor => {
void: (...args) => getVoid(editor, ...args),
withoutNormalizing: (...args) => withoutNormalizing(editor, ...args),
wrapNodes: (...args) => wrapNodes(editor, ...args),
shouldMergeNodesRemovePrevNode: (...args) =>
shouldMergeNodesRemovePrevNode(editor, ...args),
}

return editor
Expand Down
1 change: 1 addition & 0 deletions packages/slate/src/editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ export * from './start'
export * from './string'
export * from './unhang-range'
export * from './without-normalizing'
export * from './should-merge-nodes-remove-prev-node'
17 changes: 17 additions & 0 deletions packages/slate/src/editor/should-merge-nodes-remove-prev-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { EditorInterface, Element, Editor, Text } from '../interfaces'

export const shouldMergeNodesRemovePrevNode: EditorInterface['shouldMergeNodesRemovePrevNode'] =
(editor, [prevNode, prevPath], [curNode, curNodePath]) => {
// If the target node that we're merging with is empty, remove it instead
// of merging the two. This is a common rich text editor behavior to
// prevent losing formatting when deleting entire nodes when you have a
// hanging selection.
// if prevNode is first child in parent,don't remove it.

return (
(Element.isElement(prevNode) && Editor.isEmpty(editor, prevNode)) ||
(Text.isText(prevNode) &&
prevNode.text === '' &&
prevPath[prevPath.length - 1] !== 0)
)
}
15 changes: 15 additions & 0 deletions packages/slate/src/interfaces/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ export interface BaseEditor {
string: OmitFirstArg<typeof Editor.string>
unhangRange: OmitFirstArg<typeof Editor.unhangRange>
void: OmitFirstArg<typeof Editor.void>
shouldMergeNodesRemovePrevNode: OmitFirstArg<
typeof Editor.shouldMergeNodesRemovePrevNode
>
}

export type Editor = ExtendedType<'Editor', BaseEditor>
Expand Down Expand Up @@ -709,6 +712,15 @@ export interface EditorInterface {
* Call a function, deferring normalization until after it completes.
*/
withoutNormalizing: (editor: Editor, fn: () => void) => void

/**
* Call a function, Determine whether or not remove the previous node when merge.
*/
shouldMergeNodesRemovePrevNode: (
editor: Editor,
prevNodeEntry: NodeEntry,
curNodeEntry: NodeEntry
) => boolean
}

// eslint-disable-next-line no-redeclare
Expand Down Expand Up @@ -953,6 +965,9 @@ export const Editor: EditorInterface = {
withoutNormalizing(editor, fn: () => void) {
editor.withoutNormalizing(fn)
},
shouldMergeNodesRemovePrevNode: (editor, prevNode, curNode) => {
return editor.shouldMergeNodesRemovePrevNode(prevNode, curNode)
},
}

/**
Expand Down
12 changes: 1 addition & 11 deletions packages/slate/src/transforms-node/merge-nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,17 +128,7 @@ export const mergeNodes: NodeTransforms['mergeNodes'] = (
Transforms.removeNodes(editor, { at: emptyRef.current!, voids })
}

// If the target node that we're merging with is empty, remove it instead
// of merging the two. This is a common rich text editor behavior to
// prevent losing formatting when deleting entire nodes when you have a
// hanging selection.
// if prevNode is first child in parent,don't remove it.
if (
(Element.isElement(prevNode) && Editor.isEmpty(editor, prevNode)) ||
(Text.isText(prevNode) &&
prevNode.text === '' &&
prevPath[prevPath.length - 1] !== 0)
) {
if (Editor.shouldMergeNodesRemovePrevNode(editor, prev, current)) {
Transforms.removeNodes(editor, { at: prevPath, voids })
} else {
editor.apply({
Expand Down

0 comments on commit d271c4b

Please sign in to comment.