@tldraw/editor 5.4.2 → 5.5.0-canary.0241f11f2e99
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 +7 -2
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/constants.js +2 -0
- package/dist-cjs/lib/constants.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +131 -151
- package/dist-cjs/lib/editor/Editor.js.map +3 -3
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js +2 -0
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +10 -6
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js +7 -3
- package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +14 -6
- package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +3 -3
- package/dist-cjs/lib/exports/ExportDelay.js +10 -2
- package/dist-cjs/lib/exports/ExportDelay.js.map +2 -2
- package/dist-cjs/lib/exports/FontEmbedder.js +25 -11
- package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/StyleEmbedder.js +9 -4
- package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
- package/dist-cjs/lib/exports/fetchCache.js +3 -0
- package/dist-cjs/lib/exports/fetchCache.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgAsImage.js +10 -4
- package/dist-cjs/lib/exports/getSvgAsImage.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgJsx.js +18 -9
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/exports/parseCss.js +1 -1
- package/dist-cjs/lib/exports/parseCss.js.map +1 -1
- package/dist-cjs/lib/license/LicenseManager.js +9 -1
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +12 -4
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Arc2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Edge2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +8 -5
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Point2d.js +1 -1
- package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
- package/dist-cjs/lib/utils/sync/LocalIndexedDb.js +13 -17
- package/dist-cjs/lib/utils/sync/LocalIndexedDb.js.map +2 -2
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +78 -40
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.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 +7 -2
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/constants.mjs +2 -0
- package/dist-esm/lib/constants.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +132 -151
- package/dist-esm/lib/editor/Editor.mjs.map +3 -3
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +2 -0
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +10 -6
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs +7 -3
- package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +14 -6
- package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +3 -3
- package/dist-esm/lib/exports/ExportDelay.mjs +11 -3
- package/dist-esm/lib/exports/ExportDelay.mjs.map +2 -2
- package/dist-esm/lib/exports/FontEmbedder.mjs +25 -11
- package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/StyleEmbedder.mjs +9 -4
- package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
- package/dist-esm/lib/exports/fetchCache.mjs +3 -0
- package/dist-esm/lib/exports/fetchCache.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgAsImage.mjs +10 -4
- package/dist-esm/lib/exports/getSvgAsImage.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs +18 -9
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/exports/parseCss.mjs +1 -1
- package/dist-esm/lib/exports/parseCss.mjs.map +1 -1
- package/dist-esm/lib/license/LicenseManager.mjs +9 -1
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +13 -5
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +12 -6
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Point2d.mjs +1 -1
- package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs +13 -17
- package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +78 -40
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.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/constants.ts +8 -0
- package/src/lib/editor/Editor.test.ts +20 -0
- package/src/lib/editor/Editor.ts +202 -255
- package/src/lib/editor/derivations/bindingsIndex.ts +3 -0
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +35 -4
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +13 -7
- package/src/lib/editor/managers/ThemeManager/ThemeManager.test.ts +53 -0
- package/src/lib/editor/managers/ThemeManager/ThemeManager.ts +9 -3
- package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +23 -8
- package/src/lib/exports/ExportDelay.tsx +16 -4
- package/src/lib/exports/FontEmbedder.test.ts +99 -0
- package/src/lib/exports/FontEmbedder.ts +32 -11
- package/src/lib/exports/StyleEmbedder.ts +13 -4
- package/src/lib/exports/fetchCache.test.ts +22 -0
- package/src/lib/exports/fetchCache.ts +4 -0
- package/src/lib/exports/getSvgAsImage.ts +13 -5
- package/src/lib/exports/getSvgJsx.test.ts +43 -1
- package/src/lib/exports/getSvgJsx.tsx +28 -16
- package/src/lib/exports/parseCss.test.ts +4 -0
- package/src/lib/exports/parseCss.ts +2 -2
- package/src/lib/license/LicenseManager.ts +13 -1
- package/src/lib/license/LicenseProvider.test.tsx +76 -0
- package/src/lib/license/LicenseProvider.tsx +19 -5
- package/src/lib/primitives/geometry/Arc2d.test.ts +9 -0
- package/src/lib/primitives/geometry/Arc2d.ts +1 -1
- package/src/lib/primitives/geometry/CubicBezier2d.test.ts +13 -0
- package/src/lib/primitives/geometry/CubicBezier2d.ts +1 -1
- package/src/lib/primitives/geometry/Edge2d.test.ts +21 -3
- package/src/lib/primitives/geometry/Edge2d.ts +1 -1
- package/src/lib/primitives/geometry/Group2d.test.ts +26 -5
- package/src/lib/primitives/geometry/Group2d.ts +18 -7
- package/src/lib/primitives/geometry/Point2d.test.ts +14 -3
- package/src/lib/primitives/geometry/Point2d.ts +1 -1
- package/src/lib/utils/sync/LocalIndexedDb.test.ts +28 -0
- package/src/lib/utils/sync/LocalIndexedDb.ts +18 -20
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +236 -0
- package/src/lib/utils/sync/TLLocalSyncClient.ts +106 -54
- package/src/version.ts +3 -3
|
@@ -75,6 +75,7 @@ import {
|
|
|
75
75
|
import {
|
|
76
76
|
DEFAULT_ANIMATION_OPTIONS,
|
|
77
77
|
DEFAULT_CAMERA_OPTIONS,
|
|
78
|
+
FRAME_MS_60HZ,
|
|
78
79
|
INTERNAL_POINTER_IDS,
|
|
79
80
|
LEFT_MOUSE_BUTTON,
|
|
80
81
|
MIDDLE_MOUSE_BUTTON,
|
|
@@ -135,6 +136,10 @@ import { UserPreferencesManager } from "./managers/UserPreferencesManager/UserPr
|
|
|
135
136
|
import { OverlayManager } from "./overlays/OverlayManager.mjs";
|
|
136
137
|
import { RootState } from "./tools/RootState.mjs";
|
|
137
138
|
const RENDERING_SHAPES_SORT_CACHE_THRESHOLD = 100;
|
|
139
|
+
const AXIS = {
|
|
140
|
+
horizontal: { val: "x", min: "minX", max: "maxX", dim: "width" },
|
|
141
|
+
vertical: { val: "y", min: "minY", max: "maxY", dim: "height" }
|
|
142
|
+
};
|
|
138
143
|
class Editor extends EventEmitter {
|
|
139
144
|
id = uniqueId();
|
|
140
145
|
constructor({
|
|
@@ -461,7 +466,7 @@ class Editor extends EventEmitter {
|
|
|
461
466
|
}
|
|
462
467
|
}
|
|
463
468
|
if (deleteBindingIds.length) {
|
|
464
|
-
this.
|
|
469
|
+
this.store.remove(deleteBindingIds);
|
|
465
470
|
}
|
|
466
471
|
}
|
|
467
472
|
},
|
|
@@ -1421,6 +1426,7 @@ class Editor extends EventEmitter {
|
|
|
1421
1426
|
* @public
|
|
1422
1427
|
**/
|
|
1423
1428
|
updateDocumentSettings(settings) {
|
|
1429
|
+
if (this.getIsReadonly()) return this;
|
|
1424
1430
|
this.run(
|
|
1425
1431
|
() => {
|
|
1426
1432
|
this.store.put([{ ...this.getDocumentSettings(), ...settings }]);
|
|
@@ -1580,7 +1586,7 @@ class Editor extends EventEmitter {
|
|
|
1580
1586
|
* @public
|
|
1581
1587
|
*/
|
|
1582
1588
|
select(...shapes) {
|
|
1583
|
-
const ids =
|
|
1589
|
+
const ids = toShapeIds(shapes);
|
|
1584
1590
|
this.setSelectedShapes(ids);
|
|
1585
1591
|
return this;
|
|
1586
1592
|
}
|
|
@@ -1595,7 +1601,7 @@ class Editor extends EventEmitter {
|
|
|
1595
1601
|
* @public
|
|
1596
1602
|
*/
|
|
1597
1603
|
deselect(...shapes) {
|
|
1598
|
-
const ids =
|
|
1604
|
+
const ids = toShapeIds(shapes);
|
|
1599
1605
|
const selectedShapeIds = this.getSelectedShapeIds();
|
|
1600
1606
|
if (selectedShapeIds.length > 0 && ids.length > 0) {
|
|
1601
1607
|
this.setSelectedShapes(selectedShapeIds.filter((id) => !ids.includes(id)));
|
|
@@ -1633,7 +1639,7 @@ class Editor extends EventEmitter {
|
|
|
1633
1639
|
}
|
|
1634
1640
|
const ids = this.getSortedChildIdsForParent(parentToSelectWithinId);
|
|
1635
1641
|
if (ids.length <= 0) return this;
|
|
1636
|
-
this.setSelectedShapes(this.
|
|
1642
|
+
this.setSelectedShapes(ids.filter((id) => !this.getShape(id)?.isLocked));
|
|
1637
1643
|
return this;
|
|
1638
1644
|
}
|
|
1639
1645
|
/**
|
|
@@ -1650,14 +1656,18 @@ class Editor extends EventEmitter {
|
|
|
1650
1656
|
const selectedShapeIds = this.getSelectedShapeIds();
|
|
1651
1657
|
const firstParentId = selectedShapeIds[0] ? this.getShape(selectedShapeIds[0])?.parentId : null;
|
|
1652
1658
|
const isSelectedWithinContainer = firstParentId && selectedShapeIds.every((shapeId) => this.getShape(shapeId)?.parentId === firstParentId) && !isPageId(firstParentId);
|
|
1653
|
-
const filteredShapes =
|
|
1654
|
-
|
|
1659
|
+
const filteredShapes = this.getCurrentPageShapes().filter(
|
|
1660
|
+
(shape2) => !this.isShapeOrAncestorLocked(shape2) && (isSelectedWithinContainer ? shape2.parentId === firstParentId : isPageId(shape2.parentId))
|
|
1661
|
+
);
|
|
1662
|
+
const readingOrderShapes = this._getShapesInReadingOrder(filteredShapes);
|
|
1655
1663
|
const currentShapeId = selectedShapeIds.length === 1 ? selectedShapeIds[0] : readingOrderShapes.find((shape2) => selectedShapeIds.includes(shape2.id))?.id;
|
|
1656
1664
|
let adjacentShapeId;
|
|
1657
1665
|
if (direction === "next" || direction === "prev") {
|
|
1658
1666
|
const shapeIds = readingOrderShapes.map((shape2) => shape2.id);
|
|
1667
|
+
if (shapeIds.length === 0) return;
|
|
1659
1668
|
const currentIndex = currentShapeId ? shapeIds.indexOf(currentShapeId) : -1;
|
|
1660
|
-
const
|
|
1669
|
+
const startIndex = currentIndex === -1 && direction === "prev" ? 0 : currentIndex;
|
|
1670
|
+
const adjacentIndex = (startIndex + (direction === "next" ? 1 : -1) + shapeIds.length) % shapeIds.length;
|
|
1661
1671
|
adjacentShapeId = shapeIds[adjacentIndex];
|
|
1662
1672
|
} else {
|
|
1663
1673
|
if (!currentShapeId) return;
|
|
@@ -1756,13 +1766,14 @@ class Editor extends EventEmitter {
|
|
|
1756
1766
|
});
|
|
1757
1767
|
if (shapesInDirection.length === 0) return currentShapeId;
|
|
1758
1768
|
const lowestScoringShape = minBy(shapesInDirection, ({ center }) => {
|
|
1759
|
-
const distance = Vec.
|
|
1769
|
+
const distance = Vec.Dist(currentCenter, center);
|
|
1760
1770
|
const dirProp = ["left", "right"].includes(direction) ? "x" : "y";
|
|
1761
1771
|
const directionalDistance = Math.abs(center[dirProp] - currentCenter[dirProp]);
|
|
1762
1772
|
const offProp = ["left", "right"].includes(direction) ? "y" : "x";
|
|
1763
1773
|
const offAxisDeviation = Math.abs(center[offProp] - currentCenter[offProp]);
|
|
1764
|
-
const angle =
|
|
1765
|
-
const
|
|
1774
|
+
const angle = (Vec.Angle(currentCenter, center) * (180 / Math.PI) + 360) % 360;
|
|
1775
|
+
const rawAngleDeviation = Math.abs(angle - directionToAngle[direction]);
|
|
1776
|
+
const angleDeviation = Math.min(rawAngleDeviation, 360 - rawAngleDeviation);
|
|
1766
1777
|
return distance * 1 + // Base distance
|
|
1767
1778
|
offAxisDeviation * 2 + // Heavy penalty for off-axis deviation
|
|
1768
1779
|
(distance - directionalDistance) * 1.5 + // Penalty for diagonal distance
|
|
@@ -2100,7 +2111,7 @@ class Editor extends EventEmitter {
|
|
|
2100
2111
|
* @public
|
|
2101
2112
|
*/
|
|
2102
2113
|
setHintingShapes(shapes) {
|
|
2103
|
-
const ids =
|
|
2114
|
+
const ids = toShapeIds(shapes);
|
|
2104
2115
|
this.run(
|
|
2105
2116
|
() => {
|
|
2106
2117
|
this._updateCurrentPageState({ hintingShapeIds: dedupe(ids) });
|
|
@@ -2130,7 +2141,7 @@ class Editor extends EventEmitter {
|
|
|
2130
2141
|
* @public
|
|
2131
2142
|
*/
|
|
2132
2143
|
setErasingShapes(shapes) {
|
|
2133
|
-
const ids =
|
|
2144
|
+
const ids = toShapeIds(shapes).slice();
|
|
2134
2145
|
ids.sort();
|
|
2135
2146
|
const erasingShapeIds = this.getErasingShapeIds();
|
|
2136
2147
|
this.run(
|
|
@@ -2537,14 +2548,16 @@ class Editor extends EventEmitter {
|
|
|
2537
2548
|
setCamera(point, opts) {
|
|
2538
2549
|
const { isLocked } = this._cameraOptions.__unsafe__getWithoutCapture();
|
|
2539
2550
|
if (isLocked && !opts?.force) return this;
|
|
2551
|
+
const _point = new Vec(point.x, point.y, point.z ?? this.getZoomLevel());
|
|
2552
|
+
if (!Number.isFinite(_point.x) || !Number.isFinite(_point.y) || !Number.isFinite(_point.z)) {
|
|
2553
|
+
throw Error(
|
|
2554
|
+
`Editor.setCamera: expected finite values, got (${_point.x}, ${_point.y}, ${_point.z}).`
|
|
2555
|
+
);
|
|
2556
|
+
}
|
|
2540
2557
|
this.stopCameraAnimation();
|
|
2541
2558
|
if (this.getInstanceState().followingUserId) {
|
|
2542
2559
|
this.stopFollowingUser();
|
|
2543
2560
|
}
|
|
2544
|
-
const _point = Vec.Cast(point);
|
|
2545
|
-
if (!Number.isFinite(_point.x)) _point.x = 0;
|
|
2546
|
-
if (!Number.isFinite(_point.y)) _point.y = 0;
|
|
2547
|
-
if (_point.z === void 0 || !Number.isFinite(_point.z)) point.z = this.getZoomLevel();
|
|
2548
2561
|
const camera = this.getConstrainedCamera(_point, opts);
|
|
2549
2562
|
if (opts?.animation) {
|
|
2550
2563
|
const { width, height } = this.getViewportScreenBounds();
|
|
@@ -2923,7 +2936,7 @@ class Editor extends EventEmitter {
|
|
|
2923
2936
|
newCx += center.x / newCz - center.x / cz;
|
|
2924
2937
|
newCy += center.y / newCz - center.y / cz;
|
|
2925
2938
|
}
|
|
2926
|
-
currentSpeed *= 1 - friction;
|
|
2939
|
+
currentSpeed *= (1 - friction) ** (elapsed / FRAME_MS_60HZ);
|
|
2927
2940
|
if (currentSpeed < speedThreshold) {
|
|
2928
2941
|
cancel();
|
|
2929
2942
|
} else {
|
|
@@ -2957,6 +2970,7 @@ class Editor extends EventEmitter {
|
|
|
2957
2970
|
}
|
|
2958
2971
|
const isOnSamePage = presence.currentPageId === this.getCurrentPageId();
|
|
2959
2972
|
if (!isOnSamePage) {
|
|
2973
|
+
this.markHistoryStoppingPoint("change-page");
|
|
2960
2974
|
this.setCurrentPage(presence.currentPageId);
|
|
2961
2975
|
}
|
|
2962
2976
|
if (opts && opts.animation && !isOnSamePage) {
|
|
@@ -3788,7 +3802,9 @@ class Editor extends EventEmitter {
|
|
|
3788
3802
|
if (ids.length <= 0) return this;
|
|
3789
3803
|
this.run(
|
|
3790
3804
|
() => {
|
|
3791
|
-
this.store.props.assets.remove?.(ids)
|
|
3805
|
+
Promise.resolve(this.store.props.assets.remove?.(ids)).catch(
|
|
3806
|
+
(err) => console.error("Error while removing assets from the asset store:", err)
|
|
3807
|
+
);
|
|
3792
3808
|
this.store.remove(ids);
|
|
3793
3809
|
},
|
|
3794
3810
|
{ history: "ignore" }
|
|
@@ -4170,7 +4186,7 @@ class Editor extends EventEmitter {
|
|
|
4170
4186
|
if (shapes.length === 0) {
|
|
4171
4187
|
return;
|
|
4172
4188
|
}
|
|
4173
|
-
const ids =
|
|
4189
|
+
const ids = toShapeIds(shapes);
|
|
4174
4190
|
const freshShapes = compact(ids.map((id) => this.getShape(id)));
|
|
4175
4191
|
if (freshShapes.length === 1) {
|
|
4176
4192
|
const parentId = freshShapes[0].parentId;
|
|
@@ -4673,7 +4689,7 @@ class Editor extends EventEmitter {
|
|
|
4673
4689
|
* @public
|
|
4674
4690
|
*/
|
|
4675
4691
|
reparentShapes(shapes, parentId, insertIndex) {
|
|
4676
|
-
const ids =
|
|
4692
|
+
const ids = toShapeIds(shapes);
|
|
4677
4693
|
if (ids.length === 0) return this;
|
|
4678
4694
|
const changes = [];
|
|
4679
4695
|
const parentTransform = isPageId(parentId) ? Mat.Identity() : this.getShapePageTransform(parentId);
|
|
@@ -4902,6 +4918,7 @@ class Editor extends EventEmitter {
|
|
|
4902
4918
|
* binding, but the `type`, `toId`, and `fromId` must all be provided.
|
|
4903
4919
|
*/
|
|
4904
4920
|
createBindings(partials) {
|
|
4921
|
+
if (this.getIsReadonly()) return this;
|
|
4905
4922
|
const bindings = [];
|
|
4906
4923
|
for (const partial of partials) {
|
|
4907
4924
|
const fromShape = this.getShape(partial.fromId);
|
|
@@ -4936,6 +4953,7 @@ class Editor extends EventEmitter {
|
|
|
4936
4953
|
* binding is skipped. The changes from the partial are merged into the existing record.
|
|
4937
4954
|
*/
|
|
4938
4955
|
updateBindings(partials) {
|
|
4956
|
+
if (this.getIsReadonly()) return this;
|
|
4939
4957
|
const updated = [];
|
|
4940
4958
|
for (const partial of partials) {
|
|
4941
4959
|
if (!partial) continue;
|
|
@@ -4964,6 +4982,16 @@ class Editor extends EventEmitter {
|
|
|
4964
4982
|
* Delete several bindings by their IDs. If a binding ID doesn't exist, it's ignored.
|
|
4965
4983
|
*/
|
|
4966
4984
|
deleteBindings(bindings, { isolateShapes = false } = {}) {
|
|
4985
|
+
if (this.getIsReadonly()) return this;
|
|
4986
|
+
return this._deleteBindings(bindings, { isolateShapes });
|
|
4987
|
+
}
|
|
4988
|
+
/**
|
|
4989
|
+
* Unguarded so that withIsolatedShapes can transiently isolate shapes for copy and export in
|
|
4990
|
+
* readonly mode; the public deleteBindings is what readonly blocks.
|
|
4991
|
+
*
|
|
4992
|
+
* @internal
|
|
4993
|
+
*/
|
|
4994
|
+
_deleteBindings(bindings, { isolateShapes = false } = {}) {
|
|
4967
4995
|
const ids = bindings.map((binding) => typeof binding === "string" ? binding : binding.id);
|
|
4968
4996
|
if (isolateShapes) {
|
|
4969
4997
|
this.store.atomic(() => {
|
|
@@ -5022,7 +5050,7 @@ class Editor extends EventEmitter {
|
|
|
5022
5050
|
* @param opts - The options for the rotation.
|
|
5023
5051
|
*/
|
|
5024
5052
|
rotateShapesBy(shapes, delta, opts) {
|
|
5025
|
-
const ids =
|
|
5053
|
+
const ids = toShapeIds(shapes);
|
|
5026
5054
|
if (ids.length <= 0) return this;
|
|
5027
5055
|
const snapshot = getRotationSnapshot({ editor: this, ids });
|
|
5028
5056
|
if (!snapshot) return this;
|
|
@@ -5059,6 +5087,14 @@ class Editor extends EventEmitter {
|
|
|
5059
5087
|
}
|
|
5060
5088
|
return workingShape;
|
|
5061
5089
|
}
|
|
5090
|
+
// Counter-rotates the page-space delta into the parent's space; without that a child of a rotated
|
|
5091
|
+
// frame or group would move along its parent's axes instead of the page's.
|
|
5092
|
+
// todo: a shape laid out together with its own parent moves twice, once with the parent and once
|
|
5093
|
+
// on its own; the layout commands should skip shapes whose ancestors are also being laid out
|
|
5094
|
+
getChangesToTranslateShapeByPageDelta(shape, pageDelta) {
|
|
5095
|
+
const localDelta = Vec.From(pageDelta).rot(-this.getShapeParentTransform(shape).rotation());
|
|
5096
|
+
return this.getChangesToTranslateShape(shape, localDelta.add(shape));
|
|
5097
|
+
}
|
|
5062
5098
|
/**
|
|
5063
5099
|
* Move shapes by a delta.
|
|
5064
5100
|
*
|
|
@@ -5071,14 +5107,12 @@ class Editor extends EventEmitter {
|
|
|
5071
5107
|
* @param offset - The offset to apply to the shapes.
|
|
5072
5108
|
*/
|
|
5073
5109
|
nudgeShapes(shapes, offset) {
|
|
5074
|
-
const ids =
|
|
5110
|
+
const ids = toShapeIds(shapes);
|
|
5075
5111
|
if (ids.length <= 0) return this;
|
|
5076
5112
|
const changes = [];
|
|
5077
5113
|
for (const id of ids) {
|
|
5078
5114
|
const shape = this.getShape(id);
|
|
5079
|
-
|
|
5080
|
-
localDelta.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5081
|
-
changes.push(this.getChangesToTranslateShape(shape, localDelta.add(shape)));
|
|
5115
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, offset));
|
|
5082
5116
|
}
|
|
5083
5117
|
this.updateShapes(changes);
|
|
5084
5118
|
return this;
|
|
@@ -5099,7 +5133,7 @@ class Editor extends EventEmitter {
|
|
|
5099
5133
|
*/
|
|
5100
5134
|
duplicateShapes(shapes, offset) {
|
|
5101
5135
|
this.run(() => {
|
|
5102
|
-
const _ids =
|
|
5136
|
+
const _ids = toShapeIds(shapes);
|
|
5103
5137
|
const ids = this._shouldIgnoreShapeLock ? _ids : this._getUnlockedShapeIds(_ids);
|
|
5104
5138
|
if (ids.length <= 0) return this;
|
|
5105
5139
|
const initialIds = new Set(ids);
|
|
@@ -5208,7 +5242,7 @@ class Editor extends EventEmitter {
|
|
|
5208
5242
|
* @public
|
|
5209
5243
|
*/
|
|
5210
5244
|
moveShapesToPage(shapes, pageId) {
|
|
5211
|
-
const ids =
|
|
5245
|
+
const ids = toShapeIds(shapes);
|
|
5212
5246
|
if (ids.length === 0) return this;
|
|
5213
5247
|
if (this.getIsReadonly()) return this;
|
|
5214
5248
|
const currentPageId = this.getCurrentPageId();
|
|
@@ -5244,7 +5278,7 @@ class Editor extends EventEmitter {
|
|
|
5244
5278
|
* @public
|
|
5245
5279
|
*/
|
|
5246
5280
|
toggleLock(shapes) {
|
|
5247
|
-
const ids =
|
|
5281
|
+
const ids = toShapeIds(shapes);
|
|
5248
5282
|
if (this.getIsReadonly() || ids.length === 0) return this;
|
|
5249
5283
|
let allLocked = true;
|
|
5250
5284
|
const shapesToToggle = [];
|
|
@@ -5283,7 +5317,7 @@ class Editor extends EventEmitter {
|
|
|
5283
5317
|
* @public
|
|
5284
5318
|
*/
|
|
5285
5319
|
sendToBack(shapes) {
|
|
5286
|
-
const ids =
|
|
5320
|
+
const ids = toShapeIds(shapes);
|
|
5287
5321
|
const changes = getReorderingShapesChanges(this, "toBack", ids, {
|
|
5288
5322
|
considerAllShapes: true
|
|
5289
5323
|
});
|
|
@@ -5313,7 +5347,7 @@ class Editor extends EventEmitter {
|
|
|
5313
5347
|
* @public
|
|
5314
5348
|
*/
|
|
5315
5349
|
sendBackward(shapes, opts = {}) {
|
|
5316
|
-
const ids =
|
|
5350
|
+
const ids = toShapeIds(shapes);
|
|
5317
5351
|
const changes = getReorderingShapesChanges(this, "backward", ids, opts);
|
|
5318
5352
|
if (changes) this.updateShapes(changes);
|
|
5319
5353
|
return this;
|
|
@@ -5341,7 +5375,7 @@ class Editor extends EventEmitter {
|
|
|
5341
5375
|
* @public
|
|
5342
5376
|
*/
|
|
5343
5377
|
bringForward(shapes, opts = {}) {
|
|
5344
|
-
const ids =
|
|
5378
|
+
const ids = toShapeIds(shapes);
|
|
5345
5379
|
const changes = getReorderingShapesChanges(this, "forward", ids, opts);
|
|
5346
5380
|
if (changes) this.updateShapes(changes);
|
|
5347
5381
|
return this;
|
|
@@ -5360,7 +5394,7 @@ class Editor extends EventEmitter {
|
|
|
5360
5394
|
* @public
|
|
5361
5395
|
*/
|
|
5362
5396
|
bringToFront(shapes) {
|
|
5363
|
-
const ids =
|
|
5397
|
+
const ids = toShapeIds(shapes);
|
|
5364
5398
|
const changes = getReorderingShapesChanges(this, "toFront", ids);
|
|
5365
5399
|
if (changes) this.updateShapes(changes);
|
|
5366
5400
|
return this;
|
|
@@ -5372,7 +5406,7 @@ class Editor extends EventEmitter {
|
|
|
5372
5406
|
* @internal
|
|
5373
5407
|
*/
|
|
5374
5408
|
getShapeClusters(shapes, type, opts) {
|
|
5375
|
-
const ids =
|
|
5409
|
+
const ids = toShapeIds(shapes);
|
|
5376
5410
|
let freshShapes = compact(ids.map((id) => this.getShape(id)));
|
|
5377
5411
|
if (opts?.filterAxisAligned) {
|
|
5378
5412
|
freshShapes = freshShapes.filter((s) => {
|
|
@@ -5397,7 +5431,7 @@ class Editor extends EventEmitter {
|
|
|
5397
5431
|
const shapesMovingTogether = [shape];
|
|
5398
5432
|
const boundsOfShapesMovingTogether = [shapePageBounds];
|
|
5399
5433
|
this.collectShapesViaArrowBindings({
|
|
5400
|
-
bindings: this.
|
|
5434
|
+
bindings: this.getBindingsInvolvingShape(shape.id, "arrow"),
|
|
5401
5435
|
initialShapes: freshShapes,
|
|
5402
5436
|
resultShapes: shapesMovingTogether,
|
|
5403
5437
|
resultBounds: boundsOfShapesMovingTogether,
|
|
@@ -5453,7 +5487,7 @@ class Editor extends EventEmitter {
|
|
|
5453
5487
|
*/
|
|
5454
5488
|
flipShapes(shapes, operation) {
|
|
5455
5489
|
if (this.getIsReadonly()) return this;
|
|
5456
|
-
const ids =
|
|
5490
|
+
const ids = toShapeIds(shapes);
|
|
5457
5491
|
const shapesToFlipFirstPass = compact(ids.map((id) => this.getShape(id)));
|
|
5458
5492
|
for (const shape of shapesToFlipFirstPass) {
|
|
5459
5493
|
if (this.isShapeOfType(shape, "group")) {
|
|
@@ -5527,21 +5561,7 @@ class Editor extends EventEmitter {
|
|
|
5527
5561
|
const { clusters: shapeClustersToStack } = this.getShapeClusters(shapes, "stack");
|
|
5528
5562
|
const len = shapeClustersToStack.length;
|
|
5529
5563
|
if (_gap === 0 && len < 3 || len < 2) return this;
|
|
5530
|
-
|
|
5531
|
-
let min;
|
|
5532
|
-
let max;
|
|
5533
|
-
let dim;
|
|
5534
|
-
if (operation === "horizontal") {
|
|
5535
|
-
val = "x";
|
|
5536
|
-
min = "minX";
|
|
5537
|
-
max = "maxX";
|
|
5538
|
-
dim = "width";
|
|
5539
|
-
} else {
|
|
5540
|
-
val = "y";
|
|
5541
|
-
min = "minY";
|
|
5542
|
-
max = "maxY";
|
|
5543
|
-
dim = "height";
|
|
5544
|
-
}
|
|
5564
|
+
const { val, min, max, dim } = AXIS[operation];
|
|
5545
5565
|
let shapeGap = 0;
|
|
5546
5566
|
shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
|
|
5547
5567
|
if (_gap === 0) {
|
|
@@ -5580,13 +5600,7 @@ class Editor extends EventEmitter {
|
|
|
5580
5600
|
const delta = new Vec();
|
|
5581
5601
|
delta[val] = v + shapeGap - pageBounds[val];
|
|
5582
5602
|
for (const shape of shapes2) {
|
|
5583
|
-
|
|
5584
|
-
const parent = this.getShapeParent(shape);
|
|
5585
|
-
if (parent) {
|
|
5586
|
-
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5587
|
-
}
|
|
5588
|
-
shapeDelta.add(shape);
|
|
5589
|
-
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
5603
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
|
|
5590
5604
|
}
|
|
5591
5605
|
v += pageBounds[dim] + shapeGap;
|
|
5592
5606
|
}
|
|
@@ -5666,13 +5680,7 @@ class Editor extends EventEmitter {
|
|
|
5666
5680
|
for (const { shapes: shapes2, pageBounds, nextPageBounds } of shapeClustersToPack) {
|
|
5667
5681
|
const delta = Vec.Sub(nextPageBounds.point, pageBounds.point).add(centerDelta);
|
|
5668
5682
|
for (const shape of shapes2) {
|
|
5669
|
-
|
|
5670
|
-
const parent = this.getShapeParent(shape);
|
|
5671
|
-
if (parent) {
|
|
5672
|
-
shapeDelta.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5673
|
-
}
|
|
5674
|
-
shapeDelta.add(shape);
|
|
5675
|
-
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
5683
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
|
|
5676
5684
|
}
|
|
5677
5685
|
}
|
|
5678
5686
|
if (changes.length) {
|
|
@@ -5732,13 +5740,7 @@ class Editor extends EventEmitter {
|
|
|
5732
5740
|
}
|
|
5733
5741
|
}
|
|
5734
5742
|
for (const shape of shapes2) {
|
|
5735
|
-
|
|
5736
|
-
const parent = this.getShapeParent(shape);
|
|
5737
|
-
if (parent) {
|
|
5738
|
-
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5739
|
-
}
|
|
5740
|
-
shapeDelta.add(shape);
|
|
5741
|
-
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
5743
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
|
|
5742
5744
|
}
|
|
5743
5745
|
});
|
|
5744
5746
|
this.updateShapes(changes);
|
|
@@ -5762,27 +5764,13 @@ class Editor extends EventEmitter {
|
|
|
5762
5764
|
if (this.getIsReadonly()) return this;
|
|
5763
5765
|
const { clusters: shapeClustersToDistribute } = this.getShapeClusters(shapes, "distribute");
|
|
5764
5766
|
if (shapeClustersToDistribute.length < 3) return this;
|
|
5765
|
-
|
|
5766
|
-
let min;
|
|
5767
|
-
let max;
|
|
5768
|
-
let dim;
|
|
5769
|
-
if (operation === "horizontal") {
|
|
5770
|
-
val = "x";
|
|
5771
|
-
min = "minX";
|
|
5772
|
-
max = "maxX";
|
|
5773
|
-
dim = "width";
|
|
5774
|
-
} else {
|
|
5775
|
-
val = "y";
|
|
5776
|
-
min = "minY";
|
|
5777
|
-
max = "maxY";
|
|
5778
|
-
dim = "height";
|
|
5779
|
-
}
|
|
5767
|
+
const { val, min, max, dim } = AXIS[operation];
|
|
5780
5768
|
const changes = [];
|
|
5781
5769
|
const first = shapeClustersToDistribute.sort((a, b) => a.pageBounds[min] - b.pageBounds[min])[0];
|
|
5782
5770
|
const last2 = shapeClustersToDistribute.sort((a, b) => b.pageBounds[max] - a.pageBounds[max])[0];
|
|
5783
5771
|
if (first === last2) {
|
|
5784
5772
|
const excludedShapeIds = new Set(first.shapes.map((s) => s.id));
|
|
5785
|
-
const ids =
|
|
5773
|
+
const ids = toShapeIds(shapes);
|
|
5786
5774
|
return this.distributeShapes(
|
|
5787
5775
|
ids.filter((id) => !excludedShapeIds.has(id)),
|
|
5788
5776
|
operation
|
|
@@ -5806,13 +5794,7 @@ class Editor extends EventEmitter {
|
|
|
5806
5794
|
delta[val] = last2.pageBounds[max] - pageBounds[max] - 1;
|
|
5807
5795
|
}
|
|
5808
5796
|
for (const shape of shapes2) {
|
|
5809
|
-
|
|
5810
|
-
const parent = this.getShapeParent(shape);
|
|
5811
|
-
if (parent) {
|
|
5812
|
-
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5813
|
-
}
|
|
5814
|
-
shapeDelta.add(shape);
|
|
5815
|
-
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
5797
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
|
|
5816
5798
|
}
|
|
5817
5799
|
v += pageBounds[dim] + gap;
|
|
5818
5800
|
}
|
|
@@ -5842,32 +5824,17 @@ class Editor extends EventEmitter {
|
|
|
5842
5824
|
);
|
|
5843
5825
|
if (shapeClustersToStretch.length < 2) return this;
|
|
5844
5826
|
const commonBounds = Box.Common(allBounds);
|
|
5845
|
-
|
|
5846
|
-
let min;
|
|
5847
|
-
let dim;
|
|
5848
|
-
if (operation === "horizontal") {
|
|
5849
|
-
val = "x";
|
|
5850
|
-
min = "minX";
|
|
5851
|
-
dim = "width";
|
|
5852
|
-
} else {
|
|
5853
|
-
val = "y";
|
|
5854
|
-
min = "minY";
|
|
5855
|
-
dim = "height";
|
|
5856
|
-
}
|
|
5827
|
+
const { val, min, dim } = AXIS[operation];
|
|
5857
5828
|
this.run(() => {
|
|
5858
5829
|
shapeClustersToStretch.forEach(({ shapes: shapes2, pageBounds }) => {
|
|
5859
|
-
const
|
|
5860
|
-
|
|
5830
|
+
const pageOffset = new Vec();
|
|
5831
|
+
pageOffset[val] = commonBounds[min] - pageBounds[min];
|
|
5861
5832
|
const scaleOrigin = pageBounds.center.clone();
|
|
5862
5833
|
scaleOrigin[val] = commonBounds[min];
|
|
5863
5834
|
const scale = new Vec(1, 1);
|
|
5864
5835
|
scale[val] = commonBounds[dim] / pageBounds[dim];
|
|
5865
5836
|
for (const shape of shapes2) {
|
|
5866
|
-
|
|
5867
|
-
shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5868
|
-
shapeLocalOffset.add(shape);
|
|
5869
|
-
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5870
|
-
this.updateShape(changes);
|
|
5837
|
+
this.updateShape(this.getChangesToTranslateShapeByPageDelta(shape, pageOffset));
|
|
5871
5838
|
this.resizeShape(shape.id, scale, {
|
|
5872
5839
|
initialBounds: this.getShapeGeometry(shape).bounds,
|
|
5873
5840
|
scaleOrigin,
|
|
@@ -5910,7 +5877,7 @@ class Editor extends EventEmitter {
|
|
|
5910
5877
|
const scaleY = targetBounds.height / commonBounds.height;
|
|
5911
5878
|
const scale = new Vec(scaleX, scaleY);
|
|
5912
5879
|
shapeClusters.forEach(({ shapes: shapes2, pageBounds }) => {
|
|
5913
|
-
const
|
|
5880
|
+
const pageOffset = new Vec(
|
|
5914
5881
|
targetBounds.minX - commonBounds.minX + (pageBounds.minX - commonBounds.minX) * (scaleX - 1),
|
|
5915
5882
|
targetBounds.minY - commonBounds.minY + (pageBounds.minY - commonBounds.minY) * (scaleY - 1)
|
|
5916
5883
|
);
|
|
@@ -5919,11 +5886,7 @@ class Editor extends EventEmitter {
|
|
|
5919
5886
|
targetBounds.minY + (pageBounds.minY - commonBounds.minY) * scaleY
|
|
5920
5887
|
);
|
|
5921
5888
|
for (const shape of shapes2) {
|
|
5922
|
-
|
|
5923
|
-
shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5924
|
-
shapeLocalOffset.add(shape);
|
|
5925
|
-
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5926
|
-
this.updateShape(changes);
|
|
5889
|
+
this.updateShape(this.getChangesToTranslateShapeByPageDelta(shape, pageOffset));
|
|
5927
5890
|
this.resizeShape(shape.id, scale, {
|
|
5928
5891
|
initialBounds: this.getShapeGeometry(shape).bounds,
|
|
5929
5892
|
scaleOrigin,
|
|
@@ -6342,12 +6305,17 @@ class Editor extends EventEmitter {
|
|
|
6342
6305
|
let remaining = duration;
|
|
6343
6306
|
let t;
|
|
6344
6307
|
const animations = [];
|
|
6308
|
+
const ignoreShapeLock = this._shouldIgnoreShapeLock;
|
|
6345
6309
|
let partial, result;
|
|
6346
6310
|
for (let i = 0, n = partials.length; i < n; i++) {
|
|
6347
6311
|
partial = partials[i];
|
|
6348
6312
|
if (!partial) continue;
|
|
6349
6313
|
const shape = this.getShape(partial.id);
|
|
6350
6314
|
if (!shape) continue;
|
|
6315
|
+
const unlocks = shape.isLocked && Object.hasOwn(partial, "isLocked") && !partial.isLocked;
|
|
6316
|
+
if (!ignoreShapeLock && !unlocks && this.isShapeOrAncestorLocked(shape)) {
|
|
6317
|
+
continue;
|
|
6318
|
+
}
|
|
6351
6319
|
result = {
|
|
6352
6320
|
start: structuredClone(shape),
|
|
6353
6321
|
end: applyPartialToRecordWithProps(structuredClone(shape), partial)
|
|
@@ -6363,7 +6331,7 @@ class Editor extends EventEmitter {
|
|
|
6363
6331
|
(p) => p && animatingShapes2.get(p.id) === animationId
|
|
6364
6332
|
);
|
|
6365
6333
|
if (partialsToUpdate.length) {
|
|
6366
|
-
this.updateShapes(partialsToUpdate);
|
|
6334
|
+
this.run(() => this.updateShapes(partialsToUpdate), { ignoreShapeLock });
|
|
6367
6335
|
}
|
|
6368
6336
|
this.off("tick", handleTick);
|
|
6369
6337
|
return;
|
|
@@ -6396,13 +6364,13 @@ class Editor extends EventEmitter {
|
|
|
6396
6364
|
throw Error("Editor.groupShapes: must provide an array of shapes or shape ids");
|
|
6397
6365
|
}
|
|
6398
6366
|
if (this.getIsReadonly()) return this;
|
|
6399
|
-
const ids =
|
|
6400
|
-
if (ids.length <= 1) return this;
|
|
6367
|
+
const ids = toShapeIds(shapes);
|
|
6401
6368
|
const shapesToGroup = compact(
|
|
6402
6369
|
(this._shouldIgnoreShapeLock ? ids : this._getUnlockedShapeIds(ids)).map(
|
|
6403
6370
|
(id) => this.getShape(id)
|
|
6404
6371
|
)
|
|
6405
6372
|
);
|
|
6373
|
+
if (shapesToGroup.length <= 1) return this;
|
|
6406
6374
|
const sortedShapeIds = shapesToGroup.sort(sortByIndex).map((s) => s.id);
|
|
6407
6375
|
const childBounds = compact(shapesToGroup.map((shape) => this.getShapePageBounds(shape)));
|
|
6408
6376
|
const pageBounds = Box.Common(childBounds);
|
|
@@ -6411,8 +6379,11 @@ class Editor extends EventEmitter {
|
|
|
6411
6379
|
}
|
|
6412
6380
|
const { x, y } = pageBounds.point;
|
|
6413
6381
|
const parentId = this.findCommonAncestor(shapesToGroup) ?? this.getCurrentPageId();
|
|
6414
|
-
if (this.
|
|
6415
|
-
|
|
6382
|
+
if (!this.canCreateShapes([groupId])) {
|
|
6383
|
+
alertMaxShapes(this);
|
|
6384
|
+
return this;
|
|
6385
|
+
}
|
|
6386
|
+
if (this.isIn("select") && !this.isIn("select.idle")) {
|
|
6416
6387
|
this.cancel();
|
|
6417
6388
|
}
|
|
6418
6389
|
const shapesWithRootParent = shapesToGroup.filter((shape) => shape.parentId === parentId).sort(sortByIndex);
|
|
@@ -6440,15 +6411,14 @@ class Editor extends EventEmitter {
|
|
|
6440
6411
|
ungroupShapes(shapes, opts = {}) {
|
|
6441
6412
|
if (this.getIsReadonly()) return this;
|
|
6442
6413
|
const { select = true } = opts;
|
|
6443
|
-
const ids =
|
|
6414
|
+
const ids = toShapeIds(shapes);
|
|
6444
6415
|
const shapesToUngroup = compact(
|
|
6445
6416
|
(this._shouldIgnoreShapeLock ? ids : this._getUnlockedShapeIds(ids)).map(
|
|
6446
6417
|
(id) => this.getShape(id)
|
|
6447
6418
|
)
|
|
6448
6419
|
);
|
|
6449
6420
|
if (shapesToUngroup.length === 0) return this;
|
|
6450
|
-
if (this.
|
|
6451
|
-
if (!this.isIn("select.idle")) {
|
|
6421
|
+
if (this.isIn("select") && !this.isIn("select.idle")) {
|
|
6452
6422
|
this.cancel();
|
|
6453
6423
|
}
|
|
6454
6424
|
const idsToSelect = /* @__PURE__ */ new Set();
|
|
@@ -6462,16 +6432,16 @@ class Editor extends EventEmitter {
|
|
|
6462
6432
|
});
|
|
6463
6433
|
if (groups.length === 0) return this;
|
|
6464
6434
|
this.run(() => {
|
|
6465
|
-
let group;
|
|
6466
6435
|
for (let i = 0, n = groups.length; i < n; i++) {
|
|
6467
|
-
group = groups[i];
|
|
6436
|
+
const group = this.getShape(groups[i].id);
|
|
6437
|
+
if (!group) continue;
|
|
6468
6438
|
const childIds = this.getSortedChildIdsForParent(group.id);
|
|
6469
6439
|
for (let j = 0, n2 = childIds.length; j < n2; j++) {
|
|
6470
6440
|
idsToSelect.add(childIds[j]);
|
|
6471
6441
|
}
|
|
6472
6442
|
this.reparentShapes(childIds, group.parentId, group.index);
|
|
6473
6443
|
}
|
|
6474
|
-
this.deleteShapes(groups.map((
|
|
6444
|
+
this.deleteShapes(groups.map((group) => group.id));
|
|
6475
6445
|
if (select) {
|
|
6476
6446
|
this.select(...idsToSelect);
|
|
6477
6447
|
}
|
|
@@ -6552,14 +6522,14 @@ class Editor extends EventEmitter {
|
|
|
6552
6522
|
}
|
|
6553
6523
|
/** @internal */
|
|
6554
6524
|
_getUnlockedShapeIds(ids) {
|
|
6555
|
-
return ids.filter((id) => !this.
|
|
6525
|
+
return ids.filter((id) => !this.isShapeOrAncestorLocked(id));
|
|
6556
6526
|
}
|
|
6557
6527
|
deleteShapes(_ids) {
|
|
6558
6528
|
if (this.getIsReadonly()) return this;
|
|
6559
6529
|
if (!Array.isArray(_ids)) {
|
|
6560
6530
|
throw Error("Editor.deleteShapes: must provide an array of shapes or shapeIds");
|
|
6561
6531
|
}
|
|
6562
|
-
const shapeIds =
|
|
6532
|
+
const shapeIds = toShapeIds(_ids);
|
|
6563
6533
|
const shapeIdsToDelete = this._shouldIgnoreShapeLock ? shapeIds : this._getUnlockedShapeIds(shapeIds);
|
|
6564
6534
|
if (shapeIdsToDelete.length === 0) return this;
|
|
6565
6535
|
const allShapeIdsToDelete = new Set(shapeIdsToDelete);
|
|
@@ -6904,7 +6874,7 @@ class Editor extends EventEmitter {
|
|
|
6904
6874
|
* @public
|
|
6905
6875
|
*/
|
|
6906
6876
|
getContentFromCurrentPage(shapes) {
|
|
6907
|
-
const ids =
|
|
6877
|
+
const ids = toShapeIds(shapes);
|
|
6908
6878
|
if (!ids) return;
|
|
6909
6879
|
if (ids.length === 0) return;
|
|
6910
6880
|
const shapeIds = this.getShapeAndDescendantIds(ids);
|
|
@@ -6972,21 +6942,29 @@ class Editor extends EventEmitter {
|
|
|
6972
6942
|
await Promise.allSettled(
|
|
6973
6943
|
content.assets.map(async (asset) => {
|
|
6974
6944
|
if ((asset.type === "image" || asset.type === "video") && !asset.props.src?.startsWith("data:image") && !asset.props.src?.startsWith("data:video") && !asset.props.src?.startsWith("http")) {
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6945
|
+
try {
|
|
6946
|
+
const objectUrl = await this.store.props.assets.resolve(asset, {
|
|
6947
|
+
screenScale: 1,
|
|
6948
|
+
steppedScreenScale: 1,
|
|
6949
|
+
dpr: 1,
|
|
6950
|
+
networkEffectiveType: null,
|
|
6951
|
+
shouldResolveToOriginal: true
|
|
6952
|
+
});
|
|
6953
|
+
if (objectUrl) {
|
|
6954
|
+
const response = await fetch(objectUrl);
|
|
6955
|
+
if (response.ok) {
|
|
6956
|
+
const assetWithDataUrl = structuredClone(asset);
|
|
6957
|
+
assetWithDataUrl.props.src = await FileHelpers.blobToDataUrl(await response.blob());
|
|
6958
|
+
assets.push(assetWithDataUrl);
|
|
6959
|
+
return;
|
|
6960
|
+
}
|
|
6961
|
+
console.warn(`Could not inline asset ${asset.id}: fetch returned ${response.status}`);
|
|
6962
|
+
}
|
|
6963
|
+
} catch (err) {
|
|
6964
|
+
console.warn(`Could not inline asset ${asset.id}`, err);
|
|
6965
|
+
}
|
|
6989
6966
|
}
|
|
6967
|
+
assets.push(asset);
|
|
6990
6968
|
})
|
|
6991
6969
|
);
|
|
6992
6970
|
content.assets = assets;
|
|
@@ -7280,7 +7258,7 @@ class Editor extends EventEmitter {
|
|
|
7280
7258
|
* @public
|
|
7281
7259
|
*/
|
|
7282
7260
|
async getSvgElement(shapes, opts = {}) {
|
|
7283
|
-
const ids = shapes.length === 0 ? this.getCurrentPageShapeIdsSorted() :
|
|
7261
|
+
const ids = shapes.length === 0 ? this.getCurrentPageShapeIdsSorted() : toShapeIds(shapes);
|
|
7284
7262
|
if (ids.length === 0) return void 0;
|
|
7285
7263
|
await this.fonts.loadRequiredFontsForCurrentPage(this.options.maxFontsToLoadBeforeRender);
|
|
7286
7264
|
return exportToSvg(this, ids, opts);
|
|
@@ -8334,8 +8312,8 @@ class Editor extends EventEmitter {
|
|
|
8334
8312
|
break;
|
|
8335
8313
|
}
|
|
8336
8314
|
case "keyboard": {
|
|
8337
|
-
if (info.
|
|
8338
|
-
if (info.
|
|
8315
|
+
if (info.code === "ShiftRight") info.code = "ShiftLeft";
|
|
8316
|
+
if (info.code === "AltRight") info.code = "AltLeft";
|
|
8339
8317
|
if (info.code === "ControlRight") info.code = "ControlLeft";
|
|
8340
8318
|
if (info.code === "MetaRight") info.code = "MetaLeft";
|
|
8341
8319
|
switch (info.name) {
|
|
@@ -8705,6 +8683,9 @@ function pushShapeWithDescendants(editor, id, result) {
|
|
|
8705
8683
|
pushShapeWithDescendants(editor, childIds[i], result);
|
|
8706
8684
|
}
|
|
8707
8685
|
}
|
|
8686
|
+
function toShapeIds(shapes) {
|
|
8687
|
+
return typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
|
|
8688
|
+
}
|
|
8708
8689
|
function withIsolatedShapes(editor, shapeIds, callback) {
|
|
8709
8690
|
let result;
|
|
8710
8691
|
editor.run(
|
|
@@ -8727,7 +8708,7 @@ function withIsolatedShapes(editor, shapeIds, callback) {
|
|
|
8727
8708
|
}
|
|
8728
8709
|
}
|
|
8729
8710
|
}
|
|
8730
|
-
editor.
|
|
8711
|
+
editor._deleteBindings([...bindingsToRemove], { isolateShapes: true });
|
|
8731
8712
|
try {
|
|
8732
8713
|
result = Result.ok(callback(bindingsWithBoth));
|
|
8733
8714
|
} catch (error) {
|