@tldraw/editor 5.4.0-canary.042da660fa66 → 5.4.0-canary.059d049864ed
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 +31 -1
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/components/MenuClickCapture.js +6 -8
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js +1 -3
- package/dist-cjs/lib/components/default-components/CanvasOverlays.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +1 -1
- package/dist-cjs/lib/config/TLUserPreferences.js +6 -2
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/config/createTLStore.js +1 -1
- package/dist-cjs/lib/config/createTLStore.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +139 -268
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +8 -8
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +2 -1
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +79 -6
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +0 -2
- package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +1 -0
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/OverlayManager.js +3 -7
- package/dist-cjs/lib/editor/overlays/OverlayManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +0 -1
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +3 -1
- package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js +1 -0
- package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +1 -1
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js +3 -2
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/globals/menus.js +9 -4
- package/dist-cjs/lib/globals/menus.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -0
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +9 -7
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useLocalStore.js +10 -6
- package/dist-cjs/lib/hooks/useLocalStore.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +1 -0
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePeerIds.js +2 -1
- package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +2 -1
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +4 -3
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +2 -1
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/rotation.js +1 -9
- package/dist-cjs/lib/utils/rotation.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 +31 -1
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/components/MenuClickCapture.mjs +6 -8
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs +1 -3
- package/dist-esm/lib/components/default-components/CanvasOverlays.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +1 -1
- package/dist-esm/lib/config/TLUserPreferences.mjs +6 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/config/createTLStore.mjs +1 -1
- package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +147 -269
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +9 -9
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +2 -1
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +81 -8
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +0 -2
- package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs +3 -7
- package/dist-esm/lib/editor/overlays/OverlayManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +0 -1
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +3 -1
- package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs +1 -0
- package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +1 -1
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs +3 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/globals/menus.mjs +9 -4
- package/dist-esm/lib/globals/menus.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -0
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +9 -7
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useLocalStore.mjs +11 -7
- package/dist-esm/lib/hooks/useLocalStore.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +1 -0
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs +2 -1
- package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +2 -1
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +4 -3
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +2 -1
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/rotation.mjs +1 -9
- package/dist-esm/lib/utils/rotation.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/lib/components/MenuClickCapture.tsx +19 -18
- package/src/lib/components/default-components/CanvasOverlays.tsx +1 -3
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
- package/src/lib/config/TLUserPreferences.test.ts +18 -1
- package/src/lib/config/TLUserPreferences.ts +8 -4
- package/src/lib/config/createTLStore.ts +1 -1
- package/src/lib/editor/Editor.ts +196 -341
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +9 -9
- package/src/lib/editor/managers/FontManager/FontManager.ts +2 -1
- package/src/lib/editor/managers/InputsManager/InputsManager.test.ts +199 -3
- package/src/lib/editor/managers/InputsManager/InputsManager.ts +128 -9
- package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +0 -2
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +1 -0
- package/src/lib/editor/overlays/OverlayManager.ts +3 -7
- package/src/lib/editor/overlays/strokeShapeIndicators.ts +0 -1
- package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +5 -1
- package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +3 -0
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +4 -1
- package/src/lib/editor/tools/StateNode.test.ts +64 -0
- package/src/lib/editor/tools/StateNode.ts +12 -2
- package/src/lib/globals/menus.test.ts +33 -0
- package/src/lib/globals/menus.ts +11 -4
- package/src/lib/hooks/useCanvasEvents.ts +2 -0
- package/src/lib/hooks/useDocumentEvents.ts +14 -7
- package/src/lib/hooks/useLocalStore.ts +16 -8
- package/src/lib/hooks/usePassThroughWheelEvents.ts +3 -0
- package/src/lib/hooks/usePeerIds.ts +2 -1
- package/src/lib/primitives/Box.test.ts +9 -1
- package/src/lib/primitives/Box.ts +3 -1
- package/src/lib/primitives/Vec.test.ts +10 -0
- package/src/lib/primitives/Vec.ts +4 -4
- package/src/lib/primitives/utils.test.ts +10 -1
- package/src/lib/primitives/utils.ts +4 -1
- package/src/lib/test/useCanvasEvents.test.tsx +74 -0
- package/src/lib/test/useDocumentEvents.test.tsx +31 -0
- package/src/lib/test/usePassThroughWheelEvents.test.tsx +25 -2
- package/src/lib/utils/rotation.ts +4 -12
- package/src/version.ts +3 -3
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
Result,
|
|
40
40
|
ZERO_INDEX_KEY,
|
|
41
41
|
annotateError,
|
|
42
|
+
areArraysShallowEqual,
|
|
42
43
|
assert,
|
|
43
44
|
assertExists,
|
|
44
45
|
bind,
|
|
@@ -92,7 +93,13 @@ import { EASINGS } from "../primitives/easings.mjs";
|
|
|
92
93
|
import { Group2d } from "../primitives/geometry/Group2d.mjs";
|
|
93
94
|
import { intersectPolygonPolygon } from "../primitives/intersect.mjs";
|
|
94
95
|
import { Mat } from "../primitives/Mat.mjs";
|
|
95
|
-
import {
|
|
96
|
+
import {
|
|
97
|
+
HALF_PI,
|
|
98
|
+
approximately,
|
|
99
|
+
areAnglesCompatible,
|
|
100
|
+
clamp,
|
|
101
|
+
pointInPolygon
|
|
102
|
+
} from "../primitives/utils.mjs";
|
|
96
103
|
import { Vec } from "../primitives/Vec.mjs";
|
|
97
104
|
import { areShapesContentEqual } from "../utils/areShapesContentEqual.mjs";
|
|
98
105
|
import { dataUrlToFile } from "../utils/assets.mjs";
|
|
@@ -290,6 +297,10 @@ class Editor extends EventEmitter {
|
|
|
290
297
|
if (!nextPageState) nextPageState = { ...prevPageState };
|
|
291
298
|
nextPageState.editingShapeId = null;
|
|
292
299
|
}
|
|
300
|
+
if (prevPageState.croppingShapeId && shapesNoLongerInPage.has(prevPageState.croppingShapeId)) {
|
|
301
|
+
if (!nextPageState) nextPageState = { ...prevPageState };
|
|
302
|
+
nextPageState.croppingShapeId = null;
|
|
303
|
+
}
|
|
293
304
|
const hintingShapeIds = prevPageState.hintingShapeIds.filter(
|
|
294
305
|
(id) => !shapesNoLongerInPage.has(id)
|
|
295
306
|
);
|
|
@@ -532,10 +543,11 @@ class Editor extends EventEmitter {
|
|
|
532
543
|
this.cancelDoubleClick();
|
|
533
544
|
}
|
|
534
545
|
if (prev?.selectedShapeIds !== next?.selectedShapeIds) {
|
|
546
|
+
const selectedShapeIds = new Set(next.selectedShapeIds);
|
|
535
547
|
const filtered = next.selectedShapeIds.filter((id) => {
|
|
536
548
|
let parentId = this.getShape(id)?.parentId;
|
|
537
549
|
while (isShapeId(parentId)) {
|
|
538
|
-
if (
|
|
550
|
+
if (selectedShapeIds.has(parentId)) {
|
|
539
551
|
return false;
|
|
540
552
|
}
|
|
541
553
|
parentId = this.getShape(parentId)?.parentId;
|
|
@@ -619,7 +631,10 @@ class Editor extends EventEmitter {
|
|
|
619
631
|
const mode = this.store.props.collaboration.mode;
|
|
620
632
|
this.disposables.add(
|
|
621
633
|
react("update collaboration mode", () => {
|
|
622
|
-
|
|
634
|
+
const isReadonly = mode.get() === "readonly";
|
|
635
|
+
unsafe__withoutCapture(
|
|
636
|
+
() => this._updateInstanceState({ isReadonly }, { history: "ignore" })
|
|
637
|
+
);
|
|
623
638
|
})
|
|
624
639
|
);
|
|
625
640
|
}
|
|
@@ -977,7 +992,7 @@ class Editor extends EventEmitter {
|
|
|
977
992
|
getShapeUtil(arg) {
|
|
978
993
|
const type = typeof arg === "string" ? arg : arg.type;
|
|
979
994
|
const shapeUtil = getOwnProperty(this.shapeUtils, type);
|
|
980
|
-
|
|
995
|
+
if (!shapeUtil) throw new Error(`No shape util found for type "${type}"`);
|
|
981
996
|
return shapeUtil;
|
|
982
997
|
}
|
|
983
998
|
hasShapeUtil(arg) {
|
|
@@ -1766,7 +1781,9 @@ class Editor extends EventEmitter {
|
|
|
1766
1781
|
const selectedShapes = this.getSelectedShapes();
|
|
1767
1782
|
if (!selectedShapes.length) return;
|
|
1768
1783
|
const selectedShape = selectedShapes[0];
|
|
1769
|
-
const children =
|
|
1784
|
+
const children = compact(
|
|
1785
|
+
this.getSortedChildIdsForParent(selectedShape.id).map((id) => this.getShape(id))
|
|
1786
|
+
);
|
|
1770
1787
|
const sortedChildren = this._getShapesInReadingOrder(children);
|
|
1771
1788
|
if (sortedChildren.length === 0) return;
|
|
1772
1789
|
this._selectShapesAndZoom([sortedChildren[0].id]);
|
|
@@ -1833,18 +1850,13 @@ class Editor extends EventEmitter {
|
|
|
1833
1850
|
* @internal
|
|
1834
1851
|
*/
|
|
1835
1852
|
getShapesSharedRotation(shapeIds) {
|
|
1836
|
-
let foundFirst = false;
|
|
1837
1853
|
let rotation = 0;
|
|
1838
1854
|
for (let i = 0, n = shapeIds.length; i < n; i++) {
|
|
1839
|
-
const
|
|
1840
|
-
if (
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
}
|
|
1845
|
-
} else {
|
|
1846
|
-
foundFirst = true;
|
|
1847
|
-
rotation = pageTransform.rotation();
|
|
1855
|
+
const pageRotation = this.getShapePageTransform(shapeIds[i]).rotation();
|
|
1856
|
+
if (i === 0) {
|
|
1857
|
+
rotation = pageRotation;
|
|
1858
|
+
} else if (pageRotation !== rotation) {
|
|
1859
|
+
return 0;
|
|
1848
1860
|
}
|
|
1849
1861
|
}
|
|
1850
1862
|
return rotation;
|
|
@@ -1870,11 +1882,9 @@ class Editor extends EventEmitter {
|
|
|
1870
1882
|
return bounds;
|
|
1871
1883
|
}
|
|
1872
1884
|
const boxFromRotatedVertices = Box.FromPoints(
|
|
1873
|
-
shapeIds.flatMap(
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
return pageTransform.applyToPoints(this.getShapeGeometry(id).bounds.corners);
|
|
1877
|
-
}).map((p) => p.rot(-selectionRotation))
|
|
1885
|
+
shapeIds.flatMap(
|
|
1886
|
+
(id) => this.getShapePageTransform(id).applyToPoints(this.getShapeGeometry(id).bounds.corners)
|
|
1887
|
+
).map((p) => p.rot(-selectionRotation))
|
|
1878
1888
|
);
|
|
1879
1889
|
boxFromRotatedVertices.point = boxFromRotatedVertices.point.rot(selectionRotation);
|
|
1880
1890
|
return boxFromRotatedVertices;
|
|
@@ -1885,9 +1895,14 @@ class Editor extends EventEmitter {
|
|
|
1885
1895
|
getSelectionRotatedScreenBounds() {
|
|
1886
1896
|
const bounds = this.getSelectionRotatedPageBounds();
|
|
1887
1897
|
if (!bounds) return void 0;
|
|
1888
|
-
const
|
|
1889
|
-
const zoom = this.
|
|
1890
|
-
return new Box(
|
|
1898
|
+
const screenBounds = this.getViewportScreenBounds();
|
|
1899
|
+
const { x: cx, y: cy, z: zoom } = this.getCamera();
|
|
1900
|
+
return new Box(
|
|
1901
|
+
(bounds.x + cx) * zoom + screenBounds.x,
|
|
1902
|
+
(bounds.y + cy) * zoom + screenBounds.y,
|
|
1903
|
+
bounds.width * zoom,
|
|
1904
|
+
bounds.height * zoom
|
|
1905
|
+
);
|
|
1891
1906
|
}
|
|
1892
1907
|
getFocusedGroupId() {
|
|
1893
1908
|
return this.getCurrentPageState().focusedGroupId ?? this.getCurrentPageId();
|
|
@@ -1988,42 +2003,28 @@ class Editor extends EventEmitter {
|
|
|
1988
2003
|
*/
|
|
1989
2004
|
setEditingShape(shape) {
|
|
1990
2005
|
const id = typeof shape === "string" ? shape : shape?.id ?? null;
|
|
1991
|
-
if (!id)
|
|
2006
|
+
if (id && !this.canEditShape(id)) return this;
|
|
2007
|
+
this.run(() => {
|
|
2008
|
+
const prevEditingShapeId = this.getEditingShapeId();
|
|
2009
|
+
if (prevEditingShapeId) {
|
|
2010
|
+
const prevEditingShape = this.getShape(prevEditingShapeId);
|
|
2011
|
+
if (prevEditingShape) {
|
|
2012
|
+
this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
1992
2015
|
this.run(
|
|
1993
2016
|
() => {
|
|
1994
|
-
const prevEditingShapeId = this.getEditingShapeId();
|
|
1995
|
-
if (prevEditingShapeId) {
|
|
1996
|
-
const prevEditingShape = this.getShape(prevEditingShapeId);
|
|
1997
|
-
if (prevEditingShape) {
|
|
1998
|
-
this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
2017
|
this._updateCurrentPageState({ editingShapeId: null });
|
|
2002
2018
|
this._currentRichTextEditor.set(null);
|
|
2019
|
+
if (!id) return;
|
|
2020
|
+
this.select(id);
|
|
2021
|
+
this._updateCurrentPageState({ editingShapeId: id });
|
|
2022
|
+
const nextEditingShape = this.getShape(id);
|
|
2023
|
+
this.getShapeUtil(nextEditingShape).onEditStart?.(nextEditingShape);
|
|
2003
2024
|
},
|
|
2004
2025
|
{ history: "ignore" }
|
|
2005
2026
|
);
|
|
2006
|
-
|
|
2007
|
-
}
|
|
2008
|
-
if (!this.canEditShape(id)) return this;
|
|
2009
|
-
this.run(
|
|
2010
|
-
() => {
|
|
2011
|
-
const prevEditingShapeId = this.getEditingShapeId();
|
|
2012
|
-
if (prevEditingShapeId) {
|
|
2013
|
-
const prevEditingShape = this.getShape(prevEditingShapeId);
|
|
2014
|
-
if (prevEditingShape) {
|
|
2015
|
-
this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
|
|
2016
|
-
}
|
|
2017
|
-
}
|
|
2018
|
-
this._updateCurrentPageState({ editingShapeId: null });
|
|
2019
|
-
this._currentRichTextEditor.set(null);
|
|
2020
|
-
this.select(id);
|
|
2021
|
-
this._updateCurrentPageState({ editingShapeId: id });
|
|
2022
|
-
const nextEditingShape = this.getShape(id);
|
|
2023
|
-
this.getShapeUtil(nextEditingShape).onEditStart?.(nextEditingShape);
|
|
2024
|
-
},
|
|
2025
|
-
{ history: "ignore" }
|
|
2026
|
-
);
|
|
2027
|
+
});
|
|
2027
2028
|
return this;
|
|
2028
2029
|
}
|
|
2029
2030
|
// Rich text editor
|
|
@@ -2129,19 +2130,12 @@ class Editor extends EventEmitter {
|
|
|
2129
2130
|
* @public
|
|
2130
2131
|
*/
|
|
2131
2132
|
setErasingShapes(shapes) {
|
|
2132
|
-
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
|
|
2133
|
+
const ids = typeof shapes[0] === "string" ? shapes.slice() : shapes.map((shape) => shape.id);
|
|
2133
2134
|
ids.sort();
|
|
2134
2135
|
const erasingShapeIds = this.getErasingShapeIds();
|
|
2135
2136
|
this.run(
|
|
2136
2137
|
() => {
|
|
2137
|
-
if (ids
|
|
2138
|
-
for (let i = 0; i < ids.length; i++) {
|
|
2139
|
-
if (ids[i] !== erasingShapeIds[i]) {
|
|
2140
|
-
this._updateCurrentPageState({ erasingShapeIds: ids });
|
|
2141
|
-
break;
|
|
2142
|
-
}
|
|
2143
|
-
}
|
|
2144
|
-
} else {
|
|
2138
|
+
if (!areArraysShallowEqual(ids, erasingShapeIds)) {
|
|
2145
2139
|
this._updateCurrentPageState({ erasingShapeIds: ids });
|
|
2146
2140
|
}
|
|
2147
2141
|
},
|
|
@@ -2174,6 +2168,7 @@ class Editor extends EventEmitter {
|
|
|
2174
2168
|
if (!_shape) return false;
|
|
2175
2169
|
const util = this.getShapeUtil(_shape);
|
|
2176
2170
|
if (!util.canCrop(_shape)) return false;
|
|
2171
|
+
if (this.getIsReadonly()) return false;
|
|
2177
2172
|
if (this.isShapeOrAncestorLocked(_shape)) return false;
|
|
2178
2173
|
return true;
|
|
2179
2174
|
}
|
|
@@ -2238,11 +2233,11 @@ class Editor extends EventEmitter {
|
|
|
2238
2233
|
const collaborators = this.getCollaborators();
|
|
2239
2234
|
let leaderPresence = null;
|
|
2240
2235
|
while (targetUserId && !visited.includes(targetUserId)) {
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2236
|
+
const nextPresence = collaborators.find((c) => c.userId === targetUserId);
|
|
2237
|
+
if (!nextPresence) break;
|
|
2238
|
+
leaderPresence = nextPresence;
|
|
2239
|
+
targetUserId = nextPresence.followingUserId ?? null;
|
|
2240
|
+
visited.push(nextPresence.userId);
|
|
2246
2241
|
}
|
|
2247
2242
|
return leaderPresence;
|
|
2248
2243
|
}
|
|
@@ -2305,39 +2300,7 @@ class Editor extends EventEmitter {
|
|
|
2305
2300
|
*
|
|
2306
2301
|
* @public */
|
|
2307
2302
|
getInitialZoom() {
|
|
2308
|
-
|
|
2309
|
-
if (!cameraOptions.constraints) return 1;
|
|
2310
|
-
if (cameraOptions.constraints.initialZoom === "default") return 1;
|
|
2311
|
-
const { zx, zy } = getCameraFitXFitY(this, cameraOptions);
|
|
2312
|
-
switch (cameraOptions.constraints.initialZoom) {
|
|
2313
|
-
case "fit-min": {
|
|
2314
|
-
return Math.max(zx, zy);
|
|
2315
|
-
}
|
|
2316
|
-
case "fit-max": {
|
|
2317
|
-
return Math.min(zx, zy);
|
|
2318
|
-
}
|
|
2319
|
-
case "fit-x": {
|
|
2320
|
-
return zx;
|
|
2321
|
-
}
|
|
2322
|
-
case "fit-y": {
|
|
2323
|
-
return zy;
|
|
2324
|
-
}
|
|
2325
|
-
case "fit-min-100": {
|
|
2326
|
-
return Math.min(1, Math.max(zx, zy));
|
|
2327
|
-
}
|
|
2328
|
-
case "fit-max-100": {
|
|
2329
|
-
return Math.min(1, Math.min(zx, zy));
|
|
2330
|
-
}
|
|
2331
|
-
case "fit-x-100": {
|
|
2332
|
-
return Math.min(1, zx);
|
|
2333
|
-
}
|
|
2334
|
-
case "fit-y-100": {
|
|
2335
|
-
return Math.min(1, zy);
|
|
2336
|
-
}
|
|
2337
|
-
default: {
|
|
2338
|
-
throw exhaustiveSwitchError(cameraOptions.constraints.initialZoom);
|
|
2339
|
-
}
|
|
2340
|
-
}
|
|
2303
|
+
return this._getFitZoom(this.getCameraOptions().constraints?.initialZoom ?? "default");
|
|
2341
2304
|
}
|
|
2342
2305
|
/**
|
|
2343
2306
|
* Get the camera's base level for calculating actual zoom levels based on the zoom steps.
|
|
@@ -2349,11 +2312,13 @@ class Editor extends EventEmitter {
|
|
|
2349
2312
|
*
|
|
2350
2313
|
* @public */
|
|
2351
2314
|
getBaseZoom() {
|
|
2315
|
+
return this._getFitZoom(this.getCameraOptions().constraints?.baseZoom ?? "default");
|
|
2316
|
+
}
|
|
2317
|
+
_getFitZoom(fit) {
|
|
2352
2318
|
const cameraOptions = this.getCameraOptions();
|
|
2353
|
-
if (!cameraOptions.constraints) return 1;
|
|
2354
|
-
if (cameraOptions.constraints.baseZoom === "default") return 1;
|
|
2319
|
+
if (!cameraOptions.constraints || fit === "default") return 1;
|
|
2355
2320
|
const { zx, zy } = getCameraFitXFitY(this, cameraOptions);
|
|
2356
|
-
switch (
|
|
2321
|
+
switch (fit) {
|
|
2357
2322
|
case "fit-min": {
|
|
2358
2323
|
return Math.max(zx, zy);
|
|
2359
2324
|
}
|
|
@@ -2379,7 +2344,7 @@ class Editor extends EventEmitter {
|
|
|
2379
2344
|
return Math.min(1, zy);
|
|
2380
2345
|
}
|
|
2381
2346
|
default: {
|
|
2382
|
-
throw exhaustiveSwitchError(
|
|
2347
|
+
throw exhaustiveSwitchError(fit);
|
|
2383
2348
|
}
|
|
2384
2349
|
}
|
|
2385
2350
|
}
|
|
@@ -2413,7 +2378,7 @@ class Editor extends EventEmitter {
|
|
|
2413
2378
|
...this._cameraOptions.__unsafe__getWithoutCapture(),
|
|
2414
2379
|
...opts
|
|
2415
2380
|
});
|
|
2416
|
-
if (next.zoomSteps
|
|
2381
|
+
if (!next.zoomSteps || next.zoomSteps.length < 1) next.zoomSteps = [1];
|
|
2417
2382
|
this._cameraOptions.set(next);
|
|
2418
2383
|
this.setCamera(this.getCamera());
|
|
2419
2384
|
return this;
|
|
@@ -2873,9 +2838,9 @@ class Editor extends EventEmitter {
|
|
|
2873
2838
|
}
|
|
2874
2839
|
const remaining = duration - elapsed;
|
|
2875
2840
|
const t = easing(1 - remaining / duration);
|
|
2876
|
-
const left = start.minX
|
|
2877
|
-
const top = start.minY
|
|
2878
|
-
const right = start.maxX
|
|
2841
|
+
const left = lerp(start.minX, end.minX, t);
|
|
2842
|
+
const top = lerp(start.minY, end.minY, t);
|
|
2843
|
+
const right = lerp(start.maxX, end.maxX, t);
|
|
2879
2844
|
this._setCamera(new Vec(-left, -top, this.getViewportScreenBounds().width / (right - left)), {
|
|
2880
2845
|
force: true
|
|
2881
2846
|
});
|
|
@@ -2953,7 +2918,7 @@ class Editor extends EventEmitter {
|
|
|
2953
2918
|
let newCy = cy + dy;
|
|
2954
2919
|
let newCz = cz;
|
|
2955
2920
|
if (dirZ !== 0) {
|
|
2956
|
-
newCz = cz * (
|
|
2921
|
+
newCz = cz * Math.exp(dirZ * currentSpeed * elapsed);
|
|
2957
2922
|
const center = this.getViewportScreenCenter();
|
|
2958
2923
|
newCx += center.x / newCz - center.x / cz;
|
|
2959
2924
|
newCy += center.y / newCz - center.y / cz;
|
|
@@ -3391,12 +3356,12 @@ class Editor extends EventEmitter {
|
|
|
3391
3356
|
const renderingShapes = [];
|
|
3392
3357
|
let nextIndex = this.options.maxShapesPerPage * 2;
|
|
3393
3358
|
let nextBackgroundIndex = this.options.maxShapesPerPage;
|
|
3394
|
-
const erasingShapeIds = this.getErasingShapeIds();
|
|
3359
|
+
const erasingShapeIds = new Set(this.getErasingShapeIds());
|
|
3395
3360
|
const addShapeById = (id, opacity, isAncestorErasing) => {
|
|
3396
3361
|
const shape = this.getShape(id);
|
|
3397
3362
|
if (!shape) return;
|
|
3398
3363
|
if (this.isShapeHidden(shape)) {
|
|
3399
|
-
const isErasing = isAncestorErasing || erasingShapeIds.
|
|
3364
|
+
const isErasing = isAncestorErasing || erasingShapeIds.has(id);
|
|
3400
3365
|
for (const childId of this.getSortedChildIdsForParent(id)) {
|
|
3401
3366
|
addShapeById(childId, opacity, isErasing);
|
|
3402
3367
|
}
|
|
@@ -3406,7 +3371,7 @@ class Editor extends EventEmitter {
|
|
|
3406
3371
|
let isShapeErasing = false;
|
|
3407
3372
|
const util = this.getShapeUtil(shape);
|
|
3408
3373
|
if (useEditorState) {
|
|
3409
|
-
isShapeErasing = !isAncestorErasing && erasingShapeIds.
|
|
3374
|
+
isShapeErasing = !isAncestorErasing && erasingShapeIds.has(id);
|
|
3410
3375
|
if (isShapeErasing) {
|
|
3411
3376
|
opacity *= 0.32;
|
|
3412
3377
|
}
|
|
@@ -3998,10 +3963,8 @@ class Editor extends EventEmitter {
|
|
|
3998
3963
|
}
|
|
3999
3964
|
_getShapePageBoundsCache() {
|
|
4000
3965
|
return this.store.createComputedCache("pageBoundsCache", (shape) => {
|
|
4001
|
-
const pageTransform = this.getShapePageTransform(shape);
|
|
4002
|
-
if (!pageTransform) return void 0;
|
|
4003
3966
|
return Box.FromPoints(
|
|
4004
|
-
|
|
3967
|
+
this.getShapePageTransform(shape).applyToPoints(this.getShapeGeometry(shape).boundsVertices)
|
|
4005
3968
|
);
|
|
4006
3969
|
});
|
|
4007
3970
|
}
|
|
@@ -4550,9 +4513,7 @@ class Editor extends EventEmitter {
|
|
|
4550
4513
|
const freshShape = this.getShape(id);
|
|
4551
4514
|
if (!freshShape) return new Vec(0, 0);
|
|
4552
4515
|
if (isPageId(freshShape.parentId)) return Vec.From(point);
|
|
4553
|
-
|
|
4554
|
-
if (!parentTransform) return Vec.From(point);
|
|
4555
|
-
return parentTransform.clone().invert().applyToPoint(point);
|
|
4516
|
+
return this.getShapePageTransform(freshShape.parentId).clone().invert().applyToPoint(point);
|
|
4556
4517
|
}
|
|
4557
4518
|
getCurrentPageShapes() {
|
|
4558
4519
|
return Array.from(this.getCurrentPageShapeIds(), (id) => this.store.get(id));
|
|
@@ -4664,23 +4625,7 @@ class Editor extends EventEmitter {
|
|
|
4664
4625
|
* @public
|
|
4665
4626
|
*/
|
|
4666
4627
|
isShapeInPage(shape, pageId = this.getCurrentPageId()) {
|
|
4667
|
-
|
|
4668
|
-
const shapeToCheck = this.getShape(id);
|
|
4669
|
-
if (!shapeToCheck) return false;
|
|
4670
|
-
let shapeIsInPage = false;
|
|
4671
|
-
if (shapeToCheck.parentId === pageId) {
|
|
4672
|
-
shapeIsInPage = true;
|
|
4673
|
-
} else {
|
|
4674
|
-
let parent = this.getShape(shapeToCheck.parentId);
|
|
4675
|
-
isInPageSearch: while (parent) {
|
|
4676
|
-
if (parent.parentId === pageId) {
|
|
4677
|
-
shapeIsInPage = true;
|
|
4678
|
-
break isInPageSearch;
|
|
4679
|
-
}
|
|
4680
|
-
parent = this.getShape(parent.parentId);
|
|
4681
|
-
}
|
|
4682
|
-
}
|
|
4683
|
-
return shapeIsInPage;
|
|
4628
|
+
return this.getAncestorPageId(shape) === pageId;
|
|
4684
4629
|
}
|
|
4685
4630
|
/**
|
|
4686
4631
|
* Get the id of the containing page for a given shape.
|
|
@@ -4761,10 +4706,7 @@ class Editor extends EventEmitter {
|
|
|
4761
4706
|
for (let i = 0; i < shapesToReparent.length; i++) {
|
|
4762
4707
|
const shape = shapesToReparent[i];
|
|
4763
4708
|
const pageTransform = this.getShapePageTransform(shape);
|
|
4764
|
-
|
|
4765
|
-
const pagePoint = pageTransform.point();
|
|
4766
|
-
if (!pagePoint) continue;
|
|
4767
|
-
const newPoint = invertedParentTransform.applyToPoint(pagePoint);
|
|
4709
|
+
const newPoint = invertedParentTransform.applyToPoint(pageTransform.point());
|
|
4768
4710
|
const newRotation = pageTransform.rotation() - parentPageRotation;
|
|
4769
4711
|
if (shape.id === parentId) {
|
|
4770
4712
|
throw Error("Attempted to reparent a shape to itself!");
|
|
@@ -4853,7 +4795,7 @@ class Editor extends EventEmitter {
|
|
|
4853
4795
|
*/
|
|
4854
4796
|
getShapeAndDescendantIds(ids) {
|
|
4855
4797
|
const shapeIds = /* @__PURE__ */ new Set();
|
|
4856
|
-
for (const shape of ids.map((id) => this.getShape(id)).sort(sortByIndex)) {
|
|
4798
|
+
for (const shape of compact(ids.map((id) => this.getShape(id))).sort(sortByIndex)) {
|
|
4857
4799
|
shapeIds.add(shape.id);
|
|
4858
4800
|
this.visitDescendants(shape, (descendantId) => {
|
|
4859
4801
|
shapeIds.add(descendantId);
|
|
@@ -4875,11 +4817,12 @@ class Editor extends EventEmitter {
|
|
|
4875
4817
|
const draggingShapes = compact(droppingShapes.map((s) => this.getShape(s))).filter(
|
|
4876
4818
|
(s) => !s.isLocked && !this.isShapeHidden(s)
|
|
4877
4819
|
);
|
|
4820
|
+
const excludedIds = this.getShapeAndDescendantIds(draggingShapes.map((s) => s.id));
|
|
4878
4821
|
const maybeDraggingOverShapes = this.getShapesAtPoint(point, {
|
|
4879
4822
|
hitInside: true,
|
|
4880
4823
|
margin: 0
|
|
4881
4824
|
}).filter(
|
|
4882
|
-
(s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !
|
|
4825
|
+
(s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !excludedIds.has(s.id)
|
|
4883
4826
|
);
|
|
4884
4827
|
for (const maybeDraggingOverShape of maybeDraggingOverShapes) {
|
|
4885
4828
|
const shapeUtil = this.getShapeUtil(maybeDraggingOverShape);
|
|
@@ -5132,8 +5075,7 @@ class Editor extends EventEmitter {
|
|
|
5132
5075
|
for (const id of ids) {
|
|
5133
5076
|
const shape = this.getShape(id);
|
|
5134
5077
|
const localDelta = Vec.From(offset);
|
|
5135
|
-
|
|
5136
|
-
if (parentTransform) localDelta.rot(-parentTransform.rotation());
|
|
5078
|
+
localDelta.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5137
5079
|
changes.push(this.getChangesToTranslateShape(shape, localDelta.add(shape)));
|
|
5138
5080
|
}
|
|
5139
5081
|
this.updateShapes(changes);
|
|
@@ -5188,7 +5130,7 @@ class Editor extends EventEmitter {
|
|
|
5188
5130
|
if (!originalShape) continue;
|
|
5189
5131
|
let ox = 0;
|
|
5190
5132
|
let oy = 0;
|
|
5191
|
-
if (offset && initialIds.has(originalId)) {
|
|
5133
|
+
if (offset && initialIds.has(originalId) && !shapeIdSet.has(originalShape.parentId)) {
|
|
5192
5134
|
const parentTransform = this.getShapeParentTransform(originalShape);
|
|
5193
5135
|
const vec = new Vec(offset.x, offset.y).rot(-parentTransform.rotation());
|
|
5194
5136
|
ox = vec.x;
|
|
@@ -5302,26 +5244,17 @@ class Editor extends EventEmitter {
|
|
|
5302
5244
|
toggleLock(shapes) {
|
|
5303
5245
|
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
|
|
5304
5246
|
if (this.getIsReadonly() || ids.length === 0) return this;
|
|
5305
|
-
let allLocked = true
|
|
5247
|
+
let allLocked = true;
|
|
5306
5248
|
const shapesToToggle = [];
|
|
5307
5249
|
for (const id of ids) {
|
|
5308
5250
|
const shape = this.getShape(id);
|
|
5309
5251
|
if (shape) {
|
|
5310
5252
|
shapesToToggle.push(shape);
|
|
5311
|
-
if (shape.isLocked)
|
|
5312
|
-
allUnlocked = false;
|
|
5313
|
-
} else {
|
|
5314
|
-
allLocked = false;
|
|
5315
|
-
}
|
|
5253
|
+
if (!shape.isLocked) allLocked = false;
|
|
5316
5254
|
}
|
|
5317
5255
|
}
|
|
5318
5256
|
this.run(() => {
|
|
5319
|
-
if (
|
|
5320
|
-
this.updateShapes(
|
|
5321
|
-
shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: true }))
|
|
5322
|
-
);
|
|
5323
|
-
this.setSelectedShapes([]);
|
|
5324
|
-
} else if (allLocked) {
|
|
5257
|
+
if (allLocked) {
|
|
5325
5258
|
this.updateShapes(
|
|
5326
5259
|
shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: false }))
|
|
5327
5260
|
);
|
|
@@ -5329,6 +5262,7 @@ class Editor extends EventEmitter {
|
|
|
5329
5262
|
this.updateShapes(
|
|
5330
5263
|
shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: true }))
|
|
5331
5264
|
);
|
|
5265
|
+
this.setSelectedShapes([]);
|
|
5332
5266
|
}
|
|
5333
5267
|
});
|
|
5334
5268
|
return this;
|
|
@@ -5439,9 +5373,10 @@ class Editor extends EventEmitter {
|
|
|
5439
5373
|
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
|
|
5440
5374
|
let freshShapes = compact(ids.map((id) => this.getShape(id)));
|
|
5441
5375
|
if (opts?.filterAxisAligned) {
|
|
5442
|
-
freshShapes = freshShapes.filter(
|
|
5443
|
-
|
|
5444
|
-
|
|
5376
|
+
freshShapes = freshShapes.filter((s) => {
|
|
5377
|
+
const remainder = Math.abs(this.getShapePageTransform(s).rotation() % HALF_PI);
|
|
5378
|
+
return Math.min(remainder, HALF_PI - remainder) < 1e-9;
|
|
5379
|
+
});
|
|
5445
5380
|
}
|
|
5446
5381
|
const clusters = [];
|
|
5447
5382
|
const allBounds = [];
|
|
@@ -5606,9 +5541,9 @@ class Editor extends EventEmitter {
|
|
|
5606
5541
|
dim = "height";
|
|
5607
5542
|
}
|
|
5608
5543
|
let shapeGap = 0;
|
|
5544
|
+
shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
|
|
5609
5545
|
if (_gap === 0) {
|
|
5610
5546
|
const gaps = {};
|
|
5611
|
-
shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
|
|
5612
5547
|
for (let i = 0; i < len - 1; i++) {
|
|
5613
5548
|
const currCluster = shapeClustersToStack[i];
|
|
5614
5549
|
const nextCluster = shapeClustersToStack[i + 1];
|
|
@@ -5646,8 +5581,7 @@ class Editor extends EventEmitter {
|
|
|
5646
5581
|
const shapeDelta = delta.clone();
|
|
5647
5582
|
const parent = this.getShapeParent(shape);
|
|
5648
5583
|
if (parent) {
|
|
5649
|
-
|
|
5650
|
-
if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
|
|
5584
|
+
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5651
5585
|
}
|
|
5652
5586
|
shapeDelta.add(shape);
|
|
5653
5587
|
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
@@ -5685,7 +5619,7 @@ class Editor extends EventEmitter {
|
|
|
5685
5619
|
}
|
|
5686
5620
|
const commonBounds = Box.Common(allBounds);
|
|
5687
5621
|
const maxWidth = commonBounds.width;
|
|
5688
|
-
shapeClustersToPack.sort((a, b) =>
|
|
5622
|
+
shapeClustersToPack.sort((a, b) => b.pageBounds.width - a.pageBounds.width).sort((a, b) => b.pageBounds.height - a.pageBounds.height);
|
|
5689
5623
|
const startWidth = Math.max(Math.ceil(Math.sqrt(area / 0.95)), maxWidth);
|
|
5690
5624
|
const spaces = [new Box(commonBounds.x, commonBounds.y, startWidth, Infinity)];
|
|
5691
5625
|
let width = 0;
|
|
@@ -5733,8 +5667,7 @@ class Editor extends EventEmitter {
|
|
|
5733
5667
|
const shapeDelta = delta.clone();
|
|
5734
5668
|
const parent = this.getShapeParent(shape);
|
|
5735
5669
|
if (parent) {
|
|
5736
|
-
|
|
5737
|
-
if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
|
|
5670
|
+
shapeDelta.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5738
5671
|
}
|
|
5739
5672
|
shapeDelta.add(shape);
|
|
5740
5673
|
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
@@ -5800,8 +5733,7 @@ class Editor extends EventEmitter {
|
|
|
5800
5733
|
const shapeDelta = delta.clone();
|
|
5801
5734
|
const parent = this.getShapeParent(shape);
|
|
5802
5735
|
if (parent) {
|
|
5803
|
-
|
|
5804
|
-
if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
|
|
5736
|
+
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5805
5737
|
}
|
|
5806
5738
|
shapeDelta.add(shape);
|
|
5807
5739
|
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
@@ -5875,8 +5807,7 @@ class Editor extends EventEmitter {
|
|
|
5875
5807
|
const shapeDelta = delta.clone();
|
|
5876
5808
|
const parent = this.getShapeParent(shape);
|
|
5877
5809
|
if (parent) {
|
|
5878
|
-
|
|
5879
|
-
if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
|
|
5810
|
+
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5880
5811
|
}
|
|
5881
5812
|
shapeDelta.add(shape);
|
|
5882
5813
|
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
@@ -5931,8 +5862,7 @@ class Editor extends EventEmitter {
|
|
|
5931
5862
|
scale[val] = commonBounds[dim] / pageBounds[dim];
|
|
5932
5863
|
for (const shape of shapes2) {
|
|
5933
5864
|
const shapeLocalOffset = localOffset.clone();
|
|
5934
|
-
|
|
5935
|
-
if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
|
|
5865
|
+
shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5936
5866
|
shapeLocalOffset.add(shape);
|
|
5937
5867
|
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5938
5868
|
this.updateShape(changes);
|
|
@@ -5988,8 +5918,7 @@ class Editor extends EventEmitter {
|
|
|
5988
5918
|
);
|
|
5989
5919
|
for (const shape of shapes2) {
|
|
5990
5920
|
const shapeLocalOffset = localOffset.clone();
|
|
5991
|
-
|
|
5992
|
-
if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
|
|
5921
|
+
shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5993
5922
|
shapeLocalOffset.add(shape);
|
|
5994
5923
|
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5995
5924
|
this.updateShape(changes);
|
|
@@ -6038,9 +5967,7 @@ class Editor extends EventEmitter {
|
|
|
6038
5967
|
const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center;
|
|
6039
5968
|
if (!scaleOrigin) return null;
|
|
6040
5969
|
const pageTransform = opts.initialPageTransform ? Mat.Cast(opts.initialPageTransform) : this.getShapePageTransform(id);
|
|
6041
|
-
if (!pageTransform) return null;
|
|
6042
5970
|
const pageRotation = pageTransform.rotation();
|
|
6043
|
-
if (pageRotation == null) return null;
|
|
6044
5971
|
const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation;
|
|
6045
5972
|
const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds;
|
|
6046
5973
|
if (!initialBounds) return null;
|
|
@@ -6191,7 +6118,6 @@ class Editor extends EventEmitter {
|
|
|
6191
6118
|
const currentLocalBounds = this.getShapeGeometry(id).bounds;
|
|
6192
6119
|
const currentPageCenter = Mat.applyToPoint(pageTransform, currentLocalBounds.center);
|
|
6193
6120
|
const shapePageTransformOrigin = pageTransform.point();
|
|
6194
|
-
if (!currentPageCenter || !shapePageTransformOrigin) return this;
|
|
6195
6121
|
const pageDelta = Vec.Sub(postScaleShapePageCenter, currentPageCenter);
|
|
6196
6122
|
const postScaleShapePagePoint = Vec.Add(shapePageTransformOrigin, pageDelta);
|
|
6197
6123
|
const { x, y } = this.getPointInParentSpace(id, postScaleShapePagePoint);
|
|
@@ -6450,10 +6376,10 @@ class Editor extends EventEmitter {
|
|
|
6450
6376
|
if (animationIdForShape !== animationId) continue;
|
|
6451
6377
|
updates.push({
|
|
6452
6378
|
...end,
|
|
6453
|
-
x: start.x
|
|
6454
|
-
y: start.y
|
|
6455
|
-
opacity: start.opacity
|
|
6456
|
-
rotation: start.rotation
|
|
6379
|
+
x: lerp(start.x, end.x, t),
|
|
6380
|
+
y: lerp(start.y, end.y, t),
|
|
6381
|
+
opacity: lerp(start.opacity, end.opacity, t),
|
|
6382
|
+
rotation: lerp(start.rotation, end.rotation, t),
|
|
6457
6383
|
props: this.getShapeUtil(end).getInterpolatedProps?.(start, end, t) ?? end.props
|
|
6458
6384
|
});
|
|
6459
6385
|
}
|
|
@@ -6579,7 +6505,7 @@ class Editor extends EventEmitter {
|
|
|
6579
6505
|
* @public
|
|
6580
6506
|
*/
|
|
6581
6507
|
updateShapes(partials) {
|
|
6582
|
-
const compactedPartials =
|
|
6508
|
+
const compactedPartials = [];
|
|
6583
6509
|
for (let i = 0, n = partials.length; i < n; i++) {
|
|
6584
6510
|
const partial = partials[i];
|
|
6585
6511
|
if (!partial) continue;
|
|
@@ -6650,28 +6576,32 @@ class Editor extends EventEmitter {
|
|
|
6650
6576
|
}
|
|
6651
6577
|
/* --------------------- Styles --------------------- */
|
|
6652
6578
|
/**
|
|
6653
|
-
*
|
|
6579
|
+
* Groups have no styles of their own: a style read or write on a selection applies to the
|
|
6580
|
+
* non-group shapes beneath each group, however deeply nested. Returns those shapes.
|
|
6654
6581
|
*
|
|
6655
6582
|
* @internal
|
|
6656
6583
|
*/
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
if (
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6584
|
+
_getStyleableShapes(shapes) {
|
|
6585
|
+
const result = [];
|
|
6586
|
+
const visit = (shape) => {
|
|
6587
|
+
if (this.isShapeOfType(shape, "group")) {
|
|
6588
|
+
for (const childId of this.getSortedChildIdsForParent(shape.id)) {
|
|
6589
|
+
const child = this.getShape(childId);
|
|
6590
|
+
if (child) visit(child);
|
|
6591
|
+
}
|
|
6592
|
+
} else {
|
|
6593
|
+
result.push(shape);
|
|
6667
6594
|
}
|
|
6668
|
-
}
|
|
6595
|
+
};
|
|
6596
|
+
for (const shape of shapes) visit(shape);
|
|
6597
|
+
return result;
|
|
6669
6598
|
}
|
|
6670
6599
|
_getSelectionSharedStyles() {
|
|
6671
|
-
const selectedShapes = this.getSelectedShapes();
|
|
6672
6600
|
const sharedStyles = new SharedStyleMap();
|
|
6673
|
-
for (const
|
|
6674
|
-
|
|
6601
|
+
for (const shape of this._getStyleableShapes(this.getSelectedShapes())) {
|
|
6602
|
+
for (const [style, propKey] of this.styleProps[shape.type]) {
|
|
6603
|
+
sharedStyles.applyValue(style, getOwnProperty(shape.props, propKey));
|
|
6604
|
+
}
|
|
6675
6605
|
}
|
|
6676
6606
|
return sharedStyles;
|
|
6677
6607
|
}
|
|
@@ -6703,38 +6633,16 @@ class Editor extends EventEmitter {
|
|
|
6703
6633
|
const styles = new SharedStyleMap();
|
|
6704
6634
|
if (!currentTool) return styles;
|
|
6705
6635
|
if (currentTool.shapeType) {
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
if (style.id === "tldraw:color") continue;
|
|
6709
|
-
styles.applyValue(style, this.getStyleForNextShape(style));
|
|
6710
|
-
}
|
|
6711
|
-
} else {
|
|
6712
|
-
for (const style of this.styleProps[currentTool.shapeType].keys()) {
|
|
6713
|
-
styles.applyValue(style, this.getStyleForNextShape(style));
|
|
6714
|
-
}
|
|
6636
|
+
for (const style of this.styleProps[currentTool.shapeType].keys()) {
|
|
6637
|
+
styles.applyValue(style, this.getStyleForNextShape(style));
|
|
6715
6638
|
}
|
|
6716
6639
|
}
|
|
6717
6640
|
return styles;
|
|
6718
6641
|
}
|
|
6719
6642
|
getSharedOpacity() {
|
|
6720
6643
|
if (this.isIn("select") && this.getSelectedShapeIds().length > 0) {
|
|
6721
|
-
const shapesToCheck = [];
|
|
6722
|
-
const addShape = (shapeId) => {
|
|
6723
|
-
const shape = this.getShape(shapeId);
|
|
6724
|
-
if (!shape) return;
|
|
6725
|
-
if (this.isShapeOfType(shape, "group")) {
|
|
6726
|
-
for (const childId of this.getSortedChildIdsForParent(shape.id)) {
|
|
6727
|
-
addShape(childId);
|
|
6728
|
-
}
|
|
6729
|
-
} else {
|
|
6730
|
-
shapesToCheck.push(shape);
|
|
6731
|
-
}
|
|
6732
|
-
};
|
|
6733
|
-
for (const shapeId of this.getSelectedShapeIds()) {
|
|
6734
|
-
addShape(shapeId);
|
|
6735
|
-
}
|
|
6736
6644
|
let opacity = null;
|
|
6737
|
-
for (const shape of
|
|
6645
|
+
for (const shape of this._getStyleableShapes(this.getSelectedShapes())) {
|
|
6738
6646
|
if (opacity === null) {
|
|
6739
6647
|
opacity = shape.opacity;
|
|
6740
6648
|
} else if (opacity !== shape.opacity) {
|
|
@@ -6773,28 +6681,12 @@ class Editor extends EventEmitter {
|
|
|
6773
6681
|
setOpacityForSelectedShapes(opacity) {
|
|
6774
6682
|
const selectedShapes = this.getSelectedShapes();
|
|
6775
6683
|
if (selectedShapes.length > 0) {
|
|
6776
|
-
const shapesToUpdate = [];
|
|
6777
|
-
const addShapeById = (shape) => {
|
|
6778
|
-
if (this.isShapeOfType(shape, "group")) {
|
|
6779
|
-
const childIds = this.getSortedChildIdsForParent(shape);
|
|
6780
|
-
for (const childId of childIds) {
|
|
6781
|
-
addShapeById(this.getShape(childId));
|
|
6782
|
-
}
|
|
6783
|
-
} else {
|
|
6784
|
-
shapesToUpdate.push(shape);
|
|
6785
|
-
}
|
|
6786
|
-
};
|
|
6787
|
-
for (const id of selectedShapes) {
|
|
6788
|
-
addShapeById(id);
|
|
6789
|
-
}
|
|
6790
6684
|
this.updateShapes(
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
};
|
|
6797
|
-
})
|
|
6685
|
+
this._getStyleableShapes(selectedShapes).map((shape) => ({
|
|
6686
|
+
id: shape.id,
|
|
6687
|
+
type: shape.type,
|
|
6688
|
+
opacity
|
|
6689
|
+
}))
|
|
6798
6690
|
);
|
|
6799
6691
|
}
|
|
6800
6692
|
return this;
|
|
@@ -6839,33 +6731,17 @@ class Editor extends EventEmitter {
|
|
|
6839
6731
|
const selectedShapes = this.getSelectedShapes();
|
|
6840
6732
|
if (selectedShapes.length > 0) {
|
|
6841
6733
|
const updates = [];
|
|
6842
|
-
const
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
const stylePropKey = this.styleProps[shape.type].get(style);
|
|
6851
|
-
if (stylePropKey) {
|
|
6852
|
-
const shapePartial = {
|
|
6853
|
-
id: shape.id,
|
|
6854
|
-
type: shape.type,
|
|
6855
|
-
props: { [stylePropKey]: value }
|
|
6856
|
-
};
|
|
6857
|
-
updates.push({
|
|
6858
|
-
util,
|
|
6859
|
-
originalShape: shape,
|
|
6860
|
-
updatePartial: shapePartial
|
|
6861
|
-
});
|
|
6862
|
-
}
|
|
6734
|
+
for (const shape of this._getStyleableShapes(selectedShapes)) {
|
|
6735
|
+
const stylePropKey = this.styleProps[shape.type].get(style);
|
|
6736
|
+
if (stylePropKey) {
|
|
6737
|
+
updates.push({
|
|
6738
|
+
id: shape.id,
|
|
6739
|
+
type: shape.type,
|
|
6740
|
+
props: { [stylePropKey]: value }
|
|
6741
|
+
});
|
|
6863
6742
|
}
|
|
6864
|
-
};
|
|
6865
|
-
for (const shape of selectedShapes) {
|
|
6866
|
-
addShapeById(shape);
|
|
6867
6743
|
}
|
|
6868
|
-
this.updateShapes(updates
|
|
6744
|
+
this.updateShapes(updates);
|
|
6869
6745
|
}
|
|
6870
6746
|
return this;
|
|
6871
6747
|
}
|
|
@@ -7261,7 +7137,6 @@ class Editor extends EventEmitter {
|
|
|
7261
7137
|
if (shapeIdMap.has(newShape.parentId)) {
|
|
7262
7138
|
newShape.parentId = shapeIdMap.get(oldShape.parentId);
|
|
7263
7139
|
} else {
|
|
7264
|
-
rootShapeIds.push(newShape.id);
|
|
7265
7140
|
newShape.index = index;
|
|
7266
7141
|
index = getIndexAbove(index);
|
|
7267
7142
|
}
|
|
@@ -7286,8 +7161,11 @@ class Editor extends EventEmitter {
|
|
|
7286
7161
|
continue;
|
|
7287
7162
|
}
|
|
7288
7163
|
if (asset.type === "image" && asset.props.src?.startsWith("data:image") || asset.type === "video" && asset.props.src?.startsWith("data:video")) {
|
|
7289
|
-
assetsToUpdate.push(
|
|
7290
|
-
|
|
7164
|
+
assetsToUpdate.push(asset);
|
|
7165
|
+
const assetWithoutSrc = structuredClone(asset);
|
|
7166
|
+
assetWithoutSrc.props.src = null;
|
|
7167
|
+
assetsToCreate.push(assetWithoutSrc);
|
|
7168
|
+
continue;
|
|
7291
7169
|
}
|
|
7292
7170
|
assetsToCreate.push(asset);
|
|
7293
7171
|
}
|