@tldraw/editor 5.4.0-next.ef99ab47e5ce → 5.5.0-canary.078a77321dc3
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 +119 -49
- package/dist-cjs/index.js +4 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +7 -2
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- 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/constants.js +2 -0
- package/dist-cjs/lib/constants.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +190 -300
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js +7 -3
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +3 -3
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.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/EdgeScrollManager/EdgeScrollManager.js +10 -6
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.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/ScribbleManager/ScribbleManager.js +7 -0
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.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/TextManager/TextManager.js +1 -2
- 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/managers/TickManager/TickManager.js +6 -3
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +12 -1
- 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/editors.js +57 -0
- package/dist-cjs/lib/globals/editors.js.map +7 -0
- 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 +39 -9
- 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/license/LicenseManager.js +9 -2
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +16 -3
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/license/useLicenseManagerState.js +5 -4
- package/dist-cjs/lib/license/useLicenseManagerState.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/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 +71 -26
- 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/primitives/utils.js +2 -1
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/deepLinks.js +5 -1
- package/dist-cjs/lib/utils/deepLinks.js.map +2 -2
- package/dist-cjs/lib/utils/normalizeWheel.js +2 -0
- package/dist-cjs/lib/utils/normalizeWheel.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/lib/utils/sync/TLLocalSyncClient.js +17 -0
- package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
- package/dist-cjs/lib/utils/sync/alerts.js +1 -1
- package/dist-cjs/lib/utils/sync/alerts.js.map +1 -1
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +119 -49
- package/dist-esm/index.mjs +9 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +9 -4
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- 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/constants.mjs +2 -0
- package/dist-esm/lib/constants.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +199 -301
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs +7 -3
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +3 -3
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.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/EdgeScrollManager/EdgeScrollManager.mjs +10 -6
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.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/ScribbleManager/ScribbleManager.mjs +7 -0
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.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/TextManager/TextManager.mjs +2 -3
- 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/managers/TickManager/TickManager.mjs +6 -3
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +12 -1
- 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/editors.mjs +37 -0
- package/dist-esm/lib/globals/editors.mjs.map +7 -0
- 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 +40 -10
- 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/license/LicenseManager.mjs +9 -2
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +16 -3
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/license/useLicenseManagerState.mjs +5 -4
- package/dist-esm/lib/license/useLicenseManagerState.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/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 +75 -27
- 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/primitives/utils.mjs +2 -1
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/deepLinks.mjs +5 -1
- package/dist-esm/lib/utils/deepLinks.mjs.map +2 -2
- package/dist-esm/lib/utils/normalizeWheel.mjs +2 -0
- package/dist-esm/lib/utils/normalizeWheel.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/lib/utils/sync/TLLocalSyncClient.mjs +17 -0
- package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
- package/dist-esm/lib/utils/sync/alerts.mjs +1 -1
- package/dist-esm/lib/utils/sync/alerts.mjs.map +1 -1
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +13 -7
- package/src/index.ts +6 -1
- package/src/lib/TldrawEditor.tsx +16 -4
- 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/constants.ts +8 -0
- package/src/lib/editor/Editor.ts +285 -392
- package/src/lib/editor/derivations/shapeIdsInCurrentPage.ts +7 -3
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +5 -3
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +9 -9
- 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/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/ScribbleManager/ScribbleManager.ts +12 -1
- package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +0 -2
- package/src/lib/editor/managers/TextManager/TextManager.ts +2 -6
- 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/managers/TickManager/TickManager.test.ts +13 -0
- package/src/lib/editor/managers/TickManager/TickManager.ts +9 -3
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +64 -3
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +18 -1
- 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/editors.test.ts +76 -0
- package/src/lib/globals/editors.ts +53 -0
- 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 +60 -16
- 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/license/LicenseManager.test.ts +160 -0
- package/src/lib/license/LicenseManager.ts +13 -4
- package/src/lib/license/LicenseProvider.tsx +24 -3
- package/src/lib/license/useLicenseManagerState.ts +8 -6
- 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/geometry/Arc2d.test.ts +235 -3
- package/src/lib/primitives/geometry/Arc2d.ts +1 -1
- package/src/lib/primitives/geometry/CubicBezier2d.test.ts +186 -3
- package/src/lib/primitives/geometry/CubicBezier2d.ts +1 -1
- package/src/lib/primitives/geometry/CubicSpline2d.test.ts +160 -3
- package/src/lib/primitives/geometry/Edge2d.test.ts +21 -3
- package/src/lib/primitives/geometry/Edge2d.ts +1 -1
- package/src/lib/primitives/geometry/Ellipse2d.test.ts +243 -3
- package/src/lib/primitives/geometry/Geometry2d.test.ts +553 -1
- package/src/lib/primitives/geometry/Group2d.test.ts +419 -3
- package/src/lib/primitives/geometry/Group2d.ts +81 -34
- package/src/lib/primitives/geometry/Point2d.test.ts +14 -3
- package/src/lib/primitives/geometry/Point2d.ts +1 -1
- package/src/lib/primitives/geometry/Polyline2d.test.ts +207 -0
- package/src/lib/primitives/geometry/Stadium2d.test.ts +191 -3
- 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 +107 -0
- package/src/lib/test/usePassThroughWheelEvents.test.tsx +25 -2
- package/src/lib/utils/deepLinks.test.ts +15 -0
- package/src/lib/utils/deepLinks.ts +7 -1
- package/src/lib/utils/normalizeWheel.test.ts +39 -0
- package/src/lib/utils/normalizeWheel.ts +6 -0
- package/src/lib/utils/rotation.ts +4 -12
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +56 -0
- package/src/lib/utils/sync/TLLocalSyncClient.ts +24 -0
- package/src/lib/utils/sync/alerts.ts +1 -1
- package/src/version.ts +3 -3
- package/src/lib/primitives/geometry/Polyline.test.ts +0 -5
|
@@ -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,
|
|
@@ -74,6 +75,7 @@ import {
|
|
|
74
75
|
import {
|
|
75
76
|
DEFAULT_ANIMATION_OPTIONS,
|
|
76
77
|
DEFAULT_CAMERA_OPTIONS,
|
|
78
|
+
FRAME_MS_60HZ,
|
|
77
79
|
INTERNAL_POINTER_IDS,
|
|
78
80
|
LEFT_MOUSE_BUTTON,
|
|
79
81
|
MIDDLE_MOUSE_BUTTON,
|
|
@@ -83,6 +85,7 @@ import {
|
|
|
83
85
|
import { getOwnerWindow } from "../exports/domUtils.mjs";
|
|
84
86
|
import { exportToSvg } from "../exports/exportToSvg.mjs";
|
|
85
87
|
import { getSvgAsImageWithOptions, trimSvgToContent } from "../exports/getSvgAsImage.mjs";
|
|
88
|
+
import { registerMountedEditor, unregisterMountedEditor } from "../globals/editors.mjs";
|
|
86
89
|
import { tlmenus } from "../globals/menus.mjs";
|
|
87
90
|
import { tltime } from "../globals/time.mjs";
|
|
88
91
|
import { defaultTldrawOptions } from "../options.mjs";
|
|
@@ -91,7 +94,13 @@ import { EASINGS } from "../primitives/easings.mjs";
|
|
|
91
94
|
import { Group2d } from "../primitives/geometry/Group2d.mjs";
|
|
92
95
|
import { intersectPolygonPolygon } from "../primitives/intersect.mjs";
|
|
93
96
|
import { Mat } from "../primitives/Mat.mjs";
|
|
94
|
-
import {
|
|
97
|
+
import {
|
|
98
|
+
HALF_PI,
|
|
99
|
+
approximately,
|
|
100
|
+
areAnglesCompatible,
|
|
101
|
+
clamp,
|
|
102
|
+
pointInPolygon
|
|
103
|
+
} from "../primitives/utils.mjs";
|
|
95
104
|
import { Vec } from "../primitives/Vec.mjs";
|
|
96
105
|
import { areShapesContentEqual } from "../utils/areShapesContentEqual.mjs";
|
|
97
106
|
import { dataUrlToFile } from "../utils/assets.mjs";
|
|
@@ -289,6 +298,10 @@ class Editor extends EventEmitter {
|
|
|
289
298
|
if (!nextPageState) nextPageState = { ...prevPageState };
|
|
290
299
|
nextPageState.editingShapeId = null;
|
|
291
300
|
}
|
|
301
|
+
if (prevPageState.croppingShapeId && shapesNoLongerInPage.has(prevPageState.croppingShapeId)) {
|
|
302
|
+
if (!nextPageState) nextPageState = { ...prevPageState };
|
|
303
|
+
nextPageState.croppingShapeId = null;
|
|
304
|
+
}
|
|
292
305
|
const hintingShapeIds = prevPageState.hintingShapeIds.filter(
|
|
293
306
|
(id) => !shapesNoLongerInPage.has(id)
|
|
294
307
|
);
|
|
@@ -531,10 +544,11 @@ class Editor extends EventEmitter {
|
|
|
531
544
|
this.cancelDoubleClick();
|
|
532
545
|
}
|
|
533
546
|
if (prev?.selectedShapeIds !== next?.selectedShapeIds) {
|
|
547
|
+
const selectedShapeIds = new Set(next.selectedShapeIds);
|
|
534
548
|
const filtered = next.selectedShapeIds.filter((id) => {
|
|
535
549
|
let parentId = this.getShape(id)?.parentId;
|
|
536
550
|
while (isShapeId(parentId)) {
|
|
537
|
-
if (
|
|
551
|
+
if (selectedShapeIds.has(parentId)) {
|
|
538
552
|
return false;
|
|
539
553
|
}
|
|
540
554
|
parentId = this.getShape(parentId)?.parentId;
|
|
@@ -604,9 +618,11 @@ class Editor extends EventEmitter {
|
|
|
604
618
|
this.on("tick", this._flushEventsForTick);
|
|
605
619
|
this.on("mount", () => {
|
|
606
620
|
this._isMounted.set(true);
|
|
621
|
+
registerMountedEditor(this);
|
|
607
622
|
});
|
|
608
623
|
this.on("unmount", () => {
|
|
609
624
|
this._isMounted.set(false);
|
|
625
|
+
unregisterMountedEditor(this);
|
|
610
626
|
});
|
|
611
627
|
this.timers.requestAnimationFrame(() => {
|
|
612
628
|
this._tickManager.start();
|
|
@@ -616,7 +632,10 @@ class Editor extends EventEmitter {
|
|
|
616
632
|
const mode = this.store.props.collaboration.mode;
|
|
617
633
|
this.disposables.add(
|
|
618
634
|
react("update collaboration mode", () => {
|
|
619
|
-
|
|
635
|
+
const isReadonly = mode.get() === "readonly";
|
|
636
|
+
unsafe__withoutCapture(
|
|
637
|
+
() => this._updateInstanceState({ isReadonly }, { history: "ignore" })
|
|
638
|
+
);
|
|
620
639
|
})
|
|
621
640
|
);
|
|
622
641
|
}
|
|
@@ -646,6 +665,14 @@ class Editor extends EventEmitter {
|
|
|
646
665
|
);
|
|
647
666
|
}
|
|
648
667
|
options;
|
|
668
|
+
/**
|
|
669
|
+
* The license manager whose feature flags apply to this editor. Assigned by `<TldrawEditor />`
|
|
670
|
+
* when it creates the editor, so that UI rendered outside the editor tree can resolve the
|
|
671
|
+
* editor's license through the editor instance. Undefined for editors created directly.
|
|
672
|
+
*
|
|
673
|
+
* @internal
|
|
674
|
+
*/
|
|
675
|
+
licenseManager;
|
|
649
676
|
contextId = uniqueId();
|
|
650
677
|
/**
|
|
651
678
|
* The editor's store
|
|
@@ -840,6 +867,7 @@ class Editor extends EventEmitter {
|
|
|
840
867
|
if (this._isMounted.get()) {
|
|
841
868
|
this.emit("unmount");
|
|
842
869
|
}
|
|
870
|
+
unregisterMountedEditor(this);
|
|
843
871
|
this.stopCameraAnimation();
|
|
844
872
|
if (this.getInstanceState().followingUserId) {
|
|
845
873
|
this.stopFollowingUser();
|
|
@@ -965,7 +993,7 @@ class Editor extends EventEmitter {
|
|
|
965
993
|
getShapeUtil(arg) {
|
|
966
994
|
const type = typeof arg === "string" ? arg : arg.type;
|
|
967
995
|
const shapeUtil = getOwnProperty(this.shapeUtils, type);
|
|
968
|
-
|
|
996
|
+
if (!shapeUtil) throw new Error(`No shape util found for type "${type}"`);
|
|
969
997
|
return shapeUtil;
|
|
970
998
|
}
|
|
971
999
|
hasShapeUtil(arg) {
|
|
@@ -1630,7 +1658,8 @@ class Editor extends EventEmitter {
|
|
|
1630
1658
|
if (direction === "next" || direction === "prev") {
|
|
1631
1659
|
const shapeIds = readingOrderShapes.map((shape2) => shape2.id);
|
|
1632
1660
|
const currentIndex = currentShapeId ? shapeIds.indexOf(currentShapeId) : -1;
|
|
1633
|
-
const
|
|
1661
|
+
const startIndex = currentIndex === -1 && direction === "prev" ? 0 : currentIndex;
|
|
1662
|
+
const adjacentIndex = (startIndex + (direction === "next" ? 1 : -1) + shapeIds.length) % shapeIds.length;
|
|
1634
1663
|
adjacentShapeId = shapeIds[adjacentIndex];
|
|
1635
1664
|
} else {
|
|
1636
1665
|
if (!currentShapeId) return;
|
|
@@ -1754,7 +1783,9 @@ class Editor extends EventEmitter {
|
|
|
1754
1783
|
const selectedShapes = this.getSelectedShapes();
|
|
1755
1784
|
if (!selectedShapes.length) return;
|
|
1756
1785
|
const selectedShape = selectedShapes[0];
|
|
1757
|
-
const children =
|
|
1786
|
+
const children = compact(
|
|
1787
|
+
this.getSortedChildIdsForParent(selectedShape.id).map((id) => this.getShape(id))
|
|
1788
|
+
);
|
|
1758
1789
|
const sortedChildren = this._getShapesInReadingOrder(children);
|
|
1759
1790
|
if (sortedChildren.length === 0) return;
|
|
1760
1791
|
this._selectShapesAndZoom([sortedChildren[0].id]);
|
|
@@ -1821,18 +1852,13 @@ class Editor extends EventEmitter {
|
|
|
1821
1852
|
* @internal
|
|
1822
1853
|
*/
|
|
1823
1854
|
getShapesSharedRotation(shapeIds) {
|
|
1824
|
-
let foundFirst = false;
|
|
1825
1855
|
let rotation = 0;
|
|
1826
1856
|
for (let i = 0, n = shapeIds.length; i < n; i++) {
|
|
1827
|
-
const
|
|
1828
|
-
if (
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
}
|
|
1833
|
-
} else {
|
|
1834
|
-
foundFirst = true;
|
|
1835
|
-
rotation = pageTransform.rotation();
|
|
1857
|
+
const pageRotation = this.getShapePageTransform(shapeIds[i]).rotation();
|
|
1858
|
+
if (i === 0) {
|
|
1859
|
+
rotation = pageRotation;
|
|
1860
|
+
} else if (pageRotation !== rotation) {
|
|
1861
|
+
return 0;
|
|
1836
1862
|
}
|
|
1837
1863
|
}
|
|
1838
1864
|
return rotation;
|
|
@@ -1858,11 +1884,9 @@ class Editor extends EventEmitter {
|
|
|
1858
1884
|
return bounds;
|
|
1859
1885
|
}
|
|
1860
1886
|
const boxFromRotatedVertices = Box.FromPoints(
|
|
1861
|
-
shapeIds.flatMap(
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
return pageTransform.applyToPoints(this.getShapeGeometry(id).bounds.corners);
|
|
1865
|
-
}).map((p) => p.rot(-selectionRotation))
|
|
1887
|
+
shapeIds.flatMap(
|
|
1888
|
+
(id) => this.getShapePageTransform(id).applyToPoints(this.getShapeGeometry(id).bounds.corners)
|
|
1889
|
+
).map((p) => p.rot(-selectionRotation))
|
|
1866
1890
|
);
|
|
1867
1891
|
boxFromRotatedVertices.point = boxFromRotatedVertices.point.rot(selectionRotation);
|
|
1868
1892
|
return boxFromRotatedVertices;
|
|
@@ -1873,9 +1897,14 @@ class Editor extends EventEmitter {
|
|
|
1873
1897
|
getSelectionRotatedScreenBounds() {
|
|
1874
1898
|
const bounds = this.getSelectionRotatedPageBounds();
|
|
1875
1899
|
if (!bounds) return void 0;
|
|
1876
|
-
const
|
|
1877
|
-
const zoom = this.
|
|
1878
|
-
return new Box(
|
|
1900
|
+
const screenBounds = this.getViewportScreenBounds();
|
|
1901
|
+
const { x: cx, y: cy, z: zoom } = this.getCamera();
|
|
1902
|
+
return new Box(
|
|
1903
|
+
(bounds.x + cx) * zoom + screenBounds.x,
|
|
1904
|
+
(bounds.y + cy) * zoom + screenBounds.y,
|
|
1905
|
+
bounds.width * zoom,
|
|
1906
|
+
bounds.height * zoom
|
|
1907
|
+
);
|
|
1879
1908
|
}
|
|
1880
1909
|
getFocusedGroupId() {
|
|
1881
1910
|
return this.getCurrentPageState().focusedGroupId ?? this.getCurrentPageId();
|
|
@@ -1976,42 +2005,28 @@ class Editor extends EventEmitter {
|
|
|
1976
2005
|
*/
|
|
1977
2006
|
setEditingShape(shape) {
|
|
1978
2007
|
const id = typeof shape === "string" ? shape : shape?.id ?? null;
|
|
1979
|
-
if (!id)
|
|
2008
|
+
if (id && !this.canEditShape(id)) return this;
|
|
2009
|
+
this.run(() => {
|
|
2010
|
+
const prevEditingShapeId = this.getEditingShapeId();
|
|
2011
|
+
if (prevEditingShapeId) {
|
|
2012
|
+
const prevEditingShape = this.getShape(prevEditingShapeId);
|
|
2013
|
+
if (prevEditingShape) {
|
|
2014
|
+
this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
1980
2017
|
this.run(
|
|
1981
2018
|
() => {
|
|
1982
|
-
const prevEditingShapeId = this.getEditingShapeId();
|
|
1983
|
-
if (prevEditingShapeId) {
|
|
1984
|
-
const prevEditingShape = this.getShape(prevEditingShapeId);
|
|
1985
|
-
if (prevEditingShape) {
|
|
1986
|
-
this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
|
|
1987
|
-
}
|
|
1988
|
-
}
|
|
1989
2019
|
this._updateCurrentPageState({ editingShapeId: null });
|
|
1990
2020
|
this._currentRichTextEditor.set(null);
|
|
2021
|
+
if (!id) return;
|
|
2022
|
+
this.select(id);
|
|
2023
|
+
this._updateCurrentPageState({ editingShapeId: id });
|
|
2024
|
+
const nextEditingShape = this.getShape(id);
|
|
2025
|
+
this.getShapeUtil(nextEditingShape).onEditStart?.(nextEditingShape);
|
|
1991
2026
|
},
|
|
1992
2027
|
{ history: "ignore" }
|
|
1993
2028
|
);
|
|
1994
|
-
|
|
1995
|
-
}
|
|
1996
|
-
if (!this.canEditShape(id)) return this;
|
|
1997
|
-
this.run(
|
|
1998
|
-
() => {
|
|
1999
|
-
const prevEditingShapeId = this.getEditingShapeId();
|
|
2000
|
-
if (prevEditingShapeId) {
|
|
2001
|
-
const prevEditingShape = this.getShape(prevEditingShapeId);
|
|
2002
|
-
if (prevEditingShape) {
|
|
2003
|
-
this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
|
|
2004
|
-
}
|
|
2005
|
-
}
|
|
2006
|
-
this._updateCurrentPageState({ editingShapeId: null });
|
|
2007
|
-
this._currentRichTextEditor.set(null);
|
|
2008
|
-
this.select(id);
|
|
2009
|
-
this._updateCurrentPageState({ editingShapeId: id });
|
|
2010
|
-
const nextEditingShape = this.getShape(id);
|
|
2011
|
-
this.getShapeUtil(nextEditingShape).onEditStart?.(nextEditingShape);
|
|
2012
|
-
},
|
|
2013
|
-
{ history: "ignore" }
|
|
2014
|
-
);
|
|
2029
|
+
});
|
|
2015
2030
|
return this;
|
|
2016
2031
|
}
|
|
2017
2032
|
// Rich text editor
|
|
@@ -2117,19 +2132,12 @@ class Editor extends EventEmitter {
|
|
|
2117
2132
|
* @public
|
|
2118
2133
|
*/
|
|
2119
2134
|
setErasingShapes(shapes) {
|
|
2120
|
-
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
|
|
2135
|
+
const ids = typeof shapes[0] === "string" ? shapes.slice() : shapes.map((shape) => shape.id);
|
|
2121
2136
|
ids.sort();
|
|
2122
2137
|
const erasingShapeIds = this.getErasingShapeIds();
|
|
2123
2138
|
this.run(
|
|
2124
2139
|
() => {
|
|
2125
|
-
if (ids
|
|
2126
|
-
for (let i = 0; i < ids.length; i++) {
|
|
2127
|
-
if (ids[i] !== erasingShapeIds[i]) {
|
|
2128
|
-
this._updateCurrentPageState({ erasingShapeIds: ids });
|
|
2129
|
-
break;
|
|
2130
|
-
}
|
|
2131
|
-
}
|
|
2132
|
-
} else {
|
|
2140
|
+
if (!areArraysShallowEqual(ids, erasingShapeIds)) {
|
|
2133
2141
|
this._updateCurrentPageState({ erasingShapeIds: ids });
|
|
2134
2142
|
}
|
|
2135
2143
|
},
|
|
@@ -2162,6 +2170,7 @@ class Editor extends EventEmitter {
|
|
|
2162
2170
|
if (!_shape) return false;
|
|
2163
2171
|
const util = this.getShapeUtil(_shape);
|
|
2164
2172
|
if (!util.canCrop(_shape)) return false;
|
|
2173
|
+
if (this.getIsReadonly()) return false;
|
|
2165
2174
|
if (this.isShapeOrAncestorLocked(_shape)) return false;
|
|
2166
2175
|
return true;
|
|
2167
2176
|
}
|
|
@@ -2226,11 +2235,11 @@ class Editor extends EventEmitter {
|
|
|
2226
2235
|
const collaborators = this.getCollaborators();
|
|
2227
2236
|
let leaderPresence = null;
|
|
2228
2237
|
while (targetUserId && !visited.includes(targetUserId)) {
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2238
|
+
const nextPresence = collaborators.find((c) => c.userId === targetUserId);
|
|
2239
|
+
if (!nextPresence) break;
|
|
2240
|
+
leaderPresence = nextPresence;
|
|
2241
|
+
targetUserId = nextPresence.followingUserId ?? null;
|
|
2242
|
+
visited.push(nextPresence.userId);
|
|
2234
2243
|
}
|
|
2235
2244
|
return leaderPresence;
|
|
2236
2245
|
}
|
|
@@ -2293,39 +2302,7 @@ class Editor extends EventEmitter {
|
|
|
2293
2302
|
*
|
|
2294
2303
|
* @public */
|
|
2295
2304
|
getInitialZoom() {
|
|
2296
|
-
|
|
2297
|
-
if (!cameraOptions.constraints) return 1;
|
|
2298
|
-
if (cameraOptions.constraints.initialZoom === "default") return 1;
|
|
2299
|
-
const { zx, zy } = getCameraFitXFitY(this, cameraOptions);
|
|
2300
|
-
switch (cameraOptions.constraints.initialZoom) {
|
|
2301
|
-
case "fit-min": {
|
|
2302
|
-
return Math.max(zx, zy);
|
|
2303
|
-
}
|
|
2304
|
-
case "fit-max": {
|
|
2305
|
-
return Math.min(zx, zy);
|
|
2306
|
-
}
|
|
2307
|
-
case "fit-x": {
|
|
2308
|
-
return zx;
|
|
2309
|
-
}
|
|
2310
|
-
case "fit-y": {
|
|
2311
|
-
return zy;
|
|
2312
|
-
}
|
|
2313
|
-
case "fit-min-100": {
|
|
2314
|
-
return Math.min(1, Math.max(zx, zy));
|
|
2315
|
-
}
|
|
2316
|
-
case "fit-max-100": {
|
|
2317
|
-
return Math.min(1, Math.min(zx, zy));
|
|
2318
|
-
}
|
|
2319
|
-
case "fit-x-100": {
|
|
2320
|
-
return Math.min(1, zx);
|
|
2321
|
-
}
|
|
2322
|
-
case "fit-y-100": {
|
|
2323
|
-
return Math.min(1, zy);
|
|
2324
|
-
}
|
|
2325
|
-
default: {
|
|
2326
|
-
throw exhaustiveSwitchError(cameraOptions.constraints.initialZoom);
|
|
2327
|
-
}
|
|
2328
|
-
}
|
|
2305
|
+
return this._getFitZoom(this.getCameraOptions().constraints?.initialZoom ?? "default");
|
|
2329
2306
|
}
|
|
2330
2307
|
/**
|
|
2331
2308
|
* Get the camera's base level for calculating actual zoom levels based on the zoom steps.
|
|
@@ -2337,11 +2314,13 @@ class Editor extends EventEmitter {
|
|
|
2337
2314
|
*
|
|
2338
2315
|
* @public */
|
|
2339
2316
|
getBaseZoom() {
|
|
2317
|
+
return this._getFitZoom(this.getCameraOptions().constraints?.baseZoom ?? "default");
|
|
2318
|
+
}
|
|
2319
|
+
_getFitZoom(fit) {
|
|
2340
2320
|
const cameraOptions = this.getCameraOptions();
|
|
2341
|
-
if (!cameraOptions.constraints) return 1;
|
|
2342
|
-
if (cameraOptions.constraints.baseZoom === "default") return 1;
|
|
2321
|
+
if (!cameraOptions.constraints || fit === "default") return 1;
|
|
2343
2322
|
const { zx, zy } = getCameraFitXFitY(this, cameraOptions);
|
|
2344
|
-
switch (
|
|
2323
|
+
switch (fit) {
|
|
2345
2324
|
case "fit-min": {
|
|
2346
2325
|
return Math.max(zx, zy);
|
|
2347
2326
|
}
|
|
@@ -2367,7 +2346,7 @@ class Editor extends EventEmitter {
|
|
|
2367
2346
|
return Math.min(1, zy);
|
|
2368
2347
|
}
|
|
2369
2348
|
default: {
|
|
2370
|
-
throw exhaustiveSwitchError(
|
|
2349
|
+
throw exhaustiveSwitchError(fit);
|
|
2371
2350
|
}
|
|
2372
2351
|
}
|
|
2373
2352
|
}
|
|
@@ -2401,7 +2380,7 @@ class Editor extends EventEmitter {
|
|
|
2401
2380
|
...this._cameraOptions.__unsafe__getWithoutCapture(),
|
|
2402
2381
|
...opts
|
|
2403
2382
|
});
|
|
2404
|
-
if (next.zoomSteps
|
|
2383
|
+
if (!next.zoomSteps || next.zoomSteps.length < 1) next.zoomSteps = [1];
|
|
2405
2384
|
this._cameraOptions.set(next);
|
|
2406
2385
|
this.setCamera(this.getCamera());
|
|
2407
2386
|
return this;
|
|
@@ -2422,8 +2401,8 @@ class Editor extends EventEmitter {
|
|
|
2422
2401
|
const vsb = this.getViewportScreenBounds();
|
|
2423
2402
|
if (cameraOptions.constraints) {
|
|
2424
2403
|
const { constraints } = cameraOptions;
|
|
2425
|
-
const
|
|
2426
|
-
const
|
|
2404
|
+
const px = Math.min(constraints.padding.x, vsb.w / 2);
|
|
2405
|
+
const py = Math.min(constraints.padding.y, vsb.h / 2);
|
|
2427
2406
|
const bounds = Box.From(cameraOptions.constraints.bounds);
|
|
2428
2407
|
const zx = (vsb.w - px * 2) / bounds.w;
|
|
2429
2408
|
const zy = (vsb.h - py * 2) / bounds.h;
|
|
@@ -2462,12 +2441,12 @@ class Editor extends EventEmitter {
|
|
|
2462
2441
|
break;
|
|
2463
2442
|
}
|
|
2464
2443
|
case "inside": {
|
|
2465
|
-
if (z < zx) x = clamp(x, minX, (vsb.w - px) / z - bounds.w);
|
|
2444
|
+
if (z < zx) x = clamp(x, minX, (vsb.w - px) / z - bounds.w - bounds.x);
|
|
2466
2445
|
else x = clamp(x, minX + freeW, minX);
|
|
2467
2446
|
break;
|
|
2468
2447
|
}
|
|
2469
2448
|
case "outside": {
|
|
2470
|
-
x = clamp(x, px / z - bounds.w, (vsb.w - px) / z);
|
|
2449
|
+
x = clamp(x, px / z - bounds.w - bounds.x, (vsb.w - px) / z - bounds.x);
|
|
2471
2450
|
break;
|
|
2472
2451
|
}
|
|
2473
2452
|
case "free": {
|
|
@@ -2488,12 +2467,12 @@ class Editor extends EventEmitter {
|
|
|
2488
2467
|
break;
|
|
2489
2468
|
}
|
|
2490
2469
|
case "inside": {
|
|
2491
|
-
if (z < zy) y = clamp(y, minY, (vsb.h - py) / z - bounds.h);
|
|
2470
|
+
if (z < zy) y = clamp(y, minY, (vsb.h - py) / z - bounds.h - bounds.y);
|
|
2492
2471
|
else y = clamp(y, minY + freeH, minY);
|
|
2493
2472
|
break;
|
|
2494
2473
|
}
|
|
2495
2474
|
case "outside": {
|
|
2496
|
-
y = clamp(y, py / z - bounds.h, (vsb.h - py) / z);
|
|
2475
|
+
y = clamp(y, py / z - bounds.h - bounds.y, (vsb.h - py) / z - bounds.y);
|
|
2497
2476
|
break;
|
|
2498
2477
|
}
|
|
2499
2478
|
case "free": {
|
|
@@ -2560,14 +2539,16 @@ class Editor extends EventEmitter {
|
|
|
2560
2539
|
setCamera(point, opts) {
|
|
2561
2540
|
const { isLocked } = this._cameraOptions.__unsafe__getWithoutCapture();
|
|
2562
2541
|
if (isLocked && !opts?.force) return this;
|
|
2542
|
+
const _point = Vec.Cast(point);
|
|
2543
|
+
if (!Number.isFinite(_point.x) || !Number.isFinite(_point.y) || !Number.isFinite(_point.z)) {
|
|
2544
|
+
throw Error(
|
|
2545
|
+
`Editor.setCamera: expected finite values, got (${_point.x}, ${_point.y}, ${_point.z}).`
|
|
2546
|
+
);
|
|
2547
|
+
}
|
|
2563
2548
|
this.stopCameraAnimation();
|
|
2564
2549
|
if (this.getInstanceState().followingUserId) {
|
|
2565
2550
|
this.stopFollowingUser();
|
|
2566
2551
|
}
|
|
2567
|
-
const _point = Vec.Cast(point);
|
|
2568
|
-
if (!Number.isFinite(_point.x)) _point.x = 0;
|
|
2569
|
-
if (!Number.isFinite(_point.y)) _point.y = 0;
|
|
2570
|
-
if (_point.z === void 0 || !Number.isFinite(_point.z)) point.z = this.getZoomLevel();
|
|
2571
2552
|
const camera = this.getConstrainedCamera(_point, opts);
|
|
2572
2553
|
if (opts?.animation) {
|
|
2573
2554
|
const { width, height } = this.getViewportScreenBounds();
|
|
@@ -2861,9 +2842,9 @@ class Editor extends EventEmitter {
|
|
|
2861
2842
|
}
|
|
2862
2843
|
const remaining = duration - elapsed;
|
|
2863
2844
|
const t = easing(1 - remaining / duration);
|
|
2864
|
-
const left = start.minX
|
|
2865
|
-
const top = start.minY
|
|
2866
|
-
const right = start.maxX
|
|
2845
|
+
const left = lerp(start.minX, end.minX, t);
|
|
2846
|
+
const top = lerp(start.minY, end.minY, t);
|
|
2847
|
+
const right = lerp(start.maxX, end.maxX, t);
|
|
2867
2848
|
this._setCamera(new Vec(-left, -top, this.getViewportScreenBounds().width / (right - left)), {
|
|
2868
2849
|
force: true
|
|
2869
2850
|
});
|
|
@@ -2941,12 +2922,12 @@ class Editor extends EventEmitter {
|
|
|
2941
2922
|
let newCy = cy + dy;
|
|
2942
2923
|
let newCz = cz;
|
|
2943
2924
|
if (dirZ !== 0) {
|
|
2944
|
-
newCz = cz * (
|
|
2925
|
+
newCz = cz * Math.exp(dirZ * currentSpeed * elapsed);
|
|
2945
2926
|
const center = this.getViewportScreenCenter();
|
|
2946
2927
|
newCx += center.x / newCz - center.x / cz;
|
|
2947
2928
|
newCy += center.y / newCz - center.y / cz;
|
|
2948
2929
|
}
|
|
2949
|
-
currentSpeed *= 1 - friction;
|
|
2930
|
+
currentSpeed *= (1 - friction) ** (elapsed / FRAME_MS_60HZ);
|
|
2950
2931
|
if (currentSpeed < speedThreshold) {
|
|
2951
2932
|
cancel();
|
|
2952
2933
|
} else {
|
|
@@ -3379,12 +3360,12 @@ class Editor extends EventEmitter {
|
|
|
3379
3360
|
const renderingShapes = [];
|
|
3380
3361
|
let nextIndex = this.options.maxShapesPerPage * 2;
|
|
3381
3362
|
let nextBackgroundIndex = this.options.maxShapesPerPage;
|
|
3382
|
-
const erasingShapeIds = this.getErasingShapeIds();
|
|
3363
|
+
const erasingShapeIds = new Set(this.getErasingShapeIds());
|
|
3383
3364
|
const addShapeById = (id, opacity, isAncestorErasing) => {
|
|
3384
3365
|
const shape = this.getShape(id);
|
|
3385
3366
|
if (!shape) return;
|
|
3386
3367
|
if (this.isShapeHidden(shape)) {
|
|
3387
|
-
const isErasing = isAncestorErasing || erasingShapeIds.
|
|
3368
|
+
const isErasing = isAncestorErasing || erasingShapeIds.has(id);
|
|
3388
3369
|
for (const childId of this.getSortedChildIdsForParent(id)) {
|
|
3389
3370
|
addShapeById(childId, opacity, isErasing);
|
|
3390
3371
|
}
|
|
@@ -3394,7 +3375,7 @@ class Editor extends EventEmitter {
|
|
|
3394
3375
|
let isShapeErasing = false;
|
|
3395
3376
|
const util = this.getShapeUtil(shape);
|
|
3396
3377
|
if (useEditorState) {
|
|
3397
|
-
isShapeErasing = !isAncestorErasing && erasingShapeIds.
|
|
3378
|
+
isShapeErasing = !isAncestorErasing && erasingShapeIds.has(id);
|
|
3398
3379
|
if (isShapeErasing) {
|
|
3399
3380
|
opacity *= 0.32;
|
|
3400
3381
|
}
|
|
@@ -3986,10 +3967,8 @@ class Editor extends EventEmitter {
|
|
|
3986
3967
|
}
|
|
3987
3968
|
_getShapePageBoundsCache() {
|
|
3988
3969
|
return this.store.createComputedCache("pageBoundsCache", (shape) => {
|
|
3989
|
-
const pageTransform = this.getShapePageTransform(shape);
|
|
3990
|
-
if (!pageTransform) return void 0;
|
|
3991
3970
|
return Box.FromPoints(
|
|
3992
|
-
|
|
3971
|
+
this.getShapePageTransform(shape).applyToPoints(this.getShapeGeometry(shape).boundsVertices)
|
|
3993
3972
|
);
|
|
3994
3973
|
});
|
|
3995
3974
|
}
|
|
@@ -4107,7 +4086,9 @@ class Editor extends EventEmitter {
|
|
|
4107
4086
|
if (pageMask) {
|
|
4108
4087
|
if (pageMask.length === 0) return void 0;
|
|
4109
4088
|
const { corners } = pageBounds;
|
|
4110
|
-
if (corners.every((p, i) =>
|
|
4089
|
+
if (pageMask.length === corners.length && corners.every((p, i) => Vec.Equals(p, pageMask[i]))) {
|
|
4090
|
+
return pageBounds.clone();
|
|
4091
|
+
}
|
|
4111
4092
|
const intersection = intersectPolygonPolygon(pageMask, corners);
|
|
4112
4093
|
if (!intersection) return;
|
|
4113
4094
|
return Box.FromPoints(intersection);
|
|
@@ -4331,23 +4312,22 @@ class Editor extends EventEmitter {
|
|
|
4331
4312
|
let inMarginClosestToEdgeHit = null;
|
|
4332
4313
|
const searchMargin = Math.max(innerMargin, outerMargin, this.getHitTestMargin());
|
|
4333
4314
|
const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, searchMargin);
|
|
4334
|
-
const shapesToCheck =
|
|
4335
|
-
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) return false;
|
|
4336
|
-
if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group"))
|
|
4337
|
-
return false;
|
|
4338
|
-
const pageMask = this.getShapeMask(shape);
|
|
4339
|
-
if (pageMask && !pointInPolygon(point, pageMask)) return false;
|
|
4340
|
-
if (filter && !filter(shape)) return false;
|
|
4341
|
-
return true;
|
|
4342
|
-
});
|
|
4315
|
+
const shapesToCheck = opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted();
|
|
4343
4316
|
for (let i = shapesToCheck.length - 1; i >= 0; i--) {
|
|
4344
4317
|
const shape = shapesToCheck[i];
|
|
4318
|
+
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
|
|
4319
|
+
if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group")) {
|
|
4320
|
+
continue;
|
|
4321
|
+
}
|
|
4322
|
+
const pageMask = this.getShapeMask(shape);
|
|
4323
|
+
if (pageMask && !pointInPolygon(point, pageMask)) continue;
|
|
4324
|
+
if (filter && !filter(shape)) continue;
|
|
4345
4325
|
const geometry = this.getShapeGeometry(shape);
|
|
4346
4326
|
const isGroup = geometry instanceof Group2d;
|
|
4347
4327
|
const pointInShapeSpace = this.getPointInShapeSpace(shape, point);
|
|
4348
4328
|
const shapeUtil = this.getShapeUtil(shape);
|
|
4349
4329
|
const isShapeFrameLike = this.isShapeFrameLike(shape);
|
|
4350
|
-
if (isShapeFrameLike || (this.isShapeOfType(shape, "note") || this.isShapeOfType(shape, "arrow") || this.isShapeOfType(shape, "geo") && shape.props.fill === "none") && shapeUtil.getText(shape)?.trim()) {
|
|
4330
|
+
if (isGroup && (isShapeFrameLike || (this.isShapeOfType(shape, "note") || this.isShapeOfType(shape, "arrow") || this.isShapeOfType(shape, "geo") && shape.props.fill === "none") && shapeUtil.getText(shape)?.trim())) {
|
|
4351
4331
|
for (const childGeometry of geometry.children) {
|
|
4352
4332
|
if (childGeometry.isLabel && childGeometry.isPointInBounds(pointInShapeSpace)) {
|
|
4353
4333
|
return shape;
|
|
@@ -4446,11 +4426,15 @@ class Editor extends EventEmitter {
|
|
|
4446
4426
|
getShapesAtPoint(point, opts = {}) {
|
|
4447
4427
|
const margin = opts.margin ?? 0;
|
|
4448
4428
|
const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, margin);
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4429
|
+
const sorted = this.getCurrentPageShapesSorted();
|
|
4430
|
+
const result = [];
|
|
4431
|
+
for (let i = sorted.length - 1; i >= 0; i--) {
|
|
4432
|
+
const shape = sorted[i];
|
|
4433
|
+
if (this.isShapeHidden(shape)) continue;
|
|
4434
|
+
if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
|
|
4435
|
+
if (this.isPointInShape(shape, point, opts)) result.push(shape);
|
|
4436
|
+
}
|
|
4437
|
+
return result;
|
|
4454
4438
|
}
|
|
4455
4439
|
/**
|
|
4456
4440
|
* Get shape IDs within the given bounds.
|
|
@@ -4535,9 +4519,7 @@ class Editor extends EventEmitter {
|
|
|
4535
4519
|
const freshShape = this.getShape(id);
|
|
4536
4520
|
if (!freshShape) return new Vec(0, 0);
|
|
4537
4521
|
if (isPageId(freshShape.parentId)) return Vec.From(point);
|
|
4538
|
-
|
|
4539
|
-
if (!parentTransform) return Vec.From(point);
|
|
4540
|
-
return parentTransform.clone().invert().applyToPoint(point);
|
|
4522
|
+
return this.getShapePageTransform(freshShape.parentId).clone().invert().applyToPoint(point);
|
|
4541
4523
|
}
|
|
4542
4524
|
getCurrentPageShapes() {
|
|
4543
4525
|
return Array.from(this.getCurrentPageShapeIds(), (id) => this.store.get(id));
|
|
@@ -4649,23 +4631,7 @@ class Editor extends EventEmitter {
|
|
|
4649
4631
|
* @public
|
|
4650
4632
|
*/
|
|
4651
4633
|
isShapeInPage(shape, pageId = this.getCurrentPageId()) {
|
|
4652
|
-
|
|
4653
|
-
const shapeToCheck = this.getShape(id);
|
|
4654
|
-
if (!shapeToCheck) return false;
|
|
4655
|
-
let shapeIsInPage = false;
|
|
4656
|
-
if (shapeToCheck.parentId === pageId) {
|
|
4657
|
-
shapeIsInPage = true;
|
|
4658
|
-
} else {
|
|
4659
|
-
let parent = this.getShape(shapeToCheck.parentId);
|
|
4660
|
-
isInPageSearch: while (parent) {
|
|
4661
|
-
if (parent.parentId === pageId) {
|
|
4662
|
-
shapeIsInPage = true;
|
|
4663
|
-
break isInPageSearch;
|
|
4664
|
-
}
|
|
4665
|
-
parent = this.getShape(parent.parentId);
|
|
4666
|
-
}
|
|
4667
|
-
}
|
|
4668
|
-
return shapeIsInPage;
|
|
4634
|
+
return this.getAncestorPageId(shape) === pageId;
|
|
4669
4635
|
}
|
|
4670
4636
|
/**
|
|
4671
4637
|
* Get the id of the containing page for a given shape.
|
|
@@ -4746,10 +4712,7 @@ class Editor extends EventEmitter {
|
|
|
4746
4712
|
for (let i = 0; i < shapesToReparent.length; i++) {
|
|
4747
4713
|
const shape = shapesToReparent[i];
|
|
4748
4714
|
const pageTransform = this.getShapePageTransform(shape);
|
|
4749
|
-
|
|
4750
|
-
const pagePoint = pageTransform.point();
|
|
4751
|
-
if (!pagePoint) continue;
|
|
4752
|
-
const newPoint = invertedParentTransform.applyToPoint(pagePoint);
|
|
4715
|
+
const newPoint = invertedParentTransform.applyToPoint(pageTransform.point());
|
|
4753
4716
|
const newRotation = pageTransform.rotation() - parentPageRotation;
|
|
4754
4717
|
if (shape.id === parentId) {
|
|
4755
4718
|
throw Error("Attempted to reparent a shape to itself!");
|
|
@@ -4838,7 +4801,7 @@ class Editor extends EventEmitter {
|
|
|
4838
4801
|
*/
|
|
4839
4802
|
getShapeAndDescendantIds(ids) {
|
|
4840
4803
|
const shapeIds = /* @__PURE__ */ new Set();
|
|
4841
|
-
for (const shape of ids.map((id) => this.getShape(id)).sort(sortByIndex)) {
|
|
4804
|
+
for (const shape of compact(ids.map((id) => this.getShape(id))).sort(sortByIndex)) {
|
|
4842
4805
|
shapeIds.add(shape.id);
|
|
4843
4806
|
this.visitDescendants(shape, (descendantId) => {
|
|
4844
4807
|
shapeIds.add(descendantId);
|
|
@@ -4860,11 +4823,12 @@ class Editor extends EventEmitter {
|
|
|
4860
4823
|
const draggingShapes = compact(droppingShapes.map((s) => this.getShape(s))).filter(
|
|
4861
4824
|
(s) => !s.isLocked && !this.isShapeHidden(s)
|
|
4862
4825
|
);
|
|
4826
|
+
const excludedIds = this.getShapeAndDescendantIds(draggingShapes.map((s) => s.id));
|
|
4863
4827
|
const maybeDraggingOverShapes = this.getShapesAtPoint(point, {
|
|
4864
4828
|
hitInside: true,
|
|
4865
4829
|
margin: 0
|
|
4866
4830
|
}).filter(
|
|
4867
|
-
(s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !
|
|
4831
|
+
(s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !excludedIds.has(s.id)
|
|
4868
4832
|
);
|
|
4869
4833
|
for (const maybeDraggingOverShape of maybeDraggingOverShapes) {
|
|
4870
4834
|
const shapeUtil = this.getShapeUtil(maybeDraggingOverShape);
|
|
@@ -5117,8 +5081,7 @@ class Editor extends EventEmitter {
|
|
|
5117
5081
|
for (const id of ids) {
|
|
5118
5082
|
const shape = this.getShape(id);
|
|
5119
5083
|
const localDelta = Vec.From(offset);
|
|
5120
|
-
|
|
5121
|
-
if (parentTransform) localDelta.rot(-parentTransform.rotation());
|
|
5084
|
+
localDelta.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5122
5085
|
changes.push(this.getChangesToTranslateShape(shape, localDelta.add(shape)));
|
|
5123
5086
|
}
|
|
5124
5087
|
this.updateShapes(changes);
|
|
@@ -5173,7 +5136,7 @@ class Editor extends EventEmitter {
|
|
|
5173
5136
|
if (!originalShape) continue;
|
|
5174
5137
|
let ox = 0;
|
|
5175
5138
|
let oy = 0;
|
|
5176
|
-
if (offset && initialIds.has(originalId)) {
|
|
5139
|
+
if (offset && initialIds.has(originalId) && !shapeIdSet.has(originalShape.parentId)) {
|
|
5177
5140
|
const parentTransform = this.getShapeParentTransform(originalShape);
|
|
5178
5141
|
const vec = new Vec(offset.x, offset.y).rot(-parentTransform.rotation());
|
|
5179
5142
|
ox = vec.x;
|
|
@@ -5287,26 +5250,17 @@ class Editor extends EventEmitter {
|
|
|
5287
5250
|
toggleLock(shapes) {
|
|
5288
5251
|
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
|
|
5289
5252
|
if (this.getIsReadonly() || ids.length === 0) return this;
|
|
5290
|
-
let allLocked = true
|
|
5253
|
+
let allLocked = true;
|
|
5291
5254
|
const shapesToToggle = [];
|
|
5292
5255
|
for (const id of ids) {
|
|
5293
5256
|
const shape = this.getShape(id);
|
|
5294
5257
|
if (shape) {
|
|
5295
5258
|
shapesToToggle.push(shape);
|
|
5296
|
-
if (shape.isLocked)
|
|
5297
|
-
allUnlocked = false;
|
|
5298
|
-
} else {
|
|
5299
|
-
allLocked = false;
|
|
5300
|
-
}
|
|
5259
|
+
if (!shape.isLocked) allLocked = false;
|
|
5301
5260
|
}
|
|
5302
5261
|
}
|
|
5303
5262
|
this.run(() => {
|
|
5304
|
-
if (
|
|
5305
|
-
this.updateShapes(
|
|
5306
|
-
shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: true }))
|
|
5307
|
-
);
|
|
5308
|
-
this.setSelectedShapes([]);
|
|
5309
|
-
} else if (allLocked) {
|
|
5263
|
+
if (allLocked) {
|
|
5310
5264
|
this.updateShapes(
|
|
5311
5265
|
shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: false }))
|
|
5312
5266
|
);
|
|
@@ -5314,6 +5268,7 @@ class Editor extends EventEmitter {
|
|
|
5314
5268
|
this.updateShapes(
|
|
5315
5269
|
shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: true }))
|
|
5316
5270
|
);
|
|
5271
|
+
this.setSelectedShapes([]);
|
|
5317
5272
|
}
|
|
5318
5273
|
});
|
|
5319
5274
|
return this;
|
|
@@ -5424,9 +5379,10 @@ class Editor extends EventEmitter {
|
|
|
5424
5379
|
const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
|
|
5425
5380
|
let freshShapes = compact(ids.map((id) => this.getShape(id)));
|
|
5426
5381
|
if (opts?.filterAxisAligned) {
|
|
5427
|
-
freshShapes = freshShapes.filter(
|
|
5428
|
-
|
|
5429
|
-
|
|
5382
|
+
freshShapes = freshShapes.filter((s) => {
|
|
5383
|
+
const remainder = Math.abs(this.getShapePageTransform(s).rotation() % HALF_PI);
|
|
5384
|
+
return Math.min(remainder, HALF_PI - remainder) < 1e-9;
|
|
5385
|
+
});
|
|
5430
5386
|
}
|
|
5431
5387
|
const clusters = [];
|
|
5432
5388
|
const allBounds = [];
|
|
@@ -5591,9 +5547,9 @@ class Editor extends EventEmitter {
|
|
|
5591
5547
|
dim = "height";
|
|
5592
5548
|
}
|
|
5593
5549
|
let shapeGap = 0;
|
|
5550
|
+
shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
|
|
5594
5551
|
if (_gap === 0) {
|
|
5595
5552
|
const gaps = {};
|
|
5596
|
-
shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
|
|
5597
5553
|
for (let i = 0; i < len - 1; i++) {
|
|
5598
5554
|
const currCluster = shapeClustersToStack[i];
|
|
5599
5555
|
const nextCluster = shapeClustersToStack[i + 1];
|
|
@@ -5631,8 +5587,7 @@ class Editor extends EventEmitter {
|
|
|
5631
5587
|
const shapeDelta = delta.clone();
|
|
5632
5588
|
const parent = this.getShapeParent(shape);
|
|
5633
5589
|
if (parent) {
|
|
5634
|
-
|
|
5635
|
-
if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
|
|
5590
|
+
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5636
5591
|
}
|
|
5637
5592
|
shapeDelta.add(shape);
|
|
5638
5593
|
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
@@ -5670,7 +5625,7 @@ class Editor extends EventEmitter {
|
|
|
5670
5625
|
}
|
|
5671
5626
|
const commonBounds = Box.Common(allBounds);
|
|
5672
5627
|
const maxWidth = commonBounds.width;
|
|
5673
|
-
shapeClustersToPack.sort((a, b) =>
|
|
5628
|
+
shapeClustersToPack.sort((a, b) => b.pageBounds.width - a.pageBounds.width).sort((a, b) => b.pageBounds.height - a.pageBounds.height);
|
|
5674
5629
|
const startWidth = Math.max(Math.ceil(Math.sqrt(area / 0.95)), maxWidth);
|
|
5675
5630
|
const spaces = [new Box(commonBounds.x, commonBounds.y, startWidth, Infinity)];
|
|
5676
5631
|
let width = 0;
|
|
@@ -5718,8 +5673,7 @@ class Editor extends EventEmitter {
|
|
|
5718
5673
|
const shapeDelta = delta.clone();
|
|
5719
5674
|
const parent = this.getShapeParent(shape);
|
|
5720
5675
|
if (parent) {
|
|
5721
|
-
|
|
5722
|
-
if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
|
|
5676
|
+
shapeDelta.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5723
5677
|
}
|
|
5724
5678
|
shapeDelta.add(shape);
|
|
5725
5679
|
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
@@ -5785,8 +5739,7 @@ class Editor extends EventEmitter {
|
|
|
5785
5739
|
const shapeDelta = delta.clone();
|
|
5786
5740
|
const parent = this.getShapeParent(shape);
|
|
5787
5741
|
if (parent) {
|
|
5788
|
-
|
|
5789
|
-
if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
|
|
5742
|
+
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5790
5743
|
}
|
|
5791
5744
|
shapeDelta.add(shape);
|
|
5792
5745
|
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
@@ -5860,8 +5813,7 @@ class Editor extends EventEmitter {
|
|
|
5860
5813
|
const shapeDelta = delta.clone();
|
|
5861
5814
|
const parent = this.getShapeParent(shape);
|
|
5862
5815
|
if (parent) {
|
|
5863
|
-
|
|
5864
|
-
if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
|
|
5816
|
+
shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
|
|
5865
5817
|
}
|
|
5866
5818
|
shapeDelta.add(shape);
|
|
5867
5819
|
changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
|
|
@@ -5916,8 +5868,7 @@ class Editor extends EventEmitter {
|
|
|
5916
5868
|
scale[val] = commonBounds[dim] / pageBounds[dim];
|
|
5917
5869
|
for (const shape of shapes2) {
|
|
5918
5870
|
const shapeLocalOffset = localOffset.clone();
|
|
5919
|
-
|
|
5920
|
-
if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
|
|
5871
|
+
shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5921
5872
|
shapeLocalOffset.add(shape);
|
|
5922
5873
|
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5923
5874
|
this.updateShape(changes);
|
|
@@ -5973,8 +5924,7 @@ class Editor extends EventEmitter {
|
|
|
5973
5924
|
);
|
|
5974
5925
|
for (const shape of shapes2) {
|
|
5975
5926
|
const shapeLocalOffset = localOffset.clone();
|
|
5976
|
-
|
|
5977
|
-
if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
|
|
5927
|
+
shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
|
|
5978
5928
|
shapeLocalOffset.add(shape);
|
|
5979
5929
|
const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
|
|
5980
5930
|
this.updateShape(changes);
|
|
@@ -6023,9 +5973,7 @@ class Editor extends EventEmitter {
|
|
|
6023
5973
|
const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center;
|
|
6024
5974
|
if (!scaleOrigin) return null;
|
|
6025
5975
|
const pageTransform = opts.initialPageTransform ? Mat.Cast(opts.initialPageTransform) : this.getShapePageTransform(id);
|
|
6026
|
-
if (!pageTransform) return null;
|
|
6027
5976
|
const pageRotation = pageTransform.rotation();
|
|
6028
|
-
if (pageRotation == null) return null;
|
|
6029
5977
|
const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation;
|
|
6030
5978
|
const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds;
|
|
6031
5979
|
if (!initialBounds) return null;
|
|
@@ -6176,7 +6124,6 @@ class Editor extends EventEmitter {
|
|
|
6176
6124
|
const currentLocalBounds = this.getShapeGeometry(id).bounds;
|
|
6177
6125
|
const currentPageCenter = Mat.applyToPoint(pageTransform, currentLocalBounds.center);
|
|
6178
6126
|
const shapePageTransformOrigin = pageTransform.point();
|
|
6179
|
-
if (!currentPageCenter || !shapePageTransformOrigin) return this;
|
|
6180
6127
|
const pageDelta = Vec.Sub(postScaleShapePageCenter, currentPageCenter);
|
|
6181
6128
|
const postScaleShapePagePoint = Vec.Add(shapePageTransformOrigin, pageDelta);
|
|
6182
6129
|
const { x, y } = this.getPointInParentSpace(id, postScaleShapePagePoint);
|
|
@@ -6435,10 +6382,10 @@ class Editor extends EventEmitter {
|
|
|
6435
6382
|
if (animationIdForShape !== animationId) continue;
|
|
6436
6383
|
updates.push({
|
|
6437
6384
|
...end,
|
|
6438
|
-
x: start.x
|
|
6439
|
-
y: start.y
|
|
6440
|
-
opacity: start.opacity
|
|
6441
|
-
rotation: start.rotation
|
|
6385
|
+
x: lerp(start.x, end.x, t),
|
|
6386
|
+
y: lerp(start.y, end.y, t),
|
|
6387
|
+
opacity: lerp(start.opacity, end.opacity, t),
|
|
6388
|
+
rotation: lerp(start.rotation, end.rotation, t),
|
|
6442
6389
|
props: this.getShapeUtil(end).getInterpolatedProps?.(start, end, t) ?? end.props
|
|
6443
6390
|
});
|
|
6444
6391
|
}
|
|
@@ -6564,7 +6511,7 @@ class Editor extends EventEmitter {
|
|
|
6564
6511
|
* @public
|
|
6565
6512
|
*/
|
|
6566
6513
|
updateShapes(partials) {
|
|
6567
|
-
const compactedPartials =
|
|
6514
|
+
const compactedPartials = [];
|
|
6568
6515
|
for (let i = 0, n = partials.length; i < n; i++) {
|
|
6569
6516
|
const partial = partials[i];
|
|
6570
6517
|
if (!partial) continue;
|
|
@@ -6635,28 +6582,32 @@ class Editor extends EventEmitter {
|
|
|
6635
6582
|
}
|
|
6636
6583
|
/* --------------------- Styles --------------------- */
|
|
6637
6584
|
/**
|
|
6638
|
-
*
|
|
6585
|
+
* Groups have no styles of their own: a style read or write on a selection applies to the
|
|
6586
|
+
* non-group shapes beneath each group, however deeply nested. Returns those shapes.
|
|
6639
6587
|
*
|
|
6640
6588
|
* @internal
|
|
6641
6589
|
*/
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
if (
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6590
|
+
_getStyleableShapes(shapes) {
|
|
6591
|
+
const result = [];
|
|
6592
|
+
const visit = (shape) => {
|
|
6593
|
+
if (this.isShapeOfType(shape, "group")) {
|
|
6594
|
+
for (const childId of this.getSortedChildIdsForParent(shape.id)) {
|
|
6595
|
+
const child = this.getShape(childId);
|
|
6596
|
+
if (child) visit(child);
|
|
6597
|
+
}
|
|
6598
|
+
} else {
|
|
6599
|
+
result.push(shape);
|
|
6652
6600
|
}
|
|
6653
|
-
}
|
|
6601
|
+
};
|
|
6602
|
+
for (const shape of shapes) visit(shape);
|
|
6603
|
+
return result;
|
|
6654
6604
|
}
|
|
6655
6605
|
_getSelectionSharedStyles() {
|
|
6656
|
-
const selectedShapes = this.getSelectedShapes();
|
|
6657
6606
|
const sharedStyles = new SharedStyleMap();
|
|
6658
|
-
for (const
|
|
6659
|
-
|
|
6607
|
+
for (const shape of this._getStyleableShapes(this.getSelectedShapes())) {
|
|
6608
|
+
for (const [style, propKey] of this.styleProps[shape.type]) {
|
|
6609
|
+
sharedStyles.applyValue(style, getOwnProperty(shape.props, propKey));
|
|
6610
|
+
}
|
|
6660
6611
|
}
|
|
6661
6612
|
return sharedStyles;
|
|
6662
6613
|
}
|
|
@@ -6688,38 +6639,16 @@ class Editor extends EventEmitter {
|
|
|
6688
6639
|
const styles = new SharedStyleMap();
|
|
6689
6640
|
if (!currentTool) return styles;
|
|
6690
6641
|
if (currentTool.shapeType) {
|
|
6691
|
-
|
|
6692
|
-
|
|
6693
|
-
if (style.id === "tldraw:color") continue;
|
|
6694
|
-
styles.applyValue(style, this.getStyleForNextShape(style));
|
|
6695
|
-
}
|
|
6696
|
-
} else {
|
|
6697
|
-
for (const style of this.styleProps[currentTool.shapeType].keys()) {
|
|
6698
|
-
styles.applyValue(style, this.getStyleForNextShape(style));
|
|
6699
|
-
}
|
|
6642
|
+
for (const style of this.styleProps[currentTool.shapeType].keys()) {
|
|
6643
|
+
styles.applyValue(style, this.getStyleForNextShape(style));
|
|
6700
6644
|
}
|
|
6701
6645
|
}
|
|
6702
6646
|
return styles;
|
|
6703
6647
|
}
|
|
6704
6648
|
getSharedOpacity() {
|
|
6705
6649
|
if (this.isIn("select") && this.getSelectedShapeIds().length > 0) {
|
|
6706
|
-
const shapesToCheck = [];
|
|
6707
|
-
const addShape = (shapeId) => {
|
|
6708
|
-
const shape = this.getShape(shapeId);
|
|
6709
|
-
if (!shape) return;
|
|
6710
|
-
if (this.isShapeOfType(shape, "group")) {
|
|
6711
|
-
for (const childId of this.getSortedChildIdsForParent(shape.id)) {
|
|
6712
|
-
addShape(childId);
|
|
6713
|
-
}
|
|
6714
|
-
} else {
|
|
6715
|
-
shapesToCheck.push(shape);
|
|
6716
|
-
}
|
|
6717
|
-
};
|
|
6718
|
-
for (const shapeId of this.getSelectedShapeIds()) {
|
|
6719
|
-
addShape(shapeId);
|
|
6720
|
-
}
|
|
6721
6650
|
let opacity = null;
|
|
6722
|
-
for (const shape of
|
|
6651
|
+
for (const shape of this._getStyleableShapes(this.getSelectedShapes())) {
|
|
6723
6652
|
if (opacity === null) {
|
|
6724
6653
|
opacity = shape.opacity;
|
|
6725
6654
|
} else if (opacity !== shape.opacity) {
|
|
@@ -6758,28 +6687,12 @@ class Editor extends EventEmitter {
|
|
|
6758
6687
|
setOpacityForSelectedShapes(opacity) {
|
|
6759
6688
|
const selectedShapes = this.getSelectedShapes();
|
|
6760
6689
|
if (selectedShapes.length > 0) {
|
|
6761
|
-
const shapesToUpdate = [];
|
|
6762
|
-
const addShapeById = (shape) => {
|
|
6763
|
-
if (this.isShapeOfType(shape, "group")) {
|
|
6764
|
-
const childIds = this.getSortedChildIdsForParent(shape);
|
|
6765
|
-
for (const childId of childIds) {
|
|
6766
|
-
addShapeById(this.getShape(childId));
|
|
6767
|
-
}
|
|
6768
|
-
} else {
|
|
6769
|
-
shapesToUpdate.push(shape);
|
|
6770
|
-
}
|
|
6771
|
-
};
|
|
6772
|
-
for (const id of selectedShapes) {
|
|
6773
|
-
addShapeById(id);
|
|
6774
|
-
}
|
|
6775
6690
|
this.updateShapes(
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
};
|
|
6782
|
-
})
|
|
6691
|
+
this._getStyleableShapes(selectedShapes).map((shape) => ({
|
|
6692
|
+
id: shape.id,
|
|
6693
|
+
type: shape.type,
|
|
6694
|
+
opacity
|
|
6695
|
+
}))
|
|
6783
6696
|
);
|
|
6784
6697
|
}
|
|
6785
6698
|
return this;
|
|
@@ -6824,33 +6737,17 @@ class Editor extends EventEmitter {
|
|
|
6824
6737
|
const selectedShapes = this.getSelectedShapes();
|
|
6825
6738
|
if (selectedShapes.length > 0) {
|
|
6826
6739
|
const updates = [];
|
|
6827
|
-
const
|
|
6828
|
-
|
|
6829
|
-
|
|
6830
|
-
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6835
|
-
const stylePropKey = this.styleProps[shape.type].get(style);
|
|
6836
|
-
if (stylePropKey) {
|
|
6837
|
-
const shapePartial = {
|
|
6838
|
-
id: shape.id,
|
|
6839
|
-
type: shape.type,
|
|
6840
|
-
props: { [stylePropKey]: value }
|
|
6841
|
-
};
|
|
6842
|
-
updates.push({
|
|
6843
|
-
util,
|
|
6844
|
-
originalShape: shape,
|
|
6845
|
-
updatePartial: shapePartial
|
|
6846
|
-
});
|
|
6847
|
-
}
|
|
6740
|
+
for (const shape of this._getStyleableShapes(selectedShapes)) {
|
|
6741
|
+
const stylePropKey = this.styleProps[shape.type].get(style);
|
|
6742
|
+
if (stylePropKey) {
|
|
6743
|
+
updates.push({
|
|
6744
|
+
id: shape.id,
|
|
6745
|
+
type: shape.type,
|
|
6746
|
+
props: { [stylePropKey]: value }
|
|
6747
|
+
});
|
|
6848
6748
|
}
|
|
6849
|
-
};
|
|
6850
|
-
for (const shape of selectedShapes) {
|
|
6851
|
-
addShapeById(shape);
|
|
6852
6749
|
}
|
|
6853
|
-
this.updateShapes(updates
|
|
6750
|
+
this.updateShapes(updates);
|
|
6854
6751
|
}
|
|
6855
6752
|
return this;
|
|
6856
6753
|
}
|
|
@@ -7246,7 +7143,6 @@ class Editor extends EventEmitter {
|
|
|
7246
7143
|
if (shapeIdMap.has(newShape.parentId)) {
|
|
7247
7144
|
newShape.parentId = shapeIdMap.get(oldShape.parentId);
|
|
7248
7145
|
} else {
|
|
7249
|
-
rootShapeIds.push(newShape.id);
|
|
7250
7146
|
newShape.index = index;
|
|
7251
7147
|
index = getIndexAbove(index);
|
|
7252
7148
|
}
|
|
@@ -7271,8 +7167,11 @@ class Editor extends EventEmitter {
|
|
|
7271
7167
|
continue;
|
|
7272
7168
|
}
|
|
7273
7169
|
if (asset.type === "image" && asset.props.src?.startsWith("data:image") || asset.type === "video" && asset.props.src?.startsWith("data:video")) {
|
|
7274
|
-
assetsToUpdate.push(
|
|
7275
|
-
|
|
7170
|
+
assetsToUpdate.push(asset);
|
|
7171
|
+
const assetWithoutSrc = structuredClone(asset);
|
|
7172
|
+
assetWithoutSrc.props.src = null;
|
|
7173
|
+
assetsToCreate.push(assetWithoutSrc);
|
|
7174
|
+
continue;
|
|
7276
7175
|
}
|
|
7277
7176
|
assetsToCreate.push(asset);
|
|
7278
7177
|
}
|
|
@@ -8099,7 +7998,7 @@ class Editor extends EventEmitter {
|
|
|
8099
7998
|
if (info.type === "misc") {
|
|
8100
7999
|
if (info.name === "cancel" || info.name === "complete") {
|
|
8101
8000
|
this.inputs.setIsDragging(false);
|
|
8102
|
-
if (this.inputs.getIsPanning()) {
|
|
8001
|
+
if (this.inputs.getIsPanning() && !this.inputs.keys.has("Space")) {
|
|
8103
8002
|
this.inputs.setIsPanning(false);
|
|
8104
8003
|
this.inputs.setIsSpacebarPanning(false);
|
|
8105
8004
|
this.setCursor({ type: this._prevCursor, rotation: 0 });
|
|
@@ -8851,10 +8750,9 @@ function withIsolatedShapes(editor, shapeIds, callback) {
|
|
|
8851
8750
|
}
|
|
8852
8751
|
function getCameraFitXFitY(editor, cameraOptions) {
|
|
8853
8752
|
if (!cameraOptions.constraints) throw Error("Should have constraints here");
|
|
8854
|
-
const {
|
|
8855
|
-
padding: { x: px, y: py }
|
|
8856
|
-
} = cameraOptions.constraints;
|
|
8857
8753
|
const vsb = editor.getViewportScreenBounds();
|
|
8754
|
+
const px = Math.min(cameraOptions.constraints.padding.x, vsb.w / 2);
|
|
8755
|
+
const py = Math.min(cameraOptions.constraints.padding.y, vsb.h / 2);
|
|
8858
8756
|
const bounds = Box.From(cameraOptions.constraints.bounds);
|
|
8859
8757
|
const zx = (vsb.w - px * 2) / bounds.w;
|
|
8860
8758
|
const zy = (vsb.h - py * 2) / bounds.h;
|