From e6eb277f49df81a6a93575f2c1167ad53d763e1f Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Mon, 6 Sep 2021 13:14:43 +0100 Subject: [PATCH 1/3] Update command ids, add undo/redo stack --- .../state/__snapshots__/tlstate.spec.ts.snap | 63 +++++++++++++++++++ .../src/state/command/align/align.command.ts | 2 +- .../state/command/create/create.command.ts | 2 +- .../state/command/delete/delete.command.ts | 2 +- .../command/distribute/distribute.command.ts | 2 +- .../src/state/command/flip/flip.command.ts | 2 +- .../src/state/command/group/group.command.ts | 2 +- .../src/state/command/move/move.command.ts | 2 +- .../state/command/rotate/rotate.command.ts | 2 +- .../state/command/stretch/stretch.command.ts | 2 +- .../src/state/command/style/style.command.ts | 2 +- .../state/command/toggle/toggle.command.ts | 2 +- .../command/translate/translate.command.ts | 2 +- .../state/command/ungroup/ungroup.command.ts | 2 +- .../state/command/update/update.command.ts | 2 +- packages/tldraw/src/state/tlstate.spec.ts | 12 ++++ packages/tldraw/src/state/tlstate.ts | 7 +++ 17 files changed, 96 insertions(+), 14 deletions(-) diff --git a/packages/tldraw/src/state/__snapshots__/tlstate.spec.ts.snap b/packages/tldraw/src/state/__snapshots__/tlstate.spec.ts.snap index ed667cca7..8f1d066d9 100644 --- a/packages/tldraw/src/state/__snapshots__/tlstate.spec.ts.snap +++ b/packages/tldraw/src/state/__snapshots__/tlstate.spec.ts.snap @@ -3,3 +3,66 @@ exports[` 1`] = `"[]"`; exports[` 2`] = `undefined`; + +exports[`TLDrawState Exposes undo/redo stack: history 1`] = ` +Array [ + Object { + "after": Object { + "document": Object { + "pageStates": Object { + "page1": Object { + "selectedIds": Array [ + "rect1", + ], + }, + }, + "pages": Object { + "page1": Object { + "shapes": Object { + "rect1": Object { + "childIndex": 1, + "id": "rect1", + "name": "Rectangle", + "parentId": "page1", + "point": Array [ + 0, + 0, + ], + "rotation": 0, + "size": Array [ + 100, + 200, + ], + "style": Object { + "color": "Black", + "dash": "Draw", + "isFilled": false, + "size": "Medium", + }, + "type": "rectangle", + }, + }, + }, + }, + }, + }, + "before": Object { + "document": Object { + "pageStates": Object { + "page1": Object { + "selectedIds": Array [], + }, + }, + "pages": Object { + "page1": Object { + "shapes": Object { + "rect1": undefined, + }, + }, + }, + }, + }, + "id": "create", + }, +] +`; diff --git a/packages/tldraw/src/state/command/align/align.command.ts b/packages/tldraw/src/state/command/align/align.command.ts index 9ee5bdd11..cc6437808 100644 --- a/packages/tldraw/src/state/command/align/align.command.ts +++ b/packages/tldraw/src/state/command/align/align.command.ts @@ -50,7 +50,7 @@ export function align(data: Data, ids: string[], type: AlignType): TLDrawCommand ) return { - id: 'align_shapes', + id: 'align', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/create/create.command.ts b/packages/tldraw/src/state/command/create/create.command.ts index 12959acf4..e4749ecf9 100644 --- a/packages/tldraw/src/state/command/create/create.command.ts +++ b/packages/tldraw/src/state/command/create/create.command.ts @@ -14,7 +14,7 @@ export function create(data: Data, shapes: TLDrawShape[]): TLDrawCommand { }) return { - id: 'toggle_shapes', + id: 'create', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/delete/delete.command.ts b/packages/tldraw/src/state/command/delete/delete.command.ts index d9cf709e0..602c5aab9 100644 --- a/packages/tldraw/src/state/command/delete/delete.command.ts +++ b/packages/tldraw/src/state/command/delete/delete.command.ts @@ -12,7 +12,7 @@ export function deleteShapes( const { before, after } = removeShapesFromPage(data, ids, pageId) return { - id: 'delete_shapes', + id: 'delete', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/distribute/distribute.command.ts b/packages/tldraw/src/state/command/distribute/distribute.command.ts index fa73a892e..01d20ba34 100644 --- a/packages/tldraw/src/state/command/distribute/distribute.command.ts +++ b/packages/tldraw/src/state/command/distribute/distribute.command.ts @@ -18,7 +18,7 @@ export function distribute(data: Data, ids: string[], type: DistributeType): TLD ) return { - id: 'distribute_shapes', + id: 'distribute', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/flip/flip.command.ts b/packages/tldraw/src/state/command/flip/flip.command.ts index 1756b2ad2..bae659a32 100644 --- a/packages/tldraw/src/state/command/flip/flip.command.ts +++ b/packages/tldraw/src/state/command/flip/flip.command.ts @@ -58,7 +58,7 @@ export function flip(data: Data, ids: string[], type: FlipType): TLDrawCommand { ) return { - id: 'flip_shapes', + id: 'flip', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/group/group.command.ts b/packages/tldraw/src/state/command/group/group.command.ts index ce4992fb9..74197a30a 100644 --- a/packages/tldraw/src/state/command/group/group.command.ts +++ b/packages/tldraw/src/state/command/group/group.command.ts @@ -188,7 +188,7 @@ export function group( }) return { - id: 'group_shapes', + id: 'group', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/move/move.command.ts b/packages/tldraw/src/state/command/move/move.command.ts index 059933c9b..cfc1683cf 100644 --- a/packages/tldraw/src/state/command/move/move.command.ts +++ b/packages/tldraw/src/state/command/move/move.command.ts @@ -217,7 +217,7 @@ export function move(data: Data, ids: string[], type: MoveType): TLDrawCommand { }) return { - id: 'move_shapes', + id: 'move', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/rotate/rotate.command.ts b/packages/tldraw/src/state/command/rotate/rotate.command.ts index 15318b76b..cc831ffe5 100644 --- a/packages/tldraw/src/state/command/rotate/rotate.command.ts +++ b/packages/tldraw/src/state/command/rotate/rotate.command.ts @@ -44,7 +44,7 @@ export function rotate(data: Data, ids: string[], delta = -PI2 / 4): TLDrawComma ) return { - id: 'toggle_shapes', + id: 'rotate', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/stretch/stretch.command.ts b/packages/tldraw/src/state/command/stretch/stretch.command.ts index 755a41785..4fe738866 100644 --- a/packages/tldraw/src/state/command/stretch/stretch.command.ts +++ b/packages/tldraw/src/state/command/stretch/stretch.command.ts @@ -57,7 +57,7 @@ export function stretch(data: Data, ids: string[], type: StretchType): TLDrawCom ) return { - id: 'stretch_shapes', + id: 'stretch', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/style/style.command.ts b/packages/tldraw/src/state/command/style/style.command.ts index 36bb23ed0..17fe9ba71 100644 --- a/packages/tldraw/src/state/command/style/style.command.ts +++ b/packages/tldraw/src/state/command/style/style.command.ts @@ -14,7 +14,7 @@ export function style(data: Data, ids: string[], changes: Partial): ) return { - id: 'style_shapes', + id: 'style', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/toggle/toggle.command.ts b/packages/tldraw/src/state/command/toggle/toggle.command.ts index 980312117..e15353e79 100644 --- a/packages/tldraw/src/state/command/toggle/toggle.command.ts +++ b/packages/tldraw/src/state/command/toggle/toggle.command.ts @@ -16,7 +16,7 @@ export function toggle(data: Data, ids: string[], prop: keyof TLDrawShape): TLDr ) return { - id: 'toggle_shapes', + id: 'toggle', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/translate/translate.command.ts b/packages/tldraw/src/state/command/translate/translate.command.ts index 5d58cb831..d0e8a1b67 100644 --- a/packages/tldraw/src/state/command/translate/translate.command.ts +++ b/packages/tldraw/src/state/command/translate/translate.command.ts @@ -63,7 +63,7 @@ export function translate(data: Data, ids: string[], delta: number[]): TLDrawCom }) return { - id: 'translate_shapes', + id: 'translate', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/ungroup/ungroup.command.ts b/packages/tldraw/src/state/command/ungroup/ungroup.command.ts index bfe93d7f8..f96fe0471 100644 --- a/packages/tldraw/src/state/command/ungroup/ungroup.command.ts +++ b/packages/tldraw/src/state/command/ungroup/ungroup.command.ts @@ -99,7 +99,7 @@ export function ungroup(data: Data, groupId: string, pageId: string): TLDrawComm }) return { - id: 'ungroup_shapes', + id: 'ungroup', before: { document: { pages: { diff --git a/packages/tldraw/src/state/command/update/update.command.ts b/packages/tldraw/src/state/command/update/update.command.ts index 4e2b43cda..cec3dab88 100644 --- a/packages/tldraw/src/state/command/update/update.command.ts +++ b/packages/tldraw/src/state/command/update/update.command.ts @@ -28,7 +28,7 @@ export function update( after.shapes = change.after return { - id: 'translate_shapes', + id: 'update', before: { document: { pages: { diff --git a/packages/tldraw/src/state/tlstate.spec.ts b/packages/tldraw/src/state/tlstate.spec.ts index ce5bd34cf..ad02a93a3 100644 --- a/packages/tldraw/src/state/tlstate.spec.ts +++ b/packages/tldraw/src/state/tlstate.spec.ts @@ -359,4 +359,16 @@ describe('TLDrawState', () => { expect(tlstate.getShape('rect5').childIndex).toBe(3) }) }) + + it('Exposes undo/redo stack', () => { + const tlstate = new TLDrawState().loadDocument(mockDocument).createShapes({ + id: 'rect1', + type: TLDrawShapeType.Rectangle, + point: [0, 0], + size: [100, 200], + }) + + expect(tlstate.history).toBeDefined() + expect(tlstate.history).toMatchSnapshot('history') + }) }) diff --git a/packages/tldraw/src/state/tlstate.ts b/packages/tldraw/src/state/tlstate.ts index cde252d87..10b836217 100644 --- a/packages/tldraw/src/state/tlstate.ts +++ b/packages/tldraw/src/state/tlstate.ts @@ -646,6 +646,13 @@ export class TLDrawState extends StateManager { return Vec.sub(Vec.div(point, camera.zoom), camera.point) } + /** + * Get the current undo/redo stack. + */ + get history() { + return this.stack + } + /** * The current document. */ From 04b6353e4192aa0d828cf700c58e66853f561d03 Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Mon, 6 Sep 2021 13:43:56 +0100 Subject: [PATCH 2/3] Adds setter for history --- packages/core/package.json | 2 +- packages/tldraw/package.json | 2 +- packages/tldraw/src/state/tlstate.spec.ts | 9 +++++++++ packages/tldraw/src/state/tlstate.ts | 8 ++++++++ yarn.lock | 10 +++++++++- 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index 6eebbdcc9..f7f1314d7 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -23,7 +23,7 @@ "start": "node scripts/dev & yarn types:dev", "build": "node scripts/build && yarn types:build", "types:pre": "tsc", - "types:dev": "tsc --watch ", + "types:dev": "tsc --watch", "types:build": "tsc --project tsconfig.build.json", "lint": "eslint src/ --ext .ts,.tsx", "clean": "rm -rf dist", diff --git a/packages/tldraw/package.json b/packages/tldraw/package.json index 190f830c4..39b7a3034 100644 --- a/packages/tldraw/package.json +++ b/packages/tldraw/package.json @@ -67,6 +67,6 @@ "@tldraw/core": "^0.0.79", "perfect-freehand": "^0.5.3", "react-hotkeys-hook": "^3.4.0", - "rko": "^0.5.22" + "rko": "^0.5.23" } } \ No newline at end of file diff --git a/packages/tldraw/src/state/tlstate.spec.ts b/packages/tldraw/src/state/tlstate.spec.ts index ad02a93a3..b373dc6ee 100644 --- a/packages/tldraw/src/state/tlstate.spec.ts +++ b/packages/tldraw/src/state/tlstate.spec.ts @@ -370,5 +370,14 @@ describe('TLDrawState', () => { expect(tlstate.history).toBeDefined() expect(tlstate.history).toMatchSnapshot('history') + + tlstate.history = [] + expect(tlstate.history).toEqual([]) + + const before = tlstate.state + tlstate.undo() + const after = tlstate.state + + expect(before).toBe(after) }) }) diff --git a/packages/tldraw/src/state/tlstate.ts b/packages/tldraw/src/state/tlstate.ts index 10b836217..2903d7c86 100644 --- a/packages/tldraw/src/state/tlstate.ts +++ b/packages/tldraw/src/state/tlstate.ts @@ -37,6 +37,7 @@ import { TLDrawPage, TLDrawBinding, GroupShape, + TLDrawCommand, } from '~types' import { TLDR } from './tldr' import { defaultStyle } from '~shape' @@ -653,6 +654,13 @@ export class TLDrawState extends StateManager { return this.stack } + /** + * Replace the current history stack. + */ + set history(commands: TLDrawCommand[]) { + this.replaceHistory(commands) + } + /** * The current document. */ diff --git a/yarn.lock b/yarn.lock index bb9359663..01f439817 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11557,7 +11557,7 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rko@^0.5.19, rko@^0.5.20, rko@^0.5.22: +rko@^0.5.19, rko@^0.5.20: version "0.5.22" resolved "https://registry.yarnpkg.com/rko/-/rko-0.5.22.tgz#d5a563beefd97a9cfdda3c29c1fbe119d782b576" integrity sha512-aNXCHTLshLgq6XuWZzb3XKgy5RyS5YY6/YzCnrBa+tn7NTPC2HysbNhJwyt6bow3u8whiD36GajhUYR6oIbJWw== @@ -11565,6 +11565,14 @@ rko@^0.5.19, rko@^0.5.20, rko@^0.5.22: idb-keyval "^5.1.3" zustand "^3.5.9" +rko@^0.5.23: + version "0.5.23" + resolved "https://registry.yarnpkg.com/rko/-/rko-0.5.23.tgz#2613c05d518df71b08215bb031aa4680ede51302" + integrity sha512-u4c2n/99zE+j23WE7FoO5GA4ussYhvhZ5/fh/xJ9ctXyV6Vy+445r2jM2M2xegrCRkIw67RtPI5BmpCXZHnRxA== + dependencies: + idb-keyval "^5.1.3" + zustand "^3.5.9" + rollup-plugin-terser@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" From 16ba3f9b989951f14241444b2a900b22daada99d Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Mon, 6 Sep 2021 13:50:15 +0100 Subject: [PATCH 3/3] Adds setter for history, tests --- .../state/__snapshots__/tlstate.spec.ts.snap | 60 +++++++++++++++ packages/tldraw/src/state/tlstate.spec.ts | 77 +++++++++++++++++-- packages/tldraw/src/state/tlstate.ts | 2 +- 3 files changed, 132 insertions(+), 7 deletions(-) diff --git a/packages/tldraw/src/state/__snapshots__/tlstate.spec.ts.snap b/packages/tldraw/src/state/__snapshots__/tlstate.spec.ts.snap index 8f1d066d9..3ec68c8d1 100644 --- a/packages/tldraw/src/state/__snapshots__/tlstate.spec.ts.snap +++ b/packages/tldraw/src/state/__snapshots__/tlstate.spec.ts.snap @@ -64,5 +64,65 @@ Array [ }, "id": "create", }, + Object { + "after": Object { + "document": Object { + "pageStates": Object { + "page1": Object { + "selectedIds": Array [ + "rect2", + ], + }, + }, + "pages": Object { + "page1": Object { + "shapes": Object { + "rect2": Object { + "childIndex": 1, + "id": "rect2", + "name": "Rectangle", + "parentId": "page1", + "point": Array [ + 0, + 0, + ], + "rotation": 0, + "size": Array [ + 100, + 200, + ], + "style": Object { + "color": "Black", + "dash": "Draw", + "isFilled": false, + "size": "Medium", + }, + "type": "rectangle", + }, + }, + }, + }, + }, + }, + "before": Object { + "document": Object { + "pageStates": Object { + "page1": Object { + "selectedIds": Array [ + "rect1", + ], + }, + }, + "pages": Object { + "page1": Object { + "shapes": Object { + "rect2": undefined, + }, + }, + }, + }, + }, + "id": "create", + }, ] `; diff --git a/packages/tldraw/src/state/tlstate.spec.ts b/packages/tldraw/src/state/tlstate.spec.ts index b373dc6ee..02a59373d 100644 --- a/packages/tldraw/src/state/tlstate.spec.ts +++ b/packages/tldraw/src/state/tlstate.spec.ts @@ -361,12 +361,22 @@ describe('TLDrawState', () => { }) it('Exposes undo/redo stack', () => { - const tlstate = new TLDrawState().loadDocument(mockDocument).createShapes({ - id: 'rect1', - type: TLDrawShapeType.Rectangle, - point: [0, 0], - size: [100, 200], - }) + const tlstate = new TLDrawState() + .loadDocument(mockDocument) + .createShapes({ + id: 'rect1', + type: TLDrawShapeType.Rectangle, + point: [0, 0], + size: [100, 200], + }) + .createShapes({ + id: 'rect2', + type: TLDrawShapeType.Rectangle, + point: [0, 0], + size: [100, 200], + }) + + expect(tlstate.history.length).toBe(2) expect(tlstate.history).toBeDefined() expect(tlstate.history).toMatchSnapshot('history') @@ -380,4 +390,59 @@ describe('TLDrawState', () => { expect(before).toBe(after) }) + + it('Exposes undo/redo stack up to the current pointer', () => { + const tlstate = new TLDrawState() + .loadDocument(mockDocument) + .createShapes({ + id: 'rect1', + type: TLDrawShapeType.Rectangle, + point: [0, 0], + size: [100, 200], + }) + .createShapes({ + id: 'rect2', + type: TLDrawShapeType.Rectangle, + point: [0, 0], + size: [100, 200], + }) + .undo() + + expect(tlstate.history.length).toBe(1) + }) + + it('Sets the undo/redo history', () => { + const tlstate = new TLDrawState('some_state_a') + .createShapes({ + id: 'rect1', + type: TLDrawShapeType.Rectangle, + point: [0, 0], + size: [100, 200], + }) + .createShapes({ + id: 'rect2', + type: TLDrawShapeType.Rectangle, + point: [0, 0], + size: [100, 200], + }) + + // Save the history and document from the first state + const doc = tlstate.document + const history = tlstate.history + + // Create a new state + const tlstate2 = new TLDrawState('some_state_b') + + // Load the document and set the history + tlstate2.loadDocument(doc) + tlstate2.history = history + + expect(tlstate2.shapes.length).toBe(2) + + // We should be able to undo the change that was made on the first + // state, now that we've brought in its undo / redo stack + tlstate2.undo() + + expect(tlstate2.shapes.length).toBe(1) + }) }) diff --git a/packages/tldraw/src/state/tlstate.ts b/packages/tldraw/src/state/tlstate.ts index 2903d7c86..7cb8c1596 100644 --- a/packages/tldraw/src/state/tlstate.ts +++ b/packages/tldraw/src/state/tlstate.ts @@ -651,7 +651,7 @@ export class TLDrawState extends StateManager { * Get the current undo/redo stack. */ get history() { - return this.stack + return this.stack.slice(0, this.pointer + 1) } /**