1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-07-31 04:20:26 +02:00

Change how slate-history handles selection undo (#4717)

* Change how slate-history handles selection undo

* fix test

* fix lint

* cleanup and simplify

* Fix redo by applying undo beforeSelection before applying the redo

* remove unused shouldClear function

* fix lint

* add changeset
This commit is contained in:
Bryan Haakman
2022-10-23 23:02:05 +02:00
committed by GitHub
parent 4e52e5043e
commit d73026eed2
4 changed files with 33 additions and 53 deletions

View File

@@ -0,0 +1,5 @@
---
'slate-history': minor
---
Changes how selections are stored in the history resulting in more consistent results

View File

@@ -1,5 +1,10 @@
import { isPlainObject } from 'is-plain-object' import { isPlainObject } from 'is-plain-object'
import { Operation } from 'slate' import { Operation, Range } from 'slate'
interface Batch {
operations: Operation[]
selectionBefore: Range | null
}
/** /**
* `History` objects hold all of the operations that are applied to a value, so * `History` objects hold all of the operations that are applied to a value, so
@@ -7,8 +12,8 @@ import { Operation } from 'slate'
*/ */
export interface History { export interface History {
redos: Operation[][] redos: Batch[]
undos: Operation[][] undos: Batch[]
} }
// eslint-disable-next-line no-redeclare // eslint-disable-next-line no-redeclare

View File

@@ -1,4 +1,4 @@
import { Editor, Operation, Path } from 'slate' import { Editor, Operation, Path, Range, Transforms } from 'slate'
import { HistoryEditor } from './history-editor' import { HistoryEditor } from './history-editor'
@@ -24,9 +24,13 @@ export const withHistory = <T extends Editor>(editor: T) => {
if (redos.length > 0) { if (redos.length > 0) {
const batch = redos[redos.length - 1] const batch = redos[redos.length - 1]
if (batch.selectionBefore) {
Transforms.setSelection(e, batch.selectionBefore)
}
HistoryEditor.withoutSaving(e, () => { HistoryEditor.withoutSaving(e, () => {
Editor.withoutNormalizing(e, () => { Editor.withoutNormalizing(e, () => {
for (const op of batch) { for (const op of batch.operations) {
e.apply(op) e.apply(op)
} }
}) })
@@ -46,11 +50,14 @@ export const withHistory = <T extends Editor>(editor: T) => {
HistoryEditor.withoutSaving(e, () => { HistoryEditor.withoutSaving(e, () => {
Editor.withoutNormalizing(e, () => { Editor.withoutNormalizing(e, () => {
const inverseOps = batch.map(Operation.inverse).reverse() const inverseOps = batch.operations.map(Operation.inverse).reverse()
for (const op of inverseOps) { for (const op of inverseOps) {
e.apply(op) e.apply(op)
} }
if (batch.selectionBefore) {
Transforms.setSelection(e, batch.selectionBefore)
}
}) })
}) })
@@ -63,8 +70,8 @@ export const withHistory = <T extends Editor>(editor: T) => {
const { operations, history } = e const { operations, history } = e
const { undos } = history const { undos } = history
const lastBatch = undos[undos.length - 1] const lastBatch = undos[undos.length - 1]
const lastOp = lastBatch && lastBatch[lastBatch.length - 1] const lastOp =
const overwrite = shouldOverwrite(op, lastOp) lastBatch && lastBatch.operations[lastBatch.operations.length - 1]
let save = HistoryEditor.isSaving(e) let save = HistoryEditor.isSaving(e)
let merge = HistoryEditor.isMerging(e) let merge = HistoryEditor.isMerging(e)
@@ -79,18 +86,17 @@ export const withHistory = <T extends Editor>(editor: T) => {
} else if (operations.length !== 0) { } else if (operations.length !== 0) {
merge = true merge = true
} else { } else {
merge = shouldMerge(op, lastOp) || overwrite merge = shouldMerge(op, lastOp)
} }
} }
if (lastBatch && merge) { if (lastBatch && merge) {
if (overwrite) { lastBatch.operations.push(op)
lastBatch.pop()
}
lastBatch.push(op)
} else { } else {
const batch = [op] const batch = {
operations: [op],
selectionBefore: e.selection,
}
undos.push(batch) undos.push(batch)
} }
@@ -98,9 +104,7 @@ export const withHistory = <T extends Editor>(editor: T) => {
undos.shift() undos.shift()
} }
if (shouldClear(op)) { history.redos = []
history.redos = []
}
} }
apply(op) apply(op)
@@ -114,10 +118,6 @@ export const withHistory = <T extends Editor>(editor: T) => {
*/ */
const shouldMerge = (op: Operation, prev: Operation | undefined): boolean => { const shouldMerge = (op: Operation, prev: Operation | undefined): boolean => {
if (op.type === 'set_selection') {
return true
}
if ( if (
prev && prev &&
op.type === 'insert_text' && op.type === 'insert_text' &&
@@ -146,36 +146,6 @@ const shouldMerge = (op: Operation, prev: Operation | undefined): boolean => {
*/ */
const shouldSave = (op: Operation, prev: Operation | undefined): boolean => { const shouldSave = (op: Operation, prev: Operation | undefined): boolean => {
if (
op.type === 'set_selection' &&
(op.properties == null || op.newProperties == null)
) {
return false
}
return true
}
/**
* Check whether an operation should overwrite the previous one.
*/
const shouldOverwrite = (
op: Operation,
prev: Operation | undefined
): boolean => {
if (prev && op.type === 'set_selection' && prev.type === 'set_selection') {
return true
}
return false
}
/**
* Check whether an operation should clear the redos stack.
*/
const shouldClear = (op: Operation): boolean => {
if (op.type === 'set_selection') { if (op.type === 'set_selection') {
return false return false
} }

View File

@@ -44,6 +44,6 @@ export const output = {
], ],
selection: { selection: {
anchor: { path: [0, 0], offset: 5 }, anchor: { path: [0, 0], offset: 5 },
focus: { path: [0, 0], offset: 5 }, focus: { path: [0, 0], offset: 0 },
}, },
} }