@tldraw/editor 5.1.0 → 5.2.0-canary.019da1aa690a
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 +52 -50
- package/dist-cjs/index.js +4 -4
- 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/default-components/DefaultErrorFallback.js +4 -1
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +3 -3
- package/dist-cjs/lib/components/default-components/DefaultLoadingScreen.js +2 -2
- package/dist-cjs/lib/components/default-components/DefaultLoadingScreen.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeErrorFallback.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultShapeErrorFallback.js.map +3 -3
- package/dist-cjs/lib/components/default-components/DefaultSvgDefs.js +2 -2
- package/dist-cjs/lib/components/default-components/DefaultSvgDefs.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +125 -56
- package/dist-cjs/lib/editor/Editor.js.map +3 -3
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js +2 -2
- package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js +2 -2
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js +2 -2
- package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js.map +2 -2
- 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/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/tools/BaseBoxShapeTool/children/Pointing.js +3 -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/editor/types/event-types.js +0 -2
- package/dist-cjs/lib/editor/types/event-types.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +14 -7
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePresence.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +3 -1
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/primitives/utils.js +2 -2
- package/dist-cjs/lib/primitives/utils.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +5 -3
- 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 +32 -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 +52 -50
- package/dist-esm/index.mjs +5 -7
- 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/default-components/DefaultErrorFallback.mjs +4 -1
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +3 -3
- package/dist-esm/lib/components/default-components/DefaultLoadingScreen.mjs +2 -2
- package/dist-esm/lib/components/default-components/DefaultLoadingScreen.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeErrorFallback.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultShapeErrorFallback.mjs.map +3 -3
- package/dist-esm/lib/components/default-components/DefaultSvgDefs.mjs +2 -2
- package/dist-esm/lib/components/default-components/DefaultSvgDefs.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +125 -56
- package/dist-esm/lib/editor/Editor.mjs.map +3 -3
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +2 -2
- package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +2 -2
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs +2 -2
- package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs.map +2 -2
- 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/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/tools/BaseBoxShapeTool/children/Pointing.mjs +3 -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/types/event-types.mjs +0 -2
- package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +14 -7
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePresence.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +3 -1
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/primitives/utils.mjs +2 -2
- package/dist-esm/lib/primitives/utils.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +5 -3
- 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 +12 -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 +5 -3
- package/package.json +11 -8
- package/src/index.ts +2 -5
- package/src/lib/components/MenuClickCapture.tsx +8 -4
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +4 -1
- package/src/lib/components/default-components/DefaultLoadingScreen.tsx +1 -1
- package/src/lib/components/default-components/DefaultShapeErrorFallback.tsx +4 -3
- package/src/lib/components/default-components/DefaultSvgDefs.tsx +1 -1
- package/src/lib/editor/Editor.ts +174 -73
- package/src/lib/editor/derivations/bindingsIndex.ts +1 -1
- package/src/lib/editor/derivations/parentsToChildren.ts +1 -1
- package/src/lib/editor/derivations/shapeIdsInCurrentPage.ts +1 -1
- 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 +13 -9
- 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/tools/BaseBoxShapeTool/children/Pointing.ts +4 -0
- package/src/lib/editor/tools/StateNode.ts +0 -2
- package/src/lib/editor/types/event-types.ts +2 -6
- package/src/lib/hooks/useCanvasEvents.ts +19 -12
- package/src/lib/hooks/usePresence.ts +2 -2
- package/src/lib/license/LicenseProvider.tsx +3 -1
- package/src/lib/primitives/utils.ts +1 -1
- package/src/lib/utils/dom.ts +5 -3
- package/src/lib/utils/getPointerInfo.ts +2 -1
- package/src/lib/utils/pointer.test.ts +48 -0
- package/src/lib/utils/pointer.ts +18 -0
- package/src/version.ts +3 -3
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +0 -161
- package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.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/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +0 -216
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
|
|
@@ -4426,11 +4458,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4426
4458
|
*
|
|
4427
4459
|
* @public
|
|
4428
4460
|
*/
|
|
4429
|
-
startFollowingUser(userId:
|
|
4461
|
+
startFollowingUser(userId: TLUserId): this {
|
|
4430
4462
|
// if we were already following someone, stop following them
|
|
4431
4463
|
this.stopFollowingUser()
|
|
4432
4464
|
|
|
4433
|
-
const thisUserId = this.user.
|
|
4465
|
+
const thisUserId = this.user.getExternalId()
|
|
4434
4466
|
|
|
4435
4467
|
if (!thisUserId) {
|
|
4436
4468
|
console.warn('You should set the userId for the current instance before following a user')
|
|
@@ -8078,32 +8110,53 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8078
8110
|
* @public
|
|
8079
8111
|
*/
|
|
8080
8112
|
resizeShape(shape: TLShapeId | TLShape, scale: VecLike, opts: TLResizeShapeOptions = {}): this {
|
|
8113
|
+
const partial = this.getResizeShapePartial(shape, scale, opts)
|
|
8114
|
+
if (partial) this.updateShapes([partial])
|
|
8115
|
+
return this
|
|
8116
|
+
}
|
|
8117
|
+
|
|
8118
|
+
/**
|
|
8119
|
+
* Get the update for a resized shape without committing it to the store. Interactions that
|
|
8120
|
+
* resize many shapes at once use this to collect all of the updates and commit them in a
|
|
8121
|
+
* single batch. Returns null when there is nothing to update.
|
|
8122
|
+
*
|
|
8123
|
+
* Shapes that are rotated out of alignment with the scale axis cannot be resized with a
|
|
8124
|
+
* single update; those shapes are resized immediately (as `resizeShape` would do) and null
|
|
8125
|
+
* is returned.
|
|
8126
|
+
*
|
|
8127
|
+
* @internal
|
|
8128
|
+
*/
|
|
8129
|
+
getResizeShapePartial(
|
|
8130
|
+
shape: TLShapeId | TLShape,
|
|
8131
|
+
scale: VecLike,
|
|
8132
|
+
opts: TLResizeShapeOptions = {}
|
|
8133
|
+
): TLShapePartial | null {
|
|
8081
8134
|
const id = typeof shape === 'string' ? shape : shape.id
|
|
8082
|
-
if (this.getIsReadonly()) return
|
|
8135
|
+
if (this.getIsReadonly()) return null
|
|
8083
8136
|
|
|
8084
8137
|
if (!Number.isFinite(scale.x)) scale = new Vec(1, scale.y)
|
|
8085
8138
|
if (!Number.isFinite(scale.y)) scale = new Vec(scale.x, 1)
|
|
8086
8139
|
|
|
8087
8140
|
const initialShape = opts.initialShape ?? this.getShape(id)
|
|
8088
|
-
if (!initialShape) return
|
|
8141
|
+
if (!initialShape) return null
|
|
8089
8142
|
|
|
8090
8143
|
const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center
|
|
8091
|
-
if (!scaleOrigin) return
|
|
8144
|
+
if (!scaleOrigin) return null
|
|
8092
8145
|
|
|
8093
8146
|
const pageTransform = opts.initialPageTransform
|
|
8094
8147
|
? Mat.Cast(opts.initialPageTransform)
|
|
8095
8148
|
: this.getShapePageTransform(id)
|
|
8096
|
-
if (!pageTransform) return
|
|
8149
|
+
if (!pageTransform) return null
|
|
8097
8150
|
|
|
8098
8151
|
const pageRotation = pageTransform.rotation()
|
|
8099
8152
|
|
|
8100
|
-
if (pageRotation == null) return
|
|
8153
|
+
if (pageRotation == null) return null
|
|
8101
8154
|
|
|
8102
8155
|
const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation
|
|
8103
8156
|
|
|
8104
8157
|
const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds
|
|
8105
8158
|
|
|
8106
|
-
if (!initialBounds) return
|
|
8159
|
+
if (!initialBounds) return null
|
|
8107
8160
|
|
|
8108
8161
|
const isAspectRatioLocked =
|
|
8109
8162
|
opts.isAspectRatioLocked ?? this.getShapeUtil(initialShape).isAspectRatioLocked(initialShape)
|
|
@@ -8113,7 +8166,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8113
8166
|
// from whichever axis is being scaled the least, to avoid the shape getting bigger
|
|
8114
8167
|
// than the bounds of the selection
|
|
8115
8168
|
// const minScale = Math.min(Math.abs(scale.x), Math.abs(scale.y))
|
|
8116
|
-
|
|
8169
|
+
this._resizeUnalignedShape(id, scale, {
|
|
8117
8170
|
...opts,
|
|
8118
8171
|
initialBounds,
|
|
8119
8172
|
scaleOrigin,
|
|
@@ -8122,6 +8175,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8122
8175
|
isAspectRatioLocked,
|
|
8123
8176
|
initialShape,
|
|
8124
8177
|
})
|
|
8178
|
+
return null
|
|
8125
8179
|
}
|
|
8126
8180
|
|
|
8127
8181
|
const util = this.getShapeUtil(initialShape)
|
|
@@ -8134,7 +8188,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8134
8188
|
}
|
|
8135
8189
|
}
|
|
8136
8190
|
|
|
8137
|
-
let
|
|
8191
|
+
let workingShape: TLShape | null = null
|
|
8138
8192
|
|
|
8139
8193
|
if (util.onResize && util.canResize(initialShape)) {
|
|
8140
8194
|
// get the model changes from the shape util
|
|
@@ -8166,7 +8220,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8166
8220
|
// need to adjust the shape's x and y points in case the parent has moved since start of resizing
|
|
8167
8221
|
const { x, y } = this.getPointInParentSpace(initialShape.id, initialPagePoint)
|
|
8168
8222
|
|
|
8169
|
-
|
|
8223
|
+
workingShape = initialShape
|
|
8170
8224
|
if (!opts.skipStartAndEndCallbacks) {
|
|
8171
8225
|
workingShape = applyPartialToRecordWithProps(
|
|
8172
8226
|
initialShape,
|
|
@@ -8188,10 +8242,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8188
8242
|
}
|
|
8189
8243
|
)
|
|
8190
8244
|
|
|
8191
|
-
if (resizedShape) {
|
|
8192
|
-
didResize = true
|
|
8193
|
-
}
|
|
8194
|
-
|
|
8195
8245
|
workingShape = applyPartialToRecordWithProps(workingShape, {
|
|
8196
8246
|
id,
|
|
8197
8247
|
type: initialShape.type as any,
|
|
@@ -8207,40 +8257,47 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8207
8257
|
)
|
|
8208
8258
|
}
|
|
8209
8259
|
|
|
8210
|
-
|
|
8260
|
+
if (resizedShape) {
|
|
8261
|
+
return workingShape
|
|
8262
|
+
}
|
|
8211
8263
|
}
|
|
8212
8264
|
|
|
8213
|
-
|
|
8214
|
-
|
|
8265
|
+
// the shape was not resized by its util, so reposition it (rather than resizing it)
|
|
8266
|
+
// based on where its resized center would be
|
|
8215
8267
|
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8268
|
+
const initialPageCenter = Mat.applyToPoint(pageTransform, initialBounds.center)
|
|
8269
|
+
// get the model changes from the shape util
|
|
8270
|
+
const newPageCenter = this._scalePagePoint(
|
|
8271
|
+
initialPageCenter,
|
|
8272
|
+
scaleOrigin,
|
|
8273
|
+
scale,
|
|
8274
|
+
scaleAxisRotation
|
|
8275
|
+
)
|
|
8224
8276
|
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8277
|
+
const initialPageCenterInParentSpace = this.getPointInParentSpace(
|
|
8278
|
+
initialShape.id,
|
|
8279
|
+
initialPageCenter
|
|
8280
|
+
)
|
|
8281
|
+
const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter)
|
|
8230
8282
|
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8283
|
+
const delta = Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace)
|
|
8284
|
+
|
|
8285
|
+
if (workingShape) {
|
|
8286
|
+
// the util's onResize ran but returned no change; keep the working update (which may
|
|
8287
|
+
// include changes from onResizeStart / onResizeEnd) and reposition the shape
|
|
8288
|
+
return {
|
|
8289
|
+
...workingShape,
|
|
8290
|
+
x: initialShape.x + delta.x,
|
|
8291
|
+
y: initialShape.y + delta.y,
|
|
8292
|
+
}
|
|
8241
8293
|
}
|
|
8242
8294
|
|
|
8243
|
-
return
|
|
8295
|
+
return {
|
|
8296
|
+
id,
|
|
8297
|
+
type: initialShape.type as any,
|
|
8298
|
+
x: initialShape.x + delta.x,
|
|
8299
|
+
y: initialShape.y + delta.y,
|
|
8300
|
+
}
|
|
8244
8301
|
}
|
|
8245
8302
|
|
|
8246
8303
|
/** @internal */
|
|
@@ -10768,6 +10825,16 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10768
10825
|
/** @internal */
|
|
10769
10826
|
private _selectedShapeIdsAtPointerDown: TLShapeId[] = []
|
|
10770
10827
|
|
|
10828
|
+
/**
|
|
10829
|
+
* Whether `_selectedShapeIdsAtPointerDown` holds a pre-gesture selection
|
|
10830
|
+
* captured by a `pointer_down` (the touch path) that a following pinch
|
|
10831
|
+
* should restore. False when no pointer_down preceded the pinch (the
|
|
10832
|
+
* Safari trackpad path uses gesture events), in which case `pinch_start`
|
|
10833
|
+
* captures the live selection instead.
|
|
10834
|
+
* @internal
|
|
10835
|
+
*/
|
|
10836
|
+
private _didCaptureSelectionAtPointerDown = false
|
|
10837
|
+
|
|
10771
10838
|
/** @internal */
|
|
10772
10839
|
private _longPressTimeout = -1 as any
|
|
10773
10840
|
|
|
@@ -10933,16 +11000,28 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10933
11000
|
if (inputs.getIsPinching()) return
|
|
10934
11001
|
|
|
10935
11002
|
if (!inputs.getIsEditing()) {
|
|
10936
|
-
//
|
|
10937
|
-
//
|
|
10938
|
-
//
|
|
10939
|
-
|
|
11003
|
+
// If a pointer_down already captured the pre-gesture selection,
|
|
11004
|
+
// keep it: on touch, the first finger's pointer_down can change
|
|
11005
|
+
// the selection before the second finger starts the pinch, and we
|
|
11006
|
+
// want to restore the selection from before that change. When no
|
|
11007
|
+
// pointer_down preceded the pinch (Safari delivers trackpad pinches
|
|
11008
|
+
// as gesture events), capture the live selection now.
|
|
11009
|
+
if (!this._didCaptureSelectionAtPointerDown) {
|
|
11010
|
+
this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds]
|
|
11011
|
+
}
|
|
10940
11012
|
|
|
10941
11013
|
this._didPinch = true
|
|
10942
11014
|
|
|
10943
11015
|
inputs.setIsPinching(true)
|
|
10944
11016
|
|
|
10945
11017
|
this.interrupt()
|
|
11018
|
+
|
|
11019
|
+
// If the first finger changed the selection, roll it back now rather
|
|
11020
|
+
// than waiting for the pinch to end, so the pre-gesture selection is
|
|
11021
|
+
// what's shown during the pinch.
|
|
11022
|
+
if (this._didCaptureSelectionAtPointerDown) {
|
|
11023
|
+
this.setSelectedShapes(this._selectedShapeIdsAtPointerDown)
|
|
11024
|
+
}
|
|
10946
11025
|
}
|
|
10947
11026
|
|
|
10948
11027
|
this.emit('event', info)
|
|
@@ -10994,6 +11073,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10994
11073
|
const { _selectedShapeIdsAtPointerDown: shapesToReselect } = this
|
|
10995
11074
|
this.setSelectedShapes(this._selectedShapeIdsAtPointerDown)
|
|
10996
11075
|
this._selectedShapeIdsAtPointerDown = []
|
|
11076
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
10997
11077
|
|
|
10998
11078
|
if (this._didPinch) {
|
|
10999
11079
|
this._didPinch = false
|
|
@@ -11122,8 +11202,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11122
11202
|
}, this.options.longPressDurationMs)
|
|
11123
11203
|
}
|
|
11124
11204
|
|
|
11125
|
-
// Save the selected ids at
|
|
11126
|
-
|
|
11205
|
+
// Save the selected ids at the start of an interaction so a pinch can
|
|
11206
|
+
// restore the pre-gesture selection. Only capture on the first pointer:
|
|
11207
|
+
// on touch, the second finger's pointer_down arrives after the first
|
|
11208
|
+
// has already changed the selection, and we want the earlier snapshot.
|
|
11209
|
+
// Cleared on pointer_up / pinch_end.
|
|
11210
|
+
if (!this._didCaptureSelectionAtPointerDown) {
|
|
11211
|
+
this._selectedShapeIdsAtPointerDown = this.getSelectedShapeIds()
|
|
11212
|
+
this._didCaptureSelectionAtPointerDown = true
|
|
11213
|
+
}
|
|
11127
11214
|
|
|
11128
11215
|
// Firefox bug fix...
|
|
11129
11216
|
// If it's a left-mouse-click, we store the pointer id for later user
|
|
@@ -11137,7 +11224,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11137
11224
|
inputs.setIsDragging(false)
|
|
11138
11225
|
|
|
11139
11226
|
// If pen mode is off but we're not already in pen mode, turn that on
|
|
11140
|
-
if (!isPenMode && isPen)
|
|
11227
|
+
if (!isPenMode && isPen) {
|
|
11228
|
+
this.updateInstanceState({ isPenMode: true })
|
|
11229
|
+
// Once pen mode is on, touch input is ignored, so we discard the
|
|
11230
|
+
// in-progress touch interaction .
|
|
11231
|
+
this.interrupt()
|
|
11232
|
+
}
|
|
11141
11233
|
|
|
11142
11234
|
// On devices with erasers (like the Surface Pen or Wacom Pen), button 5 is the eraser
|
|
11143
11235
|
if (info.button === STYLUS_ERASER_BUTTON) {
|
|
@@ -11243,6 +11335,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11243
11335
|
if (this.inputs.getIsRightPointing() && !this.inputs.getIsPanning()) {
|
|
11244
11336
|
this.inputs.setIsRightPointing(false)
|
|
11245
11337
|
this._selectedShapeIdsAtPointerDown = []
|
|
11338
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11246
11339
|
break // fall through to state chart dispatch as right_click
|
|
11247
11340
|
}
|
|
11248
11341
|
|
|
@@ -11286,15 +11379,22 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11286
11379
|
// Don't pass right-click panning events to the state chart
|
|
11287
11380
|
// as it causes unintended shape selection on release
|
|
11288
11381
|
if (slideSpeed > 0) {
|
|
11289
|
-
this.slideCamera({
|
|
11382
|
+
this.slideCamera({
|
|
11383
|
+
speed: slideSpeed,
|
|
11384
|
+
direction: { x: slideDirection.x, y: slideDirection.y, z: 0 },
|
|
11385
|
+
})
|
|
11290
11386
|
}
|
|
11291
11387
|
this._selectedShapeIdsAtPointerDown = []
|
|
11388
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11292
11389
|
return this
|
|
11293
11390
|
}
|
|
11294
11391
|
}
|
|
11295
11392
|
|
|
11296
11393
|
if (slideSpeed > 0) {
|
|
11297
|
-
this.slideCamera({
|
|
11394
|
+
this.slideCamera({
|
|
11395
|
+
speed: slideSpeed,
|
|
11396
|
+
direction: { x: slideDirection.x, y: slideDirection.y, z: 0 },
|
|
11397
|
+
})
|
|
11298
11398
|
}
|
|
11299
11399
|
} else {
|
|
11300
11400
|
if (info.button === STYLUS_ERASER_BUTTON) {
|
|
@@ -11307,6 +11407,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11307
11407
|
// Clear the stashed selection so the next pinch captures fresh state.
|
|
11308
11408
|
// This fixes Safari pinch zoom restoring outdated selections.
|
|
11309
11409
|
this._selectedShapeIdsAtPointerDown = []
|
|
11410
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11310
11411
|
|
|
11311
11412
|
break
|
|
11312
11413
|
}
|
|
@@ -29,7 +29,7 @@ function fromScratch(bindingsQuery: Computed<TLBinding[], unknown>) {
|
|
|
29
29
|
return shapesToBindings
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export
|
|
32
|
+
export function bindingsIndex(editor: Editor): Computed<TLBindingsIndex> {
|
|
33
33
|
const { store } = editor
|
|
34
34
|
const bindingsHistory = store.query.filterHistory('binding')
|
|
35
35
|
const bindingsQuery = store.query.records('binding')
|
|
@@ -22,7 +22,7 @@ function fromScratch(
|
|
|
22
22
|
return result
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export
|
|
25
|
+
export function parentsToChildren(store: TLStore) {
|
|
26
26
|
const shapeIdsQuery = store.query.ids<'shape'>('shape')
|
|
27
27
|
const shapeHistory = store.query.filterHistory('shape')
|
|
28
28
|
|
|
@@ -33,7 +33,7 @@ const isShapeInPage = (store: TLStore, pageId: TLPageId, shape: TLShape): boolea
|
|
|
33
33
|
* @param store - The tldraw store.
|
|
34
34
|
* @param getCurrentPageId - A function that returns the current page id.
|
|
35
35
|
*/
|
|
36
|
-
export
|
|
36
|
+
export function deriveShapeIdsInCurrentPage(store: TLStore, getCurrentPageId: () => TLPageId) {
|
|
37
37
|
const shapesIndex = store.query.ids('shape')
|
|
38
38
|
let lastPageId: null | TLPageId = null
|
|
39
39
|
function fromScratch() {
|