Merge pull request #78 from tldraw/feature]-add-history-(public-undo/redo-stack)
Update command ids, add undo/redo stack
This commit is contained in:
commit
0c79bbce56
20 changed files with 249 additions and 17 deletions
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -3,3 +3,126 @@
|
|||
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",
|
||||
},
|
||||
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",
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
|
|
@ -50,7 +50,7 @@ export function align(data: Data, ids: string[], type: AlignType): TLDrawCommand
|
|||
)
|
||||
|
||||
return {
|
||||
id: 'align_shapes',
|
||||
id: 'align',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -14,7 +14,7 @@ export function create(data: Data, shapes: TLDrawShape[]): TLDrawCommand {
|
|||
})
|
||||
|
||||
return {
|
||||
id: 'toggle_shapes',
|
||||
id: 'create',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -12,7 +12,7 @@ export function deleteShapes(
|
|||
const { before, after } = removeShapesFromPage(data, ids, pageId)
|
||||
|
||||
return {
|
||||
id: 'delete_shapes',
|
||||
id: 'delete',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -18,7 +18,7 @@ export function distribute(data: Data, ids: string[], type: DistributeType): TLD
|
|||
)
|
||||
|
||||
return {
|
||||
id: 'distribute_shapes',
|
||||
id: 'distribute',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -58,7 +58,7 @@ export function flip(data: Data, ids: string[], type: FlipType): TLDrawCommand {
|
|||
)
|
||||
|
||||
return {
|
||||
id: 'flip_shapes',
|
||||
id: 'flip',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -188,7 +188,7 @@ export function group(
|
|||
})
|
||||
|
||||
return {
|
||||
id: 'group_shapes',
|
||||
id: 'group',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -217,7 +217,7 @@ export function move(data: Data, ids: string[], type: MoveType): TLDrawCommand {
|
|||
})
|
||||
|
||||
return {
|
||||
id: 'move_shapes',
|
||||
id: 'move',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -44,7 +44,7 @@ export function rotate(data: Data, ids: string[], delta = -PI2 / 4): TLDrawComma
|
|||
)
|
||||
|
||||
return {
|
||||
id: 'toggle_shapes',
|
||||
id: 'rotate',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -57,7 +57,7 @@ export function stretch(data: Data, ids: string[], type: StretchType): TLDrawCom
|
|||
)
|
||||
|
||||
return {
|
||||
id: 'stretch_shapes',
|
||||
id: 'stretch',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -14,7 +14,7 @@ export function style(data: Data, ids: string[], changes: Partial<ShapeStyles>):
|
|||
)
|
||||
|
||||
return {
|
||||
id: 'style_shapes',
|
||||
id: 'style',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -16,7 +16,7 @@ export function toggle(data: Data, ids: string[], prop: keyof TLDrawShape): TLDr
|
|||
)
|
||||
|
||||
return {
|
||||
id: 'toggle_shapes',
|
||||
id: 'toggle',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -63,7 +63,7 @@ export function translate(data: Data, ids: string[], delta: number[]): TLDrawCom
|
|||
})
|
||||
|
||||
return {
|
||||
id: 'translate_shapes',
|
||||
id: 'translate',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -99,7 +99,7 @@ export function ungroup(data: Data, groupId: string, pageId: string): TLDrawComm
|
|||
})
|
||||
|
||||
return {
|
||||
id: 'ungroup_shapes',
|
||||
id: 'ungroup',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -28,7 +28,7 @@ export function update(
|
|||
after.shapes = change.after
|
||||
|
||||
return {
|
||||
id: 'translate_shapes',
|
||||
id: 'update',
|
||||
before: {
|
||||
document: {
|
||||
pages: {
|
||||
|
|
|
@ -359,4 +359,90 @@ 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],
|
||||
})
|
||||
.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')
|
||||
|
||||
tlstate.history = []
|
||||
expect(tlstate.history).toEqual([])
|
||||
|
||||
const before = tlstate.state
|
||||
tlstate.undo()
|
||||
const after = tlstate.state
|
||||
|
||||
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)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -37,6 +37,7 @@ import {
|
|||
TLDrawPage,
|
||||
TLDrawBinding,
|
||||
GroupShape,
|
||||
TLDrawCommand,
|
||||
} from '~types'
|
||||
import { TLDR } from './tldr'
|
||||
import { defaultStyle } from '~shape'
|
||||
|
@ -646,6 +647,20 @@ export class TLDrawState extends StateManager<Data> {
|
|||
return Vec.sub(Vec.div(point, camera.zoom), camera.point)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current undo/redo stack.
|
||||
*/
|
||||
get history() {
|
||||
return this.stack.slice(0, this.pointer + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the current history stack.
|
||||
*/
|
||||
set history(commands: TLDrawCommand[]) {
|
||||
this.replaceHistory(commands)
|
||||
}
|
||||
|
||||
/**
|
||||
* The current document.
|
||||
*/
|
||||
|
|
10
yarn.lock
10
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"
|
||||
|
|
Loading…
Reference in a new issue