@tldraw/editor 5.2.0-next.ee0fa4d6244f → 5.2.0
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/README.md +7 -1
- package/dist-cjs/index.d.ts +117 -60
- package/dist-cjs/index.js +7 -8
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +8 -5
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +47 -1
- package/dist-cjs/lib/components/Shape.js.map +3 -3
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -16
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +131 -57
- package/dist-cjs/lib/editor/Editor.js.map +3 -3
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +8 -58
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +3 -3
- package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +1 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +28 -4
- package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +3 -3
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +24 -2
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +14 -3
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +4 -2
- package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +7 -3
- package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +0 -1
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +15 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +79 -0
- package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +7 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +4 -0
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
- package/dist-cjs/lib/{hooks/useTransform.js → editor/tools/cancelShapeCreationOnLongPress.js} +8 -23
- package/dist-cjs/lib/editor/tools/cancelShapeCreationOnLongPress.js.map +7 -0
- package/dist-cjs/lib/editor/types/event-types.js +0 -2
- package/dist-cjs/lib/editor/types/event-types.js.map +2 -2
- package/dist-cjs/lib/globals/environment.js +6 -1
- package/dist-cjs/lib/globals/environment.js.map +2 -2
- package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +17 -8
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useEditorComponents.js +0 -1
- package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePresence.js.map +2 -2
- package/dist-cjs/lib/hooks/useScreenBounds.js +1 -0
- package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +5 -1
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/primitives/Vec.js +3 -2
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +12 -0
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/getPointerInfo.js +2 -1
- package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
- package/dist-cjs/lib/utils/pointer.js +37 -0
- package/dist-cjs/lib/utils/pointer.js.map +7 -0
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +117 -60
- package/dist-esm/index.mjs +9 -13
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +8 -5
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +48 -2
- package/dist-esm/lib/components/Shape.mjs.map +3 -3
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -16
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +131 -57
- package/dist-esm/lib/editor/Editor.mjs.map +3 -3
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +8 -58
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +3 -3
- package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +1 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +28 -4
- package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +3 -3
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +24 -2
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +14 -3
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +4 -2
- package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +7 -3
- package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +0 -1
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +15 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +59 -0
- package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +7 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +4 -0
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/cancelShapeCreationOnLongPress.mjs +8 -0
- package/dist-esm/lib/editor/tools/cancelShapeCreationOnLongPress.mjs.map +7 -0
- package/dist-esm/lib/editor/types/event-types.mjs +0 -2
- package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
- package/dist-esm/lib/globals/environment.mjs +6 -1
- package/dist-esm/lib/globals/environment.mjs.map +2 -2
- package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +17 -8
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEditorComponents.mjs +0 -1
- package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePresence.mjs.map +2 -2
- package/dist-esm/lib/hooks/useScreenBounds.mjs +1 -0
- package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +5 -1
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/primitives/Vec.mjs +3 -2
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +12 -0
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/getPointerInfo.mjs +2 -1
- package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
- package/dist-esm/lib/utils/pointer.mjs +17 -0
- package/dist-esm/lib/utils/pointer.mjs.map +7 -0
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +15 -3
- package/package.json +11 -8
- package/src/index.ts +4 -10
- package/src/lib/components/MenuClickCapture.tsx +8 -4
- package/src/lib/components/Shape.tsx +88 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +1 -17
- package/src/lib/editor/Editor.test.ts +36 -0
- package/src/lib/editor/Editor.ts +204 -75
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +54 -74
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +15 -65
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.test.ts +43 -16
- package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +8 -5
- package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +4 -4
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +1 -2
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +37 -10
- package/src/lib/editor/managers/FontManager/FontManager.ts +46 -1
- package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +32 -0
- package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +34 -4
- package/src/lib/editor/managers/InputsManager/InputsManager.test.ts +61 -0
- package/src/lib/editor/managers/InputsManager/InputsManager.ts +16 -4
- package/src/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.ts +9 -2
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +16 -14
- package/src/lib/editor/managers/TextManager/TextManager.ts +17 -2
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +0 -40
- package/src/lib/editor/managers/TickManager/TickManager.ts +0 -1
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +12 -2
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +27 -2
- package/src/lib/editor/overlays/strokeShapeIndicators.ts +86 -0
- package/src/lib/editor/shapes/ShapeUtil.ts +41 -0
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +5 -0
- package/src/lib/editor/tools/StateNode.ts +0 -2
- package/src/lib/editor/tools/cancelShapeCreationOnLongPress.ts +31 -0
- package/src/lib/editor/types/event-types.ts +9 -6
- package/src/lib/globals/environment.ts +7 -0
- package/src/lib/hooks/EditorComponentsContext.tsx +0 -2
- package/src/lib/hooks/useCanvasEvents.ts +24 -12
- package/src/lib/hooks/useEditorComponents.tsx +0 -1
- package/src/lib/hooks/usePresence.ts +2 -2
- package/src/lib/hooks/useScreenBounds.ts +3 -0
- package/src/lib/license/LicenseManager.test.ts +24 -16
- package/src/lib/license/LicenseManager.ts +8 -2
- package/src/lib/primitives/Vec.ts +5 -2
- package/src/lib/test/ContentElementSlot.test.tsx +201 -0
- package/src/lib/utils/dom.ts +34 -0
- package/src/lib/utils/getPointerInfo.ts +2 -1
- package/src/lib/utils/pointer.test.ts +76 -0
- package/src/lib/utils/pointer.ts +42 -0
- package/src/version.ts +3 -3
- package/dist-cjs/lib/components/default-components/DefaultSelectionBackground.js +0 -49
- package/dist-cjs/lib/components/default-components/DefaultSelectionBackground.js.map +0 -7
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +0 -161
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +0 -7
- package/dist-cjs/lib/hooks/useTransform.js.map +0 -7
- package/dist-esm/lib/components/default-components/DefaultSelectionBackground.mjs +0 -19
- package/dist-esm/lib/components/default-components/DefaultSelectionBackground.mjs.map +0 -7
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs +0 -141
- package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs.map +0 -7
- package/dist-esm/lib/hooks/useTransform.mjs +0 -23
- package/dist-esm/lib/hooks/useTransform.mjs.map +0 -7
- package/src/lib/components/default-components/DefaultSelectionBackground.tsx +0 -25
- package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +0 -216
- package/src/lib/hooks/useTransform.ts +0 -30
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -409,9 +409,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
409
409
|
this._tickManager = new TickManager(this)
|
|
410
410
|
this.disposables.add(() => this._tickManager.dispose())
|
|
411
411
|
this.disposables.add(() => {
|
|
412
|
-
// Reset camera state to 'idle' so the store isn't left stuck at 'moving'
|
|
413
|
-
// when tick events stop (e.g. React strict mode disposes while camera is moving)
|
|
414
|
-
this.off('tick', this._decayCameraStateTimeout)
|
|
415
412
|
this._setCameraState('idle')
|
|
416
413
|
})
|
|
417
414
|
|
|
@@ -419,6 +416,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
419
416
|
this.disposables.add(() => this.fonts.dispose())
|
|
420
417
|
|
|
421
418
|
this.inputs = new InputsManager(this)
|
|
419
|
+
this.disposables.add(() => this.inputs.dispose())
|
|
422
420
|
this.performance = new PerformanceManager(this)
|
|
423
421
|
this.disposables.add(() => this.performance.dispose())
|
|
424
422
|
this.collaborators = new CollaboratorsManager(this)
|
|
@@ -1179,6 +1177,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1179
1177
|
this.store.dispose()
|
|
1180
1178
|
this.isDisposed = true
|
|
1181
1179
|
this.emit('dispose')
|
|
1180
|
+
this.removeAllListeners()
|
|
1182
1181
|
}
|
|
1183
1182
|
|
|
1184
1183
|
/* ------------------ Themes (shadowing the theme manager) ------------------ */
|
|
@@ -1551,6 +1550,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1551
1550
|
return this.history.getMarkIdMatching(idSubstring)
|
|
1552
1551
|
}
|
|
1553
1552
|
|
|
1553
|
+
/**
|
|
1554
|
+
* Whether the editor is currently replaying history (i.e. an undo or redo is being applied).
|
|
1555
|
+
*
|
|
1556
|
+
* @internal
|
|
1557
|
+
*/
|
|
1558
|
+
isReplayingHistory(): boolean {
|
|
1559
|
+
return this.history.isReplaying()
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1554
1562
|
/**
|
|
1555
1563
|
* Coalesces all changes since the given mark into a single change, removing any intermediate marks.
|
|
1556
1564
|
*
|
|
@@ -3068,8 +3076,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3068
3076
|
return baseCamera
|
|
3069
3077
|
}
|
|
3070
3078
|
|
|
3071
|
-
private _getFollowingPresence(targetUserId:
|
|
3072
|
-
const visited = [this.user.
|
|
3079
|
+
private _getFollowingPresence(targetUserId: TLUserId | null) {
|
|
3080
|
+
const visited = [this.user.getRecordId()]
|
|
3073
3081
|
const collaborators = this.getCollaborators()
|
|
3074
3082
|
let leaderPresence = null as null | TLInstancePresence
|
|
3075
3083
|
while (targetUserId && !visited.includes(targetUserId)) {
|
|
@@ -3336,6 +3344,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3336
3344
|
|
|
3337
3345
|
let { x, y, z = currentCamera.z } = point
|
|
3338
3346
|
|
|
3347
|
+
// `requested` kept the caller's focal point (e.g. the cursor) fixed at
|
|
3348
|
+
// zoom `rz`. When `rz` gets clamped, keep that same focal point fixed at
|
|
3349
|
+
// the clamped zoom `z` rather than snapping to the viewport center.
|
|
3350
|
+
const preserveFocalPoint = (current: number, requested: number, rz: number, z: number) => {
|
|
3351
|
+
const cz = currentCamera.z
|
|
3352
|
+
if (rz === cz) return current
|
|
3353
|
+
return current + ((requested - current) * (1 / z - 1 / cz)) / (1 / rz - 1 / cz)
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3339
3356
|
// If force is true, then we'll set the camera to the point regardless of
|
|
3340
3357
|
// the camera options, so that we can handle gestures that permit elasticity
|
|
3341
3358
|
// or decay, or animations that occur while the camera is locked.
|
|
@@ -3378,17 +3395,14 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3378
3395
|
}
|
|
3379
3396
|
|
|
3380
3397
|
if (z < minZ || z > maxZ) {
|
|
3381
|
-
// We're trying to zoom out past the minimum zoom level,
|
|
3382
|
-
//
|
|
3383
|
-
//
|
|
3384
|
-
|
|
3385
|
-
const
|
|
3386
|
-
const cyA = -cy + vsb.h / cz / 2
|
|
3398
|
+
// We're trying to zoom out past the minimum zoom level, or in
|
|
3399
|
+
// past the maximum zoom level, so clamp the zoom while keeping
|
|
3400
|
+
// the caller's focal point fixed. Axis constraints below still
|
|
3401
|
+
// apply on top of this.
|
|
3402
|
+
const rz = z
|
|
3387
3403
|
z = clamp(z, minZ, maxZ)
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
x = cx + cxB - cxA
|
|
3391
|
-
y = cy + cyB - cyA
|
|
3404
|
+
x = preserveFocalPoint(currentCamera.x, x, rz, z)
|
|
3405
|
+
y = preserveFocalPoint(currentCamera.y, y, rz, z)
|
|
3392
3406
|
}
|
|
3393
3407
|
|
|
3394
3408
|
// Calculate available space
|
|
@@ -3477,12 +3491,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3477
3491
|
}
|
|
3478
3492
|
}
|
|
3479
3493
|
} else {
|
|
3480
|
-
// constrain the zoom,
|
|
3494
|
+
// constrain the zoom, keeping the caller's focal point fixed
|
|
3481
3495
|
if (z > zoomMax || z < zoomMin) {
|
|
3482
|
-
const
|
|
3496
|
+
const rz = z
|
|
3483
3497
|
z = clamp(z, zoomMin, zoomMax)
|
|
3484
|
-
x =
|
|
3485
|
-
y =
|
|
3498
|
+
x = preserveFocalPoint(currentCamera.x, x, rz, z)
|
|
3499
|
+
y = preserveFocalPoint(currentCamera.y, y, rz, z)
|
|
3486
3500
|
}
|
|
3487
3501
|
}
|
|
3488
3502
|
}
|
|
@@ -4023,16 +4037,34 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4023
4037
|
|
|
4024
4038
|
this.once('stop-camera-animation', cancel)
|
|
4025
4039
|
|
|
4040
|
+
const dirZ = direction.z ?? 0
|
|
4041
|
+
|
|
4026
4042
|
const moveCamera = (elapsed: number) => {
|
|
4027
4043
|
const { x: cx, y: cy, z: cz } = this.getCamera()
|
|
4028
|
-
|
|
4044
|
+
|
|
4045
|
+
// Pan movement from x/y direction
|
|
4046
|
+
const dx = (direction.x * (currentSpeed * elapsed)) / cz
|
|
4047
|
+
const dy = (direction.y * (currentSpeed * elapsed)) / cz
|
|
4048
|
+
|
|
4049
|
+
let newCx = cx + dx
|
|
4050
|
+
let newCy = cy + dy
|
|
4051
|
+
let newCz = cz
|
|
4052
|
+
|
|
4053
|
+
// animate zoom if z direction is passed in
|
|
4054
|
+
if (dirZ !== 0) {
|
|
4055
|
+
newCz = cz * (1 + dirZ * currentSpeed * elapsed)
|
|
4056
|
+
// Adjust x/y to keep the viewport center fixed while zooming
|
|
4057
|
+
const center = this.getViewportScreenCenter()
|
|
4058
|
+
newCx += center.x / newCz - center.x / cz
|
|
4059
|
+
newCy += center.y / newCz - center.y / cz
|
|
4060
|
+
}
|
|
4029
4061
|
|
|
4030
4062
|
// Apply friction
|
|
4031
4063
|
currentSpeed *= 1 - friction
|
|
4032
4064
|
if (currentSpeed < speedThreshold) {
|
|
4033
4065
|
cancel()
|
|
4034
4066
|
} else {
|
|
4035
|
-
this._setCamera(new Vec(
|
|
4067
|
+
this._setCamera(new Vec(newCx, newCy, newCz))
|
|
4036
4068
|
}
|
|
4037
4069
|
}
|
|
4038
4070
|
|
|
@@ -4054,7 +4086,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4054
4086
|
* @param opts - The camera move options.
|
|
4055
4087
|
* @public
|
|
4056
4088
|
*/
|
|
4057
|
-
zoomToUser(userId:
|
|
4089
|
+
zoomToUser(userId: TLUserId, opts: TLCameraMoveOptions = { animation: { duration: 500 } }): this {
|
|
4058
4090
|
const presence = this.getCollaborators().find((c) => c.userId === userId)
|
|
4059
4091
|
|
|
4060
4092
|
if (!presence) return this
|
|
@@ -4133,6 +4165,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4133
4165
|
}
|
|
4134
4166
|
|
|
4135
4167
|
const doc = this.getContainerDocument()
|
|
4168
|
+
// If the container's document has been torn down (e.g. an iframe being
|
|
4169
|
+
// removed), its body is null and there's nothing meaningful to measure.
|
|
4170
|
+
if (!doc.body) return this
|
|
4171
|
+
|
|
4136
4172
|
const insets = [
|
|
4137
4173
|
// top
|
|
4138
4174
|
screenBounds.minY !== 0,
|
|
@@ -4394,7 +4430,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4394
4430
|
|
|
4395
4431
|
/**
|
|
4396
4432
|
* Collect user IDs referenced by a set of shapes via shape-specific props
|
|
4397
|
-
* (e.g. `
|
|
4433
|
+
* (e.g. `textLastEditedBy` on notes).
|
|
4398
4434
|
*
|
|
4399
4435
|
* @internal
|
|
4400
4436
|
*/
|
|
@@ -4426,11 +4462,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4426
4462
|
*
|
|
4427
4463
|
* @public
|
|
4428
4464
|
*/
|
|
4429
|
-
startFollowingUser(userId:
|
|
4465
|
+
startFollowingUser(userId: TLUserId): this {
|
|
4430
4466
|
// if we were already following someone, stop following them
|
|
4431
4467
|
this.stopFollowingUser()
|
|
4432
4468
|
|
|
4433
|
-
const thisUserId = this.user.
|
|
4469
|
+
const thisUserId = this.user.getExternalId()
|
|
4434
4470
|
|
|
4435
4471
|
if (!thisUserId) {
|
|
4436
4472
|
console.warn('You should set the userId for the current instance before following a user')
|
|
@@ -8078,32 +8114,53 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8078
8114
|
* @public
|
|
8079
8115
|
*/
|
|
8080
8116
|
resizeShape(shape: TLShapeId | TLShape, scale: VecLike, opts: TLResizeShapeOptions = {}): this {
|
|
8117
|
+
const partial = this.getResizeShapePartial(shape, scale, opts)
|
|
8118
|
+
if (partial) this.updateShapes([partial])
|
|
8119
|
+
return this
|
|
8120
|
+
}
|
|
8121
|
+
|
|
8122
|
+
/**
|
|
8123
|
+
* Get the update for a resized shape without committing it to the store. Interactions that
|
|
8124
|
+
* resize many shapes at once use this to collect all of the updates and commit them in a
|
|
8125
|
+
* single batch. Returns null when there is nothing to update.
|
|
8126
|
+
*
|
|
8127
|
+
* Shapes that are rotated out of alignment with the scale axis cannot be resized with a
|
|
8128
|
+
* single update; those shapes are resized immediately (as `resizeShape` would do) and null
|
|
8129
|
+
* is returned.
|
|
8130
|
+
*
|
|
8131
|
+
* @internal
|
|
8132
|
+
*/
|
|
8133
|
+
getResizeShapePartial(
|
|
8134
|
+
shape: TLShapeId | TLShape,
|
|
8135
|
+
scale: VecLike,
|
|
8136
|
+
opts: TLResizeShapeOptions = {}
|
|
8137
|
+
): TLShapePartial | null {
|
|
8081
8138
|
const id = typeof shape === 'string' ? shape : shape.id
|
|
8082
|
-
if (this.getIsReadonly()) return
|
|
8139
|
+
if (this.getIsReadonly()) return null
|
|
8083
8140
|
|
|
8084
8141
|
if (!Number.isFinite(scale.x)) scale = new Vec(1, scale.y)
|
|
8085
8142
|
if (!Number.isFinite(scale.y)) scale = new Vec(scale.x, 1)
|
|
8086
8143
|
|
|
8087
8144
|
const initialShape = opts.initialShape ?? this.getShape(id)
|
|
8088
|
-
if (!initialShape) return
|
|
8145
|
+
if (!initialShape) return null
|
|
8089
8146
|
|
|
8090
8147
|
const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center
|
|
8091
|
-
if (!scaleOrigin) return
|
|
8148
|
+
if (!scaleOrigin) return null
|
|
8092
8149
|
|
|
8093
8150
|
const pageTransform = opts.initialPageTransform
|
|
8094
8151
|
? Mat.Cast(opts.initialPageTransform)
|
|
8095
8152
|
: this.getShapePageTransform(id)
|
|
8096
|
-
if (!pageTransform) return
|
|
8153
|
+
if (!pageTransform) return null
|
|
8097
8154
|
|
|
8098
8155
|
const pageRotation = pageTransform.rotation()
|
|
8099
8156
|
|
|
8100
|
-
if (pageRotation == null) return
|
|
8157
|
+
if (pageRotation == null) return null
|
|
8101
8158
|
|
|
8102
8159
|
const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation
|
|
8103
8160
|
|
|
8104
8161
|
const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds
|
|
8105
8162
|
|
|
8106
|
-
if (!initialBounds) return
|
|
8163
|
+
if (!initialBounds) return null
|
|
8107
8164
|
|
|
8108
8165
|
const isAspectRatioLocked =
|
|
8109
8166
|
opts.isAspectRatioLocked ?? this.getShapeUtil(initialShape).isAspectRatioLocked(initialShape)
|
|
@@ -8113,7 +8170,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8113
8170
|
// from whichever axis is being scaled the least, to avoid the shape getting bigger
|
|
8114
8171
|
// than the bounds of the selection
|
|
8115
8172
|
// const minScale = Math.min(Math.abs(scale.x), Math.abs(scale.y))
|
|
8116
|
-
|
|
8173
|
+
this._resizeUnalignedShape(id, scale, {
|
|
8117
8174
|
...opts,
|
|
8118
8175
|
initialBounds,
|
|
8119
8176
|
scaleOrigin,
|
|
@@ -8122,6 +8179,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8122
8179
|
isAspectRatioLocked,
|
|
8123
8180
|
initialShape,
|
|
8124
8181
|
})
|
|
8182
|
+
return null
|
|
8125
8183
|
}
|
|
8126
8184
|
|
|
8127
8185
|
const util = this.getShapeUtil(initialShape)
|
|
@@ -8134,7 +8192,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8134
8192
|
}
|
|
8135
8193
|
}
|
|
8136
8194
|
|
|
8137
|
-
let
|
|
8195
|
+
let workingShape: TLShape | null = null
|
|
8138
8196
|
|
|
8139
8197
|
if (util.onResize && util.canResize(initialShape)) {
|
|
8140
8198
|
// get the model changes from the shape util
|
|
@@ -8166,7 +8224,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8166
8224
|
// need to adjust the shape's x and y points in case the parent has moved since start of resizing
|
|
8167
8225
|
const { x, y } = this.getPointInParentSpace(initialShape.id, initialPagePoint)
|
|
8168
8226
|
|
|
8169
|
-
|
|
8227
|
+
workingShape = initialShape
|
|
8170
8228
|
if (!opts.skipStartAndEndCallbacks) {
|
|
8171
8229
|
workingShape = applyPartialToRecordWithProps(
|
|
8172
8230
|
initialShape,
|
|
@@ -8188,10 +8246,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8188
8246
|
}
|
|
8189
8247
|
)
|
|
8190
8248
|
|
|
8191
|
-
if (resizedShape) {
|
|
8192
|
-
didResize = true
|
|
8193
|
-
}
|
|
8194
|
-
|
|
8195
8249
|
workingShape = applyPartialToRecordWithProps(workingShape, {
|
|
8196
8250
|
id,
|
|
8197
8251
|
type: initialShape.type as any,
|
|
@@ -8207,40 +8261,47 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8207
8261
|
)
|
|
8208
8262
|
}
|
|
8209
8263
|
|
|
8210
|
-
|
|
8264
|
+
if (resizedShape) {
|
|
8265
|
+
return workingShape
|
|
8266
|
+
}
|
|
8211
8267
|
}
|
|
8212
8268
|
|
|
8213
|
-
|
|
8214
|
-
|
|
8269
|
+
// the shape was not resized by its util, so reposition it (rather than resizing it)
|
|
8270
|
+
// based on where its resized center would be
|
|
8215
8271
|
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8272
|
+
const initialPageCenter = Mat.applyToPoint(pageTransform, initialBounds.center)
|
|
8273
|
+
// get the model changes from the shape util
|
|
8274
|
+
const newPageCenter = this._scalePagePoint(
|
|
8275
|
+
initialPageCenter,
|
|
8276
|
+
scaleOrigin,
|
|
8277
|
+
scale,
|
|
8278
|
+
scaleAxisRotation
|
|
8279
|
+
)
|
|
8224
8280
|
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8281
|
+
const initialPageCenterInParentSpace = this.getPointInParentSpace(
|
|
8282
|
+
initialShape.id,
|
|
8283
|
+
initialPageCenter
|
|
8284
|
+
)
|
|
8285
|
+
const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter)
|
|
8230
8286
|
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8287
|
+
const delta = Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace)
|
|
8288
|
+
|
|
8289
|
+
if (workingShape) {
|
|
8290
|
+
// the util's onResize ran but returned no change; keep the working update (which may
|
|
8291
|
+
// include changes from onResizeStart / onResizeEnd) and reposition the shape
|
|
8292
|
+
return {
|
|
8293
|
+
...workingShape,
|
|
8294
|
+
x: initialShape.x + delta.x,
|
|
8295
|
+
y: initialShape.y + delta.y,
|
|
8296
|
+
}
|
|
8241
8297
|
}
|
|
8242
8298
|
|
|
8243
|
-
return
|
|
8299
|
+
return {
|
|
8300
|
+
id,
|
|
8301
|
+
type: initialShape.type as any,
|
|
8302
|
+
x: initialShape.x + delta.x,
|
|
8303
|
+
y: initialShape.y + delta.y,
|
|
8304
|
+
}
|
|
8244
8305
|
}
|
|
8245
8306
|
|
|
8246
8307
|
/** @internal */
|
|
@@ -10120,6 +10181,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10120
10181
|
|
|
10121
10182
|
if (ids.length === 0) return undefined
|
|
10122
10183
|
|
|
10184
|
+
// Text geometry is measured from the loaded font, so the export's bounds - and the
|
|
10185
|
+
// layout of any text within it - depend on the right fonts having loaded. Wait for them
|
|
10186
|
+
// before we measure; otherwise an export taken before fonts finish loading (e.g. right
|
|
10187
|
+
// after the editor mounts) is sized and laid out with fallback-font metrics.
|
|
10188
|
+
await this.fonts.loadRequiredFontsForCurrentPage(this.options.maxFontsToLoadBeforeRender)
|
|
10189
|
+
|
|
10123
10190
|
return exportToSvg(this, ids, opts)
|
|
10124
10191
|
}
|
|
10125
10192
|
|
|
@@ -10768,6 +10835,16 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10768
10835
|
/** @internal */
|
|
10769
10836
|
private _selectedShapeIdsAtPointerDown: TLShapeId[] = []
|
|
10770
10837
|
|
|
10838
|
+
/**
|
|
10839
|
+
* Whether `_selectedShapeIdsAtPointerDown` holds a pre-gesture selection
|
|
10840
|
+
* captured by a `pointer_down` (the touch path) that a following pinch
|
|
10841
|
+
* should restore. False when no pointer_down preceded the pinch (the
|
|
10842
|
+
* Safari trackpad path uses gesture events), in which case `pinch_start`
|
|
10843
|
+
* captures the live selection instead.
|
|
10844
|
+
* @internal
|
|
10845
|
+
*/
|
|
10846
|
+
private _didCaptureSelectionAtPointerDown = false
|
|
10847
|
+
|
|
10771
10848
|
/** @internal */
|
|
10772
10849
|
private _longPressTimeout = -1 as any
|
|
10773
10850
|
|
|
@@ -10933,16 +11010,28 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10933
11010
|
if (inputs.getIsPinching()) return
|
|
10934
11011
|
|
|
10935
11012
|
if (!inputs.getIsEditing()) {
|
|
10936
|
-
//
|
|
10937
|
-
//
|
|
10938
|
-
//
|
|
10939
|
-
|
|
11013
|
+
// If a pointer_down already captured the pre-gesture selection,
|
|
11014
|
+
// keep it: on touch, the first finger's pointer_down can change
|
|
11015
|
+
// the selection before the second finger starts the pinch, and we
|
|
11016
|
+
// want to restore the selection from before that change. When no
|
|
11017
|
+
// pointer_down preceded the pinch (Safari delivers trackpad pinches
|
|
11018
|
+
// as gesture events), capture the live selection now.
|
|
11019
|
+
if (!this._didCaptureSelectionAtPointerDown) {
|
|
11020
|
+
this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds]
|
|
11021
|
+
}
|
|
10940
11022
|
|
|
10941
11023
|
this._didPinch = true
|
|
10942
11024
|
|
|
10943
11025
|
inputs.setIsPinching(true)
|
|
10944
11026
|
|
|
10945
11027
|
this.interrupt()
|
|
11028
|
+
|
|
11029
|
+
// If the first finger changed the selection, roll it back now rather
|
|
11030
|
+
// than waiting for the pinch to end, so the pre-gesture selection is
|
|
11031
|
+
// what's shown during the pinch.
|
|
11032
|
+
if (this._didCaptureSelectionAtPointerDown) {
|
|
11033
|
+
this.setSelectedShapes(this._selectedShapeIdsAtPointerDown)
|
|
11034
|
+
}
|
|
10946
11035
|
}
|
|
10947
11036
|
|
|
10948
11037
|
this.emit('event', info)
|
|
@@ -10994,6 +11083,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10994
11083
|
const { _selectedShapeIdsAtPointerDown: shapesToReselect } = this
|
|
10995
11084
|
this.setSelectedShapes(this._selectedShapeIdsAtPointerDown)
|
|
10996
11085
|
this._selectedShapeIdsAtPointerDown = []
|
|
11086
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
10997
11087
|
|
|
10998
11088
|
if (this._didPinch) {
|
|
10999
11089
|
this._didPinch = false
|
|
@@ -11122,8 +11212,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11122
11212
|
}, this.options.longPressDurationMs)
|
|
11123
11213
|
}
|
|
11124
11214
|
|
|
11125
|
-
// Save the selected ids at
|
|
11126
|
-
|
|
11215
|
+
// Save the selected ids at the start of an interaction so a pinch can
|
|
11216
|
+
// restore the pre-gesture selection. Only capture on the first pointer:
|
|
11217
|
+
// on touch, the second finger's pointer_down arrives after the first
|
|
11218
|
+
// has already changed the selection, and we want the earlier snapshot.
|
|
11219
|
+
// Cleared on pointer_up / pinch_end.
|
|
11220
|
+
if (!this._didCaptureSelectionAtPointerDown) {
|
|
11221
|
+
this._selectedShapeIdsAtPointerDown = this.getSelectedShapeIds()
|
|
11222
|
+
this._didCaptureSelectionAtPointerDown = true
|
|
11223
|
+
}
|
|
11127
11224
|
|
|
11128
11225
|
// Firefox bug fix...
|
|
11129
11226
|
// If it's a left-mouse-click, we store the pointer id for later user
|
|
@@ -11136,8 +11233,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11136
11233
|
inputs.setIsPointing(true)
|
|
11137
11234
|
inputs.setIsDragging(false)
|
|
11138
11235
|
|
|
11139
|
-
// If pen mode is off
|
|
11140
|
-
|
|
11236
|
+
// If pen mode is off, turn it on for direct-display pen input only (e.g. Apple
|
|
11237
|
+
// Pencil on an iPad or a Surface Pen on a touchscreen). Indirect desktop tablet
|
|
11238
|
+
// styluses still draw as pens, but should not auto-enable pen mode.
|
|
11239
|
+
if (!isPenMode && info.isPenDirect) {
|
|
11240
|
+
this.updateInstanceState({ isPenMode: true })
|
|
11241
|
+
// Once pen mode is on, touch input is ignored, so we discard the
|
|
11242
|
+
// in-progress touch interaction .
|
|
11243
|
+
this.interrupt()
|
|
11244
|
+
}
|
|
11141
11245
|
|
|
11142
11246
|
// On devices with erasers (like the Surface Pen or Wacom Pen), button 5 is the eraser
|
|
11143
11247
|
if (info.button === STYLUS_ERASER_BUTTON) {
|
|
@@ -11243,6 +11347,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11243
11347
|
if (this.inputs.getIsRightPointing() && !this.inputs.getIsPanning()) {
|
|
11244
11348
|
this.inputs.setIsRightPointing(false)
|
|
11245
11349
|
this._selectedShapeIdsAtPointerDown = []
|
|
11350
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11246
11351
|
break // fall through to state chart dispatch as right_click
|
|
11247
11352
|
}
|
|
11248
11353
|
|
|
@@ -11286,15 +11391,22 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11286
11391
|
// Don't pass right-click panning events to the state chart
|
|
11287
11392
|
// as it causes unintended shape selection on release
|
|
11288
11393
|
if (slideSpeed > 0) {
|
|
11289
|
-
this.slideCamera({
|
|
11394
|
+
this.slideCamera({
|
|
11395
|
+
speed: slideSpeed,
|
|
11396
|
+
direction: { x: slideDirection.x, y: slideDirection.y, z: 0 },
|
|
11397
|
+
})
|
|
11290
11398
|
}
|
|
11291
11399
|
this._selectedShapeIdsAtPointerDown = []
|
|
11400
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11292
11401
|
return this
|
|
11293
11402
|
}
|
|
11294
11403
|
}
|
|
11295
11404
|
|
|
11296
11405
|
if (slideSpeed > 0) {
|
|
11297
|
-
this.slideCamera({
|
|
11406
|
+
this.slideCamera({
|
|
11407
|
+
speed: slideSpeed,
|
|
11408
|
+
direction: { x: slideDirection.x, y: slideDirection.y, z: 0 },
|
|
11409
|
+
})
|
|
11298
11410
|
}
|
|
11299
11411
|
} else {
|
|
11300
11412
|
if (info.button === STYLUS_ERASER_BUTTON) {
|
|
@@ -11307,6 +11419,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11307
11419
|
// Clear the stashed selection so the next pinch captures fresh state.
|
|
11308
11420
|
// This fixes Safari pinch zoom restoring outdated selections.
|
|
11309
11421
|
this._selectedShapeIdsAtPointerDown = []
|
|
11422
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11310
11423
|
|
|
11311
11424
|
break
|
|
11312
11425
|
}
|
|
@@ -11408,6 +11521,22 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11408
11521
|
info.name = 'right_click'
|
|
11409
11522
|
}
|
|
11410
11523
|
|
|
11524
|
+
// The context menu is a select-tool surface: every item acts on the
|
|
11525
|
+
// current selection. Route a right-click through the select tool before
|
|
11526
|
+
// the event reaches the state chart, so the select tool's idle resolves
|
|
11527
|
+
// the selection at the click point (select the shape under the pointer,
|
|
11528
|
+
// or clear it) no matter which tool was active. Without this, opening the
|
|
11529
|
+
// menu from another tool leaves a stale selection that doesn't match the
|
|
11530
|
+
// click (#8828). Guarded on the select tool existing, since the bare
|
|
11531
|
+
// editor can be configured without it.
|
|
11532
|
+
if (
|
|
11533
|
+
info.name === 'right_click' &&
|
|
11534
|
+
this.getCurrentToolId() !== 'select' &&
|
|
11535
|
+
this.getStateDescendant('select')
|
|
11536
|
+
) {
|
|
11537
|
+
this.setCurrentTool('select')
|
|
11538
|
+
}
|
|
11539
|
+
|
|
11411
11540
|
// If a left click pointer event, send the event to the click manager.
|
|
11412
11541
|
const { isPenMode } = this.store.unsafeGetWithoutCapture(TLINSTANCE_ID)!
|
|
11413
11542
|
if (info.isPen === isPenMode) {
|