@tsdraw/core 0.6.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -225,25 +225,34 @@ var StateNode = class {
225
225
 
226
226
  // src/canvas/viewport.ts
227
227
  function createViewport() {
228
- return { x: 0, y: 0, zoom: 1 };
228
+ return { x: 0, y: 0, zoom: 1, rotation: 0 };
229
229
  }
230
230
  function screenToPage(viewport, screenX, screenY) {
231
+ const tx = screenX - viewport.x;
232
+ const ty = screenY - viewport.y;
233
+ const cos = Math.cos(viewport.rotation);
234
+ const sin = Math.sin(viewport.rotation);
231
235
  return {
232
- x: (screenX - viewport.x) / viewport.zoom,
233
- y: (screenY - viewport.y) / viewport.zoom
236
+ x: (tx * cos + ty * sin) / viewport.zoom,
237
+ y: (-tx * sin + ty * cos) / viewport.zoom
234
238
  };
235
239
  }
236
240
  function pageToScreen(viewport, pageX, pageY) {
241
+ const scaledX = pageX * viewport.zoom;
242
+ const scaledY = pageY * viewport.zoom;
243
+ const cos = Math.cos(viewport.rotation);
244
+ const sin = Math.sin(viewport.rotation);
237
245
  return {
238
- x: pageX * viewport.zoom + viewport.x,
239
- y: pageY * viewport.zoom + viewport.y
246
+ x: scaledX * cos - scaledY * sin + viewport.x,
247
+ y: scaledX * sin + scaledY * cos + viewport.y
240
248
  };
241
249
  }
242
250
  function setViewport(viewport, updater) {
243
251
  return {
244
252
  x: updater.x ?? viewport.x,
245
253
  y: updater.y ?? viewport.y,
246
- zoom: updater.zoom ?? viewport.zoom
254
+ zoom: updater.zoom ?? viewport.zoom,
255
+ rotation: updater.rotation ?? viewport.rotation
247
256
  };
248
257
  }
249
258
  function panViewport(viewport, dx, dy) {
@@ -255,9 +264,23 @@ function zoomViewport(viewport, factor, centerX, centerY) {
255
264
  return { ...viewport, zoom };
256
265
  }
257
266
  const pageBefore = screenToPage(viewport, centerX, centerY);
258
- const x = centerX - pageBefore.x * zoom;
259
- const y = centerY - pageBefore.y * zoom;
260
- return { x, y, zoom };
267
+ const cos = Math.cos(viewport.rotation);
268
+ const sin = Math.sin(viewport.rotation);
269
+ const x = centerX - (pageBefore.x * zoom * cos - pageBefore.y * zoom * sin);
270
+ const y = centerY - (pageBefore.x * zoom * sin + pageBefore.y * zoom * cos);
271
+ return { x, y, zoom, rotation: viewport.rotation };
272
+ }
273
+ function rotateViewport(viewport, delta, centerX, centerY) {
274
+ const rotation = viewport.rotation + delta;
275
+ if (centerX == null || centerY == null) {
276
+ return { ...viewport, rotation };
277
+ }
278
+ const pageBefore = screenToPage(viewport, centerX, centerY);
279
+ const cos = Math.cos(rotation);
280
+ const sin = Math.sin(rotation);
281
+ const x = centerX - (pageBefore.x * viewport.zoom * cos - pageBefore.y * viewport.zoom * sin);
282
+ const y = centerY - (pageBefore.x * viewport.zoom * sin + pageBefore.y * viewport.zoom * cos);
283
+ return { x, y, zoom: viewport.zoom, rotation };
261
284
  }
262
285
 
263
286
  // src/utils/colors.ts
@@ -290,6 +313,7 @@ var CanvasRenderer = class {
290
313
  render(ctx, viewport, shapes) {
291
314
  ctx.save();
292
315
  ctx.translate(viewport.x, viewport.y);
316
+ ctx.rotate(viewport.rotation);
293
317
  ctx.scale(viewport.zoom, viewport.zoom);
294
318
  for (const shape of shapes) {
295
319
  if (shape.type === "draw") {
@@ -298,11 +322,16 @@ var CanvasRenderer = class {
298
322
  }
299
323
  ctx.restore();
300
324
  }
325
+ // Paints a single stroke
301
326
  paintStroke(ctx, shape) {
302
327
  const width = (STROKE_WIDTHS[shape.props.size] ?? 3.5) * shape.props.scale;
303
328
  const samples = flattenSegments(shape);
304
329
  if (samples.length === 0) return;
305
330
  const color = resolveThemeColor(shape.props.color, this.theme);
331
+ const fillStyle = shape.props.fill ?? "none";
332
+ if (shape.props.isClosed && fillStyle !== "none") {
333
+ this.paintClosedShapeFill(ctx, samples, color, fillStyle);
334
+ }
306
335
  if (shape.props.dash !== "draw") {
307
336
  this.paintDashedStroke(ctx, samples, width, color, shape.props.dash);
308
337
  return;
@@ -349,6 +378,30 @@ var CanvasRenderer = class {
349
378
  ctx.stroke();
350
379
  ctx.restore();
351
380
  }
381
+ // Closed shapes are shapes where their start and end point are the same
382
+ paintClosedShapeFill(ctx, samples, color, fillStyle) {
383
+ if (samples.length < 3) return;
384
+ ctx.save();
385
+ ctx.beginPath();
386
+ ctx.moveTo(samples[0].x, samples[0].y);
387
+ for (let i = 1; i < samples.length; i++) {
388
+ const sample = samples[i];
389
+ ctx.lineTo(sample.x, sample.y);
390
+ }
391
+ ctx.closePath();
392
+ if (fillStyle === "solid") {
393
+ ctx.fillStyle = color;
394
+ ctx.globalAlpha = 0.55;
395
+ } else if (fillStyle === "none") {
396
+ ctx.fillStyle = this.theme === "dark" ? "#0f0f0f" : "#fafafa";
397
+ ctx.globalAlpha = 1;
398
+ } else {
399
+ ctx.fillStyle = color;
400
+ ctx.globalAlpha = 0.28;
401
+ }
402
+ ctx.fill();
403
+ ctx.restore();
404
+ }
352
405
  };
353
406
  var PRESSURE_FLOOR = 0.025;
354
407
  var STYLUS_CURVE = (t) => t * 0.65 + Math.sin(t * Math.PI / 2) * 0.35;
@@ -362,7 +415,7 @@ function remap(value, inRange, outRange, clamp = false) {
362
415
  return outLo + (outHi - outLo) * clamped;
363
416
  }
364
417
  function strokeConfig(shape, width) {
365
- const done = shape.props.isComplete;
418
+ const done = shape.props.isComplete || shape.props.isClosed === true;
366
419
  if (shape.props.isPen) {
367
420
  return {
368
421
  size: 1 + width * 1.2,
@@ -421,9 +474,6 @@ function flattenSegments(shape) {
421
474
  }
422
475
  out.push(D);
423
476
  }
424
- if (out.length > 0 && !shape.props.isPen) {
425
- for (const p of out) p.pressure = 0.5;
426
- }
427
477
  return out;
428
478
  }
429
479
  function getLineDash(dash, width) {
@@ -754,8 +804,8 @@ var PenDrawingState = class extends StateNode {
754
804
  const penActive = inputs.getIsPen();
755
805
  const z = this._startInfo?.point?.z ?? 0.5;
756
806
  this._isPenDevice = penActive;
757
- this._hasPressure = penActive && z !== 0 || z > 0 && z < 0.5 || z > 0.5 && z < 1;
758
- const pressure = this._hasPressure ? toFixed(z * 1.25) : 0.5;
807
+ this._hasPressure = penActive || z !== 0.5;
808
+ const pressure = this._hasPressure ? toFixed(z) : 0.5;
759
809
  this._phase = inputs.getShiftKey() ? "straight" : "free";
760
810
  this._extending = false;
761
811
  this._lastSample = { ...origin };
@@ -850,8 +900,15 @@ var PenDrawingState = class extends StateNode {
850
900
  const { id, props: { size, scale } } = target;
851
901
  const { segments } = shape.props;
852
902
  const curPt = inputs.getCurrentPagePoint();
903
+ if (!this._hasPressure) {
904
+ const liveZ = curPt.z ?? 0.5;
905
+ if (liveZ !== 0.5 || inputs.getIsPen()) {
906
+ this._hasPressure = true;
907
+ this.editor.updateShapes([{ id, type: "draw", props: { isPen: true } }]);
908
+ }
909
+ }
853
910
  const local = this.editor.getPointInShapeSpace(shape, curPt);
854
- const pressure = this._hasPressure ? toFixed((curPt.z ?? 0.5) * 1.25) : 0.5;
911
+ const pressure = this._hasPressure ? toFixed(curPt.z ?? 0.5) : 0.5;
855
912
  const pt = { x: toFixed(local.x), y: toFixed(local.y), z: pressure };
856
913
  switch (this._phase) {
857
914
  case "starting_straight": {
@@ -997,7 +1054,7 @@ var PenDrawingState = class extends StateNode {
997
1054
  const firstPt = {
998
1055
  x: 0,
999
1056
  y: 0,
1000
- z: this._hasPressure ? toFixed((curPage.z ?? 0.5) * 1.25) : 0.5
1057
+ z: this._hasPressure ? toFixed(curPage.z ?? 0.5) : 0.5
1001
1058
  };
1002
1059
  this._activePts = [firstPt];
1003
1060
  this.editor.createShape({
@@ -1035,6 +1092,236 @@ var PenDrawingState = class extends StateNode {
1035
1092
  }
1036
1093
  };
1037
1094
 
1095
+ // src/tools/square/states/SquareIdleState.ts
1096
+ var SquareIdleState = class extends StateNode {
1097
+ static id = "square_idle";
1098
+ onPointerDown(info) {
1099
+ this.ctx.transition("square_drawing", info);
1100
+ }
1101
+ };
1102
+
1103
+ // src/tools/geometric/states/GeometricDrawingState.ts
1104
+ var GeometricDrawingState = class extends StateNode {
1105
+ currentShapeId = null;
1106
+ startedAt = { point: { x: 0, y: 0, z: 0.5 } };
1107
+ onEnter(info) {
1108
+ this.startedAt = info ?? { point: { x: 0, y: 0, z: 0.5 } };
1109
+ const originPoint = this.editor.input.getOriginPagePoint();
1110
+ const drawStyle = this.editor.getCurrentDrawStyle();
1111
+ const nextShapeId = this.editor.createShapeId();
1112
+ const config = this.getConfig();
1113
+ this.editor.createShape({
1114
+ id: nextShapeId,
1115
+ type: "draw",
1116
+ x: originPoint.x,
1117
+ y: originPoint.y,
1118
+ props: {
1119
+ color: drawStyle.color,
1120
+ dash: drawStyle.dash,
1121
+ fill: drawStyle.fill,
1122
+ size: drawStyle.size,
1123
+ scale: 1,
1124
+ isPen: false,
1125
+ isComplete: false,
1126
+ isClosed: true,
1127
+ segments: config.buildSegments(1, 1)
1128
+ }
1129
+ });
1130
+ this.currentShapeId = nextShapeId;
1131
+ }
1132
+ onPointerMove() {
1133
+ const activeShape = this.getActiveShape();
1134
+ if (!activeShape) return;
1135
+ const config = this.getConfig();
1136
+ const originPoint = this.editor.input.getOriginPagePoint();
1137
+ const cursorPoint = this.editor.input.getCurrentPagePoint();
1138
+ const shapeBounds = this.editor.input.getShiftKey() ? config.buildConstrainedBounds(originPoint.x, originPoint.y, cursorPoint.x, cursorPoint.y) : config.buildUnconstrainedBounds(originPoint.x, originPoint.y, cursorPoint.x, cursorPoint.y);
1139
+ this.editor.store.updateShape(activeShape.id, {
1140
+ x: shapeBounds.x,
1141
+ y: shapeBounds.y,
1142
+ props: {
1143
+ ...activeShape.props,
1144
+ segments: config.buildSegments(shapeBounds.width, shapeBounds.height),
1145
+ isClosed: true
1146
+ }
1147
+ });
1148
+ }
1149
+ onPointerUp() {
1150
+ this.completeShape();
1151
+ }
1152
+ onCancel() {
1153
+ this.removeCurrentShape();
1154
+ this.ctx.transition(this.getConfig().idleStateId, this.startedAt);
1155
+ }
1156
+ onInterrupt() {
1157
+ this.completeShape();
1158
+ }
1159
+ onKeyDown() {
1160
+ this.onPointerMove();
1161
+ }
1162
+ onKeyUp() {
1163
+ this.onPointerMove();
1164
+ }
1165
+ completeShape() {
1166
+ const activeShape = this.getActiveShape();
1167
+ const config = this.getConfig();
1168
+ if (!activeShape) {
1169
+ this.ctx.transition(config.idleStateId, this.startedAt);
1170
+ return;
1171
+ }
1172
+ const originPoint = this.editor.input.getOriginPagePoint();
1173
+ const cursorPoint = this.editor.input.getCurrentPagePoint();
1174
+ const finalizedBounds = this.editor.input.getIsDragging() ? this.editor.input.getShiftKey() ? config.buildConstrainedBounds(originPoint.x, originPoint.y, cursorPoint.x, cursorPoint.y) : config.buildUnconstrainedBounds(originPoint.x, originPoint.y, cursorPoint.x, cursorPoint.y) : config.buildDefaultBounds(originPoint.x, originPoint.y);
1175
+ this.editor.store.updateShape(activeShape.id, {
1176
+ x: finalizedBounds.x,
1177
+ y: finalizedBounds.y,
1178
+ props: {
1179
+ ...activeShape.props,
1180
+ fill: this.editor.getCurrentDrawStyle().fill,
1181
+ isComplete: true,
1182
+ isClosed: true,
1183
+ segments: config.buildSegments(finalizedBounds.width, finalizedBounds.height)
1184
+ }
1185
+ });
1186
+ this.currentShapeId = null;
1187
+ this.ctx.transition(config.idleStateId);
1188
+ }
1189
+ removeCurrentShape() {
1190
+ if (!this.currentShapeId) return;
1191
+ this.editor.store.deleteShapes([this.currentShapeId]);
1192
+ this.currentShapeId = null;
1193
+ }
1194
+ getActiveShape() {
1195
+ if (!this.currentShapeId) return null;
1196
+ const shape = this.editor.getShape(this.currentShapeId);
1197
+ if (!shape || shape.type !== "draw") return null;
1198
+ return shape;
1199
+ }
1200
+ };
1201
+
1202
+ // src/tools/geometric/geometricShapeHelpers.ts
1203
+ var MIN_SIDE_LENGTH = 1;
1204
+ var DEFAULT_RECTANGLE_WIDTH = 180;
1205
+ var DEFAULT_RECTANGLE_HEIGHT = 120;
1206
+ var DEFAULT_ELLIPSE_WIDTH = 180;
1207
+ var DEFAULT_ELLIPSE_HEIGHT = 120;
1208
+ function toSizedBounds(anchorX, anchorY, cursorX, cursorY, forceEqualSides) {
1209
+ const rawDeltaX = cursorX - anchorX;
1210
+ const rawDeltaY = cursorY - anchorY;
1211
+ const sideLength = Math.max(Math.abs(rawDeltaX), Math.abs(rawDeltaY), MIN_SIDE_LENGTH);
1212
+ if (forceEqualSides) {
1213
+ const nextDeltaX = rawDeltaX < 0 ? -sideLength : sideLength;
1214
+ const nextDeltaY = rawDeltaY < 0 ? -sideLength : sideLength;
1215
+ return normalizeBounds(anchorX, anchorY, anchorX + nextDeltaX, anchorY + nextDeltaY);
1216
+ }
1217
+ return normalizeBounds(anchorX, anchorY, cursorX, cursorY);
1218
+ }
1219
+ function normalizeBounds(startX, startY, endX, endY) {
1220
+ const x = Math.min(startX, endX);
1221
+ const y = Math.min(startY, endY);
1222
+ const width = Math.max(Math.abs(endX - startX), MIN_SIDE_LENGTH);
1223
+ const height = Math.max(Math.abs(endY - startY), MIN_SIDE_LENGTH);
1224
+ return { x, y, width, height };
1225
+ }
1226
+ function buildSquareBounds(anchorX, anchorY, cursorX, cursorY) {
1227
+ return toSizedBounds(anchorX, anchorY, cursorX, cursorY, true);
1228
+ }
1229
+ function buildRectangleBounds(anchorX, anchorY, cursorX, cursorY) {
1230
+ return toSizedBounds(anchorX, anchorY, cursorX, cursorY, false);
1231
+ }
1232
+ function buildDefaultCenteredRectangleBounds(centerX, centerY) {
1233
+ const halfWidth = DEFAULT_RECTANGLE_WIDTH / 2;
1234
+ const halfHeight = DEFAULT_RECTANGLE_HEIGHT / 2;
1235
+ return {
1236
+ x: centerX - halfWidth,
1237
+ y: centerY - halfHeight,
1238
+ width: DEFAULT_RECTANGLE_WIDTH,
1239
+ height: DEFAULT_RECTANGLE_HEIGHT
1240
+ };
1241
+ }
1242
+ function buildRectangleSegments(width, height) {
1243
+ const topLeft = { x: 0, y: 0, z: 0.5 };
1244
+ const topRight = { x: width, y: 0, z: 0.5 };
1245
+ const bottomRight = { x: width, y: height, z: 0.5 };
1246
+ const bottomLeft = { x: 0, y: height, z: 0.5 };
1247
+ return [
1248
+ { type: "straight", path: encodePoints([topLeft, topRight]) },
1249
+ { type: "straight", path: encodePoints([topRight, bottomRight]) },
1250
+ { type: "straight", path: encodePoints([bottomRight, bottomLeft]) },
1251
+ { type: "straight", path: encodePoints([bottomLeft, topLeft]) }
1252
+ ];
1253
+ }
1254
+ function buildCircleBounds(anchorX, anchorY, cursorX, cursorY) {
1255
+ return toSizedBounds(anchorX, anchorY, cursorX, cursorY, true);
1256
+ }
1257
+ function buildEllipseBounds(anchorX, anchorY, cursorX, cursorY) {
1258
+ return toSizedBounds(anchorX, anchorY, cursorX, cursorY, false);
1259
+ }
1260
+ function buildDefaultCenteredEllipseBounds(centerX, centerY) {
1261
+ const halfWidth = DEFAULT_ELLIPSE_WIDTH / 2;
1262
+ const halfHeight = DEFAULT_ELLIPSE_HEIGHT / 2;
1263
+ return {
1264
+ x: centerX - halfWidth,
1265
+ y: centerY - halfHeight,
1266
+ width: DEFAULT_ELLIPSE_WIDTH,
1267
+ height: DEFAULT_ELLIPSE_HEIGHT
1268
+ };
1269
+ }
1270
+ function buildEllipseSegments(width, height) {
1271
+ const centerX = width / 2;
1272
+ const centerY = height / 2;
1273
+ const radiusX = width / 2;
1274
+ const radiusY = height / 2;
1275
+ const sampleCount = 64;
1276
+ const sampledPoints = [];
1277
+ for (let sampleIndex = 0; sampleIndex <= sampleCount; sampleIndex += 1) {
1278
+ const progress = sampleIndex / sampleCount;
1279
+ const angle = progress * Math.PI * 2;
1280
+ sampledPoints.push({
1281
+ x: centerX + Math.cos(angle) * radiusX,
1282
+ y: centerY + Math.sin(angle) * radiusY,
1283
+ z: 0.5
1284
+ });
1285
+ }
1286
+ return [{ type: "free", path: encodePoints(sampledPoints) }];
1287
+ }
1288
+
1289
+ // src/tools/square/states/SquareDrawingState.ts
1290
+ var SquareDrawingState = class extends GeometricDrawingState {
1291
+ static id = "square_drawing";
1292
+ getConfig() {
1293
+ return {
1294
+ idleStateId: "square_idle",
1295
+ buildConstrainedBounds: buildSquareBounds,
1296
+ buildUnconstrainedBounds: buildRectangleBounds,
1297
+ buildDefaultBounds: buildDefaultCenteredRectangleBounds,
1298
+ buildSegments: buildRectangleSegments
1299
+ };
1300
+ }
1301
+ };
1302
+
1303
+ // src/tools/circle/states/CircleIdleState.ts
1304
+ var CircleIdleState = class extends StateNode {
1305
+ static id = "circle_idle";
1306
+ onPointerDown(info) {
1307
+ this.ctx.transition("circle_drawing", info);
1308
+ }
1309
+ };
1310
+
1311
+ // src/tools/circle/states/CircleDrawingState.ts
1312
+ var CircleDrawingState = class extends GeometricDrawingState {
1313
+ static id = "circle_drawing";
1314
+ getConfig() {
1315
+ return {
1316
+ idleStateId: "circle_idle",
1317
+ buildConstrainedBounds: buildCircleBounds,
1318
+ buildUnconstrainedBounds: buildEllipseBounds,
1319
+ buildDefaultBounds: buildDefaultCenteredEllipseBounds,
1320
+ buildSegments: buildEllipseSegments
1321
+ };
1322
+ }
1323
+ };
1324
+
1038
1325
  // src/tools/eraser/states/EraserIdleState.ts
1039
1326
  var EraserIdleState = class extends StateNode {
1040
1327
  static id = "eraser_idle";
@@ -1348,6 +1635,7 @@ var Editor = class {
1348
1635
  drawStyle = {
1349
1636
  color: "black",
1350
1637
  dash: "draw",
1638
+ fill: "none",
1351
1639
  size: "m"
1352
1640
  };
1353
1641
  toolStateContext;
@@ -1407,6 +1695,8 @@ var Editor = class {
1407
1695
  getDefaultToolDefinitions() {
1408
1696
  return [
1409
1697
  { id: "pen", initialStateId: PenIdleState.id, stateConstructors: [PenIdleState, PenDrawingState] },
1698
+ { id: "square", initialStateId: SquareIdleState.id, stateConstructors: [SquareIdleState, SquareDrawingState] },
1699
+ { id: "circle", initialStateId: CircleIdleState.id, stateConstructors: [CircleIdleState, CircleDrawingState] },
1410
1700
  { id: "eraser", initialStateId: EraserIdleState.id, stateConstructors: [EraserIdleState, EraserPointingState, EraserErasingState] },
1411
1701
  { id: "select", initialStateId: SelectIdleState.id, stateConstructors: [SelectIdleState] },
1412
1702
  { id: "hand", initialStateId: HandIdleState.id, stateConstructors: [HandIdleState, HandDraggingState] }
@@ -1474,7 +1764,8 @@ var Editor = class {
1474
1764
  this.viewport = {
1475
1765
  x: partial.x ?? this.viewport.x,
1476
1766
  y: partial.y ?? this.viewport.y,
1477
- zoom: Math.max(0.1, Math.min(4, rawZoom))
1767
+ zoom: Math.max(0.1, Math.min(4, rawZoom)),
1768
+ rotation: partial.rotation ?? this.viewport.rotation
1478
1769
  };
1479
1770
  this.emitChange();
1480
1771
  }
@@ -1484,6 +1775,18 @@ var Editor = class {
1484
1775
  y: this.viewport.y + dy
1485
1776
  });
1486
1777
  }
1778
+ zoomAt(factor, screenX, screenY) {
1779
+ this.viewport = zoomViewport(this.viewport, factor, screenX, screenY);
1780
+ this.emitChange();
1781
+ }
1782
+ rotateAt(delta, screenX, screenY) {
1783
+ this.viewport = rotateViewport(this.viewport, delta, screenX, screenY);
1784
+ this.emitChange();
1785
+ }
1786
+ deleteShapes(ids) {
1787
+ if (ids.length === 0) return;
1788
+ this.store.deleteShapes(ids);
1789
+ }
1487
1790
  getDocumentSnapshot() {
1488
1791
  return {
1489
1792
  records: documentSnapshotToRecords(this.store.getSnapshot())
@@ -1502,7 +1805,8 @@ var Editor = class {
1502
1805
  viewport: {
1503
1806
  x: this.viewport.x,
1504
1807
  y: this.viewport.y,
1505
- zoom: this.viewport.zoom
1808
+ zoom: this.viewport.zoom,
1809
+ rotation: this.viewport.rotation
1506
1810
  },
1507
1811
  currentToolId: this.getCurrentToolId(),
1508
1812
  drawStyle: this.getCurrentDrawStyle(),
@@ -1510,8 +1814,16 @@ var Editor = class {
1510
1814
  };
1511
1815
  }
1512
1816
  loadSessionStateSnapshot(snapshot) {
1513
- this.setViewport(snapshot.viewport);
1514
- this.setCurrentDrawStyle(snapshot.drawStyle);
1817
+ this.setViewport({
1818
+ ...snapshot.viewport,
1819
+ rotation: snapshot.viewport.rotation ?? 0
1820
+ });
1821
+ this.setCurrentDrawStyle({
1822
+ color: snapshot.drawStyle.color,
1823
+ dash: snapshot.drawStyle.dash,
1824
+ fill: snapshot.drawStyle.fill ?? "none",
1825
+ size: snapshot.drawStyle.size
1826
+ });
1515
1827
  if (this.tools.hasTool(snapshot.currentToolId)) {
1516
1828
  this.setCurrentTool(snapshot.currentToolId);
1517
1829
  }
@@ -1893,6 +2205,8 @@ function applyResize(editor, handle, startBounds, startShapes, pointer, lockAspe
1893
2205
  }
1894
2206
 
1895
2207
  exports.CanvasRenderer = CanvasRenderer;
2208
+ exports.CircleDrawingState = CircleDrawingState;
2209
+ exports.CircleIdleState = CircleIdleState;
1896
2210
  exports.DEFAULT_COLORS = DEFAULT_COLORS;
1897
2211
  exports.DRAG_DISTANCE_SQUARED = DRAG_DISTANCE_SQUARED;
1898
2212
  exports.DocumentStore = DocumentStore;
@@ -1909,6 +2223,8 @@ exports.PenDrawingState = PenDrawingState;
1909
2223
  exports.PenIdleState = PenIdleState;
1910
2224
  exports.STROKE_WIDTHS = STROKE_WIDTHS;
1911
2225
  exports.SelectIdleState = SelectIdleState;
2226
+ exports.SquareDrawingState = SquareDrawingState;
2227
+ exports.SquareIdleState = SquareIdleState;
1912
2228
  exports.StateNode = StateNode;
1913
2229
  exports.ToolManager = ToolManager;
1914
2230
  exports.applyMove = applyMove;
@@ -1942,6 +2258,7 @@ exports.pointHitsShape = pointHitsShape;
1942
2258
  exports.recordsToDocumentSnapshot = recordsToDocumentSnapshot;
1943
2259
  exports.resolveThemeColor = resolveThemeColor;
1944
2260
  exports.rotatePoint = rotatePoint;
2261
+ exports.rotateViewport = rotateViewport;
1945
2262
  exports.screenToPage = screenToPage;
1946
2263
  exports.segmentHitsShape = segmentHitsShape;
1947
2264
  exports.segmentTouchesPolyline = segmentTouchesPolyline;