diff --git a/.changeset/chatty-kids-smile.md b/.changeset/chatty-kids-smile.md new file mode 100644 index 000000000..2a3e8ce65 --- /dev/null +++ b/.changeset/chatty-kids-smile.md @@ -0,0 +1,7 @@ +--- +'@plait/core': minor +--- + +improve redos logic to support withNewBatch handle(inspired by slate) + +ref: https://github.com/ianstormtaylor/slate/pull/5747 \ No newline at end of file diff --git a/packages/core/src/interfaces/history.ts b/packages/core/src/interfaces/history.ts index d8cb1a7e2..7304e3617 100644 --- a/packages/core/src/interfaces/history.ts +++ b/packages/core/src/interfaces/history.ts @@ -8,3 +8,5 @@ export interface PlaitHistory { export const SAVING = new WeakMap(); export const MERGING = new WeakMap(); +export const HISTORY = new WeakMap(); +export const SPLITTING_ONCE = new WeakMap(); diff --git a/packages/core/src/plugins/with-history.ts b/packages/core/src/plugins/with-history.ts index 8d4721e76..4ffe0db04 100644 --- a/packages/core/src/plugins/with-history.ts +++ b/packages/core/src/plugins/with-history.ts @@ -66,6 +66,11 @@ export function withHistory(board: T) { } } + if (PlaitHistoryBoard.isSplittingOnce(board)) { + merge = false; + PlaitHistoryBoard.setSplittingOnce(board, undefined); + } + if (lastBatch && merge) { lastBatch.push(op); } else { diff --git a/packages/core/src/utils/history.ts b/packages/core/src/utils/history.ts index 1302c7727..adf49d1cc 100644 --- a/packages/core/src/utils/history.ts +++ b/packages/core/src/utils/history.ts @@ -1,4 +1,6 @@ -import { MERGING, PlaitBoard, PlaitOperation, SAVING } from '../interfaces'; +// Credits to slate - https://github.com/ianstormtaylor/slate + +import { MERGING, PlaitBoard, PlaitOperation, SAVING, SPLITTING_ONCE } from '../interfaces'; /** * Check whether to merge an operation into the previous operation. @@ -51,6 +53,43 @@ export const PlaitHistoryBoard = { return MERGING.get(board); }, + /** + * Get the splitting once flag's current value. + */ + + isSplittingOnce(board: PlaitBoard): boolean | undefined { + return SPLITTING_ONCE.get(board); + }, + + setSplittingOnce(board: PlaitBoard, value: boolean | undefined): void { + SPLITTING_ONCE.set(board, value); + }, + + /** + * Apply a series of changes inside a synchronous `fn`, These operations will + * be merged into the previous history. + */ + withMerging(board: PlaitBoard, fn: () => void): void { + const prev = PlaitHistoryBoard.isMerging(board); + MERGING.set(board, true); + fn(); + MERGING.set(board, prev); + }, + + /** + * Apply a series of changes inside a synchronous `fn`, ensuring that the first + * operation starts a new batch in the history. Subsequent operations will be + * merged as usual. + */ + withNewBatch(board: PlaitBoard, fn: () => void): void { + const prev = PlaitHistoryBoard.isMerging(board); + MERGING.set(board, true); + SPLITTING_ONCE.set(board, true); + fn(); + MERGING.set(board, prev); + SPLITTING_ONCE.delete(board); + }, + /** * Apply a series of changes inside a synchronous `fn`, without merging any of * the new operations into previous save point in the history.