@tldraw/driver 4.5.0-canary.0666ccb8f1fd

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.
@@ -0,0 +1,590 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var Driver_exports = {};
20
+ __export(Driver_exports, {
21
+ Driver: () => Driver
22
+ });
23
+ module.exports = __toCommonJS(Driver_exports);
24
+ var import_editor = require("@tldraw/editor");
25
+ class Driver {
26
+ constructor(editor) {
27
+ this.editor = editor;
28
+ this._cleanup = this.editor.sideEffects.registerAfterCreateHandler("shape", (record) => {
29
+ this._lastCreatedShapes.push(record);
30
+ if (this._lastCreatedShapes.length > 1e3) {
31
+ this._lastCreatedShapes = this._lastCreatedShapes.slice(-500);
32
+ }
33
+ });
34
+ }
35
+ /** The underlying Editor instance. */
36
+ _cleanup = null;
37
+ /** Remove all registered side-effect handlers. Call when this controller is no longer needed. */
38
+ dispose() {
39
+ this._cleanup?.();
40
+ this._cleanup = null;
41
+ }
42
+ /** Local clipboard content. Used by copy, cut, and paste. */
43
+ clipboard = null;
44
+ _lastCreatedShapes = [];
45
+ /**
46
+ * Get the last created shapes.
47
+ * @param count - The number of shapes to get.
48
+ */
49
+ getLastCreatedShapes(count = 1) {
50
+ return this._lastCreatedShapes.slice(-count).map((s) => this.editor.getShape(s));
51
+ }
52
+ /**
53
+ * Get the last created shape.
54
+ */
55
+ getLastCreatedShape() {
56
+ const lastShape = this._lastCreatedShapes[this._lastCreatedShapes.length - 1];
57
+ return this.editor.getShape(lastShape);
58
+ }
59
+ /* ---------------------- IDs ---------------------- */
60
+ /**
61
+ * Creates a shape ID from a string.
62
+ * @param id - The string to convert to a shape ID.
63
+ */
64
+ createShapeID(id) {
65
+ return (0, import_editor.createShapeId)(id);
66
+ }
67
+ /**
68
+ * Creates a page ID from a string.
69
+ * @param id - The string to convert to a page ID.
70
+ */
71
+ createPageID(id) {
72
+ return import_editor.PageRecordType.createId(id);
73
+ }
74
+ /* ------------------- Clipboard ------------------- */
75
+ /**
76
+ * Copies the given shapes to the controller clipboard. Defaults to the current selection.
77
+ * @param ids - Shape IDs to copy. Defaults to the current selection.
78
+ */
79
+ copy(ids = this.editor.getSelectedShapeIds()) {
80
+ if (ids.length > 0) {
81
+ const content = this.editor.getContentFromCurrentPage(ids);
82
+ if (content) {
83
+ this.clipboard = content;
84
+ }
85
+ }
86
+ return this;
87
+ }
88
+ /**
89
+ * Cuts the given shapes (copy to clipboard, then delete). Defaults to the current selection.
90
+ * @param ids - Shape IDs to cut. Defaults to the current selection.
91
+ */
92
+ cut(ids = this.editor.getSelectedShapeIds()) {
93
+ if (ids.length > 0) {
94
+ const content = this.editor.getContentFromCurrentPage(ids);
95
+ if (content) {
96
+ this.clipboard = content;
97
+ }
98
+ this.editor.deleteShapes(ids);
99
+ }
100
+ return this;
101
+ }
102
+ /**
103
+ * Pastes content from the controller clipboard. If shift is held, uses current pointer. Otherwise uses the given point.
104
+ * @param point - Page coordinates for paste location. If omitted and shift is not held, placement may vary.
105
+ */
106
+ paste(point) {
107
+ if (this.clipboard !== null) {
108
+ const p = this.editor.inputs.getShiftKey() ? this.editor.inputs.getCurrentPagePoint() : point;
109
+ this.editor.markHistoryStoppingPoint("pasting");
110
+ this.editor.putContentOntoCurrentPage(this.clipboard, {
111
+ point: p,
112
+ select: true
113
+ });
114
+ }
115
+ return this;
116
+ }
117
+ /* ------------------- Queries ------------------- */
118
+ /** Returns the center of the viewport in page coordinates. */
119
+ getViewportPageCenter() {
120
+ return this.editor.getViewportPageBounds().center;
121
+ }
122
+ /** Returns the center of the current selection in page coordinates, or null if nothing is selected. */
123
+ getSelectionPageCenter() {
124
+ const selectionRotation = this.editor.getSelectionRotation();
125
+ const selectionBounds = this.editor.getSelectionRotatedPageBounds();
126
+ if (!selectionBounds) return null;
127
+ return import_editor.Vec.RotWith(selectionBounds.center, selectionBounds.point, selectionRotation);
128
+ }
129
+ /**
130
+ * Returns the center of a shape in page coordinates, or null if the shape has no page transform.
131
+ * @param shape - The shape to get the center of.
132
+ */
133
+ getPageCenter(shape) {
134
+ const pageTransform = this.editor.getShapePageTransform(shape.id);
135
+ if (!pageTransform) return null;
136
+ const center = this.editor.getShapeGeometry(shape).bounds.center;
137
+ return import_editor.Mat.applyToPoint(pageTransform, center);
138
+ }
139
+ /**
140
+ * Returns the rotation of a shape in page space by ID, in radians.
141
+ * @param id - The shape ID.
142
+ */
143
+ getPageRotationById(id) {
144
+ const pageTransform = this.editor.getShapePageTransform(id);
145
+ if (pageTransform) {
146
+ return import_editor.Mat.Decompose(pageTransform).rotation;
147
+ }
148
+ return 0;
149
+ }
150
+ /**
151
+ * Returns the rotation of a shape in page space, in radians.
152
+ * @param shape - The shape to get the rotation of.
153
+ */
154
+ getPageRotation(shape) {
155
+ return this.getPageRotationById(shape.id);
156
+ }
157
+ /**
158
+ * Returns all arrow shapes bound to the given shape.
159
+ * @param shapeId - The shape ID to find arrows bound to.
160
+ */
161
+ getArrowsBoundTo(shapeId) {
162
+ const ids = new Set(this.editor.getBindingsToShape(shapeId, "arrow").map((b) => b.fromId));
163
+ return (0, import_editor.compact)(Array.from(ids, (id) => this.editor.getShape(id)));
164
+ }
165
+ /* --------------- Event building --------------- */
166
+ /**
167
+ * Builds a TLPointerEventInfo object for input simulation.
168
+ * @param x - Screen x coordinate. Defaults to current pointer.
169
+ * @param y - Screen y coordinate. Defaults to current pointer.
170
+ * @param options - Target shape/selection or partial event info.
171
+ * @param modifiers - Override shift, ctrl, or alt key state.
172
+ */
173
+ getPointerEventInfo(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, options, modifiers) {
174
+ if (typeof options === "string") {
175
+ options = { target: "shape", shape: this.editor.getShape(options) };
176
+ } else if (options === void 0) {
177
+ options = { target: "canvas" };
178
+ }
179
+ return {
180
+ name: "pointer_down",
181
+ type: "pointer",
182
+ pointerId: 1,
183
+ shiftKey: this.editor.inputs.getShiftKey(),
184
+ ctrlKey: this.editor.inputs.getCtrlKey(),
185
+ altKey: this.editor.inputs.getAltKey(),
186
+ metaKey: this.editor.inputs.getMetaKey(),
187
+ accelKey: (0, import_editor.isAccelKey)({ ...this.editor.inputs.toJson(), ...modifiers }),
188
+ point: { x, y, z: null },
189
+ button: 0,
190
+ isPen: false,
191
+ ...options,
192
+ ...modifiers
193
+ };
194
+ }
195
+ /**
196
+ * Builds a TLKeyboardEventInfo object for input simulation.
197
+ * @param key - The key being pressed.
198
+ * @param name - The event name (key_down, key_up, key_repeat).
199
+ * @param options - Partial event info overrides.
200
+ */
201
+ getKeyboardEventInfo(key, name, options = {}) {
202
+ return {
203
+ shiftKey: key === "Shift",
204
+ ctrlKey: key === "Control" || key === "Meta",
205
+ altKey: key === "Alt",
206
+ metaKey: key === "Meta",
207
+ accelKey: import_editor.tlenv.isDarwin ? key === "Meta" : key === "Control" || key === "Meta",
208
+ ...options,
209
+ name,
210
+ code: key === "Shift" ? "ShiftLeft" : key === "Alt" ? "AltLeft" : key === "Control" ? "CtrlLeft" : key === "Meta" ? "MetaLeft" : key === " " ? "Space" : key === "Enter" || key === "ArrowRight" || key === "ArrowLeft" || key === "ArrowUp" || key === "ArrowDown" ? key : "Key" + key[0].toUpperCase() + key.slice(1),
211
+ type: "keyboard",
212
+ key
213
+ };
214
+ }
215
+ /* --------------- Input events --------------- */
216
+ /**
217
+ * Emits tick events to advance the editor by the given number of frames (default 1).
218
+ * @param count - Number of tick events to emit. Defaults to 1.
219
+ */
220
+ forceTick(count = 1) {
221
+ for (let i = 0; i < count; i++) {
222
+ this.editor.emit("tick", 16);
223
+ }
224
+ return this;
225
+ }
226
+ /**
227
+ * Dispatches a pointer move event at the given screen coordinates.
228
+ * @param x - Screen x coordinate. Defaults to current pointer.
229
+ * @param y - Screen y coordinate. Defaults to current pointer.
230
+ * @param options - Target shape/selection or partial event info.
231
+ * @param modifiers - Override shift, ctrl, or alt key state.
232
+ */
233
+ pointerMove(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, options, modifiers) {
234
+ this.editor.dispatch({
235
+ ...this.getPointerEventInfo(x, y, options, modifiers),
236
+ name: "pointer_move"
237
+ });
238
+ this.forceTick();
239
+ return this;
240
+ }
241
+ /**
242
+ * Dispatches a pointer down event at the given screen coordinates.
243
+ * @param x - Screen x coordinate. Defaults to current pointer.
244
+ * @param y - Screen y coordinate. Defaults to current pointer.
245
+ * @param options - Target shape/selection or partial event info.
246
+ * @param modifiers - Override shift, ctrl, or alt key state.
247
+ */
248
+ pointerDown(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, options, modifiers) {
249
+ this.editor.dispatch({
250
+ ...this.getPointerEventInfo(x, y, options, modifiers),
251
+ name: "pointer_down"
252
+ });
253
+ this.forceTick();
254
+ return this;
255
+ }
256
+ /**
257
+ * Dispatches a pointer up event at the given screen coordinates.
258
+ * @param x - Screen x coordinate. Defaults to current pointer.
259
+ * @param y - Screen y coordinate. Defaults to current pointer.
260
+ * @param options - Target shape/selection or partial event info.
261
+ * @param modifiers - Override shift, ctrl, or alt key state.
262
+ */
263
+ pointerUp(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, options, modifiers) {
264
+ this.editor.dispatch({
265
+ ...this.getPointerEventInfo(x, y, options, modifiers),
266
+ name: "pointer_up"
267
+ });
268
+ this.forceTick();
269
+ return this;
270
+ }
271
+ /**
272
+ * Dispatches a pointer down followed by pointer up at the given screen coordinates.
273
+ * @param x - Screen x coordinate. Defaults to current pointer.
274
+ * @param y - Screen y coordinate. Defaults to current pointer.
275
+ * @param options - Target shape/selection or partial event info.
276
+ * @param modifiers - Override shift, ctrl, or alt key state.
277
+ */
278
+ click(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, options, modifiers) {
279
+ this.pointerDown(x, y, options, modifiers);
280
+ this.pointerUp(x, y, options, modifiers);
281
+ return this;
282
+ }
283
+ /**
284
+ * Dispatches a right-click (button 2) down and up at the given screen coordinates.
285
+ * @param x - Screen x coordinate. Defaults to current pointer.
286
+ * @param y - Screen y coordinate. Defaults to current pointer.
287
+ * @param options - Target shape/selection or partial event info.
288
+ * @param modifiers - Override shift, ctrl, or alt key state.
289
+ */
290
+ rightClick(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, options, modifiers) {
291
+ this.editor.dispatch({
292
+ ...this.getPointerEventInfo(x, y, options, modifiers),
293
+ name: "pointer_down",
294
+ button: 2
295
+ });
296
+ this.forceTick();
297
+ this.editor.dispatch({
298
+ ...this.getPointerEventInfo(x, y, options, modifiers),
299
+ name: "pointer_up",
300
+ button: 2
301
+ });
302
+ this.forceTick();
303
+ return this;
304
+ }
305
+ /**
306
+ * Dispatches a double-click sequence at the given screen coordinates.
307
+ * @param x - Screen x coordinate. Defaults to current pointer.
308
+ * @param y - Screen y coordinate. Defaults to current pointer.
309
+ * @param options - Target shape/selection or partial event info.
310
+ * @param modifiers - Override shift, ctrl, or alt key state.
311
+ */
312
+ doubleClick(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, options, modifiers) {
313
+ this.pointerDown(x, y, options, modifiers);
314
+ this.pointerUp(x, y, options, modifiers);
315
+ this.editor.dispatch({
316
+ ...this.getPointerEventInfo(x, y, options, modifiers),
317
+ type: "click",
318
+ name: "double_click",
319
+ phase: "down"
320
+ });
321
+ this.editor.dispatch({
322
+ ...this.getPointerEventInfo(x, y, options, modifiers),
323
+ type: "click",
324
+ name: "double_click",
325
+ phase: "up"
326
+ });
327
+ this.forceTick();
328
+ return this;
329
+ }
330
+ /**
331
+ * Dispatches a key down followed by key up for the given key.
332
+ * @param key - The key to press (e.g. 'a', 'Enter', 'Shift').
333
+ * @param options - Partial keyboard event overrides.
334
+ */
335
+ keyPress(key, options = {}) {
336
+ this.keyDown(key, options);
337
+ this.keyUp(key, options);
338
+ return this;
339
+ }
340
+ /**
341
+ * Dispatches a key down event for the given key.
342
+ * @param key - The key to press (e.g. 'a', 'Enter', 'Shift').
343
+ * @param options - Partial keyboard event overrides.
344
+ */
345
+ keyDown(key, options = {}) {
346
+ this.editor.dispatch({ ...this.getKeyboardEventInfo(key, "key_down", options) });
347
+ this.forceTick();
348
+ return this;
349
+ }
350
+ /**
351
+ * Dispatches a key repeat event for the given key.
352
+ * @param key - The key that is repeating (e.g. 'a', 'ArrowDown').
353
+ * @param options - Partial keyboard event overrides.
354
+ */
355
+ keyRepeat(key, options = {}) {
356
+ this.editor.dispatch({ ...this.getKeyboardEventInfo(key, "key_repeat", options) });
357
+ this.forceTick();
358
+ return this;
359
+ }
360
+ /**
361
+ * Dispatches a key up event for the given key.
362
+ * @param key - The key to release (e.g. 'a', 'Enter', 'Shift').
363
+ * @param options - Partial keyboard event overrides.
364
+ */
365
+ keyUp(key, options = {}) {
366
+ this.editor.dispatch({
367
+ ...this.getKeyboardEventInfo(key, "key_up", {
368
+ shiftKey: this.editor.inputs.getShiftKey() && key !== "Shift",
369
+ ctrlKey: this.editor.inputs.getCtrlKey() && !(key === "Control" || key === "Meta"),
370
+ altKey: this.editor.inputs.getAltKey() && key !== "Alt",
371
+ metaKey: this.editor.inputs.getMetaKey() && key !== "Meta",
372
+ ...options
373
+ })
374
+ });
375
+ this.forceTick();
376
+ return this;
377
+ }
378
+ /**
379
+ * Dispatches a wheel event with the given delta values.
380
+ * @param dx - Horizontal scroll delta.
381
+ * @param dy - Vertical scroll delta.
382
+ * @param options - Partial wheel event overrides.
383
+ */
384
+ wheel(dx, dy, options = {}) {
385
+ const currentScreenPoint = this.editor.inputs.getCurrentScreenPoint();
386
+ this.editor.dispatch({
387
+ type: "wheel",
388
+ name: "wheel",
389
+ point: new import_editor.Vec(currentScreenPoint.x, currentScreenPoint.y),
390
+ shiftKey: this.editor.inputs.getShiftKey(),
391
+ ctrlKey: this.editor.inputs.getCtrlKey(),
392
+ altKey: this.editor.inputs.getAltKey(),
393
+ metaKey: this.editor.inputs.getMetaKey(),
394
+ accelKey: (0, import_editor.isAccelKey)(this.editor.inputs),
395
+ ...options,
396
+ delta: { x: dx, y: dy }
397
+ });
398
+ this.forceTick(2);
399
+ return this;
400
+ }
401
+ /**
402
+ * Pans the camera by the given offset (in page coordinates). Does nothing if camera is locked.
403
+ * @param offset - The pan delta (x, y) in page coordinates.
404
+ */
405
+ pan(offset) {
406
+ const { isLocked, panSpeed } = this.editor.getCameraOptions();
407
+ if (isLocked) return this;
408
+ const { x: cx, y: cy, z: cz } = this.editor.getCamera();
409
+ this.editor.setCamera(
410
+ new import_editor.Vec(cx + offset.x * panSpeed / cz, cy + offset.y * panSpeed / cz, cz),
411
+ { immediate: true }
412
+ );
413
+ return this;
414
+ }
415
+ /**
416
+ * Dispatches a pinch start event.
417
+ * @param x - Screen x coordinate. Defaults to current pointer.
418
+ * @param y - Screen y coordinate. Defaults to current pointer.
419
+ * @param z - Pinch scale/factor.
420
+ * @param dx - Delta x for pinch.
421
+ * @param dy - Delta y for pinch.
422
+ * @param dz - Delta z for pinch.
423
+ * @param options - Partial pinch event overrides.
424
+ */
425
+ pinchStart(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, z, dx, dy, dz, options = {}) {
426
+ this.editor.dispatch({
427
+ type: "pinch",
428
+ name: "pinch_start",
429
+ shiftKey: this.editor.inputs.getShiftKey(),
430
+ ctrlKey: this.editor.inputs.getCtrlKey(),
431
+ altKey: this.editor.inputs.getAltKey(),
432
+ metaKey: this.editor.inputs.getMetaKey(),
433
+ accelKey: (0, import_editor.isAccelKey)(this.editor.inputs),
434
+ ...options,
435
+ point: { x, y, z },
436
+ delta: { x: dx, y: dy, z: dz }
437
+ });
438
+ this.forceTick();
439
+ return this;
440
+ }
441
+ /**
442
+ * Dispatches a pinch move event (pinch_to).
443
+ * @param x - Screen x coordinate. Defaults to current pointer.
444
+ * @param y - Screen y coordinate. Defaults to current pointer.
445
+ * @param z - Pinch scale/factor.
446
+ * @param dx - Delta x for pinch.
447
+ * @param dy - Delta y for pinch.
448
+ * @param dz - Delta z for pinch.
449
+ * @param options - Partial pinch event overrides.
450
+ */
451
+ pinchTo(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, z, dx, dy, dz, options = {}) {
452
+ this.editor.dispatch({
453
+ type: "pinch",
454
+ name: "pinch",
455
+ shiftKey: this.editor.inputs.getShiftKey(),
456
+ ctrlKey: this.editor.inputs.getCtrlKey(),
457
+ altKey: this.editor.inputs.getAltKey(),
458
+ metaKey: this.editor.inputs.getMetaKey(),
459
+ accelKey: (0, import_editor.isAccelKey)(this.editor.inputs),
460
+ ...options,
461
+ point: { x, y, z },
462
+ delta: { x: dx, y: dy, z: dz }
463
+ });
464
+ return this;
465
+ }
466
+ /**
467
+ * Dispatches a pinch end event.
468
+ * @param x - Screen x coordinate. Defaults to current pointer.
469
+ * @param y - Screen y coordinate. Defaults to current pointer.
470
+ * @param z - Pinch scale/factor.
471
+ * @param dx - Delta x for pinch.
472
+ * @param dy - Delta y for pinch.
473
+ * @param dz - Delta z for pinch.
474
+ * @param options - Partial pinch event overrides.
475
+ */
476
+ pinchEnd(x = this.editor.inputs.getCurrentScreenPoint().x, y = this.editor.inputs.getCurrentScreenPoint().y, z, dx, dy, dz, options = {}) {
477
+ this.editor.dispatch({
478
+ type: "pinch",
479
+ name: "pinch_end",
480
+ shiftKey: this.editor.inputs.getShiftKey(),
481
+ ctrlKey: this.editor.inputs.getCtrlKey(),
482
+ altKey: this.editor.inputs.getAltKey(),
483
+ metaKey: this.editor.inputs.getMetaKey(),
484
+ accelKey: (0, import_editor.isAccelKey)(this.editor.inputs),
485
+ ...options,
486
+ point: { x, y, z },
487
+ delta: { x: dx, y: dy, z: dz }
488
+ });
489
+ this.forceTick();
490
+ return this;
491
+ }
492
+ /* --------------- Interaction helpers --------------- */
493
+ /**
494
+ * Converts a point from page coordinates to screen coordinates.
495
+ * Pointer events operate in screen space, so page-space points must be
496
+ * converted before being passed to pointerDown/Move/Up.
497
+ */
498
+ pageToScreen(point) {
499
+ return this.editor.pageToScreen(point);
500
+ }
501
+ /**
502
+ * Simulates rotating the current selection by the given angle in radians via the rotation handle.
503
+ * @param angleRadians - Rotation angle in radians.
504
+ * @param options - Optional handle and shiftKey. handle defaults to 'top_left_rotate'.
505
+ */
506
+ rotateSelection(angleRadians, options = {}) {
507
+ const { handle = "top_left_rotate", shiftKey = false } = options;
508
+ if (this.editor.getSelectedShapeIds().length === 0) {
509
+ throw new Error("No selection");
510
+ }
511
+ this.editor.setCurrentTool("select");
512
+ const handlePoint = this.editor.getSelectionRotatedPageBounds().getHandlePoint(import_editor.ROTATE_CORNER_TO_SELECTION_CORNER[handle]).clone().rotWith(
513
+ this.editor.getSelectionRotatedPageBounds().point,
514
+ this.editor.getSelectionRotation()
515
+ );
516
+ const targetHandlePoint = import_editor.Vec.RotWith(handlePoint, this.getSelectionPageCenter(), angleRadians);
517
+ const screenHandle = this.pageToScreen(handlePoint);
518
+ const screenTarget = this.pageToScreen(targetHandlePoint);
519
+ this.pointerDown(screenHandle.x, screenHandle.y, { target: "selection", handle });
520
+ this.pointerMove(screenTarget.x, screenTarget.y, { shiftKey });
521
+ this.pointerUp();
522
+ return this;
523
+ }
524
+ /**
525
+ * Simulates translating the current selection by the given delta in page coordinates.
526
+ * @param dx - Horizontal delta in page coordinates.
527
+ * @param dy - Vertical delta in page coordinates.
528
+ * @param options - Partial pointer event overrides (e.g. altKey for center-based scaling).
529
+ */
530
+ translateSelection(dx, dy, options) {
531
+ if (this.editor.getSelectedShapeIds().length === 0) {
532
+ throw new Error("No selection");
533
+ }
534
+ this.editor.setCurrentTool("select");
535
+ const center = this.getSelectionPageCenter();
536
+ const screenCenter = this.pageToScreen(center);
537
+ this.pointerDown(screenCenter.x, screenCenter.y, this.editor.getSelectedShapeIds()[0]);
538
+ const numSteps = 10;
539
+ for (let i = 1; i < numSteps; i++) {
540
+ const p = this.pageToScreen({
541
+ x: center.x + i * dx / numSteps,
542
+ y: center.y + i * dy / numSteps
543
+ });
544
+ this.pointerMove(p.x, p.y, options);
545
+ }
546
+ const endScreen = this.pageToScreen({ x: center.x + dx, y: center.y + dy });
547
+ this.pointerUp(endScreen.x, endScreen.y, options);
548
+ return this;
549
+ }
550
+ /**
551
+ * Simulates resizing the current selection via the given handle, with optional scale factors.
552
+ * @param scale - Scale factors for x and y. Defaults to `\{ scaleX: 1, scaleY: 1 \}`.
553
+ * @param handle - The selection handle to drag (e.g. 'top', 'bottom_right').
554
+ * @param options - Partial pointer event overrides (e.g. altKey to scale from center).
555
+ */
556
+ resizeSelection(scale = {}, handle, options) {
557
+ const { scaleX = 1, scaleY = 1 } = scale;
558
+ if (this.editor.getSelectedShapeIds().length === 0) {
559
+ throw new Error("No selection");
560
+ }
561
+ this.editor.setCurrentTool("select");
562
+ const bounds = this.editor.getSelectionRotatedPageBounds();
563
+ const preRotationHandlePoint = bounds.getHandlePoint(handle);
564
+ const preRotationScaleOriginPoint = options?.altKey ? bounds.center : bounds.getHandlePoint((0, import_editor.rotateSelectionHandle)(handle, Math.PI));
565
+ const preRotationTargetHandlePoint = import_editor.Vec.Add(
566
+ import_editor.Vec.Sub(preRotationHandlePoint, preRotationScaleOriginPoint).mulV({
567
+ x: scaleX,
568
+ y: scaleY
569
+ }),
570
+ preRotationScaleOriginPoint
571
+ );
572
+ const handlePoint = import_editor.Vec.RotWith(
573
+ preRotationHandlePoint,
574
+ bounds.point,
575
+ this.editor.getSelectionRotation()
576
+ );
577
+ const targetHandlePoint = import_editor.Vec.RotWith(
578
+ preRotationTargetHandlePoint,
579
+ bounds.point,
580
+ this.editor.getSelectionRotation()
581
+ );
582
+ const screenHandle = this.pageToScreen(handlePoint);
583
+ const screenTarget = this.pageToScreen(targetHandlePoint);
584
+ this.pointerDown(screenHandle.x, screenHandle.y, { target: "selection", handle }, options);
585
+ this.pointerMove(screenTarget.x, screenTarget.y, options);
586
+ this.pointerUp(screenTarget.x, screenTarget.y, options);
587
+ return this;
588
+ }
589
+ }
590
+ //# sourceMappingURL=Driver.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/lib/Driver.ts"],
4
+ "sourcesContent": ["import {\n\tEditor,\n\tMat,\n\tPageRecordType,\n\tROTATE_CORNER_TO_SELECTION_CORNER,\n\tRotateCorner,\n\tSelectionHandle,\n\tTLArrowShape,\n\tTLContent,\n\tTLKeyboardEventInfo,\n\tTLPinchEventInfo,\n\tTLPointerEventInfo,\n\tTLShape,\n\tTLShapeId,\n\tTLWheelEventInfo,\n\tVec,\n\tVecLike,\n\tcompact,\n\tcreateShapeId,\n\tisAccelKey,\n\trotateSelectionHandle,\n\ttlenv,\n} from '@tldraw/editor'\n\n/** Options for pointer events. Either partial pointer event info or a shape ID to target. @public */\nexport type PointerEventInit = Partial<TLPointerEventInfo> | TLShapeId\n\n/** Modifier keys for events. @public */\nexport type EventModifiers = Partial<Pick<TLPointerEventInfo, 'shiftKey' | 'ctrlKey' | 'altKey'>>\n\n/**\n * Driver wraps an Editor instance and provides an imperative API for driving it\n * programmatically. Useful for scripting, automation, REPL usage, and testing.\n *\n * All methods use only public Editor APIs and return `this` for fluent chaining.\n *\n * @public\n */\nexport class Driver {\n\t/** The underlying Editor instance. */\n\tprivate _cleanup: (() => void) | null = null\n\n\tconstructor(public readonly editor: Editor) {\n\t\tthis._cleanup = this.editor.sideEffects.registerAfterCreateHandler('shape', (record) => {\n\t\t\tthis._lastCreatedShapes.push(record)\n\t\t\tif (this._lastCreatedShapes.length > 1000) {\n\t\t\t\tthis._lastCreatedShapes = this._lastCreatedShapes.slice(-500)\n\t\t\t}\n\t\t})\n\t}\n\n\t/** Remove all registered side-effect handlers. Call when this controller is no longer needed. */\n\tdispose() {\n\t\tthis._cleanup?.()\n\t\tthis._cleanup = null\n\t}\n\n\t/** Local clipboard content. Used by copy, cut, and paste. */\n\tclipboard: TLContent | null = null\n\n\tprivate _lastCreatedShapes: TLShape[] = []\n\n\t/**\n\t * Get the last created shapes.\n\t * @param count - The number of shapes to get.\n\t */\n\tgetLastCreatedShapes(count = 1) {\n\t\treturn this._lastCreatedShapes.slice(-count).map((s) => this.editor.getShape(s)!)\n\t}\n\n\t/**\n\t * Get the last created shape.\n\t */\n\tgetLastCreatedShape<T extends TLShape>() {\n\t\tconst lastShape = this._lastCreatedShapes[this._lastCreatedShapes.length - 1] as T\n\t\treturn this.editor.getShape<T>(lastShape)!\n\t}\n\n\t/* ---------------------- IDs ---------------------- */\n\n\t/**\n\t * Creates a shape ID from a string.\n\t * @param id - The string to convert to a shape ID.\n\t */\n\tcreateShapeID(id: string) {\n\t\treturn createShapeId(id)\n\t}\n\n\t/**\n\t * Creates a page ID from a string.\n\t * @param id - The string to convert to a page ID.\n\t */\n\tcreatePageID(id: string) {\n\t\treturn PageRecordType.createId(id)\n\t}\n\n\t/* ------------------- Clipboard ------------------- */\n\n\t/**\n\t * Copies the given shapes to the controller clipboard. Defaults to the current selection.\n\t * @param ids - Shape IDs to copy. Defaults to the current selection.\n\t */\n\tcopy(ids = this.editor.getSelectedShapeIds()) {\n\t\tif (ids.length > 0) {\n\t\t\tconst content = this.editor.getContentFromCurrentPage(ids)\n\t\t\tif (content) {\n\t\t\t\tthis.clipboard = content\n\t\t\t}\n\t\t}\n\t\treturn this\n\t}\n\n\t/**\n\t * Cuts the given shapes (copy to clipboard, then delete). Defaults to the current selection.\n\t * @param ids - Shape IDs to cut. Defaults to the current selection.\n\t */\n\tcut(ids = this.editor.getSelectedShapeIds()) {\n\t\tif (ids.length > 0) {\n\t\t\tconst content = this.editor.getContentFromCurrentPage(ids)\n\t\t\tif (content) {\n\t\t\t\tthis.clipboard = content\n\t\t\t}\n\t\t\tthis.editor.deleteShapes(ids)\n\t\t}\n\t\treturn this\n\t}\n\n\t/**\n\t * Pastes content from the controller clipboard. If shift is held, uses current pointer. Otherwise uses the given point.\n\t * @param point - Page coordinates for paste location. If omitted and shift is not held, placement may vary.\n\t */\n\tpaste(point?: VecLike) {\n\t\tif (this.clipboard !== null) {\n\t\t\tconst p = this.editor.inputs.getShiftKey() ? this.editor.inputs.getCurrentPagePoint() : point\n\n\t\t\tthis.editor.markHistoryStoppingPoint('pasting')\n\t\t\tthis.editor.putContentOntoCurrentPage(this.clipboard, {\n\t\t\t\tpoint: p,\n\t\t\t\tselect: true,\n\t\t\t})\n\t\t}\n\t\treturn this\n\t}\n\n\t/* ------------------- Queries ------------------- */\n\n\t/** Returns the center of the viewport in page coordinates. */\n\tgetViewportPageCenter() {\n\t\treturn this.editor.getViewportPageBounds().center\n\t}\n\n\t/** Returns the center of the current selection in page coordinates, or null if nothing is selected. */\n\tgetSelectionPageCenter() {\n\t\tconst selectionRotation = this.editor.getSelectionRotation()\n\t\tconst selectionBounds = this.editor.getSelectionRotatedPageBounds()\n\t\tif (!selectionBounds) return null\n\t\treturn Vec.RotWith(selectionBounds.center, selectionBounds.point, selectionRotation)\n\t}\n\n\t/**\n\t * Returns the center of a shape in page coordinates, or null if the shape has no page transform.\n\t * @param shape - The shape to get the center of.\n\t */\n\tgetPageCenter(shape: TLShape) {\n\t\tconst pageTransform = this.editor.getShapePageTransform(shape.id)\n\t\tif (!pageTransform) return null\n\t\tconst center = this.editor.getShapeGeometry(shape).bounds.center\n\t\treturn Mat.applyToPoint(pageTransform, center)\n\t}\n\n\t/**\n\t * Returns the rotation of a shape in page space by ID, in radians.\n\t * @param id - The shape ID.\n\t */\n\tgetPageRotationById(id: TLShapeId): number {\n\t\tconst pageTransform = this.editor.getShapePageTransform(id)\n\t\tif (pageTransform) {\n\t\t\treturn Mat.Decompose(pageTransform).rotation\n\t\t}\n\t\treturn 0\n\t}\n\n\t/**\n\t * Returns the rotation of a shape in page space, in radians.\n\t * @param shape - The shape to get the rotation of.\n\t */\n\tgetPageRotation(shape: TLShape) {\n\t\treturn this.getPageRotationById(shape.id)\n\t}\n\n\t/**\n\t * Returns all arrow shapes bound to the given shape.\n\t * @param shapeId - The shape ID to find arrows bound to.\n\t */\n\tgetArrowsBoundTo(shapeId: TLShapeId) {\n\t\tconst ids = new Set(this.editor.getBindingsToShape(shapeId, 'arrow').map((b) => b.fromId))\n\t\treturn compact(Array.from(ids, (id) => this.editor.getShape<TLArrowShape>(id)))\n\t}\n\n\t/* --------------- Event building --------------- */\n\n\t/**\n\t * Builds a TLPointerEventInfo object for input simulation.\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param options - Target shape/selection or partial event info.\n\t * @param modifiers - Override shift, ctrl, or alt key state.\n\t */\n\tprivate getPointerEventInfo(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\toptions?: PointerEventInit,\n\t\tmodifiers?: EventModifiers\n\t): TLPointerEventInfo {\n\t\tif (typeof options === 'string') {\n\t\t\toptions = { target: 'shape', shape: this.editor.getShape(options) }\n\t\t} else if (options === undefined) {\n\t\t\toptions = { target: 'canvas' }\n\t\t}\n\t\treturn {\n\t\t\tname: 'pointer_down',\n\t\t\ttype: 'pointer',\n\t\t\tpointerId: 1,\n\t\t\tshiftKey: this.editor.inputs.getShiftKey(),\n\t\t\tctrlKey: this.editor.inputs.getCtrlKey(),\n\t\t\taltKey: this.editor.inputs.getAltKey(),\n\t\t\tmetaKey: this.editor.inputs.getMetaKey(),\n\t\t\taccelKey: isAccelKey({ ...this.editor.inputs.toJson(), ...modifiers }),\n\t\t\tpoint: { x, y, z: null },\n\t\t\tbutton: 0,\n\t\t\tisPen: false,\n\t\t\t...options,\n\t\t\t...modifiers,\n\t\t} as TLPointerEventInfo\n\t}\n\n\t/**\n\t * Builds a TLKeyboardEventInfo object for input simulation.\n\t * @param key - The key being pressed.\n\t * @param name - The event name (key_down, key_up, key_repeat).\n\t * @param options - Partial event info overrides.\n\t */\n\tprivate getKeyboardEventInfo(\n\t\tkey: string,\n\t\tname: TLKeyboardEventInfo['name'],\n\t\toptions = {} as Partial<Omit<TLKeyboardEventInfo, 'point'>>\n\t): TLKeyboardEventInfo {\n\t\treturn {\n\t\t\tshiftKey: key === 'Shift',\n\t\t\tctrlKey: key === 'Control' || key === 'Meta',\n\t\t\taltKey: key === 'Alt',\n\t\t\tmetaKey: key === 'Meta',\n\t\t\taccelKey: tlenv.isDarwin ? key === 'Meta' : key === 'Control' || key === 'Meta',\n\t\t\t...options,\n\t\t\tname,\n\t\t\tcode:\n\t\t\t\tkey === 'Shift'\n\t\t\t\t\t? 'ShiftLeft'\n\t\t\t\t\t: key === 'Alt'\n\t\t\t\t\t\t? 'AltLeft'\n\t\t\t\t\t\t: key === 'Control'\n\t\t\t\t\t\t\t? 'CtrlLeft'\n\t\t\t\t\t\t\t: key === 'Meta'\n\t\t\t\t\t\t\t\t? 'MetaLeft'\n\t\t\t\t\t\t\t\t: key === ' '\n\t\t\t\t\t\t\t\t\t? 'Space'\n\t\t\t\t\t\t\t\t\t: key === 'Enter' ||\n\t\t\t\t\t\t\t\t\t\t key === 'ArrowRight' ||\n\t\t\t\t\t\t\t\t\t\t key === 'ArrowLeft' ||\n\t\t\t\t\t\t\t\t\t\t key === 'ArrowUp' ||\n\t\t\t\t\t\t\t\t\t\t key === 'ArrowDown'\n\t\t\t\t\t\t\t\t\t\t? key\n\t\t\t\t\t\t\t\t\t\t: 'Key' + key[0].toUpperCase() + key.slice(1),\n\t\t\ttype: 'keyboard',\n\t\t\tkey,\n\t\t}\n\t}\n\n\t/* --------------- Input events --------------- */\n\n\t/**\n\t * Emits tick events to advance the editor by the given number of frames (default 1).\n\t * @param count - Number of tick events to emit. Defaults to 1.\n\t */\n\tforceTick(count = 1) {\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tthis.editor.emit('tick', 16)\n\t\t}\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a pointer move event at the given screen coordinates.\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param options - Target shape/selection or partial event info.\n\t * @param modifiers - Override shift, ctrl, or alt key state.\n\t */\n\tpointerMove(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\toptions?: PointerEventInit,\n\t\tmodifiers?: EventModifiers\n\t) {\n\t\tthis.editor.dispatch({\n\t\t\t...this.getPointerEventInfo(x, y, options, modifiers),\n\t\t\tname: 'pointer_move',\n\t\t})\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a pointer down event at the given screen coordinates.\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param options - Target shape/selection or partial event info.\n\t * @param modifiers - Override shift, ctrl, or alt key state.\n\t */\n\tpointerDown(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\toptions?: PointerEventInit,\n\t\tmodifiers?: EventModifiers\n\t) {\n\t\tthis.editor.dispatch({\n\t\t\t...this.getPointerEventInfo(x, y, options, modifiers),\n\t\t\tname: 'pointer_down',\n\t\t})\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a pointer up event at the given screen coordinates.\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param options - Target shape/selection or partial event info.\n\t * @param modifiers - Override shift, ctrl, or alt key state.\n\t */\n\tpointerUp(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\toptions?: PointerEventInit,\n\t\tmodifiers?: EventModifiers\n\t) {\n\t\tthis.editor.dispatch({\n\t\t\t...this.getPointerEventInfo(x, y, options, modifiers),\n\t\t\tname: 'pointer_up',\n\t\t})\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a pointer down followed by pointer up at the given screen coordinates.\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param options - Target shape/selection or partial event info.\n\t * @param modifiers - Override shift, ctrl, or alt key state.\n\t */\n\tclick(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\toptions?: PointerEventInit,\n\t\tmodifiers?: EventModifiers\n\t) {\n\t\tthis.pointerDown(x, y, options, modifiers)\n\t\tthis.pointerUp(x, y, options, modifiers)\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a right-click (button 2) down and up at the given screen coordinates.\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param options - Target shape/selection or partial event info.\n\t * @param modifiers - Override shift, ctrl, or alt key state.\n\t */\n\trightClick(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\toptions?: PointerEventInit,\n\t\tmodifiers?: EventModifiers\n\t) {\n\t\tthis.editor.dispatch({\n\t\t\t...this.getPointerEventInfo(x, y, options, modifiers),\n\t\t\tname: 'pointer_down',\n\t\t\tbutton: 2,\n\t\t})\n\t\tthis.forceTick()\n\t\tthis.editor.dispatch({\n\t\t\t...this.getPointerEventInfo(x, y, options, modifiers),\n\t\t\tname: 'pointer_up',\n\t\t\tbutton: 2,\n\t\t})\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a double-click sequence at the given screen coordinates.\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param options - Target shape/selection or partial event info.\n\t * @param modifiers - Override shift, ctrl, or alt key state.\n\t */\n\tdoubleClick(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\toptions?: PointerEventInit,\n\t\tmodifiers?: EventModifiers\n\t) {\n\t\tthis.pointerDown(x, y, options, modifiers)\n\t\tthis.pointerUp(x, y, options, modifiers)\n\t\tthis.editor.dispatch({\n\t\t\t...this.getPointerEventInfo(x, y, options, modifiers),\n\t\t\ttype: 'click',\n\t\t\tname: 'double_click',\n\t\t\tphase: 'down',\n\t\t})\n\t\tthis.editor.dispatch({\n\t\t\t...this.getPointerEventInfo(x, y, options, modifiers),\n\t\t\ttype: 'click',\n\t\t\tname: 'double_click',\n\t\t\tphase: 'up',\n\t\t})\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a key down followed by key up for the given key.\n\t * @param key - The key to press (e.g. 'a', 'Enter', 'Shift').\n\t * @param options - Partial keyboard event overrides.\n\t */\n\tkeyPress(key: string, options = {} as Partial<Omit<TLKeyboardEventInfo, 'key'>>) {\n\t\tthis.keyDown(key, options)\n\t\tthis.keyUp(key, options)\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a key down event for the given key.\n\t * @param key - The key to press (e.g. 'a', 'Enter', 'Shift').\n\t * @param options - Partial keyboard event overrides.\n\t */\n\tkeyDown(key: string, options = {} as Partial<Omit<TLKeyboardEventInfo, 'key'>>) {\n\t\tthis.editor.dispatch({ ...this.getKeyboardEventInfo(key, 'key_down', options) })\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a key repeat event for the given key.\n\t * @param key - The key that is repeating (e.g. 'a', 'ArrowDown').\n\t * @param options - Partial keyboard event overrides.\n\t */\n\tkeyRepeat(key: string, options = {} as Partial<Omit<TLKeyboardEventInfo, 'key'>>) {\n\t\tthis.editor.dispatch({ ...this.getKeyboardEventInfo(key, 'key_repeat', options) })\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a key up event for the given key.\n\t * @param key - The key to release (e.g. 'a', 'Enter', 'Shift').\n\t * @param options - Partial keyboard event overrides.\n\t */\n\tkeyUp(key: string, options = {} as Partial<Omit<TLKeyboardEventInfo, 'key'>>) {\n\t\tthis.editor.dispatch({\n\t\t\t...this.getKeyboardEventInfo(key, 'key_up', {\n\t\t\t\tshiftKey: this.editor.inputs.getShiftKey() && key !== 'Shift',\n\t\t\t\tctrlKey: this.editor.inputs.getCtrlKey() && !(key === 'Control' || key === 'Meta'),\n\t\t\t\taltKey: this.editor.inputs.getAltKey() && key !== 'Alt',\n\t\t\t\tmetaKey: this.editor.inputs.getMetaKey() && key !== 'Meta',\n\t\t\t\t...options,\n\t\t\t}),\n\t\t})\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a wheel event with the given delta values.\n\t * @param dx - Horizontal scroll delta.\n\t * @param dy - Vertical scroll delta.\n\t * @param options - Partial wheel event overrides.\n\t */\n\twheel(dx: number, dy: number, options = {} as Partial<Omit<TLWheelEventInfo, 'delta'>>) {\n\t\tconst currentScreenPoint = this.editor.inputs.getCurrentScreenPoint()\n\t\tthis.editor.dispatch({\n\t\t\ttype: 'wheel',\n\t\t\tname: 'wheel',\n\t\t\tpoint: new Vec(currentScreenPoint.x, currentScreenPoint.y),\n\t\t\tshiftKey: this.editor.inputs.getShiftKey(),\n\t\t\tctrlKey: this.editor.inputs.getCtrlKey(),\n\t\t\taltKey: this.editor.inputs.getAltKey(),\n\t\t\tmetaKey: this.editor.inputs.getMetaKey(),\n\t\t\taccelKey: isAccelKey(this.editor.inputs),\n\t\t\t...options,\n\t\t\tdelta: { x: dx, y: dy },\n\t\t})\n\t\tthis.forceTick(2)\n\t\treturn this\n\t}\n\n\t/**\n\t * Pans the camera by the given offset (in page coordinates). Does nothing if camera is locked.\n\t * @param offset - The pan delta (x, y) in page coordinates.\n\t */\n\tpan(offset: VecLike) {\n\t\tconst { isLocked, panSpeed } = this.editor.getCameraOptions()\n\t\tif (isLocked) return this\n\t\tconst { x: cx, y: cy, z: cz } = this.editor.getCamera()\n\t\tthis.editor.setCamera(\n\t\t\tnew Vec(cx + (offset.x * panSpeed) / cz, cy + (offset.y * panSpeed) / cz, cz),\n\t\t\t{ immediate: true }\n\t\t)\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a pinch start event.\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param z - Pinch scale/factor.\n\t * @param dx - Delta x for pinch.\n\t * @param dy - Delta y for pinch.\n\t * @param dz - Delta z for pinch.\n\t * @param options - Partial pinch event overrides.\n\t */\n\tpinchStart(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\tz: number,\n\t\tdx: number,\n\t\tdy: number,\n\t\tdz: number,\n\t\toptions = {} as Partial<Omit<TLPinchEventInfo, 'point' | 'delta' | 'offset'>>\n\t) {\n\t\tthis.editor.dispatch({\n\t\t\ttype: 'pinch',\n\t\t\tname: 'pinch_start',\n\t\t\tshiftKey: this.editor.inputs.getShiftKey(),\n\t\t\tctrlKey: this.editor.inputs.getCtrlKey(),\n\t\t\taltKey: this.editor.inputs.getAltKey(),\n\t\t\tmetaKey: this.editor.inputs.getMetaKey(),\n\t\t\taccelKey: isAccelKey(this.editor.inputs),\n\t\t\t...options,\n\t\t\tpoint: { x, y, z },\n\t\t\tdelta: { x: dx, y: dy, z: dz },\n\t\t})\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a pinch move event (pinch_to).\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param z - Pinch scale/factor.\n\t * @param dx - Delta x for pinch.\n\t * @param dy - Delta y for pinch.\n\t * @param dz - Delta z for pinch.\n\t * @param options - Partial pinch event overrides.\n\t */\n\tpinchTo(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\tz: number,\n\t\tdx: number,\n\t\tdy: number,\n\t\tdz: number,\n\t\toptions = {} as Partial<Omit<TLPinchEventInfo, 'point' | 'delta' | 'offset'>>\n\t) {\n\t\tthis.editor.dispatch({\n\t\t\ttype: 'pinch',\n\t\t\tname: 'pinch',\n\t\t\tshiftKey: this.editor.inputs.getShiftKey(),\n\t\t\tctrlKey: this.editor.inputs.getCtrlKey(),\n\t\t\taltKey: this.editor.inputs.getAltKey(),\n\t\t\tmetaKey: this.editor.inputs.getMetaKey(),\n\t\t\taccelKey: isAccelKey(this.editor.inputs),\n\t\t\t...options,\n\t\t\tpoint: { x, y, z },\n\t\t\tdelta: { x: dx, y: dy, z: dz },\n\t\t})\n\t\treturn this\n\t}\n\n\t/**\n\t * Dispatches a pinch end event.\n\t * @param x - Screen x coordinate. Defaults to current pointer.\n\t * @param y - Screen y coordinate. Defaults to current pointer.\n\t * @param z - Pinch scale/factor.\n\t * @param dx - Delta x for pinch.\n\t * @param dy - Delta y for pinch.\n\t * @param dz - Delta z for pinch.\n\t * @param options - Partial pinch event overrides.\n\t */\n\tpinchEnd(\n\t\tx = this.editor.inputs.getCurrentScreenPoint().x,\n\t\ty = this.editor.inputs.getCurrentScreenPoint().y,\n\t\tz: number,\n\t\tdx: number,\n\t\tdy: number,\n\t\tdz: number,\n\t\toptions = {} as Partial<Omit<TLPinchEventInfo, 'point' | 'delta' | 'offset'>>\n\t) {\n\t\tthis.editor.dispatch({\n\t\t\ttype: 'pinch',\n\t\t\tname: 'pinch_end',\n\t\t\tshiftKey: this.editor.inputs.getShiftKey(),\n\t\t\tctrlKey: this.editor.inputs.getCtrlKey(),\n\t\t\taltKey: this.editor.inputs.getAltKey(),\n\t\t\tmetaKey: this.editor.inputs.getMetaKey(),\n\t\t\taccelKey: isAccelKey(this.editor.inputs),\n\t\t\t...options,\n\t\t\tpoint: { x, y, z },\n\t\t\tdelta: { x: dx, y: dy, z: dz },\n\t\t})\n\t\tthis.forceTick()\n\t\treturn this\n\t}\n\n\t/* --------------- Interaction helpers --------------- */\n\n\t/**\n\t * Converts a point from page coordinates to screen coordinates.\n\t * Pointer events operate in screen space, so page-space points must be\n\t * converted before being passed to pointerDown/Move/Up.\n\t */\n\tprivate pageToScreen(point: VecLike) {\n\t\treturn this.editor.pageToScreen(point)\n\t}\n\n\t/**\n\t * Simulates rotating the current selection by the given angle in radians via the rotation handle.\n\t * @param angleRadians - Rotation angle in radians.\n\t * @param options - Optional handle and shiftKey. handle defaults to 'top_left_rotate'.\n\t */\n\trotateSelection(\n\t\tangleRadians: number,\n\t\toptions: { handle?: RotateCorner; shiftKey?: boolean } = {}\n\t) {\n\t\tconst { handle = 'top_left_rotate', shiftKey = false } = options\n\t\tif (this.editor.getSelectedShapeIds().length === 0) {\n\t\t\tthrow new Error('No selection')\n\t\t}\n\n\t\tthis.editor.setCurrentTool('select')\n\n\t\tconst handlePoint = this.editor\n\t\t\t.getSelectionRotatedPageBounds()!\n\t\t\t.getHandlePoint(ROTATE_CORNER_TO_SELECTION_CORNER[handle])\n\t\t\t.clone()\n\t\t\t.rotWith(\n\t\t\t\tthis.editor.getSelectionRotatedPageBounds()!.point,\n\t\t\t\tthis.editor.getSelectionRotation()\n\t\t\t)\n\n\t\tconst targetHandlePoint = Vec.RotWith(handlePoint, this.getSelectionPageCenter()!, angleRadians)\n\n\t\tconst screenHandle = this.pageToScreen(handlePoint)\n\t\tconst screenTarget = this.pageToScreen(targetHandlePoint)\n\n\t\tthis.pointerDown(screenHandle.x, screenHandle.y, { target: 'selection', handle })\n\t\tthis.pointerMove(screenTarget.x, screenTarget.y, { shiftKey })\n\t\tthis.pointerUp()\n\t\treturn this\n\t}\n\n\t/**\n\t * Simulates translating the current selection by the given delta in page coordinates.\n\t * @param dx - Horizontal delta in page coordinates.\n\t * @param dy - Vertical delta in page coordinates.\n\t * @param options - Partial pointer event overrides (e.g. altKey for center-based scaling).\n\t */\n\ttranslateSelection(dx: number, dy: number, options?: Partial<TLPointerEventInfo>) {\n\t\tif (this.editor.getSelectedShapeIds().length === 0) {\n\t\t\tthrow new Error('No selection')\n\t\t}\n\t\tthis.editor.setCurrentTool('select')\n\n\t\tconst center = this.getSelectionPageCenter()!\n\t\tconst screenCenter = this.pageToScreen(center)\n\n\t\tthis.pointerDown(screenCenter.x, screenCenter.y, this.editor.getSelectedShapeIds()[0])\n\t\tconst numSteps = 10\n\t\tfor (let i = 1; i < numSteps; i++) {\n\t\t\tconst p = this.pageToScreen({\n\t\t\t\tx: center.x + (i * dx) / numSteps,\n\t\t\t\ty: center.y + (i * dy) / numSteps,\n\t\t\t})\n\t\t\tthis.pointerMove(p.x, p.y, options)\n\t\t}\n\t\tconst endScreen = this.pageToScreen({ x: center.x + dx, y: center.y + dy })\n\t\tthis.pointerUp(endScreen.x, endScreen.y, options)\n\t\treturn this\n\t}\n\n\t/**\n\t * Simulates resizing the current selection via the given handle, with optional scale factors.\n\t * @param scale - Scale factors for x and y. Defaults to `\\{ scaleX: 1, scaleY: 1 \\}`.\n\t * @param handle - The selection handle to drag (e.g. 'top', 'bottom_right').\n\t * @param options - Partial pointer event overrides (e.g. altKey to scale from center).\n\t */\n\tresizeSelection(\n\t\tscale: { scaleX?: number; scaleY?: number } = {},\n\t\thandle: SelectionHandle,\n\t\toptions?: Partial<TLPointerEventInfo>\n\t) {\n\t\tconst { scaleX = 1, scaleY = 1 } = scale\n\t\tif (this.editor.getSelectedShapeIds().length === 0) {\n\t\t\tthrow new Error('No selection')\n\t\t}\n\t\tthis.editor.setCurrentTool('select')\n\t\tconst bounds = this.editor.getSelectionRotatedPageBounds()!\n\t\tconst preRotationHandlePoint = bounds.getHandlePoint(handle)\n\n\t\tconst preRotationScaleOriginPoint = options?.altKey\n\t\t\t? bounds.center\n\t\t\t: bounds.getHandlePoint(rotateSelectionHandle(handle, Math.PI))\n\n\t\tconst preRotationTargetHandlePoint = Vec.Add(\n\t\t\tVec.Sub(preRotationHandlePoint, preRotationScaleOriginPoint).mulV({\n\t\t\t\tx: scaleX,\n\t\t\t\ty: scaleY,\n\t\t\t}),\n\t\t\tpreRotationScaleOriginPoint\n\t\t)\n\n\t\tconst handlePoint = Vec.RotWith(\n\t\t\tpreRotationHandlePoint,\n\t\t\tbounds.point,\n\t\t\tthis.editor.getSelectionRotation()\n\t\t)\n\t\tconst targetHandlePoint = Vec.RotWith(\n\t\t\tpreRotationTargetHandlePoint,\n\t\t\tbounds.point,\n\t\t\tthis.editor.getSelectionRotation()\n\t\t)\n\n\t\tconst screenHandle = this.pageToScreen(handlePoint)\n\t\tconst screenTarget = this.pageToScreen(targetHandlePoint)\n\n\t\tthis.pointerDown(screenHandle.x, screenHandle.y, { target: 'selection', handle }, options)\n\t\tthis.pointerMove(screenTarget.x, screenTarget.y, options)\n\t\tthis.pointerUp(screenTarget.x, screenTarget.y, options)\n\t\treturn this\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }