@tldraw/editor 5.1.0 → 5.2.0-canary.05c017c18b15
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 +50 -50
- package/dist-cjs/index.js +4 -4
- package/dist-cjs/index.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 +123 -55
- 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/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/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/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/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +50 -50
- package/dist-esm/index.mjs +5 -7
- package/dist-esm/index.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 +123 -55
- 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/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/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/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/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +2 -0
- package/package.json +8 -8
- package/src/index.ts +2 -5
- 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 +172 -70
- 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/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/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/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/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
|
@@ -1551,6 +1551,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1551
1551
|
return this.history.getMarkIdMatching(idSubstring)
|
|
1552
1552
|
}
|
|
1553
1553
|
|
|
1554
|
+
/**
|
|
1555
|
+
* Whether the editor is currently replaying history (i.e. an undo or redo is being applied).
|
|
1556
|
+
*
|
|
1557
|
+
* @internal
|
|
1558
|
+
*/
|
|
1559
|
+
isReplayingHistory(): boolean {
|
|
1560
|
+
return this.history.isReplaying()
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1554
1563
|
/**
|
|
1555
1564
|
* Coalesces all changes since the given mark into a single change, removing any intermediate marks.
|
|
1556
1565
|
*
|
|
@@ -3068,8 +3077,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3068
3077
|
return baseCamera
|
|
3069
3078
|
}
|
|
3070
3079
|
|
|
3071
|
-
private _getFollowingPresence(targetUserId:
|
|
3072
|
-
const visited = [this.user.
|
|
3080
|
+
private _getFollowingPresence(targetUserId: TLUserId | null) {
|
|
3081
|
+
const visited = [this.user.getRecordId()]
|
|
3073
3082
|
const collaborators = this.getCollaborators()
|
|
3074
3083
|
let leaderPresence = null as null | TLInstancePresence
|
|
3075
3084
|
while (targetUserId && !visited.includes(targetUserId)) {
|
|
@@ -3336,6 +3345,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3336
3345
|
|
|
3337
3346
|
let { x, y, z = currentCamera.z } = point
|
|
3338
3347
|
|
|
3348
|
+
// `requested` kept the caller's focal point (e.g. the cursor) fixed at
|
|
3349
|
+
// zoom `rz`. When `rz` gets clamped, keep that same focal point fixed at
|
|
3350
|
+
// the clamped zoom `z` rather than snapping to the viewport center.
|
|
3351
|
+
const preserveFocalPoint = (current: number, requested: number, rz: number, z: number) => {
|
|
3352
|
+
const cz = currentCamera.z
|
|
3353
|
+
if (rz === cz) return current
|
|
3354
|
+
return current + ((requested - current) * (1 / z - 1 / cz)) / (1 / rz - 1 / cz)
|
|
3355
|
+
}
|
|
3356
|
+
|
|
3339
3357
|
// If force is true, then we'll set the camera to the point regardless of
|
|
3340
3358
|
// the camera options, so that we can handle gestures that permit elasticity
|
|
3341
3359
|
// or decay, or animations that occur while the camera is locked.
|
|
@@ -3378,17 +3396,14 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3378
3396
|
}
|
|
3379
3397
|
|
|
3380
3398
|
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
|
|
3399
|
+
// We're trying to zoom out past the minimum zoom level, or in
|
|
3400
|
+
// past the maximum zoom level, so clamp the zoom while keeping
|
|
3401
|
+
// the caller's focal point fixed. Axis constraints below still
|
|
3402
|
+
// apply on top of this.
|
|
3403
|
+
const rz = z
|
|
3387
3404
|
z = clamp(z, minZ, maxZ)
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
x = cx + cxB - cxA
|
|
3391
|
-
y = cy + cyB - cyA
|
|
3405
|
+
x = preserveFocalPoint(currentCamera.x, x, rz, z)
|
|
3406
|
+
y = preserveFocalPoint(currentCamera.y, y, rz, z)
|
|
3392
3407
|
}
|
|
3393
3408
|
|
|
3394
3409
|
// Calculate available space
|
|
@@ -3477,12 +3492,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
3477
3492
|
}
|
|
3478
3493
|
}
|
|
3479
3494
|
} else {
|
|
3480
|
-
// constrain the zoom,
|
|
3495
|
+
// constrain the zoom, keeping the caller's focal point fixed
|
|
3481
3496
|
if (z > zoomMax || z < zoomMin) {
|
|
3482
|
-
const
|
|
3497
|
+
const rz = z
|
|
3483
3498
|
z = clamp(z, zoomMin, zoomMax)
|
|
3484
|
-
x =
|
|
3485
|
-
y =
|
|
3499
|
+
x = preserveFocalPoint(currentCamera.x, x, rz, z)
|
|
3500
|
+
y = preserveFocalPoint(currentCamera.y, y, rz, z)
|
|
3486
3501
|
}
|
|
3487
3502
|
}
|
|
3488
3503
|
}
|
|
@@ -4023,16 +4038,34 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4023
4038
|
|
|
4024
4039
|
this.once('stop-camera-animation', cancel)
|
|
4025
4040
|
|
|
4041
|
+
const dirZ = direction.z ?? 0
|
|
4042
|
+
|
|
4026
4043
|
const moveCamera = (elapsed: number) => {
|
|
4027
4044
|
const { x: cx, y: cy, z: cz } = this.getCamera()
|
|
4028
|
-
|
|
4045
|
+
|
|
4046
|
+
// Pan movement from x/y direction
|
|
4047
|
+
const dx = (direction.x * (currentSpeed * elapsed)) / cz
|
|
4048
|
+
const dy = (direction.y * (currentSpeed * elapsed)) / cz
|
|
4049
|
+
|
|
4050
|
+
let newCx = cx + dx
|
|
4051
|
+
let newCy = cy + dy
|
|
4052
|
+
let newCz = cz
|
|
4053
|
+
|
|
4054
|
+
// animate zoom if z direction is passed in
|
|
4055
|
+
if (dirZ !== 0) {
|
|
4056
|
+
newCz = cz * (1 + dirZ * currentSpeed * elapsed)
|
|
4057
|
+
// Adjust x/y to keep the viewport center fixed while zooming
|
|
4058
|
+
const center = this.getViewportScreenCenter()
|
|
4059
|
+
newCx += center.x / newCz - center.x / cz
|
|
4060
|
+
newCy += center.y / newCz - center.y / cz
|
|
4061
|
+
}
|
|
4029
4062
|
|
|
4030
4063
|
// Apply friction
|
|
4031
4064
|
currentSpeed *= 1 - friction
|
|
4032
4065
|
if (currentSpeed < speedThreshold) {
|
|
4033
4066
|
cancel()
|
|
4034
4067
|
} else {
|
|
4035
|
-
this._setCamera(new Vec(
|
|
4068
|
+
this._setCamera(new Vec(newCx, newCy, newCz))
|
|
4036
4069
|
}
|
|
4037
4070
|
}
|
|
4038
4071
|
|
|
@@ -4054,7 +4087,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4054
4087
|
* @param opts - The camera move options.
|
|
4055
4088
|
* @public
|
|
4056
4089
|
*/
|
|
4057
|
-
zoomToUser(userId:
|
|
4090
|
+
zoomToUser(userId: TLUserId, opts: TLCameraMoveOptions = { animation: { duration: 500 } }): this {
|
|
4058
4091
|
const presence = this.getCollaborators().find((c) => c.userId === userId)
|
|
4059
4092
|
|
|
4060
4093
|
if (!presence) return this
|
|
@@ -4426,11 +4459,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4426
4459
|
*
|
|
4427
4460
|
* @public
|
|
4428
4461
|
*/
|
|
4429
|
-
startFollowingUser(userId:
|
|
4462
|
+
startFollowingUser(userId: TLUserId): this {
|
|
4430
4463
|
// if we were already following someone, stop following them
|
|
4431
4464
|
this.stopFollowingUser()
|
|
4432
4465
|
|
|
4433
|
-
const thisUserId = this.user.
|
|
4466
|
+
const thisUserId = this.user.getExternalId()
|
|
4434
4467
|
|
|
4435
4468
|
if (!thisUserId) {
|
|
4436
4469
|
console.warn('You should set the userId for the current instance before following a user')
|
|
@@ -8078,32 +8111,53 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8078
8111
|
* @public
|
|
8079
8112
|
*/
|
|
8080
8113
|
resizeShape(shape: TLShapeId | TLShape, scale: VecLike, opts: TLResizeShapeOptions = {}): this {
|
|
8114
|
+
const partial = this.getResizeShapePartial(shape, scale, opts)
|
|
8115
|
+
if (partial) this.updateShapes([partial])
|
|
8116
|
+
return this
|
|
8117
|
+
}
|
|
8118
|
+
|
|
8119
|
+
/**
|
|
8120
|
+
* Get the update for a resized shape without committing it to the store. Interactions that
|
|
8121
|
+
* resize many shapes at once use this to collect all of the updates and commit them in a
|
|
8122
|
+
* single batch. Returns null when there is nothing to update.
|
|
8123
|
+
*
|
|
8124
|
+
* Shapes that are rotated out of alignment with the scale axis cannot be resized with a
|
|
8125
|
+
* single update; those shapes are resized immediately (as `resizeShape` would do) and null
|
|
8126
|
+
* is returned.
|
|
8127
|
+
*
|
|
8128
|
+
* @internal
|
|
8129
|
+
*/
|
|
8130
|
+
getResizeShapePartial(
|
|
8131
|
+
shape: TLShapeId | TLShape,
|
|
8132
|
+
scale: VecLike,
|
|
8133
|
+
opts: TLResizeShapeOptions = {}
|
|
8134
|
+
): TLShapePartial | null {
|
|
8081
8135
|
const id = typeof shape === 'string' ? shape : shape.id
|
|
8082
|
-
if (this.getIsReadonly()) return
|
|
8136
|
+
if (this.getIsReadonly()) return null
|
|
8083
8137
|
|
|
8084
8138
|
if (!Number.isFinite(scale.x)) scale = new Vec(1, scale.y)
|
|
8085
8139
|
if (!Number.isFinite(scale.y)) scale = new Vec(scale.x, 1)
|
|
8086
8140
|
|
|
8087
8141
|
const initialShape = opts.initialShape ?? this.getShape(id)
|
|
8088
|
-
if (!initialShape) return
|
|
8142
|
+
if (!initialShape) return null
|
|
8089
8143
|
|
|
8090
8144
|
const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center
|
|
8091
|
-
if (!scaleOrigin) return
|
|
8145
|
+
if (!scaleOrigin) return null
|
|
8092
8146
|
|
|
8093
8147
|
const pageTransform = opts.initialPageTransform
|
|
8094
8148
|
? Mat.Cast(opts.initialPageTransform)
|
|
8095
8149
|
: this.getShapePageTransform(id)
|
|
8096
|
-
if (!pageTransform) return
|
|
8150
|
+
if (!pageTransform) return null
|
|
8097
8151
|
|
|
8098
8152
|
const pageRotation = pageTransform.rotation()
|
|
8099
8153
|
|
|
8100
|
-
if (pageRotation == null) return
|
|
8154
|
+
if (pageRotation == null) return null
|
|
8101
8155
|
|
|
8102
8156
|
const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation
|
|
8103
8157
|
|
|
8104
8158
|
const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds
|
|
8105
8159
|
|
|
8106
|
-
if (!initialBounds) return
|
|
8160
|
+
if (!initialBounds) return null
|
|
8107
8161
|
|
|
8108
8162
|
const isAspectRatioLocked =
|
|
8109
8163
|
opts.isAspectRatioLocked ?? this.getShapeUtil(initialShape).isAspectRatioLocked(initialShape)
|
|
@@ -8113,7 +8167,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8113
8167
|
// from whichever axis is being scaled the least, to avoid the shape getting bigger
|
|
8114
8168
|
// than the bounds of the selection
|
|
8115
8169
|
// const minScale = Math.min(Math.abs(scale.x), Math.abs(scale.y))
|
|
8116
|
-
|
|
8170
|
+
this._resizeUnalignedShape(id, scale, {
|
|
8117
8171
|
...opts,
|
|
8118
8172
|
initialBounds,
|
|
8119
8173
|
scaleOrigin,
|
|
@@ -8122,6 +8176,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8122
8176
|
isAspectRatioLocked,
|
|
8123
8177
|
initialShape,
|
|
8124
8178
|
})
|
|
8179
|
+
return null
|
|
8125
8180
|
}
|
|
8126
8181
|
|
|
8127
8182
|
const util = this.getShapeUtil(initialShape)
|
|
@@ -8134,7 +8189,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8134
8189
|
}
|
|
8135
8190
|
}
|
|
8136
8191
|
|
|
8137
|
-
let
|
|
8192
|
+
let workingShape: TLShape | null = null
|
|
8138
8193
|
|
|
8139
8194
|
if (util.onResize && util.canResize(initialShape)) {
|
|
8140
8195
|
// get the model changes from the shape util
|
|
@@ -8166,7 +8221,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8166
8221
|
// need to adjust the shape's x and y points in case the parent has moved since start of resizing
|
|
8167
8222
|
const { x, y } = this.getPointInParentSpace(initialShape.id, initialPagePoint)
|
|
8168
8223
|
|
|
8169
|
-
|
|
8224
|
+
workingShape = initialShape
|
|
8170
8225
|
if (!opts.skipStartAndEndCallbacks) {
|
|
8171
8226
|
workingShape = applyPartialToRecordWithProps(
|
|
8172
8227
|
initialShape,
|
|
@@ -8188,10 +8243,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8188
8243
|
}
|
|
8189
8244
|
)
|
|
8190
8245
|
|
|
8191
|
-
if (resizedShape) {
|
|
8192
|
-
didResize = true
|
|
8193
|
-
}
|
|
8194
|
-
|
|
8195
8246
|
workingShape = applyPartialToRecordWithProps(workingShape, {
|
|
8196
8247
|
id,
|
|
8197
8248
|
type: initialShape.type as any,
|
|
@@ -8207,40 +8258,47 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8207
8258
|
)
|
|
8208
8259
|
}
|
|
8209
8260
|
|
|
8210
|
-
|
|
8261
|
+
if (resizedShape) {
|
|
8262
|
+
return workingShape
|
|
8263
|
+
}
|
|
8211
8264
|
}
|
|
8212
8265
|
|
|
8213
|
-
|
|
8214
|
-
|
|
8266
|
+
// the shape was not resized by its util, so reposition it (rather than resizing it)
|
|
8267
|
+
// based on where its resized center would be
|
|
8215
8268
|
|
|
8216
|
-
|
|
8217
|
-
|
|
8218
|
-
|
|
8219
|
-
|
|
8220
|
-
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8269
|
+
const initialPageCenter = Mat.applyToPoint(pageTransform, initialBounds.center)
|
|
8270
|
+
// get the model changes from the shape util
|
|
8271
|
+
const newPageCenter = this._scalePagePoint(
|
|
8272
|
+
initialPageCenter,
|
|
8273
|
+
scaleOrigin,
|
|
8274
|
+
scale,
|
|
8275
|
+
scaleAxisRotation
|
|
8276
|
+
)
|
|
8224
8277
|
|
|
8225
|
-
|
|
8226
|
-
|
|
8227
|
-
|
|
8228
|
-
|
|
8229
|
-
|
|
8278
|
+
const initialPageCenterInParentSpace = this.getPointInParentSpace(
|
|
8279
|
+
initialShape.id,
|
|
8280
|
+
initialPageCenter
|
|
8281
|
+
)
|
|
8282
|
+
const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter)
|
|
8230
8283
|
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
|
|
8237
|
-
|
|
8238
|
-
|
|
8239
|
-
|
|
8240
|
-
|
|
8284
|
+
const delta = Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace)
|
|
8285
|
+
|
|
8286
|
+
if (workingShape) {
|
|
8287
|
+
// the util's onResize ran but returned no change; keep the working update (which may
|
|
8288
|
+
// include changes from onResizeStart / onResizeEnd) and reposition the shape
|
|
8289
|
+
return {
|
|
8290
|
+
...workingShape,
|
|
8291
|
+
x: initialShape.x + delta.x,
|
|
8292
|
+
y: initialShape.y + delta.y,
|
|
8293
|
+
}
|
|
8241
8294
|
}
|
|
8242
8295
|
|
|
8243
|
-
return
|
|
8296
|
+
return {
|
|
8297
|
+
id,
|
|
8298
|
+
type: initialShape.type as any,
|
|
8299
|
+
x: initialShape.x + delta.x,
|
|
8300
|
+
y: initialShape.y + delta.y,
|
|
8301
|
+
}
|
|
8244
8302
|
}
|
|
8245
8303
|
|
|
8246
8304
|
/** @internal */
|
|
@@ -10768,6 +10826,16 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10768
10826
|
/** @internal */
|
|
10769
10827
|
private _selectedShapeIdsAtPointerDown: TLShapeId[] = []
|
|
10770
10828
|
|
|
10829
|
+
/**
|
|
10830
|
+
* Whether `_selectedShapeIdsAtPointerDown` holds a pre-gesture selection
|
|
10831
|
+
* captured by a `pointer_down` (the touch path) that a following pinch
|
|
10832
|
+
* should restore. False when no pointer_down preceded the pinch (the
|
|
10833
|
+
* Safari trackpad path uses gesture events), in which case `pinch_start`
|
|
10834
|
+
* captures the live selection instead.
|
|
10835
|
+
* @internal
|
|
10836
|
+
*/
|
|
10837
|
+
private _didCaptureSelectionAtPointerDown = false
|
|
10838
|
+
|
|
10771
10839
|
/** @internal */
|
|
10772
10840
|
private _longPressTimeout = -1 as any
|
|
10773
10841
|
|
|
@@ -10933,16 +11001,28 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10933
11001
|
if (inputs.getIsPinching()) return
|
|
10934
11002
|
|
|
10935
11003
|
if (!inputs.getIsEditing()) {
|
|
10936
|
-
//
|
|
10937
|
-
//
|
|
10938
|
-
//
|
|
10939
|
-
|
|
11004
|
+
// If a pointer_down already captured the pre-gesture selection,
|
|
11005
|
+
// keep it: on touch, the first finger's pointer_down can change
|
|
11006
|
+
// the selection before the second finger starts the pinch, and we
|
|
11007
|
+
// want to restore the selection from before that change. When no
|
|
11008
|
+
// pointer_down preceded the pinch (Safari delivers trackpad pinches
|
|
11009
|
+
// as gesture events), capture the live selection now.
|
|
11010
|
+
if (!this._didCaptureSelectionAtPointerDown) {
|
|
11011
|
+
this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds]
|
|
11012
|
+
}
|
|
10940
11013
|
|
|
10941
11014
|
this._didPinch = true
|
|
10942
11015
|
|
|
10943
11016
|
inputs.setIsPinching(true)
|
|
10944
11017
|
|
|
10945
11018
|
this.interrupt()
|
|
11019
|
+
|
|
11020
|
+
// If the first finger changed the selection, roll it back now rather
|
|
11021
|
+
// than waiting for the pinch to end, so the pre-gesture selection is
|
|
11022
|
+
// what's shown during the pinch.
|
|
11023
|
+
if (this._didCaptureSelectionAtPointerDown) {
|
|
11024
|
+
this.setSelectedShapes(this._selectedShapeIdsAtPointerDown)
|
|
11025
|
+
}
|
|
10946
11026
|
}
|
|
10947
11027
|
|
|
10948
11028
|
this.emit('event', info)
|
|
@@ -10994,6 +11074,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10994
11074
|
const { _selectedShapeIdsAtPointerDown: shapesToReselect } = this
|
|
10995
11075
|
this.setSelectedShapes(this._selectedShapeIdsAtPointerDown)
|
|
10996
11076
|
this._selectedShapeIdsAtPointerDown = []
|
|
11077
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
10997
11078
|
|
|
10998
11079
|
if (this._didPinch) {
|
|
10999
11080
|
this._didPinch = false
|
|
@@ -11122,8 +11203,15 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11122
11203
|
}, this.options.longPressDurationMs)
|
|
11123
11204
|
}
|
|
11124
11205
|
|
|
11125
|
-
// Save the selected ids at
|
|
11126
|
-
|
|
11206
|
+
// Save the selected ids at the start of an interaction so a pinch can
|
|
11207
|
+
// restore the pre-gesture selection. Only capture on the first pointer:
|
|
11208
|
+
// on touch, the second finger's pointer_down arrives after the first
|
|
11209
|
+
// has already changed the selection, and we want the earlier snapshot.
|
|
11210
|
+
// Cleared on pointer_up / pinch_end.
|
|
11211
|
+
if (!this._didCaptureSelectionAtPointerDown) {
|
|
11212
|
+
this._selectedShapeIdsAtPointerDown = this.getSelectedShapeIds()
|
|
11213
|
+
this._didCaptureSelectionAtPointerDown = true
|
|
11214
|
+
}
|
|
11127
11215
|
|
|
11128
11216
|
// Firefox bug fix...
|
|
11129
11217
|
// If it's a left-mouse-click, we store the pointer id for later user
|
|
@@ -11137,7 +11225,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11137
11225
|
inputs.setIsDragging(false)
|
|
11138
11226
|
|
|
11139
11227
|
// If pen mode is off but we're not already in pen mode, turn that on
|
|
11140
|
-
if (!isPenMode && isPen)
|
|
11228
|
+
if (!isPenMode && isPen) {
|
|
11229
|
+
this.updateInstanceState({ isPenMode: true })
|
|
11230
|
+
// Once pen mode is on, touch input is ignored, so we discard the
|
|
11231
|
+
// in-progress touch interaction .
|
|
11232
|
+
this.interrupt()
|
|
11233
|
+
}
|
|
11141
11234
|
|
|
11142
11235
|
// On devices with erasers (like the Surface Pen or Wacom Pen), button 5 is the eraser
|
|
11143
11236
|
if (info.button === STYLUS_ERASER_BUTTON) {
|
|
@@ -11243,6 +11336,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11243
11336
|
if (this.inputs.getIsRightPointing() && !this.inputs.getIsPanning()) {
|
|
11244
11337
|
this.inputs.setIsRightPointing(false)
|
|
11245
11338
|
this._selectedShapeIdsAtPointerDown = []
|
|
11339
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11246
11340
|
break // fall through to state chart dispatch as right_click
|
|
11247
11341
|
}
|
|
11248
11342
|
|
|
@@ -11286,15 +11380,22 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11286
11380
|
// Don't pass right-click panning events to the state chart
|
|
11287
11381
|
// as it causes unintended shape selection on release
|
|
11288
11382
|
if (slideSpeed > 0) {
|
|
11289
|
-
this.slideCamera({
|
|
11383
|
+
this.slideCamera({
|
|
11384
|
+
speed: slideSpeed,
|
|
11385
|
+
direction: { x: slideDirection.x, y: slideDirection.y, z: 0 },
|
|
11386
|
+
})
|
|
11290
11387
|
}
|
|
11291
11388
|
this._selectedShapeIdsAtPointerDown = []
|
|
11389
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11292
11390
|
return this
|
|
11293
11391
|
}
|
|
11294
11392
|
}
|
|
11295
11393
|
|
|
11296
11394
|
if (slideSpeed > 0) {
|
|
11297
|
-
this.slideCamera({
|
|
11395
|
+
this.slideCamera({
|
|
11396
|
+
speed: slideSpeed,
|
|
11397
|
+
direction: { x: slideDirection.x, y: slideDirection.y, z: 0 },
|
|
11398
|
+
})
|
|
11298
11399
|
}
|
|
11299
11400
|
} else {
|
|
11300
11401
|
if (info.button === STYLUS_ERASER_BUTTON) {
|
|
@@ -11307,6 +11408,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
11307
11408
|
// Clear the stashed selection so the next pinch captures fresh state.
|
|
11308
11409
|
// This fixes Safari pinch zoom restoring outdated selections.
|
|
11309
11410
|
this._selectedShapeIdsAtPointerDown = []
|
|
11411
|
+
this._didCaptureSelectionAtPointerDown = false
|
|
11310
11412
|
|
|
11311
11413
|
break
|
|
11312
11414
|
}
|
|
@@ -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() {
|