@tldraw/editor 4.3.0-next.7f179bd04d6c → 4.3.0-next.842fb21476f2
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 +441 -120
- package/dist-cjs/index.js +6 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/ErrorBoundary.js.map +1 -1
- package/dist-cjs/lib/components/GeometryDebuggingView.js +1 -17
- package/dist-cjs/lib/components/GeometryDebuggingView.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +3 -3
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/constants.js +1 -3
- package/dist-cjs/lib/constants.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +288 -275
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +18 -17
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +3 -3
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js +12 -3
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +1 -1
- package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +5 -6
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +591 -0
- package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +7 -0
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +1 -1
- package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +1 -22
- package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +31 -23
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js +1 -1
- package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js.map +2 -2
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +3 -3
- package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
- package/dist-cjs/lib/exports/parseCss.js +1 -1
- package/dist-cjs/lib/exports/parseCss.js.map +2 -2
- package/dist-cjs/lib/globals/environment.js +45 -9
- package/dist-cjs/lib/globals/environment.js.map +2 -2
- package/dist-cjs/lib/hooks/useCoarsePointer.js +14 -29
- package/dist-cjs/lib/hooks/useCoarsePointer.js.map +2 -2
- package/dist-cjs/lib/hooks/useEvent.js +1 -1
- package/dist-cjs/lib/hooks/useEvent.js.map +2 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useGestureEvents.js +1 -1
- package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
- package/dist-cjs/lib/hooks/useStateAttribute.js +4 -1
- package/dist-cjs/lib/hooks/useStateAttribute.js.map +2 -2
- package/dist-cjs/lib/hooks/useTransform.js.map +1 -1
- package/dist-cjs/lib/hooks/useZoomCss.js +4 -8
- package/dist-cjs/lib/hooks/useZoomCss.js.map +2 -2
- package/dist-cjs/lib/options.js +6 -1
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +3 -0
- package/dist-cjs/lib/primitives/Box.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +1 -0
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/utils/rotation.js +1 -1
- package/dist-cjs/lib/utils/rotation.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 +441 -120
- package/dist-esm/index.mjs +7 -2
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/ErrorBoundary.mjs.map +1 -1
- package/dist-esm/lib/components/GeometryDebuggingView.mjs +1 -17
- package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +3 -3
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/constants.mjs +1 -3
- package/dist-esm/lib/constants.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +289 -278
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +18 -17
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +3 -3
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +13 -4
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +5 -6
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +573 -0
- package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +7 -0
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +1 -22
- package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +31 -23
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/group/DashedOutlineBox.mjs +1 -1
- package/dist-esm/lib/editor/shapes/group/DashedOutlineBox.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +3 -3
- package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
- package/dist-esm/lib/exports/parseCss.mjs +1 -1
- package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
- package/dist-esm/lib/globals/environment.mjs +45 -9
- package/dist-esm/lib/globals/environment.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCoarsePointer.mjs +15 -30
- package/dist-esm/lib/hooks/useCoarsePointer.mjs.map +2 -2
- package/dist-esm/lib/hooks/useEvent.mjs +1 -1
- package/dist-esm/lib/hooks/useEvent.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs +1 -1
- package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
- package/dist-esm/lib/hooks/useStateAttribute.mjs +4 -1
- package/dist-esm/lib/hooks/useStateAttribute.mjs.map +2 -2
- package/dist-esm/lib/hooks/useTransform.mjs.map +1 -1
- package/dist-esm/lib/hooks/useZoomCss.mjs +4 -8
- package/dist-esm/lib/hooks/useZoomCss.mjs.map +2 -2
- package/dist-esm/lib/options.mjs +6 -1
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +3 -0
- package/dist-esm/lib/primitives/Box.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +1 -0
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/utils/rotation.mjs +1 -1
- package/dist-esm/lib/utils/rotation.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +14 -12
- package/package.json +18 -16
- package/src/index.ts +4 -1
- package/src/lib/components/ErrorBoundary.tsx +1 -1
- package/src/lib/components/GeometryDebuggingView.tsx +1 -19
- package/src/lib/components/default-components/DefaultCanvas.tsx +3 -3
- package/src/lib/config/TLUserPreferences.test.ts +40 -0
- package/src/lib/constants.ts +0 -2
- package/src/lib/editor/Editor.test.ts +140 -0
- package/src/lib/editor/Editor.ts +374 -321
- package/src/lib/editor/derivations/notVisibleShapes.ts +37 -23
- package/src/lib/editor/derivations/parentsToChildren.ts +18 -7
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +17 -31
- package/src/lib/editor/managers/ClickManager/ClickManager.ts +1 -1
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +129 -79
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +10 -6
- package/src/lib/editor/managers/InputsManager/InputsManager.ts +566 -0
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +0 -4
- package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +12 -0
- package/src/lib/editor/managers/SnapManager/SnapManager.ts +1 -1
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +40 -107
- package/src/lib/editor/managers/TickManager/TickManager.ts +2 -32
- package/src/lib/editor/shapes/ShapeUtil.ts +67 -24
- package/src/lib/editor/shapes/group/DashedOutlineBox.tsx +1 -1
- package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +3 -3
- package/src/lib/exports/parseCss.test.ts +1 -0
- package/src/lib/exports/parseCss.ts +1 -1
- package/src/lib/globals/environment.ts +65 -10
- package/src/lib/hooks/useCoarsePointer.ts +16 -59
- package/src/lib/hooks/useEvent.tsx +1 -1
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -1
- package/src/lib/hooks/useGestureEvents.ts +2 -2
- package/src/lib/hooks/usePassThroughMouseOverEvents.ts +1 -1
- package/src/lib/hooks/usePassThroughWheelEvents.ts +1 -1
- package/src/lib/hooks/useScreenBounds.ts +1 -1
- package/src/lib/hooks/useStateAttribute.ts +4 -1
- package/src/lib/hooks/useTransform.ts +1 -1
- package/src/lib/hooks/useZoomCss.ts +3 -8
- package/src/lib/options.ts +32 -0
- package/src/lib/primitives/Box.ts +9 -0
- package/src/lib/primitives/geometry/Geometry2d.ts +1 -0
- package/src/lib/utils/rotation.ts +1 -1
- package/src/version.ts +3 -3
|
@@ -21,6 +21,17 @@ describe('TickManager', () => {
|
|
|
21
21
|
let tickManager: TickManager
|
|
22
22
|
let mockEmit: Mock
|
|
23
23
|
let mockDisposablesAdd: Mock
|
|
24
|
+
let mockInputs: {
|
|
25
|
+
_currentScreenPoint: Vec
|
|
26
|
+
getCurrentScreenPoint(): Vec
|
|
27
|
+
currentScreenPoint: Vec
|
|
28
|
+
setCurrentScreenPoint(value: Vec): void
|
|
29
|
+
_pointerVelocity: Vec
|
|
30
|
+
getPointerVelocity(): Vec
|
|
31
|
+
pointerVelocity: Vec
|
|
32
|
+
setPointerVelocity(value: Vec): void
|
|
33
|
+
updatePointerVelocity(elapsed: number): void
|
|
34
|
+
}
|
|
24
35
|
|
|
25
36
|
beforeEach(() => {
|
|
26
37
|
vi.clearAllMocks()
|
|
@@ -41,16 +52,40 @@ describe('TickManager', () => {
|
|
|
41
52
|
mockEmit = vi.fn()
|
|
42
53
|
mockDisposablesAdd = vi.fn()
|
|
43
54
|
|
|
55
|
+
// Create a mock inputs object with getters and setters
|
|
56
|
+
mockInputs = {
|
|
57
|
+
_currentScreenPoint: new Vec(100, 100),
|
|
58
|
+
getCurrentScreenPoint() {
|
|
59
|
+
return this._currentScreenPoint
|
|
60
|
+
},
|
|
61
|
+
get currentScreenPoint() {
|
|
62
|
+
return this.getCurrentScreenPoint()
|
|
63
|
+
},
|
|
64
|
+
setCurrentScreenPoint(value: Vec) {
|
|
65
|
+
this._currentScreenPoint = value
|
|
66
|
+
},
|
|
67
|
+
_pointerVelocity: new Vec(0, 0),
|
|
68
|
+
getPointerVelocity() {
|
|
69
|
+
return this._pointerVelocity
|
|
70
|
+
},
|
|
71
|
+
get pointerVelocity() {
|
|
72
|
+
return this.getPointerVelocity()
|
|
73
|
+
},
|
|
74
|
+
setPointerVelocity(value: Vec) {
|
|
75
|
+
this._pointerVelocity = value
|
|
76
|
+
},
|
|
77
|
+
updatePointerVelocity(_elapsed: number) {
|
|
78
|
+
// Mock implementation - no-op for tests
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
44
82
|
editor = {
|
|
45
83
|
emit: mockEmit,
|
|
46
84
|
disposables: {
|
|
47
85
|
add: mockDisposablesAdd,
|
|
48
86
|
},
|
|
49
|
-
inputs:
|
|
50
|
-
|
|
51
|
-
pointerVelocity: new Vec(0, 0),
|
|
52
|
-
},
|
|
53
|
-
} as any
|
|
87
|
+
inputs: mockInputs as unknown as Editor['inputs'],
|
|
88
|
+
} as unknown as Mocked<Editor>
|
|
54
89
|
|
|
55
90
|
tickManager = new TickManager(editor)
|
|
56
91
|
})
|
|
@@ -143,16 +178,6 @@ describe('TickManager', () => {
|
|
|
143
178
|
expect(mockEmit).toHaveBeenCalledTimes(2)
|
|
144
179
|
})
|
|
145
180
|
|
|
146
|
-
it('should update pointer velocity', () => {
|
|
147
|
-
const updatePointerVelocitySpy = vi.spyOn(tickManager as any, 'updatePointerVelocity')
|
|
148
|
-
tickManager.now = 1000
|
|
149
|
-
mockDateNow.mockReturnValue(1016)
|
|
150
|
-
|
|
151
|
-
tickManager.tick()
|
|
152
|
-
|
|
153
|
-
expect(updatePointerVelocitySpy).toHaveBeenCalledWith(16)
|
|
154
|
-
})
|
|
155
|
-
|
|
156
181
|
it('should schedule next RAF', () => {
|
|
157
182
|
tickManager.tick()
|
|
158
183
|
expect(mockRequestAnimationFrame).toHaveBeenCalled()
|
|
@@ -192,98 +217,6 @@ describe('TickManager', () => {
|
|
|
192
217
|
})
|
|
193
218
|
})
|
|
194
219
|
|
|
195
|
-
describe('updatePointerVelocity method', () => {
|
|
196
|
-
let updatePointerVelocity: any
|
|
197
|
-
|
|
198
|
-
beforeEach(() => {
|
|
199
|
-
// Access private method for testing
|
|
200
|
-
updatePointerVelocity = (tickManager as any).updatePointerVelocity.bind(tickManager)
|
|
201
|
-
// Reset the prevPoint to a known state
|
|
202
|
-
;(tickManager as any).prevPoint = new Vec(50, 50)
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
it('should return early if elapsed time is 0', () => {
|
|
206
|
-
const originalVelocity = editor.inputs.pointerVelocity.clone()
|
|
207
|
-
|
|
208
|
-
updatePointerVelocity(0)
|
|
209
|
-
|
|
210
|
-
expect(editor.inputs.pointerVelocity).toEqual(originalVelocity)
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
it('should calculate velocity based on pointer movement', () => {
|
|
214
|
-
editor.inputs.currentScreenPoint = new Vec(150, 150)
|
|
215
|
-
;(tickManager as any).prevPoint = new Vec(50, 50)
|
|
216
|
-
editor.inputs.pointerVelocity = new Vec(0, 0)
|
|
217
|
-
|
|
218
|
-
updatePointerVelocity(100) // 100ms elapsed
|
|
219
|
-
|
|
220
|
-
// Delta should be (100, 100), length = ~141.42, direction = (~0.707, ~0.707)
|
|
221
|
-
// Velocity should be length/elapsed = ~1.414 per ms in each direction
|
|
222
|
-
// But with linear interpolation (lrp factor 0.5), it will be halved
|
|
223
|
-
const expectedVelocity = new Vec(0.5, 0.5) // With lrp factor 0.5
|
|
224
|
-
expect(editor.inputs.pointerVelocity.x).toBeCloseTo(expectedVelocity.x, 1)
|
|
225
|
-
expect(editor.inputs.pointerVelocity.y).toBeCloseTo(expectedVelocity.y, 1)
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
it('should update prevPoint to current screen point', () => {
|
|
229
|
-
const newPoint = new Vec(200, 200)
|
|
230
|
-
editor.inputs.currentScreenPoint = newPoint
|
|
231
|
-
|
|
232
|
-
updatePointerVelocity(16)
|
|
233
|
-
|
|
234
|
-
expect((tickManager as any).prevPoint).toEqual(newPoint)
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
it('should use linear interpolation to smooth velocity', () => {
|
|
238
|
-
editor.inputs.currentScreenPoint = new Vec(150, 50)
|
|
239
|
-
;(tickManager as any).prevPoint = new Vec(50, 50)
|
|
240
|
-
editor.inputs.pointerVelocity = new Vec(2, 2)
|
|
241
|
-
|
|
242
|
-
updatePointerVelocity(100)
|
|
243
|
-
|
|
244
|
-
// Should interpolate between current velocity (2,2) and new velocity (1,0)
|
|
245
|
-
// lrp with factor 0.5 should give us something between them
|
|
246
|
-
expect(editor.inputs.pointerVelocity.x).toBeGreaterThan(0.5)
|
|
247
|
-
expect(editor.inputs.pointerVelocity.x).toBeLessThan(2)
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
it('should set very small velocity components to 0', () => {
|
|
251
|
-
editor.inputs.currentScreenPoint = new Vec(50.005, 50.005)
|
|
252
|
-
;(tickManager as any).prevPoint = new Vec(50, 50)
|
|
253
|
-
editor.inputs.pointerVelocity = new Vec(0, 0)
|
|
254
|
-
|
|
255
|
-
updatePointerVelocity(1000) // Long elapsed time = very small velocity
|
|
256
|
-
|
|
257
|
-
expect(editor.inputs.pointerVelocity.x).toBe(0)
|
|
258
|
-
expect(editor.inputs.pointerVelocity.y).toBe(0)
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
it('should handle zero movement (stationary pointer)', () => {
|
|
262
|
-
editor.inputs.currentScreenPoint = new Vec(100, 100)
|
|
263
|
-
;(tickManager as any).prevPoint = new Vec(100, 100)
|
|
264
|
-
editor.inputs.pointerVelocity = new Vec(1, 1)
|
|
265
|
-
|
|
266
|
-
updatePointerVelocity(16)
|
|
267
|
-
|
|
268
|
-
// Should interpolate towards zero velocity
|
|
269
|
-
expect(editor.inputs.pointerVelocity.x).toBeLessThan(1)
|
|
270
|
-
expect(editor.inputs.pointerVelocity.y).toBeLessThan(1)
|
|
271
|
-
})
|
|
272
|
-
|
|
273
|
-
it('should only update pointerVelocity if it actually changes', () => {
|
|
274
|
-
// Setup scenario where velocity won't change
|
|
275
|
-
editor.inputs.currentScreenPoint = new Vec(100, 100)
|
|
276
|
-
;(tickManager as any).prevPoint = new Vec(100, 100)
|
|
277
|
-
editor.inputs.pointerVelocity = new Vec(0, 0)
|
|
278
|
-
|
|
279
|
-
const originalVelocity = editor.inputs.pointerVelocity
|
|
280
|
-
updatePointerVelocity(16)
|
|
281
|
-
|
|
282
|
-
// Should still be the same object reference since no change occurred
|
|
283
|
-
expect(editor.inputs.pointerVelocity).toBe(originalVelocity)
|
|
284
|
-
})
|
|
285
|
-
})
|
|
286
|
-
|
|
287
220
|
describe('RAF throttling behavior', () => {
|
|
288
221
|
it('should use test-specific RAF behavior in test environment', () => {
|
|
289
222
|
// The TickManager should detect test environment and use requestAnimationFrame directly
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { throttleToNextFrame as _throttleToNextFrame, bind } from '@tldraw/utils'
|
|
2
|
-
import { Vec } from '../../../primitives/Vec'
|
|
3
2
|
import { Editor } from '../../Editor'
|
|
4
3
|
|
|
5
4
|
const throttleToNextFrame =
|
|
@@ -13,6 +12,7 @@ const throttleToNextFrame =
|
|
|
13
12
|
}
|
|
14
13
|
: _throttleToNextFrame
|
|
15
14
|
|
|
15
|
+
/** @internal */
|
|
16
16
|
export class TickManager {
|
|
17
17
|
constructor(public editor: Editor) {
|
|
18
18
|
this.editor.disposables.add(this.dispose)
|
|
@@ -40,7 +40,7 @@ export class TickManager {
|
|
|
40
40
|
const elapsed = now - this.now
|
|
41
41
|
this.now = now
|
|
42
42
|
|
|
43
|
-
this.updatePointerVelocity(elapsed)
|
|
43
|
+
this.editor.inputs.updatePointerVelocity(elapsed)
|
|
44
44
|
this.editor.emit('frame', elapsed)
|
|
45
45
|
this.editor.emit('tick', elapsed)
|
|
46
46
|
this.cancelRaf = throttleToNextFrame(this.tick)
|
|
@@ -53,34 +53,4 @@ export class TickManager {
|
|
|
53
53
|
|
|
54
54
|
this.cancelRaf?.()
|
|
55
55
|
}
|
|
56
|
-
|
|
57
|
-
private prevPoint = new Vec()
|
|
58
|
-
|
|
59
|
-
updatePointerVelocity(elapsed: number) {
|
|
60
|
-
const {
|
|
61
|
-
prevPoint,
|
|
62
|
-
editor: {
|
|
63
|
-
inputs: { currentScreenPoint, pointerVelocity },
|
|
64
|
-
},
|
|
65
|
-
} = this
|
|
66
|
-
|
|
67
|
-
if (elapsed === 0) return
|
|
68
|
-
|
|
69
|
-
const delta = Vec.Sub(currentScreenPoint, prevPoint)
|
|
70
|
-
this.prevPoint = currentScreenPoint.clone()
|
|
71
|
-
|
|
72
|
-
const length = delta.len()
|
|
73
|
-
const direction = length ? delta.div(length) : new Vec(0, 0)
|
|
74
|
-
|
|
75
|
-
// consider adjusting this with an easing rather than a linear interpolation
|
|
76
|
-
const next = pointerVelocity.clone().lrp(direction.mul(length / elapsed), 0.5)
|
|
77
|
-
|
|
78
|
-
// if the velocity is very small, just set it to 0
|
|
79
|
-
if (Math.abs(next.x) < 0.01) next.x = 0
|
|
80
|
-
if (Math.abs(next.y) < 0.01) next.y = 0
|
|
81
|
-
|
|
82
|
-
if (!pointerVelocity.equals(next)) {
|
|
83
|
-
this.editor.inputs.pointerVelocity = next
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
56
|
}
|
|
@@ -190,7 +190,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
190
190
|
* @param shape - The shape.
|
|
191
191
|
* @public
|
|
192
192
|
*/
|
|
193
|
-
canSnap(
|
|
193
|
+
canSnap(shape: Shape): boolean {
|
|
194
194
|
return true
|
|
195
195
|
}
|
|
196
196
|
|
|
@@ -200,7 +200,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
200
200
|
* @param shape - The shape.
|
|
201
201
|
* @public
|
|
202
202
|
*/
|
|
203
|
-
canTabTo(
|
|
203
|
+
canTabTo(shape: Shape): boolean {
|
|
204
204
|
return true
|
|
205
205
|
}
|
|
206
206
|
|
|
@@ -209,7 +209,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
209
209
|
*
|
|
210
210
|
* @public
|
|
211
211
|
*/
|
|
212
|
-
canScroll(
|
|
212
|
+
canScroll(shape: Shape): boolean {
|
|
213
213
|
return false
|
|
214
214
|
}
|
|
215
215
|
|
|
@@ -227,7 +227,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
227
227
|
*
|
|
228
228
|
* @public
|
|
229
229
|
*/
|
|
230
|
-
canEdit(
|
|
230
|
+
canEdit(shape: Shape, info: TLEditStartInfo): boolean {
|
|
231
231
|
return false
|
|
232
232
|
}
|
|
233
233
|
|
|
@@ -236,7 +236,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
236
236
|
*
|
|
237
237
|
* @public
|
|
238
238
|
*/
|
|
239
|
-
canResize(
|
|
239
|
+
canResize(shape: Shape): boolean {
|
|
240
240
|
return true
|
|
241
241
|
}
|
|
242
242
|
|
|
@@ -245,7 +245,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
245
245
|
*
|
|
246
246
|
* @public
|
|
247
247
|
*/
|
|
248
|
-
canResizeChildren(
|
|
248
|
+
canResizeChildren(shape: Shape): boolean {
|
|
249
249
|
return true
|
|
250
250
|
}
|
|
251
251
|
|
|
@@ -254,7 +254,16 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
254
254
|
*
|
|
255
255
|
* @public
|
|
256
256
|
*/
|
|
257
|
-
canEditInReadonly(
|
|
257
|
+
canEditInReadonly(shape: Shape): boolean {
|
|
258
|
+
return false
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Whether the shape can be edited while locked or while an ancestor is locked.
|
|
263
|
+
*
|
|
264
|
+
* @public
|
|
265
|
+
*/
|
|
266
|
+
canEditWhileLocked(shape: Shape): boolean {
|
|
258
267
|
return false
|
|
259
268
|
}
|
|
260
269
|
|
|
@@ -263,7 +272,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
263
272
|
*
|
|
264
273
|
* @public
|
|
265
274
|
*/
|
|
266
|
-
canCrop(
|
|
275
|
+
canCrop(shape: Shape): boolean {
|
|
267
276
|
return false
|
|
268
277
|
}
|
|
269
278
|
|
|
@@ -276,7 +285,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
276
285
|
*
|
|
277
286
|
* @public
|
|
278
287
|
*/
|
|
279
|
-
canBeLaidOut(
|
|
288
|
+
canBeLaidOut(shape: Shape, info: TLShapeUtilCanBeLaidOutOpts): boolean {
|
|
280
289
|
return true
|
|
281
290
|
}
|
|
282
291
|
|
|
@@ -287,7 +296,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
287
296
|
*
|
|
288
297
|
* @param shape - The shape.
|
|
289
298
|
*/
|
|
290
|
-
canCull(
|
|
299
|
+
canCull(shape: Shape): boolean {
|
|
291
300
|
return true
|
|
292
301
|
}
|
|
293
302
|
|
|
@@ -300,13 +309,33 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
300
309
|
*
|
|
301
310
|
* @internal
|
|
302
311
|
*/
|
|
303
|
-
providesBackgroundForChildren(
|
|
312
|
+
providesBackgroundForChildren(shape: Shape): boolean {
|
|
304
313
|
return false
|
|
305
314
|
}
|
|
306
315
|
|
|
307
316
|
/**
|
|
308
317
|
* Get the clip path to apply to this shape's children.
|
|
309
318
|
*
|
|
319
|
+
* The returned points should define the **inner** clip boundary - the area where
|
|
320
|
+
* children will be visible. If your shape has a stroke, you should inset the clip
|
|
321
|
+
* path by half the stroke width so children are clipped to the inner edge of the
|
|
322
|
+
* stroke rather than its center line.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* override getClipPath(shape: MyShape): Vec[] | undefined {
|
|
327
|
+
* const strokeWidth = 2
|
|
328
|
+
* const inset = strokeWidth / 2
|
|
329
|
+
* // Return points inset by half the stroke width
|
|
330
|
+
* return [
|
|
331
|
+
* new Vec(inset, inset),
|
|
332
|
+
* new Vec(shape.props.w - inset, inset),
|
|
333
|
+
* new Vec(shape.props.w - inset, shape.props.h - inset),
|
|
334
|
+
* new Vec(inset, shape.props.h - inset),
|
|
335
|
+
* ]
|
|
336
|
+
* }
|
|
337
|
+
* ```
|
|
338
|
+
*
|
|
310
339
|
* @param shape - The shape to get the clip path for
|
|
311
340
|
* @returns Array of points defining the clipping polygon in local coordinates, or undefined if no clipping
|
|
312
341
|
* @public
|
|
@@ -333,14 +362,14 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
333
362
|
* @returns boolean indicating if this shape should hide in the minimap
|
|
334
363
|
* @public
|
|
335
364
|
*/
|
|
336
|
-
hideInMinimap?(
|
|
365
|
+
hideInMinimap?(shape: Shape): boolean
|
|
337
366
|
|
|
338
367
|
/**
|
|
339
368
|
* Whether the shape should hide its resize handles when selected.
|
|
340
369
|
*
|
|
341
370
|
* @public
|
|
342
371
|
*/
|
|
343
|
-
hideResizeHandles(
|
|
372
|
+
hideResizeHandles(shape: Shape): boolean {
|
|
344
373
|
return false
|
|
345
374
|
}
|
|
346
375
|
|
|
@@ -349,7 +378,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
349
378
|
*
|
|
350
379
|
* @public
|
|
351
380
|
*/
|
|
352
|
-
hideRotateHandle(
|
|
381
|
+
hideRotateHandle(shape: Shape): boolean {
|
|
353
382
|
return false
|
|
354
383
|
}
|
|
355
384
|
|
|
@@ -358,7 +387,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
358
387
|
*
|
|
359
388
|
* @public
|
|
360
389
|
*/
|
|
361
|
-
hideSelectionBoundsBg(
|
|
390
|
+
hideSelectionBoundsBg(shape: Shape): boolean {
|
|
362
391
|
return false
|
|
363
392
|
}
|
|
364
393
|
|
|
@@ -367,7 +396,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
367
396
|
*
|
|
368
397
|
* @public
|
|
369
398
|
*/
|
|
370
|
-
hideSelectionBoundsFg(
|
|
399
|
+
hideSelectionBoundsFg(shape: Shape): boolean {
|
|
371
400
|
return false
|
|
372
401
|
}
|
|
373
402
|
|
|
@@ -376,7 +405,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
376
405
|
*
|
|
377
406
|
* @public
|
|
378
407
|
*/
|
|
379
|
-
isAspectRatioLocked(
|
|
408
|
+
isAspectRatioLocked(shape: Shape): boolean {
|
|
380
409
|
return false
|
|
381
410
|
}
|
|
382
411
|
|
|
@@ -387,10 +416,10 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
387
416
|
* useful in cases like annotating on top of an image, where you usually want to avoid extra
|
|
388
417
|
* padding around the image if you don't need it.
|
|
389
418
|
*
|
|
390
|
-
* @param
|
|
419
|
+
* @param shape - The shape to check
|
|
391
420
|
* @returns True if this shape should be treated as an export bounds container
|
|
392
421
|
*/
|
|
393
|
-
isExportBoundsContainer(
|
|
422
|
+
isExportBoundsContainer(shape: Shape): boolean {
|
|
394
423
|
return false
|
|
395
424
|
}
|
|
396
425
|
|
|
@@ -439,7 +468,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
439
468
|
* @param type - The shape type.
|
|
440
469
|
* @public
|
|
441
470
|
*/
|
|
442
|
-
canReceiveNewChildrenOfType(
|
|
471
|
+
canReceiveNewChildrenOfType(shape: Shape, _type: TLShape['type']) {
|
|
443
472
|
return false
|
|
444
473
|
}
|
|
445
474
|
|
|
@@ -487,7 +516,7 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
487
516
|
* Get the geometry to use when snapping to this this shape in translate/resize operations. See
|
|
488
517
|
* {@link BoundsSnapGeometry} for details.
|
|
489
518
|
*/
|
|
490
|
-
getBoundsSnapGeometry(
|
|
519
|
+
getBoundsSnapGeometry(shape: Shape): BoundsSnapGeometry {
|
|
491
520
|
return {}
|
|
492
521
|
}
|
|
493
522
|
|
|
@@ -495,15 +524,15 @@ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
|
|
|
495
524
|
* Get the geometry to use when snapping handles to this shape. See {@link HandleSnapGeometry}
|
|
496
525
|
* for details.
|
|
497
526
|
*/
|
|
498
|
-
getHandleSnapGeometry(
|
|
527
|
+
getHandleSnapGeometry(shape: Shape): HandleSnapGeometry {
|
|
499
528
|
return {}
|
|
500
529
|
}
|
|
501
530
|
|
|
502
|
-
getText(
|
|
531
|
+
getText(shape: Shape): string | undefined {
|
|
503
532
|
return undefined
|
|
504
533
|
}
|
|
505
534
|
|
|
506
|
-
getAriaDescriptor(
|
|
535
|
+
getAriaDescriptor(shape: Shape): string | undefined {
|
|
507
536
|
return undefined
|
|
508
537
|
}
|
|
509
538
|
|
|
@@ -931,3 +960,17 @@ export interface TLHandleDragInfo<T extends TLShape> {
|
|
|
931
960
|
isCreatingShape: boolean
|
|
932
961
|
initial?: T | undefined
|
|
933
962
|
}
|
|
963
|
+
|
|
964
|
+
/* --------------------------------- Editing -------------------------------- */
|
|
965
|
+
|
|
966
|
+
/** @public */
|
|
967
|
+
export interface TLEditStartInfo {
|
|
968
|
+
type:
|
|
969
|
+
| 'press_enter'
|
|
970
|
+
| 'click'
|
|
971
|
+
| 'double-click'
|
|
972
|
+
| 'double-click-edge'
|
|
973
|
+
| 'double-click-corner'
|
|
974
|
+
| 'click-header'
|
|
975
|
+
| 'unknown'
|
|
976
|
+
}
|
|
@@ -6,7 +6,7 @@ import { getPerfectDashProps } from '../shared/getPerfectDashProps'
|
|
|
6
6
|
export function DashedOutlineBox({ bounds, className }: { bounds: Box; className: string }) {
|
|
7
7
|
const editor = useEditor()
|
|
8
8
|
|
|
9
|
-
const zoomLevel = useValue('zoom level', () => editor.
|
|
9
|
+
const zoomLevel = useValue('zoom level', () => editor.getEfficientZoomLevel(), [editor])
|
|
10
10
|
|
|
11
11
|
return (
|
|
12
12
|
<g className={className} pointerEvents="none" strokeLinecap="round" strokeLinejoin="round">
|
|
@@ -12,8 +12,8 @@ export class Pointing extends StateNode {
|
|
|
12
12
|
|
|
13
13
|
override onPointerMove(info: TLPointerEventInfo) {
|
|
14
14
|
const { editor } = this
|
|
15
|
-
if (editor.inputs.
|
|
16
|
-
const
|
|
15
|
+
if (editor.inputs.getIsDragging()) {
|
|
16
|
+
const originPagePoint = editor.inputs.getOriginPagePoint()
|
|
17
17
|
|
|
18
18
|
const shapeType = (this.parent as BaseBoxShapeTool)!.shapeType
|
|
19
19
|
|
|
@@ -78,7 +78,7 @@ export class Pointing extends StateNode {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
complete() {
|
|
81
|
-
const
|
|
81
|
+
const originPagePoint = this.editor.inputs.getOriginPagePoint()
|
|
82
82
|
|
|
83
83
|
const shapeType = (this.parent as BaseBoxShapeTool)!.shapeType as TLBaseBoxShape['type']
|
|
84
84
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { atom } from '@tldraw/state'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* An object that contains information about the current device and environment.
|
|
5
|
+
* This object is not reactive and will not update automatically when the environment changes,
|
|
6
|
+
* so only include values that are fixed, such as the user's browser and operating system.
|
|
3
7
|
*
|
|
4
8
|
* @public
|
|
5
9
|
*/
|
|
@@ -14,15 +18,66 @@ const tlenv = {
|
|
|
14
18
|
hasCanvasSupport: false,
|
|
15
19
|
}
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
let isForcedFinePointer = false
|
|
22
|
+
|
|
23
|
+
if (typeof window !== 'undefined') {
|
|
24
|
+
if ('navigator' in window) {
|
|
25
|
+
tlenv.isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
|
|
26
|
+
tlenv.isIos = !!navigator.userAgent.match(/iPad/i) || !!navigator.userAgent.match(/iPhone/i)
|
|
27
|
+
tlenv.isChromeForIos = /crios.*safari/i.test(navigator.userAgent)
|
|
28
|
+
tlenv.isFirefox = /firefox/i.test(navigator.userAgent)
|
|
29
|
+
tlenv.isAndroid = /android/i.test(navigator.userAgent)
|
|
30
|
+
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf('mac') > -1
|
|
31
|
+
}
|
|
32
|
+
tlenv.hasCanvasSupport = 'Promise' in window && 'HTMLCanvasElement' in window
|
|
33
|
+
isForcedFinePointer = tlenv.isFirefox && !tlenv.isAndroid && !tlenv.isIos
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* An atom that contains information about the current device and environment.
|
|
38
|
+
* This object is reactive and will update automatically when the environment changes.
|
|
39
|
+
* Use it for values that may change over time, such as the pointer type.
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
const tlenvReactive = atom('tlenvReactive', {
|
|
44
|
+
// Whether the user's device has a coarse pointer. This is dynamic on many systems, especially
|
|
45
|
+
// on touch-screen laptops, which will become "coarse" if the user touches the screen.
|
|
46
|
+
// See https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@media/pointer#coarse
|
|
47
|
+
isCoarsePointer: false,
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
if (typeof window !== 'undefined' && !isForcedFinePointer) {
|
|
51
|
+
const mql = window.matchMedia && window.matchMedia('(any-pointer: coarse)')
|
|
52
|
+
|
|
53
|
+
const isCurrentCoarsePointer = () => tlenvReactive.__unsafe__getWithoutCapture().isCoarsePointer
|
|
54
|
+
|
|
55
|
+
if (mql) {
|
|
56
|
+
// 1. Update the coarse pointer automatically when the media query changes
|
|
57
|
+
const updateIsCoarsePointer = () => {
|
|
58
|
+
const isCoarsePointer = mql.matches
|
|
59
|
+
if (isCoarsePointer !== isCurrentCoarsePointer()) {
|
|
60
|
+
tlenvReactive.update((prev) => ({ ...prev, isCoarsePointer: isCoarsePointer }))
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
updateIsCoarsePointer()
|
|
64
|
+
mql.addEventListener('change', updateIsCoarsePointer)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 2. Also update the coarse pointer state when a pointer down event occurs. We need `capture: true`
|
|
68
|
+
// here because the tldraw component itself stops propagation on pointer events it receives.
|
|
69
|
+
window.addEventListener(
|
|
70
|
+
'pointerdown',
|
|
71
|
+
(e: PointerEvent) => {
|
|
72
|
+
// when the user interacts with a mouse, we assume they have a fine pointer.
|
|
73
|
+
// otherwise, we assume they have a coarse pointer.
|
|
74
|
+
const isCoarseEvent = e.pointerType !== 'mouse'
|
|
75
|
+
if (isCoarseEvent !== isCurrentCoarsePointer()) {
|
|
76
|
+
tlenvReactive.update((prev) => ({ ...prev, isCoarsePointer: isCoarseEvent }))
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{ capture: true }
|
|
80
|
+
)
|
|
26
81
|
}
|
|
27
82
|
|
|
28
|
-
export { tlenv }
|
|
83
|
+
export { tlenv, tlenvReactive }
|