@portabletext/editor 2.1.11 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { Behavior, Editor, EditorEmittedEvent, EditorSchema } from "../_chunks-dts/behavior.types.action.cjs";
2
- import * as react12 from "react";
2
+ import * as react21 from "react";
3
3
  import React from "react";
4
4
  /**
5
5
  * @beta
@@ -181,7 +181,7 @@ type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
181
181
  */
182
182
  declare function MarkdownPlugin(props: {
183
183
  config: MarkdownPluginConfig;
184
- }): react12.JSX.Element;
184
+ }): react21.JSX.Element;
185
185
  /**
186
186
  * @beta
187
187
  * Restrict the editor to one line. The plugin takes care of blocking
@@ -192,5 +192,5 @@ declare function MarkdownPlugin(props: {
192
192
  *
193
193
  * @deprecated Install the plugin from `@portabletext/plugin-one-line`
194
194
  */
195
- declare function OneLinePlugin(): react12.JSX.Element;
195
+ declare function OneLinePlugin(): react21.JSX.Element;
196
196
  export { BehaviorPlugin, DecoratorShortcutPlugin, EditorRefPlugin, EventListenerPlugin, MarkdownPlugin, type MarkdownPluginConfig, OneLinePlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "2.1.11",
3
+ "version": "2.2.0",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -80,8 +80,8 @@
80
80
  "slate-react": "0.117.4",
81
81
  "xstate": "^5.20.2",
82
82
  "@portabletext/block-tools": "2.0.8",
83
- "@portabletext/patches": "1.1.6",
84
- "@portabletext/keyboard-shortcuts": "1.1.1"
83
+ "@portabletext/keyboard-shortcuts": "1.1.1",
84
+ "@portabletext/patches": "1.1.6"
85
85
  },
86
86
  "devDependencies": {
87
87
  "@portabletext/toolkit": "^2.0.17",
@@ -56,6 +56,79 @@ export const abstractSplitBehaviors = [
56
56
  actions: [(_, {selection}) => [raise({type: 'delete', at: selection})]],
57
57
  }),
58
58
 
59
+ defineBehavior({
60
+ on: 'split',
61
+ guard: ({snapshot}) => {
62
+ const selection = snapshot.context.selection
63
+
64
+ if (!selection || utils.isSelectionCollapsed(selection)) {
65
+ return false
66
+ }
67
+
68
+ const selectionStartBlock = selectors.getSelectionStartBlock(snapshot)
69
+ const selectionEndBlock = selectors.getSelectionEndBlock(snapshot)
70
+
71
+ if (!selectionStartBlock || !selectionEndBlock) {
72
+ return false
73
+ }
74
+
75
+ if (selectionStartBlock.node._key === selectionEndBlock.node._key) {
76
+ return false
77
+ }
78
+
79
+ const startPoint = utils.getSelectionStartPoint(selection)
80
+ const startBlockEndPoint = utils.getBlockEndPoint({
81
+ context: snapshot.context,
82
+ block: selectionStartBlock,
83
+ })
84
+ const endPoint = utils.getSelectionEndPoint(selection)
85
+ const endBlockStartPoint = utils.getBlockStartPoint({
86
+ context: snapshot.context,
87
+ block: selectionEndBlock,
88
+ })
89
+
90
+ const selectedValue = selectors.getSelectedValue(snapshot)
91
+
92
+ const blocksInBetween = selectedValue.filter(
93
+ (block) =>
94
+ block._key !== selectionStartBlock.node._key &&
95
+ block._key !== selectionEndBlock.node._key,
96
+ )
97
+
98
+ return {
99
+ startPoint,
100
+ startBlockEndPoint,
101
+ endPoint,
102
+ endBlockStartPoint,
103
+ blocksInBetween,
104
+ }
105
+ },
106
+ actions: [
107
+ (
108
+ _,
109
+ {
110
+ startPoint,
111
+ startBlockEndPoint,
112
+ endPoint,
113
+ endBlockStartPoint,
114
+ blocksInBetween,
115
+ },
116
+ ) => [
117
+ raise({
118
+ type: 'delete',
119
+ at: {anchor: startPoint, focus: startBlockEndPoint},
120
+ }),
121
+ ...blocksInBetween.map((block) =>
122
+ raise({type: 'delete.block', at: [{_key: block._key}]}),
123
+ ),
124
+ raise({
125
+ type: 'delete',
126
+ at: {anchor: endBlockStartPoint, focus: endPoint},
127
+ }),
128
+ ],
129
+ ],
130
+ }),
131
+
59
132
  defineBehavior({
60
133
  on: 'split',
61
134
  guard: ({snapshot}) => {
@@ -111,7 +184,10 @@ export const abstractSplitBehaviors = [
111
184
  block: focusTextBlock.node,
112
185
  }),
113
186
  context: snapshot.context,
114
- options: {refreshKeys: true, validateFields: true},
187
+ options: {
188
+ refreshKeys: false,
189
+ validateFields: false,
190
+ },
115
191
  })
116
192
 
117
193
  if (!newTextBlock) {
@@ -159,7 +159,7 @@ describe(converterPortableText.deserialize, () => {
159
159
  ).toMatchObject({
160
160
  data: [
161
161
  {
162
- _key: 'k0',
162
+ _key: 'b2',
163
163
  _type: 'image',
164
164
  src: 'https://example.com/image.jpg',
165
165
  },
@@ -573,7 +573,7 @@ describe(converterPortableText.deserialize, () => {
573
573
  {
574
574
  _type: 'span',
575
575
  text: 'foo',
576
- marks: ['k1'],
576
+ marks: ['b0m0'],
577
577
  },
578
578
  {
579
579
  _type: 'span',
@@ -583,7 +583,7 @@ describe(converterPortableText.deserialize, () => {
583
583
  ],
584
584
  markDefs: [
585
585
  {
586
- _key: 'k1',
586
+ _key: 'b0m0',
587
587
  _type: 'link',
588
588
  href: 'https://example.com',
589
589
  },
@@ -50,7 +50,7 @@ export const converterPortableText = defineConverter({
50
50
  context: snapshot.context,
51
51
  block,
52
52
  options: {
53
- refreshKeys: true,
53
+ refreshKeys: false,
54
54
  validateFields: false,
55
55
  },
56
56
  })
@@ -62,7 +62,7 @@ export function createConverterTextHtml(
62
62
  block,
63
63
  options: {
64
64
  refreshKeys: false,
65
- validateFields: true,
65
+ validateFields: false,
66
66
  },
67
67
  })
68
68
  return parsedBlock ? [parsedBlock] : []
@@ -85,7 +85,7 @@ export function createConverterTextPlain(
85
85
  block,
86
86
  options: {
87
87
  refreshKeys: false,
88
- validateFields: true,
88
+ validateFields: false,
89
89
  },
90
90
  })
91
91
  return parsedBlock ? [parsedBlock] : []
@@ -474,8 +474,8 @@ export const PortableTextEditable = forwardRef<
474
474
  },
475
475
  blocks: result.insert,
476
476
  options: {
477
- refreshKeys: true,
478
- validateFields: true,
477
+ refreshKeys: false,
478
+ validateFields: false,
479
479
  },
480
480
  }),
481
481
  placement: 'auto',
@@ -191,57 +191,51 @@ describe('plugin:withPortableTextMarksModel', () => {
191
191
  await waitFor(() => {
192
192
  PortableTextEditor.select(editor, sel)
193
193
  PortableTextEditor.delete(editor, sel)
194
- expect(PortableTextEditor.getValue(editor)).toMatchInlineSnapshot(`
195
- [
194
+ expect(PortableTextEditor.getValue(editor)).toEqual([
196
195
  {
197
- "_key": "5fc57af23597",
198
- "_type": "myTestBlockType",
199
- "children": [
196
+ _key: '5fc57af23597',
197
+ _type: 'myTestBlockType',
198
+ children: [
200
199
  {
201
- "_key": "be1c67c6971a",
202
- "_type": "span",
203
- "marks": [],
204
- "text": "This is a ",
200
+ _key: 'be1c67c6971a',
201
+ _type: 'span',
202
+ marks: [],
203
+ text: 'This is a ',
205
204
  },
206
205
  {
207
- "_key": "11c8c9f783a8",
208
- "_type": "span",
209
- "marks": [
210
- "fde1fd54b544",
211
- ],
212
- "text": "link",
206
+ _key: '11c8c9f783a8',
207
+ _type: 'span',
208
+ marks: ['fde1fd54b544'],
209
+ text: 'link',
213
210
  },
214
211
  {
215
- "_key": "576c748e0cd2",
216
- "_type": "span",
217
- "marks": [],
218
- "text": "This is ",
212
+ _key: '576c748e0cd2',
213
+ _type: 'span',
214
+ marks: [],
215
+ text: 'This is ',
219
216
  },
220
217
  {
221
- "_key": "f3d73d3833bf",
222
- "_type": "span",
223
- "marks": [
224
- "7b6d3d5de30c",
225
- ],
226
- "text": "another",
218
+ _key: 'f3d73d3833bf',
219
+ _type: 'span',
220
+ marks: ['7b6d3d5de30c'],
221
+ text: 'another',
227
222
  },
228
223
  ],
229
- "markDefs": [
224
+ markDefs: [
230
225
  {
231
- "_key": "fde1fd54b544",
232
- "_type": "link",
233
- "url": "1",
226
+ _key: 'fde1fd54b544',
227
+ _type: 'link',
228
+ url: '1',
234
229
  },
235
230
  {
236
- "_key": "7b6d3d5de30c",
237
- "_type": "link",
238
- "url": "2",
231
+ _key: '7b6d3d5de30c',
232
+ _type: 'link',
233
+ url: '2',
239
234
  },
240
235
  ],
241
- "style": "normal",
236
+ style: 'normal',
242
237
  },
243
- ]
244
- `)
238
+ ])
245
239
  })
246
240
  })
247
241
 
@@ -1,4 +1,6 @@
1
- import {Editor, Element, Node, Transforms} from 'slate'
1
+ import {isEqual} from 'lodash'
2
+ import {Editor, Element, Node, Path, Transforms} from 'slate'
3
+ import {isSpan, isTextBlock} from '../../internal-utils/parse-blocks'
2
4
  import {isChangingRemotely} from '../../internal-utils/withChanges'
3
5
  import {isRedoing, isUndoing} from '../../internal-utils/withUndoRedo'
4
6
  import type {PortableTextSlateEditor} from '../../types/editor'
@@ -78,6 +80,113 @@ export function createWithObjectKeys(editorActor: EditorActor) {
78
80
  }
79
81
  }
80
82
 
83
+ if (operation.type === 'merge_node') {
84
+ const index = operation.path[operation.path.length - 1]
85
+ const prevPath = Path.previous(operation.path)
86
+ const prevIndex = prevPath[prevPath.length - 1]
87
+
88
+ if (operation.path.length !== 1 || prevPath.length !== 1) {
89
+ apply(operation)
90
+ return
91
+ }
92
+
93
+ const block = editor.value.at(index)
94
+ const previousBlock = editor.value.at(prevIndex)
95
+
96
+ if (!block || !previousBlock) {
97
+ apply(operation)
98
+ return
99
+ }
100
+
101
+ if (
102
+ !isTextBlock(editorActor.getSnapshot().context, block) ||
103
+ !isTextBlock(editorActor.getSnapshot().context, previousBlock)
104
+ ) {
105
+ apply(operation)
106
+ return
107
+ }
108
+
109
+ // If we are merging two text blocks, then we need to make sure there
110
+ // are no duplicate keys in the blocks. Therefore, we assign new keys
111
+ // to any child or markDef that shares key with other children or
112
+ // markDefs in the previous block.
113
+ const previousBlockChildKeys = previousBlock.children.map(
114
+ (child) => child._key,
115
+ )
116
+ const previousBlockMarkDefKeys =
117
+ previousBlock.markDefs?.map((markDef) => markDef._key) ?? []
118
+
119
+ // Assign new keys to markDefs with duplicate keys and keep track of
120
+ // the mapping between the old and new keys
121
+ const markDefKeyMap = new Map<string, string>()
122
+ const adjustedMarkDefs = block.markDefs?.map((markDef) => {
123
+ if (previousBlockMarkDefKeys.includes(markDef._key)) {
124
+ const newKey = editorActor.getSnapshot().context.keyGenerator()
125
+ markDefKeyMap.set(markDef._key, newKey)
126
+ return {
127
+ ...markDef,
128
+ _key: newKey,
129
+ }
130
+ }
131
+
132
+ return markDef
133
+ })
134
+
135
+ // Assign new keys to spans with duplicate keys and update any markDef
136
+ // key if needed
137
+ let childIndex = 0
138
+ for (const child of block.children) {
139
+ if (isSpan(editorActor.getSnapshot().context, child)) {
140
+ const marks =
141
+ child.marks?.map((mark) => {
142
+ const markDefKey = markDefKeyMap.get(mark)
143
+
144
+ if (markDefKey) {
145
+ return markDefKey
146
+ }
147
+
148
+ return mark
149
+ }) ?? []
150
+
151
+ if (!isEqual(child.marks, marks)) {
152
+ Transforms.setNodes(
153
+ editor,
154
+ {
155
+ marks,
156
+ },
157
+ {
158
+ at: [index, childIndex],
159
+ },
160
+ )
161
+ }
162
+ }
163
+
164
+ if (previousBlockChildKeys.includes(child._key)) {
165
+ Transforms.setNodes(
166
+ editor,
167
+ {
168
+ _key: editorActor.getSnapshot().context.keyGenerator(),
169
+ },
170
+ {
171
+ at: [index, childIndex],
172
+ },
173
+ )
174
+ }
175
+ childIndex++
176
+ }
177
+
178
+ apply({
179
+ ...operation,
180
+ properties: {
181
+ ...operation.properties,
182
+ // Make sure the adjusted markDefs are carried along for the merge
183
+ // operation
184
+ markDefs: adjustedMarkDefs,
185
+ },
186
+ })
187
+ return
188
+ }
189
+
81
190
  apply(operation)
82
191
  }
83
192
 
@@ -24,6 +24,7 @@ export async function createTestEditor(
24
24
  initialValue?: Array<PortableTextBlock>
25
25
  keyGenerator?: () => string
26
26
  schemaDefinition?: SchemaDefinition
27
+ children?: React.ReactNode
27
28
  } = {},
28
29
  ) {
29
30
  const editorRef = React.createRef<Editor>()
@@ -45,6 +46,7 @@ export async function createTestEditor(
45
46
  <InternalSlateEditorRefPlugin ref={slateRef} />
46
47
  <EventListenerPlugin on={onEvent} />
47
48
  <PortableTextEditable />
49
+ {options.children}
48
50
  </EditorProvider>,
49
51
  )
50
52
 
@@ -1,4 +1,4 @@
1
- import {Transforms} from 'slate'
1
+ import {deleteText, setSelection, Transforms} from 'slate'
2
2
  import {createPlaceholderBlock} from '../internal-utils/create-placeholder-block'
3
3
  import {isTextBlock} from '../internal-utils/parse-blocks'
4
4
  import {getBlockPath} from '../internal-utils/slate-utils'
@@ -11,15 +11,33 @@ export const deleteOperationImplementation: BehaviorOperationImplementation<
11
11
  > = ({context, operation}) => {
12
12
  const anchorBlockKey = getBlockKeyFromSelectionPoint(operation.at.anchor)
13
13
  const focusBlockKey = getBlockKeyFromSelectionPoint(operation.at.focus)
14
+
15
+ const startBlockKey = operation.at.backward ? focusBlockKey : anchorBlockKey
14
16
  const endBlockKey = operation.at.backward ? anchorBlockKey : focusBlockKey
15
17
  const endOffset = operation.at.backward
16
18
  ? operation.at.focus.offset
17
19
  : operation.at.anchor.offset
18
20
 
21
+ if (!startBlockKey) {
22
+ throw new Error('Failed to get start block key')
23
+ }
24
+
19
25
  if (!endBlockKey) {
20
26
  throw new Error('Failed to get end block key')
21
27
  }
22
28
 
29
+ const startBlockIndex = operation.editor.blockIndexMap.get(startBlockKey)
30
+
31
+ if (startBlockIndex === undefined) {
32
+ throw new Error('Failed to get start block index')
33
+ }
34
+
35
+ const startBlock = operation.editor.value.at(startBlockIndex)
36
+
37
+ if (!startBlock) {
38
+ throw new Error('Failed to get start block')
39
+ }
40
+
23
41
  const endBlockIndex = operation.editor.blockIndexMap.get(endBlockKey)
24
42
 
25
43
  if (endBlockIndex === undefined) {
@@ -82,10 +100,21 @@ export const deleteOperationImplementation: BehaviorOperationImplementation<
82
100
 
83
101
  const hanging = isTextBlock(context, endBlock) && endOffset === 0
84
102
 
85
- operation.editor.delete({
103
+ deleteText(operation.editor, {
86
104
  at: range,
87
105
  reverse: operation.direction === 'backward',
88
106
  unit: operation.unit,
89
107
  hanging,
90
108
  })
109
+
110
+ if (
111
+ operation.editor.selection &&
112
+ isTextBlock(context, startBlock) &&
113
+ isTextBlock(context, endBlock)
114
+ ) {
115
+ setSelection(operation.editor, {
116
+ anchor: operation.editor.selection.focus,
117
+ focus: operation.editor.selection.focus,
118
+ })
119
+ }
91
120
  }
@@ -1,7 +1,7 @@
1
+ import {isEqual} from 'lodash'
1
2
  import {Editor, Path, Point, Range, Transforms, type Descendant} from 'slate'
2
3
  import {DOMEditor} from 'slate-dom'
3
- import type {EditorSchema} from '../editor/editor-schema'
4
- import {parseBlock} from '../internal-utils/parse-blocks'
4
+ import {isSpan, parseBlock} from '../internal-utils/parse-blocks'
5
5
  import {
6
6
  getFocusBlock,
7
7
  getFocusChild,
@@ -12,7 +12,10 @@ import {
12
12
  import {isEqualToEmptyEditor, toSlateValue} from '../internal-utils/values'
13
13
  import type {PortableTextSlateEditor} from '../types/editor'
14
14
  import {isEmptyTextBlock} from '../utils'
15
- import type {BehaviorOperationImplementation} from './behavior.operations'
15
+ import type {
16
+ BehaviorOperationImplementation,
17
+ BehaviorOperationImplementationContext,
18
+ } from './behavior.operations'
16
19
 
17
20
  export const insertBlockOperationImplementation: BehaviorOperationImplementation<
18
21
  'insert.block'
@@ -36,26 +39,26 @@ export const insertBlockOperationImplementation: BehaviorOperationImplementation
36
39
  }
37
40
 
38
41
  insertBlock({
42
+ context,
39
43
  block: fragment,
40
44
  placement: operation.placement,
41
45
  select: operation.select ?? 'start',
42
46
  editor: operation.editor,
43
- schema: context.schema,
44
47
  })
45
48
  }
46
49
 
47
50
  export function insertBlock({
51
+ context,
48
52
  block,
49
53
  placement,
50
54
  select,
51
55
  editor,
52
- schema,
53
56
  }: {
57
+ context: BehaviorOperationImplementationContext
54
58
  block: Descendant
55
59
  placement: 'auto' | 'after' | 'before'
56
60
  select: 'start' | 'end' | 'none'
57
61
  editor: PortableTextSlateEditor
58
- schema: EditorSchema
59
62
  }) {
60
63
  const [startBlock, startBlockPath] = getSelectionStartBlock({editor})
61
64
  const [endBlock, endBlockPath] = getSelectionEndBlock({editor})
@@ -93,7 +96,7 @@ export function insertBlock({
93
96
  } else {
94
97
  // placement === 'auto'
95
98
 
96
- if (lastBlock && isEqualToEmptyEditor([lastBlock], schema)) {
99
+ if (lastBlock && isEqualToEmptyEditor([lastBlock], context.schema)) {
97
100
  // And if the last block was an empty text block, let's remove
98
101
  // that too
99
102
  Transforms.removeNodes(editor, {at: lastBlockPath})
@@ -211,7 +214,7 @@ export function insertBlock({
211
214
  Transforms.select(editor, adjustedSelection)
212
215
  }
213
216
 
214
- if (focusBlock && isEqualToEmptyEditor([focusBlock], schema)) {
217
+ if (focusBlock && isEqualToEmptyEditor([focusBlock], context.schema)) {
215
218
  Transforms.removeNodes(editor, {at: focusBlockPath})
216
219
  }
217
220
 
@@ -221,7 +224,7 @@ export function insertBlock({
221
224
  if (editor.isTextBlock(endBlock) && editor.isTextBlock(block)) {
222
225
  const selectionStartPoint = Range.start(currentSelection)
223
226
 
224
- if (isEqualToEmptyEditor([endBlock], schema)) {
227
+ if (isEqualToEmptyEditor([endBlock], context.schema)) {
225
228
  const currentSelection = editor.selection
226
229
 
227
230
  Transforms.insertNodes(editor, [block], {
@@ -241,25 +244,94 @@ export function insertBlock({
241
244
  return
242
245
  }
243
246
 
247
+ const endBlockChildKeys = endBlock.children.map((child) => child._key)
248
+ const endBlockMarkDefsKeys =
249
+ endBlock.markDefs?.map((markDef) => markDef._key) ?? []
250
+
251
+ // Assign new keys to markDefs with duplicate keys and keep track of
252
+ // the mapping between the old and new keys
253
+ const markDefKeyMap = new Map<string, string>()
254
+ const adjustedMarkDefs = block.markDefs?.map((markDef) => {
255
+ if (endBlockMarkDefsKeys.includes(markDef._key)) {
256
+ const newKey = context.keyGenerator()
257
+ markDefKeyMap.set(markDef._key, newKey)
258
+ return {
259
+ ...markDef,
260
+ _key: newKey,
261
+ }
262
+ }
263
+
264
+ return markDef
265
+ })
266
+
267
+ // Assign new keys to spans with duplicate keys and update any markDef
268
+ // key if needed
269
+ const adjustedChildren = block.children.map((child) => {
270
+ if (isSpan(context, child)) {
271
+ const marks =
272
+ child.marks?.map((mark) => {
273
+ const markDefKey = markDefKeyMap.get(mark)
274
+
275
+ if (markDefKey) {
276
+ return markDefKey
277
+ }
278
+
279
+ return mark
280
+ }) ?? []
281
+
282
+ if (!isEqual(child.marks, marks)) {
283
+ return {
284
+ ...child,
285
+ _key: endBlockChildKeys.includes(child._key)
286
+ ? context.keyGenerator()
287
+ : child._key,
288
+ marks,
289
+ }
290
+ }
291
+ }
292
+
293
+ if (endBlockChildKeys.includes(child._key)) {
294
+ return {
295
+ ...child,
296
+ _key: context.keyGenerator(),
297
+ }
298
+ }
299
+
300
+ return child
301
+ })
302
+
303
+ // Carry over the markDefs from the incoming block to the end block
244
304
  Transforms.setNodes(
245
305
  editor,
246
306
  {
247
- markDefs: [...(endBlock.markDefs ?? []), ...(block.markDefs ?? [])],
307
+ markDefs: [
308
+ ...(endBlock.markDefs ?? []),
309
+ ...(adjustedMarkDefs ?? []),
310
+ ],
248
311
  },
249
312
  {
250
313
  at: endBlockPath,
251
314
  },
252
315
  )
253
316
 
317
+ // If the children have changed, we need to create a new block with
318
+ // the adjusted children
319
+ const adjustedBlock = !isEqual(block.children, adjustedChildren)
320
+ ? {
321
+ ...block,
322
+ children: adjustedChildren as Descendant[],
323
+ }
324
+ : block
325
+
254
326
  if (select === 'end') {
255
- Transforms.insertFragment(editor, [block], {
327
+ Transforms.insertFragment(editor, [adjustedBlock], {
256
328
  voids: true,
257
329
  })
258
330
 
259
331
  return
260
332
  }
261
333
 
262
- Transforms.insertFragment(editor, [block], {
334
+ Transforms.insertFragment(editor, [adjustedBlock], {
263
335
  at: currentSelection,
264
336
  voids: true,
265
337
  })
@@ -301,7 +373,7 @@ export function insertBlock({
301
373
  Transforms.select(editor, Editor.start(editor, endBlockPath))
302
374
  }
303
375
 
304
- if (isEmptyTextBlock({schema}, endBlock)) {
376
+ if (isEmptyTextBlock(context, endBlock)) {
305
377
  Transforms.removeNodes(editor, {at: Path.next(endBlockPath)})
306
378
  }
307
379
  } else if (
@@ -18,7 +18,7 @@ export function mergeTextBlocks({
18
18
  const parsedIncomingBlock = parseBlock({
19
19
  context,
20
20
  block: incomingBlock,
21
- options: {refreshKeys: true, validateFields: true},
21
+ options: {refreshKeys: false, validateFields: false},
22
22
  })
23
23
 
24
24
  if (!parsedIncomingBlock || !isTextBlock(context, parsedIncomingBlock)) {