Merge pull request #31 from tldraw/testing-30-transform-command
Adds testMode, tests for transform
This commit is contained in:
commit
b2904d6a1e
40 changed files with 1796 additions and 231 deletions
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
|
@ -12,3 +12,5 @@ jobs:
|
|||
uses: mattallty/jest-github-action@v1.0.3
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
test-command: 'yarn test'
|
||||
|
|
|
@ -15,8 +15,8 @@
|
|||
"name": "Rectangle",
|
||||
"parentId": "page1",
|
||||
"childIndex": 3,
|
||||
"point": [171.47, 288.63],
|
||||
"size": [176.22, 192.26],
|
||||
"point": [100, 100],
|
||||
"size": [100, 100],
|
||||
"radius": 2,
|
||||
"rotation": 0,
|
||||
"style": {
|
||||
|
@ -32,8 +32,8 @@
|
|||
"name": "Rectangle",
|
||||
"parentId": "page1",
|
||||
"childIndex": 4,
|
||||
"point": [511.7, 404.19],
|
||||
"size": [181.08999999999992, 150.40999999999997],
|
||||
"point": [500, 400],
|
||||
"size": [200, 200],
|
||||
"radius": 2,
|
||||
"rotation": 0,
|
||||
"style": {
|
||||
|
|
|
@ -64,14 +64,14 @@ for (let i = 0; i < count; i++) {
|
|||
"name": "Rectangle",
|
||||
"parentId": "page1",
|
||||
"point": Array [
|
||||
511.7,
|
||||
404.19,
|
||||
500,
|
||||
400,
|
||||
],
|
||||
"radius": 2,
|
||||
"rotation": 0,
|
||||
"size": Array [
|
||||
181.08999999999992,
|
||||
150.40999999999997,
|
||||
200,
|
||||
200,
|
||||
],
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
|
@ -330,14 +330,14 @@ for (let i = 0; i < count; i++) {
|
|||
"name": "Rectangle",
|
||||
"parentId": "page1",
|
||||
"point": Array [
|
||||
171.47,
|
||||
288.63,
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"radius": 2,
|
||||
"rotation": 0,
|
||||
"size": Array [
|
||||
176.22,
|
||||
192.26,
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
|
@ -468,14 +468,14 @@ for (let i = 0; i < count; i++) {
|
|||
"name": "Rectangle",
|
||||
"parentId": "page1",
|
||||
"point": Array [
|
||||
511.7,
|
||||
404.19,
|
||||
500,
|
||||
400,
|
||||
],
|
||||
"radius": 2,
|
||||
"rotation": 0,
|
||||
"size": Array [
|
||||
181.08999999999992,
|
||||
150.40999999999997,
|
||||
200,
|
||||
200,
|
||||
],
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
|
@ -734,14 +734,14 @@ for (let i = 0; i < count; i++) {
|
|||
"name": "Rectangle",
|
||||
"parentId": "page1",
|
||||
"point": Array [
|
||||
171.47,
|
||||
288.63,
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"radius": 2,
|
||||
"rotation": 0,
|
||||
"size": Array [
|
||||
176.22,
|
||||
192.26,
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"style": Object {
|
||||
"color": "Black",
|
||||
|
|
852
__tests__/commands/__snapshots__/transform.test.ts.snap
Normal file
852
__tests__/commands/__snapshots__/transform.test.ts.snap
Normal file
|
@ -0,0 +1,852 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms corners 1`] = `
|
||||
Object {
|
||||
"height": 593.73,
|
||||
"maxX": 700,
|
||||
"maxY": 600,
|
||||
"minX": -12.476,
|
||||
"minY": 6.27,
|
||||
"width": 712.476,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms corners 2`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
-12.476,
|
||||
6.27,
|
||||
],
|
||||
"size": Array [
|
||||
118.75,
|
||||
118.75,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
462.51,
|
||||
362.51,
|
||||
],
|
||||
"size": Array [
|
||||
237.49,
|
||||
237.49,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms corners 3`] = `
|
||||
Object {
|
||||
"height": 531.6320000000001,
|
||||
"maxX": 737.9599999999999,
|
||||
"maxY": 600,
|
||||
"minX": 100,
|
||||
"minY": 68.368,
|
||||
"width": 637.9599999999999,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms corners 4`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
68.368,
|
||||
],
|
||||
"size": Array [
|
||||
106.33,
|
||||
106.33,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
525.31,
|
||||
387.35,
|
||||
],
|
||||
"size": Array [
|
||||
212.65,
|
||||
212.65,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms corners 5`] = `
|
||||
Object {
|
||||
"height": 533.62,
|
||||
"maxX": 740.3499999999999,
|
||||
"maxY": 633.62,
|
||||
"minX": 100,
|
||||
"minY": 100,
|
||||
"width": 640.3499999999999,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms corners 6`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
106.72,
|
||||
106.72,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
526.9,
|
||||
420.17,
|
||||
],
|
||||
"size": Array [
|
||||
213.45,
|
||||
213.45,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms corners 7`] = `
|
||||
Object {
|
||||
"height": 490.52,
|
||||
"maxX": 700,
|
||||
"maxY": 590.52,
|
||||
"minX": 111.38,
|
||||
"minY": 100,
|
||||
"width": 588.62,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms corners 8`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
111.38,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
98.104,
|
||||
98.104,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
503.79,
|
||||
394.31,
|
||||
],
|
||||
"size": Array [
|
||||
196.21,
|
||||
196.21,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms edges 1`] = `
|
||||
Object {
|
||||
"height": 593.73,
|
||||
"maxX": 756.24,
|
||||
"maxY": 600,
|
||||
"minX": 43.762,
|
||||
"minY": 6.27,
|
||||
"width": 712.4780000000001,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms edges 2`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
43.762,
|
||||
6.27,
|
||||
],
|
||||
"size": Array [
|
||||
118.75,
|
||||
118.75,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
518.75,
|
||||
362.51,
|
||||
],
|
||||
"size": Array [
|
||||
237.49,
|
||||
237.49,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms edges 3`] = `
|
||||
Object {
|
||||
"height": 531.6260000000001,
|
||||
"maxX": 737.9599999999999,
|
||||
"maxY": 615.8100000000001,
|
||||
"minX": 100,
|
||||
"minY": 84.184,
|
||||
"width": 637.9599999999999,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms edges 4`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
84.184,
|
||||
],
|
||||
"size": Array [
|
||||
106.33,
|
||||
106.33,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
525.31,
|
||||
403.16,
|
||||
],
|
||||
"size": Array [
|
||||
212.65,
|
||||
212.65,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms edges 5`] = `
|
||||
Object {
|
||||
"height": 411.35,
|
||||
"maxX": 646.81,
|
||||
"maxY": 511.35,
|
||||
"minX": 153.19,
|
||||
"minY": 100,
|
||||
"width": 493.61999999999995,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms edges 6`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
153.19,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
82.269,
|
||||
82.269,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
482.27,
|
||||
346.81,
|
||||
],
|
||||
"size": Array [
|
||||
164.54,
|
||||
164.54,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms edges 7`] = `
|
||||
Object {
|
||||
"height": 490.52,
|
||||
"maxX": 700,
|
||||
"maxY": 595.26,
|
||||
"minX": 111.38,
|
||||
"minY": 104.74,
|
||||
"width": 588.62,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests shift-transforms edges 8`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
111.38,
|
||||
104.74,
|
||||
],
|
||||
"size": Array [
|
||||
98.104,
|
||||
98.104,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
503.79,
|
||||
399.05,
|
||||
],
|
||||
"size": Array [
|
||||
196.21,
|
||||
196.21,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms corners 1`] = `
|
||||
Object {
|
||||
"height": 593.73,
|
||||
"maxX": 700,
|
||||
"maxY": 600,
|
||||
"minX": 27.892,
|
||||
"minY": 6.27,
|
||||
"width": 672.108,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms corners 2`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
27.892,
|
||||
6.27,
|
||||
],
|
||||
"size": Array [
|
||||
112.02,
|
||||
118.75,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
475.96,
|
||||
362.51,
|
||||
],
|
||||
"size": Array [
|
||||
224.04,
|
||||
237.49,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms corners 3`] = `
|
||||
Object {
|
||||
"height": 490.17,
|
||||
"maxX": 737.9599999999999,
|
||||
"maxY": 600,
|
||||
"minX": 100,
|
||||
"minY": 109.83,
|
||||
"width": 637.9599999999999,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms corners 4`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
109.83,
|
||||
],
|
||||
"size": Array [
|
||||
106.33,
|
||||
98.034,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
525.31,
|
||||
403.93,
|
||||
],
|
||||
"size": Array [
|
||||
212.65,
|
||||
196.07,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms corners 5`] = `
|
||||
Object {
|
||||
"height": 411.35,
|
||||
"maxX": 740.3499999999999,
|
||||
"maxY": 511.35,
|
||||
"minX": 100,
|
||||
"minY": 100,
|
||||
"width": 640.3499999999999,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms corners 6`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
106.72,
|
||||
82.269,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
526.9,
|
||||
346.81,
|
||||
],
|
||||
"size": Array [
|
||||
213.45,
|
||||
164.54,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms corners 7`] = `
|
||||
Object {
|
||||
"height": 437.4,
|
||||
"maxX": 700,
|
||||
"maxY": 537.4,
|
||||
"minX": 111.38,
|
||||
"minY": 100,
|
||||
"width": 588.62,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms corners 8`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
111.38,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
98.104,
|
||||
87.479,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
503.79,
|
||||
362.44,
|
||||
],
|
||||
"size": Array [
|
||||
196.21,
|
||||
174.96,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms edges 1`] = `
|
||||
Object {
|
||||
"height": 593.73,
|
||||
"maxX": 700,
|
||||
"maxY": 600,
|
||||
"minX": 100,
|
||||
"minY": 6.27,
|
||||
"width": 600,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms edges 2`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
6.27,
|
||||
],
|
||||
"size": Array [
|
||||
100,
|
||||
118.75,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
500,
|
||||
362.51,
|
||||
],
|
||||
"size": Array [
|
||||
200,
|
||||
237.49,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms edges 3`] = `
|
||||
Object {
|
||||
"height": 500,
|
||||
"maxX": 737.9599999999999,
|
||||
"maxY": 600,
|
||||
"minX": 100,
|
||||
"minY": 100,
|
||||
"width": 637.9599999999999,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms edges 4`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
106.33,
|
||||
100,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
525.31,
|
||||
400,
|
||||
],
|
||||
"size": Array [
|
||||
212.65,
|
||||
200,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms edges 5`] = `
|
||||
Object {
|
||||
"height": 411.35,
|
||||
"maxX": 700,
|
||||
"maxY": 511.35,
|
||||
"minX": 100,
|
||||
"minY": 100,
|
||||
"width": 600,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms edges 6`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
100,
|
||||
82.269,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
500,
|
||||
346.81,
|
||||
],
|
||||
"size": Array [
|
||||
200,
|
||||
164.54,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms edges 7`] = `
|
||||
Object {
|
||||
"height": 500,
|
||||
"maxX": 700,
|
||||
"maxY": 600,
|
||||
"minX": 111.38,
|
||||
"minY": 100,
|
||||
"width": 588.62,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command snapshot tests transforms edges 8`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
111.38,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
98.104,
|
||||
100,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
503.79,
|
||||
400,
|
||||
],
|
||||
"size": Array [
|
||||
196.21,
|
||||
200,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command transforms from the bottom edge 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
100,
|
||||
120,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
500,
|
||||
460,
|
||||
],
|
||||
"size": Array [
|
||||
200,
|
||||
240,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command transforms from the bottom-left corner 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
200,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
83.333,
|
||||
120,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
533.33,
|
||||
460,
|
||||
],
|
||||
"size": Array [
|
||||
166.67,
|
||||
240,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command transforms from the bottom-right corner 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
116.67,
|
||||
120,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
566.67,
|
||||
460,
|
||||
],
|
||||
"size": Array [
|
||||
233.33,
|
||||
240,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command transforms from the left edge 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
200,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
83.333,
|
||||
100,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
533.33,
|
||||
400,
|
||||
],
|
||||
"size": Array [
|
||||
166.67,
|
||||
200,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command transforms from the right edge 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
116.67,
|
||||
100,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
566.67,
|
||||
400,
|
||||
],
|
||||
"size": Array [
|
||||
233.33,
|
||||
200,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command transforms from the top edge 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
200,
|
||||
],
|
||||
"size": Array [
|
||||
100,
|
||||
80,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
500,
|
||||
440,
|
||||
],
|
||||
"size": Array [
|
||||
200,
|
||||
160,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command transforms from the top-left corner 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
200,
|
||||
200,
|
||||
],
|
||||
"size": Array [
|
||||
83.333,
|
||||
80,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
533.33,
|
||||
440,
|
||||
],
|
||||
"size": Array [
|
||||
166.67,
|
||||
160,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command transforms from the top-right corner 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
200,
|
||||
],
|
||||
"size": Array [
|
||||
116.67,
|
||||
80,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
566.67,
|
||||
440,
|
||||
],
|
||||
"size": Array [
|
||||
233.33,
|
||||
160,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command when transforming from the bottom-right corner does command 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
116.67,
|
||||
120,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
566.67,
|
||||
460,
|
||||
],
|
||||
"size": Array [
|
||||
233.33,
|
||||
240,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command when transforming from the bottom-right corner re-does command 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
116.67,
|
||||
120,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
566.67,
|
||||
460,
|
||||
],
|
||||
"size": Array [
|
||||
233.33,
|
||||
240,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`transform command when transforming from the bottom-right corner un-does command 1`] = `
|
||||
Object {
|
||||
"rect1": Object {
|
||||
"point": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
"size": Array [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
},
|
||||
"rect2": Object {
|
||||
"point": Array [
|
||||
500,
|
||||
400,
|
||||
],
|
||||
"size": Array [
|
||||
200,
|
||||
200,
|
||||
],
|
||||
},
|
||||
}
|
||||
`;
|
40
__tests__/commands/align.test.ts
Normal file
40
__tests__/commands/align.test.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('align command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
describe('when one item is selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when multiple items are selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
})
|
21
__tests__/commands/change-page.ts
Normal file
21
__tests__/commands/change-page.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('change page command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
57
__tests__/commands/delete-page.ts
Normal file
57
__tests__/commands/delete-page.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('delete page command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
describe('when last page is selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when first page is selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when project only has one page', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
})
|
40
__tests__/commands/delete-selected.ts
Normal file
40
__tests__/commands/delete-selected.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('delete-selected command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
describe('when one item is selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when multiple items are selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,7 +1,7 @@
|
|||
import { ShapeType } from 'types'
|
||||
import TestState, { rectangleId, arrowId } from './test-utils'
|
||||
import TestState, { rectangleId, arrowId } from '../test-utils'
|
||||
|
||||
describe('deleting single shapes', () => {
|
||||
describe('delete command', () => {
|
||||
const tt = new TestState()
|
||||
|
||||
describe('deleting single shapes', () => {
|
37
__tests__/commands/distribute.ts
Normal file
37
__tests__/commands/distribute.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('distribute command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
describe('when one item is selected', () => {
|
||||
it('does not change anything', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when two items are selected', () => {
|
||||
it('does not change anything', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when three or more items are selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
})
|
21
__tests__/commands/draw.ts
Normal file
21
__tests__/commands/draw.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('draw command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
40
__tests__/commands/duplicate.ts
Normal file
40
__tests__/commands/duplicate.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('duplicate command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
describe('when one item is selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when multiple items are selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
})
|
21
__tests__/commands/edit.ts
Normal file
21
__tests__/commands/edit.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('edit command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
21
__tests__/commands/generate.ts
Normal file
21
__tests__/commands/generate.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('generate command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
40
__tests__/commands/group.ts
Normal file
40
__tests__/commands/group.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('group command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
describe('when one item is selected', () => {
|
||||
it('does not change anything', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when multiple items are selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
it('groups shapes with different parents', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('does not group a parent group shape and its child', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
40
__tests__/commands/move-to-page.ts
Normal file
40
__tests__/commands/move-to-page.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import TestState from '../test-utils'
|
||||
|
||||
describe('move-to-page command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
describe('when one item is selected', () => {
|
||||
it('does not change anything', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('when multiple items are selected', () => {
|
||||
it('does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
it('reparents children of groups to page', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('correctly preserves moved groups', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
347
__tests__/commands/transform.test.ts
Normal file
347
__tests__/commands/transform.test.ts
Normal file
|
@ -0,0 +1,347 @@
|
|||
import { Corner, Edge, RectangleShape, ShapeType } from 'types'
|
||||
import { rng } from 'utils'
|
||||
import TestState from '../test-utils'
|
||||
|
||||
describe('transform command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
.createShape(
|
||||
{
|
||||
type: ShapeType.Rectangle,
|
||||
point: [100, 100],
|
||||
size: [100, 100],
|
||||
childIndex: 1,
|
||||
},
|
||||
'rect1'
|
||||
)
|
||||
.createShape(
|
||||
{
|
||||
type: ShapeType.Rectangle,
|
||||
point: [500, 400],
|
||||
size: [200, 200],
|
||||
childIndex: 2,
|
||||
},
|
||||
'rect2'
|
||||
)
|
||||
.clickShape('rect1')
|
||||
.clickShape('rect2', { shiftKey: true })
|
||||
.save()
|
||||
|
||||
function getSnapInfo() {
|
||||
return {
|
||||
rect1: {
|
||||
point: tt.getShape<RectangleShape>('rect1').point,
|
||||
size: tt.getShape<RectangleShape>('rect1').size,
|
||||
},
|
||||
rect2: {
|
||||
point: tt.getShape<RectangleShape>('rect2').point,
|
||||
size: tt.getShape<RectangleShape>('rect2').size,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
it('sets up initial bounds', () => {
|
||||
expect(tt.selectedIds).toEqual(['rect1', 'rect2'])
|
||||
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 100,
|
||||
minY: 100,
|
||||
maxX: 700,
|
||||
maxY: 600,
|
||||
width: 600,
|
||||
height: 500,
|
||||
})
|
||||
})
|
||||
|
||||
describe('when transforming from the bottom-right corner', () => {
|
||||
it('does command', () => {
|
||||
// Restore the saved data state, with the initial selection
|
||||
tt.restore()
|
||||
|
||||
// Move the bounds handle
|
||||
tt.startClickingBoundsHandle(Corner.BottomRight)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 100,
|
||||
minY: 100,
|
||||
maxX: 800,
|
||||
maxY: 700,
|
||||
width: 700,
|
||||
height: 600,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('un-does command', () => {
|
||||
// Repeat the same actions, but add an undo at the end
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Corner.BottomRight)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
.undo()
|
||||
|
||||
// Expect the bounds to be the initial bounds
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 100,
|
||||
minY: 100,
|
||||
maxX: 700,
|
||||
maxY: 600,
|
||||
width: 600,
|
||||
height: 500,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('re-does command', () => {
|
||||
// Repeat the same actions but add an undo and a redo at the end
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Corner.BottomRight)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
.undo()
|
||||
.redo()
|
||||
|
||||
// Expect the bounds to be the transformed bounds
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 100,
|
||||
minY: 100,
|
||||
maxX: 800,
|
||||
maxY: 700,
|
||||
width: 700,
|
||||
height: 600,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
// From here on, let's assume that the undo and redos work as expected,
|
||||
// so let's only test the command's execution.
|
||||
|
||||
it('transforms from the top edge', () => {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Edge.Top)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 100,
|
||||
minY: 200,
|
||||
maxX: 700,
|
||||
maxY: 600,
|
||||
width: 600,
|
||||
height: 400,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('transforms from the right edge', () => {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Edge.Right)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 100,
|
||||
minY: 100,
|
||||
maxX: 800,
|
||||
maxY: 600,
|
||||
width: 700,
|
||||
height: 500,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('transforms from the bottom edge', () => {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Edge.Bottom)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 100,
|
||||
minY: 100,
|
||||
maxX: 700,
|
||||
maxY: 700,
|
||||
width: 600,
|
||||
height: 600,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('transforms from the left edge', () => {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Edge.Left)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 200,
|
||||
minY: 100,
|
||||
maxX: 700,
|
||||
maxY: 600,
|
||||
width: 500,
|
||||
height: 500,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('transforms from the top-left corner', () => {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Corner.TopLeft)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 200,
|
||||
minY: 200,
|
||||
maxX: 700,
|
||||
maxY: 600,
|
||||
width: 500,
|
||||
height: 400,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('transforms from the top-right corner', () => {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Corner.TopRight)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 100,
|
||||
minY: 200,
|
||||
maxX: 800,
|
||||
maxY: 600,
|
||||
width: 700,
|
||||
height: 400,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('transforms from the bottom-right corner', () => {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Corner.BottomRight)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 100,
|
||||
minY: 100,
|
||||
maxX: 800,
|
||||
maxY: 700,
|
||||
width: 700,
|
||||
height: 600,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('transforms from the bottom-left corner', () => {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(Corner.BottomLeft)
|
||||
.movePointerBy([100, 100])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchObject({
|
||||
minX: 200,
|
||||
minY: 100,
|
||||
maxX: 700,
|
||||
maxY: 700,
|
||||
width: 500,
|
||||
height: 600,
|
||||
})
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
})
|
||||
|
||||
describe('snapshot tests', () => {
|
||||
it('transforms corners', () => {
|
||||
const getRandom = rng('transform-tests-random-number-generator')
|
||||
|
||||
for (const corner of Object.values(Corner)) {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(corner)
|
||||
.movePointerBy([getRandom() * 200, getRandom() * 200])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchSnapshot()
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
}
|
||||
})
|
||||
|
||||
it('transforms edges', () => {
|
||||
const getRandom = rng('transform-tests-random-number-generator')
|
||||
|
||||
for (const edge of Object.values(Edge)) {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(edge)
|
||||
.movePointerBy([getRandom() * 200, getRandom() * 200])
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchSnapshot()
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
}
|
||||
})
|
||||
|
||||
it('shift-transforms corners', () => {
|
||||
const getRandom = rng('transform-tests-random-number-generator')
|
||||
|
||||
for (const corner of Object.values(Corner)) {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(corner)
|
||||
.movePointerBy([getRandom() * 200, getRandom() * 200], {
|
||||
shiftKey: true,
|
||||
})
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchSnapshot()
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
}
|
||||
})
|
||||
|
||||
it('shift-transforms edges', () => {
|
||||
const getRandom = rng('transform-tests-random-number-generator')
|
||||
|
||||
for (const edge of Object.values(Edge)) {
|
||||
tt.restore()
|
||||
.startClickingBoundsHandle(edge)
|
||||
.movePointerBy([getRandom() * 200, getRandom() * 200], {
|
||||
shiftKey: true,
|
||||
})
|
||||
.stopClickingBounds()
|
||||
|
||||
// Ensure the bounds have been transformed
|
||||
expect(tt.state.values.selectedBounds).toMatchSnapshot()
|
||||
|
||||
expect(getSnapInfo()).toMatchSnapshot()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
|
@ -1,11 +1,9 @@
|
|||
import state from 'state'
|
||||
import * as json from './__mocks__/document.json'
|
||||
import TestState from '../test-utils'
|
||||
|
||||
state.reset()
|
||||
state.send('MOUNTED').send('LOADED_FROM_FILE', { json: JSON.stringify(json) })
|
||||
state.send('CLEARED_PAGE')
|
||||
describe('translate command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
describe('translates shapes', () => {
|
||||
it('translates a single selected shape', () => {
|
||||
// TODO
|
||||
null
|
|
@ -1,6 +1,6 @@
|
|||
import TestState from './test-utils'
|
||||
|
||||
describe('locked shapes', () => {
|
||||
describe('lock command', () => {
|
||||
const tt = new TestState()
|
||||
tt.resetDocumentState()
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ import _state from 'state'
|
|||
import tld from 'utils/tld'
|
||||
import inputs from 'state/inputs'
|
||||
import { createShape, getShapeUtils } from 'state/shape-utils'
|
||||
import { Data, Shape, ShapeType, ShapeUtility } from 'types'
|
||||
import { deepCompareArrays, setToArray, uniqueId, vec } from 'utils'
|
||||
import { Corner, Data, Edge, Shape, ShapeType, ShapeUtility } from 'types'
|
||||
import { deepClone, deepCompareArrays, uniqueId, vec } from 'utils'
|
||||
import * as mockDocument from './__mocks__/document.json'
|
||||
|
||||
type State = typeof _state
|
||||
|
@ -22,9 +22,12 @@ interface PointerOptions {
|
|||
|
||||
class TestState {
|
||||
state: State
|
||||
snapshot: Data
|
||||
|
||||
constructor() {
|
||||
this.state = _state
|
||||
this.state.send('TOGGLED_TEST_MODE')
|
||||
this.snapshot = deepClone(this.state.data)
|
||||
this.reset()
|
||||
}
|
||||
|
||||
|
@ -57,7 +60,7 @@ class TestState {
|
|||
*```
|
||||
*/
|
||||
resetDocumentState(): TestState {
|
||||
this.state.send('RESET_DOCUMENT_STATE')
|
||||
this.state.send('RESET_DOCUMENT_STATE').send('TOGGLED_TEST_MODE')
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -122,13 +125,13 @@ class TestState {
|
|||
idsAreSelected(ids: string[], strict = true): boolean {
|
||||
const selectedIds = tld.getSelectedIds(this.data)
|
||||
return (
|
||||
(strict ? selectedIds.size === ids.length : true) &&
|
||||
ids.every((id) => selectedIds.has(id))
|
||||
(strict ? selectedIds.length === ids.length : true) &&
|
||||
ids.every((id) => selectedIds.includes(id))
|
||||
)
|
||||
}
|
||||
|
||||
get selectedIds(): string[] {
|
||||
return setToArray(tld.getSelectedIds(this.data))
|
||||
return tld.getSelectedIds(this.data)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,6 +343,63 @@ class TestState {
|
|||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Start clicking bounds.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
*```ts
|
||||
* tt.startClickingBounds()
|
||||
*```
|
||||
*/
|
||||
startClickingBounds(options: PointerOptions = {}): TestState {
|
||||
this.state.send(
|
||||
'POINTED_BOUNDS',
|
||||
inputs.pointerDown(TestState.point(options), 'bounds')
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop clicking the bounding box.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
*```ts
|
||||
* tt.stopClickingBounds()
|
||||
*```
|
||||
*/
|
||||
stopClickingBounds(options: PointerOptions = {}): TestState {
|
||||
this.state.send(
|
||||
'STOPPED_POINTING',
|
||||
inputs.pointerUp(TestState.point(options), 'bounds')
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Start clicking a bounds handle.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
*```ts
|
||||
* tt.startClickingBoundsHandle(Edge.Top)
|
||||
*```
|
||||
*/
|
||||
startClickingBoundsHandle(
|
||||
handle: Corner | Edge | 'center',
|
||||
options: PointerOptions = {}
|
||||
): TestState {
|
||||
this.state.send(
|
||||
'POINTED_BOUNDS_HANDLE',
|
||||
inputs.pointerDown(TestState.point(options), handle)
|
||||
)
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the pointer to a new point, or to several points in order.
|
||||
*
|
||||
|
@ -572,6 +632,35 @@ class TestState {
|
|||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a snapshot of the state's current data.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
*```ts
|
||||
* tt.save()
|
||||
*```
|
||||
*/
|
||||
save(): TestState {
|
||||
this.snapshot = deepClone(this.data)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the state's saved data.
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
*```ts
|
||||
* tt.save()
|
||||
* tt.restore()
|
||||
*```
|
||||
*/
|
||||
restore(): TestState {
|
||||
this.state.forceData(this.snapshot)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state's current data.
|
||||
*
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
import state from 'state'
|
||||
import * as json from './__mocks__/document.json'
|
||||
|
||||
state.reset()
|
||||
state.send('MOUNTED').send('LOADED_FROM_FILE', { json: JSON.stringify(json) })
|
||||
state.send('CLEARED_PAGE')
|
||||
|
||||
describe('transforms shapes', () => {
|
||||
it('transforms from the top edge', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the right edge', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the bottom edge', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the left edge', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the top-left corner', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the top-right corner', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the bottom-right corner', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the bottom-left corner', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
||||
|
||||
describe('transforms shapes while aspect-ratio locked', () => {
|
||||
// Fixed
|
||||
|
||||
it('transforms from the top edge while aspect-ratio locked', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the right edge while aspect-ratio locked', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the bottom edge while aspect-ratio locked', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
it('transforms from the left edge while aspect-ratio locked', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the top-left corner while aspect-ratio locked', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the top-right corner while aspect-ratio locked', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the bottom-right corner while aspect-ratio locked', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
|
||||
it('transforms from the bottom-left corner while aspect-ratio locked', () => {
|
||||
// TODO
|
||||
null
|
||||
})
|
||||
})
|
|
@ -1840,14 +1840,6 @@ type RequiredKeys<T> = {
|
|||
return Array.from(new Set(items).values())
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a set to an array.
|
||||
* @param set
|
||||
*/
|
||||
static setToArray<T>(set: Set<T>): T[] {
|
||||
return Array.from(set.values())
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the outer of between a circle and a point.
|
||||
* @param C The circle's center.
|
||||
|
|
|
@ -86,11 +86,11 @@ function ShapesFunctions() {
|
|||
})
|
||||
|
||||
const hasSelection = useSelector((s) => {
|
||||
return tld.getSelectedIds(s.data).size > 0
|
||||
return tld.getSelectedIds(s.data).length > 0
|
||||
})
|
||||
|
||||
const hasMultipleSelection = useSelector((s) => {
|
||||
return tld.getSelectedIds(s.data).size > 1
|
||||
return tld.getSelectedIds(s.data).length > 1
|
||||
})
|
||||
|
||||
return (
|
||||
|
|
|
@ -7,13 +7,13 @@ import {
|
|||
SizeStyle,
|
||||
} from 'types'
|
||||
import { createShape, getShapeUtils } from 'state/shape-utils'
|
||||
import { setToArray, uniqueId } from 'utils'
|
||||
import { uniqueId } from 'utils'
|
||||
import Vec from 'utils/vec'
|
||||
|
||||
export const codeShapes = new Set<CodeShape<Shape>>([])
|
||||
|
||||
function getOrderedShapes() {
|
||||
return setToArray(codeShapes).sort(
|
||||
return Array.from(codeShapes.values()).sort(
|
||||
(a, b) => a.shape.childIndex - b.shape.childIndex
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import { Data } from 'types'
|
||||
import { setToArray } from 'utils'
|
||||
import tld from 'utils/tld'
|
||||
|
||||
/* ------------------ Command Class ----------------- */
|
||||
|
@ -85,7 +84,7 @@ export class BaseCommand<T extends any> {
|
|||
export default class Command extends BaseCommand<Data> {
|
||||
saveSelectionState = (data: Data): ((next: Data) => void) => {
|
||||
const { currentPageId } = data
|
||||
const selectedIds = setToArray(tld.getSelectedIds(data))
|
||||
const selectedIds = [...tld.getSelectedIds(data)]
|
||||
return (next: Data) => {
|
||||
next.currentPageId = currentPageId
|
||||
next.hoveredId = undefined
|
||||
|
|
|
@ -54,7 +54,7 @@ function getSnapshot(data: Data) {
|
|||
|
||||
const pageState: PageState = {
|
||||
id,
|
||||
selectedIds: new Set([]),
|
||||
selectedIds: [],
|
||||
camera: {
|
||||
point: [0, 0],
|
||||
zoom: 1,
|
||||
|
|
|
@ -100,7 +100,7 @@ export default function groupCommand(data: Data): void {
|
|||
getShapeUtils(oldParent).setProperty(
|
||||
oldParent,
|
||||
'children',
|
||||
oldParent.children.filter((id) => !oldSelectedIds.has(id))
|
||||
oldParent.children.filter((id) => !oldSelectedIds.includes(id))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Command from './command'
|
||||
import history from '../history'
|
||||
import { Data } from 'types'
|
||||
import { setToArray, uniqueArray } from 'utils'
|
||||
import { uniqueArray } from 'utils'
|
||||
import tld from 'utils/tld'
|
||||
import { getShapeUtils } from 'state/shape-utils'
|
||||
import storage from 'state/storage'
|
||||
|
@ -9,7 +9,7 @@ import storage from 'state/storage'
|
|||
export default function moveToPageCommand(data: Data, newPageId: string): void {
|
||||
const { currentPageId: oldPageId } = data
|
||||
const oldPage = tld.getPage(data)
|
||||
const selectedIds = setToArray(tld.getSelectedIds(data))
|
||||
const selectedIds = [...tld.getSelectedIds(data)]
|
||||
|
||||
const idsToMove = uniqueArray(
|
||||
...selectedIds.flatMap((id) => tld.getDocumentBranch(data, id))
|
||||
|
@ -59,7 +59,7 @@ export default function moveToPageCommand(data: Data, newPageId: string): void {
|
|||
})
|
||||
|
||||
// Clear the current page state's selected ids
|
||||
tld.getPageState(data).selectedIds.clear()
|
||||
tld.setSelectedIds(data, [])
|
||||
|
||||
// Save the "from" page
|
||||
storage.savePage(data, data.document.id, fromPageId)
|
||||
|
@ -83,7 +83,7 @@ export default function moveToPageCommand(data: Data, newPageId: string): void {
|
|||
})
|
||||
|
||||
// Select the selected ids on the new page
|
||||
tld.getPageState(data).selectedIds = new Set(selectedIds)
|
||||
tld.setSelectedIds(data, [...selectedIds])
|
||||
|
||||
// Move to the new page
|
||||
data.currentPageId = toPageId
|
||||
|
@ -113,7 +113,7 @@ export default function moveToPageCommand(data: Data, newPageId: string): void {
|
|||
delete fromPage.shapes[shape.id]
|
||||
})
|
||||
|
||||
tld.getPageState(data).selectedIds.clear()
|
||||
tld.setSelectedIds(data, [])
|
||||
|
||||
storage.savePage(data, data.document.id, fromPageId)
|
||||
|
||||
|
@ -138,7 +138,7 @@ export default function moveToPageCommand(data: Data, newPageId: string): void {
|
|||
}
|
||||
})
|
||||
|
||||
tld.getPageState(data).selectedIds = new Set(selectedIds)
|
||||
tld.setSelectedIds(data, [...selectedIds])
|
||||
|
||||
data.currentPageId = toPageId
|
||||
},
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import Command from './command'
|
||||
import history from '../history'
|
||||
import { Data, MoveType, Shape } from 'types'
|
||||
import { setToArray } from 'utils'
|
||||
import tld from 'utils/tld'
|
||||
import { getShapeUtils } from 'state/shape-utils'
|
||||
|
||||
export default function moveCommand(data: Data, type: MoveType): void {
|
||||
const page = tld.getPage(data)
|
||||
|
||||
const selectedIds = setToArray(tld.getSelectedIds(data))
|
||||
const selectedIds = [...tld.getSelectedIds(data)]
|
||||
|
||||
const initialIndices = Object.fromEntries(
|
||||
selectedIds.map((id) => [id, page.shapes[id].childIndex])
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Command from './command'
|
||||
import history from '../history'
|
||||
import { Data, Shape } from 'types'
|
||||
import { getCommonBounds, setToArray } from 'utils'
|
||||
import { getCommonBounds } from 'utils'
|
||||
import tld from 'utils/tld'
|
||||
import { uniqueId } from 'utils/utils'
|
||||
import vec from 'utils/vec'
|
||||
|
@ -26,7 +26,7 @@ export default function pasteCommand(data: Data, initialShapes: Shape[]): void {
|
|||
initialShapes.map((shape) => [shape.id, uniqueId()])
|
||||
)
|
||||
|
||||
const oldSelectedIds = setToArray(tld.getSelectedIds(data))
|
||||
const oldSelectedIds = [...tld.getSelectedIds(data)]
|
||||
|
||||
history.execute(
|
||||
data,
|
||||
|
|
|
@ -2,7 +2,7 @@ import Command from './command'
|
|||
import history from '../history'
|
||||
import { Data, ShapeStyles } from 'types'
|
||||
import tld from 'utils/tld'
|
||||
import { deepClone, setToArray } from 'utils'
|
||||
import { deepClone } from 'utils'
|
||||
import { getShapeUtils } from 'state/shape-utils'
|
||||
|
||||
export default function styleCommand(
|
||||
|
@ -11,7 +11,7 @@ export default function styleCommand(
|
|||
): void {
|
||||
const page = tld.getPage(data)
|
||||
|
||||
const selectedIds = setToArray(tld.getSelectedIds(data))
|
||||
const selectedIds = [...tld.getSelectedIds(data)]
|
||||
|
||||
const shapesToStyle = selectedIds
|
||||
.flatMap((id) => tld.getDocumentBranch(data, id))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { DrawShape, PointerInfo } from 'types'
|
||||
import { deepClone, setToArray } from 'utils'
|
||||
import { deepClone } from 'utils'
|
||||
import tld from 'utils/tld'
|
||||
import { freeze } from 'immer'
|
||||
import session from './session'
|
||||
|
@ -56,7 +56,7 @@ export function fastDrawUpdate(info: PointerInfo): void {
|
|||
info.shiftKey
|
||||
)
|
||||
|
||||
const selectedId = setToArray(tld.getSelectedIds(data))[0]
|
||||
const selectedId = [...tld.getSelectedIds(data)][0]
|
||||
|
||||
const { shapes } = data.document.pages[data.currentPageId]
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ import { Data } from 'types'
|
|||
import clipboard from './clipboard'
|
||||
import state from './state'
|
||||
import { isDraft, current } from 'immer'
|
||||
import { setToArray } from 'utils'
|
||||
import tld from 'utils/tld'
|
||||
import inputs from './inputs'
|
||||
|
||||
|
@ -59,9 +58,9 @@ class Logger {
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
this.snapshotStart.pageStates[data.currentPageId].selectedIds = setToArray(
|
||||
tld.getSelectedIds(data)
|
||||
)
|
||||
this.snapshotStart.pageStates[data.currentPageId].selectedIds = [
|
||||
...tld.getSelectedIds(data),
|
||||
]
|
||||
|
||||
return this
|
||||
}
|
||||
|
@ -84,9 +83,9 @@ class Logger {
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
this.snapshotEnd.pageStates[data.currentPageId].selectedIds = setToArray(
|
||||
tld.getSelectedIds(data)
|
||||
)
|
||||
this.snapshotEnd.pageStates[data.currentPageId].selectedIds = [
|
||||
...tld.getSelectedIds(data),
|
||||
]
|
||||
|
||||
// if (window.confirm('Stopped logging. Copy to clipboard?')) {
|
||||
// this.copyToJson()
|
||||
|
@ -138,9 +137,9 @@ class Logger {
|
|||
this.isSimulating = true
|
||||
|
||||
try {
|
||||
data.pageStates[data.currentPageId].selectedIds = new Set(
|
||||
start.pageStates[start.currentPageId].selectedIds
|
||||
)
|
||||
data.pageStates[data.currentPageId].selectedIds = [
|
||||
...start.pageStates[start.currentPageId].selectedIds,
|
||||
]
|
||||
|
||||
state.send('RESET_DOCUMENT_STATE').forceData(start)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { Bounds, Data, ShapeType } from 'types'
|
||||
import BaseSession from './base-session'
|
||||
import { getShapeUtils } from 'state/shape-utils'
|
||||
import { deepClone, getBoundsFromPoints, setToArray } from 'utils'
|
||||
import { deepClone, getBoundsFromPoints } from 'utils'
|
||||
import vec from 'utils/vec'
|
||||
import tld from 'utils/tld'
|
||||
|
||||
|
@ -24,10 +24,10 @@ export default class BrushSession extends BaseSession {
|
|||
|
||||
const hits = new Set<string>([])
|
||||
|
||||
const selectedIds = new Set(snapshot.selectedIds)
|
||||
const selectedIds = [...snapshot.selectedIds]
|
||||
|
||||
for (const id in snapshot.shapeHitTests) {
|
||||
if (selectedIds.has(id)) continue
|
||||
if (selectedIds.includes(id)) continue
|
||||
|
||||
const { test, selectId } = snapshot.shapeHitTests[id]
|
||||
if (!hits.has(selectId)) {
|
||||
|
@ -35,11 +35,11 @@ export default class BrushSession extends BaseSession {
|
|||
hits.add(selectId)
|
||||
|
||||
// When brushing a shape, select its top group parent.
|
||||
if (!selectedIds.has(selectId)) {
|
||||
selectedIds.add(selectId)
|
||||
if (!selectedIds.includes(selectId)) {
|
||||
selectedIds.push(selectId)
|
||||
}
|
||||
} else if (selectedIds.has(selectId)) {
|
||||
selectedIds.delete(selectId)
|
||||
} else if (selectedIds.includes(selectId)) {
|
||||
selectedIds.splice(selectedIds.indexOf(selectId), 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,12 +73,15 @@ export function getBrushSnapshot(data: Data) {
|
|||
.getShapes(cData)
|
||||
.filter((shape) => shape.type !== ShapeType.Group && !shape.isHidden)
|
||||
.filter(
|
||||
(shape) => !(selectedIds.has(shape.id) || selectedIds.has(shape.parentId))
|
||||
(shape) =>
|
||||
!(
|
||||
selectedIds.includes(shape.id) || selectedIds.includes(shape.parentId)
|
||||
)
|
||||
)
|
||||
.map(deepClone)
|
||||
|
||||
return {
|
||||
selectedIds: setToArray(selectedIds),
|
||||
selectedIds: [...selectedIds],
|
||||
shapeHitTests: Object.fromEntries(
|
||||
shapesToTest.map((shape) => {
|
||||
return [
|
||||
|
|
|
@ -133,22 +133,21 @@ const rectangle = registerShapeUtils<RectangleShape>({
|
|||
|
||||
transform(shape, bounds, { initialShape, transformOrigin, scaleX, scaleY }) {
|
||||
if (shape.rotation === 0 && !shape.isAspectRatioLocked) {
|
||||
shape.size = [bounds.width, bounds.height]
|
||||
shape.point = [bounds.minX, bounds.minY]
|
||||
shape.size = vec.round([bounds.width, bounds.height])
|
||||
shape.point = vec.round([bounds.minX, bounds.minY])
|
||||
} else {
|
||||
shape.size = vec.mul(
|
||||
initialShape.size,
|
||||
Math.min(Math.abs(scaleX), Math.abs(scaleY))
|
||||
shape.size = vec.round(
|
||||
vec.mul(initialShape.size, Math.min(Math.abs(scaleX), Math.abs(scaleY)))
|
||||
)
|
||||
|
||||
shape.point = [
|
||||
shape.point = vec.round([
|
||||
bounds.minX +
|
||||
(bounds.width - shape.size[0]) *
|
||||
(scaleX < 0 ? 1 - transformOrigin[0] : transformOrigin[0]),
|
||||
bounds.minY +
|
||||
(bounds.height - shape.size[1]) *
|
||||
(scaleY < 0 ? 1 - transformOrigin[1] : transformOrigin[1]),
|
||||
]
|
||||
])
|
||||
|
||||
shape.rotation =
|
||||
(scaleX < 0 && scaleY >= 0) || (scaleY < 0 && scaleX >= 0)
|
||||
|
@ -160,8 +159,8 @@ const rectangle = registerShapeUtils<RectangleShape>({
|
|||
},
|
||||
|
||||
transformSingle(shape, bounds) {
|
||||
shape.size = [bounds.width, bounds.height]
|
||||
shape.point = [bounds.minX, bounds.minY]
|
||||
shape.size = vec.round([bounds.width, bounds.height])
|
||||
shape.point = vec.round([bounds.minX, bounds.minY])
|
||||
return this
|
||||
},
|
||||
})
|
||||
|
|
|
@ -13,7 +13,6 @@ import {
|
|||
getCommonBounds,
|
||||
rotateBounds,
|
||||
getBoundsCenter,
|
||||
setToArray,
|
||||
deepClone,
|
||||
pointInBounds,
|
||||
uniqueId,
|
||||
|
@ -43,6 +42,7 @@ const initialData: Data = {
|
|||
isReadOnly: false,
|
||||
settings: {
|
||||
fontSize: 13,
|
||||
isTestMode: false,
|
||||
isDarkMode: false,
|
||||
isCodeOpen: false,
|
||||
isDebugMode: false,
|
||||
|
@ -133,7 +133,7 @@ for (let i = 0; i < count; i++) {
|
|||
pageStates: {
|
||||
page1: {
|
||||
id: 'page1',
|
||||
selectedIds: new Set([]),
|
||||
selectedIds: [],
|
||||
camera: {
|
||||
point: [0, 0],
|
||||
zoom: 1,
|
||||
|
@ -147,6 +147,7 @@ const state = createState({
|
|||
on: {
|
||||
TOGGLED_DEBUG_PANEL: 'toggleDebugPanel',
|
||||
TOGGLED_DEBUG_MODE: 'toggleDebugMode',
|
||||
TOGGLED_TEST_MODE: 'toggleTestMode',
|
||||
TOGGLED_LOGGER: 'toggleLogger',
|
||||
COPIED_DEBUG_LOG: 'copyDebugLog',
|
||||
LOADED_FROM_SNAPSHOT: {
|
||||
|
@ -588,7 +589,10 @@ const state = createState({
|
|||
onEnter: 'startTransformSession',
|
||||
onExit: 'completeSession',
|
||||
on: {
|
||||
// MOVED_POINTER: 'updateTransformSession', using hacks.fastTransform
|
||||
MOVED_POINTER: {
|
||||
ifAny: ['isSimulating', 'isTestMode'],
|
||||
do: 'updateTransformSession',
|
||||
},
|
||||
PANNED_CAMERA: 'updateTransformSession',
|
||||
PRESSED_SHIFT_KEY: 'keyUpdateTransformSession',
|
||||
RELEASED_SHIFT_KEY: 'keyUpdateTransformSession',
|
||||
|
@ -638,7 +642,7 @@ const state = createState({
|
|||
'startBrushSession',
|
||||
],
|
||||
on: {
|
||||
// MOVED_POINTER: 'updateBrushSession', using hacks.fastBrushSelect
|
||||
MOVED_POINTER: { if: 'isTestMode', do: 'updateBrushSession' },
|
||||
PANNED_CAMERA: 'updateBrushSession',
|
||||
STOPPED_POINTING: { to: 'selecting' },
|
||||
STARTED_PINCHING: { to: 'pinching' },
|
||||
|
@ -694,7 +698,7 @@ const state = createState({
|
|||
},
|
||||
pinching: {
|
||||
on: {
|
||||
// PINCHED: { do: 'pinchCamera' }, using hacks.fastPinchCamera
|
||||
PINCHED: { if: 'isTestMode', do: 'pinchCamera' },
|
||||
},
|
||||
initial: 'selectPinching',
|
||||
onExit: { secretlyDo: 'updateZoomCSS' },
|
||||
|
@ -760,7 +764,7 @@ const state = createState({
|
|||
RELEASED_SHIFT: 'keyUpdateDrawSession',
|
||||
PANNED_CAMERA: 'updateDrawSession',
|
||||
MOVED_POINTER: {
|
||||
if: 'isSimulating',
|
||||
ifAny: ['isSimulating', 'isTestMode'],
|
||||
do: 'updateDrawSession',
|
||||
},
|
||||
},
|
||||
|
@ -1115,6 +1119,9 @@ const state = createState({
|
|||
isSimulating() {
|
||||
return logger.isSimulating
|
||||
},
|
||||
isTestMode(data) {
|
||||
return data.settings.isTestMode
|
||||
},
|
||||
isEditingShape(data, payload: { id: string }) {
|
||||
return payload.id === data.editingId
|
||||
},
|
||||
|
@ -1131,7 +1138,7 @@ const state = createState({
|
|||
return tld.getShape(data, payload.target)?.type === ShapeType.Text
|
||||
},
|
||||
isPointingBounds(data, payload: PointerInfo) {
|
||||
return tld.getSelectedIds(data).size > 0 && payload.target === 'bounds'
|
||||
return tld.getSelectedIds(data).length > 0 && payload.target === 'bounds'
|
||||
},
|
||||
isPointingShape(data, payload: PointerInfo) {
|
||||
return (
|
||||
|
@ -1156,7 +1163,7 @@ const state = createState({
|
|||
return payload.target !== undefined
|
||||
},
|
||||
isPointedShapeSelected(data) {
|
||||
return tld.getSelectedIds(data).has(data.pointedId)
|
||||
return tld.getSelectedIds(data).includes(data.pointedId)
|
||||
},
|
||||
isPressingShiftKey(data, payload: PointerInfo) {
|
||||
return payload.shiftKey
|
||||
|
@ -1192,13 +1199,13 @@ const state = createState({
|
|||
return payload.target === 'rotate'
|
||||
},
|
||||
hasSelection(data) {
|
||||
return tld.getSelectedIds(data).size > 0
|
||||
return tld.getSelectedIds(data).length > 0
|
||||
},
|
||||
hasSingleSelection(data) {
|
||||
return tld.getSelectedIds(data).size === 1
|
||||
return tld.getSelectedIds(data).length === 1
|
||||
},
|
||||
hasMultipleSelection(data) {
|
||||
return tld.getSelectedIds(data).size > 1
|
||||
return tld.getSelectedIds(data).length > 1
|
||||
},
|
||||
hasCurrentParentShape(data) {
|
||||
return data.currentParentId !== data.currentPageId
|
||||
|
@ -1230,6 +1237,9 @@ const state = createState({
|
|||
toggleDebugMode(data) {
|
||||
data.settings.isDebugMode = !data.settings.isDebugMode
|
||||
},
|
||||
toggleTestMode(data) {
|
||||
data.settings.isTestMode = !data.settings.isTestMode
|
||||
},
|
||||
toggleDebugPanel(data) {
|
||||
data.settings.isDebugOpen = !data.settings.isDebugOpen
|
||||
},
|
||||
|
@ -1304,7 +1314,7 @@ const state = createState({
|
|||
data.pageStates = {
|
||||
[newPageId]: {
|
||||
id: newPageId,
|
||||
selectedIds: new Set(),
|
||||
selectedIds: [],
|
||||
camera: {
|
||||
point: [0, 0],
|
||||
zoom: 1,
|
||||
|
@ -1464,7 +1474,7 @@ const state = createState({
|
|||
|
||||
// Handles
|
||||
doublePointHandle(data, payload: PointerInfo) {
|
||||
const id = setToArray(tld.getSelectedIds(data))[0]
|
||||
const id = tld.getSelectedIds(data)[0]
|
||||
commands.doublePointHandle(data, id, payload)
|
||||
},
|
||||
|
||||
|
@ -1511,7 +1521,7 @@ const state = createState({
|
|||
) {
|
||||
const point = tld.screenToWorld(inputs.pointer.origin, data)
|
||||
session.begin(
|
||||
tld.getSelectedIds(data).size === 1
|
||||
tld.getSelectedIds(data).length === 1
|
||||
? new Sessions.TransformSingleSession(data, payload.target, point)
|
||||
: new Sessions.TransformSession(data, payload.target, point)
|
||||
)
|
||||
|
@ -1618,7 +1628,7 @@ const state = createState({
|
|||
inputs.clear()
|
||||
},
|
||||
deselectAll(data) {
|
||||
tld.getSelectedIds(data).clear()
|
||||
tld.setSelectedIds(data, [])
|
||||
},
|
||||
selectAll(data) {
|
||||
tld.setSelectedIds(
|
||||
|
@ -1673,10 +1683,10 @@ const state = createState({
|
|||
pullPointedIdFromSelectedIds(data) {
|
||||
const { pointedId } = data
|
||||
const selectedIds = tld.getSelectedIds(data)
|
||||
selectedIds.delete(pointedId)
|
||||
selectedIds.splice(selectedIds.indexOf(pointedId), 1)
|
||||
},
|
||||
pushPointedIdToSelectedIds(data) {
|
||||
tld.getSelectedIds(data).add(data.pointedId)
|
||||
tld.getSelectedIds(data).push(data.pointedId)
|
||||
},
|
||||
moveSelection(data, payload: { type: MoveType }) {
|
||||
commands.move(data, payload.type)
|
||||
|
@ -1732,7 +1742,7 @@ const state = createState({
|
|||
data.editingId = selectedShape.id
|
||||
}
|
||||
|
||||
tld.getPageState(data).selectedIds = new Set([selectedShape.id])
|
||||
tld.getPageState(data).selectedIds = [selectedShape.id]
|
||||
},
|
||||
clearEditingId(data) {
|
||||
data.editingId = null
|
||||
|
@ -2094,7 +2104,7 @@ const state = createState({
|
|||
},
|
||||
values: {
|
||||
selectedIds(data) {
|
||||
return setToArray(tld.getSelectedIds(data))
|
||||
return tld.getSelectedIds(data)
|
||||
},
|
||||
selectedBounds(data) {
|
||||
return getSelectionBounds(data)
|
||||
|
@ -2107,7 +2117,7 @@ const state = createState({
|
|||
.sort((a, b) => a.childIndex - b.childIndex)
|
||||
},
|
||||
selectedStyle(data) {
|
||||
const selectedIds = setToArray(tld.getSelectedIds(data))
|
||||
const selectedIds = tld.getSelectedIds(data)
|
||||
const { currentStyle } = data
|
||||
|
||||
if (selectedIds.length === 0) {
|
||||
|
@ -2195,9 +2205,9 @@ function getSelectionBounds(data: Data) {
|
|||
|
||||
const shapes = tld.getSelectedShapes(data)
|
||||
|
||||
if (selectedIds.size === 0) return null
|
||||
if (selectedIds.length === 0) return null
|
||||
|
||||
if (selectedIds.size === 1) {
|
||||
if (selectedIds.length === 1) {
|
||||
if (!shapes[0]) {
|
||||
console.warn('Could not find that shape! Clearing selected IDs.')
|
||||
tld.setSelectedIds(data, [])
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Data, PageState, TLDocument } from 'types'
|
||||
import { decompress, compress, setToArray } from 'utils'
|
||||
import { decompress, compress } from 'utils'
|
||||
import state from './state'
|
||||
import { uniqueId } from 'utils/utils'
|
||||
import * as idb from 'idb-keyval'
|
||||
|
@ -132,14 +132,11 @@ class Storage {
|
|||
if (savedPageState !== null) {
|
||||
// If we've found a page state in local storage, set it into state.
|
||||
data.pageStates[pageId] = JSON.parse(decompress(savedPageState))
|
||||
data.pageStates[pageId].selectedIds = new Set(
|
||||
data.pageStates[pageId].selectedIds
|
||||
)
|
||||
} else {
|
||||
// Or else create a new one.
|
||||
data.pageStates[pageId] = {
|
||||
id: pageId,
|
||||
selectedIds: new Set([]),
|
||||
selectedIds: [],
|
||||
camera: {
|
||||
point: [0, 0],
|
||||
zoom: 1,
|
||||
|
@ -161,13 +158,13 @@ class Storage {
|
|||
throw new Error('Page state id not in document')
|
||||
}
|
||||
|
||||
pageState.selectedIds = new Set([])
|
||||
pageState.selectedIds = []
|
||||
data.pageStates[pageState.id] = pageState
|
||||
data.currentPageId = pageState.id
|
||||
} catch (e) {
|
||||
data.pageStates[data.currentPageId] = {
|
||||
id: data.currentPageId,
|
||||
selectedIds: new Set([]),
|
||||
selectedIds: [],
|
||||
camera: {
|
||||
point: [0, 0],
|
||||
zoom: 1,
|
||||
|
@ -249,7 +246,7 @@ class Storage {
|
|||
storageId(fileId, 'pageState', pageId),
|
||||
JSON.stringify({
|
||||
...currentPageState,
|
||||
selectedIds: setToArray(currentPageState.selectedIds),
|
||||
selectedIds: [...currentPageState.selectedIds],
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -286,7 +283,6 @@ class Storage {
|
|||
// If we have a page, move it into state
|
||||
const restored: PageState = JSON.parse(savedPageState)
|
||||
data.pageStates[pageId] = restored
|
||||
data.pageStates[pageId].selectedIds = new Set(restored.selectedIds)
|
||||
} else {
|
||||
data.pageStates[pageId] = {
|
||||
id: pageId,
|
||||
|
@ -294,7 +290,7 @@ class Storage {
|
|||
point: [0, 0],
|
||||
zoom: 1,
|
||||
},
|
||||
selectedIds: new Set([]),
|
||||
selectedIds: [],
|
||||
}
|
||||
}
|
||||
|
||||
|
|
3
types.ts
3
types.ts
|
@ -8,6 +8,7 @@ export interface Data {
|
|||
fontSize: number
|
||||
isDarkMode: boolean
|
||||
isCodeOpen: boolean
|
||||
isTestMode: boolean
|
||||
isDebugOpen: boolean
|
||||
isDebugMode: boolean
|
||||
isStyleOpen: boolean
|
||||
|
@ -66,7 +67,7 @@ export interface Page {
|
|||
|
||||
export interface PageState {
|
||||
id: string
|
||||
selectedIds: Set<string>
|
||||
selectedIds: string[]
|
||||
camera: {
|
||||
point: number[]
|
||||
zoom: number
|
||||
|
|
12
utils/tld.ts
12
utils/tld.ts
|
@ -1,4 +1,4 @@
|
|||
import { clamp, deepClone, getCommonBounds, setToArray } from 'utils'
|
||||
import { clamp, deepClone, getCommonBounds } from 'utils'
|
||||
import { getShapeUtils } from 'state/shape-utils'
|
||||
import vec from './vec'
|
||||
import {
|
||||
|
@ -98,7 +98,7 @@ export default class StateUtils {
|
|||
*/
|
||||
static getSelectedShapes(data: Data): Shape[] {
|
||||
const page = this.getPage(data)
|
||||
const ids = setToArray(this.getSelectedIds(data))
|
||||
const ids = this.getSelectedIds(data)
|
||||
return ids.map((id) => page.shapes[id])
|
||||
}
|
||||
|
||||
|
@ -306,12 +306,12 @@ export default class StateUtils {
|
|||
]
|
||||
}
|
||||
|
||||
static getSelectedIds(data: Data): Set<string> {
|
||||
static getSelectedIds(data: Data): string[] {
|
||||
return data.pageStates[data.currentPageId].selectedIds
|
||||
}
|
||||
|
||||
static setSelectedIds(data: Data, ids: string[]): Set<string> {
|
||||
data.pageStates[data.currentPageId].selectedIds = new Set(ids)
|
||||
static setSelectedIds(data: Data, ids: string[]): string[] {
|
||||
data.pageStates[data.currentPageId].selectedIds = [...ids]
|
||||
return data.pageStates[data.currentPageId].selectedIds
|
||||
}
|
||||
|
||||
|
@ -347,7 +347,7 @@ export default class StateUtils {
|
|||
>(data: Data, fn?: F): (Shape | K)[] {
|
||||
const page = this.getPage(data)
|
||||
|
||||
const copies = setToArray(this.getSelectedIds(data))
|
||||
const copies = this.getSelectedIds(data)
|
||||
.flatMap((id) =>
|
||||
this.getDocumentBranch(data, id).map((id) => page.shapes[id])
|
||||
)
|
||||
|
|
|
@ -1572,14 +1572,6 @@ export function uniqueArray<T extends string | number>(...items: T[]): T[] {
|
|||
return Array.from(new Set(items).values())
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a set to an array.
|
||||
* @param set
|
||||
*/
|
||||
export function setToArray<T>(set: Set<T>): T[] {
|
||||
return Array.from(set.values())
|
||||
}
|
||||
|
||||
/* -------------------------------------------------- */
|
||||
/* Browser and DOM */
|
||||
/* -------------------------------------------------- */
|
||||
|
|
Loading…
Reference in a new issue