@inditextech/weave-sdk 5.4.1 → 5.6.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/sdk.js CHANGED
@@ -5937,6 +5937,7 @@ const MOVE_TOOL_STATE = {
5937
5937
  };
5938
5938
  //#endregion
5939
5939
  //#region src/nodes/node.ts
5940
+ const nodeInstanceListeners = /* @__PURE__ */ new WeakMap();
5940
5941
  const augmentKonvaNodeClass = (config) => {
5941
5942
  const { transform } = config ?? {};
5942
5943
  Konva.Node.prototype.getTransformerProperties = function() {
@@ -5952,6 +5953,8 @@ const augmentKonvaNodeClass = (config) => {
5952
5953
  Konva.Node.prototype.triggerCrop = function() {};
5953
5954
  Konva.Node.prototype.closeCrop = function() {};
5954
5955
  Konva.Node.prototype.resetCrop = function() {};
5956
+ Konva.Node.prototype.flipHorizontal = function() {};
5957
+ Konva.Node.prototype.flipVertical = function() {};
5955
5958
  Konva.Node.prototype.dblClick = function() {};
5956
5959
  Konva.Node.prototype.click = function() {};
5957
5960
  Konva.Node.prototype.allowedAnchors = function() {
@@ -6037,6 +6040,8 @@ var WeaveNode = class {
6037
6040
  };
6038
6041
  node.updatePosition = function() {};
6039
6042
  node.resetCrop = function() {};
6043
+ node.flipHorizontal = function() {};
6044
+ node.flipVertical = function() {};
6040
6045
  node.handleMouseover = function() {};
6041
6046
  node.handleMouseout = function() {};
6042
6047
  node.handleSelectNode = function() {};
@@ -6207,7 +6212,7 @@ var WeaveNode = class {
6207
6212
  node.draggable(false);
6208
6213
  };
6209
6214
  if (node.getAttrs().locked ?? false) {
6210
- this.instance.removeEventListener("onNodesChange", handleNodesChange);
6215
+ this.removeNodeInstanceListeners(node, false);
6211
6216
  node.off("transformstart");
6212
6217
  node.off("transform");
6213
6218
  node.off("transformend");
@@ -6217,7 +6222,7 @@ var WeaveNode = class {
6217
6222
  node.off("pointerover");
6218
6223
  node.off("pointerleave");
6219
6224
  } else {
6220
- this.instance.addEventListener("onNodesChange", handleNodesChange);
6225
+ this.setNodeInstanceListener(node, "onNodesChange", handleNodesChange);
6221
6226
  node.off("transformstart");
6222
6227
  node.on("transformstart", (e) => {
6223
6228
  if (e.target.getAttrs().strokeScaleEnabled !== false) {
@@ -6276,7 +6281,7 @@ var WeaveNode = class {
6276
6281
  });
6277
6282
  const stage = this.instance.getStage();
6278
6283
  let originalPosition = null;
6279
- this.instance.addEventListener("onSelectionState", (state) => {
6284
+ this.setNodeInstanceListener(node, "onSelectionState", (state) => {
6280
6285
  const selectedNodes = this.getSelectionPlugin()?.getSelectedNodes() ?? [];
6281
6286
  if (!state && selectedNodes?.some((n) => n.getAttrs().id === node.getAttrs().id)) originalPosition = node.getAbsolutePosition();
6282
6287
  });
@@ -6592,8 +6597,39 @@ var WeaveNode = class {
6592
6597
  async onRegister() {}
6593
6598
  onAdd(nodeInstance) {}
6594
6599
  onDestroy(nodeInstance) {
6600
+ this.removeNodeInstanceListeners(nodeInstance);
6595
6601
  nodeInstance.destroy();
6596
6602
  }
6603
+ /**
6604
+ * Registers a Weave instance listener on behalf of a node. Only one listener
6605
+ * is kept per node and event: registering the same event again for the same
6606
+ * node replaces the previous listener, including the ones registered by
6607
+ * setupDefaultNodeEvents (onNodesChange, onSelectionState).
6608
+ */
6609
+ setNodeInstanceListener(node, event, callback) {
6610
+ let listeners = nodeInstanceListeners.get(node);
6611
+ if (!listeners) {
6612
+ listeners = /* @__PURE__ */ new Map();
6613
+ nodeInstanceListeners.set(node, listeners);
6614
+ }
6615
+ const previous = listeners.get(event);
6616
+ if (previous) this.instance.removeEventListener(event, previous);
6617
+ listeners.set(event, callback);
6618
+ this.instance.addEventListener(event, callback);
6619
+ }
6620
+ /**
6621
+ * Removes the listeners registered with setNodeInstanceListener for the node
6622
+ * and, unless disabled, for its descendants.
6623
+ */
6624
+ removeNodeInstanceListeners(node, includeDescendants = true) {
6625
+ const nodes = includeDescendants && node instanceof Konva.Container ? [node, ...node.find(() => true)] : [node];
6626
+ for (const actNode of nodes) {
6627
+ const listeners = nodeInstanceListeners.get(actNode);
6628
+ if (!listeners) continue;
6629
+ for (const [event, callback] of listeners) this.instance.removeEventListener(event, callback);
6630
+ nodeInstanceListeners.delete(actNode);
6631
+ }
6632
+ }
6597
6633
  onDestroyInstance() {}
6598
6634
  serialize(instance) {
6599
6635
  const attrs = instance.getAttrs();
@@ -9466,7 +9502,7 @@ var WeaveRegisterManager = class {
9466
9502
  };
9467
9503
  //#endregion
9468
9504
  //#region package.json
9469
- var version = "5.4.1";
9505
+ var version = "5.6.0";
9470
9506
  //#endregion
9471
9507
  //#region src/managers/setup.ts
9472
9508
  var WeaveSetupManager = class {
@@ -11187,6 +11223,9 @@ var Weave = class {
11187
11223
  getBoundingBox(nodes, config) {
11188
11224
  return getBoundingBox(nodes, config);
11189
11225
  }
11226
+ flipImage(node, options) {
11227
+ this.getNodeHandler("image")?.flipImage(node, options);
11228
+ }
11190
11229
  stateTransactional(callback, origin) {
11191
11230
  this.stateManager.stateTransactional(callback, origin);
11192
11231
  }
@@ -14444,24 +14483,64 @@ var WeaveImageCrop = class WeaveImageCrop {
14444
14483
  this.onClose = () => {};
14445
14484
  this.handleHide = this.hide.bind(this);
14446
14485
  }
14447
- setupCropImage(imageAttrs, visible) {
14448
- this.cropGroup.destroyChildren();
14486
+ /**
14487
+ * Mirrors the start of a segment inside a container along one axis:
14488
+ * the segment [start, start + length] inside [0, size] becomes
14489
+ * [size - start - length, size - start]. Used to convert between visual
14490
+ * space (what the user sees on a flipped image) and source space (where
14491
+ * the crop information is stored). It is its own inverse.
14492
+ */
14493
+ static mirrorOffset(start, length, size) {
14494
+ return size - start - length;
14495
+ }
14496
+ /**
14497
+ * Returns the offset (in uncropped display units) of the visible crop
14498
+ * window inside the visually rendered uncropped image, along with the real
14499
+ * scale. When the image is flipped the stored crop (source space) is
14500
+ * mirrored to match what the user sees.
14501
+ */
14502
+ getVisualCropOffset(imageAttrs) {
14449
14503
  const actualScale = imageAttrs.uncroppedImage.width / imageAttrs.imageInfo.width;
14450
14504
  const realScale = actualScale / (imageAttrs.cropInfo ? imageAttrs.cropInfo.scaleX : actualScale);
14505
+ let x = 0;
14506
+ let y = 0;
14507
+ if (imageAttrs.cropInfo) {
14508
+ x = imageAttrs.cropInfo.x * realScale;
14509
+ y = imageAttrs.cropInfo.y * realScale;
14510
+ if (imageAttrs.flipX === true) x = WeaveImageCrop.mirrorOffset(x, imageAttrs.cropInfo.width * realScale, imageAttrs.uncroppedImage.width);
14511
+ if (imageAttrs.flipY === true) y = WeaveImageCrop.mirrorOffset(y, imageAttrs.cropInfo.height * realScale, imageAttrs.uncroppedImage.height);
14512
+ }
14513
+ return {
14514
+ x,
14515
+ y,
14516
+ realScale
14517
+ };
14518
+ }
14519
+ setupCropImage(imageAttrs, visible) {
14520
+ this.cropGroup.destroyChildren();
14521
+ const { x, y, realScale } = this.getVisualCropOffset(imageAttrs);
14522
+ const flipX = imageAttrs.flipX === true;
14523
+ const flipY = imageAttrs.flipY === true;
14451
14524
  this.cropImage = new Konva.Image({
14452
- x: imageAttrs.cropInfo ? -imageAttrs.cropInfo.x * realScale : 0,
14453
- y: imageAttrs.cropInfo ? -imageAttrs.cropInfo.y * realScale : 0,
14525
+ x: -x,
14526
+ y: -y,
14454
14527
  width: imageAttrs.uncroppedImage.width,
14455
14528
  height: imageAttrs.uncroppedImage.height,
14456
- scaleX: 1,
14457
- scaleY: 1,
14529
+ scaleX: flipX ? -1 : 1,
14530
+ scaleY: flipY ? -1 : 1,
14531
+ offsetX: flipX ? imageAttrs.uncroppedImage.width : 0,
14532
+ offsetY: flipY ? imageAttrs.uncroppedImage.height : 0,
14458
14533
  image: this.internalImage.image(),
14459
14534
  crop: void 0,
14460
14535
  visible,
14461
14536
  listening: false,
14462
14537
  draggable: false
14463
14538
  });
14464
- return { realScale };
14539
+ return {
14540
+ realScale,
14541
+ offsetX: x,
14542
+ offsetY: y
14543
+ };
14465
14544
  }
14466
14545
  show(onClose, options) {
14467
14546
  this.onClose = onClose;
@@ -14472,9 +14551,9 @@ var WeaveImageCrop = class WeaveImageCrop {
14472
14551
  this.image.listening(false);
14473
14552
  const imageAttrs = this.image.getAttrs();
14474
14553
  this.internalImage.hide();
14475
- const { realScale } = this.setupCropImage(imageAttrs, true);
14476
- this.imageOffsetX = imageAttrs.cropInfo ? imageAttrs.cropInfo.x * realScale : 0;
14477
- this.imageOffsetY = imageAttrs.cropInfo ? imageAttrs.cropInfo.y * realScale : 0;
14554
+ const { realScale, offsetX, offsetY } = this.setupCropImage(imageAttrs, true);
14555
+ this.imageOffsetX = offsetX;
14556
+ this.imageOffsetY = offsetY;
14478
14557
  const cropModeConfiguration = this.node.getConfiguration().cropMode;
14479
14558
  this.cropRect = new Konva.Rect({
14480
14559
  x: 0,
@@ -14522,7 +14601,10 @@ var WeaveImageCrop = class WeaveImageCrop {
14522
14601
  const center = this.cropImage.getAbsolutePosition();
14523
14602
  const width = this.cropImage.width() * stage.scaleX();
14524
14603
  const height = this.cropImage.height() * stage.scaleY();
14525
- const offset = this.cropImage.offset();
14604
+ const offset = {
14605
+ x: this.cropImage.scaleX() < 0 ? 0 : this.cropImage.offsetX(),
14606
+ y: this.cropImage.scaleY() < 0 ? 0 : this.cropImage.offsetY()
14607
+ };
14526
14608
  const corners = [
14527
14609
  {
14528
14610
  x: -offset.x,
@@ -14866,11 +14948,15 @@ var WeaveImageCrop = class WeaveImageCrop {
14866
14948
  if (!intersectionRect) return;
14867
14949
  const imageAttrs = this.image.getAttrs();
14868
14950
  const actualScale = imageAttrs.uncroppedImage.width / imageAttrs.imageInfo.width;
14951
+ let sourceX = clipRectGroup.x + this.imageOffsetX;
14952
+ let sourceY = clipRectGroup.y + this.imageOffsetY;
14953
+ if (imageAttrs.flipX === true) sourceX = WeaveImageCrop.mirrorOffset(sourceX, clipRectGroup.width, imageAttrs.uncroppedImage.width);
14954
+ if (imageAttrs.flipY === true) sourceY = WeaveImageCrop.mirrorOffset(sourceY, clipRectGroup.height, imageAttrs.uncroppedImage.height);
14869
14955
  const realClipRect = {
14870
14956
  scaleX: actualScale,
14871
14957
  scaleY: actualScale,
14872
- x: WeaveImageCrop.roundTo6Decimals(clipRectGroup.x + this.imageOffsetX),
14873
- y: WeaveImageCrop.roundTo6Decimals(clipRectGroup.y + this.imageOffsetY),
14958
+ x: WeaveImageCrop.roundTo6Decimals(sourceX),
14959
+ y: WeaveImageCrop.roundTo6Decimals(sourceY),
14874
14960
  width: WeaveImageCrop.roundTo6Decimals(clipRectGroup.width),
14875
14961
  height: WeaveImageCrop.roundTo6Decimals(clipRectGroup.height)
14876
14962
  };
@@ -14912,16 +14998,18 @@ var WeaveImageCrop = class WeaveImageCrop {
14912
14998
  if (!intersectionRect || !intersectionRectAbs) return;
14913
14999
  const imageAttrs = this.image.getAttrs();
14914
15000
  const actualScale = imageAttrs.uncroppedImage.width / imageAttrs.imageInfo.width;
14915
- const realScale = actualScale / (imageAttrs.cropInfo ? imageAttrs.cropInfo.scaleX : actualScale);
14916
- const imageOffsetX = imageAttrs.cropInfo ? imageAttrs.cropInfo.x * realScale : 0;
14917
- const imageOffsetY = imageAttrs.cropInfo ? imageAttrs.cropInfo.y * realScale : 0;
15001
+ const { x: imageOffsetX, y: imageOffsetY } = this.getVisualCropOffset(imageAttrs);
14918
15002
  const diffX = intersectionRect.x - imageRect.x;
14919
15003
  const diffY = intersectionRect.y - imageRect.y;
15004
+ let sourceX = diffX + imageOffsetX;
15005
+ let sourceY = diffY + imageOffsetY;
15006
+ if (imageAttrs.flipX === true) sourceX = WeaveImageCrop.mirrorOffset(sourceX, intersectionRect.width, imageAttrs.uncroppedImage.width);
15007
+ if (imageAttrs.flipY === true) sourceY = WeaveImageCrop.mirrorOffset(sourceY, intersectionRect.height, imageAttrs.uncroppedImage.height);
14920
15008
  const realClipRect = {
14921
15009
  scaleX: actualScale,
14922
15010
  scaleY: actualScale,
14923
- x: WeaveImageCrop.roundTo6Decimals(diffX + imageOffsetX),
14924
- y: WeaveImageCrop.roundTo6Decimals(diffY + imageOffsetY),
15011
+ x: WeaveImageCrop.roundTo6Decimals(sourceX),
15012
+ y: WeaveImageCrop.roundTo6Decimals(sourceY),
14925
15013
  width: WeaveImageCrop.roundTo6Decimals(intersectionRect.width),
14926
15014
  height: WeaveImageCrop.roundTo6Decimals(intersectionRect.height)
14927
15015
  };
@@ -15227,6 +15315,27 @@ var WeaveImageNode = class extends WeaveNode {
15227
15315
  if (!internalImage || !cropGroup) return;
15228
15316
  new WeaveImageCrop(this.instance, this, imageNode, internalImage, cropGroup).unCrop();
15229
15317
  };
15318
+ flipImage = (imageNode, options) => {
15319
+ if (imageNode.getAttrs().cropping) return;
15320
+ const prop = options.axis === "horizontal" ? "flipX" : "flipY";
15321
+ this.instance.stateTransactional(() => {
15322
+ imageNode.setAttrs({ [prop]: !(imageNode.getAttrs()[prop] ?? false) });
15323
+ this.applyFlip(imageNode);
15324
+ this.cacheNode(imageNode);
15325
+ this.instance.updateNode(this.serialize(imageNode));
15326
+ });
15327
+ };
15328
+ applyFlip(image) {
15329
+ const attrs = image.getAttrs();
15330
+ const internalImage = image.findOne(`#${attrs.id}-image`);
15331
+ if (!internalImage) return;
15332
+ const flipX = attrs.flipX === true;
15333
+ const flipY = attrs.flipY === true;
15334
+ internalImage.scaleX(flipX ? -1 : 1);
15335
+ internalImage.scaleY(flipY ? -1 : 1);
15336
+ internalImage.offsetX(flipX ? internalImage.width() : 0);
15337
+ internalImage.offsetY(flipY ? internalImage.height() : 0);
15338
+ }
15230
15339
  loadAsyncElement(nodeId) {
15231
15340
  this.instance.loadAsyncElement(nodeId, WEAVE_IMAGE_NODE_TYPE);
15232
15341
  }
@@ -15274,6 +15383,12 @@ var WeaveImageNode = class extends WeaveNode {
15274
15383
  new WeaveImageCrop(this.instance, this, image, internalImage, cropGroup).unCrop();
15275
15384
  };
15276
15385
  }
15386
+ image.flipHorizontal = () => {
15387
+ this.flipImage(image, { axis: "horizontal" });
15388
+ };
15389
+ image.flipVertical = () => {
15390
+ this.flipImage(image, { axis: "vertical" });
15391
+ };
15277
15392
  const defaultTransformerProperties = this.defaultGetTransformerProperties(this.config.transform);
15278
15393
  image.getTransformerProperties = function() {
15279
15394
  return defaultTransformerProperties;
@@ -15889,6 +16004,10 @@ var WeaveImageNode = class extends WeaveNode {
15889
16004
  if (!this.imageState[imageAttrs.id ?? ""]?.loaded) return;
15890
16005
  }
15891
16006
  updateImageCrop(image) {
16007
+ this.updateImageCropGeometry(image);
16008
+ this.applyFlip(image);
16009
+ }
16010
+ updateImageCropGeometry(image) {
15892
16011
  const imageAttrs = image.getAttrs();
15893
16012
  const internalImage = image?.findOne(`#${imageAttrs.id}-image`);
15894
16013
  if (!this.imageState[imageAttrs.id ?? ""]?.loaded) return;
@@ -15966,8 +16085,12 @@ var WeaveImageNode = class extends WeaveNode {
15966
16085
  });
15967
16086
  }
15968
16087
  if (internalImage) {
15969
- internalImage.width(Math.max(5, internalImage.width() * internalImage.scaleX()));
15970
- internalImage.height(Math.max(5, internalImage.height() * internalImage.scaleY()));
16088
+ internalImage.offset({
16089
+ x: 0,
16090
+ y: 0
16091
+ });
16092
+ internalImage.width(Math.max(5, internalImage.width() * Math.abs(internalImage.scaleX())));
16093
+ internalImage.height(Math.max(5, internalImage.height() * Math.abs(internalImage.scaleY())));
15971
16094
  internalImage.scale({
15972
16095
  x: 1,
15973
16096
  y: 1
@@ -16022,7 +16145,7 @@ var WeaveImageNode = class extends WeaveNode {
16022
16145
  clearTimeout(this.imageTryoutIds[nodeId]);
16023
16146
  delete this.imageTryoutIds[nodeId];
16024
16147
  }
16025
- nodeInstance.destroy();
16148
+ super.onDestroy(nodeInstance);
16026
16149
  }
16027
16150
  loadImageTryout(imageId) {
16028
16151
  this.imageTryoutIds[imageId] = setTimeout(() => {
@@ -16109,7 +16232,9 @@ var WeaveImageNode = class extends WeaveNode {
16109
16232
  width: props.uncroppedImage.width,
16110
16233
  height: props.uncroppedImage.height
16111
16234
  },
16112
- cropping: props.cropping
16235
+ cropping: props.cropping,
16236
+ ...props.flipX !== void 0 && { flipX: props.flipX },
16237
+ ...props.flipY !== void 0 && { flipY: props.flipY }
16113
16238
  } });
16114
16239
  }
16115
16240
  static updateNodeState(prevNodeState, nextProps) {
@@ -16132,7 +16257,9 @@ var WeaveImageNode = class extends WeaveNode {
16132
16257
  width: nextProps.uncroppedImage?.width,
16133
16258
  height: nextProps.uncroppedImage?.height
16134
16259
  } },
16135
- cropping: nextProps.cropping
16260
+ cropping: nextProps.cropping,
16261
+ ...nextProps.flipX !== void 0 && { flipX: nextProps.flipX },
16262
+ ...nextProps.flipY !== void 0 && { flipY: nextProps.flipY }
16136
16263
  } });
16137
16264
  }
16138
16265
  static getSchema() {
@@ -16156,7 +16283,9 @@ var WeaveImageNode = class extends WeaveNode {
16156
16283
  width: z.number().describe("The width of the image before cropping, used for cropping calculations"),
16157
16284
  height: z.number().describe("The height of the image before cropping, used for cropping calculations")
16158
16285
  }),
16159
- cropping: z.boolean().default(false).describe("Whether the image is currently being cropped")
16286
+ cropping: z.boolean().default(false).describe("Whether the image is currently being cropped"),
16287
+ flipX: z.boolean().optional().describe("Whether the image is flipped horizontally"),
16288
+ flipY: z.boolean().optional().describe("Whether the image is flipped vertically")
16160
16289
  })
16161
16290
  });
16162
16291
  }
@@ -19585,7 +19714,7 @@ var WeaveCommentNode = class extends WeaveNode {
19585
19714
  this.normalizeNodeSize(commentNode);
19586
19715
  }
19587
19716
  onDestroy(nodeInstance) {
19588
- nodeInstance.destroy();
19717
+ super.onDestroy(nodeInstance);
19589
19718
  }
19590
19719
  expandNode(commentNode) {
19591
19720
  const widthExpanded = this.config.style.expanded.width;
@@ -23239,6 +23368,70 @@ const RECTANGLE_TOOL_STATE = {
23239
23368
  ["ADDED"]: "added"
23240
23369
  };
23241
23370
  //#endregion
23371
+ //#region src/actions/shared/shape-geometry.ts
23372
+ /** Returns the normalized bounds described by a drag, including its modifiers. */
23373
+ function getShapeDragBounds(anchor, pointer, options = {}) {
23374
+ const { centered = false, constrained = false, aspectRatio = 1 } = options;
23375
+ const deltaX = Math.abs(pointer.x - anchor.x);
23376
+ const deltaY = Math.abs(pointer.y - anchor.y);
23377
+ let width = deltaX;
23378
+ let height = deltaY;
23379
+ if (constrained && aspectRatio > 0) {
23380
+ if (width / (height || Number.EPSILON) > aspectRatio) height = width / aspectRatio;
23381
+ else width = height * aspectRatio;
23382
+ }
23383
+ if (constrained && aspectRatio > 0 && width > 0 && height > 0) {
23384
+ const minimumSizeScale = Math.max(1, 1 / width, 1 / height);
23385
+ width *= minimumSizeScale;
23386
+ height *= minimumSizeScale;
23387
+ } else {
23388
+ width = Math.max(1, width);
23389
+ height = Math.max(1, height);
23390
+ }
23391
+ if (centered) {
23392
+ width *= 2;
23393
+ height *= 2;
23394
+ return {
23395
+ x: anchor.x - width / 2,
23396
+ y: anchor.y - height / 2,
23397
+ width,
23398
+ height
23399
+ };
23400
+ }
23401
+ const signedWidth = Math.sign(pointer.x - anchor.x || 1) * width;
23402
+ const signedHeight = Math.sign(pointer.y - anchor.y || 1) * height;
23403
+ return {
23404
+ x: Math.min(anchor.x, anchor.x + signedWidth),
23405
+ y: Math.min(anchor.y, anchor.y + signedHeight),
23406
+ width,
23407
+ height
23408
+ };
23409
+ }
23410
+ //#endregion
23411
+ //#region src/actions/shared/shape-keyboard.ts
23412
+ /** Binds the common keyboard behavior for tools that create shapes by dragging. */
23413
+ function bindShapeDragKeyboardHandlers(signal, isActionActive, isDragInProgress, canUpdateModifiers, onCancel, onModifiersChange) {
23414
+ const handleModifierKey = (event) => {
23415
+ if (event.key !== "Shift" && event.key !== "Alt") return;
23416
+ const actionActive = isActionActive();
23417
+ const dragInProgress = isDragInProgress();
23418
+ if (event.type === "keydown" && event.key === "Alt" && actionActive && dragInProgress) event.preventDefault();
23419
+ if (!actionActive || !canUpdateModifiers()) return;
23420
+ onModifiersChange({
23421
+ shiftKey: event.shiftKey,
23422
+ altKey: event.altKey
23423
+ });
23424
+ };
23425
+ window.addEventListener("keydown", (event) => {
23426
+ if (isActionActive() && (event.code === "Enter" || event.code === "Escape")) {
23427
+ onCancel();
23428
+ return;
23429
+ }
23430
+ handleModifierKey(event);
23431
+ }, { signal });
23432
+ window.addEventListener("keyup", handleModifierKey, { signal });
23433
+ }
23434
+ //#endregion
23242
23435
  //#region src/actions/rectangle-tool/rectangle-tool.ts
23243
23436
  var WeaveRectangleToolAction = class extends WeaveAction {
23244
23437
  initialized = false;
@@ -23284,16 +23477,7 @@ var WeaveRectangleToolAction = class extends WeaveAction {
23284
23477
  }
23285
23478
  setupEvents() {
23286
23479
  const stage = this.instance.getStage();
23287
- window.addEventListener("keydown", (e) => {
23288
- if (e.code === "Enter" && this.instance.getActiveAction() === "rectangleTool") {
23289
- this.cancelAction();
23290
- return;
23291
- }
23292
- if (e.code === "Escape" && this.instance.getActiveAction() === "rectangleTool") {
23293
- this.cancelAction();
23294
- return;
23295
- }
23296
- }, { signal: this.instance.getEventsController().signal });
23480
+ bindShapeDragKeyboardHandlers(this.instance.getEventsController().signal, () => this.instance.getActiveAction() === RECTANGLE_TOOL_ACTION_NAME, () => this.state === RECTANGLE_TOOL_STATE.DEFINING_SIZE, () => this.state === RECTANGLE_TOOL_STATE.DEFINING_SIZE && this.moved, () => this.cancelAction(), (modifiers) => this.handleMovement(modifiers));
23297
23481
  stage.on("pointermove", () => {
23298
23482
  if (this.state === RECTANGLE_TOOL_STATE.IDLE) return;
23299
23483
  this.setCursor();
@@ -23319,12 +23503,12 @@ var WeaveRectangleToolAction = class extends WeaveAction {
23319
23503
  this.state = RECTANGLE_TOOL_STATE.ADDING;
23320
23504
  return;
23321
23505
  }
23322
- if (this.state === RECTANGLE_TOOL_STATE.DEFINING_SIZE) this.handleMovement();
23506
+ if (this.state === RECTANGLE_TOOL_STATE.DEFINING_SIZE) this.handleMovement(e.evt);
23323
23507
  });
23324
23508
  stage.on("pointerup", (e) => {
23325
23509
  this.pointers.delete(e.evt.pointerId);
23326
23510
  if (this.isTap(e)) this.moved = false;
23327
- if (this.state === RECTANGLE_TOOL_STATE.DEFINING_SIZE) this.handleSettingSize();
23511
+ if (this.state === RECTANGLE_TOOL_STATE.DEFINING_SIZE) this.handleSettingSize(e.evt);
23328
23512
  });
23329
23513
  this.initialized = true;
23330
23514
  }
@@ -23358,7 +23542,7 @@ var WeaveRectangleToolAction = class extends WeaveAction {
23358
23542
  }
23359
23543
  this.setState(RECTANGLE_TOOL_STATE.DEFINING_SIZE);
23360
23544
  }
23361
- handleSettingSize() {
23545
+ handleSettingSize(modifiers = {}) {
23362
23546
  if (this.rectId && this.tempRectNode && this.clickPoint && this.container) {
23363
23547
  const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.container);
23364
23548
  const rectPos = {
@@ -23368,10 +23552,14 @@ var WeaveRectangleToolAction = class extends WeaveAction {
23368
23552
  let rectWidth = this.props.width;
23369
23553
  let rectHeight = this.props.height;
23370
23554
  if (this.moved) {
23371
- rectPos.x = Math.min(this.clickPoint.x, mousePoint.x);
23372
- rectPos.y = Math.min(this.clickPoint.y, mousePoint.y);
23373
- rectWidth = Math.abs(this.clickPoint.x - mousePoint.x);
23374
- rectHeight = Math.abs(this.clickPoint.y - mousePoint.y);
23555
+ const bounds = getShapeDragBounds(this.clickPoint, mousePoint, {
23556
+ centered: modifiers.altKey,
23557
+ constrained: modifiers.shiftKey
23558
+ });
23559
+ rectPos.x = bounds.x;
23560
+ rectPos.y = bounds.y;
23561
+ rectWidth = bounds.width;
23562
+ rectHeight = bounds.height;
23375
23563
  }
23376
23564
  this.tempRectNode.setAttrs({
23377
23565
  ...this.props,
@@ -23403,16 +23591,20 @@ var WeaveRectangleToolAction = class extends WeaveAction {
23403
23591
  }
23404
23592
  this.cancelAction();
23405
23593
  }
23406
- handleMovement() {
23594
+ handleMovement(modifiers = {}) {
23407
23595
  if (this.state !== RECTANGLE_TOOL_STATE.DEFINING_SIZE) return;
23408
23596
  if (this.rectId && this.tempRectNode && this.measureContainer && this.clickPoint) {
23409
23597
  this.moved = true;
23410
23598
  const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.measureContainer);
23411
- const deltaX = mousePoint.x - this.clickPoint?.x;
23412
- const deltaY = mousePoint.y - this.clickPoint?.y;
23599
+ const bounds = getShapeDragBounds(this.clickPoint, mousePoint, {
23600
+ centered: modifiers.altKey,
23601
+ constrained: modifiers.shiftKey
23602
+ });
23413
23603
  this.tempRectNode.setAttrs({
23414
- width: deltaX,
23415
- height: deltaY
23604
+ x: bounds.x,
23605
+ y: bounds.y,
23606
+ width: bounds.width,
23607
+ height: bounds.height
23416
23608
  });
23417
23609
  }
23418
23610
  }
@@ -23511,16 +23703,7 @@ var WeaveEllipseToolAction = class extends WeaveAction {
23511
23703
  }
23512
23704
  setupEvents() {
23513
23705
  const stage = this.instance.getStage();
23514
- window.addEventListener("keydown", (e) => {
23515
- if (e.code === "Enter" && this.instance.getActiveAction() === "ellipseTool") {
23516
- this.cancelAction();
23517
- return;
23518
- }
23519
- if (e.code === "Escape" && this.instance.getActiveAction() === "ellipseTool") {
23520
- this.cancelAction();
23521
- return;
23522
- }
23523
- }, { signal: this.instance.getEventsController().signal });
23706
+ bindShapeDragKeyboardHandlers(this.instance.getEventsController().signal, () => this.instance.getActiveAction() === ELLIPSE_TOOL_ACTION_NAME, () => this.state === ELLIPSE_TOOL_STATE.DEFINING_SIZE, () => this.state === ELLIPSE_TOOL_STATE.DEFINING_SIZE && this.moved, () => this.cancelAction(), (modifiers) => this.handleMovement(modifiers));
23524
23707
  stage.on("pointerdown", (e) => {
23525
23708
  this.setTapStart(e);
23526
23709
  this.pointers.set(e.evt.pointerId, {
@@ -23547,7 +23730,7 @@ var WeaveEllipseToolAction = class extends WeaveAction {
23547
23730
  }
23548
23731
  if (this.state === ELLIPSE_TOOL_STATE.DEFINING_SIZE) {
23549
23732
  this.moved = true;
23550
- this.handleMovement();
23733
+ this.handleMovement(e.evt);
23551
23734
  }
23552
23735
  });
23553
23736
  stage.on("pointerup", (e) => {
@@ -23555,7 +23738,7 @@ var WeaveEllipseToolAction = class extends WeaveAction {
23555
23738
  if (this.isTap(e)) this.moved = false;
23556
23739
  if (this.state === ELLIPSE_TOOL_STATE.DEFINING_SIZE) {
23557
23740
  this.creating = false;
23558
- this.handleSettingSize();
23741
+ this.handleSettingSize(e.evt);
23559
23742
  }
23560
23743
  });
23561
23744
  this.initialized = true;
@@ -23579,8 +23762,8 @@ var WeaveEllipseToolAction = class extends WeaveAction {
23579
23762
  if (nodeHandler) {
23580
23763
  const node = nodeHandler.create(this.ellipseId, {
23581
23764
  ...this.props,
23582
- x: this.clickPoint?.x ?? 0 + this.props.radiusX,
23583
- y: this.clickPoint?.y ?? 0 + this.props.radiusY,
23765
+ x: this.clickPoint?.x ?? 0,
23766
+ y: this.clickPoint?.y ?? 0,
23584
23767
  radiusX: 1,
23585
23768
  radiusY: 1
23586
23769
  });
@@ -23588,22 +23771,28 @@ var WeaveEllipseToolAction = class extends WeaveAction {
23588
23771
  }
23589
23772
  this.setState(ELLIPSE_TOOL_STATE.DEFINING_SIZE);
23590
23773
  }
23591
- handleSettingSize() {
23774
+ handleSettingSize(modifiers = {}) {
23592
23775
  const ellipse = this.instance.getStage().findOne(`#${this.ellipseId}`);
23593
23776
  if (this.ellipseId && this.clickPoint && this.container && ellipse) {
23594
23777
  const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.container);
23595
23778
  const nodeHandler = this.instance.getNodeHandler("ellipse");
23596
- const ellipsePos = {
23779
+ let ellipsePos = {
23597
23780
  x: this.clickPoint.x,
23598
23781
  y: this.clickPoint.y
23599
23782
  };
23600
- let ellipseRadiusX = this.props.radiusY;
23783
+ let ellipseRadiusX = this.props.radiusX;
23601
23784
  let ellipseRadiusY = this.props.radiusY;
23602
23785
  if (this.moved) {
23603
- ellipsePos.x = Math.min(this.clickPoint.x, mousePoint.x);
23604
- ellipsePos.y = Math.min(this.clickPoint.y, mousePoint.y);
23605
- ellipseRadiusX = Math.abs(this.clickPoint.x - mousePoint.x);
23606
- ellipseRadiusY = Math.abs(this.clickPoint.y - mousePoint.y);
23786
+ const bounds = getShapeDragBounds(this.clickPoint, mousePoint, {
23787
+ centered: modifiers.altKey,
23788
+ constrained: modifiers.shiftKey
23789
+ });
23790
+ ellipsePos = {
23791
+ x: bounds.x,
23792
+ y: bounds.y
23793
+ };
23794
+ ellipseRadiusX = bounds.width;
23795
+ ellipseRadiusY = bounds.height;
23607
23796
  }
23608
23797
  ellipse.setAttrs({
23609
23798
  ...this.props,
@@ -23617,27 +23806,23 @@ var WeaveEllipseToolAction = class extends WeaveAction {
23617
23806
  }
23618
23807
  this.cancelAction();
23619
23808
  }
23620
- handleMovement() {
23809
+ handleMovement(modifiers = {}) {
23621
23810
  if (this.state !== ELLIPSE_TOOL_STATE.DEFINING_SIZE) return;
23622
23811
  const ellipse = this.instance.getStage().findOne(`#${this.ellipseId}`);
23623
23812
  if (this.ellipseId && this.container && this.clickPoint && ellipse) {
23624
23813
  const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.container);
23625
- const deltaX = Math.abs(mousePoint.x - this.clickPoint?.x);
23626
- const deltaY = Math.abs(mousePoint.y - this.clickPoint?.y);
23627
- const ellipsePos = {
23628
- x: this.clickPoint.x,
23629
- y: this.clickPoint.y
23630
- };
23631
- if (this.moved) {
23632
- ellipsePos.x = Math.min(this.clickPoint.x, mousePoint.x);
23633
- ellipsePos.y = Math.min(this.clickPoint.y, mousePoint.y);
23634
- }
23814
+ const bounds = getShapeDragBounds(this.clickPoint, mousePoint, {
23815
+ centered: modifiers.altKey,
23816
+ constrained: modifiers.shiftKey
23817
+ });
23635
23818
  const nodeHandler = this.instance.getNodeHandler("ellipse");
23636
23819
  if (nodeHandler) nodeHandler.onUpdate(ellipse, {
23637
23820
  ...this.props,
23638
23821
  id: this.ellipseId,
23639
- radiusX: deltaX / 2,
23640
- radiusY: deltaY / 2
23822
+ x: bounds.x,
23823
+ y: bounds.y,
23824
+ radiusX: bounds.width / 2,
23825
+ radiusY: bounds.height / 2
23641
23826
  });
23642
23827
  }
23643
23828
  }
@@ -26608,16 +26793,7 @@ var WeaveRegularPolygonToolAction = class extends WeaveAction {
26608
26793
  }
26609
26794
  setupEvents() {
26610
26795
  const stage = this.instance.getStage();
26611
- window.addEventListener("keydown", (e) => {
26612
- if (e.code === "Enter" && this.instance.getActiveAction() === "regularPolygonTool") {
26613
- this.cancelAction();
26614
- return;
26615
- }
26616
- if (e.code === "Escape" && this.instance.getActiveAction() === "regularPolygonTool") {
26617
- this.cancelAction();
26618
- return;
26619
- }
26620
- }, { signal: this.instance.getEventsController().signal });
26796
+ bindShapeDragKeyboardHandlers(this.instance.getEventsController().signal, () => this.instance.getActiveAction() === REGULAR_POLYGON_TOOL_ACTION_NAME, () => this.state === REGULAR_POLYGON_TOOL_STATE.DEFINING_SIZE, () => this.state === REGULAR_POLYGON_TOOL_STATE.DEFINING_SIZE && this.moved, () => this.cancelAction(), (modifiers) => this.handleMovement(modifiers));
26621
26797
  stage.on("pointerdown", (e) => {
26622
26798
  this.setTapStart(e);
26623
26799
  this.pointers.set(e.evt.pointerId, {
@@ -26644,7 +26820,7 @@ var WeaveRegularPolygonToolAction = class extends WeaveAction {
26644
26820
  }
26645
26821
  if (this.state === REGULAR_POLYGON_TOOL_STATE.DEFINING_SIZE) {
26646
26822
  this.moved = true;
26647
- this.handleMovement();
26823
+ this.handleMovement(e.evt);
26648
26824
  }
26649
26825
  });
26650
26826
  stage.on("pointerup", (e) => {
@@ -26652,7 +26828,7 @@ var WeaveRegularPolygonToolAction = class extends WeaveAction {
26652
26828
  if (this.isTap(e)) this.moved = false;
26653
26829
  if (this.state === REGULAR_POLYGON_TOOL_STATE.DEFINING_SIZE) {
26654
26830
  this.creating = false;
26655
- this.handleSettingSize();
26831
+ this.handleSettingSize(e.evt);
26656
26832
  }
26657
26833
  });
26658
26834
  this.initialized = true;
@@ -26684,20 +26860,26 @@ var WeaveRegularPolygonToolAction = class extends WeaveAction {
26684
26860
  }
26685
26861
  this.setState(REGULAR_POLYGON_TOOL_STATE.DEFINING_SIZE);
26686
26862
  }
26687
- handleSettingSize() {
26863
+ handleSettingSize(modifiers = {}) {
26688
26864
  const regularPolygon = this.instance.getStage().findOne(`#${this.regularPolygonId}`);
26689
26865
  if (this.regularPolygonId && this.clickPoint && this.container && regularPolygon) {
26690
26866
  const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.container);
26691
26867
  const nodeHandler = this.instance.getNodeHandler("regular-polygon");
26692
- const starPos = {
26868
+ let starPos = {
26693
26869
  x: this.clickPoint.x,
26694
26870
  y: this.clickPoint.y
26695
26871
  };
26696
26872
  let newRadius = this.props.radius;
26697
26873
  if (this.moved) {
26698
- starPos.x = Math.min(this.clickPoint.x, mousePoint.x);
26699
- starPos.y = Math.min(this.clickPoint.y, mousePoint.y);
26700
- newRadius = Math.abs(this.clickPoint.x - mousePoint.x);
26874
+ const bounds = getShapeDragBounds(this.clickPoint, mousePoint, {
26875
+ centered: modifiers.altKey,
26876
+ constrained: true
26877
+ });
26878
+ starPos = {
26879
+ x: bounds.x,
26880
+ y: bounds.y
26881
+ };
26882
+ newRadius = bounds.width;
26701
26883
  }
26702
26884
  regularPolygon.setAttrs({
26703
26885
  ...this.props,
@@ -26710,25 +26892,22 @@ var WeaveRegularPolygonToolAction = class extends WeaveAction {
26710
26892
  }
26711
26893
  this.cancelAction();
26712
26894
  }
26713
- handleMovement() {
26895
+ handleMovement(modifiers = {}) {
26714
26896
  if (this.state !== REGULAR_POLYGON_TOOL_STATE.DEFINING_SIZE) return;
26715
26897
  const regularPolygon = this.instance.getStage().findOne(`#${this.regularPolygonId}`);
26716
26898
  if (this.regularPolygonId && this.container && this.clickPoint && regularPolygon) {
26717
26899
  const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.container);
26718
- const deltaX = Math.abs(mousePoint.x - this.clickPoint?.x);
26719
- const starPos = {
26720
- x: this.clickPoint.x,
26721
- y: this.clickPoint.y
26722
- };
26723
- if (this.moved) {
26724
- starPos.x = Math.min(this.clickPoint.x, mousePoint.x);
26725
- starPos.y = Math.min(this.clickPoint.y, mousePoint.y);
26726
- }
26900
+ const bounds = getShapeDragBounds(this.clickPoint, mousePoint, {
26901
+ centered: modifiers.altKey,
26902
+ constrained: true
26903
+ });
26727
26904
  const nodeHandler = this.instance.getNodeHandler("regular-polygon");
26728
26905
  if (nodeHandler) nodeHandler.onUpdate(regularPolygon, {
26729
26906
  ...this.props,
26730
26907
  id: this.regularPolygonId,
26731
- radius: deltaX / 2
26908
+ x: bounds.x,
26909
+ y: bounds.y,
26910
+ radius: bounds.width / 2
26732
26911
  });
26733
26912
  }
26734
26913
  }
@@ -26777,14 +26956,22 @@ const POLYGON_TOOL_ACTION_NAME = "polygonTool";
26777
26956
  const POLYGON_TOOL_STATE = {
26778
26957
  ["IDLE"]: "idle",
26779
26958
  ["ADDING"]: "adding",
26959
+ ["DEFINING_SIZE"]: "defining-size",
26780
26960
  ["ADDED"]: "added"
26781
26961
  };
26782
26962
  //#endregion
26783
26963
  //#region src/actions/polygon-tool/polygon-tool.ts
26964
+ const MIN_POLYGON_DRAG_DISTANCE = 3;
26784
26965
  var WeavePolygonToolAction = class extends WeaveAction {
26785
26966
  initialized = false;
26786
26967
  state;
26787
26968
  polygonId;
26969
+ pointers;
26970
+ clickPoint;
26971
+ container;
26972
+ moved;
26973
+ placementCommitted;
26974
+ polygonNode;
26788
26975
  cancelAction;
26789
26976
  preset;
26790
26977
  onPropsChange = void 0;
@@ -26798,6 +26985,12 @@ var WeavePolygonToolAction = class extends WeaveAction {
26798
26985
  this.initialized = false;
26799
26986
  this.state = POLYGON_TOOL_STATE.IDLE;
26800
26987
  this.polygonId = null;
26988
+ this.pointers = /* @__PURE__ */ new Map();
26989
+ this.clickPoint = null;
26990
+ this.container = void 0;
26991
+ this.moved = false;
26992
+ this.placementCommitted = false;
26993
+ this.polygonNode = null;
26801
26994
  this.props = this.initProps();
26802
26995
  }
26803
26996
  getName() {
@@ -26822,18 +27015,41 @@ var WeavePolygonToolAction = class extends WeaveAction {
26822
27015
  }
26823
27016
  setupEvents() {
26824
27017
  const stage = this.instance.getStage();
26825
- window.addEventListener("keydown", (e) => {
26826
- if ((e.code === "Enter" || e.code === "Escape") && this.instance.getActiveAction() === "polygonTool") this.cancelAction();
26827
- }, { signal: this.instance.getEventsController().signal });
27018
+ bindShapeDragKeyboardHandlers(this.instance.getEventsController().signal, () => this.instance.getActiveAction() === POLYGON_TOOL_ACTION_NAME, () => this.state === POLYGON_TOOL_STATE.DEFINING_SIZE, () => this.state === POLYGON_TOOL_STATE.DEFINING_SIZE && this.moved, () => this.cancelAction(), (modifiers) => this.handleMovement(modifiers));
26828
27019
  stage.on("pointermove", () => {
26829
27020
  if (this.state === POLYGON_TOOL_STATE.IDLE) return;
26830
27021
  this.setCursor();
26831
27022
  });
26832
27023
  stage.on("pointerdown", (e) => {
26833
27024
  this.setTapStart(e);
27025
+ this.pointers.set(e.evt.pointerId, {
27026
+ x: e.evt.clientX,
27027
+ y: e.evt.clientY
27028
+ });
26834
27029
  if (this.state !== POLYGON_TOOL_STATE.ADDING) return;
26835
27030
  this.handleAdding();
26836
27031
  });
27032
+ stage.on("pointermove", (e) => {
27033
+ if (this.state === POLYGON_TOOL_STATE.IDLE) return;
27034
+ this.setCursor();
27035
+ if (!this.isPressed(e) || !this.pointers.has(e.evt.pointerId)) return;
27036
+ if (this.state === POLYGON_TOOL_STATE.DEFINING_SIZE) {
27037
+ const pointerStart = this.pointers.get(e.evt.pointerId);
27038
+ if (!pointerStart || Math.hypot(e.evt.clientX - pointerStart.x, e.evt.clientY - pointerStart.y) < MIN_POLYGON_DRAG_DISTANCE) return;
27039
+ this.moved = true;
27040
+ this.handleMovement(e.evt);
27041
+ }
27042
+ });
27043
+ stage.on("pointerup", (e) => {
27044
+ this.pointers.delete(e.evt.pointerId);
27045
+ if (this.isTap(e)) this.moved = false;
27046
+ if (this.state === POLYGON_TOOL_STATE.DEFINING_SIZE) this.handleSettingSize(e.evt);
27047
+ });
27048
+ stage.on("pointercancel", (e) => {
27049
+ if (!this.pointers.has(e.evt.pointerId)) return;
27050
+ this.pointers.delete(e.evt.pointerId);
27051
+ if (this.state === POLYGON_TOOL_STATE.DEFINING_SIZE) this.cancelAction();
27052
+ });
26837
27053
  this.initialized = true;
26838
27054
  }
26839
27055
  setState(state) {
@@ -26847,7 +27063,10 @@ var WeavePolygonToolAction = class extends WeaveAction {
26847
27063
  }
26848
27064
  handleAdding() {
26849
27065
  const { mousePoint, container } = this.instance.getMousePointer();
27066
+ this.clickPoint = mousePoint;
27067
+ this.container = container;
26850
27068
  this.polygonId = v4();
27069
+ this.polygonNode = null;
26851
27070
  const presetDef = WEAVE_POLYGON_PRESETS[this.preset];
26852
27071
  const scaleFactor = this.props.scaleFactor ?? 1;
26853
27072
  const { points, innerRect, width, height } = instantiatePreset(presetDef, presetDef.defaultWidth * scaleFactor, presetDef.defaultHeight * scaleFactor);
@@ -26863,15 +27082,49 @@ var WeavePolygonToolAction = class extends WeaveAction {
26863
27082
  points,
26864
27083
  innerRect
26865
27084
  });
27085
+ this.polygonNode = node;
26866
27086
  this.instance.addNode(node, container?.getAttrs().id);
26867
27087
  }
26868
- this.instance.emitEvent("onAddedPolygon");
27088
+ this.setState(POLYGON_TOOL_STATE.DEFINING_SIZE);
27089
+ }
27090
+ handleMovement(modifiers = {}) {
27091
+ if (this.state !== POLYGON_TOOL_STATE.DEFINING_SIZE || !this.polygonId || !this.clickPoint || !this.container) return;
27092
+ const polygon = this.instance.getStage().findOne(`#${this.polygonId}`);
27093
+ const nodeHandler = this.instance.getNodeHandler(WEAVE_POLYGON_NODE_TYPE);
27094
+ const presetDef = WEAVE_POLYGON_PRESETS[this.preset];
27095
+ if (!polygon || !nodeHandler) return;
27096
+ const { mousePoint } = this.instance.getMousePointerRelativeToContainer(this.container);
27097
+ const defaultGeometry = instantiatePreset(presetDef, presetDef.defaultWidth, presetDef.defaultHeight);
27098
+ const bounds = getShapeDragBounds(this.clickPoint, mousePoint, {
27099
+ centered: modifiers.altKey,
27100
+ constrained: modifiers.shiftKey,
27101
+ aspectRatio: defaultGeometry.width / defaultGeometry.height
27102
+ });
27103
+ const geometry = instantiatePreset(presetDef, bounds.width * presetDef.defaultWidth / defaultGeometry.width, bounds.height * presetDef.defaultHeight / defaultGeometry.height);
27104
+ nodeHandler.onUpdate(polygon, {
27105
+ ...this.props,
27106
+ id: this.polygonId,
27107
+ x: bounds.x,
27108
+ y: bounds.y,
27109
+ ...geometry
27110
+ });
27111
+ }
27112
+ handleSettingSize(modifiers = {}) {
27113
+ if (this.moved) this.handleMovement(modifiers);
27114
+ const polygon = this.polygonId && this.instance.getStage().findOne(`#${this.polygonId}`);
27115
+ const nodeHandler = this.instance.getNodeHandler(WEAVE_POLYGON_NODE_TYPE);
27116
+ if (polygon && nodeHandler) {
27117
+ this.instance.updateNode(nodeHandler.serialize(polygon));
27118
+ this.placementCommitted = true;
27119
+ this.instance.emitEvent("onAddedPolygon");
27120
+ }
26869
27121
  this.cancelAction();
26870
27122
  }
26871
27123
  trigger(cancelAction, params) {
26872
27124
  if (!this.instance) throw new Error("Instance not defined");
26873
27125
  if (!this.initialized) this.setupEvents();
26874
27126
  this.preset = params?.presetId ?? "pentagon";
27127
+ this.placementCommitted = false;
26875
27128
  const stage = this.instance.getStage();
26876
27129
  stage.container().tabIndex = 1;
26877
27130
  stage.container().focus();
@@ -26884,13 +27137,21 @@ var WeavePolygonToolAction = class extends WeaveAction {
26884
27137
  cleanup() {
26885
27138
  const stage = this.instance.getStage();
26886
27139
  stage.container().style.cursor = "default";
27140
+ const isCancelledPlacement = this.state === POLYGON_TOOL_STATE.DEFINING_SIZE && this.polygonId !== null && !this.placementCommitted;
27141
+ if (isCancelledPlacement && this.polygonNode) this.instance.removeNode(this.polygonNode);
26887
27142
  const selectionPlugin = this.instance.getPlugin("nodesSelection");
26888
27143
  if (selectionPlugin) {
26889
- const node = stage.findOne(`#${this.polygonId}`);
27144
+ const node = isCancelledPlacement ? void 0 : stage.findOne(`#${this.polygonId}`);
26890
27145
  if (node) selectionPlugin.setSelectedNodes([node]);
26891
27146
  this.instance.triggerAction(SELECTION_TOOL_ACTION_NAME);
26892
27147
  }
26893
27148
  this.polygonId = null;
27149
+ this.pointers.clear();
27150
+ this.clickPoint = null;
27151
+ this.container = void 0;
27152
+ this.moved = false;
27153
+ this.placementCommitted = false;
27154
+ this.polygonNode = null;
26894
27155
  this.setState(POLYGON_TOOL_STATE.IDLE);
26895
27156
  }
26896
27157
  setCursor() {