From 7f00127279d0e6c20549cfdee0c562c8a5927973 Mon Sep 17 00:00:00 2001 From: jelkes1 Date: Sun, 26 Jul 2026 15:59:30 -0700 Subject: [PATCH] fix: preserve undo history after collaboration upgrade --- .../editor-history-snapshot-adapter.test.ts | 20 +++++++++++++++++++ .../editor-history-snapshot-adapter.ts | 12 +++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/packages/super-editor/src/editors/v1/core/presentation-editor/history/editor-history-snapshot-adapter.test.ts b/packages/super-editor/src/editors/v1/core/presentation-editor/history/editor-history-snapshot-adapter.test.ts index a94c000a3a..1846b0d264 100644 --- a/packages/super-editor/src/editors/v1/core/presentation-editor/history/editor-history-snapshot-adapter.test.ts +++ b/packages/super-editor/src/editors/v1/core/presentation-editor/history/editor-history-snapshot-adapter.test.ts @@ -169,6 +169,26 @@ describe('EditorHistorySnapshotAdapter — Yjs-backed editors', () => { }); }); +describe('EditorHistorySnapshotAdapter — late collaboration upgrade', () => { + it('switches to Yjs history after a local editor is upgraded in place', () => { + mockUndoDepth.mockReturnValue(0); + mockRedoDepth.mockReturnValue(0); + mockGetPluginState.mockReturnValue({ + undoManager: { undoStack: [1], redoStack: [] }, + }); + + const editor = buildEditor(); + const adapter = new EditorHistorySnapshotAdapter(editor as Editor); + + editor.options.collaborationProvider = {}; + editor.options.ydoc = {}; + + expect(adapter.getSnapshot()).toEqual({ undoDepth: 1, redoDepth: 0 }); + expect(mockUndoDepth).not.toHaveBeenCalled(); + expect(mockRedoDepth).not.toHaveBeenCalled(); + }); +}); + describe('EditorHistorySnapshotAdapter — command delegation', () => { it('undo() / redo() delegate to the shared history helpers', () => { mockRunEditorUndo.mockReturnValue(true); diff --git a/packages/super-editor/src/editors/v1/core/presentation-editor/history/editor-history-snapshot-adapter.ts b/packages/super-editor/src/editors/v1/core/presentation-editor/history/editor-history-snapshot-adapter.ts index 288b8e02b1..4a04411a60 100644 --- a/packages/super-editor/src/editors/v1/core/presentation-editor/history/editor-history-snapshot-adapter.ts +++ b/packages/super-editor/src/editors/v1/core/presentation-editor/history/editor-history-snapshot-adapter.ts @@ -1,10 +1,10 @@ /** * Snapshot adapter that works for both PM-history-backed and Yjs-backed editors. * - * The backend type is determined once per editor by whether it was created - * with a `collaborationProvider` + `ydoc` pair. We keep one adapter class - * instead of two because the surface difference is small — read depth from - * the right stack, delegate undo/redo to `runEditorUndo` / `runEditorRedo`. + * The backend type is determined from the editor's current options whenever + * a snapshot is read. This allows an adapter created for a local editor to + * switch to Yjs history after `upgradeToCollaboration()` attaches a provider + * and ydoc in place. */ import { undoDepth, redoDepth } from 'prosemirror-history'; @@ -65,16 +65,14 @@ export const readEditorHistorySnapshot = (editor: Editor): ParticipantHistorySna */ export class EditorHistorySnapshotAdapter implements HistorySnapshotAdapter { readonly #editor: Editor; - readonly #collaborative: boolean; #pendingChangeKind: ParticipantHistoryChangeKind = 'unknown'; constructor(editor: Editor) { this.#editor = editor; - this.#collaborative = isYjsBacked(editor); } getSnapshot(): ParticipantHistorySnapshot { - if (this.#collaborative) { + if (isYjsBacked(this.#editor)) { return readYjsDepths(this.#editor); } return readPmDepths(this.#editor);