@portabletext/editor 1.31.2 → 1.32.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.
@@ -20,6 +20,7 @@ import {
20
20
  type Descendant,
21
21
  type SelectionOperation,
22
22
  } from 'slate'
23
+ import type {BehaviorActionImplementation} from '../../behavior-actions/behavior.actions'
23
24
  import {debugWithName} from '../../internal-utils/debug'
24
25
  import {fromSlateValue} from '../../internal-utils/values'
25
26
  import {isChangingRemotely} from '../../internal-utils/withChanges'
@@ -33,6 +34,7 @@ import {
33
34
  } from '../../internal-utils/withUndoRedo'
34
35
  import type {PortableTextSlateEditor} from '../../types/editor'
35
36
  import type {EditorActor} from '../editor-machine'
37
+ import {getCurrentBehaviorActionSetId} from '../with-applying-behavior-actions'
36
38
 
37
39
  const debug = debugWithName('plugin:withUndoRedo')
38
40
  const debugVerbose = debug.enabled && false
@@ -78,6 +80,8 @@ export function createWithUndoRedo(
78
80
  blockSchemaType.name,
79
81
  )
80
82
  const remotePatches = getRemotePatches(editor)
83
+ let previousBehaviorActionIntendSetId =
84
+ getCurrentBehaviorActionSetId(editor)
81
85
 
82
86
  options.subscriptions.push(() => {
83
87
  debug('Subscribing to patches')
@@ -112,7 +116,9 @@ export function createWithUndoRedo(
112
116
  })
113
117
 
114
118
  editor.history = {undos: [], redos: []}
119
+
115
120
  const {apply} = editor
121
+
116
122
  editor.apply = (op: Operation) => {
117
123
  if (editorActor.getSnapshot().matches({'edit mode': 'read only'})) {
118
124
  apply(op)
@@ -145,12 +151,28 @@ export function createWithUndoRedo(
145
151
  const overwrite = shouldOverwrite(op, lastOp)
146
152
  const save = isSaving(editor)
147
153
 
148
- let merge = true
154
+ const currentBehaviorActionIntendSetId =
155
+ getCurrentBehaviorActionSetId(editor)
156
+
157
+ let merge =
158
+ currentBehaviorActionIntendSetId !== undefined &&
159
+ previousBehaviorActionIntendSetId === undefined
160
+ ? false
161
+ : currentBehaviorActionIntendSetId !== undefined &&
162
+ previousBehaviorActionIntendSetId !== undefined
163
+ ? currentBehaviorActionIntendSetId ===
164
+ previousBehaviorActionIntendSetId
165
+ : true
166
+
149
167
  if (save) {
150
168
  if (!step) {
151
169
  merge = false
152
170
  } else if (operations.length === 0) {
153
- merge = shouldMerge(op, lastOp) || overwrite
171
+ merge =
172
+ currentBehaviorActionIntendSetId === undefined &&
173
+ previousBehaviorActionIntendSetId === undefined
174
+ ? shouldMerge(op, lastOp) || overwrite
175
+ : merge
154
176
  }
155
177
 
156
178
  if (step && merge) {
@@ -177,123 +199,126 @@ export function createWithUndoRedo(
177
199
  history.redos = []
178
200
  }
179
201
  }
202
+
203
+ previousBehaviorActionIntendSetId = currentBehaviorActionIntendSetId
204
+
180
205
  apply(op)
181
206
  }
182
207
 
183
- editor.undo = () => {
184
- if (editorActor.getSnapshot().matches({'edit mode': 'read only'})) {
185
- return
186
- }
187
- const {undos} = editor.history
188
- if (undos.length > 0) {
189
- const step = undos[undos.length - 1]
190
- debug('Undoing', step)
191
- if (step.operations.length > 0) {
192
- const otherPatches = remotePatches.filter(
193
- (item) => item.time >= step.timestamp,
194
- )
195
- let transformedOperations = step.operations
196
- otherPatches.forEach((item) => {
197
- transformedOperations = flatten(
198
- transformedOperations.map((op) =>
199
- transformOperation(
200
- editor,
201
- item.patch,
202
- op,
203
- item.snapshot,
204
- item.previousSnapshot,
205
- ),
206
- ),
207
- )
208
- })
209
- const reversedOperations = transformedOperations
210
- .map(Operation.inverse)
211
- .reverse()
212
-
213
- try {
214
- Editor.withoutNormalizing(editor, () => {
215
- withUndoing(editor, () => {
216
- withoutSaving(editor, () => {
217
- reversedOperations.forEach((op) => {
218
- editor.apply(op)
219
- })
220
- })
208
+ // Plugin return
209
+ return editor
210
+ }
211
+ }
212
+
213
+ export const historyUndoActionImplementation: BehaviorActionImplementation<
214
+ 'history.undo'
215
+ > = ({action}) => {
216
+ const editor = action.editor
217
+ const {undos} = editor.history
218
+ const remotePatches = getRemotePatches(editor)
219
+
220
+ if (undos.length > 0) {
221
+ const step = undos[undos.length - 1]
222
+ debug('Undoing', step)
223
+ if (step.operations.length > 0) {
224
+ const otherPatches = remotePatches.filter(
225
+ (item) => item.time >= step.timestamp,
226
+ )
227
+ let transformedOperations = step.operations
228
+ otherPatches.forEach((item) => {
229
+ transformedOperations = flatten(
230
+ transformedOperations.map((op) =>
231
+ transformOperation(
232
+ editor,
233
+ item.patch,
234
+ op,
235
+ item.snapshot,
236
+ item.previousSnapshot,
237
+ ),
238
+ ),
239
+ )
240
+ })
241
+ const reversedOperations = transformedOperations
242
+ .map(Operation.inverse)
243
+ .reverse()
244
+
245
+ try {
246
+ Editor.withoutNormalizing(editor, () => {
247
+ withUndoing(editor, () => {
248
+ withoutSaving(editor, () => {
249
+ reversedOperations.forEach((op) => {
250
+ editor.apply(op)
221
251
  })
222
252
  })
223
- editor.normalize()
224
- editor.onChange()
225
- } catch (err) {
226
- debug('Could not perform undo step', err)
227
- remotePatches.splice(0, remotePatches.length)
228
- Transforms.deselect(editor)
229
- editor.history = {undos: [], redos: []}
230
- SAVING.set(editor, true)
231
- setIsUndoing(editor, false)
232
- editor.onChange()
233
- return
234
- }
235
- editor.history.redos.push(step)
236
- editor.history.undos.pop()
237
- }
253
+ })
254
+ })
255
+ } catch (err) {
256
+ debug('Could not perform undo step', err)
257
+ remotePatches.splice(0, remotePatches.length)
258
+ Transforms.deselect(editor)
259
+ editor.history = {undos: [], redos: []}
260
+ SAVING.set(editor, true)
261
+ setIsUndoing(editor, false)
262
+ editor.onChange()
263
+ return
238
264
  }
265
+ editor.history.redos.push(step)
266
+ editor.history.undos.pop()
239
267
  }
268
+ }
269
+ }
240
270
 
241
- editor.redo = () => {
242
- if (editorActor.getSnapshot().matches({'edit mode': 'read only'})) {
243
- return
244
- }
245
- const {redos} = editor.history
246
- if (redos.length > 0) {
247
- const step = redos[redos.length - 1]
248
- debug('Redoing', step)
249
- if (step.operations.length > 0) {
250
- const otherPatches = remotePatches.filter(
251
- (item) => item.time >= step.timestamp,
252
- )
253
- let transformedOperations = step.operations
254
- otherPatches.forEach((item) => {
255
- transformedOperations = flatten(
256
- transformedOperations.map((op) =>
257
- transformOperation(
258
- editor,
259
- item.patch,
260
- op,
261
- item.snapshot,
262
- item.previousSnapshot,
263
- ),
264
- ),
265
- )
266
- })
267
- try {
268
- Editor.withoutNormalizing(editor, () => {
269
- withRedoing(editor, () => {
270
- withoutSaving(editor, () => {
271
- transformedOperations.forEach((op) => {
272
- editor.apply(op)
273
- })
274
- })
271
+ export const historyRedoActionImplementation: BehaviorActionImplementation<
272
+ 'history.redo'
273
+ > = ({action}) => {
274
+ const editor = action.editor
275
+ const {redos} = editor.history
276
+ const remotePatches = getRemotePatches(editor)
277
+
278
+ if (redos.length > 0) {
279
+ const step = redos[redos.length - 1]
280
+ debug('Redoing', step)
281
+ if (step.operations.length > 0) {
282
+ const otherPatches = remotePatches.filter(
283
+ (item) => item.time >= step.timestamp,
284
+ )
285
+ let transformedOperations = step.operations
286
+ otherPatches.forEach((item) => {
287
+ transformedOperations = flatten(
288
+ transformedOperations.map((op) =>
289
+ transformOperation(
290
+ editor,
291
+ item.patch,
292
+ op,
293
+ item.snapshot,
294
+ item.previousSnapshot,
295
+ ),
296
+ ),
297
+ )
298
+ })
299
+ try {
300
+ Editor.withoutNormalizing(editor, () => {
301
+ withRedoing(editor, () => {
302
+ withoutSaving(editor, () => {
303
+ transformedOperations.forEach((op) => {
304
+ editor.apply(op)
275
305
  })
276
306
  })
277
- editor.normalize()
278
- editor.onChange()
279
- } catch (err) {
280
- debug('Could not perform redo step', err)
281
- remotePatches.splice(0, remotePatches.length)
282
- Transforms.deselect(editor)
283
- editor.history = {undos: [], redos: []}
284
- SAVING.set(editor, true)
285
- setIsRedoing(editor, false)
286
- editor.onChange()
287
- return
288
- }
289
- editor.history.undos.push(step)
290
- editor.history.redos.pop()
291
- }
307
+ })
308
+ })
309
+ } catch (err) {
310
+ debug('Could not perform redo step', err)
311
+ remotePatches.splice(0, remotePatches.length)
312
+ Transforms.deselect(editor)
313
+ editor.history = {undos: [], redos: []}
314
+ SAVING.set(editor, true)
315
+ setIsRedoing(editor, false)
316
+ editor.onChange()
317
+ return
292
318
  }
319
+ editor.history.undos.push(step)
320
+ editor.history.redos.pop()
293
321
  }
294
-
295
- // Plugin return
296
- return editor
297
322
  }
298
323
  }
299
324
 
@@ -1,15 +1,39 @@
1
- import type {Editor} from 'slate'
1
+ import {Editor} from 'slate'
2
+ import {defaultKeyGenerator} from './key-generator'
2
3
 
3
4
  const IS_APPLYING_BEHAVIOR_ACTIONS: WeakMap<Editor, boolean | undefined> =
4
5
  new WeakMap()
5
6
 
6
7
  export function withApplyingBehaviorActions(editor: Editor, fn: () => void) {
7
- const prev = isApplyingBehaviorActions(editor)
8
+ const prev = IS_APPLYING_BEHAVIOR_ACTIONS.get(editor)
8
9
  IS_APPLYING_BEHAVIOR_ACTIONS.set(editor, true)
9
- fn()
10
+ Editor.withoutNormalizing(editor, fn)
10
11
  IS_APPLYING_BEHAVIOR_ACTIONS.set(editor, prev)
11
12
  }
12
13
 
13
14
  export function isApplyingBehaviorActions(editor: Editor) {
14
15
  return IS_APPLYING_BEHAVIOR_ACTIONS.get(editor) ?? false
15
16
  }
17
+
18
+ ////////
19
+
20
+ const CURRENT_BEHAVIOR_ACTION_INTEND_SET: WeakMap<
21
+ Editor,
22
+ {actionSetId: string} | undefined
23
+ > = new WeakMap()
24
+
25
+ export function withApplyingBehaviorActionIntendSet(
26
+ editor: Editor,
27
+ fn: () => void,
28
+ ) {
29
+ const current = CURRENT_BEHAVIOR_ACTION_INTEND_SET.get(editor)
30
+ CURRENT_BEHAVIOR_ACTION_INTEND_SET.set(editor, {
31
+ actionSetId: defaultKeyGenerator(),
32
+ })
33
+ withApplyingBehaviorActions(editor, fn)
34
+ CURRENT_BEHAVIOR_ACTION_INTEND_SET.set(editor, current)
35
+ }
36
+
37
+ export function getCurrentBehaviorActionSetId(editor: Editor) {
38
+ return CURRENT_BEHAVIOR_ACTION_INTEND_SET.get(editor)?.actionSetId
39
+ }