From 5b9009a823411207cdbbf8628267061b755eeda0 Mon Sep 17 00:00:00 2001 From: Miguel Angel Simon Sierra Date: Fri, 2 Oct 2026 03:11:56 -0700 Subject: [PATCH] fix(studio): undo takes back the edit pending at the key even after a later edit claims --- .../hooks/usePersistentEditHistory.test.ts | 23 +++++++++++++++++++ .../src/hooks/usePersistentEditHistory.ts | 10 ++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/packages/studio/src/hooks/usePersistentEditHistory.test.ts b/packages/studio/src/hooks/usePersistentEditHistory.test.ts index 1497865c2a..71c8e115f3 100644 --- a/packages/studio/src/hooks/usePersistentEditHistory.test.ts +++ b/packages/studio/src/hooks/usePersistentEditHistory.test.ts @@ -116,6 +116,29 @@ it("undoes the edit claimed since the key, not a later edit the server took in f expect(readFileSync(join(dir, "card.html"), "utf8")).toBe("Y"); }); +it("undoes the edit pending at the key even when a later edit claims before the step", async () => { + const { dir, hook, file, save, readFile } = await studio(); + const atKey = hook().claims(); + save("B"); + await act(() => + hook().recordEdit({ + label: "Moved Title", + files: { "index.html": { before: "A", after: "B" } }, + }), + ); + writeFileSync(join(dir, "card.html"), "Y"); + await act(() => + hook().recordEdit({ label: "Added Card", files: { "card.html": { before: "", after: "Y" } } }), + ); + + const undone = await act(() => + hook().undo({ readFile, serialize: (_, task) => task(), claimedAfter: atKey }), + ); + expect(undone).toMatchObject({ ok: true, label: "Undid: Moved Title" }); + expect(file()).toBe("A"); + expect(readFileSync(join(dir, "card.html"), "utf8")).toBe("Y"); +}); + it("a drag's edits under one key undo as one step, even before the drag goes idle", async () => { const { hook, file, save, readFile } = await studio(); const writes: Array<[before: string, after: string]> = [ diff --git a/packages/studio/src/hooks/usePersistentEditHistory.ts b/packages/studio/src/hooks/usePersistentEditHistory.ts index 4e5570f985..831e08065e 100644 --- a/packages/studio/src/hooks/usePersistentEditHistory.ts +++ b/packages/studio/src/hooks/usePersistentEditHistory.ts @@ -55,7 +55,7 @@ function createOwnHistory() { const own = new Map(); let next: Record<"undo" | "redo", NextStep | null> | null = null; let changes = 0; - let claimed = { count: 0, id: "" }; + const claims: string[] = []; const remember = (id: string, files: OwnFiles) => { const known = own.get(id) ?? {}; for (const [path, { before, after }] of Object.entries(files)) { @@ -76,11 +76,9 @@ function createOwnHistory() { if (seen === changes) next = { undo: view.back, redo: view.forward }; }, changes: () => changes, - claimCount: () => claimed.count, - claimedAfter: (count: number) => (claimed.count > count ? claimed.id : null), - noteClaim: (id: string) => { - claimed = { count: claimed.count + 1, id }; - }, + claimCount: () => claims.length, + claimedAfter: (count: number) => claims[count] ?? null, + noteClaim: (id: string) => claims.push(id), stepped: (entry: { id: string; undoes?: string }) => { const undone = entry.undoes ? own.get(entry.undoes) : undefined; if (!undone) return;