@tldraw/editor 5.4.1 → 5.5.0-canary.003bf5951274
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 +37 -14
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +16 -12
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +42 -3
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +5 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +2 -5
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +3 -3
- package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +2 -2
- package/dist-cjs/lib/constants.js +2 -0
- package/dist-cjs/lib/constants.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +147 -157
- 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/TextManager/TextManager.js +4 -4
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.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/editor/types/external-content.js.map +1 -1
- 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/hooks/EditorComponentsContext.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +24 -0
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useIdentity.js +6 -2
- package/dist-cjs/lib/hooks/useIdentity.js.map +3 -3
- 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/debug-flags.js +0 -6
- package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
- package/dist-cjs/lib/utils/deepLinks.js +2 -1
- package/dist-cjs/lib/utils/deepLinks.js.map +2 -2
- package/dist-cjs/lib/utils/sync/LocalIndexedDb.js +22 -24
- package/dist-cjs/lib/utils/sync/LocalIndexedDb.js.map +2 -2
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +81 -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 +37 -14
- package/dist-esm/index.mjs +4 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +17 -13
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +42 -3
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +5 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +2 -5
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +3 -3
- package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
- package/dist-esm/lib/constants.mjs +2 -0
- package/dist-esm/lib/constants.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +148 -157
- 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/TextManager/TextManager.mjs +4 -4
- package/dist-esm/lib/editor/managers/TextManager/TextManager.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/hooks/EditorComponentsContext.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +24 -0
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useIdentity.mjs +7 -3
- package/dist-esm/lib/hooks/useIdentity.mjs.map +3 -3
- 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/debug-flags.mjs +0 -6
- package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
- package/dist-esm/lib/utils/deepLinks.mjs +2 -1
- package/dist-esm/lib/utils/deepLinks.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs +22 -24
- package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +81 -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/editor.css +9 -1
- package/package.json +8 -11
- package/src/index.ts +5 -1
- package/src/lib/TldrawEditor.tsx +35 -21
- package/src/lib/components/MenuClickCapture.tsx +55 -4
- package/src/lib/components/default-components/DefaultCanvas.tsx +7 -1
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +13 -5
- package/src/lib/components/default-components/DefaultSpinner.tsx +4 -1
- package/src/lib/constants.ts +8 -0
- package/src/lib/editor/Editor.test.ts +20 -0
- package/src/lib/editor/Editor.ts +228 -262
- 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/TextManager/TextManager.test.ts +74 -0
- package/src/lib/editor/managers/TextManager/TextManager.ts +6 -5
- 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/editor/types/external-content.ts +5 -0
- 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/hooks/EditorComponentsContext.tsx +2 -1
- package/src/lib/hooks/useCanvasEvents.ts +42 -0
- package/src/lib/hooks/useIdentity.tsx +12 -1
- 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/test/preserveFocus.test.tsx +81 -0
- package/src/lib/utils/debug-flags.ts +0 -6
- package/src/lib/utils/deepLinks.test.ts +15 -0
- package/src/lib/utils/deepLinks.ts +8 -3
- package/src/lib/utils/sync/LocalIndexedDb.test.ts +95 -0
- package/src/lib/utils/sync/LocalIndexedDb.ts +31 -27
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +257 -1
- package/src/lib/utils/sync/TLLocalSyncClient.ts +112 -54
- package/src/version.ts +3 -3
- package/dist-cjs/lib/primitives/geometry/geometry.bench.js +0 -133
- package/dist-cjs/lib/primitives/geometry/geometry.bench.js.map +0 -7
- package/dist-esm/lib/primitives/geometry/geometry.bench.mjs +0 -132
- package/dist-esm/lib/primitives/geometry/geometry.bench.mjs.map +0 -7
- package/src/lib/primitives/geometry/geometry.bench.ts +0 -179
|
@@ -95,6 +95,10 @@ var import_UserPreferencesManager = require("./managers/UserPreferencesManager/U
|
|
|
95
95
|
var import_OverlayManager = require("./overlays/OverlayManager");
|
|
96
96
|
var import_RootState = require("./tools/RootState");
|
|
97
97
|
const RENDERING_SHAPES_SORT_CACHE_THRESHOLD = 100;
|
|
98
|
+
const AXIS = {
|
|
99
|
+
horizontal: { val: "x", min: "minX", max: "maxX", dim: "width" },
|
|
100
|
+
vertical: { val: "y", min: "minY", max: "maxY", dim: "height" }
|
|
101
|
+
};
|
|
98
102
|
class Editor extends import_eventemitter3.default {
|
|
99
103
|
id = (0, import_utils.uniqueId)();
|
|
100
104
|
constructor({
|
|
@@ -421,7 +425,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
421
425
|
}
|
|
422
426
|
}
|
|
423
427
|
if (deleteBindingIds.length) {
|
|
424
|
-
this.
|
|
428
|
+
this.store.remove(deleteBindingIds);
|
|
425
429
|
}
|
|
426
430
|
}
|
|
427
431
|
},
|
|
@@ -1381,6 +1385,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
1381
1385
|
* @public
|
|
1382
1386
|
**/
|
|
1383
1387
|
updateDocumentSettings(settings) {
|
|
1388
|
+
if (this.getIsReadonly()) return this;
|
|
1384
1389
|
this.run(
|
|
1385
1390
|
() => {
|
|
1386
1391
|
this.store.put([{ ...this.getDocumentSettings(), ...settings }]);
|
|
@@ -1540,7 +1545,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
1540
1545
|
* @public
|
|
1541
1546
|
*/
|
|
1542
1547
|
select(...shapes) {
|
|
1543
|
-
const ids =
|
|
1548
|
+
const ids = toShapeIds(shapes);
|
|
1544
1549
|
this.setSelectedShapes(ids);
|
|
1545
1550
|
return this;
|
|
1546
1551
|
}
|
|
@@ -1555,7 +1560,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
1555
1560
|
* @public
|
|
1556
1561
|
*/
|
|
1557
1562
|
deselect(...shapes) {
|
|
1558
|
-
const ids =
|
|
1563
|
+
const ids = toShapeIds(shapes);
|
|
1559
1564
|
const selectedShapeIds = this.getSelectedShapeIds();
|
|
1560
1565
|
if (selectedShapeIds.length > 0 && ids.length > 0) {
|
|
1561
1566
|
this.setSelectedShapes(selectedShapeIds.filter((id) => !ids.includes(id)));
|
|
@@ -1593,7 +1598,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
1593
1598
|
}
|
|
1594
1599
|
const ids = this.getSortedChildIdsForParent(parentToSelectWithinId);
|
|
1595
1600
|
if (ids.length <= 0) return this;
|
|
1596
|
-
this.setSelectedShapes(this.
|
|
1601
|
+
this.setSelectedShapes(ids.filter((id) => !this.getShape(id)?.isLocked));
|
|
1597
1602
|
return this;
|
|
1598
1603
|
}
|
|
1599
1604
|
/**
|
|
@@ -1610,14 +1615,18 @@ class Editor extends import_eventemitter3.default {
|
|
|
1610
1615
|
const selectedShapeIds = this.getSelectedShapeIds();
|
|
1611
1616
|
const firstParentId = selectedShapeIds[0] ? this.getShape(selectedShapeIds[0])?.parentId : null;
|
|
1612
1617
|
const isSelectedWithinContainer = firstParentId && selectedShapeIds.every((shapeId) => this.getShape(shapeId)?.parentId === firstParentId) && !(0, import_tlschema.isPageId)(firstParentId);
|
|
1613
|
-
const filteredShapes =
|
|
1614
|
-
|
|
1618
|
+
const filteredShapes = this.getCurrentPageShapes().filter(
|
|
1619
|
+
(shape2) => !this.isShapeOrAncestorLocked(shape2) && (isSelectedWithinContainer ? shape2.parentId === firstParentId : (0, import_tlschema.isPageId)(shape2.parentId))
|
|
1620
|
+
);
|
|
1621
|
+
const readingOrderShapes = this._getShapesInReadingOrder(filteredShapes);
|
|
1615
1622
|
const currentShapeId = selectedShapeIds.length === 1 ? selectedShapeIds[0] : readingOrderShapes.find((shape2) => selectedShapeIds.includes(shape2.id))?.id;
|
|
1616
1623
|
let adjacentShapeId;
|
|
1617
1624
|
if (direction === "next" || direction === "prev") {
|
|
1618
1625
|
const shapeIds = readingOrderShapes.map((shape2) => shape2.id);
|
|
1626
|
+
if (shapeIds.length === 0) return;
|
|
1619
1627
|
const currentIndex = currentShapeId ? shapeIds.indexOf(currentShapeId) : -1;
|
|
1620
|
-
const
|
|
1628
|
+
const startIndex = currentIndex === -1 && direction === "prev" ? 0 : currentIndex;
|
|
1629
|
+
const adjacentIndex = (startIndex + (direction === "next" ? 1 : -1) + shapeIds.length) % shapeIds.length;
|
|
1621
1630
|
adjacentShapeId = shapeIds[adjacentIndex];
|
|
1622
1631
|
} else {
|
|
1623
1632
|
if (!currentShapeId) return;
|
|
@@ -1716,13 +1725,14 @@ class Editor extends import_eventemitter3.default {
|
|
|
1716
1725
|
});
|
|
1717
1726
|
if (shapesInDirection.length === 0) return currentShapeId;
|
|
1718
1727
|
const lowestScoringShape = (0, import_utils.minBy)(shapesInDirection, ({ center }) => {
|
|
1719
|
-
const distance = import_Vec.Vec.
|
|
1728
|
+
const distance = import_Vec.Vec.Dist(currentCenter, center);
|
|
1720
1729
|
const dirProp = ["left", "right"].includes(direction) ? "x" : "y";
|
|
1721
1730
|
const directionalDistance = Math.abs(center[dirProp] - currentCenter[dirProp]);
|
|
1722
1731
|
const offProp = ["left", "right"].includes(direction) ? "y" : "x";
|
|
1723
1732
|
const offAxisDeviation = Math.abs(center[offProp] - currentCenter[offProp]);
|
|
1724
|
-
const angle =
|
|
1725
|
-
const
|
|
1733
|
+
const angle = (import_Vec.Vec.Angle(currentCenter, center) * (180 / Math.PI) + 360) % 360;
|
|
1734
|
+
const rawAngleDeviation = Math.abs(angle - directionToAngle[direction]);
|
|
1735
|
+
const angleDeviation = Math.min(rawAngleDeviation, 360 - rawAngleDeviation);
|
|
1726
1736
|
return distance * 1 + // Base distance
|
|
1727
1737
|
offAxisDeviation * 2 + // Heavy penalty for off-axis deviation
|
|
1728
1738
|
(distance - directionalDistance) * 1.5 + // Penalty for diagonal distance
|
|
@@ -2060,7 +2070,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
2060
2070
|
* @public
|
|
2061
2071
|
*/
|
|
2062
2072
|
setHintingShapes(shapes) {
|
|
2063
|
-
const ids =
|
|
2073
|
+
const ids = toShapeIds(shapes);
|
|
2064
2074
|
this.run(
|
|
2065
2075
|
() => {
|
|
2066
2076
|
this._updateCurrentPageState({ hintingShapeIds: (0, import_utils.dedupe)(ids) });
|
|
@@ -2090,7 +2100,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
2090
2100
|
* @public
|
|
2091
2101
|
*/
|
|
2092
2102
|
setErasingShapes(shapes) {
|
|
2093
|
-
const ids =
|
|
2103
|
+
const ids = toShapeIds(shapes).slice();
|
|
2094
2104
|
ids.sort();
|
|
2095
2105
|
const erasingShapeIds = this.getErasingShapeIds();
|
|
2096
2106
|
this.run(
|
|
@@ -2497,14 +2507,16 @@ class Editor extends import_eventemitter3.default {
|
|
|
2497
2507
|
setCamera(point, opts) {
|
|
2498
2508
|
const { isLocked } = this._cameraOptions.__unsafe__getWithoutCapture();
|
|
2499
2509
|
if (isLocked && !opts?.force) return this;
|
|
2510
|
+
const _point = new import_Vec.Vec(point.x, point.y, point.z ?? this.getZoomLevel());
|
|
2511
|
+
if (!Number.isFinite(_point.x) || !Number.isFinite(_point.y) || !Number.isFinite(_point.z)) {
|
|
2512
|
+
throw Error(
|
|
2513
|
+
`Editor.setCamera: expected finite values, got (${_point.x}, ${_point.y}, ${_point.z}).`
|
|
2514
|
+
);
|
|
2515
|
+
}
|
|
2500
2516
|
this.stopCameraAnimation();
|
|
2501
2517
|
if (this.getInstanceState().followingUserId) {
|
|
2502
2518
|
this.stopFollowingUser();
|
|
2503
2519
|
}
|
|
2504
|
-
const _point = import_Vec.Vec.Cast(point);
|
|
2505
|
-
if (!Number.isFinite(_point.x)) _point.x = 0;
|
|
2506
|
-
if (!Number.isFinite(_point.y)) _point.y = 0;
|
|
2507
|
-
if (_point.z === void 0 || !Number.isFinite(_point.z)) point.z = this.getZoomLevel();
|
|
2508
2520
|
const camera = this.getConstrainedCamera(_point, opts);
|
|
2509
2521
|
if (opts?.animation) {
|
|
2510
2522
|
const { width, height } = this.getViewportScreenBounds();
|
|
@@ -2789,11 +2801,14 @@ class Editor extends import_eventemitter3.default {
|
|
|
2789
2801
|
_animateViewport(ms) {
|
|
2790
2802
|
if (!this._viewportAnimation) return;
|
|
2791
2803
|
this._viewportAnimation.elapsed += ms;
|
|
2792
|
-
const { elapsed, easing, duration, start, end } = this._viewportAnimation;
|
|
2804
|
+
const { elapsed, easing, duration, start, end, opts } = this._viewportAnimation;
|
|
2793
2805
|
if (elapsed > duration) {
|
|
2794
2806
|
this.off("tick", this._animateViewport);
|
|
2795
2807
|
this._viewportAnimation = null;
|
|
2796
|
-
this._setCamera(
|
|
2808
|
+
this._setCamera(
|
|
2809
|
+
new import_Vec.Vec(-end.x, -end.y, this.getViewportScreenBounds().width / end.width),
|
|
2810
|
+
opts
|
|
2811
|
+
);
|
|
2797
2812
|
return;
|
|
2798
2813
|
}
|
|
2799
2814
|
const remaining = duration - elapsed;
|
|
@@ -2831,7 +2846,8 @@ class Editor extends import_eventemitter3.default {
|
|
|
2831
2846
|
duration: duration / animationSpeed,
|
|
2832
2847
|
easing,
|
|
2833
2848
|
start: viewportPageBounds.clone(),
|
|
2834
|
-
end: targetViewportPage.clone()
|
|
2849
|
+
end: targetViewportPage.clone(),
|
|
2850
|
+
opts: rest
|
|
2835
2851
|
};
|
|
2836
2852
|
this.once("stop-camera-animation", () => {
|
|
2837
2853
|
this.off("tick", this._animateViewport);
|
|
@@ -2883,7 +2899,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
2883
2899
|
newCx += center.x / newCz - center.x / cz;
|
|
2884
2900
|
newCy += center.y / newCz - center.y / cz;
|
|
2885
2901
|
}
|
|
2886
|
-
currentSpeed *= 1 - friction;
|
|
2902
|
+
currentSpeed *= (1 - friction) ** (elapsed / import_constants.FRAME_MS_60HZ);
|
|
2887
2903
|
if (currentSpeed < speedThreshold) {
|
|
2888
2904
|
cancel();
|
|
2889
2905
|
} else {
|
|
@@ -2917,6 +2933,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
2917
2933
|
}
|
|
2918
2934
|
const isOnSamePage = presence.currentPageId === this.getCurrentPageId();
|
|
2919
2935
|
if (!isOnSamePage) {
|
|
2936
|
+
this.markHistoryStoppingPoint("change-page");
|
|
2920
2937
|
this.setCurrentPage(presence.currentPageId);
|
|
2921
2938
|
}
|
|
2922
2939
|
if (opts && opts.animation && !isOnSamePage) {
|
|
@@ -3748,7 +3765,9 @@ class Editor extends import_eventemitter3.default {
|
|
|
3748
3765
|
if (ids.length <= 0) return this;
|
|
3749
3766
|
this.run(
|
|
3750
3767
|
() => {
|
|
3751
|
-
this.store.props.assets.remove?.(ids)
|
|
3768
|
+
Promise.resolve(this.store.props.assets.remove?.(ids)).catch(
|
|
3769
|
+
(err) => console.error("Error while removing assets from the asset store:", err)
|
|
3770
|
+
);
|
|
3752
3771
|
this.store.remove(ids);
|
|
3753
3772
|
},
|
|
3754
3773
|
{ history: "ignore" }
|
|
@@ -4130,7 +4149,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
4130
4149
|
if (shapes.length === 0) {
|
|
4131
4150
|
return;
|
|
4132
4151
|
}
|
|
4133
|
-
const ids =
|
|
4152
|
+
const ids = toShapeIds(shapes);
|
|
4134
4153
|
const freshShapes = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
|
|
4135
4154
|
if (freshShapes.length === 1) {
|
|
4136
4155
|
const parentId = freshShapes[0].parentId;
|
|
@@ -4227,12 +4246,14 @@ class Editor extends import_eventemitter3.default {
|
|
|
4227
4246
|
*/
|
|
4228
4247
|
getSelectedShapeAtPoint(point) {
|
|
4229
4248
|
const selectedShapeIds = this.getSelectedShapeIds();
|
|
4230
|
-
|
|
4249
|
+
if (selectedShapeIds.length === 0) return void 0;
|
|
4250
|
+
const selectedShapeIdSet = new Set(selectedShapeIds);
|
|
4251
|
+
const margin = this.getHitTestMargin();
|
|
4231
4252
|
const sortedShapes = this.getCurrentPageShapesSorted();
|
|
4232
4253
|
for (let i = sortedShapes.length - 1; i >= 0; i--) {
|
|
4233
4254
|
const shape = sortedShapes[i];
|
|
4234
4255
|
if (shape.type === "group") continue;
|
|
4235
|
-
if (!
|
|
4256
|
+
if (!selectedShapeIdSet.has(shape.id)) continue;
|
|
4236
4257
|
if (this.getShapeGeometry(shape).hitTestPoint(
|
|
4237
4258
|
this.getPointInShapeSpace(shape, point),
|
|
4238
4259
|
margin,
|
|
@@ -4330,7 +4351,6 @@ class Editor extends import_eventemitter3.default {
|
|
|
4330
4351
|
}
|
|
4331
4352
|
return inMarginClosestToEdgeHit || shape;
|
|
4332
4353
|
} else {
|
|
4333
|
-
if (this.getShapePageBounds(shape).contains(viewportPageBounds)) continue;
|
|
4334
4354
|
if (hitInside ? (
|
|
4335
4355
|
// On hitInside, the distance will be negative for hits inside
|
|
4336
4356
|
// If the distance is positive, check against the outer margin
|
|
@@ -4347,6 +4367,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
4347
4367
|
inMarginClosestToEdgeHit = shape;
|
|
4348
4368
|
}
|
|
4349
4369
|
} else if (!inMarginClosestToEdgeHit) {
|
|
4370
|
+
if (this.getShapePageBounds(shape).contains(viewportPageBounds)) continue;
|
|
4350
4371
|
const { area } = geometry;
|
|
4351
4372
|
if (area < inHollowSmallestArea) {
|
|
4352
4373
|
inHollowSmallestArea = area;
|
|
@@ -4357,6 +4378,9 @@ class Editor extends import_eventemitter3.default {
|
|
|
4357
4378
|
}
|
|
4358
4379
|
} else {
|
|
4359
4380
|
if (distance < this.getHitTestMargin()) {
|
|
4381
|
+
if (inMarginClosestToEdgeHit && inMarginClosestToEdgeDistance <= distance) {
|
|
4382
|
+
return inMarginClosestToEdgeHit;
|
|
4383
|
+
}
|
|
4360
4384
|
return shape;
|
|
4361
4385
|
}
|
|
4362
4386
|
}
|
|
@@ -4633,7 +4657,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
4633
4657
|
* @public
|
|
4634
4658
|
*/
|
|
4635
4659
|
reparentShapes(shapes, parentId, insertIndex) {
|
|
4636
|
-
const ids =
|
|
4660
|
+
const ids = toShapeIds(shapes);
|
|
4637
4661
|
if (ids.length === 0) return this;
|
|
4638
4662
|
const changes = [];
|
|
4639
4663
|
const parentTransform = (0, import_tlschema.isPageId)(parentId) ? import_Mat.Mat.Identity() : this.getShapePageTransform(parentId);
|
|
@@ -4862,6 +4886,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
4862
4886
|
* binding, but the `type`, `toId`, and `fromId` must all be provided.
|
|
4863
4887
|
*/
|
|
4864
4888
|
createBindings(partials) {
|
|
4889
|
+
if (this.getIsReadonly()) return this;
|
|
4865
4890
|
const bindings = [];
|
|
4866
4891
|
for (const partial of partials) {
|
|
4867
4892
|
const fromShape = this.getShape(partial.fromId);
|
|
@@ -4896,6 +4921,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
4896
4921
|
* binding is skipped. The changes from the partial are merged into the existing record.
|
|
4897
4922
|
*/
|
|
4898
4923
|
updateBindings(partials) {
|
|
4924
|
+
if (this.getIsReadonly()) return this;
|
|
4899
4925
|
const updated = [];
|
|
4900
4926
|
for (const partial of partials) {
|
|
4901
4927
|
if (!partial) continue;
|
|
@@ -4924,6 +4950,16 @@ class Editor extends import_eventemitter3.default {
|
|
|
4924
4950
|
* Delete several bindings by their IDs. If a binding ID doesn't exist, it's ignored.
|
|
4925
4951
|
*/
|
|
4926
4952
|
deleteBindings(bindings, { isolateShapes = false } = {}) {
|
|
4953
|
+
if (this.getIsReadonly()) return this;
|
|
4954
|
+
return this._deleteBindings(bindings, { isolateShapes });
|
|
4955
|
+
}
|
|
4956
|
+
/**
|
|
4957
|
+
* Unguarded so that withIsolatedShapes can transiently isolate shapes for copy and export in
|
|
4958
|
+
* readonly mode; the public deleteBindings is what readonly blocks.
|
|
4959
|
+
*
|
|
4960
|
+
* @internal
|
|
4961
|
+
*/
|
|
4962
|
+
_deleteBindings(bindings, { isolateShapes = false } = {}) {
|
|
4927
4963
|
const ids = bindings.map((binding) => typeof binding === "string" ? binding : binding.id);
|
|
4928
4964
|
if (isolateShapes) {
|
|
4929
4965
|
this.store.atomic(() => {
|
|
@@ -4982,7 +5018,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
4982
5018
|
* @param opts - The options for the rotation.
|
|
4983
5019
|
*/
|
|
4984
5020
|
rotateShapesBy(shapes, delta, opts) {
|
|
4985
|
-
const ids =
|
|
5021
|
+
const ids = toShapeIds(shapes);
|
|
4986
5022
|
if (ids.length <= 0) return this;
|
|
4987
5023
|
const snapshot = (0, import_rotation.getRotationSnapshot)({ editor: this, ids });
|
|
4988
5024
|
if (!snapshot) return this;
|
|
@@ -5019,6 +5055,14 @@ class Editor extends import_eventemitter3.default {
|
|
|
5019
5055
|
}
|
|
5020
5056
|
return workingShape;
|
|
5021
5057
|
}
|
|
5058
|
+
// Counter-rotates the page-space delta into the parent's space; without that a child of a rotated
|
|
5059
|
+
// frame or group would move along its parent's axes instead of the page's.
|
|
5060
|
+
// todo: a shape laid out together with its own parent moves twice, once with the parent and once
|
|
5061
|
+
// on its own; the layout commands should skip shapes whose ancestors are also being laid out
|
|
5062
|
+
getChangesToTranslateShapeByPageDelta(shape, pageDelta) {
|
|
5063
|
+
const localDelta = import_Vec.Vec.From(pageDelta).rot(-this.getShapeParentTransform(shape).rotation());
|
|
5064
|
+
return this.getChangesToTranslateShape(shape, localDelta.add(shape));
|
|
5065
|
+
}
|
|
5022
5066
|
/**
|
|
5023
5067
|
* Move shapes by a delta.
|
|
5024
5068
|
*
|
|
@@ -5031,14 +5075,12 @@ class Editor extends import_eventemitter3.default {
|
|
|
5031
5075
|
* @param offset - The offset to apply to the shapes.
|
|
5032
5076
|
*/
|
|
5033
5077
|
nudgeShapes(shapes, offset) {
|
|
5034
|
-
const ids =
|
|
5078
|
+
const ids = toShapeIds(shapes);
|
|
5035
5079
|
if (ids.length <= 0) return this;
|
|
5036
5080
|
const changes = [];
|
|
5037
5081
|
for (const id of ids) {
|
|
5038
5082
|
const shape = this.getShape(id);
|
|
5039
|
-
|
|
5040
|
-
localDelta.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5041
|
-
changes.push(this.getChangesToTranslateShape(shape, localDelta.add(shape)));
|
|
5083
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, offset));
|
|
5042
5084
|
}
|
|
5043
5085
|
this.updateShapes(changes);
|
|
5044
5086
|
return this;
|
|
@@ -5059,7 +5101,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5059
5101
|
*/
|
|
5060
5102
|
duplicateShapes(shapes, offset) {
|
|
5061
5103
|
this.run(() => {
|
|
5062
|
-
const _ids =
|
|
5104
|
+
const _ids = toShapeIds(shapes);
|
|
5063
5105
|
const ids = this._shouldIgnoreShapeLock ? _ids : this._getUnlockedShapeIds(_ids);
|
|
5064
5106
|
if (ids.length <= 0) return this;
|
|
5065
5107
|
const initialIds = new Set(ids);
|
|
@@ -5168,7 +5210,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5168
5210
|
* @public
|
|
5169
5211
|
*/
|
|
5170
5212
|
moveShapesToPage(shapes, pageId) {
|
|
5171
|
-
const ids =
|
|
5213
|
+
const ids = toShapeIds(shapes);
|
|
5172
5214
|
if (ids.length === 0) return this;
|
|
5173
5215
|
if (this.getIsReadonly()) return this;
|
|
5174
5216
|
const currentPageId = this.getCurrentPageId();
|
|
@@ -5204,7 +5246,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5204
5246
|
* @public
|
|
5205
5247
|
*/
|
|
5206
5248
|
toggleLock(shapes) {
|
|
5207
|
-
const ids =
|
|
5249
|
+
const ids = toShapeIds(shapes);
|
|
5208
5250
|
if (this.getIsReadonly() || ids.length === 0) return this;
|
|
5209
5251
|
let allLocked = true;
|
|
5210
5252
|
const shapesToToggle = [];
|
|
@@ -5243,7 +5285,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5243
5285
|
* @public
|
|
5244
5286
|
*/
|
|
5245
5287
|
sendToBack(shapes) {
|
|
5246
|
-
const ids =
|
|
5288
|
+
const ids = toShapeIds(shapes);
|
|
5247
5289
|
const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "toBack", ids, {
|
|
5248
5290
|
considerAllShapes: true
|
|
5249
5291
|
});
|
|
@@ -5273,7 +5315,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5273
5315
|
* @public
|
|
5274
5316
|
*/
|
|
5275
5317
|
sendBackward(shapes, opts = {}) {
|
|
5276
|
-
const ids =
|
|
5318
|
+
const ids = toShapeIds(shapes);
|
|
5277
5319
|
const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "backward", ids, opts);
|
|
5278
5320
|
if (changes) this.updateShapes(changes);
|
|
5279
5321
|
return this;
|
|
@@ -5301,7 +5343,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5301
5343
|
* @public
|
|
5302
5344
|
*/
|
|
5303
5345
|
bringForward(shapes, opts = {}) {
|
|
5304
|
-
const ids =
|
|
5346
|
+
const ids = toShapeIds(shapes);
|
|
5305
5347
|
const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "forward", ids, opts);
|
|
5306
5348
|
if (changes) this.updateShapes(changes);
|
|
5307
5349
|
return this;
|
|
@@ -5320,7 +5362,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5320
5362
|
* @public
|
|
5321
5363
|
*/
|
|
5322
5364
|
bringToFront(shapes) {
|
|
5323
|
-
const ids =
|
|
5365
|
+
const ids = toShapeIds(shapes);
|
|
5324
5366
|
const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "toFront", ids);
|
|
5325
5367
|
if (changes) this.updateShapes(changes);
|
|
5326
5368
|
return this;
|
|
@@ -5332,7 +5374,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5332
5374
|
* @internal
|
|
5333
5375
|
*/
|
|
5334
5376
|
getShapeClusters(shapes, type, opts) {
|
|
5335
|
-
const ids =
|
|
5377
|
+
const ids = toShapeIds(shapes);
|
|
5336
5378
|
let freshShapes = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
|
|
5337
5379
|
if (opts?.filterAxisAligned) {
|
|
5338
5380
|
freshShapes = freshShapes.filter((s) => {
|
|
@@ -5357,7 +5399,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5357
5399
|
const shapesMovingTogether = [shape];
|
|
5358
5400
|
const boundsOfShapesMovingTogether = [shapePageBounds];
|
|
5359
5401
|
this.collectShapesViaArrowBindings({
|
|
5360
|
-
bindings: this.
|
|
5402
|
+
bindings: this.getBindingsInvolvingShape(shape.id, "arrow"),
|
|
5361
5403
|
initialShapes: freshShapes,
|
|
5362
5404
|
resultShapes: shapesMovingTogether,
|
|
5363
5405
|
resultBounds: boundsOfShapesMovingTogether,
|
|
@@ -5413,7 +5455,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5413
5455
|
*/
|
|
5414
5456
|
flipShapes(shapes, operation) {
|
|
5415
5457
|
if (this.getIsReadonly()) return this;
|
|
5416
|
-
const ids =
|
|
5458
|
+
const ids = toShapeIds(shapes);
|
|
5417
5459
|
const shapesToFlipFirstPass = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
|
|
5418
5460
|
for (const shape of shapesToFlipFirstPass) {
|
|
5419
5461
|
if (this.isShapeOfType(shape, "group")) {
|
|
@@ -5487,21 +5529,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5487
5529
|
const { clusters: shapeClustersToStack } = this.getShapeClusters(shapes, "stack");
|
|
5488
5530
|
const len = shapeClustersToStack.length;
|
|
5489
5531
|
if (_gap === 0 && len < 3 || len < 2) return this;
|
|
5490
|
-
|
|
5491
|
-
let min;
|
|
5492
|
-
let max;
|
|
5493
|
-
let dim;
|
|
5494
|
-
if (operation === "horizontal") {
|
|
5495
|
-
val = "x";
|
|
5496
|
-
min = "minX";
|
|
5497
|
-
max = "maxX";
|
|
5498
|
-
dim = "width";
|
|
5499
|
-
} else {
|
|
5500
|
-
val = "y";
|
|
5501
|
-
min = "minY";
|
|
5502
|
-
max = "maxY";
|
|
5503
|
-
dim = "height";
|
|
5504
|
-
}
|
|
5532
|
+
const { val, min, max, dim } = AXIS[operation];
|
|
5505
5533
|
let shapeGap = 0;
|
|
5506
5534
|
shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
|
|
5507
5535
|
if (_gap === 0) {
|
|
@@ -5540,13 +5568,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5540
5568
|
const delta = new import_Vec.Vec();
|
|
5541
5569
|
delta[val] = v + shapeGap - pageBounds[val];
|
|
5542
5570
|
for (const shape of shapes2) {
|
|
5543
|
-
|
|
5544
|
-
const parent = this.getShapeParent(shape);
|
|
5545
|
-
if (parent) {
|
|
5546
|
-
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5547
|
-
}
|
|
5548
|
-
shapeDelta.add(shape);
|
|
5549
|
-
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
5571
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
|
|
5550
5572
|
}
|
|
5551
5573
|
v += pageBounds[dim] + shapeGap;
|
|
5552
5574
|
}
|
|
@@ -5626,13 +5648,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5626
5648
|
for (const { shapes: shapes2, pageBounds, nextPageBounds } of shapeClustersToPack) {
|
|
5627
5649
|
const delta = import_Vec.Vec.Sub(nextPageBounds.point, pageBounds.point).add(centerDelta);
|
|
5628
5650
|
for (const shape of shapes2) {
|
|
5629
|
-
|
|
5630
|
-
const parent = this.getShapeParent(shape);
|
|
5631
|
-
if (parent) {
|
|
5632
|
-
shapeDelta.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5633
|
-
}
|
|
5634
|
-
shapeDelta.add(shape);
|
|
5635
|
-
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
5651
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
|
|
5636
5652
|
}
|
|
5637
5653
|
}
|
|
5638
5654
|
if (changes.length) {
|
|
@@ -5692,13 +5708,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5692
5708
|
}
|
|
5693
5709
|
}
|
|
5694
5710
|
for (const shape of shapes2) {
|
|
5695
|
-
|
|
5696
|
-
const parent = this.getShapeParent(shape);
|
|
5697
|
-
if (parent) {
|
|
5698
|
-
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5699
|
-
}
|
|
5700
|
-
shapeDelta.add(shape);
|
|
5701
|
-
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
5711
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
|
|
5702
5712
|
}
|
|
5703
5713
|
});
|
|
5704
5714
|
this.updateShapes(changes);
|
|
@@ -5722,27 +5732,13 @@ class Editor extends import_eventemitter3.default {
|
|
|
5722
5732
|
if (this.getIsReadonly()) return this;
|
|
5723
5733
|
const { clusters: shapeClustersToDistribute } = this.getShapeClusters(shapes, "distribute");
|
|
5724
5734
|
if (shapeClustersToDistribute.length < 3) return this;
|
|
5725
|
-
|
|
5726
|
-
let min;
|
|
5727
|
-
let max;
|
|
5728
|
-
let dim;
|
|
5729
|
-
if (operation === "horizontal") {
|
|
5730
|
-
val = "x";
|
|
5731
|
-
min = "minX";
|
|
5732
|
-
max = "maxX";
|
|
5733
|
-
dim = "width";
|
|
5734
|
-
} else {
|
|
5735
|
-
val = "y";
|
|
5736
|
-
min = "minY";
|
|
5737
|
-
max = "maxY";
|
|
5738
|
-
dim = "height";
|
|
5739
|
-
}
|
|
5735
|
+
const { val, min, max, dim } = AXIS[operation];
|
|
5740
5736
|
const changes = [];
|
|
5741
5737
|
const first = shapeClustersToDistribute.sort((a, b) => a.pageBounds[min] - b.pageBounds[min])[0];
|
|
5742
5738
|
const last2 = shapeClustersToDistribute.sort((a, b) => b.pageBounds[max] - a.pageBounds[max])[0];
|
|
5743
5739
|
if (first === last2) {
|
|
5744
5740
|
const excludedShapeIds = new Set(first.shapes.map((s) => s.id));
|
|
5745
|
-
const ids =
|
|
5741
|
+
const ids = toShapeIds(shapes);
|
|
5746
5742
|
return this.distributeShapes(
|
|
5747
5743
|
ids.filter((id) => !excludedShapeIds.has(id)),
|
|
5748
5744
|
operation
|
|
@@ -5766,13 +5762,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5766
5762
|
delta[val] = last2.pageBounds[max] - pageBounds[max] - 1;
|
|
5767
5763
|
}
|
|
5768
5764
|
for (const shape of shapes2) {
|
|
5769
|
-
|
|
5770
|
-
const parent = this.getShapeParent(shape);
|
|
5771
|
-
if (parent) {
|
|
5772
|
-
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5773
|
-
}
|
|
5774
|
-
shapeDelta.add(shape);
|
|
5775
|
-
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
5765
|
+
changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
|
|
5776
5766
|
}
|
|
5777
5767
|
v += pageBounds[dim] + gap;
|
|
5778
5768
|
}
|
|
@@ -5802,32 +5792,17 @@ class Editor extends import_eventemitter3.default {
|
|
|
5802
5792
|
);
|
|
5803
5793
|
if (shapeClustersToStretch.length < 2) return this;
|
|
5804
5794
|
const commonBounds = import_Box.Box.Common(allBounds);
|
|
5805
|
-
|
|
5806
|
-
let min;
|
|
5807
|
-
let dim;
|
|
5808
|
-
if (operation === "horizontal") {
|
|
5809
|
-
val = "x";
|
|
5810
|
-
min = "minX";
|
|
5811
|
-
dim = "width";
|
|
5812
|
-
} else {
|
|
5813
|
-
val = "y";
|
|
5814
|
-
min = "minY";
|
|
5815
|
-
dim = "height";
|
|
5816
|
-
}
|
|
5795
|
+
const { val, min, dim } = AXIS[operation];
|
|
5817
5796
|
this.run(() => {
|
|
5818
5797
|
shapeClustersToStretch.forEach(({ shapes: shapes2, pageBounds }) => {
|
|
5819
|
-
const
|
|
5820
|
-
|
|
5798
|
+
const pageOffset = new import_Vec.Vec();
|
|
5799
|
+
pageOffset[val] = commonBounds[min] - pageBounds[min];
|
|
5821
5800
|
const scaleOrigin = pageBounds.center.clone();
|
|
5822
5801
|
scaleOrigin[val] = commonBounds[min];
|
|
5823
5802
|
const scale = new import_Vec.Vec(1, 1);
|
|
5824
5803
|
scale[val] = commonBounds[dim] / pageBounds[dim];
|
|
5825
5804
|
for (const shape of shapes2) {
|
|
5826
|
-
|
|
5827
|
-
shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5828
|
-
shapeLocalOffset.add(shape);
|
|
5829
|
-
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5830
|
-
this.updateShape(changes);
|
|
5805
|
+
this.updateShape(this.getChangesToTranslateShapeByPageDelta(shape, pageOffset));
|
|
5831
5806
|
this.resizeShape(shape.id, scale, {
|
|
5832
5807
|
initialBounds: this.getShapeGeometry(shape).bounds,
|
|
5833
5808
|
scaleOrigin,
|
|
@@ -5870,7 +5845,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5870
5845
|
const scaleY = targetBounds.height / commonBounds.height;
|
|
5871
5846
|
const scale = new import_Vec.Vec(scaleX, scaleY);
|
|
5872
5847
|
shapeClusters.forEach(({ shapes: shapes2, pageBounds }) => {
|
|
5873
|
-
const
|
|
5848
|
+
const pageOffset = new import_Vec.Vec(
|
|
5874
5849
|
targetBounds.minX - commonBounds.minX + (pageBounds.minX - commonBounds.minX) * (scaleX - 1),
|
|
5875
5850
|
targetBounds.minY - commonBounds.minY + (pageBounds.minY - commonBounds.minY) * (scaleY - 1)
|
|
5876
5851
|
);
|
|
@@ -5879,11 +5854,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
5879
5854
|
targetBounds.minY + (pageBounds.minY - commonBounds.minY) * scaleY
|
|
5880
5855
|
);
|
|
5881
5856
|
for (const shape of shapes2) {
|
|
5882
|
-
|
|
5883
|
-
shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5884
|
-
shapeLocalOffset.add(shape);
|
|
5885
|
-
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5886
|
-
this.updateShape(changes);
|
|
5857
|
+
this.updateShape(this.getChangesToTranslateShapeByPageDelta(shape, pageOffset));
|
|
5887
5858
|
this.resizeShape(shape.id, scale, {
|
|
5888
5859
|
initialBounds: this.getShapeGeometry(shape).bounds,
|
|
5889
5860
|
scaleOrigin,
|
|
@@ -6302,12 +6273,17 @@ class Editor extends import_eventemitter3.default {
|
|
|
6302
6273
|
let remaining = duration;
|
|
6303
6274
|
let t;
|
|
6304
6275
|
const animations = [];
|
|
6276
|
+
const ignoreShapeLock = this._shouldIgnoreShapeLock;
|
|
6305
6277
|
let partial, result;
|
|
6306
6278
|
for (let i = 0, n = partials.length; i < n; i++) {
|
|
6307
6279
|
partial = partials[i];
|
|
6308
6280
|
if (!partial) continue;
|
|
6309
6281
|
const shape = this.getShape(partial.id);
|
|
6310
6282
|
if (!shape) continue;
|
|
6283
|
+
const unlocks = shape.isLocked && Object.hasOwn(partial, "isLocked") && !partial.isLocked;
|
|
6284
|
+
if (!ignoreShapeLock && !unlocks && this.isShapeOrAncestorLocked(shape)) {
|
|
6285
|
+
continue;
|
|
6286
|
+
}
|
|
6311
6287
|
result = {
|
|
6312
6288
|
start: (0, import_utils.structuredClone)(shape),
|
|
6313
6289
|
end: applyPartialToRecordWithProps((0, import_utils.structuredClone)(shape), partial)
|
|
@@ -6323,7 +6299,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
6323
6299
|
(p) => p && animatingShapes2.get(p.id) === animationId
|
|
6324
6300
|
);
|
|
6325
6301
|
if (partialsToUpdate.length) {
|
|
6326
|
-
this.updateShapes(partialsToUpdate);
|
|
6302
|
+
this.run(() => this.updateShapes(partialsToUpdate), { ignoreShapeLock });
|
|
6327
6303
|
}
|
|
6328
6304
|
this.off("tick", handleTick);
|
|
6329
6305
|
return;
|
|
@@ -6356,13 +6332,13 @@ class Editor extends import_eventemitter3.default {
|
|
|
6356
6332
|
throw Error("Editor.groupShapes: must provide an array of shapes or shape ids");
|
|
6357
6333
|
}
|
|
6358
6334
|
if (this.getIsReadonly()) return this;
|
|
6359
|
-
const ids =
|
|
6360
|
-
if (ids.length <= 1) return this;
|
|
6335
|
+
const ids = toShapeIds(shapes);
|
|
6361
6336
|
const shapesToGroup = (0, import_utils.compact)(
|
|
6362
6337
|
(this._shouldIgnoreShapeLock ? ids : this._getUnlockedShapeIds(ids)).map(
|
|
6363
6338
|
(id) => this.getShape(id)
|
|
6364
6339
|
)
|
|
6365
6340
|
);
|
|
6341
|
+
if (shapesToGroup.length <= 1) return this;
|
|
6366
6342
|
const sortedShapeIds = shapesToGroup.sort(import_utils.sortByIndex).map((s) => s.id);
|
|
6367
6343
|
const childBounds = (0, import_utils.compact)(shapesToGroup.map((shape) => this.getShapePageBounds(shape)));
|
|
6368
6344
|
const pageBounds = import_Box.Box.Common(childBounds);
|
|
@@ -6371,8 +6347,11 @@ class Editor extends import_eventemitter3.default {
|
|
|
6371
6347
|
}
|
|
6372
6348
|
const { x, y } = pageBounds.point;
|
|
6373
6349
|
const parentId = this.findCommonAncestor(shapesToGroup) ?? this.getCurrentPageId();
|
|
6374
|
-
if (this.
|
|
6375
|
-
|
|
6350
|
+
if (!this.canCreateShapes([groupId])) {
|
|
6351
|
+
alertMaxShapes(this);
|
|
6352
|
+
return this;
|
|
6353
|
+
}
|
|
6354
|
+
if (this.isIn("select") && !this.isIn("select.idle")) {
|
|
6376
6355
|
this.cancel();
|
|
6377
6356
|
}
|
|
6378
6357
|
const shapesWithRootParent = shapesToGroup.filter((shape) => shape.parentId === parentId).sort(import_utils.sortByIndex);
|
|
@@ -6400,15 +6379,14 @@ class Editor extends import_eventemitter3.default {
|
|
|
6400
6379
|
ungroupShapes(shapes, opts = {}) {
|
|
6401
6380
|
if (this.getIsReadonly()) return this;
|
|
6402
6381
|
const { select = true } = opts;
|
|
6403
|
-
const ids =
|
|
6382
|
+
const ids = toShapeIds(shapes);
|
|
6404
6383
|
const shapesToUngroup = (0, import_utils.compact)(
|
|
6405
6384
|
(this._shouldIgnoreShapeLock ? ids : this._getUnlockedShapeIds(ids)).map(
|
|
6406
6385
|
(id) => this.getShape(id)
|
|
6407
6386
|
)
|
|
6408
6387
|
);
|
|
6409
6388
|
if (shapesToUngroup.length === 0) return this;
|
|
6410
|
-
if (this.
|
|
6411
|
-
if (!this.isIn("select.idle")) {
|
|
6389
|
+
if (this.isIn("select") && !this.isIn("select.idle")) {
|
|
6412
6390
|
this.cancel();
|
|
6413
6391
|
}
|
|
6414
6392
|
const idsToSelect = /* @__PURE__ */ new Set();
|
|
@@ -6422,16 +6400,16 @@ class Editor extends import_eventemitter3.default {
|
|
|
6422
6400
|
});
|
|
6423
6401
|
if (groups.length === 0) return this;
|
|
6424
6402
|
this.run(() => {
|
|
6425
|
-
let group;
|
|
6426
6403
|
for (let i = 0, n = groups.length; i < n; i++) {
|
|
6427
|
-
group = groups[i];
|
|
6404
|
+
const group = this.getShape(groups[i].id);
|
|
6405
|
+
if (!group) continue;
|
|
6428
6406
|
const childIds = this.getSortedChildIdsForParent(group.id);
|
|
6429
6407
|
for (let j = 0, n2 = childIds.length; j < n2; j++) {
|
|
6430
6408
|
idsToSelect.add(childIds[j]);
|
|
6431
6409
|
}
|
|
6432
6410
|
this.reparentShapes(childIds, group.parentId, group.index);
|
|
6433
6411
|
}
|
|
6434
|
-
this.deleteShapes(groups.map((
|
|
6412
|
+
this.deleteShapes(groups.map((group) => group.id));
|
|
6435
6413
|
if (select) {
|
|
6436
6414
|
this.select(...idsToSelect);
|
|
6437
6415
|
}
|
|
@@ -6512,14 +6490,14 @@ class Editor extends import_eventemitter3.default {
|
|
|
6512
6490
|
}
|
|
6513
6491
|
/** @internal */
|
|
6514
6492
|
_getUnlockedShapeIds(ids) {
|
|
6515
|
-
return ids.filter((id) => !this.
|
|
6493
|
+
return ids.filter((id) => !this.isShapeOrAncestorLocked(id));
|
|
6516
6494
|
}
|
|
6517
6495
|
deleteShapes(_ids) {
|
|
6518
6496
|
if (this.getIsReadonly()) return this;
|
|
6519
6497
|
if (!Array.isArray(_ids)) {
|
|
6520
6498
|
throw Error("Editor.deleteShapes: must provide an array of shapes or shapeIds");
|
|
6521
6499
|
}
|
|
6522
|
-
const shapeIds =
|
|
6500
|
+
const shapeIds = toShapeIds(_ids);
|
|
6523
6501
|
const shapeIdsToDelete = this._shouldIgnoreShapeLock ? shapeIds : this._getUnlockedShapeIds(shapeIds);
|
|
6524
6502
|
if (shapeIdsToDelete.length === 0) return this;
|
|
6525
6503
|
const allShapeIdsToDelete = new Set(shapeIdsToDelete);
|
|
@@ -6864,7 +6842,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
6864
6842
|
* @public
|
|
6865
6843
|
*/
|
|
6866
6844
|
getContentFromCurrentPage(shapes) {
|
|
6867
|
-
const ids =
|
|
6845
|
+
const ids = toShapeIds(shapes);
|
|
6868
6846
|
if (!ids) return;
|
|
6869
6847
|
if (ids.length === 0) return;
|
|
6870
6848
|
const shapeIds = this.getShapeAndDescendantIds(ids);
|
|
@@ -6932,21 +6910,29 @@ class Editor extends import_eventemitter3.default {
|
|
|
6932
6910
|
await Promise.allSettled(
|
|
6933
6911
|
content.assets.map(async (asset) => {
|
|
6934
6912
|
if ((asset.type === "image" || asset.type === "video") && !asset.props.src?.startsWith("data:image") && !asset.props.src?.startsWith("data:video") && !asset.props.src?.startsWith("http")) {
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6913
|
+
try {
|
|
6914
|
+
const objectUrl = await this.store.props.assets.resolve(asset, {
|
|
6915
|
+
screenScale: 1,
|
|
6916
|
+
steppedScreenScale: 1,
|
|
6917
|
+
dpr: 1,
|
|
6918
|
+
networkEffectiveType: null,
|
|
6919
|
+
shouldResolveToOriginal: true
|
|
6920
|
+
});
|
|
6921
|
+
if (objectUrl) {
|
|
6922
|
+
const response = await (0, import_utils.fetch)(objectUrl);
|
|
6923
|
+
if (response.ok) {
|
|
6924
|
+
const assetWithDataUrl = (0, import_utils.structuredClone)(asset);
|
|
6925
|
+
assetWithDataUrl.props.src = await import_utils.FileHelpers.blobToDataUrl(await response.blob());
|
|
6926
|
+
assets.push(assetWithDataUrl);
|
|
6927
|
+
return;
|
|
6928
|
+
}
|
|
6929
|
+
console.warn(`Could not inline asset ${asset.id}: fetch returned ${response.status}`);
|
|
6930
|
+
}
|
|
6931
|
+
} catch (err) {
|
|
6932
|
+
console.warn(`Could not inline asset ${asset.id}`, err);
|
|
6933
|
+
}
|
|
6949
6934
|
}
|
|
6935
|
+
assets.push(asset);
|
|
6950
6936
|
})
|
|
6951
6937
|
);
|
|
6952
6938
|
content.assets = assets;
|
|
@@ -7240,7 +7226,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
7240
7226
|
* @public
|
|
7241
7227
|
*/
|
|
7242
7228
|
async getSvgElement(shapes, opts = {}) {
|
|
7243
|
-
const ids = shapes.length === 0 ? this.getCurrentPageShapeIdsSorted() :
|
|
7229
|
+
const ids = shapes.length === 0 ? this.getCurrentPageShapeIdsSorted() : toShapeIds(shapes);
|
|
7244
7230
|
if (ids.length === 0) return void 0;
|
|
7245
7231
|
await this.fonts.loadRequiredFontsForCurrentPage(this.options.maxFontsToLoadBeforeRender);
|
|
7246
7232
|
return (0, import_exportToSvg.exportToSvg)(this, ids, opts);
|
|
@@ -8158,6 +8144,7 @@ class Editor extends import_eventemitter3.default {
|
|
|
8158
8144
|
inputs.buttons.add(info.button);
|
|
8159
8145
|
inputs.setIsPointing(true);
|
|
8160
8146
|
inputs.setIsDragging(false);
|
|
8147
|
+
this.stopCameraAnimation();
|
|
8161
8148
|
if (!isPenMode && info.isPenDirect) {
|
|
8162
8149
|
this.updateInstanceState({ isPenMode: true });
|
|
8163
8150
|
this.interrupt();
|
|
@@ -8294,8 +8281,8 @@ class Editor extends import_eventemitter3.default {
|
|
|
8294
8281
|
break;
|
|
8295
8282
|
}
|
|
8296
8283
|
case "keyboard": {
|
|
8297
|
-
if (info.
|
|
8298
|
-
if (info.
|
|
8284
|
+
if (info.code === "ShiftRight") info.code = "ShiftLeft";
|
|
8285
|
+
if (info.code === "AltRight") info.code = "AltLeft";
|
|
8299
8286
|
if (info.code === "ControlRight") info.code = "ControlLeft";
|
|
8300
8287
|
if (info.code === "MetaRight") info.code = "MetaLeft";
|
|
8301
8288
|
switch (info.name) {
|
|
@@ -8665,6 +8652,9 @@ function pushShapeWithDescendants(editor, id, result) {
|
|
|
8665
8652
|
pushShapeWithDescendants(editor, childIds[i], result);
|
|
8666
8653
|
}
|
|
8667
8654
|
}
|
|
8655
|
+
function toShapeIds(shapes) {
|
|
8656
|
+
return typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
|
|
8657
|
+
}
|
|
8668
8658
|
function withIsolatedShapes(editor, shapeIds, callback) {
|
|
8669
8659
|
let result;
|
|
8670
8660
|
editor.run(
|
|
@@ -8687,7 +8677,7 @@ function withIsolatedShapes(editor, shapeIds, callback) {
|
|
|
8687
8677
|
}
|
|
8688
8678
|
}
|
|
8689
8679
|
}
|
|
8690
|
-
editor.
|
|
8680
|
+
editor._deleteBindings([...bindingsToRemove], { isolateShapes: true });
|
|
8691
8681
|
try {
|
|
8692
8682
|
result = import_utils.Result.ok(callback(bindingsWithBoth));
|
|
8693
8683
|
} catch (error) {
|