1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-26 08:34:28 +02:00

Add way to prevent data loss in normalizeNode (#5878)

* fix(docs): Consider passed options when overriding normalizeNode

* feat: Allow to prevent data-loss on normalizeNode

When overriding normalizeNode, you can specify a `wrapperElement`
that is used to wrap text & inline nodes which would otherwise be
deleted in the normalization path if they are not allowed.

* changeset
This commit is contained in:
Alex
2025-05-24 22:53:02 +02:00
committed by GitHub
parent ffe3f8c129
commit 11b957a441
11 changed files with 128 additions and 16 deletions

View File

@@ -7,7 +7,8 @@ import { Editor } from '../interfaces/editor'
export const normalizeNode: WithEditorFirstArg<Editor['normalizeNode']> = (
editor,
entry
entry,
options
) => {
const [node, path] = entry
@@ -54,7 +55,14 @@ export const normalizeNode: WithEditorFirstArg<Editor['normalizeNode']> = (
// text.
if (isInlineOrText !== shouldHaveInlines) {
if (isInlineOrText) {
Transforms.removeNodes(editor, { at: path.concat(n), voids: true })
if (options?.fallbackElement) {
Transforms.wrapNodes(editor, options.fallbackElement(), {
at: path.concat(n),
voids: true,
})
} else {
Transforms.removeNodes(editor, { at: path.concat(n), voids: true })
}
} else {
Transforms.unwrapNodes(editor, { at: path.concat(n), voids: true })
}

View File

@@ -54,7 +54,13 @@ export interface BaseEditor {
isElementReadOnly: (element: Element) => boolean
isSelectable: (element: Element) => boolean
markableVoid: (element: Element) => boolean
normalizeNode: (entry: NodeEntry, options?: { operation?: Operation }) => void
normalizeNode: (
entry: NodeEntry,
options?: {
operation?: Operation
fallbackElement?: () => Element
}
) => void
onChange: (options?: { operation?: Operation }) => void
shouldNormalize: ({
iteration,

View File

@@ -25,8 +25,14 @@ describe('slate', () => {
assert.deepEqual(editor.selection, output.selection)
})
fixtures(__dirname, 'normalization', ({ module }) => {
const { input, output } = module
const { input, output, withFallbackElement } = module
const editor = withTest(input)
if (withFallbackElement) {
const { normalizeNode } = editor
editor.normalizeNode = (entry, options) => {
normalizeNode(entry, { ...options, fallbackElement: () => ({}) })
}
}
Editor.normalize(editor, { force: true })
assert.deepEqual(editor.children, output.children)
assert.deepEqual(editor.selection, output.selection)

View File

@@ -0,0 +1,33 @@
/** @jsx jsx */
import { jsx } from '../..'
export const withFallbackElement = true
export const input = (
<editor>
<block>
<block>one</block>
<inline>two</inline>
<block>three</block>
<inline>four</inline>
</block>
</editor>
)
export const output = (
<editor>
<block>
<block>one</block>
<block>
<text />
<inline>two</inline>
<text />
</block>
<block>three</block>
<block>
<text />
<inline>four</inline>
<text />
</block>
</block>
</editor>
)

View File

@@ -0,0 +1,29 @@
/** @jsx jsx */
import { jsx } from '../..'
export const withFallbackElement = true
export const input = (
<editor>
<inline>one</inline>
<block>two</block>
<inline>three</inline>
<block>four</block>
</editor>
)
export const output = (
<editor>
<block>
<text />
<inline>one</inline>
<text />
</block>
<block>two</block>
<block>
<text />
<inline>three</inline>
<text />
</block>
<block>four</block>
</editor>
)

View File

@@ -0,0 +1,25 @@
/** @jsx jsx */
import { jsx } from '../..'
export const withFallbackElement = true
export const input = (
<editor>
<text>one</text>
<block>two</block>
<text>three</text>
<block>four</block>
</editor>
)
export const output = (
<editor>
<block>
<text>one</text>
</block>
<block>two</block>
<block>
<text>three</text>
</block>
<block>four</block>
</editor>
)