@tldraw/editor 5.2.0-canary.fe03bcdddf34 → 5.2.0-canary.ff23978d50f6

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.
Files changed (30) hide show
  1. package/dist-cjs/index.d.ts +4 -7
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +8 -58
  4. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
  5. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +1 -2
  6. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
  7. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  8. package/dist-cjs/lib/editor/types/event-types.js +0 -2
  9. package/dist-cjs/lib/editor/types/event-types.js.map +2 -2
  10. package/dist-cjs/version.js +3 -3
  11. package/dist-cjs/version.js.map +1 -1
  12. package/dist-esm/index.d.mts +4 -7
  13. package/dist-esm/index.mjs +1 -1
  14. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +8 -58
  15. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
  16. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +1 -2
  17. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
  18. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  19. package/dist-esm/lib/editor/types/event-types.mjs +0 -2
  20. package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
  21. package/dist-esm/version.mjs +3 -3
  22. package/dist-esm/version.mjs.map +1 -1
  23. package/package.json +7 -7
  24. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +54 -74
  25. package/src/lib/editor/managers/ClickManager/ClickManager.ts +15 -65
  26. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +4 -4
  27. package/src/lib/editor/managers/FocusManager/FocusManager.ts +1 -2
  28. package/src/lib/editor/tools/StateNode.ts +0 -2
  29. package/src/lib/editor/types/event-types.ts +2 -6
  30. package/src/version.ts +3 -3
@@ -746,6 +746,7 @@ export declare class ClickManager {
746
746
  private _clickTimeout?;
747
747
  private _clickScreenPoint?;
748
748
  private _previousScreenPoint?;
749
+ private _isPressingWhilePending;
749
750
  _getClickTimeout(state: TLClickState, id?: string): void;
750
751
  /* Excluded from this release type: _clickState */
751
752
  /**
@@ -7166,8 +7167,6 @@ export declare abstract class StateNode implements Partial<TLEventHandlers> {
7166
7167
  onLongPress?(info: TLPointerEventInfo): void;
7167
7168
  onPointerUp?(info: TLPointerEventInfo): void;
7168
7169
  onDoubleClick?(info: TLClickEventInfo): void;
7169
- onTripleClick?(info: TLClickEventInfo): void;
7170
- onQuadrupleClick?(info: TLClickEventInfo): void;
7171
7170
  onRightClick?(info: TLPointerEventInfo): void;
7172
7171
  onMiddleClick?(info: TLPointerEventInfo): void;
7173
7172
  onKeyDown?(info: TLKeyboardEventInfo): void;
@@ -7567,17 +7566,17 @@ export declare type TLClickEvent = (info: TLClickEventInfo) => void;
7567
7566
  export declare type TLClickEventInfo = TLBaseEventInfo & {
7568
7567
  button: number;
7569
7568
  name: TLCLickEventName;
7570
- phase: 'down' | 'settle' | 'up';
7569
+ phase: 'down' | 'settle-down' | 'settle-up' | 'up';
7571
7570
  point: VecLike;
7572
7571
  pointerId: number;
7573
7572
  type: 'click';
7574
7573
  } & TLPointerEventTarget;
7575
7574
 
7576
7575
  /** @public */
7577
- export declare type TLCLickEventName = 'double_click' | 'quadruple_click' | 'triple_click';
7576
+ export declare type TLCLickEventName = 'double_click';
7578
7577
 
7579
7578
  /** @public */
7580
- export declare type TLClickState = 'idle' | 'overflow' | 'pendingDouble' | 'pendingOverflow' | 'pendingQuadruple' | 'pendingTriple';
7579
+ export declare type TLClickState = 'idle' | 'overflow' | 'pendingDouble' | 'pendingOverflow';
7581
7580
 
7582
7581
  /**
7583
7582
  * Raw clipboard paste payload, before tldraw parses clipboard contents into {@link TLExternalContent}.
@@ -8357,8 +8356,6 @@ export declare interface TLEventHandlers {
8357
8356
  onLongPress: TLPointerEvent;
8358
8357
  onRightClick: TLPointerEvent;
8359
8358
  onDoubleClick: TLClickEvent;
8360
- onTripleClick: TLClickEvent;
8361
- onQuadrupleClick: TLClickEvent;
8362
8359
  onMiddleClick: TLPointerEvent;
8363
8360
  onPointerUp: TLPointerEvent;
8364
8361
  onKeyDown: TLKeyboardEvent;
package/dist-cjs/index.js CHANGED
@@ -380,7 +380,7 @@ var import_uniq = require("./lib/utils/uniq");
380
380
  var import_defaultThemes2 = require("./lib/editor/managers/ThemeManager/defaultThemes");
381
381
  (0, import_utils.registerTldrawLibraryVersion)(
382
382
  "@tldraw/editor",
383
- "5.2.0-canary.fe03bcdddf34",
383
+ "5.2.0-canary.ff23978d50f6",
384
384
  "cjs"
385
385
  );
386
386
  //# sourceMappingURL=index.js.map
@@ -41,6 +41,7 @@ class ClickManager {
41
41
  _clickTimeout;
42
42
  _clickScreenPoint;
43
43
  _previousScreenPoint;
44
+ _isPressingWhilePending = false;
44
45
  _getClickTimeout(state, id = (0, import_utils.uniqueId)()) {
45
46
  this._clickId = id;
46
47
  clearTimeout(this._clickTimeout);
@@ -48,30 +49,12 @@ class ClickManager {
48
49
  () => {
49
50
  if (this._clickState === state && this._clickId === id) {
50
51
  switch (this._clickState) {
51
- case "pendingTriple": {
52
- this.editor.dispatch({
53
- ...this.lastPointerInfo,
54
- type: "click",
55
- name: "double_click",
56
- phase: "settle"
57
- });
58
- break;
59
- }
60
- case "pendingQuadruple": {
61
- this.editor.dispatch({
62
- ...this.lastPointerInfo,
63
- type: "click",
64
- name: "triple_click",
65
- phase: "settle"
66
- });
67
- break;
68
- }
69
52
  case "pendingOverflow": {
70
53
  this.editor.dispatch({
71
54
  ...this.lastPointerInfo,
72
55
  type: "click",
73
- name: "quadruple_click",
74
- phase: "settle"
56
+ name: "double_click",
57
+ phase: this._isPressingWhilePending ? "settle-down" : "settle-up"
75
58
  });
76
59
  break;
77
60
  }
@@ -105,6 +88,7 @@ class ClickManager {
105
88
  case "pointer_down": {
106
89
  if (!this._clickState) return info;
107
90
  this._clickScreenPoint = import_Vec.Vec.From(info.point);
91
+ this._isPressingWhilePending = true;
108
92
  if (this._previousScreenPoint && import_Vec.Vec.Dist2(this._previousScreenPoint, this._clickScreenPoint) > MAX_CLICK_DISTANCE ** 2) {
109
93
  this._clickState = "idle";
110
94
  }
@@ -112,32 +96,12 @@ class ClickManager {
112
96
  this.lastPointerInfo = info;
113
97
  switch (this._clickState) {
114
98
  case "pendingDouble": {
115
- this._clickState = "pendingTriple";
116
- this._clickTimeout = this._getClickTimeout(this._clickState);
117
- return {
118
- ...info,
119
- type: "click",
120
- name: "double_click",
121
- phase: "down"
122
- };
123
- }
124
- case "pendingTriple": {
125
- this._clickState = "pendingQuadruple";
126
- this._clickTimeout = this._getClickTimeout(this._clickState);
127
- return {
128
- ...info,
129
- type: "click",
130
- name: "triple_click",
131
- phase: "down"
132
- };
133
- }
134
- case "pendingQuadruple": {
135
99
  this._clickState = "pendingOverflow";
136
100
  this._clickTimeout = this._getClickTimeout(this._clickState);
137
101
  return {
138
102
  ...info,
139
103
  type: "click",
140
- name: "quadruple_click",
104
+ name: "double_click",
141
105
  phase: "down"
142
106
  };
143
107
  }
@@ -158,28 +122,13 @@ class ClickManager {
158
122
  case "pointer_up": {
159
123
  if (!this._clickState) return info;
160
124
  this._clickScreenPoint = import_Vec.Vec.From(info.point);
125
+ this._isPressingWhilePending = false;
161
126
  switch (this._clickState) {
162
- case "pendingTriple": {
163
- return {
164
- ...this.lastPointerInfo,
165
- type: "click",
166
- name: "double_click",
167
- phase: "up"
168
- };
169
- }
170
- case "pendingQuadruple": {
171
- return {
172
- ...this.lastPointerInfo,
173
- type: "click",
174
- name: "triple_click",
175
- phase: "up"
176
- };
177
- }
178
127
  case "pendingOverflow": {
179
128
  return {
180
129
  ...this.lastPointerInfo,
181
130
  type: "click",
182
- name: "quadruple_click",
131
+ name: "double_click",
183
132
  phase: "up"
184
133
  };
185
134
  }
@@ -200,6 +149,7 @@ class ClickManager {
200
149
  cancelDoubleClickTimeout() {
201
150
  this._clickTimeout = clearTimeout(this._clickTimeout);
202
151
  this._clickState = "idle";
152
+ this._isPressingWhilePending = false;
203
153
  }
204
154
  }
205
155
  __decorateClass([
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/editor/managers/ClickManager/ClickManager.ts"],
4
- "sourcesContent": ["import { bind, uniqueId } from '@tldraw/utils'\nimport { Vec } from '../../../primitives/Vec'\nimport type { Editor } from '../../Editor'\nimport { TLClickEventInfo, TLPointerEventInfo } from '../../types/event-types'\n\n/** @public */\nexport type TLClickState =\n\t| 'idle'\n\t| 'pendingDouble'\n\t| 'pendingTriple'\n\t| 'pendingQuadruple'\n\t| 'pendingOverflow'\n\t| 'overflow'\n\nconst MAX_CLICK_DISTANCE = 40\n\n/** @public */\nexport class ClickManager {\n\tconstructor(public editor: Editor) {}\n\n\tprivate _clickId = ''\n\n\tprivate _clickTimeout?: any\n\n\tprivate _clickScreenPoint?: Vec\n\n\tprivate _previousScreenPoint?: Vec\n\n\t@bind\n\t_getClickTimeout(state: TLClickState, id = uniqueId()) {\n\t\tthis._clickId = id\n\t\tclearTimeout(this._clickTimeout)\n\t\tthis._clickTimeout = this.editor.timers.setTimeout(\n\t\t\t() => {\n\t\t\t\tif (this._clickState === state && this._clickId === id) {\n\t\t\t\t\tswitch (this._clickState) {\n\t\t\t\t\t\tcase 'pendingTriple': {\n\t\t\t\t\t\t\tthis.editor.dispatch({\n\t\t\t\t\t\t\t\t...this.lastPointerInfo,\n\t\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\t\tname: 'double_click',\n\t\t\t\t\t\t\t\tphase: 'settle',\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'pendingQuadruple': {\n\t\t\t\t\t\t\tthis.editor.dispatch({\n\t\t\t\t\t\t\t\t...this.lastPointerInfo,\n\t\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\t\tname: 'triple_click',\n\t\t\t\t\t\t\t\tphase: 'settle',\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcase 'pendingOverflow': {\n\t\t\t\t\t\t\tthis.editor.dispatch({\n\t\t\t\t\t\t\t\t...this.lastPointerInfo,\n\t\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\t\tname: 'quadruple_click',\n\t\t\t\t\t\t\t\tphase: 'settle',\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t// noop\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._clickState = 'idle'\n\t\t\t\t}\n\t\t\t},\n\t\t\tstate === 'idle' || state === 'pendingDouble'\n\t\t\t\t? this.editor.options.doubleClickDurationMs\n\t\t\t\t: this.editor.options.multiClickDurationMs\n\t\t)\n\t}\n\n\t/**\n\t * The current click state.\n\t *\n\t * @internal\n\t */\n\tprivate _clickState?: TLClickState = 'idle'\n\n\t/**\n\t * The current click state.\n\t *\n\t * @public\n\t */\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tget clickState() {\n\t\treturn this._clickState\n\t}\n\n\tlastPointerInfo = {} as TLPointerEventInfo\n\n\thandlePointerEvent(info: TLPointerEventInfo): TLPointerEventInfo | TLClickEventInfo {\n\t\tswitch (info.name) {\n\t\t\tcase 'pointer_down': {\n\t\t\t\tif (!this._clickState) return info\n\t\t\t\tthis._clickScreenPoint = Vec.From(info.point)\n\n\t\t\t\tif (\n\t\t\t\t\tthis._previousScreenPoint &&\n\t\t\t\t\tVec.Dist2(this._previousScreenPoint, this._clickScreenPoint) > MAX_CLICK_DISTANCE ** 2\n\t\t\t\t) {\n\t\t\t\t\tthis._clickState = 'idle'\n\t\t\t\t}\n\n\t\t\t\tthis._previousScreenPoint = this._clickScreenPoint\n\n\t\t\t\tthis.lastPointerInfo = info\n\n\t\t\t\tswitch (this._clickState) {\n\t\t\t\t\tcase 'pendingDouble': {\n\t\t\t\t\t\tthis._clickState = 'pendingTriple'\n\t\t\t\t\t\tthis._clickTimeout = this._getClickTimeout(this._clickState)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\tname: 'double_click',\n\t\t\t\t\t\t\tphase: 'down',\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'pendingTriple': {\n\t\t\t\t\t\tthis._clickState = 'pendingQuadruple'\n\t\t\t\t\t\tthis._clickTimeout = this._getClickTimeout(this._clickState)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\tname: 'triple_click',\n\t\t\t\t\t\t\tphase: 'down',\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'pendingQuadruple': {\n\t\t\t\t\t\tthis._clickState = 'pendingOverflow'\n\t\t\t\t\t\tthis._clickTimeout = this._getClickTimeout(this._clickState)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\tname: 'quadruple_click',\n\t\t\t\t\t\t\tphase: 'down',\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'idle': {\n\t\t\t\t\t\tthis._clickState = 'pendingDouble'\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'pendingOverflow': {\n\t\t\t\t\t\tthis._clickState = 'overflow'\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\t// overflow\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis._clickTimeout = this._getClickTimeout(this._clickState)\n\t\t\t\treturn info\n\t\t\t}\n\t\t\tcase 'pointer_up': {\n\t\t\t\tif (!this._clickState) return info\n\t\t\t\tthis._clickScreenPoint = Vec.From(info.point)\n\n\t\t\t\tswitch (this._clickState) {\n\t\t\t\t\tcase 'pendingTriple': {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...this.lastPointerInfo,\n\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\tname: 'double_click',\n\t\t\t\t\t\t\tphase: 'up',\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'pendingQuadruple': {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...this.lastPointerInfo,\n\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\tname: 'triple_click',\n\t\t\t\t\t\t\tphase: 'up',\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'pendingOverflow': {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...this.lastPointerInfo,\n\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\tname: 'quadruple_click',\n\t\t\t\t\t\t\tphase: 'up',\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\t// idle, pendingDouble, overflow\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn info\n\t\t\t}\n\t\t\tcase 'pointer_move': {\n\t\t\t\tif (\n\t\t\t\t\tthis._clickState !== 'idle' &&\n\t\t\t\t\tthis._clickScreenPoint &&\n\t\t\t\t\tVec.Dist2(this._clickScreenPoint, this.editor.inputs.getCurrentScreenPoint()) >\n\t\t\t\t\t\t(this.editor.getInstanceState().isCoarsePointer\n\t\t\t\t\t\t\t? this.editor.options.coarseDragDistanceSquared\n\t\t\t\t\t\t\t: this.editor.options.dragDistanceSquared)\n\t\t\t\t) {\n\t\t\t\t\tthis.cancelDoubleClickTimeout()\n\t\t\t\t}\n\t\t\t\treturn info\n\t\t\t}\n\t\t}\n\t\treturn info\n\t}\n\n\t/**\n\t * Cancel the double click timeout.\n\t *\n\t * @internal\n\t */\n\t@bind\n\tcancelDoubleClickTimeout() {\n\t\tthis._clickTimeout = clearTimeout(this._clickTimeout)\n\t\tthis._clickState = 'idle'\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { bind, uniqueId } from '@tldraw/utils'\nimport { Vec } from '../../../primitives/Vec'\nimport type { Editor } from '../../Editor'\nimport { TLClickEventInfo, TLPointerEventInfo } from '../../types/event-types'\n\n/** @public */\nexport type TLClickState = 'idle' | 'pendingDouble' | 'pendingOverflow' | 'overflow'\n\nconst MAX_CLICK_DISTANCE = 40\n\n/** @public */\nexport class ClickManager {\n\tconstructor(public editor: Editor) {}\n\n\tprivate _clickId = ''\n\n\tprivate _clickTimeout?: any\n\n\tprivate _clickScreenPoint?: Vec\n\n\tprivate _previousScreenPoint?: Vec\n\n\tprivate _isPressingWhilePending = false\n\n\t@bind\n\t_getClickTimeout(state: TLClickState, id = uniqueId()) {\n\t\tthis._clickId = id\n\t\tclearTimeout(this._clickTimeout)\n\t\tthis._clickTimeout = this.editor.timers.setTimeout(\n\t\t\t() => {\n\t\t\t\tif (this._clickState === state && this._clickId === id) {\n\t\t\t\t\tswitch (this._clickState) {\n\t\t\t\t\t\tcase 'pendingOverflow': {\n\t\t\t\t\t\t\tthis.editor.dispatch({\n\t\t\t\t\t\t\t\t...this.lastPointerInfo,\n\t\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\t\tname: 'double_click',\n\t\t\t\t\t\t\t\tphase: this._isPressingWhilePending ? 'settle-down' : 'settle-up',\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdefault: {\n\t\t\t\t\t\t\t// noop\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._clickState = 'idle'\n\t\t\t\t}\n\t\t\t},\n\t\t\tstate === 'idle' || state === 'pendingDouble'\n\t\t\t\t? this.editor.options.doubleClickDurationMs\n\t\t\t\t: this.editor.options.multiClickDurationMs\n\t\t)\n\t}\n\n\t/**\n\t * The current click state.\n\t *\n\t * @internal\n\t */\n\tprivate _clickState?: TLClickState = 'idle'\n\n\t/**\n\t * The current click state.\n\t *\n\t * @public\n\t */\n\t// eslint-disable-next-line tldraw/no-setter-getter\n\tget clickState() {\n\t\treturn this._clickState\n\t}\n\n\tlastPointerInfo = {} as TLPointerEventInfo\n\n\thandlePointerEvent(info: TLPointerEventInfo): TLPointerEventInfo | TLClickEventInfo {\n\t\tswitch (info.name) {\n\t\t\tcase 'pointer_down': {\n\t\t\t\tif (!this._clickState) return info\n\t\t\t\tthis._clickScreenPoint = Vec.From(info.point)\n\n\t\t\t\tthis._isPressingWhilePending = true\n\n\t\t\t\tif (\n\t\t\t\t\tthis._previousScreenPoint &&\n\t\t\t\t\tVec.Dist2(this._previousScreenPoint, this._clickScreenPoint) > MAX_CLICK_DISTANCE ** 2\n\t\t\t\t) {\n\t\t\t\t\tthis._clickState = 'idle'\n\t\t\t\t}\n\n\t\t\t\tthis._previousScreenPoint = this._clickScreenPoint\n\n\t\t\t\tthis.lastPointerInfo = info\n\n\t\t\t\tswitch (this._clickState) {\n\t\t\t\t\tcase 'pendingDouble': {\n\t\t\t\t\t\tthis._clickState = 'pendingOverflow'\n\t\t\t\t\t\tthis._clickTimeout = this._getClickTimeout(this._clickState)\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\tname: 'double_click',\n\t\t\t\t\t\t\tphase: 'down',\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tcase 'idle': {\n\t\t\t\t\t\tthis._clickState = 'pendingDouble'\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'pendingOverflow': {\n\t\t\t\t\t\tthis._clickState = 'overflow'\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\t// overflow\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis._clickTimeout = this._getClickTimeout(this._clickState)\n\t\t\t\treturn info\n\t\t\t}\n\t\t\tcase 'pointer_up': {\n\t\t\t\tif (!this._clickState) return info\n\n\t\t\t\tthis._clickScreenPoint = Vec.From(info.point)\n\n\t\t\t\tthis._isPressingWhilePending = false\n\n\t\t\t\tswitch (this._clickState) {\n\t\t\t\t\tcase 'pendingOverflow': {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t...this.lastPointerInfo,\n\t\t\t\t\t\t\ttype: 'click',\n\t\t\t\t\t\t\tname: 'double_click',\n\t\t\t\t\t\t\tphase: 'up',\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tdefault: {\n\t\t\t\t\t\t// idle, pendingDouble, overflow\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn info\n\t\t\t}\n\t\t\tcase 'pointer_move': {\n\t\t\t\tif (\n\t\t\t\t\tthis._clickState !== 'idle' &&\n\t\t\t\t\tthis._clickScreenPoint &&\n\t\t\t\t\tVec.Dist2(this._clickScreenPoint, this.editor.inputs.getCurrentScreenPoint()) >\n\t\t\t\t\t\t(this.editor.getInstanceState().isCoarsePointer\n\t\t\t\t\t\t\t? this.editor.options.coarseDragDistanceSquared\n\t\t\t\t\t\t\t: this.editor.options.dragDistanceSquared)\n\t\t\t\t) {\n\t\t\t\t\tthis.cancelDoubleClickTimeout()\n\t\t\t\t}\n\t\t\t\treturn info\n\t\t\t}\n\t\t}\n\t\treturn info\n\t}\n\n\t/**\n\t * Cancel the double click timeout.\n\t *\n\t * @internal\n\t */\n\t@bind\n\tcancelDoubleClickTimeout() {\n\t\tthis._clickTimeout = clearTimeout(this._clickTimeout)\n\t\tthis._clickState = 'idle'\n\t\t// when a double click is cancelled, we are no longer pending any further\n\t\t// clicks, so we set this to false even if the user is still pressing\n\t\tthis._isPressingWhilePending = false\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA+B;AAC/B,iBAAoB;AAOpB,MAAM,qBAAqB;AAGpB,MAAM,aAAa;AAAA,EACzB,YAAmB,QAAgB;AAAhB;AAAA,EAAiB;AAAA,EAAjB;AAAA,EAEX,WAAW;AAAA,EAEX;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA,0BAA0B;AAAA,EAGlC,iBAAiB,OAAqB,SAAK,uBAAS,GAAG;AACtD,SAAK,WAAW;AAChB,iBAAa,KAAK,aAAa;AAC/B,SAAK,gBAAgB,KAAK,OAAO,OAAO;AAAA,MACvC,MAAM;AACL,YAAI,KAAK,gBAAgB,SAAS,KAAK,aAAa,IAAI;AACvD,kBAAQ,KAAK,aAAa;AAAA,YACzB,KAAK,mBAAmB;AACvB,mBAAK,OAAO,SAAS;AAAA,gBACpB,GAAG,KAAK;AAAA,gBACR,MAAM;AAAA,gBACN,MAAM;AAAA,gBACN,OAAO,KAAK,0BAA0B,gBAAgB;AAAA,cACvD,CAAC;AACD;AAAA,YACD;AAAA,YACA,SAAS;AAAA,YAET;AAAA,UACD;AAEA,eAAK,cAAc;AAAA,QACpB;AAAA,MACD;AAAA,MACA,UAAU,UAAU,UAAU,kBAC3B,KAAK,OAAO,QAAQ,wBACpB,KAAK,OAAO,QAAQ;AAAA,IACxB;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,cAA6B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrC,IAAI,aAAa;AAChB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,kBAAkB,CAAC;AAAA,EAEnB,mBAAmB,MAAiE;AACnF,YAAQ,KAAK,MAAM;AAAA,MAClB,KAAK,gBAAgB;AACpB,YAAI,CAAC,KAAK,YAAa,QAAO;AAC9B,aAAK,oBAAoB,eAAI,KAAK,KAAK,KAAK;AAE5C,aAAK,0BAA0B;AAE/B,YACC,KAAK,wBACL,eAAI,MAAM,KAAK,sBAAsB,KAAK,iBAAiB,IAAI,sBAAsB,GACpF;AACD,eAAK,cAAc;AAAA,QACpB;AAEA,aAAK,uBAAuB,KAAK;AAEjC,aAAK,kBAAkB;AAEvB,gBAAQ,KAAK,aAAa;AAAA,UACzB,KAAK,iBAAiB;AACrB,iBAAK,cAAc;AACnB,iBAAK,gBAAgB,KAAK,iBAAiB,KAAK,WAAW;AAC3D,mBAAO;AAAA,cACN,GAAG;AAAA,cACH,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,YACR;AAAA,UACD;AAAA,UACA,KAAK,QAAQ;AACZ,iBAAK,cAAc;AACnB;AAAA,UACD;AAAA,UACA,KAAK,mBAAmB;AACvB,iBAAK,cAAc;AACnB;AAAA,UACD;AAAA,UACA,SAAS;AAAA,UAET;AAAA,QACD;AACA,aAAK,gBAAgB,KAAK,iBAAiB,KAAK,WAAW;AAC3D,eAAO;AAAA,MACR;AAAA,MACA,KAAK,cAAc;AAClB,YAAI,CAAC,KAAK,YAAa,QAAO;AAE9B,aAAK,oBAAoB,eAAI,KAAK,KAAK,KAAK;AAE5C,aAAK,0BAA0B;AAE/B,gBAAQ,KAAK,aAAa;AAAA,UACzB,KAAK,mBAAmB;AACvB,mBAAO;AAAA,cACN,GAAG,KAAK;AAAA,cACR,MAAM;AAAA,cACN,MAAM;AAAA,cACN,OAAO;AAAA,YACR;AAAA,UACD;AAAA,UACA,SAAS;AAAA,UAET;AAAA,QACD;AAEA,eAAO;AAAA,MACR;AAAA,MACA,KAAK,gBAAgB;AACpB,YACC,KAAK,gBAAgB,UACrB,KAAK,qBACL,eAAI,MAAM,KAAK,mBAAmB,KAAK,OAAO,OAAO,sBAAsB,CAAC,KAC1E,KAAK,OAAO,iBAAiB,EAAE,kBAC7B,KAAK,OAAO,QAAQ,4BACpB,KAAK,OAAO,QAAQ,sBACvB;AACD,eAAK,yBAAyB;AAAA,QAC/B;AACA,eAAO;AAAA,MACR;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA,EAQA,2BAA2B;AAC1B,SAAK,gBAAgB,aAAa,KAAK,aAAa;AACpD,SAAK,cAAc;AAGnB,SAAK,0BAA0B;AAAA,EAChC;AACD;AAnJC;AAAA,EADC;AAAA,GAbW,aAcZ;AA4IA;AAAA,EADC;AAAA,GAzJW,aA0JZ;",
6
6
  "names": []
7
7
  }
@@ -74,8 +74,7 @@ class FocusManager {
74
74
  handleKeyDown(keyEvent) {
75
75
  const container = this.editor.getContainer();
76
76
  const activeEl = container.ownerDocument.activeElement;
77
- if (this.editor.isIn("select.editing_shape") && !activeEl?.closest(".tlui-contextual-toolbar"))
78
- return;
77
+ if (this.editor.getEditingShapeId() && !activeEl?.closest(".tlui-contextual-toolbar")) return;
79
78
  if (activeEl === container && this.editor.getSelectedShapeIds().length > 0) return;
80
79
  if (["Tab", "ArrowUp", "ArrowDown"].includes(keyEvent.key)) {
81
80
  container.classList.remove("tl-container__no-focus-ring");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/editor/managers/FocusManager/FocusManager.ts"],
4
- "sourcesContent": ["import { bind } from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\n\n/**\n * A manager for ensuring correct focus across the editor.\n * It will listen for changes in the instance state to make sure the\n * container is focused when the editor is focused.\n * Also, it will make sure that the focus is on things like text\n * labels when the editor is in editing mode.\n *\n * @internal\n */\nexport class FocusManager {\n\tprivate disposeSideEffectListener?: () => void\n\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tautoFocus?: boolean\n\t) {\n\t\tthis.disposeSideEffectListener = editor.sideEffects.registerAfterChangeHandler(\n\t\t\t'instance',\n\t\t\t(prev, next) => {\n\t\t\t\tif (prev.isFocused !== next.isFocused) {\n\t\t\t\t\tthis.updateContainerClass()\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\n\t\tconst currentFocusState = editor.getInstanceState().isFocused\n\t\tif (autoFocus !== currentFocusState) {\n\t\t\teditor.updateInstanceState({ isFocused: !!autoFocus })\n\t\t}\n\t\tthis.updateContainerClass()\n\n\t\tconst body = editor.getContainerDocument().body\n\t\tbody.addEventListener('keydown', this.handleKeyDown)\n\t\tbody.addEventListener('mousedown', this.handleMouseDown)\n\t}\n\n\t/**\n\t * The editor's focus state and the container's focus state\n\t * are not necessarily always in sync. For that reason we\n\t * can't rely on the css `:focus` or `:focus-within` selectors to style the\n\t * editor when it is in focus.\n\t *\n\t * For that reason we synchronize the editor's focus state with a\n\t * special class on the container: tl-container__focused\n\t */\n\tprivate updateContainerClass() {\n\t\tconst container = this.editor.getContainer()\n\t\tconst instanceState = this.editor.getInstanceState()\n\n\t\tif (instanceState.isFocused) {\n\t\t\tcontainer.classList.add('tl-container__focused')\n\t\t} else {\n\t\t\tcontainer.classList.remove('tl-container__focused')\n\t\t}\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\t@bind private handleKeyDown(keyEvent: KeyboardEvent) {\n\t\tconst container = this.editor.getContainer()\n\t\tconst activeEl = container.ownerDocument.activeElement\n\t\t// Edit mode should remove the focus ring, however if the active element's\n\t\t// parent is the contextual toolbar, then allow it.\n\t\tif (this.editor.isIn('select.editing_shape') && !activeEl?.closest('.tlui-contextual-toolbar'))\n\t\t\treturn\n\t\tif (activeEl === container && this.editor.getSelectedShapeIds().length > 0) return\n\t\tif (['Tab', 'ArrowUp', 'ArrowDown'].includes(keyEvent.key)) {\n\t\t\tcontainer.classList.remove('tl-container__no-focus-ring')\n\t\t}\n\t}\n\n\t@bind private handleMouseDown() {\n\t\tconst container = this.editor.getContainer()\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\tfocus() {\n\t\tthis.editor.getContainer().focus()\n\t}\n\n\tblur({ blurContainer = true } = {}) {\n\t\tthis.editor.complete() // stop any interaction\n\t\tif (blurContainer) this.editor.getContainer().blur() // blur the container\n\t}\n\n\tdispose() {\n\t\tconst body = this.editor.getContainerDocument().body\n\t\tbody.removeEventListener('keydown', this.handleKeyDown)\n\t\tbody.removeEventListener('mousedown', this.handleMouseDown)\n\t\tthis.disposeSideEffectListener?.()\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqB;AAYd,MAAM,aAAa;AAAA,EAGzB,YACQ,QACP,WACC;AAFM;AAGP,SAAK,4BAA4B,OAAO,YAAY;AAAA,MACnD;AAAA,MACA,CAAC,MAAM,SAAS;AACf,YAAI,KAAK,cAAc,KAAK,WAAW;AACtC,eAAK,qBAAqB;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAEA,UAAM,oBAAoB,OAAO,iBAAiB,EAAE;AACpD,QAAI,cAAc,mBAAmB;AACpC,aAAO,oBAAoB,EAAE,WAAW,CAAC,CAAC,UAAU,CAAC;AAAA,IACtD;AACA,SAAK,qBAAqB;AAE1B,UAAM,OAAO,OAAO,qBAAqB,EAAE;AAC3C,SAAK,iBAAiB,WAAW,KAAK,aAAa;AACnD,SAAK,iBAAiB,aAAa,KAAK,eAAe;AAAA,EACxD;AAAA,EArBQ;AAAA,EAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmCA,uBAAuB;AAC9B,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,gBAAgB,KAAK,OAAO,iBAAiB;AAEnD,QAAI,cAAc,WAAW;AAC5B,gBAAU,UAAU,IAAI,uBAAuB;AAAA,IAChD,OAAO;AACN,gBAAU,UAAU,OAAO,uBAAuB;AAAA,IACnD;AACA,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEc,cAAc,UAAyB;AACpD,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,WAAW,UAAU,cAAc;AAGzC,QAAI,KAAK,OAAO,KAAK,sBAAsB,KAAK,CAAC,UAAU,QAAQ,0BAA0B;AAC5F;AACD,QAAI,aAAa,aAAa,KAAK,OAAO,oBAAoB,EAAE,SAAS,EAAG;AAC5E,QAAI,CAAC,OAAO,WAAW,WAAW,EAAE,SAAS,SAAS,GAAG,GAAG;AAC3D,gBAAU,UAAU,OAAO,6BAA6B;AAAA,IACzD;AAAA,EACD;AAAA,EAEc,kBAAkB;AAC/B,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEA,QAAQ;AACP,SAAK,OAAO,aAAa,EAAE,MAAM;AAAA,EAClC;AAAA,EAEA,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC,GAAG;AACnC,SAAK,OAAO,SAAS;AACrB,QAAI,cAAe,MAAK,OAAO,aAAa,EAAE,KAAK;AAAA,EACpD;AAAA,EAEA,UAAU;AACT,UAAM,OAAO,KAAK,OAAO,qBAAqB,EAAE;AAChD,SAAK,oBAAoB,WAAW,KAAK,aAAa;AACtD,SAAK,oBAAoB,aAAa,KAAK,eAAe;AAC1D,SAAK,4BAA4B;AAAA,EAClC;AACD;AAjCe;AAAA,EAAb;AAAA,GAhDW,aAgDE;AAaA;AAAA,EAAb;AAAA,GA7DW,aA6DE;",
4
+ "sourcesContent": ["import { bind } from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\n\n/**\n * A manager for ensuring correct focus across the editor.\n * It will listen for changes in the instance state to make sure the\n * container is focused when the editor is focused.\n * Also, it will make sure that the focus is on things like text\n * labels when the editor is in editing mode.\n *\n * @internal\n */\nexport class FocusManager {\n\tprivate disposeSideEffectListener?: () => void\n\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tautoFocus?: boolean\n\t) {\n\t\tthis.disposeSideEffectListener = editor.sideEffects.registerAfterChangeHandler(\n\t\t\t'instance',\n\t\t\t(prev, next) => {\n\t\t\t\tif (prev.isFocused !== next.isFocused) {\n\t\t\t\t\tthis.updateContainerClass()\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\n\t\tconst currentFocusState = editor.getInstanceState().isFocused\n\t\tif (autoFocus !== currentFocusState) {\n\t\t\teditor.updateInstanceState({ isFocused: !!autoFocus })\n\t\t}\n\t\tthis.updateContainerClass()\n\n\t\tconst body = editor.getContainerDocument().body\n\t\tbody.addEventListener('keydown', this.handleKeyDown)\n\t\tbody.addEventListener('mousedown', this.handleMouseDown)\n\t}\n\n\t/**\n\t * The editor's focus state and the container's focus state\n\t * are not necessarily always in sync. For that reason we\n\t * can't rely on the css `:focus` or `:focus-within` selectors to style the\n\t * editor when it is in focus.\n\t *\n\t * For that reason we synchronize the editor's focus state with a\n\t * special class on the container: tl-container__focused\n\t */\n\tprivate updateContainerClass() {\n\t\tconst container = this.editor.getContainer()\n\t\tconst instanceState = this.editor.getInstanceState()\n\n\t\tif (instanceState.isFocused) {\n\t\t\tcontainer.classList.add('tl-container__focused')\n\t\t} else {\n\t\t\tcontainer.classList.remove('tl-container__focused')\n\t\t}\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\t@bind private handleKeyDown(keyEvent: KeyboardEvent) {\n\t\tconst container = this.editor.getContainer()\n\t\tconst activeEl = container.ownerDocument.activeElement\n\t\t// Edit mode should remove the focus ring, however if the active element's\n\t\t// parent is the contextual toolbar, then allow it.\n\t\tif (this.editor.getEditingShapeId() && !activeEl?.closest('.tlui-contextual-toolbar')) return\n\t\tif (activeEl === container && this.editor.getSelectedShapeIds().length > 0) return\n\t\tif (['Tab', 'ArrowUp', 'ArrowDown'].includes(keyEvent.key)) {\n\t\t\tcontainer.classList.remove('tl-container__no-focus-ring')\n\t\t}\n\t}\n\n\t@bind private handleMouseDown() {\n\t\tconst container = this.editor.getContainer()\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\tfocus() {\n\t\tthis.editor.getContainer().focus()\n\t}\n\n\tblur({ blurContainer = true } = {}) {\n\t\tthis.editor.complete() // stop any interaction\n\t\tif (blurContainer) this.editor.getContainer().blur() // blur the container\n\t}\n\n\tdispose() {\n\t\tconst body = this.editor.getContainerDocument().body\n\t\tbody.removeEventListener('keydown', this.handleKeyDown)\n\t\tbody.removeEventListener('mousedown', this.handleMouseDown)\n\t\tthis.disposeSideEffectListener?.()\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqB;AAYd,MAAM,aAAa;AAAA,EAGzB,YACQ,QACP,WACC;AAFM;AAGP,SAAK,4BAA4B,OAAO,YAAY;AAAA,MACnD;AAAA,MACA,CAAC,MAAM,SAAS;AACf,YAAI,KAAK,cAAc,KAAK,WAAW;AACtC,eAAK,qBAAqB;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAEA,UAAM,oBAAoB,OAAO,iBAAiB,EAAE;AACpD,QAAI,cAAc,mBAAmB;AACpC,aAAO,oBAAoB,EAAE,WAAW,CAAC,CAAC,UAAU,CAAC;AAAA,IACtD;AACA,SAAK,qBAAqB;AAE1B,UAAM,OAAO,OAAO,qBAAqB,EAAE;AAC3C,SAAK,iBAAiB,WAAW,KAAK,aAAa;AACnD,SAAK,iBAAiB,aAAa,KAAK,eAAe;AAAA,EACxD;AAAA,EArBQ;AAAA,EAHA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmCA,uBAAuB;AAC9B,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,gBAAgB,KAAK,OAAO,iBAAiB;AAEnD,QAAI,cAAc,WAAW;AAC5B,gBAAU,UAAU,IAAI,uBAAuB;AAAA,IAChD,OAAO;AACN,gBAAU,UAAU,OAAO,uBAAuB;AAAA,IACnD;AACA,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEc,cAAc,UAAyB;AACpD,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,WAAW,UAAU,cAAc;AAGzC,QAAI,KAAK,OAAO,kBAAkB,KAAK,CAAC,UAAU,QAAQ,0BAA0B,EAAG;AACvF,QAAI,aAAa,aAAa,KAAK,OAAO,oBAAoB,EAAE,SAAS,EAAG;AAC5E,QAAI,CAAC,OAAO,WAAW,WAAW,EAAE,SAAS,SAAS,GAAG,GAAG;AAC3D,gBAAU,UAAU,OAAO,6BAA6B;AAAA,IACzD;AAAA,EACD;AAAA,EAEc,kBAAkB;AAC/B,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEA,QAAQ;AACP,SAAK,OAAO,aAAa,EAAE,MAAM;AAAA,EAClC;AAAA,EAEA,KAAK,EAAE,gBAAgB,KAAK,IAAI,CAAC,GAAG;AACnC,SAAK,OAAO,SAAS;AACrB,QAAI,cAAe,MAAK,OAAO,aAAa,EAAE,KAAK;AAAA,EACpD;AAAA,EAEA,UAAU;AACT,UAAM,OAAO,KAAK,OAAO,qBAAqB,EAAE;AAChD,SAAK,oBAAoB,WAAW,KAAK,aAAa;AACtD,SAAK,oBAAoB,aAAa,KAAK,eAAe;AAC1D,SAAK,4BAA4B;AAAA,EAClC;AACD;AAhCe;AAAA,EAAb;AAAA,GAhDW,aAgDE;AAYA;AAAA,EAAb;AAAA,GA5DW,aA4DE;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/editor/tools/StateNode.ts"],
4
- "sourcesContent": ["import { Atom, Computed, atom, computed } from '@tldraw/state'\nimport { PerformanceTracker } from '@tldraw/utils'\nimport { debugFlags } from '../../utils/debug-flags'\nimport type { Editor } from '../Editor'\nimport {\n\tEVENT_NAME_MAP,\n\tTLCancelEventInfo,\n\tTLClickEventInfo,\n\tTLCompleteEventInfo,\n\tTLEventHandlers,\n\tTLEventInfo,\n\tTLInterruptEventInfo,\n\tTLKeyboardEventInfo,\n\tTLPinchEventInfo,\n\tTLPointerEventInfo,\n\tTLTickEventInfo,\n\tTLWheelEventInfo,\n} from '../types/event-types'\n\n/** @public */\nexport interface TLStateNodeConstructor {\n\tnew (editor: Editor, parent?: StateNode): StateNode\n\tid: string\n\tinitial?: string\n\tchildren?(): TLStateNodeConstructor[]\n\tisLockable: boolean\n\tuseCoalescedEvents: boolean\n\ttrackPerformance: boolean\n}\n\n/** @public */\nexport abstract class StateNode implements Partial<TLEventHandlers> {\n\tperformanceTracker: PerformanceTracker\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tparent?: StateNode\n\t) {\n\t\tconst { id, children, initial, isLockable, useCoalescedEvents } = this\n\t\t\t.constructor as TLStateNodeConstructor\n\n\t\tthis.id = id\n\t\tthis._isActive = atom<boolean>('toolIsActive' + this.id, false)\n\t\tthis._current = atom<StateNode | undefined>('toolState' + this.id, undefined)\n\n\t\tthis._path = computed('toolPath' + this.id, () => {\n\t\t\tconst current = this.getCurrent()\n\t\t\treturn this.id + (current ? `.${current.getPath()}` : '')\n\t\t})\n\n\t\tthis.parent = parent ?? ({} as any)\n\n\t\tif (parent) {\n\t\t\tif (children && initial) {\n\t\t\t\tthis.type = 'branch'\n\t\t\t\tthis.initial = initial\n\t\t\t\tthis.children = Object.fromEntries(\n\t\t\t\t\tchildren().map((Ctor) => [Ctor.id, new Ctor(this.editor, this)])\n\t\t\t\t)\n\t\t\t\tthis._current.set(this.children[this.initial])\n\t\t\t} else {\n\t\t\t\tthis.type = 'leaf'\n\t\t\t}\n\t\t} else {\n\t\t\tthis.type = 'root'\n\n\t\t\tif (children && initial) {\n\t\t\t\tthis.initial = initial\n\t\t\t\tthis.children = Object.fromEntries(\n\t\t\t\t\tchildren().map((Ctor) => [Ctor.id, new Ctor(this.editor, this)])\n\t\t\t\t)\n\t\t\t\tthis._current.set(this.children[this.initial])\n\t\t\t}\n\t\t}\n\t\tthis.isLockable = isLockable\n\t\tthis.useCoalescedEvents = useCoalescedEvents\n\t\tthis.performanceTracker = new PerformanceTracker()\n\t}\n\n\tstatic id: string\n\tstatic initial?: string\n\tstatic children?: () => TLStateNodeConstructor[]\n\tstatic isLockable = true\n\tstatic useCoalescedEvents = false\n\t/** Set to `true` in subclasses to emit interaction-start/end performance events when this state is entered/exited. */\n\tstatic trackPerformance = false\n\n\tid: string\n\ttype: 'branch' | 'leaf' | 'root'\n\tshapeType?: string\n\tinitial?: string\n\tchildren?: Record<string, StateNode>\n\tisLockable: boolean\n\tuseCoalescedEvents: boolean\n\tparent: StateNode\n\n\t/**\n\t * This node's path of active state nodes\n\t *\n\t * @public\n\t */\n\tgetPath() {\n\t\treturn this._path.get()\n\t}\n\t_path: Computed<string>\n\n\t/**\n\t * This node's current active child node, if any.\n\t *\n\t * @public\n\t */\n\tgetCurrent() {\n\t\treturn this._current.get()\n\t}\n\tprivate _current: Atom<StateNode | undefined>\n\n\t/**\n\t * Whether this node is active.\n\t *\n\t * @public\n\t */\n\tgetIsActive() {\n\t\treturn this._isActive.get()\n\t}\n\tprivate _isActive: Atom<boolean>\n\n\t/**\n\t * Transition to a new active child state node.\n\t *\n\t * @example\n\t * ```ts\n\t * parentState.transition('childStateA')\n\t * parentState.transition('childStateB', { myData: 4 })\n\t *```\n\t *\n\t * @param id - The id of the child state node to transition to.\n\t * @param info - Any data to pass to the `onEnter` and `onExit` handlers.\n\t *\n\t * @public\n\t */\n\ttransition(id: string, info: any = {}) {\n\t\tconst path = id.split('.')\n\n\t\tlet currState = this as StateNode\n\n\t\tfor (let i = 0; i < path.length; i++) {\n\t\t\tconst id = path[i]\n\t\t\tconst prevChildState = currState.getCurrent()\n\t\t\tconst nextChildState = currState.children?.[id]\n\n\t\t\tif (!nextChildState) {\n\t\t\t\tthrow Error(`${currState.id} - no child state exists with the id ${id}.`)\n\t\t\t}\n\n\t\t\tif (prevChildState?.id !== nextChildState.id) {\n\t\t\t\tprevChildState?.exit(info, id)\n\t\t\t\tcurrState._current.set(nextChildState)\n\t\t\t\tnextChildState.enter(info, prevChildState?.id || 'initial')\n\t\t\t\tif (!nextChildState.getIsActive()) break\n\t\t\t}\n\n\t\t\tcurrState = nextChildState\n\t\t}\n\n\t\treturn this\n\t}\n\n\thandleEvent(info: Exclude<TLEventInfo, TLPinchEventInfo>) {\n\t\tconst cbName = EVENT_NAME_MAP[info.name]\n\t\tconst currentActiveChild = this._current.__unsafe__getWithoutCapture()\n\n\t\tthis[cbName]?.(info as any)\n\t\tif (\n\t\t\tthis._isActive.__unsafe__getWithoutCapture() &&\n\t\t\tcurrentActiveChild &&\n\t\t\tcurrentActiveChild === this._current.__unsafe__getWithoutCapture()\n\t\t) {\n\t\t\tcurrentActiveChild.handleEvent(info)\n\t\t}\n\t}\n\n\t// todo: move this logic into transition\n\tenter(info: any, from: string) {\n\t\tconst track = (this.constructor as TLStateNodeConstructor).trackPerformance\n\t\tif (track) {\n\t\t\tif (debugFlags.measurePerformance.get()) {\n\t\t\t\tthis.performanceTracker.start(this.id)\n\t\t\t}\n\t\t\tthis.editor.performance._notifyInteractionStart(this.id, this.getPath())\n\t\t}\n\n\t\tthis._isActive.set(true)\n\t\tthis.onEnter?.(info, from)\n\n\t\tif (this.children && this.initial && this.getIsActive()) {\n\t\t\tconst initial = this.children[this.initial]\n\t\t\tthis._current.set(initial)\n\t\t\tinitial.enter(info, from)\n\t\t}\n\t}\n\n\t// todo: move this logic into transition\n\texit(info: any, to: string) {\n\t\tconst track = (this.constructor as TLStateNodeConstructor).trackPerformance\n\t\tif (track) {\n\t\t\tif (debugFlags.measurePerformance.get() && this.performanceTracker.isStarted()) {\n\t\t\t\tthis.performanceTracker.stop()\n\t\t\t}\n\t\t\tthis.editor.performance._notifyInteractionEnd()\n\t\t}\n\n\t\tthis._isActive.set(false)\n\t\tthis.onExit?.(info, to)\n\n\t\tif (!this.getIsActive()) {\n\t\t\tthis.getCurrent()?.exit(info, to)\n\t\t}\n\t}\n\n\t/**\n\t * This is a hack / escape hatch that will tell the editor to\n\t * report a different state as active (in `getCurrentToolId()`) when\n\t * this state is active. This is usually used when a tool transitions\n\t * to a child of a different state for a certain interaction and then\n\t * returns to the original tool when that interaction completes; and\n\t * where we would want to show the original tool as active in the UI.\n\t *\n\t * @public\n\t */\n\t_currentToolIdMask = atom('curent tool id mask', undefined as string | undefined)\n\n\tgetCurrentToolIdMask() {\n\t\treturn this._currentToolIdMask.get()\n\t}\n\n\tsetCurrentToolIdMask(id: string | undefined) {\n\t\tthis._currentToolIdMask.set(id)\n\t}\n\n\t/**\n\t * Add a child node to this state node.\n\t *\n\t * @public\n\t */\n\taddChild(childConstructor: TLStateNodeConstructor): this {\n\t\tif (this.type === 'leaf') {\n\t\t\tthrow new Error('StateNode.addChild: cannot add child to a leaf node')\n\t\t}\n\n\t\t// Initialize children if it's undefined (for root nodes without static children)\n\t\tif (!this.children) {\n\t\t\tthis.children = {}\n\t\t}\n\n\t\tconst child = new childConstructor(this.editor, this)\n\n\t\t// Check if a child with this ID already exists\n\t\tif (this.children[child.id]) {\n\t\t\tthrow new Error(`StateNode.addChild: a child with id '${child.id}' already exists`)\n\t\t}\n\n\t\tthis.children[child.id] = child\n\t\treturn this\n\t}\n\n\tonWheel?(info: TLWheelEventInfo): void\n\tonPointerDown?(info: TLPointerEventInfo): void\n\tonPointerMove?(info: TLPointerEventInfo): void\n\tonLongPress?(info: TLPointerEventInfo): void\n\tonPointerUp?(info: TLPointerEventInfo): void\n\tonDoubleClick?(info: TLClickEventInfo): void\n\tonTripleClick?(info: TLClickEventInfo): void\n\tonQuadrupleClick?(info: TLClickEventInfo): void\n\tonRightClick?(info: TLPointerEventInfo): void\n\tonMiddleClick?(info: TLPointerEventInfo): void\n\tonKeyDown?(info: TLKeyboardEventInfo): void\n\tonKeyUp?(info: TLKeyboardEventInfo): void\n\tonKeyRepeat?(info: TLKeyboardEventInfo): void\n\tonCancel?(info: TLCancelEventInfo): void\n\tonComplete?(info: TLCompleteEventInfo): void\n\tonInterrupt?(info: TLInterruptEventInfo): void\n\tonTick?(info: TLTickEventInfo): void\n\n\tonEnter?(info: any, from: string): void\n\tonExit?(info: any, to: string): void\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Atom, Computed, atom, computed } from '@tldraw/state'\nimport { PerformanceTracker } from '@tldraw/utils'\nimport { debugFlags } from '../../utils/debug-flags'\nimport type { Editor } from '../Editor'\nimport {\n\tEVENT_NAME_MAP,\n\tTLCancelEventInfo,\n\tTLClickEventInfo,\n\tTLCompleteEventInfo,\n\tTLEventHandlers,\n\tTLEventInfo,\n\tTLInterruptEventInfo,\n\tTLKeyboardEventInfo,\n\tTLPinchEventInfo,\n\tTLPointerEventInfo,\n\tTLTickEventInfo,\n\tTLWheelEventInfo,\n} from '../types/event-types'\n\n/** @public */\nexport interface TLStateNodeConstructor {\n\tnew (editor: Editor, parent?: StateNode): StateNode\n\tid: string\n\tinitial?: string\n\tchildren?(): TLStateNodeConstructor[]\n\tisLockable: boolean\n\tuseCoalescedEvents: boolean\n\ttrackPerformance: boolean\n}\n\n/** @public */\nexport abstract class StateNode implements Partial<TLEventHandlers> {\n\tperformanceTracker: PerformanceTracker\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tparent?: StateNode\n\t) {\n\t\tconst { id, children, initial, isLockable, useCoalescedEvents } = this\n\t\t\t.constructor as TLStateNodeConstructor\n\n\t\tthis.id = id\n\t\tthis._isActive = atom<boolean>('toolIsActive' + this.id, false)\n\t\tthis._current = atom<StateNode | undefined>('toolState' + this.id, undefined)\n\n\t\tthis._path = computed('toolPath' + this.id, () => {\n\t\t\tconst current = this.getCurrent()\n\t\t\treturn this.id + (current ? `.${current.getPath()}` : '')\n\t\t})\n\n\t\tthis.parent = parent ?? ({} as any)\n\n\t\tif (parent) {\n\t\t\tif (children && initial) {\n\t\t\t\tthis.type = 'branch'\n\t\t\t\tthis.initial = initial\n\t\t\t\tthis.children = Object.fromEntries(\n\t\t\t\t\tchildren().map((Ctor) => [Ctor.id, new Ctor(this.editor, this)])\n\t\t\t\t)\n\t\t\t\tthis._current.set(this.children[this.initial])\n\t\t\t} else {\n\t\t\t\tthis.type = 'leaf'\n\t\t\t}\n\t\t} else {\n\t\t\tthis.type = 'root'\n\n\t\t\tif (children && initial) {\n\t\t\t\tthis.initial = initial\n\t\t\t\tthis.children = Object.fromEntries(\n\t\t\t\t\tchildren().map((Ctor) => [Ctor.id, new Ctor(this.editor, this)])\n\t\t\t\t)\n\t\t\t\tthis._current.set(this.children[this.initial])\n\t\t\t}\n\t\t}\n\t\tthis.isLockable = isLockable\n\t\tthis.useCoalescedEvents = useCoalescedEvents\n\t\tthis.performanceTracker = new PerformanceTracker()\n\t}\n\n\tstatic id: string\n\tstatic initial?: string\n\tstatic children?: () => TLStateNodeConstructor[]\n\tstatic isLockable = true\n\tstatic useCoalescedEvents = false\n\t/** Set to `true` in subclasses to emit interaction-start/end performance events when this state is entered/exited. */\n\tstatic trackPerformance = false\n\n\tid: string\n\ttype: 'branch' | 'leaf' | 'root'\n\tshapeType?: string\n\tinitial?: string\n\tchildren?: Record<string, StateNode>\n\tisLockable: boolean\n\tuseCoalescedEvents: boolean\n\tparent: StateNode\n\n\t/**\n\t * This node's path of active state nodes\n\t *\n\t * @public\n\t */\n\tgetPath() {\n\t\treturn this._path.get()\n\t}\n\t_path: Computed<string>\n\n\t/**\n\t * This node's current active child node, if any.\n\t *\n\t * @public\n\t */\n\tgetCurrent() {\n\t\treturn this._current.get()\n\t}\n\tprivate _current: Atom<StateNode | undefined>\n\n\t/**\n\t * Whether this node is active.\n\t *\n\t * @public\n\t */\n\tgetIsActive() {\n\t\treturn this._isActive.get()\n\t}\n\tprivate _isActive: Atom<boolean>\n\n\t/**\n\t * Transition to a new active child state node.\n\t *\n\t * @example\n\t * ```ts\n\t * parentState.transition('childStateA')\n\t * parentState.transition('childStateB', { myData: 4 })\n\t *```\n\t *\n\t * @param id - The id of the child state node to transition to.\n\t * @param info - Any data to pass to the `onEnter` and `onExit` handlers.\n\t *\n\t * @public\n\t */\n\ttransition(id: string, info: any = {}) {\n\t\tconst path = id.split('.')\n\n\t\tlet currState = this as StateNode\n\n\t\tfor (let i = 0; i < path.length; i++) {\n\t\t\tconst id = path[i]\n\t\t\tconst prevChildState = currState.getCurrent()\n\t\t\tconst nextChildState = currState.children?.[id]\n\n\t\t\tif (!nextChildState) {\n\t\t\t\tthrow Error(`${currState.id} - no child state exists with the id ${id}.`)\n\t\t\t}\n\n\t\t\tif (prevChildState?.id !== nextChildState.id) {\n\t\t\t\tprevChildState?.exit(info, id)\n\t\t\t\tcurrState._current.set(nextChildState)\n\t\t\t\tnextChildState.enter(info, prevChildState?.id || 'initial')\n\t\t\t\tif (!nextChildState.getIsActive()) break\n\t\t\t}\n\n\t\t\tcurrState = nextChildState\n\t\t}\n\n\t\treturn this\n\t}\n\n\thandleEvent(info: Exclude<TLEventInfo, TLPinchEventInfo>) {\n\t\tconst cbName = EVENT_NAME_MAP[info.name]\n\t\tconst currentActiveChild = this._current.__unsafe__getWithoutCapture()\n\n\t\tthis[cbName]?.(info as any)\n\t\tif (\n\t\t\tthis._isActive.__unsafe__getWithoutCapture() &&\n\t\t\tcurrentActiveChild &&\n\t\t\tcurrentActiveChild === this._current.__unsafe__getWithoutCapture()\n\t\t) {\n\t\t\tcurrentActiveChild.handleEvent(info)\n\t\t}\n\t}\n\n\t// todo: move this logic into transition\n\tenter(info: any, from: string) {\n\t\tconst track = (this.constructor as TLStateNodeConstructor).trackPerformance\n\t\tif (track) {\n\t\t\tif (debugFlags.measurePerformance.get()) {\n\t\t\t\tthis.performanceTracker.start(this.id)\n\t\t\t}\n\t\t\tthis.editor.performance._notifyInteractionStart(this.id, this.getPath())\n\t\t}\n\n\t\tthis._isActive.set(true)\n\t\tthis.onEnter?.(info, from)\n\n\t\tif (this.children && this.initial && this.getIsActive()) {\n\t\t\tconst initial = this.children[this.initial]\n\t\t\tthis._current.set(initial)\n\t\t\tinitial.enter(info, from)\n\t\t}\n\t}\n\n\t// todo: move this logic into transition\n\texit(info: any, to: string) {\n\t\tconst track = (this.constructor as TLStateNodeConstructor).trackPerformance\n\t\tif (track) {\n\t\t\tif (debugFlags.measurePerformance.get() && this.performanceTracker.isStarted()) {\n\t\t\t\tthis.performanceTracker.stop()\n\t\t\t}\n\t\t\tthis.editor.performance._notifyInteractionEnd()\n\t\t}\n\n\t\tthis._isActive.set(false)\n\t\tthis.onExit?.(info, to)\n\n\t\tif (!this.getIsActive()) {\n\t\t\tthis.getCurrent()?.exit(info, to)\n\t\t}\n\t}\n\n\t/**\n\t * This is a hack / escape hatch that will tell the editor to\n\t * report a different state as active (in `getCurrentToolId()`) when\n\t * this state is active. This is usually used when a tool transitions\n\t * to a child of a different state for a certain interaction and then\n\t * returns to the original tool when that interaction completes; and\n\t * where we would want to show the original tool as active in the UI.\n\t *\n\t * @public\n\t */\n\t_currentToolIdMask = atom('curent tool id mask', undefined as string | undefined)\n\n\tgetCurrentToolIdMask() {\n\t\treturn this._currentToolIdMask.get()\n\t}\n\n\tsetCurrentToolIdMask(id: string | undefined) {\n\t\tthis._currentToolIdMask.set(id)\n\t}\n\n\t/**\n\t * Add a child node to this state node.\n\t *\n\t * @public\n\t */\n\taddChild(childConstructor: TLStateNodeConstructor): this {\n\t\tif (this.type === 'leaf') {\n\t\t\tthrow new Error('StateNode.addChild: cannot add child to a leaf node')\n\t\t}\n\n\t\t// Initialize children if it's undefined (for root nodes without static children)\n\t\tif (!this.children) {\n\t\t\tthis.children = {}\n\t\t}\n\n\t\tconst child = new childConstructor(this.editor, this)\n\n\t\t// Check if a child with this ID already exists\n\t\tif (this.children[child.id]) {\n\t\t\tthrow new Error(`StateNode.addChild: a child with id '${child.id}' already exists`)\n\t\t}\n\n\t\tthis.children[child.id] = child\n\t\treturn this\n\t}\n\n\tonWheel?(info: TLWheelEventInfo): void\n\tonPointerDown?(info: TLPointerEventInfo): void\n\tonPointerMove?(info: TLPointerEventInfo): void\n\tonLongPress?(info: TLPointerEventInfo): void\n\tonPointerUp?(info: TLPointerEventInfo): void\n\tonDoubleClick?(info: TLClickEventInfo): void\n\tonRightClick?(info: TLPointerEventInfo): void\n\tonMiddleClick?(info: TLPointerEventInfo): void\n\tonKeyDown?(info: TLKeyboardEventInfo): void\n\tonKeyUp?(info: TLKeyboardEventInfo): void\n\tonKeyRepeat?(info: TLKeyboardEventInfo): void\n\tonCancel?(info: TLCancelEventInfo): void\n\tonComplete?(info: TLCompleteEventInfo): void\n\tonInterrupt?(info: TLInterruptEventInfo): void\n\tonTick?(info: TLTickEventInfo): void\n\n\tonEnter?(info: any, from: string): void\n\tonExit?(info: any, to: string): void\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["id"]
7
7
  }
@@ -36,8 +36,6 @@ const EVENT_NAME_MAP = {
36
36
  complete: "onComplete",
37
37
  interrupt: "onInterrupt",
38
38
  double_click: "onDoubleClick",
39
- triple_click: "onTripleClick",
40
- quadruple_click: "onQuadrupleClick",
41
39
  tick: "onTick"
42
40
  };
43
41
  //# sourceMappingURL=event-types.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/editor/types/event-types.ts"],
4
- "sourcesContent": ["import { TLHandle, TLShape, VecModel } from '@tldraw/tlschema'\nimport { VecLike } from '../../primitives/Vec'\nimport { TLOverlay } from '../overlays/OverlayUtil'\nimport { TLSelectionHandle } from './selection-types'\n\n/** @public */\nexport type UiEventType = 'pointer' | 'click' | 'keyboard' | 'wheel' | 'pinch' | 'zoom'\n\n/** @public */\nexport type TLPointerEventTarget =\n\t| { target: 'canvas'; shape?: undefined }\n\t| { target: 'selection'; handle?: TLSelectionHandle; shape?: undefined }\n\t| { target: 'shape'; shape: TLShape }\n\t| { target: 'handle'; shape: TLShape; handle: TLHandle }\n\t| { target: 'overlay'; overlay: TLOverlay; shape?: undefined }\n\n/** @public */\nexport type TLPointerEventName =\n\t| 'pointer_down'\n\t| 'pointer_move'\n\t| 'long_press'\n\t| 'pointer_up'\n\t| 'right_click'\n\t| 'middle_click'\n\n/** @public */\nexport type TLCLickEventName = 'double_click' | 'triple_click' | 'quadruple_click'\n\n/** @public */\nexport type TLPinchEventName = 'pinch_start' | 'pinch' | 'pinch_end'\n\n/** @public */\nexport type TLKeyboardEventName = 'key_down' | 'key_up' | 'key_repeat'\n\n/** @public */\nexport type TLEventName =\n\t| TLPointerEventName\n\t| TLCLickEventName\n\t| TLPinchEventName\n\t| TLKeyboardEventName\n\t| 'wheel'\n\t| 'cancel'\n\t| 'complete'\n\t| 'interrupt'\n\t| 'tick'\n\n/** @public */\nexport interface TLBaseEventInfo {\n\ttype: UiEventType\n\tshiftKey: boolean\n\taltKey: boolean\n\tctrlKey: boolean\n\tmetaKey: boolean\n\taccelKey: boolean\n}\n\n/** @public */\nexport type TLPointerEventInfo = TLBaseEventInfo & {\n\ttype: 'pointer'\n\tname: TLPointerEventName\n\t// The pointer position in client space, i.e. clientX / clientY\n\tpoint: VecLike\n\tpointerId: number\n\tbutton: number\n\tisPen: boolean\n} & TLPointerEventTarget\n\n/** @public */\nexport type TLClickEventInfo = TLBaseEventInfo & {\n\ttype: 'click'\n\tname: TLCLickEventName\n\tpoint: VecLike\n\tpointerId: number\n\tbutton: number\n\tphase: 'down' | 'up' | 'settle'\n} & TLPointerEventTarget\n\n/** @public */\nexport type TLKeyboardEventInfo = TLBaseEventInfo & {\n\ttype: 'keyboard'\n\tname: TLKeyboardEventName\n\tkey: string\n\tcode: string\n}\n\n/** @public */\nexport type TLPinchEventInfo = TLBaseEventInfo & {\n\ttype: 'pinch'\n\tname: TLPinchEventName\n\tpoint: VecModel\n\tdelta: VecModel\n}\n\n/** @public */\nexport type TLWheelEventInfo = TLBaseEventInfo & {\n\ttype: 'wheel'\n\tname: 'wheel'\n\tdelta: VecModel\n\tpoint: VecModel\n}\n\n/** @public */\nexport interface TLCancelEventInfo {\n\ttype: 'misc'\n\tname: 'cancel'\n}\n/** @public */\nexport interface TLCompleteEventInfo {\n\ttype: 'misc'\n\tname: 'complete'\n}\n/** @public */\nexport interface TLInterruptEventInfo {\n\ttype: 'misc'\n\tname: 'interrupt'\n}\n/** @public */\nexport interface TLTickEventInfo {\n\ttype: 'misc'\n\tname: 'tick'\n\telapsed: number\n}\n\n/** @public */\nexport type TLEventInfo =\n\t| TLPointerEventInfo\n\t| TLClickEventInfo\n\t| TLKeyboardEventInfo\n\t| TLPinchEventInfo\n\t| TLWheelEventInfo\n\t| TLCancelEventInfo\n\t| TLCompleteEventInfo\n\t| TLInterruptEventInfo\n\t| TLTickEventInfo\n\n/** @public */\nexport type TLPointerEvent = (info: TLPointerEventInfo) => void\n/** @public */\nexport type TLClickEvent = (info: TLClickEventInfo) => void\n/** @public */\nexport type TLKeyboardEvent = (info: TLKeyboardEventInfo) => void\n/** @public */\nexport type TLPinchEvent = (info: TLPinchEventInfo) => void\n/** @public */\nexport type TLWheelEvent = (info: TLWheelEventInfo) => void\n/** @public */\nexport type TLCancelEvent = (info: TLCancelEventInfo) => void\n/** @public */\nexport type TLCompleteEvent = (info: TLCompleteEventInfo) => void\n/** @public */\nexport type TLInterruptEvent = (info: TLInterruptEventInfo) => void\n/** @public */\nexport type TLTickEvent = (info: TLTickEventInfo) => void\n\n/** @public */\nexport type UiEvent =\n\t| TLPointerEvent\n\t| TLClickEvent\n\t| TLKeyboardEvent\n\t| TLPinchEvent\n\t| TLCancelEvent\n\t| TLCompleteEvent\n\n/** @public */\nexport type TLEnterEventHandler = (info: any, from: string) => void\n/** @public */\nexport type TLExitEventHandler = (info: any, to: string) => void\n\n/** @public */\nexport interface TLEventHandlers {\n\tonPointerDown: TLPointerEvent\n\tonPointerMove: TLPointerEvent\n\tonLongPress: TLPointerEvent\n\tonRightClick: TLPointerEvent\n\tonDoubleClick: TLClickEvent\n\tonTripleClick: TLClickEvent\n\tonQuadrupleClick: TLClickEvent\n\tonMiddleClick: TLPointerEvent\n\tonPointerUp: TLPointerEvent\n\tonKeyDown: TLKeyboardEvent\n\tonKeyUp: TLKeyboardEvent\n\tonKeyRepeat: TLKeyboardEvent\n\tonWheel: TLWheelEvent\n\tonCancel: TLCancelEvent\n\tonComplete: TLCompleteEvent\n\tonInterrupt: TLInterruptEvent\n\tonTick: TLTickEvent\n}\n\n/** @public */\nexport const EVENT_NAME_MAP: Record<\n\tExclude<TLEventName, TLPinchEventName>,\n\tkeyof TLEventHandlers\n> = {\n\twheel: 'onWheel',\n\tpointer_down: 'onPointerDown',\n\tpointer_move: 'onPointerMove',\n\tlong_press: 'onLongPress',\n\tpointer_up: 'onPointerUp',\n\tright_click: 'onRightClick',\n\tmiddle_click: 'onMiddleClick',\n\tkey_down: 'onKeyDown',\n\tkey_up: 'onKeyUp',\n\tkey_repeat: 'onKeyRepeat',\n\tcancel: 'onCancel',\n\tcomplete: 'onComplete',\n\tinterrupt: 'onInterrupt',\n\tdouble_click: 'onDoubleClick',\n\ttriple_click: 'onTripleClick',\n\tquadruple_click: 'onQuadrupleClick',\n\ttick: 'onTick',\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA8LO,MAAM,iBAGT;AAAA,EACH,OAAO;AAAA,EACP,cAAc;AAAA,EACd,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,cAAc;AAAA,EACd,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc;AAAA,EACd,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,MAAM;AACP;",
4
+ "sourcesContent": ["import { TLHandle, TLShape, VecModel } from '@tldraw/tlschema'\nimport { VecLike } from '../../primitives/Vec'\nimport { TLOverlay } from '../overlays/OverlayUtil'\nimport { TLSelectionHandle } from './selection-types'\n\n/** @public */\nexport type UiEventType = 'pointer' | 'click' | 'keyboard' | 'wheel' | 'pinch' | 'zoom'\n\n/** @public */\nexport type TLPointerEventTarget =\n\t| { target: 'canvas'; shape?: undefined }\n\t| { target: 'selection'; handle?: TLSelectionHandle; shape?: undefined }\n\t| { target: 'shape'; shape: TLShape }\n\t| { target: 'handle'; shape: TLShape; handle: TLHandle }\n\t| { target: 'overlay'; overlay: TLOverlay; shape?: undefined }\n\n/** @public */\nexport type TLPointerEventName =\n\t| 'pointer_down'\n\t| 'pointer_move'\n\t| 'long_press'\n\t| 'pointer_up'\n\t| 'right_click'\n\t| 'middle_click'\n\n/** @public */\nexport type TLCLickEventName = 'double_click'\n\n/** @public */\nexport type TLPinchEventName = 'pinch_start' | 'pinch' | 'pinch_end'\n\n/** @public */\nexport type TLKeyboardEventName = 'key_down' | 'key_up' | 'key_repeat'\n\n/** @public */\nexport type TLEventName =\n\t| TLPointerEventName\n\t| TLCLickEventName\n\t| TLPinchEventName\n\t| TLKeyboardEventName\n\t| 'wheel'\n\t| 'cancel'\n\t| 'complete'\n\t| 'interrupt'\n\t| 'tick'\n\n/** @public */\nexport interface TLBaseEventInfo {\n\ttype: UiEventType\n\tshiftKey: boolean\n\taltKey: boolean\n\tctrlKey: boolean\n\tmetaKey: boolean\n\taccelKey: boolean\n}\n\n/** @public */\nexport type TLPointerEventInfo = TLBaseEventInfo & {\n\ttype: 'pointer'\n\tname: TLPointerEventName\n\t// The pointer position in client space, i.e. clientX / clientY\n\tpoint: VecLike\n\tpointerId: number\n\tbutton: number\n\tisPen: boolean\n} & TLPointerEventTarget\n\n/** @public */\nexport type TLClickEventInfo = TLBaseEventInfo & {\n\ttype: 'click'\n\tname: TLCLickEventName\n\tpoint: VecLike\n\tpointerId: number\n\tbutton: number\n\tphase: 'down' | 'up' | 'settle-down' | 'settle-up'\n} & TLPointerEventTarget\n\n/** @public */\nexport type TLKeyboardEventInfo = TLBaseEventInfo & {\n\ttype: 'keyboard'\n\tname: TLKeyboardEventName\n\tkey: string\n\tcode: string\n}\n\n/** @public */\nexport type TLPinchEventInfo = TLBaseEventInfo & {\n\ttype: 'pinch'\n\tname: TLPinchEventName\n\tpoint: VecModel\n\tdelta: VecModel\n}\n\n/** @public */\nexport type TLWheelEventInfo = TLBaseEventInfo & {\n\ttype: 'wheel'\n\tname: 'wheel'\n\tdelta: VecModel\n\tpoint: VecModel\n}\n\n/** @public */\nexport interface TLCancelEventInfo {\n\ttype: 'misc'\n\tname: 'cancel'\n}\n/** @public */\nexport interface TLCompleteEventInfo {\n\ttype: 'misc'\n\tname: 'complete'\n}\n/** @public */\nexport interface TLInterruptEventInfo {\n\ttype: 'misc'\n\tname: 'interrupt'\n}\n/** @public */\nexport interface TLTickEventInfo {\n\ttype: 'misc'\n\tname: 'tick'\n\telapsed: number\n}\n\n/** @public */\nexport type TLEventInfo =\n\t| TLPointerEventInfo\n\t| TLClickEventInfo\n\t| TLKeyboardEventInfo\n\t| TLPinchEventInfo\n\t| TLWheelEventInfo\n\t| TLCancelEventInfo\n\t| TLCompleteEventInfo\n\t| TLInterruptEventInfo\n\t| TLTickEventInfo\n\n/** @public */\nexport type TLPointerEvent = (info: TLPointerEventInfo) => void\n/** @public */\nexport type TLClickEvent = (info: TLClickEventInfo) => void\n/** @public */\nexport type TLKeyboardEvent = (info: TLKeyboardEventInfo) => void\n/** @public */\nexport type TLPinchEvent = (info: TLPinchEventInfo) => void\n/** @public */\nexport type TLWheelEvent = (info: TLWheelEventInfo) => void\n/** @public */\nexport type TLCancelEvent = (info: TLCancelEventInfo) => void\n/** @public */\nexport type TLCompleteEvent = (info: TLCompleteEventInfo) => void\n/** @public */\nexport type TLInterruptEvent = (info: TLInterruptEventInfo) => void\n/** @public */\nexport type TLTickEvent = (info: TLTickEventInfo) => void\n\n/** @public */\nexport type UiEvent =\n\t| TLPointerEvent\n\t| TLClickEvent\n\t| TLKeyboardEvent\n\t| TLPinchEvent\n\t| TLCancelEvent\n\t| TLCompleteEvent\n\n/** @public */\nexport type TLEnterEventHandler = (info: any, from: string) => void\n/** @public */\nexport type TLExitEventHandler = (info: any, to: string) => void\n\n/** @public */\nexport interface TLEventHandlers {\n\tonPointerDown: TLPointerEvent\n\tonPointerMove: TLPointerEvent\n\tonLongPress: TLPointerEvent\n\tonRightClick: TLPointerEvent\n\tonDoubleClick: TLClickEvent\n\tonMiddleClick: TLPointerEvent\n\tonPointerUp: TLPointerEvent\n\tonKeyDown: TLKeyboardEvent\n\tonKeyUp: TLKeyboardEvent\n\tonKeyRepeat: TLKeyboardEvent\n\tonWheel: TLWheelEvent\n\tonCancel: TLCancelEvent\n\tonComplete: TLCompleteEvent\n\tonInterrupt: TLInterruptEvent\n\tonTick: TLTickEvent\n}\n\n/** @public */\nexport const EVENT_NAME_MAP: Record<\n\tExclude<TLEventName, TLPinchEventName>,\n\tkeyof TLEventHandlers\n> = {\n\twheel: 'onWheel',\n\tpointer_down: 'onPointerDown',\n\tpointer_move: 'onPointerMove',\n\tlong_press: 'onLongPress',\n\tpointer_up: 'onPointerUp',\n\tright_click: 'onRightClick',\n\tmiddle_click: 'onMiddleClick',\n\tkey_down: 'onKeyDown',\n\tkey_up: 'onKeyUp',\n\tkey_repeat: 'onKeyRepeat',\n\tcancel: 'onCancel',\n\tcomplete: 'onComplete',\n\tinterrupt: 'onInterrupt',\n\tdouble_click: 'onDoubleClick',\n\ttick: 'onTick',\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4LO,MAAM,iBAGT;AAAA,EACH,OAAO;AAAA,EACP,cAAc;AAAA,EACd,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,cAAc;AAAA,EACd,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc;AAAA,EACd,MAAM;AACP;",
6
6
  "names": []
7
7
  }
@@ -22,10 +22,10 @@ __export(version_exports, {
22
22
  version: () => version
23
23
  });
24
24
  module.exports = __toCommonJS(version_exports);
25
- const version = "5.2.0-canary.fe03bcdddf34";
25
+ const version = "5.2.0-canary.ff23978d50f6";
26
26
  const publishDates = {
27
27
  major: "2026-05-06T16:28:18.473Z",
28
- minor: "2026-06-05T10:03:03.535Z",
29
- patch: "2026-06-05T10:03:03.535Z"
28
+ minor: "2026-06-05T12:02:54.232Z",
29
+ patch: "2026-06-05T12:02:54.232Z"
30
30
  };
31
31
  //# sourceMappingURL=version.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.2.0-canary.fe03bcdddf34'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-06-05T10:03:03.535Z',\n\tpatch: '2026-06-05T10:03:03.535Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.2.0-canary.ff23978d50f6'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-06-05T12:02:54.232Z',\n\tpatch: '2026-06-05T12:02:54.232Z',\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
@@ -746,6 +746,7 @@ export declare class ClickManager {
746
746
  private _clickTimeout?;
747
747
  private _clickScreenPoint?;
748
748
  private _previousScreenPoint?;
749
+ private _isPressingWhilePending;
749
750
  _getClickTimeout(state: TLClickState, id?: string): void;
750
751
  /* Excluded from this release type: _clickState */
751
752
  /**
@@ -7166,8 +7167,6 @@ export declare abstract class StateNode implements Partial<TLEventHandlers> {
7166
7167
  onLongPress?(info: TLPointerEventInfo): void;
7167
7168
  onPointerUp?(info: TLPointerEventInfo): void;
7168
7169
  onDoubleClick?(info: TLClickEventInfo): void;
7169
- onTripleClick?(info: TLClickEventInfo): void;
7170
- onQuadrupleClick?(info: TLClickEventInfo): void;
7171
7170
  onRightClick?(info: TLPointerEventInfo): void;
7172
7171
  onMiddleClick?(info: TLPointerEventInfo): void;
7173
7172
  onKeyDown?(info: TLKeyboardEventInfo): void;
@@ -7567,17 +7566,17 @@ export declare type TLClickEvent = (info: TLClickEventInfo) => void;
7567
7566
  export declare type TLClickEventInfo = TLBaseEventInfo & {
7568
7567
  button: number;
7569
7568
  name: TLCLickEventName;
7570
- phase: 'down' | 'settle' | 'up';
7569
+ phase: 'down' | 'settle-down' | 'settle-up' | 'up';
7571
7570
  point: VecLike;
7572
7571
  pointerId: number;
7573
7572
  type: 'click';
7574
7573
  } & TLPointerEventTarget;
7575
7574
 
7576
7575
  /** @public */
7577
- export declare type TLCLickEventName = 'double_click' | 'quadruple_click' | 'triple_click';
7576
+ export declare type TLCLickEventName = 'double_click';
7578
7577
 
7579
7578
  /** @public */
7580
- export declare type TLClickState = 'idle' | 'overflow' | 'pendingDouble' | 'pendingOverflow' | 'pendingQuadruple' | 'pendingTriple';
7579
+ export declare type TLClickState = 'idle' | 'overflow' | 'pendingDouble' | 'pendingOverflow';
7581
7580
 
7582
7581
  /**
7583
7582
  * Raw clipboard paste payload, before tldraw parses clipboard contents into {@link TLExternalContent}.
@@ -8357,8 +8356,6 @@ export declare interface TLEventHandlers {
8357
8356
  onLongPress: TLPointerEvent;
8358
8357
  onRightClick: TLPointerEvent;
8359
8358
  onDoubleClick: TLClickEvent;
8360
- onTripleClick: TLClickEvent;
8361
- onQuadrupleClick: TLClickEvent;
8362
8359
  onMiddleClick: TLPointerEvent;
8363
8360
  onPointerUp: TLPointerEvent;
8364
8361
  onKeyDown: TLKeyboardEvent;
@@ -300,7 +300,7 @@ import { LocalIndexedDb, Table } from "./lib/utils/sync/LocalIndexedDb.mjs";
300
300
  import { uniq } from "./lib/utils/uniq.mjs";
301
301
  registerTldrawLibraryVersion(
302
302
  "@tldraw/editor",
303
- "5.2.0-canary.fe03bcdddf34",
303
+ "5.2.0-canary.ff23978d50f6",
304
304
  "esm"
305
305
  );
306
306
  import { getColorValue } from "./lib/editor/managers/ThemeManager/defaultThemes.mjs";
@@ -20,6 +20,7 @@ class ClickManager {
20
20
  _clickTimeout;
21
21
  _clickScreenPoint;
22
22
  _previousScreenPoint;
23
+ _isPressingWhilePending = false;
23
24
  _getClickTimeout(state, id = uniqueId()) {
24
25
  this._clickId = id;
25
26
  clearTimeout(this._clickTimeout);
@@ -27,30 +28,12 @@ class ClickManager {
27
28
  () => {
28
29
  if (this._clickState === state && this._clickId === id) {
29
30
  switch (this._clickState) {
30
- case "pendingTriple": {
31
- this.editor.dispatch({
32
- ...this.lastPointerInfo,
33
- type: "click",
34
- name: "double_click",
35
- phase: "settle"
36
- });
37
- break;
38
- }
39
- case "pendingQuadruple": {
40
- this.editor.dispatch({
41
- ...this.lastPointerInfo,
42
- type: "click",
43
- name: "triple_click",
44
- phase: "settle"
45
- });
46
- break;
47
- }
48
31
  case "pendingOverflow": {
49
32
  this.editor.dispatch({
50
33
  ...this.lastPointerInfo,
51
34
  type: "click",
52
- name: "quadruple_click",
53
- phase: "settle"
35
+ name: "double_click",
36
+ phase: this._isPressingWhilePending ? "settle-down" : "settle-up"
54
37
  });
55
38
  break;
56
39
  }
@@ -84,6 +67,7 @@ class ClickManager {
84
67
  case "pointer_down": {
85
68
  if (!this._clickState) return info;
86
69
  this._clickScreenPoint = Vec.From(info.point);
70
+ this._isPressingWhilePending = true;
87
71
  if (this._previousScreenPoint && Vec.Dist2(this._previousScreenPoint, this._clickScreenPoint) > MAX_CLICK_DISTANCE ** 2) {
88
72
  this._clickState = "idle";
89
73
  }
@@ -91,32 +75,12 @@ class ClickManager {
91
75
  this.lastPointerInfo = info;
92
76
  switch (this._clickState) {
93
77
  case "pendingDouble": {
94
- this._clickState = "pendingTriple";
95
- this._clickTimeout = this._getClickTimeout(this._clickState);
96
- return {
97
- ...info,
98
- type: "click",
99
- name: "double_click",
100
- phase: "down"
101
- };
102
- }
103
- case "pendingTriple": {
104
- this._clickState = "pendingQuadruple";
105
- this._clickTimeout = this._getClickTimeout(this._clickState);
106
- return {
107
- ...info,
108
- type: "click",
109
- name: "triple_click",
110
- phase: "down"
111
- };
112
- }
113
- case "pendingQuadruple": {
114
78
  this._clickState = "pendingOverflow";
115
79
  this._clickTimeout = this._getClickTimeout(this._clickState);
116
80
  return {
117
81
  ...info,
118
82
  type: "click",
119
- name: "quadruple_click",
83
+ name: "double_click",
120
84
  phase: "down"
121
85
  };
122
86
  }
@@ -137,28 +101,13 @@ class ClickManager {
137
101
  case "pointer_up": {
138
102
  if (!this._clickState) return info;
139
103
  this._clickScreenPoint = Vec.From(info.point);
104
+ this._isPressingWhilePending = false;
140
105
  switch (this._clickState) {
141
- case "pendingTriple": {
142
- return {
143
- ...this.lastPointerInfo,
144
- type: "click",
145
- name: "double_click",
146
- phase: "up"
147
- };
148
- }
149
- case "pendingQuadruple": {
150
- return {
151
- ...this.lastPointerInfo,
152
- type: "click",
153
- name: "triple_click",
154
- phase: "up"
155
- };
156
- }
157
106
  case "pendingOverflow": {
158
107
  return {
159
108
  ...this.lastPointerInfo,
160
109
  type: "click",
161
- name: "quadruple_click",
110
+ name: "double_click",
162
111
  phase: "up"
163
112
  };
164
113
  }
@@ -179,6 +128,7 @@ class ClickManager {
179
128
  cancelDoubleClickTimeout() {
180
129
  this._clickTimeout = clearTimeout(this._clickTimeout);
181
130
  this._clickState = "idle";
131
+ this._isPressingWhilePending = false;
182
132
  }
183
133
  }
184
134
  __decorateClass([