Implement document-wide undo/redo

Snapshot-based, like the existing JSON export/import round-trip
(snapshot()/replaceDocument()) rather than a patch/command log -- simple and
provably correct for a document this size.

- document.ts: a deep watch on `doc` tracks a "content fingerprint" (sheets +
  locale + csvDelimiter, deliberately excluding selection/activeObjectId, so
  moving the cursor is never an undo step) and debounces commits by 150ms --
  long enough to coalesce a resize-drag's per-mousemove calls into one step,
  short enough that two genuinely separate quick actions don't merge. A new
  edit after an undo immediately drops the redo branch (not debounced, so a
  bound button is never briefly wrong). undo()/redo() flush any pending
  change first, then pop/apply a snapshot via a new applyDocumentState() core
  that replaceDocument() also uses -- replaceDocument() (JSON import
  "replace", "reset to seed") additionally resets history, since loading a
  different document shouldn't leave the old one undoable into it; undo/redo
  themselves must not (that's the very stack they're unwinding).
- TableGrid.vue: Strg/Cmd+Z undoes, Strg/Cmd+Y or +Shift+Z redoes, deferring
  to a cell editor's native undo while one is open (the existing `if
  (editing.value) return` guard already covers this).
- App.vue: a window-level fallback for when no table has focus, skipped
  whenever focus sits in any text field so their own native undo keeps
  working.
- AppToolbar.vue: ↶/↷ buttons, disabled via store.canUndo/canRedo.

Verified interactively against the dev server with Playwright: the toolbar
button enables the instant a change happens (not after the debounce);
separately-timed edits each undo as their own step; a multi-tick resize drag
undoes in one step back to the original width; Ctrl+Z, Ctrl+Y and the
toolbar buttons all work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
wkh
2026-09-02 14:19:43 +02:00
co-authored by Claude Sonnet 5
parent 67b011637d
commit 5a06d08a6a
6 changed files with 351 additions and 5 deletions
+10
View File
@@ -736,6 +736,16 @@ function onKeydown(e: KeyboardEvent) {
e.stopPropagation();
return store.pasteClipboard();
}
if (k === 'z' && !e.shiftKey) {
e.preventDefault();
e.stopPropagation();
return store.undo();
}
if ((k === 'z' && e.shiftKey) || k === 'y') {
e.preventDefault();
e.stopPropagation();
return store.redo();
}
}
switch (e.key) {