@tldraw/editor 4.5.0-canary.034ea85352da → 4.5.0-canary.0d748e7df5db
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-cjs/index.d.ts +24 -1
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +13 -16
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +206 -254
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +15 -16
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +3 -3
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +1 -1
- package/dist-cjs/lib/hooks/useCanvasEvents.js +1 -1
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +10 -0
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +24 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +13 -16
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +207 -255
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +15 -16
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +3 -3
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +1 -1
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +1 -1
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +10 -0
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/lib/components/default-components/DefaultCanvas.tsx +19 -26
- package/src/lib/editor/Editor.ts +283 -393
- package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +6 -5
- package/src/lib/editor/shapes/ShapeUtil.ts +1 -1
- package/src/lib/hooks/useCanvasEvents.ts +1 -1
- package/src/lib/primitives/geometry/Geometry2d.ts +12 -0
- package/src/version.ts +3 -3
|
@@ -3990,6 +3990,9 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
3990
3990
|
if (geometry.isClosed) {
|
|
3991
3991
|
if (distance <= outerMargin || hitInside && distance <= 0 && distance > -innerMargin) {
|
|
3992
3992
|
if (geometry.isFilled || isGroup && geometry.children[0].isFilled) {
|
|
3993
|
+
if (geometry.ignoreHit(pointInShapeSpace)) {
|
|
3994
|
+
continue;
|
|
3995
|
+
}
|
|
3993
3996
|
return inMarginClosestToEdgeHit || shape;
|
|
3994
3997
|
} else {
|
|
3995
3998
|
if (this.getShapePageBounds(shape).contains(viewportPageBounds)) continue;
|
|
@@ -4985,6 +4988,53 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
4985
4988
|
if (changes) this.updateShapes(changes);
|
|
4986
4989
|
return this;
|
|
4987
4990
|
}
|
|
4991
|
+
/**
|
|
4992
|
+
* Shared clustering logic for layout methods. Resolves shapes, optionally filters to
|
|
4993
|
+
* axis-aligned shapes, checks canBeLaidOut, and groups shapes into clusters via arrow bindings.
|
|
4994
|
+
*
|
|
4995
|
+
* @internal
|
|
4996
|
+
*/
|
|
4997
|
+
getShapeClusters(shapes, type, opts) {
|
|
4998
|
+
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
|
|
4999
|
+
let freshShapes = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
|
|
5000
|
+
if (opts?.filterAxisAligned) {
|
|
5001
|
+
freshShapes = freshShapes.filter(
|
|
5002
|
+
(s) => this.getShapePageTransform(s)?.rotation() % (import_utils2.PI / 2) === 0
|
|
5003
|
+
);
|
|
5004
|
+
}
|
|
5005
|
+
const clusters = [];
|
|
5006
|
+
const allBounds = [];
|
|
5007
|
+
const visited = /* @__PURE__ */ new Set();
|
|
5008
|
+
for (const shape of freshShapes) {
|
|
5009
|
+
if (visited.has(shape.id)) continue;
|
|
5010
|
+
visited.add(shape.id);
|
|
5011
|
+
const shapePageBounds = this.getShapePageBounds(shape);
|
|
5012
|
+
if (!shapePageBounds) continue;
|
|
5013
|
+
if (!this.getShapeUtil(shape).canBeLaidOut?.(shape, {
|
|
5014
|
+
type,
|
|
5015
|
+
shapes: freshShapes
|
|
5016
|
+
})) {
|
|
5017
|
+
continue;
|
|
5018
|
+
}
|
|
5019
|
+
const shapesMovingTogether = [shape];
|
|
5020
|
+
const boundsOfShapesMovingTogether = [shapePageBounds];
|
|
5021
|
+
this.collectShapesViaArrowBindings({
|
|
5022
|
+
bindings: this.getBindingsToShape(shape.id, "arrow"),
|
|
5023
|
+
initialShapes: freshShapes,
|
|
5024
|
+
resultShapes: shapesMovingTogether,
|
|
5025
|
+
resultBounds: boundsOfShapesMovingTogether,
|
|
5026
|
+
visited
|
|
5027
|
+
});
|
|
5028
|
+
const commonPageBounds = import_Box.Box.Common(boundsOfShapesMovingTogether);
|
|
5029
|
+
if (!commonPageBounds) continue;
|
|
5030
|
+
clusters.push({
|
|
5031
|
+
shapes: shapesMovingTogether,
|
|
5032
|
+
pageBounds: commonPageBounds
|
|
5033
|
+
});
|
|
5034
|
+
allBounds.push(commonPageBounds);
|
|
5035
|
+
}
|
|
5036
|
+
return { clusters, allBounds };
|
|
5037
|
+
}
|
|
4988
5038
|
/**
|
|
4989
5039
|
* @internal
|
|
4990
5040
|
*/
|
|
@@ -5095,40 +5145,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
5095
5145
|
*/
|
|
5096
5146
|
stackShapes(shapes, operation, gap) {
|
|
5097
5147
|
const _gap = gap ?? this.options.adjacentShapeMargin;
|
|
5098
|
-
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
|
|
5099
5148
|
if (this.getIsReadonly()) return this;
|
|
5100
|
-
const
|
|
5101
|
-
const shapeClustersToStack = [];
|
|
5102
|
-
const allBounds = [];
|
|
5103
|
-
const visited = /* @__PURE__ */ new Set();
|
|
5104
|
-
for (const shape of shapesToStackFirstPass) {
|
|
5105
|
-
if (visited.has(shape.id)) continue;
|
|
5106
|
-
visited.add(shape.id);
|
|
5107
|
-
const shapePageBounds = this.getShapePageBounds(shape);
|
|
5108
|
-
if (!shapePageBounds) continue;
|
|
5109
|
-
if (!this.getShapeUtil(shape).canBeLaidOut?.(shape, {
|
|
5110
|
-
type: "stack",
|
|
5111
|
-
shapes: shapesToStackFirstPass
|
|
5112
|
-
})) {
|
|
5113
|
-
continue;
|
|
5114
|
-
}
|
|
5115
|
-
const shapesMovingTogether = [shape];
|
|
5116
|
-
const boundsOfShapesMovingTogether = [shapePageBounds];
|
|
5117
|
-
this.collectShapesViaArrowBindings({
|
|
5118
|
-
bindings: this.getBindingsToShape(shape.id, "arrow"),
|
|
5119
|
-
initialShapes: shapesToStackFirstPass,
|
|
5120
|
-
resultShapes: shapesMovingTogether,
|
|
5121
|
-
resultBounds: boundsOfShapesMovingTogether,
|
|
5122
|
-
visited
|
|
5123
|
-
});
|
|
5124
|
-
const commonPageBounds = import_Box.Box.Common(boundsOfShapesMovingTogether);
|
|
5125
|
-
if (!commonPageBounds) continue;
|
|
5126
|
-
shapeClustersToStack.push({
|
|
5127
|
-
shapes: shapesMovingTogether,
|
|
5128
|
-
pageBounds: commonPageBounds
|
|
5129
|
-
});
|
|
5130
|
-
allBounds.push(commonPageBounds);
|
|
5131
|
-
}
|
|
5149
|
+
const { clusters: shapeClustersToStack } = this.getShapeClusters(shapes, "stack");
|
|
5132
5150
|
const len = shapeClustersToStack.length;
|
|
5133
5151
|
if (_gap === 0 && len < 3 || len < 2) return this;
|
|
5134
5152
|
let val;
|
|
@@ -5214,40 +5232,11 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
5214
5232
|
packShapes(shapes, _gap) {
|
|
5215
5233
|
if (this.getIsReadonly()) return this;
|
|
5216
5234
|
const gap = _gap ?? this.options.adjacentShapeMargin;
|
|
5217
|
-
const
|
|
5218
|
-
const
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
for (const shape of shapesToPackFirstPass) {
|
|
5223
|
-
if (visited.has(shape.id)) continue;
|
|
5224
|
-
visited.add(shape.id);
|
|
5225
|
-
const shapePageBounds = this.getShapePageBounds(shape);
|
|
5226
|
-
if (!shapePageBounds) continue;
|
|
5227
|
-
if (!this.getShapeUtil(shape).canBeLaidOut?.(shape, {
|
|
5228
|
-
type: "pack",
|
|
5229
|
-
shapes: shapesToPackFirstPass
|
|
5230
|
-
})) {
|
|
5231
|
-
continue;
|
|
5232
|
-
}
|
|
5233
|
-
const shapesMovingTogether = [shape];
|
|
5234
|
-
const boundsOfShapesMovingTogether = [shapePageBounds];
|
|
5235
|
-
this.collectShapesViaArrowBindings({
|
|
5236
|
-
bindings: this.getBindingsToShape(shape.id, "arrow"),
|
|
5237
|
-
initialShapes: shapesToPackFirstPass,
|
|
5238
|
-
resultShapes: shapesMovingTogether,
|
|
5239
|
-
resultBounds: boundsOfShapesMovingTogether,
|
|
5240
|
-
visited
|
|
5241
|
-
});
|
|
5242
|
-
const commonPageBounds = import_Box.Box.Common(boundsOfShapesMovingTogether);
|
|
5243
|
-
if (!commonPageBounds) continue;
|
|
5244
|
-
shapeClustersToPack.push({
|
|
5245
|
-
shapes: shapesMovingTogether,
|
|
5246
|
-
pageBounds: commonPageBounds,
|
|
5247
|
-
nextPageBounds: commonPageBounds.clone()
|
|
5248
|
-
});
|
|
5249
|
-
allBounds.push(commonPageBounds);
|
|
5250
|
-
}
|
|
5235
|
+
const { clusters, allBounds } = this.getShapeClusters(shapes, "pack");
|
|
5236
|
+
const shapeClustersToPack = clusters.map((cluster) => ({
|
|
5237
|
+
...cluster,
|
|
5238
|
+
nextPageBounds: cluster.pageBounds.clone()
|
|
5239
|
+
}));
|
|
5251
5240
|
if (shapeClustersToPack.length < 2) return this;
|
|
5252
5241
|
let area = 0;
|
|
5253
5242
|
for (const { pageBounds } of shapeClustersToPack) {
|
|
@@ -5331,39 +5320,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
5331
5320
|
*/
|
|
5332
5321
|
alignShapes(shapes, operation) {
|
|
5333
5322
|
if (this.getIsReadonly()) return this;
|
|
5334
|
-
const
|
|
5335
|
-
const shapesToAlignFirstPass = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
|
|
5336
|
-
const shapeClustersToAlign = [];
|
|
5337
|
-
const allBounds = [];
|
|
5338
|
-
const visited = /* @__PURE__ */ new Set();
|
|
5339
|
-
for (const shape of shapesToAlignFirstPass) {
|
|
5340
|
-
if (visited.has(shape.id)) continue;
|
|
5341
|
-
visited.add(shape.id);
|
|
5342
|
-
const shapePageBounds = this.getShapePageBounds(shape);
|
|
5343
|
-
if (!shapePageBounds) continue;
|
|
5344
|
-
if (!this.getShapeUtil(shape).canBeLaidOut?.(shape, {
|
|
5345
|
-
type: "align",
|
|
5346
|
-
shapes: shapesToAlignFirstPass
|
|
5347
|
-
})) {
|
|
5348
|
-
continue;
|
|
5349
|
-
}
|
|
5350
|
-
const shapesMovingTogether = [shape];
|
|
5351
|
-
const boundsOfShapesMovingTogether = [shapePageBounds];
|
|
5352
|
-
this.collectShapesViaArrowBindings({
|
|
5353
|
-
bindings: this.getBindingsToShape(shape.id, "arrow"),
|
|
5354
|
-
initialShapes: shapesToAlignFirstPass,
|
|
5355
|
-
resultShapes: shapesMovingTogether,
|
|
5356
|
-
resultBounds: boundsOfShapesMovingTogether,
|
|
5357
|
-
visited
|
|
5358
|
-
});
|
|
5359
|
-
const commonPageBounds = import_Box.Box.Common(boundsOfShapesMovingTogether);
|
|
5360
|
-
if (!commonPageBounds) continue;
|
|
5361
|
-
shapeClustersToAlign.push({
|
|
5362
|
-
shapes: shapesMovingTogether,
|
|
5363
|
-
pageBounds: commonPageBounds
|
|
5364
|
-
});
|
|
5365
|
-
allBounds.push(commonPageBounds);
|
|
5366
|
-
}
|
|
5323
|
+
const { clusters: shapeClustersToAlign, allBounds } = this.getShapeClusters(shapes, "align");
|
|
5367
5324
|
if (shapeClustersToAlign.length < 2) return this;
|
|
5368
5325
|
const commonBounds = import_Box.Box.Common(allBounds);
|
|
5369
5326
|
const changes = [];
|
|
@@ -5425,39 +5382,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
5425
5382
|
*/
|
|
5426
5383
|
distributeShapes(shapes, operation) {
|
|
5427
5384
|
if (this.getIsReadonly()) return this;
|
|
5428
|
-
const
|
|
5429
|
-
const shapesToDistributeFirstPass = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
|
|
5430
|
-
const shapeClustersToDistribute = [];
|
|
5431
|
-
const allBounds = [];
|
|
5432
|
-
const visited = /* @__PURE__ */ new Set();
|
|
5433
|
-
for (const shape of shapesToDistributeFirstPass) {
|
|
5434
|
-
if (visited.has(shape.id)) continue;
|
|
5435
|
-
visited.add(shape.id);
|
|
5436
|
-
const shapePageBounds = this.getShapePageBounds(shape);
|
|
5437
|
-
if (!shapePageBounds) continue;
|
|
5438
|
-
if (!this.getShapeUtil(shape).canBeLaidOut?.(shape, {
|
|
5439
|
-
type: "distribute",
|
|
5440
|
-
shapes: shapesToDistributeFirstPass
|
|
5441
|
-
})) {
|
|
5442
|
-
continue;
|
|
5443
|
-
}
|
|
5444
|
-
const shapesMovingTogether = [shape];
|
|
5445
|
-
const boundsOfShapesMovingTogether = [shapePageBounds];
|
|
5446
|
-
this.collectShapesViaArrowBindings({
|
|
5447
|
-
bindings: this.getBindingsToShape(shape.id, "arrow"),
|
|
5448
|
-
initialShapes: shapesToDistributeFirstPass,
|
|
5449
|
-
resultShapes: shapesMovingTogether,
|
|
5450
|
-
resultBounds: boundsOfShapesMovingTogether,
|
|
5451
|
-
visited
|
|
5452
|
-
});
|
|
5453
|
-
const commonPageBounds = import_Box.Box.Common(boundsOfShapesMovingTogether);
|
|
5454
|
-
if (!commonPageBounds) continue;
|
|
5455
|
-
shapeClustersToDistribute.push({
|
|
5456
|
-
shapes: shapesMovingTogether,
|
|
5457
|
-
pageBounds: commonPageBounds
|
|
5458
|
-
});
|
|
5459
|
-
allBounds.push(commonPageBounds);
|
|
5460
|
-
}
|
|
5385
|
+
const { clusters: shapeClustersToDistribute } = this.getShapeClusters(shapes, "distribute");
|
|
5461
5386
|
if (shapeClustersToDistribute.length < 3) return this;
|
|
5462
5387
|
let val;
|
|
5463
5388
|
let min;
|
|
@@ -5479,6 +5404,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
5479
5404
|
const last2 = shapeClustersToDistribute.sort((a, b) => b.pageBounds[max] - a.pageBounds[max])[0];
|
|
5480
5405
|
if (first === last2) {
|
|
5481
5406
|
const excludedShapeIds = new Set(first.shapes.map((s) => s.id));
|
|
5407
|
+
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
|
|
5482
5408
|
return this.distributeShapes(
|
|
5483
5409
|
ids.filter((id) => !excludedShapeIds.has(id)),
|
|
5484
5410
|
operation
|
|
@@ -5531,41 +5457,12 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
5531
5457
|
* @public
|
|
5532
5458
|
*/
|
|
5533
5459
|
stretchShapes(shapes, operation) {
|
|
5534
|
-
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
|
|
5535
5460
|
if (this.getIsReadonly()) return this;
|
|
5536
|
-
const
|
|
5537
|
-
|
|
5461
|
+
const { clusters: shapeClustersToStretch, allBounds } = this.getShapeClusters(
|
|
5462
|
+
shapes,
|
|
5463
|
+
"stretch",
|
|
5464
|
+
{ filterAxisAligned: true }
|
|
5538
5465
|
);
|
|
5539
|
-
const shapeClustersToStretch = [];
|
|
5540
|
-
const allBounds = [];
|
|
5541
|
-
const visited = /* @__PURE__ */ new Set();
|
|
5542
|
-
for (const shape of shapesToStretchFirstPass) {
|
|
5543
|
-
if (visited.has(shape.id)) continue;
|
|
5544
|
-
visited.add(shape.id);
|
|
5545
|
-
const shapePageBounds = this.getShapePageBounds(shape);
|
|
5546
|
-
if (!shapePageBounds) continue;
|
|
5547
|
-
const shapesMovingTogether = [shape];
|
|
5548
|
-
const boundsOfShapesMovingTogether = [shapePageBounds];
|
|
5549
|
-
if (!this.getShapeUtil(shape).canBeLaidOut?.(shape, {
|
|
5550
|
-
type: "stretch"
|
|
5551
|
-
})) {
|
|
5552
|
-
continue;
|
|
5553
|
-
}
|
|
5554
|
-
this.collectShapesViaArrowBindings({
|
|
5555
|
-
bindings: this.getBindingsToShape(shape.id, "arrow"),
|
|
5556
|
-
initialShapes: shapesToStretchFirstPass,
|
|
5557
|
-
resultShapes: shapesMovingTogether,
|
|
5558
|
-
resultBounds: boundsOfShapesMovingTogether,
|
|
5559
|
-
visited
|
|
5560
|
-
});
|
|
5561
|
-
const commonPageBounds = import_Box.Box.Common(boundsOfShapesMovingTogether);
|
|
5562
|
-
if (!commonPageBounds) continue;
|
|
5563
|
-
shapeClustersToStretch.push({
|
|
5564
|
-
shapes: shapesMovingTogether,
|
|
5565
|
-
pageBounds: commonPageBounds
|
|
5566
|
-
});
|
|
5567
|
-
allBounds.push(commonPageBounds);
|
|
5568
|
-
}
|
|
5569
5466
|
if (shapeClustersToStretch.length < 2) return this;
|
|
5570
5467
|
const commonBounds = import_Box.Box.Common(allBounds);
|
|
5571
5468
|
let val;
|
|
@@ -5591,7 +5488,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
5591
5488
|
for (const shape of shapes2) {
|
|
5592
5489
|
const shapeLocalOffset = localOffset.clone();
|
|
5593
5490
|
const parentTransform = this.getShapeParentTransform(shape);
|
|
5594
|
-
if (parentTransform)
|
|
5491
|
+
if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
|
|
5595
5492
|
shapeLocalOffset.add(shape);
|
|
5596
5493
|
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5597
5494
|
this.updateShape(changes);
|
|
@@ -5606,6 +5503,62 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
5606
5503
|
});
|
|
5607
5504
|
return this;
|
|
5608
5505
|
}
|
|
5506
|
+
/**
|
|
5507
|
+
* Resize and reposition a set of shapes so that their combined page bounds matches the given
|
|
5508
|
+
* target bounds.
|
|
5509
|
+
*
|
|
5510
|
+
* @example
|
|
5511
|
+
* ```ts
|
|
5512
|
+
* editor.resizeToBounds([box1, box2], { x: 0, y: 0, w: 500, h: 500 })
|
|
5513
|
+
* editor.resizeToBounds(editor.getSelectedShapeIds(), new Box(0, 0, 500, 500))
|
|
5514
|
+
* ```
|
|
5515
|
+
*
|
|
5516
|
+
* @param shapes - The shapes (or shape ids) to resize.
|
|
5517
|
+
* @param bounds - The target bounding box.
|
|
5518
|
+
*
|
|
5519
|
+
* @public
|
|
5520
|
+
*/
|
|
5521
|
+
resizeToBounds(shapes, bounds) {
|
|
5522
|
+
if (this.getIsReadonly()) return this;
|
|
5523
|
+
const targetBounds = import_Box.Box.From(bounds);
|
|
5524
|
+
const { clusters: shapeClusters, allBounds } = this.getShapeClusters(
|
|
5525
|
+
shapes,
|
|
5526
|
+
"resize_to_bounds",
|
|
5527
|
+
{ filterAxisAligned: true }
|
|
5528
|
+
);
|
|
5529
|
+
if (shapeClusters.length === 0) return this;
|
|
5530
|
+
const commonBounds = import_Box.Box.Common(allBounds);
|
|
5531
|
+
if (!commonBounds) return this;
|
|
5532
|
+
if (commonBounds.width === 0 || commonBounds.height === 0) return this;
|
|
5533
|
+
const scaleX = targetBounds.width / commonBounds.width;
|
|
5534
|
+
const scaleY = targetBounds.height / commonBounds.height;
|
|
5535
|
+
const scale = new import_Vec.Vec(scaleX, scaleY);
|
|
5536
|
+
shapeClusters.forEach(({ shapes: shapes2, pageBounds }) => {
|
|
5537
|
+
const localOffset = new import_Vec.Vec(
|
|
5538
|
+
targetBounds.minX - commonBounds.minX + (pageBounds.minX - commonBounds.minX) * (scaleX - 1),
|
|
5539
|
+
targetBounds.minY - commonBounds.minY + (pageBounds.minY - commonBounds.minY) * (scaleY - 1)
|
|
5540
|
+
);
|
|
5541
|
+
const scaleOrigin = new import_Vec.Vec(
|
|
5542
|
+
targetBounds.minX + (pageBounds.minX - commonBounds.minX) * scaleX,
|
|
5543
|
+
targetBounds.minY + (pageBounds.minY - commonBounds.minY) * scaleY
|
|
5544
|
+
);
|
|
5545
|
+
for (const shape of shapes2) {
|
|
5546
|
+
const shapeLocalOffset = localOffset.clone();
|
|
5547
|
+
const parentTransform = this.getShapeParentTransform(shape);
|
|
5548
|
+
if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
|
|
5549
|
+
shapeLocalOffset.add(shape);
|
|
5550
|
+
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5551
|
+
this.updateShape(changes);
|
|
5552
|
+
this.resizeShape(shape.id, scale, {
|
|
5553
|
+
initialBounds: this.getShapeGeometry(shape).bounds,
|
|
5554
|
+
scaleOrigin,
|
|
5555
|
+
isAspectRatioLocked: this.getShapeUtil(shape).isAspectRatioLocked(shape),
|
|
5556
|
+
scaleAxisRotation: 0
|
|
5557
|
+
});
|
|
5558
|
+
}
|
|
5559
|
+
});
|
|
5560
|
+
return this;
|
|
5561
|
+
}
|
|
5609
5562
|
/**
|
|
5610
5563
|
* Resize a shape.
|
|
5611
5564
|
*
|
|
@@ -6725,38 +6678,10 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
6725
6678
|
const bindingIdMap = new Map(
|
|
6726
6679
|
preserveIds ? bindings.map((binding) => [binding.id, binding.id]) : bindings.map((binding) => [binding.id, (0, import_tlschema.createBindingId)()])
|
|
6727
6680
|
);
|
|
6728
|
-
let pasteParentId =
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
for (const shape of this.getSelectedShapes()) {
|
|
6732
|
-
if (lowestDepth === 0) break;
|
|
6733
|
-
const isFrame = this.isShapeOfType(shape, "frame");
|
|
6734
|
-
const ancestors = this.getShapeAncestors(shape);
|
|
6735
|
-
if (isFrame) ancestors.push(shape);
|
|
6736
|
-
const depth = isFrame ? ancestors.length + 1 : ancestors.length;
|
|
6737
|
-
if (depth < lowestDepth) {
|
|
6738
|
-
lowestDepth = depth;
|
|
6739
|
-
lowestAncestors = ancestors;
|
|
6740
|
-
pasteParentId = isFrame ? shape.id : shape.parentId;
|
|
6741
|
-
} else if (depth === lowestDepth) {
|
|
6742
|
-
if (lowestAncestors.length !== ancestors.length) {
|
|
6743
|
-
throw Error(`Ancestors: ${lowestAncestors.length} !== ${ancestors.length}`);
|
|
6744
|
-
}
|
|
6745
|
-
if (lowestAncestors.length === 0) {
|
|
6746
|
-
pasteParentId = currentPageId;
|
|
6747
|
-
break;
|
|
6748
|
-
} else {
|
|
6749
|
-
pasteParentId = currentPageId;
|
|
6750
|
-
for (let i = 0; i < lowestAncestors.length; i++) {
|
|
6751
|
-
if (ancestors[i] !== lowestAncestors[i]) break;
|
|
6752
|
-
pasteParentId = ancestors[i].id;
|
|
6753
|
-
}
|
|
6754
|
-
}
|
|
6755
|
-
}
|
|
6756
|
-
}
|
|
6681
|
+
let pasteParentId = currentPageId;
|
|
6682
|
+
const shapesById = new Map(shapes.map((s) => [s.id, s]));
|
|
6683
|
+
const rootShapesFromContent = (0, import_utils.compact)(rootShapeIds.map((id) => shapesById.get(id)));
|
|
6757
6684
|
if (point) {
|
|
6758
|
-
const shapesById = new Map(shapes.map((shape) => [shape.id, shape]));
|
|
6759
|
-
const rootShapesFromContent = (0, import_utils.compact)(rootShapeIds.map((id) => shapesById.get(id)));
|
|
6760
6685
|
if (rootShapesFromContent.length > 0) {
|
|
6761
6686
|
const targetParent = this.getShapeAtPoint(point, {
|
|
6762
6687
|
hitInside: true,
|
|
@@ -6764,38 +6689,55 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
6764
6689
|
hitLocked: true,
|
|
6765
6690
|
filter: (shape) => {
|
|
6766
6691
|
const util = this.getShapeUtil(shape);
|
|
6767
|
-
if (!util.canReceiveNewChildrenOfType) return false;
|
|
6768
6692
|
return rootShapesFromContent.every(
|
|
6769
|
-
(rootShape) => util.canReceiveNewChildrenOfType(shape, rootShape.type)
|
|
6693
|
+
(rootShape) => util.canReceiveNewChildrenOfType?.(shape, rootShape.type)
|
|
6770
6694
|
);
|
|
6771
6695
|
}
|
|
6772
6696
|
});
|
|
6773
|
-
pasteParentId = targetParent
|
|
6774
|
-
}
|
|
6775
|
-
}
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
const
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6697
|
+
pasteParentId = targetParent?.id ?? currentPageId;
|
|
6698
|
+
}
|
|
6699
|
+
} else if (!preservePosition) {
|
|
6700
|
+
const selectedShapes = this.getSelectedShapes();
|
|
6701
|
+
let selectedParent = null;
|
|
6702
|
+
const canAcceptAll = (candidate) => {
|
|
6703
|
+
const util = this.getShapeUtil(candidate);
|
|
6704
|
+
return rootShapesFromContent.every(
|
|
6705
|
+
(rs) => util.canReceiveNewChildrenOfType?.(candidate, rs.type)
|
|
6706
|
+
);
|
|
6707
|
+
};
|
|
6708
|
+
for (const shape of selectedShapes) {
|
|
6709
|
+
const candidate = canAcceptAll(shape) ? shape : this.findShapeAncestor(shape, canAcceptAll) ?? ((0, import_tlschema.isShapeId)(shape.parentId) ? this.getShape(shape.parentId) : null);
|
|
6710
|
+
if (!candidate) {
|
|
6711
|
+
selectedParent = null;
|
|
6712
|
+
break;
|
|
6713
|
+
}
|
|
6714
|
+
if (!selectedParent) {
|
|
6715
|
+
selectedParent = candidate;
|
|
6716
|
+
} else if (selectedParent.id !== candidate.id) {
|
|
6717
|
+
const spAncestors = this.getShapeAncestors(selectedParent);
|
|
6718
|
+
if (canAcceptAll(selectedParent)) spAncestors.push(selectedParent);
|
|
6719
|
+
const acceptingAncestors = spAncestors.filter(canAcceptAll);
|
|
6720
|
+
const candidateAncestorIds = /* @__PURE__ */ new Set([
|
|
6721
|
+
candidate.id,
|
|
6722
|
+
...this.getShapeAncestors(candidate).map((a) => a.id)
|
|
6723
|
+
]);
|
|
6724
|
+
let common = null;
|
|
6725
|
+
for (let i = acceptingAncestors.length - 1; i >= 0; i--) {
|
|
6726
|
+
if (candidateAncestorIds.has(acceptingAncestors[i].id)) {
|
|
6727
|
+
common = acceptingAncestors[i];
|
|
6728
|
+
break;
|
|
6787
6729
|
}
|
|
6788
6730
|
}
|
|
6731
|
+
selectedParent = common;
|
|
6732
|
+
if (!selectedParent) break;
|
|
6789
6733
|
}
|
|
6790
|
-
} else {
|
|
6791
|
-
pasteParentId = currentPageId;
|
|
6792
6734
|
}
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6735
|
+
if (selectedParent && shapeIdMap.has(selectedParent.id)) {
|
|
6736
|
+
selectedParent = null;
|
|
6737
|
+
}
|
|
6738
|
+
if (selectedParent) {
|
|
6739
|
+
pasteParentId = selectedParent.id;
|
|
6740
|
+
}
|
|
6799
6741
|
}
|
|
6800
6742
|
let index = this.getHighestIndexForParent(pasteParentId);
|
|
6801
6743
|
const rootShapes = [];
|
|
@@ -6859,22 +6801,17 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
6859
6801
|
})
|
|
6860
6802
|
);
|
|
6861
6803
|
this.run(() => {
|
|
6862
|
-
if (assetsToCreate.length > 0)
|
|
6863
|
-
this.createAssets(assetsToCreate);
|
|
6864
|
-
}
|
|
6804
|
+
if (assetsToCreate.length > 0) this.createAssets(assetsToCreate);
|
|
6865
6805
|
this.createShapes(newShapes);
|
|
6866
6806
|
this.createBindings(newBindings);
|
|
6867
|
-
if (select)
|
|
6868
|
-
this.select(...rootShapes.map((s) => s.id));
|
|
6869
|
-
}
|
|
6807
|
+
if (select) this.select(...rootShapes.map((s) => s.id));
|
|
6870
6808
|
if (pasteParentId !== currentPageId) {
|
|
6871
6809
|
this.reparentShapes(
|
|
6872
6810
|
rootShapes.map((s) => s.id),
|
|
6873
6811
|
pasteParentId
|
|
6874
6812
|
);
|
|
6875
6813
|
}
|
|
6876
|
-
const
|
|
6877
|
-
const bounds = import_Box.Box.Common(newCreatedShapes.map((s) => this.getShapePageBounds(s)));
|
|
6814
|
+
const rootBounds = import_Box.Box.Common((0, import_utils.compact)(rootShapes.map((s) => this.getShapePageBounds(s.id))));
|
|
6878
6815
|
if (point === void 0) {
|
|
6879
6816
|
if (!(0, import_tlschema.isPageId)(pasteParentId)) {
|
|
6880
6817
|
const shape = this.getShape(pasteParentId);
|
|
@@ -6882,40 +6819,44 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
6882
6819
|
this.getShapePageTransform(shape),
|
|
6883
6820
|
this.getShapeGeometry(shape).bounds.center
|
|
6884
6821
|
);
|
|
6822
|
+
} else if (preservePosition) {
|
|
6823
|
+
point = rootBounds.center;
|
|
6885
6824
|
} else {
|
|
6886
6825
|
const viewportPageBounds = this.getViewportPageBounds();
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
}
|
|
6893
|
-
}
|
|
6894
|
-
if (rootShapes.length === 1) {
|
|
6895
|
-
const onlyRoot = rootShapes[0];
|
|
6896
|
-
if (this.isShapeOfType(onlyRoot, "frame")) {
|
|
6897
|
-
while (this.getShapesAtPoint(point).some(
|
|
6898
|
-
(shape) => this.isShapeOfType(shape, "frame") && shape.props.w === onlyRoot.props.w && shape.props.h === onlyRoot.props.h
|
|
6899
|
-
)) {
|
|
6900
|
-
point.x += bounds.w + 16;
|
|
6901
|
-
}
|
|
6826
|
+
const anyOverlap = rootShapes.some((s) => {
|
|
6827
|
+
const b = this.getShapePageBounds(s.id);
|
|
6828
|
+
return b && viewportPageBounds.collides(b);
|
|
6829
|
+
});
|
|
6830
|
+
point = anyOverlap ? rootBounds.center : viewportPageBounds.center;
|
|
6902
6831
|
}
|
|
6903
6832
|
}
|
|
6904
6833
|
const pageCenter = import_Box.Box.Common(
|
|
6905
6834
|
(0, import_utils.compact)(rootShapes.map(({ id }) => this.getShapePageBounds(id)))
|
|
6906
6835
|
).center;
|
|
6907
6836
|
const offset = import_Vec.Vec.Sub(point, pageCenter);
|
|
6908
|
-
|
|
6909
|
-
|
|
6910
|
-
|
|
6911
|
-
|
|
6912
|
-
|
|
6913
|
-
|
|
6914
|
-
|
|
6915
|
-
|
|
6837
|
+
if (offset.x !== 0 || offset.y !== 0) {
|
|
6838
|
+
this.updateShapes(
|
|
6839
|
+
rootShapes.map(({ id }) => {
|
|
6840
|
+
const s = this.getShape(id);
|
|
6841
|
+
const localRotation = this.getShapeParentTransform(id).decompose().rotation;
|
|
6842
|
+
const localDelta = import_Vec.Vec.Rot(offset, -localRotation);
|
|
6843
|
+
return { id: s.id, type: s.type, x: s.x + localDelta.x, y: s.y + localDelta.y };
|
|
6844
|
+
})
|
|
6845
|
+
);
|
|
6846
|
+
}
|
|
6916
6847
|
if ((0, import_tlschema.isPageId)(pasteParentId)) {
|
|
6917
6848
|
const currentRootShapes = (0, import_utils.compact)(rootShapes.map((s) => this.getShape(s.id)));
|
|
6918
|
-
const { reparenting } = (0, import_reparenting.getDroppedShapesToNewParents)(
|
|
6849
|
+
const { reparenting } = (0, import_reparenting.getDroppedShapesToNewParents)(
|
|
6850
|
+
this,
|
|
6851
|
+
currentRootShapes,
|
|
6852
|
+
(shape, parent) => {
|
|
6853
|
+
if (shapeIdMap.has(parent.id)) return false;
|
|
6854
|
+
const shapeBounds = this.getShapePageBounds(shape);
|
|
6855
|
+
const parentBounds = this.getShapePageBounds(parent);
|
|
6856
|
+
if (!shapeBounds || !parentBounds) return false;
|
|
6857
|
+
return parentBounds.containsPoint(shapeBounds.center);
|
|
6858
|
+
}
|
|
6859
|
+
);
|
|
6919
6860
|
reparenting.forEach((childrenToReparent, newParentId) => {
|
|
6920
6861
|
if (childrenToReparent.length === 0) return;
|
|
6921
6862
|
this.reparentShapes(
|
|
@@ -6924,6 +6865,17 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
|
|
|
6924
6865
|
);
|
|
6925
6866
|
});
|
|
6926
6867
|
}
|
|
6868
|
+
const newShapeIdSet = new Set(newShapes.map((s) => s.id));
|
|
6869
|
+
const shapesToKickout = rootShapes.map((s) => s.id).filter((id) => {
|
|
6870
|
+
const shape = this.getShape(id);
|
|
6871
|
+
if (!shape) return false;
|
|
6872
|
+
if ((0, import_tlschema.isPageId)(shape.parentId)) return false;
|
|
6873
|
+
const children = this.getSortedChildIdsForParent(id);
|
|
6874
|
+
return !children.some((childId) => newShapeIdSet.has(childId));
|
|
6875
|
+
});
|
|
6876
|
+
if (shapesToKickout.length > 0) {
|
|
6877
|
+
(0, import_reparenting.kickoutOccludedShapes)(this, shapesToKickout);
|
|
6878
|
+
}
|
|
6927
6879
|
});
|
|
6928
6880
|
return this;
|
|
6929
6881
|
}
|