@portabletext/editor 1.49.8 → 1.49.9

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "1.49.8",
3
+ "version": "1.49.9",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -1169,6 +1169,7 @@ export const PortableTextEditable = forwardRef<
1169
1169
  return hasInvalidValue ? null : (
1170
1170
  <SlateEditable
1171
1171
  {...restProps}
1172
+ data-read-only={readOnly}
1172
1173
  autoFocus={false}
1173
1174
  className={restProps.className || 'pt-editable'}
1174
1175
  decorate={decorate}
@@ -14,10 +14,9 @@ import {
14
14
  } from 'react'
15
15
  import {Subject} from 'rxjs'
16
16
  import {Slate} from 'slate-react'
17
- import {createActor} from 'xstate'
18
- import {createCoreConverters} from '../converters/converters.core'
19
17
  import {debugWithName} from '../internal-utils/debug'
20
18
  import {compileType} from '../internal-utils/schema'
19
+ import {stopActor} from '../internal-utils/stop-actor'
21
20
  import type {AddedAnnotationPaths} from '../operations/behavior.operation.annotation.add'
22
21
  import type {
23
22
  EditableAPI,
@@ -30,13 +29,14 @@ import type {
30
29
  } from '../types/editor'
31
30
  import {createInternalEditor, type InternalEditor} from './create-editor'
32
31
  import {EditorActorContext} from './editor-actor-context'
33
- import {editorMachine, type EditorActor} from './editor-machine'
32
+ import type {EditorActor} from './editor-machine'
34
33
  import {legacySchemaToEditorSchema} from './editor-schema'
35
34
  import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
36
35
  import {PortableTextEditorSelectionProvider} from './hooks/usePortableTextEditorSelection'
37
- import {defaultKeyGenerator} from './key-generator'
38
36
  import {createLegacySchema} from './legacy-schema'
37
+ import type {MutationActor} from './mutation-machine'
39
38
  import {eventToChange} from './route-events-to-changes'
39
+ import type {SyncActor} from './sync-machine'
40
40
 
41
41
  const debug = debugWithName('component:PortableTextEditor')
42
42
 
@@ -132,6 +132,14 @@ export class PortableTextEditor extends Component<
132
132
  */
133
133
  private editable: EditableAPI
134
134
 
135
+ private actors?: {
136
+ editorActor: EditorActor
137
+ mutationActor: MutationActor
138
+ syncActor: SyncActor
139
+ }
140
+
141
+ private unsubscribers: Array<() => void> = []
142
+
135
143
  constructor(props: PortableTextEditorProps) {
136
144
  super(props)
137
145
 
@@ -141,45 +149,60 @@ export class PortableTextEditor extends Component<
141
149
  .getSnapshot()
142
150
  .context.getLegacySchema()
143
151
  } else {
144
- const legacySchema = createLegacySchema(
145
- props.schemaType.hasOwnProperty('jsonType')
146
- ? props.schemaType
147
- : compileType(props.schemaType),
148
- )
149
- const schema = legacySchemaToEditorSchema(legacySchema)
150
- const editorActor = createActor(editorMachine, {
151
- input: {
152
- converters: createCoreConverters(legacySchema),
153
- getLegacySchema: () => legacySchema,
154
- initialValue: props.value,
155
- keyGenerator: props.keyGenerator ?? defaultKeyGenerator,
156
- maxBlocks:
157
- props.maxBlocks === undefined
158
- ? undefined
159
- : Number.parseInt(props.maxBlocks.toString(), 10),
160
- readOnly: props.readOnly,
161
- schema,
162
- },
152
+ const {actors, editor, subscriptions} = createInternalEditor({
153
+ initialValue: props.value,
154
+ keyGenerator: props.keyGenerator,
155
+ maxBlocks:
156
+ props.maxBlocks === undefined
157
+ ? undefined
158
+ : Number.parseInt(props.maxBlocks.toString(), 10),
159
+ readOnly: props.readOnly,
160
+ schema: props.schemaType,
163
161
  })
164
- editorActor.start()
165
162
 
166
- editorActor.on('*', (event) => {
167
- const change = eventToChange(event)
163
+ this.unsubscribers.push(
164
+ (() => {
165
+ const subscription = actors.editorActor.on('*', (event) => {
166
+ const change = eventToChange(event)
168
167
 
169
- if (change) {
170
- props.onChange(change)
168
+ if (change) {
169
+ props.onChange(change)
171
170
 
172
- this.change$.next(change)
173
- }
174
- })
171
+ this.change$.next(change)
172
+ }
173
+ })
174
+
175
+ return () => {
176
+ subscription.unsubscribe()
177
+ }
178
+ })(),
179
+ )
180
+
181
+ for (const subscription of subscriptions) {
182
+ this.unsubscribers.push(subscription())
183
+ }
184
+
185
+ this.actors = actors
175
186
 
176
- this.editor = createInternalEditor(editorActor)
177
- this.schemaTypes = legacySchema
187
+ this.editor = editor
188
+ this.schemaTypes = actors.editorActor
189
+ .getSnapshot()
190
+ .context.getLegacySchema()
178
191
  }
179
192
 
180
193
  this.editable = this.editor._internal.editable
181
194
  }
182
195
 
196
+ componentDidMount(): void {
197
+ if (!this.actors) {
198
+ return
199
+ }
200
+
201
+ this.actors.editorActor.start()
202
+ this.actors.mutationActor.start()
203
+ this.actors.syncActor.start()
204
+ }
205
+
183
206
  componentDidUpdate(prevProps: PortableTextEditorProps) {
184
207
  // Set up the schema type lookup table again if the source schema type changes
185
208
  if (
@@ -233,6 +256,18 @@ export class PortableTextEditor extends Component<
233
256
  }
234
257
  }
235
258
 
259
+ componentWillUnmount(): void {
260
+ for (const unsubscribe of this.unsubscribers) {
261
+ unsubscribe()
262
+ }
263
+
264
+ if (this.actors) {
265
+ stopActor(this.actors.editorActor)
266
+ stopActor(this.actors.mutationActor)
267
+ stopActor(this.actors.syncActor)
268
+ }
269
+ }
270
+
236
271
  public setEditable = (editable: EditableAPI) => {
237
272
  this.editor._internal.editable = {
238
273
  ...this.editor._internal.editable,
@@ -43,6 +43,7 @@ describe('initialization', () => {
43
43
  autocorrect="false"
44
44
  class="pt-editable"
45
45
  contenteditable="true"
46
+ data-read-only="false"
46
47
  data-slate-editor="true"
47
48
  data-slate-node="value"
48
49
  role="textbox"
@@ -1,4 +1,4 @@
1
- import {createActor, type ActorRefFrom} from 'xstate'
1
+ import {createActor} from 'xstate'
2
2
  import {createCoreConverters} from '../converters/converters.core'
3
3
  import type {Editor, EditorConfig} from '../editor'
4
4
  import {debugWithName} from '../internal-utils/debug'
@@ -10,6 +10,7 @@ import {createEditorPriority} from '../priority/priority.types'
10
10
  import type {EditableAPI, PortableTextSlateEditor} from '../types/editor'
11
11
  import {createSlateEditor, type SlateEditor} from './create-slate-editor'
12
12
  import type {EditorActor} from './editor-machine'
13
+ import {editorMachine} from './editor-machine'
13
14
  import {
14
15
  compileSchemaDefinitionToLegacySchema,
15
16
  legacySchemaToEditorSchema,
@@ -17,11 +18,11 @@ import {
17
18
  import {getEditorSnapshot} from './editor-selector'
18
19
  import {defaultKeyGenerator} from './key-generator'
19
20
  import {createLegacySchema} from './legacy-schema'
20
- import {mutationMachine} from './mutation-machine'
21
+ import {mutationMachine, type MutationActor} from './mutation-machine'
21
22
  import {createEditableAPI} from './plugins/createWithEditableAPI'
22
- import {syncMachine} from './sync-machine'
23
+ import {syncMachine, type SyncActor} from './sync-machine'
23
24
 
24
- const debug = debugWithName('createInternalEditor')
25
+ const debug = debugWithName('setup')
25
26
 
26
27
  export type InternalEditor = Editor & {
27
28
  _internal: {
@@ -61,18 +62,30 @@ export function editorConfigToMachineInput(config: EditorConfig) {
61
62
  } as const
62
63
  }
63
64
 
64
- export function createInternalEditor(editorActor: EditorActor): InternalEditor {
65
- const slateEditor = createSlateEditor({editorActor})
65
+ export function createInternalEditor(config: EditorConfig): {
66
+ actors: {
67
+ editorActor: EditorActor
68
+ mutationActor: MutationActor
69
+ syncActor: SyncActor
70
+ }
71
+ editor: InternalEditor
72
+ subscriptions: Array<() => () => void>
73
+ } {
74
+ debug('Creating new Editor instance')
75
+
76
+ const subscriptions: Array<() => () => void> = []
77
+ const editorActor = createActor(editorMachine, {
78
+ input: editorConfigToMachineInput(config),
79
+ })
80
+ const slateEditor = createSlateEditor({editorActor, subscriptions})
66
81
  const editable = createEditableAPI(slateEditor.instance, editorActor)
67
82
  const {mutationActor, syncActor} = createActors({
68
83
  editorActor,
69
84
  slateEditor: slateEditor.instance,
85
+ subscriptions,
70
86
  })
71
87
 
72
- mutationActor.start()
73
- syncActor.start()
74
-
75
- return {
88
+ const editor = {
76
89
  getSnapshot: () =>
77
90
  getEditorSnapshot({
78
91
  editorActorSnapshot: editorActor.getSnapshot(),
@@ -182,32 +195,28 @@ export function createInternalEditor(editorActor: EditorActor): InternalEditor {
182
195
  editorActor,
183
196
  slateEditor,
184
197
  },
185
- }
186
- }
198
+ } satisfies InternalEditor
187
199
 
188
- const actors = new WeakMap<
189
- EditorActor,
190
- {
191
- syncActor: ActorRefFrom<typeof syncMachine>
192
- mutationActor: ActorRefFrom<typeof mutationMachine>
200
+ return {
201
+ actors: {
202
+ editorActor,
203
+ mutationActor,
204
+ syncActor,
205
+ },
206
+ editor,
207
+ subscriptions,
193
208
  }
194
- >()
209
+ }
195
210
 
196
211
  function createActors(config: {
197
212
  editorActor: EditorActor
198
213
  slateEditor: PortableTextSlateEditor
214
+ subscriptions: Array<() => () => void>
199
215
  }): {
200
- syncActor: ActorRefFrom<typeof syncMachine>
201
- mutationActor: ActorRefFrom<typeof mutationMachine>
216
+ syncActor: SyncActor
217
+ mutationActor: MutationActor
202
218
  } {
203
- const existingActor = actors.get(config.editorActor)
204
-
205
- if (existingActor) {
206
- debug('Reusing existing actors')
207
- return existingActor
208
- }
209
-
210
- debug('Creating new actors')
219
+ debug('Creating new Actors')
211
220
 
212
221
  const mutationActor = createActor(mutationMachine, {
213
222
  input: {
@@ -228,67 +237,82 @@ function createActors(config: {
228
237
  },
229
238
  })
230
239
 
231
- mutationActor.on('*', (event) => {
232
- if (event.type === 'has pending patches') {
233
- syncActor.send({type: 'has pending patches'})
234
- }
235
- if (event.type === 'mutation') {
236
- syncActor.send({type: 'mutation'})
237
- config.editorActor.send({
238
- type: 'mutation',
239
- patches: event.patches,
240
- snapshot: event.snapshot,
241
- value: event.snapshot,
242
- })
243
- }
244
- })
245
-
246
- syncActor.on('*', (event) => {
247
- switch (event.type) {
248
- case 'invalid value':
249
- config.editorActor.send({
250
- ...event,
251
- type: 'notify.invalid value',
252
- })
253
- break
254
- case 'value changed':
255
- config.editorActor.send({
256
- ...event,
257
- type: 'notify.value changed',
258
- })
259
- break
260
- case 'patch':
240
+ config.subscriptions.push(() => {
241
+ const subscription = mutationActor.on('*', (event) => {
242
+ if (event.type === 'has pending patches') {
243
+ syncActor.send({type: 'has pending patches'})
244
+ }
245
+ if (event.type === 'mutation') {
246
+ syncActor.send({type: 'mutation'})
261
247
  config.editorActor.send({
262
- ...event,
263
- type: 'internal.patch',
264
- value: fromSlateValue(
265
- config.slateEditor.children,
266
- config.editorActor.getSnapshot().context.schema.block.name,
267
- KEY_TO_VALUE_ELEMENT.get(config.slateEditor),
268
- ),
248
+ type: 'mutation',
249
+ patches: event.patches,
250
+ snapshot: event.snapshot,
251
+ value: event.snapshot,
269
252
  })
270
- break
253
+ }
254
+ })
271
255
 
272
- default:
273
- config.editorActor.send(event)
256
+ return () => {
257
+ subscription.unsubscribe()
274
258
  }
275
259
  })
276
260
 
277
- config.editorActor.on('*', (event) => {
278
- if (event.type === 'read only') {
279
- syncActor.send({type: 'update readOnly', readOnly: true})
280
- }
281
- if (event.type === 'editable') {
282
- syncActor.send({type: 'update readOnly', readOnly: false})
283
- }
284
- if (event.type === 'internal.patch') {
285
- mutationActor.send({...event, type: 'patch'})
261
+ config.subscriptions.push(() => {
262
+ const subscription = syncActor.on('*', (event) => {
263
+ switch (event.type) {
264
+ case 'invalid value':
265
+ config.editorActor.send({
266
+ ...event,
267
+ type: 'notify.invalid value',
268
+ })
269
+ break
270
+ case 'value changed':
271
+ config.editorActor.send({
272
+ ...event,
273
+ type: 'notify.value changed',
274
+ })
275
+ break
276
+ case 'patch':
277
+ config.editorActor.send({
278
+ ...event,
279
+ type: 'internal.patch',
280
+ value: fromSlateValue(
281
+ config.slateEditor.children,
282
+ config.editorActor.getSnapshot().context.schema.block.name,
283
+ KEY_TO_VALUE_ELEMENT.get(config.slateEditor),
284
+ ),
285
+ })
286
+ break
287
+
288
+ default:
289
+ config.editorActor.send(event)
290
+ }
291
+ })
292
+
293
+ return () => {
294
+ subscription.unsubscribe()
286
295
  }
287
296
  })
288
297
 
289
- actors.set(config.editorActor, {
290
- syncActor,
291
- mutationActor,
298
+ config.subscriptions.push(() => {
299
+ const subscription = config.editorActor.on('*', (event) => {
300
+ if (
301
+ config.editorActor.getSnapshot().matches({'edit mode': 'read only'})
302
+ ) {
303
+ syncActor.send({type: 'update readOnly', readOnly: true})
304
+ } else {
305
+ syncActor.send({type: 'update readOnly', readOnly: false})
306
+ }
307
+
308
+ if (event.type === 'internal.patch') {
309
+ mutationActor.send({...event, type: 'patch'})
310
+ }
311
+ })
312
+
313
+ return () => {
314
+ subscription.unsubscribe()
315
+ }
292
316
  })
293
317
 
294
318
  return {
@@ -9,10 +9,11 @@ import type {PortableTextSlateEditor} from '../types/editor'
9
9
  import type {EditorActor} from './editor-machine'
10
10
  import {withPlugins} from './plugins/with-plugins'
11
11
 
12
- const debug = debugWithName('component:PortableTextEditor:SlateContainer')
12
+ const debug = debugWithName('setup')
13
13
 
14
14
  type SlateEditorConfig = {
15
15
  editorActor: EditorActor
16
+ subscriptions: Array<() => () => void>
16
17
  }
17
18
 
18
19
  export type SlateEditor = {
@@ -20,33 +21,17 @@ export type SlateEditor = {
20
21
  initialValue: Array<Descendant>
21
22
  }
22
23
 
23
- const slateEditors = new WeakMap<EditorActor, SlateEditor>()
24
-
25
24
  export function createSlateEditor(config: SlateEditorConfig): SlateEditor {
26
- const existingSlateEditor = slateEditors.get(config.editorActor)
27
-
28
- if (existingSlateEditor) {
29
- debug('Reusing existing Slate editor instance', config.editorActor.id)
30
- return existingSlateEditor
31
- }
32
-
33
- debug('Creating new Slate editor instance', config.editorActor.id)
34
-
35
- const unsubscriptions: Array<() => void> = []
36
- const subscriptions: Array<() => () => void> = []
25
+ debug('Creating new Slate editor instance')
37
26
 
38
27
  const instance = withPlugins(withReact(createEditor()), {
39
28
  editorActor: config.editorActor,
40
- subscriptions,
29
+ subscriptions: config.subscriptions,
41
30
  })
42
31
 
43
32
  KEY_TO_VALUE_ELEMENT.set(instance, {})
44
33
  KEY_TO_SLATE_ELEMENT.set(instance, {})
45
34
 
46
- for (const subscription of subscriptions) {
47
- unsubscriptions.push(subscription())
48
- }
49
-
50
35
  const initialValue = [instance.pteCreateTextBlock({decorators: []})]
51
36
 
52
37
  const slateEditor: SlateEditor = {
@@ -54,7 +39,5 @@ export function createSlateEditor(config: SlateEditorConfig): SlateEditor {
54
39
  initialValue,
55
40
  }
56
41
 
57
- slateEditors.set(config.editorActor, slateEditor)
58
-
59
42
  return slateEditor
60
43
  }
@@ -1,12 +1,12 @@
1
- import {useActorRef} from '@xstate/react'
2
1
  import type React from 'react'
3
- import {useMemo} from 'react'
2
+ import {useEffect} from 'react'
4
3
  import {Slate} from 'slate-react'
5
4
  import type {EditorConfig} from '../editor'
6
- import {createInternalEditor, editorConfigToMachineInput} from './create-editor'
5
+ import {stopActor} from '../internal-utils/stop-actor'
6
+ import useConstant from '../internal-utils/use-constant'
7
+ import {createInternalEditor} from './create-editor'
7
8
  import {EditorActorContext} from './editor-actor-context'
8
9
  import {EditorContext} from './editor-context'
9
- import {editorMachine} from './editor-machine'
10
10
  import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
11
11
  import {PortableTextEditorSelectionProvider} from './hooks/usePortableTextEditorSelection'
12
12
  import {
@@ -42,36 +42,56 @@ export type EditorProviderProps = {
42
42
  * @group Components
43
43
  */
44
44
  export function EditorProvider(props: EditorProviderProps) {
45
- const editorActor = useActorRef(editorMachine, {
46
- input: editorConfigToMachineInput(props.initialConfig),
45
+ const {internalEditor, portableTextEditor} = useConstant(() => {
46
+ const internalEditor = createInternalEditor(props.initialConfig)
47
+ const portableTextEditor = new PortableTextEditor({
48
+ editor: internalEditor.editor,
49
+ } as unknown as PortableTextEditorProps)
50
+
51
+ return {internalEditor, portableTextEditor}
47
52
  })
48
- const internalEditor = useMemo(
49
- () => createInternalEditor(editorActor),
50
- [editorActor],
51
- )
52
- const portableTextEditor = useMemo(
53
- () =>
54
- new PortableTextEditor({
55
- editor: internalEditor,
56
- } as unknown as PortableTextEditorProps),
57
- [internalEditor],
58
- )
53
+
54
+ useEffect(() => {
55
+ const unsubscribers: Array<() => void> = []
56
+
57
+ for (const subscription of internalEditor.subscriptions) {
58
+ unsubscribers.push(subscription())
59
+ }
60
+
61
+ internalEditor.actors.editorActor.start()
62
+ internalEditor.actors.mutationActor.start()
63
+ internalEditor.actors.syncActor.start()
64
+
65
+ return () => {
66
+ for (const unsubscribe of unsubscribers) {
67
+ unsubscribe()
68
+ }
69
+
70
+ stopActor(internalEditor.actors.editorActor)
71
+ stopActor(internalEditor.actors.mutationActor)
72
+ stopActor(internalEditor.actors.syncActor)
73
+ }
74
+ }, [internalEditor])
59
75
 
60
76
  return (
61
- <EditorContext.Provider value={internalEditor}>
77
+ <EditorContext.Provider value={internalEditor.editor}>
62
78
  <RouteEventsToChanges
63
- editorActor={editorActor}
79
+ editorActor={internalEditor.actors.editorActor}
64
80
  onChange={(change) => {
65
81
  portableTextEditor.change$.next(change)
66
82
  }}
67
83
  />
68
- <EditorActorContext.Provider value={editorActor}>
84
+ <EditorActorContext.Provider value={internalEditor.actors.editorActor}>
69
85
  <Slate
70
- editor={internalEditor._internal.slateEditor.instance}
71
- initialValue={internalEditor._internal.slateEditor.initialValue}
86
+ editor={internalEditor.editor._internal.slateEditor.instance}
87
+ initialValue={
88
+ internalEditor.editor._internal.slateEditor.initialValue
89
+ }
72
90
  >
73
91
  <PortableTextEditorContext.Provider value={portableTextEditor}>
74
- <PortableTextEditorSelectionProvider editorActor={editorActor}>
92
+ <PortableTextEditorSelectionProvider
93
+ editorActor={internalEditor.actors.editorActor}
94
+ >
75
95
  {props.children}
76
96
  </PortableTextEditorSelectionProvider>
77
97
  </PortableTextEditorContext.Provider>
@@ -13,9 +13,12 @@ import {
13
13
  stateIn,
14
14
  type AnyEventObject,
15
15
  } from 'xstate'
16
+ import type {ActorRefFrom} from 'xstate'
16
17
  import type {PortableTextSlateEditor} from '../types/editor'
17
18
  import type {EditorSchema} from './editor-schema'
18
19
 
20
+ export type MutationActor = ActorRefFrom<typeof mutationMachine>
21
+
19
22
  /**
20
23
  * Makes sure editor mutation events are debounced
21
24
  */
@@ -14,6 +14,7 @@ import {
14
14
  type AnyEventObject,
15
15
  type CallbackLogicFunction,
16
16
  } from 'xstate'
17
+ import type {ActorRefFrom} from 'xstate'
17
18
  import {debugWithName} from '../internal-utils/debug'
18
19
  import {validateValue} from '../internal-utils/validateValue'
19
20
  import {toSlateValue, VOID_CHILD_KEY} from '../internal-utils/values'
@@ -77,6 +78,8 @@ const syncValueCallback: CallbackLogicFunction<
77
78
 
78
79
  const syncValueLogic = fromCallback(syncValueCallback)
79
80
 
81
+ export type SyncActor = ActorRefFrom<typeof syncMachine>
82
+
80
83
  /**
81
84
  * Sync value with the editor state
82
85
  *
@@ -24,16 +24,16 @@ import type {
24
24
  } from '@sanity/types'
25
25
  import {
26
26
  Element,
27
+ Node,
27
28
  Text,
28
29
  Transforms,
29
30
  type Descendant,
30
- type Node,
31
31
  type Path as SlatePath,
32
32
  } from 'slate'
33
33
  import type {EditorSchema} from '../editor/editor-schema'
34
34
  import type {PortableTextSlateEditor} from '../types/editor'
35
35
  import {debugWithName} from './debug'
36
- import {toSlateValue} from './values'
36
+ import {isEqualToEmptyEditor, toSlateValue} from './values'
37
37
  import {KEY_TO_SLATE_ELEMENT} from './weakMaps'
38
38
 
39
39
  const debug = debugWithName('applyPatches')
@@ -173,9 +173,20 @@ function insertPatch(
173
173
  const targetBlockIndex = targetBlockPath[0]
174
174
  const normalizedIdx =
175
175
  position === 'after' ? targetBlockIndex + 1 : targetBlockIndex
176
+
176
177
  debug(`Inserting blocks at path [${normalizedIdx}]`)
177
178
  debugState(editor, 'before')
179
+
180
+ const editorWasEmptyBefore = isEqualToEmptyEditor(editor.children, schema)
181
+
178
182
  Transforms.insertNodes(editor, blocksToInsert, {at: [normalizedIdx]})
183
+
184
+ if (editorWasEmptyBefore) {
185
+ Transforms.removeNodes(editor, {
186
+ at: [position === 'after' ? targetBlockIndex + 1 : targetBlockIndex],
187
+ })
188
+ }
189
+
179
190
  debugState(editor, 'after')
180
191
  return true
181
192
  }
@@ -319,9 +330,15 @@ function unsetPatch(editor: PortableTextSlateEditor, patch: UnsetPatch) {
319
330
  debugState(editor, 'before')
320
331
  const previousSelection = editor.selection
321
332
  Transforms.deselect(editor)
322
- editor.children.forEach((_child, i) => {
323
- Transforms.removeNodes(editor, {at: [i]})
333
+
334
+ const children = Node.children(editor, [], {
335
+ reverse: true,
324
336
  })
337
+
338
+ for (const [_, path] of children) {
339
+ Transforms.removeNodes(editor, {at: path})
340
+ }
341
+
325
342
  Transforms.insertNodes(editor, editor.pteCreateTextBlock({decorators: []}))
326
343
  if (previousSelection) {
327
344
  Transforms.select(editor, {