@tldraw/editor 4.1.0-canary.24319e4fb924 → 4.1.0-canary.25dd14633e5b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +1 -0
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/editor/Editor.js +1 -1
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js +67 -2
- package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -1
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +2 -0
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +5 -0
- package/dist-cjs/lib/primitives/geometry/Geometry2d.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 +1 -0
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/editor/Editor.mjs +2 -1
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs +67 -2
- package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -1
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +2 -0
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +5 -0
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/lib/editor/Editor.ts +2 -1
- package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +91 -4
- package/src/lib/hooks/useCanvasEvents.ts +8 -1
- package/src/lib/license/LicenseManager.ts +8 -0
- package/src/lib/primitives/geometry/Geometry2d.ts +6 -0
- package/src/version.ts +3 -3
|
@@ -4,7 +4,7 @@ import { assertExists, uniqueId } from '@tldraw/utils'
|
|
|
4
4
|
import { Vec } from '../../../primitives/Vec'
|
|
5
5
|
import { Geometry2d } from '../../../primitives/geometry/Geometry2d'
|
|
6
6
|
import { Editor } from '../../Editor'
|
|
7
|
-
import { SnapData, SnapManager } from './SnapManager'
|
|
7
|
+
import { PointsSnapIndicator, SnapData, SnapManager } from './SnapManager'
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* When dragging a handle, users can snap the handle to key geometry on other nearby shapes.
|
|
@@ -43,6 +43,11 @@ export interface HandleSnapGeometry {
|
|
|
43
43
|
getSelfSnapPoints?(handle: TLHandle): VecModel[]
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
interface AlignPointsSnap {
|
|
47
|
+
snaps: PointsSnapIndicator[]
|
|
48
|
+
nudge: Vec
|
|
49
|
+
}
|
|
50
|
+
|
|
46
51
|
const defaultGetSelfSnapOutline = () => null
|
|
47
52
|
const defaultGetSelfSnapPoints = () => []
|
|
48
53
|
/** @public */
|
|
@@ -171,6 +176,67 @@ export class HandleSnaps {
|
|
|
171
176
|
return null
|
|
172
177
|
}
|
|
173
178
|
|
|
179
|
+
private getHandleSnapData({
|
|
180
|
+
handle,
|
|
181
|
+
currentShapeId,
|
|
182
|
+
}: {
|
|
183
|
+
handle: TLHandle
|
|
184
|
+
currentShapeId: TLShapeId
|
|
185
|
+
}): AlignPointsSnap | null {
|
|
186
|
+
const snapThreshold = this.manager.getSnapThreshold()
|
|
187
|
+
const currentShapeTransform = assertExists(this.editor.getShapePageTransform(currentShapeId))
|
|
188
|
+
const handleInPageSpace = currentShapeTransform.applyToPoint(handle)
|
|
189
|
+
|
|
190
|
+
let nearestXSnap: Vec | null = null
|
|
191
|
+
let nearestYSnap: Vec | null = null
|
|
192
|
+
let minOffsetX = snapThreshold
|
|
193
|
+
let minOffsetY = snapThreshold
|
|
194
|
+
|
|
195
|
+
for (const snapPoint of this.iterateSnapPointsInPageSpace(currentShapeId, handle)) {
|
|
196
|
+
const offsetX = Math.abs(handleInPageSpace.x - snapPoint.x)
|
|
197
|
+
const offsetY = Math.abs(handleInPageSpace.y - snapPoint.y)
|
|
198
|
+
if (offsetX < minOffsetX) {
|
|
199
|
+
minOffsetX = offsetX
|
|
200
|
+
nearestXSnap = snapPoint
|
|
201
|
+
}
|
|
202
|
+
if (offsetY < minOffsetY) {
|
|
203
|
+
minOffsetY = offsetY
|
|
204
|
+
nearestYSnap = snapPoint
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (!nearestXSnap && !nearestYSnap) {
|
|
209
|
+
return null
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const nudge = new Vec(
|
|
213
|
+
nearestXSnap ? nearestXSnap.x - handleInPageSpace.x : 0,
|
|
214
|
+
nearestYSnap ? nearestYSnap.y - handleInPageSpace.y : 0
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
const snappedHandle = Vec.Add(handleInPageSpace, nudge)
|
|
218
|
+
const snaps: PointsSnapIndicator[] = []
|
|
219
|
+
|
|
220
|
+
if (nearestXSnap) {
|
|
221
|
+
const snappedHandleOnX = new Vec(nearestXSnap.x, snappedHandle.y)
|
|
222
|
+
snaps.push({
|
|
223
|
+
id: uniqueId(),
|
|
224
|
+
type: 'points',
|
|
225
|
+
points: [nearestXSnap, snappedHandleOnX],
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
if (nearestYSnap) {
|
|
229
|
+
const snappedHandleOnY = new Vec(snappedHandle.x, nearestYSnap.y)
|
|
230
|
+
snaps.push({
|
|
231
|
+
id: uniqueId(),
|
|
232
|
+
type: 'points',
|
|
233
|
+
points: [nearestYSnap, snappedHandleOnY],
|
|
234
|
+
})
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return { snaps, nudge }
|
|
238
|
+
}
|
|
239
|
+
|
|
174
240
|
snapHandle({
|
|
175
241
|
currentShapeId,
|
|
176
242
|
handle,
|
|
@@ -180,10 +246,16 @@ export class HandleSnaps {
|
|
|
180
246
|
}): SnapData | null {
|
|
181
247
|
const currentShapeTransform = assertExists(this.editor.getShapePageTransform(currentShapeId))
|
|
182
248
|
const handleInPageSpace = currentShapeTransform.applyToPoint(handle)
|
|
183
|
-
|
|
249
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
250
|
+
const snapType = handle.canSnap ? 'point' : handle.snapType
|
|
251
|
+
|
|
252
|
+
if (snapType === 'point') {
|
|
253
|
+
const snapPosition = this.getHandleSnapPosition({ currentShapeId, handle, handleInPageSpace })
|
|
254
|
+
|
|
255
|
+
if (!snapPosition) {
|
|
256
|
+
return null
|
|
257
|
+
}
|
|
184
258
|
|
|
185
|
-
// If we found a point, display snap lines, and return the nudge
|
|
186
|
-
if (snapPosition) {
|
|
187
259
|
this.manager.setIndicators([
|
|
188
260
|
{
|
|
189
261
|
id: uniqueId(),
|
|
@@ -195,6 +267,21 @@ export class HandleSnaps {
|
|
|
195
267
|
return { nudge: Vec.Sub(snapPosition, handleInPageSpace) }
|
|
196
268
|
}
|
|
197
269
|
|
|
270
|
+
if (snapType === 'align') {
|
|
271
|
+
const snapData = this.getHandleSnapData({
|
|
272
|
+
handle,
|
|
273
|
+
currentShapeId,
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
if (!snapData) {
|
|
277
|
+
return null
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
this.manager.setIndicators(snapData.snaps)
|
|
281
|
+
|
|
282
|
+
return { nudge: snapData.nudge }
|
|
283
|
+
}
|
|
284
|
+
|
|
198
285
|
return null
|
|
199
286
|
}
|
|
200
287
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { useValue } from '@tldraw/state-react'
|
|
2
2
|
import React, { useEffect, useMemo } from 'react'
|
|
3
3
|
import { RIGHT_MOUSE_BUTTON } from '../constants'
|
|
4
|
+
import { tlenv } from '../globals/environment'
|
|
4
5
|
import { preventDefault, releasePointerCapture, setPointerCapture } from '../utils/dom'
|
|
5
6
|
import { getPointerInfo } from '../utils/getPointerInfo'
|
|
6
7
|
import { useEditor } from './useEditor'
|
|
@@ -161,8 +162,14 @@ export function useCanvasEvents() {
|
|
|
161
162
|
// For tools that benefit from a higher fidelity of events,
|
|
162
163
|
// we dispatch the coalesced events.
|
|
163
164
|
// N.B. Sometimes getCoalescedEvents isn't present on iOS, ugh.
|
|
165
|
+
// Specifically, in local mode (non-https) mode, iOS does not `useCoalescedEvents`
|
|
166
|
+
// so it appears like the ink is working locally, when really it's just that `useCoalescedEvents`
|
|
167
|
+
// is disabled. The intent here is to have `useCoalescedEvents` disabled for iOS.
|
|
164
168
|
const events =
|
|
165
|
-
|
|
169
|
+
!tlenv.isIos && currentTool.useCoalescedEvents && e.getCoalescedEvents
|
|
170
|
+
? e.getCoalescedEvents()
|
|
171
|
+
: [e]
|
|
172
|
+
|
|
166
173
|
for (const singleEvent of events) {
|
|
167
174
|
editor.dispatch({
|
|
168
175
|
type: 'pointer',
|
|
@@ -171,6 +171,14 @@ export class LicenseManager {
|
|
|
171
171
|
url.searchParams.set('license_type', trackType)
|
|
172
172
|
if ('license' in result) {
|
|
173
173
|
url.searchParams.set('license_id', result.license.id)
|
|
174
|
+
const sku = this.isFlagEnabled(result.license.flags, FLAGS.EVALUATION_LICENSE)
|
|
175
|
+
? 'evaluation'
|
|
176
|
+
: this.isFlagEnabled(result.license.flags, FLAGS.ANNUAL_LICENSE)
|
|
177
|
+
? 'annual'
|
|
178
|
+
: this.isFlagEnabled(result.license.flags, FLAGS.PERPETUAL_LICENSE)
|
|
179
|
+
? 'perpetual'
|
|
180
|
+
: 'unknown'
|
|
181
|
+
url.searchParams.set('sku', sku)
|
|
174
182
|
}
|
|
175
183
|
if (process.env.NODE_ENV) {
|
|
176
184
|
url.searchParams.set('environment', process.env.NODE_ENV)
|
|
@@ -120,6 +120,8 @@ export abstract class Geometry2d {
|
|
|
120
120
|
distanceToLineSegment(A: VecLike, B: VecLike, filters?: Geometry2dFilters) {
|
|
121
121
|
if (Vec.Equals(A, B)) return this.distanceToPoint(A, false, filters)
|
|
122
122
|
const { vertices } = this
|
|
123
|
+
if (vertices.length === 0) throw Error('nearest point not found')
|
|
124
|
+
if (vertices.length === 1) return Vec.Dist(A, vertices[0])
|
|
123
125
|
let nearest: Vec | undefined
|
|
124
126
|
let dist = Infinity
|
|
125
127
|
let d: number, p: Vec, q: Vec
|
|
@@ -175,6 +177,8 @@ export abstract class Geometry2d {
|
|
|
175
177
|
interpolateAlongEdge(t: number, _filters?: Geometry2dFilters): Vec {
|
|
176
178
|
const { vertices } = this
|
|
177
179
|
|
|
180
|
+
if (vertices.length === 0) return new Vec(0, 0)
|
|
181
|
+
if (vertices.length === 1) return vertices[0]
|
|
178
182
|
if (t <= 0) return vertices[0]
|
|
179
183
|
|
|
180
184
|
const distanceToTravel = t * this.length
|
|
@@ -209,6 +213,8 @@ export abstract class Geometry2d {
|
|
|
209
213
|
let closestDistance = Infinity
|
|
210
214
|
let distanceTraveled = 0
|
|
211
215
|
|
|
216
|
+
if (vertices.length === 0 || vertices.length === 1) return 0
|
|
217
|
+
|
|
212
218
|
for (let i = 0; i < (this.isClosed ? vertices.length : vertices.length - 1); i++) {
|
|
213
219
|
const curr = vertices[i]
|
|
214
220
|
const next = vertices[(i + 1) % vertices.length]
|
package/src/version.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This file is automatically generated by internal/scripts/refresh-assets.ts.
|
|
2
2
|
// Do not edit manually. Or do, I'm a comment, not a cop.
|
|
3
3
|
|
|
4
|
-
export const version = '4.1.0-canary.
|
|
4
|
+
export const version = '4.1.0-canary.25dd14633e5b'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2025-09-18T14:39:22.803Z',
|
|
7
|
-
minor: '2025-10-
|
|
8
|
-
patch: '2025-10-
|
|
7
|
+
minor: '2025-10-15T09:39:34.246Z',
|
|
8
|
+
patch: '2025-10-15T09:39:34.246Z',
|
|
9
9
|
}
|