@tldraw/editor 3.14.0-canary.403af9c5d8f2 → 3.14.0-canary.4255c71c8c87

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 (180) hide show
  1. package/dist-cjs/index.d.ts +166 -71
  2. package/dist-cjs/index.js +11 -8
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/config/TLSessionStateSnapshot.js +1 -12
  5. package/dist-cjs/lib/config/TLSessionStateSnapshot.js.map +3 -3
  6. package/dist-cjs/lib/editor/Editor.js +132 -100
  7. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  8. package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +2 -2
  9. package/dist-cjs/lib/editor/derivations/bindingsIndex.js +22 -22
  10. package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
  11. package/dist-cjs/lib/editor/derivations/parentsToChildren.js +16 -16
  12. package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
  13. package/dist-cjs/lib/editor/managers/{ClickManager.js → ClickManager/ClickManager.js} +1 -1
  14. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +7 -0
  15. package/dist-cjs/lib/editor/managers/{EdgeScrollManager.js → EdgeScrollManager/EdgeScrollManager.js} +2 -2
  16. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +7 -0
  17. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +7 -0
  18. package/dist-cjs/lib/editor/managers/{FontManager.js → FontManager/FontManager.js} +4 -1
  19. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +7 -0
  20. package/dist-cjs/lib/editor/managers/{HistoryManager.js → HistoryManager/HistoryManager.js} +67 -7
  21. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +7 -0
  22. package/dist-cjs/lib/editor/managers/{ScribbleManager.js → ScribbleManager/ScribbleManager.js} +1 -1
  23. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +7 -0
  24. package/dist-cjs/lib/editor/managers/{TextManager.js → TextManager/TextManager.js} +73 -42
  25. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +7 -0
  26. package/dist-cjs/lib/editor/managers/{TickManager.js → TickManager/TickManager.js} +1 -1
  27. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +7 -0
  28. package/dist-cjs/lib/editor/managers/{UserPreferencesManager.js → UserPreferencesManager/UserPreferencesManager.js} +1 -1
  29. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +7 -0
  30. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +0 -10
  31. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  32. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +1 -1
  33. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +1 -1
  34. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +10 -6
  35. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +3 -3
  36. package/dist-cjs/lib/editor/tools/StateNode.js +3 -3
  37. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  38. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  39. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  40. package/dist-cjs/lib/exports/getSvgJsx.js.map +1 -1
  41. package/dist-cjs/lib/hooks/useCanvasEvents.js +1 -2
  42. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  43. package/dist-cjs/lib/primitives/Box.js +33 -33
  44. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  45. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +6 -2
  46. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  47. package/dist-cjs/lib/utils/dom.js +1 -1
  48. package/dist-cjs/lib/utils/dom.js.map +2 -2
  49. package/dist-cjs/lib/utils/reorderShapes.js +11 -10
  50. package/dist-cjs/lib/utils/reorderShapes.js.map +2 -2
  51. package/dist-cjs/lib/utils/reparenting.js +232 -0
  52. package/dist-cjs/lib/utils/reparenting.js.map +7 -0
  53. package/dist-cjs/lib/utils/richText.js +7 -2
  54. package/dist-cjs/lib/utils/richText.js.map +2 -2
  55. package/dist-cjs/version.js +3 -3
  56. package/dist-cjs/version.js.map +1 -1
  57. package/dist-esm/index.d.mts +166 -71
  58. package/dist-esm/index.mjs +15 -8
  59. package/dist-esm/index.mjs.map +2 -2
  60. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs +1 -1
  61. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs.map +2 -2
  62. package/dist-esm/lib/editor/Editor.mjs +132 -100
  63. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  64. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +2 -2
  65. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +22 -22
  66. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
  67. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +16 -16
  68. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
  69. package/dist-esm/lib/editor/managers/{ClickManager.mjs → ClickManager/ClickManager.mjs} +1 -1
  70. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +7 -0
  71. package/dist-esm/lib/editor/managers/{EdgeScrollManager.mjs → EdgeScrollManager/EdgeScrollManager.mjs} +2 -2
  72. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +7 -0
  73. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +7 -0
  74. package/dist-esm/lib/editor/managers/{FontManager.mjs → FontManager/FontManager.mjs} +4 -1
  75. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +7 -0
  76. package/dist-esm/lib/editor/managers/{HistoryManager.mjs → HistoryManager/HistoryManager.mjs} +63 -3
  77. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +7 -0
  78. package/dist-esm/lib/editor/managers/{ScribbleManager.mjs → ScribbleManager/ScribbleManager.mjs} +1 -1
  79. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +7 -0
  80. package/dist-esm/lib/editor/managers/{TextManager.mjs → TextManager/TextManager.mjs} +73 -42
  81. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +7 -0
  82. package/dist-esm/lib/editor/managers/{TickManager.mjs → TickManager/TickManager.mjs} +1 -1
  83. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +7 -0
  84. package/dist-esm/lib/editor/managers/{UserPreferencesManager.mjs → UserPreferencesManager/UserPreferencesManager.mjs} +1 -1
  85. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +7 -0
  86. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +0 -10
  87. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  88. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +1 -1
  89. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +1 -1
  90. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +10 -6
  91. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +3 -3
  92. package/dist-esm/lib/editor/tools/StateNode.mjs +3 -3
  93. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  94. package/dist-esm/lib/exports/getSvgJsx.mjs.map +1 -1
  95. package/dist-esm/lib/hooks/useCanvasEvents.mjs +1 -2
  96. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  97. package/dist-esm/lib/primitives/Box.mjs +33 -33
  98. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  99. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +6 -2
  100. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  101. package/dist-esm/lib/utils/dom.mjs +1 -1
  102. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  103. package/dist-esm/lib/utils/reorderShapes.mjs +11 -10
  104. package/dist-esm/lib/utils/reorderShapes.mjs.map +2 -2
  105. package/dist-esm/lib/utils/reparenting.mjs +216 -0
  106. package/dist-esm/lib/utils/reparenting.mjs.map +7 -0
  107. package/dist-esm/lib/utils/richText.mjs +8 -3
  108. package/dist-esm/lib/utils/richText.mjs.map +2 -2
  109. package/dist-esm/version.mjs +3 -3
  110. package/dist-esm/version.mjs.map +1 -1
  111. package/editor.css +442 -492
  112. package/package.json +8 -9
  113. package/src/index.ts +20 -7
  114. package/src/lib/config/TLSessionStateSnapshot.ts +1 -1
  115. package/src/lib/editor/Editor.test.ts +252 -3
  116. package/src/lib/editor/Editor.ts +150 -108
  117. package/src/lib/editor/bindings/BindingUtil.ts +6 -0
  118. package/src/lib/editor/derivations/bindingsIndex.ts +27 -26
  119. package/src/lib/editor/derivations/parentsToChildren.ts +28 -25
  120. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +442 -0
  121. package/src/lib/editor/managers/{ClickManager.ts → ClickManager/ClickManager.ts} +3 -3
  122. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +374 -0
  123. package/src/lib/editor/managers/{EdgeScrollManager.ts → EdgeScrollManager/EdgeScrollManager.ts} +3 -3
  124. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +455 -0
  125. package/src/lib/editor/managers/{FocusManager.ts → FocusManager/FocusManager.ts} +1 -1
  126. package/src/lib/editor/managers/FontManager/FontManager.test.ts +263 -0
  127. package/src/lib/editor/managers/{FontManager.ts → FontManager/FontManager.ts} +5 -2
  128. package/src/lib/editor/managers/{HistoryManager.test.ts → HistoryManager/HistoryManager.test.ts} +388 -1
  129. package/src/lib/editor/managers/{HistoryManager.ts → HistoryManager/HistoryManager.ts} +76 -3
  130. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +624 -0
  131. package/src/lib/editor/managers/{ScribbleManager.ts → ScribbleManager/ScribbleManager.ts} +2 -2
  132. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +485 -0
  133. package/src/lib/editor/managers/TextManager/TextManager.test.ts +407 -0
  134. package/src/lib/editor/managers/{TextManager.ts → TextManager/TextManager.ts} +119 -87
  135. package/src/lib/editor/managers/TickManager/TickManager.test.ts +314 -0
  136. package/src/lib/editor/managers/{TickManager.ts → TickManager/TickManager.ts} +2 -2
  137. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +591 -0
  138. package/src/lib/editor/managers/{UserPreferencesManager.ts → UserPreferencesManager/UserPreferencesManager.ts} +2 -2
  139. package/src/lib/editor/shapes/ShapeUtil.ts +48 -16
  140. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -1
  141. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +22 -17
  142. package/src/lib/editor/tools/StateNode.ts +3 -3
  143. package/src/lib/editor/types/emit-types.ts +4 -0
  144. package/src/lib/editor/types/external-content.ts +11 -2
  145. package/src/lib/exports/getSvgJsx.tsx +1 -1
  146. package/src/lib/hooks/useCanvasEvents.ts +0 -1
  147. package/src/lib/primitives/Box.test.ts +588 -7
  148. package/src/lib/primitives/Box.ts +33 -33
  149. package/src/lib/primitives/geometry/Geometry2d.ts +7 -2
  150. package/src/lib/utils/dom.ts +1 -1
  151. package/src/lib/utils/reorderShapes.ts +10 -13
  152. package/src/lib/utils/reparenting.ts +383 -0
  153. package/src/lib/utils/richText.ts +10 -4
  154. package/src/version.ts +3 -3
  155. package/dist-cjs/lib/editor/managers/ClickManager.js.map +0 -7
  156. package/dist-cjs/lib/editor/managers/EdgeScrollManager.js.map +0 -7
  157. package/dist-cjs/lib/editor/managers/FocusManager.js.map +0 -7
  158. package/dist-cjs/lib/editor/managers/FontManager.js.map +0 -7
  159. package/dist-cjs/lib/editor/managers/HistoryManager.js.map +0 -7
  160. package/dist-cjs/lib/editor/managers/ScribbleManager.js.map +0 -7
  161. package/dist-cjs/lib/editor/managers/Stack.js +0 -82
  162. package/dist-cjs/lib/editor/managers/Stack.js.map +0 -7
  163. package/dist-cjs/lib/editor/managers/TextManager.js.map +0 -7
  164. package/dist-cjs/lib/editor/managers/TickManager.js.map +0 -7
  165. package/dist-cjs/lib/editor/managers/UserPreferencesManager.js.map +0 -7
  166. package/dist-esm/lib/editor/managers/ClickManager.mjs.map +0 -7
  167. package/dist-esm/lib/editor/managers/EdgeScrollManager.mjs.map +0 -7
  168. package/dist-esm/lib/editor/managers/FocusManager.mjs.map +0 -7
  169. package/dist-esm/lib/editor/managers/FontManager.mjs.map +0 -7
  170. package/dist-esm/lib/editor/managers/HistoryManager.mjs.map +0 -7
  171. package/dist-esm/lib/editor/managers/ScribbleManager.mjs.map +0 -7
  172. package/dist-esm/lib/editor/managers/Stack.mjs +0 -62
  173. package/dist-esm/lib/editor/managers/Stack.mjs.map +0 -7
  174. package/dist-esm/lib/editor/managers/TextManager.mjs.map +0 -7
  175. package/dist-esm/lib/editor/managers/TickManager.mjs.map +0 -7
  176. package/dist-esm/lib/editor/managers/UserPreferencesManager.mjs.map +0 -7
  177. package/src/lib/editor/managers/ScribbleManager.test.ts +0 -32
  178. package/src/lib/editor/managers/Stack.ts +0 -71
  179. /package/dist-cjs/lib/editor/managers/{FocusManager.js → FocusManager/FocusManager.js} +0 -0
  180. /package/dist-esm/lib/editor/managers/{FocusManager.mjs → FocusManager/FocusManager.mjs} +0 -0
@@ -134,33 +134,33 @@ export class Box {
134
134
 
135
135
  // eslint-disable-next-line no-restricted-syntax
136
136
  get center() {
137
- return new Vec(this.midX, this.midY)
137
+ return new Vec(this.x + this.w / 2, this.y + this.h / 2)
138
138
  }
139
139
 
140
140
  // eslint-disable-next-line no-restricted-syntax
141
141
  set center(v: Vec) {
142
- this.minX = v.x - this.width / 2
143
- this.minY = v.y - this.height / 2
142
+ this.x = v.x - this.w / 2
143
+ this.y = v.y - this.h / 2
144
144
  }
145
145
 
146
146
  // eslint-disable-next-line no-restricted-syntax
147
147
  get corners() {
148
148
  return [
149
- new Vec(this.minX, this.minY),
150
- new Vec(this.maxX, this.minY),
151
- new Vec(this.maxX, this.maxY),
152
- new Vec(this.minX, this.maxY),
149
+ new Vec(this.x, this.y),
150
+ new Vec(this.x + this.w, this.y),
151
+ new Vec(this.x + this.w, this.y + this.h),
152
+ new Vec(this.x, this.y + this.h),
153
153
  ]
154
154
  }
155
155
 
156
156
  // eslint-disable-next-line no-restricted-syntax
157
157
  get cornersAndCenter() {
158
158
  return [
159
- new Vec(this.minX, this.minY),
160
- new Vec(this.maxX, this.minY),
161
- new Vec(this.maxX, this.maxY),
162
- new Vec(this.minX, this.maxY),
163
- this.center,
159
+ new Vec(this.x, this.y),
160
+ new Vec(this.x + this.w, this.y),
161
+ new Vec(this.x + this.w, this.y + this.h),
162
+ new Vec(this.x, this.y + this.h),
163
+ new Vec(this.x + this.w / 2, this.y + this.h / 2),
164
164
  ]
165
165
  }
166
166
 
@@ -205,10 +205,10 @@ export class Box {
205
205
  }
206
206
 
207
207
  expand(A: Box) {
208
- const minX = Math.min(this.minX, A.minX)
209
- const minY = Math.min(this.minY, A.minY)
210
- const maxX = Math.max(this.maxX, A.maxX)
211
- const maxY = Math.max(this.maxY, A.maxY)
208
+ const minX = Math.min(this.x, A.x)
209
+ const minY = Math.min(this.y, A.y)
210
+ const maxX = Math.max(this.x + this.w, A.x + A.w)
211
+ const maxY = Math.max(this.y + this.h, A.y + A.h)
212
212
 
213
213
  this.x = minX
214
214
  this.y = minY
@@ -245,10 +245,10 @@ export class Box {
245
245
  }
246
246
 
247
247
  snapToGrid(size: number) {
248
- const minX = Math.round(this.minX / size) * size
249
- const minY = Math.round(this.minY / size) * size
250
- const maxX = Math.round(this.maxX / size) * size
251
- const maxY = Math.round(this.maxY / size) * size
248
+ const minX = Math.round(this.x / size) * size
249
+ const minY = Math.round(this.y / size) * size
250
+ const maxX = Math.round((this.x + this.w) / size) * size
251
+ const maxY = Math.round((this.y + this.h) / size) * size
252
252
  this.minX = minX
253
253
  this.minY = minY
254
254
  this.width = Math.max(1, maxX - minX)
@@ -274,26 +274,26 @@ export class Box {
274
274
  getHandlePoint(handle: SelectionCorner | SelectionEdge) {
275
275
  switch (handle) {
276
276
  case 'top_left':
277
- return new Vec(this.minX, this.minY)
277
+ return new Vec(this.x, this.y)
278
278
  case 'top_right':
279
- return new Vec(this.maxX, this.minY)
279
+ return new Vec(this.x + this.w, this.y)
280
280
  case 'bottom_left':
281
- return new Vec(this.minX, this.maxY)
281
+ return new Vec(this.x, this.y + this.h)
282
282
  case 'bottom_right':
283
- return new Vec(this.maxX, this.maxY)
283
+ return new Vec(this.x + this.w, this.y + this.h)
284
284
  case 'top':
285
- return new Vec(this.midX, this.minY)
285
+ return new Vec(this.x + this.w / 2, this.y)
286
286
  case 'right':
287
- return new Vec(this.maxX, this.midY)
287
+ return new Vec(this.x + this.w, this.y + this.h / 2)
288
288
  case 'bottom':
289
- return new Vec(this.midX, this.maxY)
289
+ return new Vec(this.x + this.w / 2, this.y + this.h)
290
290
  case 'left':
291
- return new Vec(this.minX, this.midY)
291
+ return new Vec(this.x, this.y + this.h / 2)
292
292
  }
293
293
  }
294
294
 
295
295
  toJson(): BoxModel {
296
- return { x: this.minX, y: this.minY, w: this.w, h: this.h }
296
+ return { x: this.x, y: this.y, w: this.w, h: this.h }
297
297
  }
298
298
 
299
299
  resize(handle: SelectionCorner | SelectionEdge | string, dx: number, dy: number) {
@@ -357,10 +357,10 @@ export class Box {
357
357
  }
358
358
 
359
359
  union(box: BoxModel) {
360
- const minX = Math.min(this.minX, box.x)
361
- const minY = Math.min(this.minY, box.y)
362
- const maxX = Math.max(this.maxX, box.w + box.x)
363
- const maxY = Math.max(this.maxY, box.h + box.y)
360
+ const minX = Math.min(this.x, box.x)
361
+ const minY = Math.min(this.y, box.y)
362
+ const maxX = Math.max(this.x + this.w, box.x + box.w)
363
+ const maxY = Math.max(this.y + this.h, box.y + box.h)
364
364
 
365
365
  this.x = minX
366
366
  this.y = minY
@@ -44,6 +44,7 @@ export const Geometry2dFilters: {
44
44
  /** @public */
45
45
  export interface TransformedGeometry2dOptions {
46
46
  isLabel?: boolean
47
+ isEmptyLabel?: boolean
47
48
  isInternal?: boolean
48
49
  debugColor?: string
49
50
  ignore?: boolean
@@ -57,20 +58,24 @@ export interface Geometry2dOptions extends TransformedGeometry2dOptions {
57
58
 
58
59
  /** @public */
59
60
  export abstract class Geometry2d {
61
+ // todo: consider making accessors for these too, so that they can be overridden in subclasses by geometries with more complex logic
60
62
  isFilled = false
61
63
  isClosed = true
62
64
  isLabel = false
65
+ isEmptyLabel = false
63
66
  isInternal = false
64
67
  debugColor?: string
65
68
  ignore?: boolean
66
69
 
67
70
  constructor(opts: Geometry2dOptions) {
71
+ const { isLabel = false, isEmptyLabel = false, isInternal = false } = opts
68
72
  this.isFilled = opts.isFilled
69
73
  this.isClosed = opts.isClosed
70
- this.isLabel = opts.isLabel ?? false
71
- this.isInternal = opts.isInternal ?? false
72
74
  this.debugColor = opts.debugColor
73
75
  this.ignore = opts.ignore
76
+ this.isLabel = isLabel
77
+ this.isEmptyLabel = isEmptyLabel
78
+ this.isInternal = isInternal
74
79
  }
75
80
 
76
81
  isExcludedByFilter(filters?: Geometry2dFilters) {
@@ -18,7 +18,7 @@ import { debugFlags, pointerCaptureTrackingObject } from './debug-flags'
18
18
 
19
19
  /** @public */
20
20
  export function loopToHtmlElement(elm: Element): HTMLElement {
21
- if (elm instanceof HTMLElement) return elm
21
+ if (elm.nodeType === Node.ELEMENT_NODE) return elm as HTMLElement
22
22
  if (elm.parentElement) return loopToHtmlElement(elm.parentElement)
23
23
  else throw Error('Could not find a parent element of an HTML type!')
24
24
  }
@@ -1,8 +1,6 @@
1
1
  import { TLParentId, TLShape, TLShapeId, TLShapePartial } from '@tldraw/tlschema'
2
2
  import { IndexKey, compact, getIndicesBetween, sortByIndex } from '@tldraw/utils'
3
3
  import { Editor } from '../editor/Editor'
4
- import { Vec } from '../primitives/Vec'
5
- import { polygonsIntersect } from '../primitives/intersect'
6
4
 
7
5
  export function getReorderingShapesChanges(
8
6
  editor: Editor,
@@ -155,19 +153,18 @@ function reorderToFront(moving: Set<TLShape>, children: TLShape[], changes: TLSh
155
153
  }
156
154
 
157
155
  function getOverlapChecker(editor: Editor, moving: Set<TLShape>) {
158
- const movingVertices = Array.from(moving)
159
- .map((shape) => {
160
- const vertices = editor.getShapePageGeometry(shape).vertices
161
- if (!vertices) return null
162
- return { shape, vertices }
156
+ const movingBounds = compact(
157
+ Array.from(moving).map((shape) => {
158
+ const bounds = editor.getShapePageBounds(shape)
159
+ if (!bounds) return null
160
+ return { shape, bounds }
163
161
  })
164
- .filter(Boolean) as { shape: TLShape; vertices: Vec[] }[]
165
-
162
+ )
166
163
  const isOverlapping = (child: TLShape) => {
167
- const vertices = editor.getShapePageGeometry(child).vertices
168
- if (!vertices) return false
169
- return movingVertices.some((other) => {
170
- return polygonsIntersect(other.vertices, vertices)
164
+ const bounds = editor.getShapePageBounds(child)
165
+ if (!bounds) return false
166
+ return movingBounds.some((other) => {
167
+ return other.bounds.includes(bounds)
171
168
  })
172
169
  }
173
170
 
@@ -0,0 +1,383 @@
1
+ import { EMPTY_ARRAY } from '@tldraw/state'
2
+ import { TLGroupShape, TLParentId, TLShape, TLShapeId } from '@tldraw/tlschema'
3
+ import { IndexKey, compact, getIndexAbove, getIndexBetween } from '@tldraw/utils'
4
+ import { Editor } from '../editor/Editor'
5
+ import { Vec } from '../primitives/Vec'
6
+ import { Geometry2d } from '../primitives/geometry/Geometry2d'
7
+ import { Group2d } from '../primitives/geometry/Group2d'
8
+ import {
9
+ intersectPolygonPolygon,
10
+ polygonIntersectsPolyline,
11
+ polygonsIntersect,
12
+ } from '../primitives/intersect'
13
+ import { pointInPolygon } from '../primitives/utils'
14
+
15
+ /**
16
+ * Reparents shapes that are no longer contained within their parent shapes.
17
+ * todo: rename me to something more descriptive, like `reparentOccludedShapes` or `reparentAutoDroppedShapes`
18
+ *
19
+ * @param editor - The editor instance.
20
+ * @param shapeIds - The IDs of the shapes to reparent.
21
+ * @param opts - Optional options, including a callback to filter out certain parents, such as when removing a frame.
22
+ *
23
+ * @public
24
+ */
25
+ export function kickoutOccludedShapes(
26
+ editor: Editor,
27
+ shapeIds: TLShapeId[],
28
+ opts?: { filter?(parent: TLShape): boolean }
29
+ ) {
30
+ const parentsToCheck = new Set<TLShape>()
31
+
32
+ for (const id of shapeIds) {
33
+ const shape = editor.getShape(id)
34
+
35
+ if (!shape) continue
36
+ parentsToCheck.add(shape)
37
+
38
+ const parent = editor.getShape(shape.parentId)
39
+ if (!parent) continue
40
+ parentsToCheck.add(parent)
41
+ }
42
+
43
+ // Check all of the parents and gather up parents who have lost children
44
+ const parentsToLostChildren = new Map<TLShape, TLShapeId[]>()
45
+
46
+ for (const parent of parentsToCheck) {
47
+ const childIds = editor.getSortedChildIdsForParent(parent)
48
+ if (opts?.filter && !opts.filter(parent)) {
49
+ // If the shape is filtered out, we kick out all of its children
50
+ parentsToLostChildren.set(parent, childIds)
51
+ } else {
52
+ const overlappingChildren = getOverlappingShapes(editor, parent.id, childIds)
53
+ if (overlappingChildren.length < childIds.length) {
54
+ parentsToLostChildren.set(
55
+ parent,
56
+ childIds.filter((id) => !overlappingChildren.includes(id))
57
+ )
58
+ }
59
+ }
60
+ }
61
+
62
+ // Get all of the shapes on the current page, sorted by their index
63
+ const sortedShapeIds = editor.getCurrentPageShapesSorted().map((s) => s.id)
64
+
65
+ const parentsToNewChildren: Record<
66
+ TLParentId,
67
+ { parentId: TLParentId; shapeIds: TLShapeId[]; index?: IndexKey }
68
+ > = {}
69
+
70
+ for (const [prevParent, lostChildrenIds] of parentsToLostChildren) {
71
+ const lostChildren = compact(lostChildrenIds.map((id) => editor.getShape(id)))
72
+
73
+ // Don't fall "up" into frames in front of the shape
74
+ // if (pageShapes.indexOf(shape) < frameSortPosition) continue shapeCheck
75
+
76
+ // Otherwise, we have no next dropping shape under the cursor, so go find
77
+ // all the frames on the page where the moving shapes will fall into
78
+ const { reparenting, remainingShapesToReparent } = getDroppedShapesToNewParents(
79
+ editor,
80
+ lostChildren,
81
+ (shape, maybeNewParent) => {
82
+ // If we're filtering out a potential parent, don't reparent shapes to the filtered out shape
83
+ if (opts?.filter && !opts.filter(maybeNewParent)) return false
84
+ return (
85
+ maybeNewParent.id !== prevParent.id &&
86
+ sortedShapeIds.indexOf(maybeNewParent.id) < sortedShapeIds.indexOf(shape.id)
87
+ )
88
+ }
89
+ )
90
+
91
+ reparenting.forEach((childrenToReparent, newParentId) => {
92
+ if (childrenToReparent.length === 0) return
93
+ if (!parentsToNewChildren[newParentId]) {
94
+ parentsToNewChildren[newParentId] = {
95
+ parentId: newParentId,
96
+ shapeIds: [],
97
+ }
98
+ }
99
+ parentsToNewChildren[newParentId].shapeIds.push(...childrenToReparent.map((s) => s.id))
100
+ })
101
+
102
+ // Reparent the rest to the page (or containing group)
103
+ if (remainingShapesToReparent.size > 0) {
104
+ // The remaining shapes are going to be reparented to the old parent's containing group, if there was one, or else to the page
105
+ const newParentId =
106
+ editor.findShapeAncestor(prevParent, (s) => editor.isShapeOfType<TLGroupShape>(s, 'group'))
107
+ ?.id ?? editor.getCurrentPageId()
108
+
109
+ remainingShapesToReparent.forEach((shape) => {
110
+ if (!parentsToNewChildren[newParentId]) {
111
+ let insertIndexKey: IndexKey | undefined
112
+
113
+ const oldParentSiblingIds = editor.getSortedChildIdsForParent(newParentId)
114
+ const oldParentIndex = oldParentSiblingIds.indexOf(prevParent.id)
115
+ if (oldParentIndex > -1) {
116
+ // If the old parent is a direct child of the new parent, then we'll add them above the old parent but below the next sibling.
117
+ const siblingsIndexAbove = oldParentSiblingIds[oldParentIndex + 1]
118
+ const indexKeyAbove = siblingsIndexAbove
119
+ ? editor.getShape(siblingsIndexAbove)!.index
120
+ : getIndexAbove(prevParent.index)
121
+ insertIndexKey = getIndexBetween(prevParent.index, indexKeyAbove)
122
+ } else {
123
+ // If the old parent is not a direct child of the new parent, then we'll add them to the "top" of the new parent's children.
124
+ // This is done automatically if we leave the index undefined, so let's do that.
125
+ }
126
+
127
+ parentsToNewChildren[newParentId] = {
128
+ parentId: newParentId,
129
+ shapeIds: [],
130
+ index: insertIndexKey,
131
+ }
132
+ }
133
+
134
+ parentsToNewChildren[newParentId].shapeIds.push(shape.id)
135
+ })
136
+ }
137
+ }
138
+
139
+ editor.run(() => {
140
+ Object.values(parentsToNewChildren).forEach(({ parentId, shapeIds, index }) => {
141
+ if (shapeIds.length === 0) return
142
+ // Before we reparent, sort the new shape ids by their place in the original absolute order on the page
143
+ shapeIds.sort((a, b) => (sortedShapeIds.indexOf(a) < sortedShapeIds.indexOf(b) ? -1 : 1))
144
+ editor.reparentShapes(shapeIds, parentId, index)
145
+ })
146
+ })
147
+ }
148
+
149
+ /**
150
+ * Get the shapes that overlap with a given shape.
151
+ *
152
+ * @param editor - The editor instance.
153
+ * @param shape - The shapes or shape IDs to check against.
154
+ * @param otherShapes - The shapes or shape IDs to check for overlap.
155
+ * @returns An array of shapes or shape IDs that overlap with the given shape.
156
+ */
157
+ function getOverlappingShapes<T extends TLShape[] | TLShapeId[]>(
158
+ editor: Editor,
159
+ shape: T[number],
160
+ otherShapes: T
161
+ ) {
162
+ if (otherShapes.length === 0) {
163
+ return EMPTY_ARRAY
164
+ }
165
+
166
+ const parentPageBounds = editor.getShapePageBounds(shape)
167
+ if (!parentPageBounds) return EMPTY_ARRAY
168
+
169
+ const parentGeometry = editor.getShapeGeometry(shape)
170
+ const parentPageTransform = editor.getShapePageTransform(shape)
171
+ const parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)
172
+
173
+ const parentPageMaskVertices = editor.getShapeMask(shape)
174
+ const parentPagePolygon = parentPageMaskVertices
175
+ ? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)
176
+ : parentPageCorners
177
+
178
+ if (!parentPagePolygon) return EMPTY_ARRAY
179
+
180
+ return otherShapes.filter((childId) => {
181
+ const shapePageBounds = editor.getShapePageBounds(childId)
182
+ if (!shapePageBounds || !parentPageBounds.includes(shapePageBounds)) return false
183
+
184
+ const parentPolygonInShapeShape = editor
185
+ .getShapePageTransform(childId)
186
+ .clone()
187
+ .invert()
188
+ .applyToPoints(parentPagePolygon)
189
+
190
+ const geometry = editor.getShapeGeometry(childId)
191
+
192
+ return doesGeometryOverlapPolygon(geometry, parentPolygonInShapeShape)
193
+ })
194
+ }
195
+
196
+ /**
197
+ * @public
198
+ */
199
+ export function doesGeometryOverlapPolygon(
200
+ geometry: Geometry2d,
201
+ parentCornersInShapeSpace: Vec[]
202
+ ): boolean {
203
+ // If the child is a group, check if any of its children overlap the box
204
+ if (geometry instanceof Group2d) {
205
+ return geometry.children.some((childGeometry) =>
206
+ doesGeometryOverlapPolygon(childGeometry, parentCornersInShapeSpace)
207
+ )
208
+ }
209
+
210
+ // Otherwise, check if the geometry overlaps the box
211
+ const { vertices, center, isFilled, isEmptyLabel, isClosed } = geometry
212
+
213
+ // We'll do things in order of cheapest to most expensive checks
214
+
215
+ // Skip empty labels
216
+ if (isEmptyLabel) return false
217
+
218
+ // If any of the shape's vertices are inside the occluder, it's inside
219
+ if (vertices.some((v) => pointInPolygon(v, parentCornersInShapeSpace))) {
220
+ return true
221
+ }
222
+
223
+ // If the shape is filled and closed and its center is inside the parent, it's inside
224
+ if (isClosed) {
225
+ if (isFilled) {
226
+ // If closed and filled, check if the center is inside the parent
227
+ if (pointInPolygon(center, parentCornersInShapeSpace)) {
228
+ return true
229
+ }
230
+
231
+ // ..then, slightly more expensive check, see the shape covers the entire parent but not its center
232
+ if (parentCornersInShapeSpace.every((v) => pointInPolygon(v, vertices))) {
233
+ return true
234
+ }
235
+ }
236
+
237
+ // If any the shape's vertices intersect the edge of the occluder, it's inside.
238
+ // for example when a rotated rectangle is moved over the corner of a parent rectangle
239
+ // If the child shape is closed, intersect as a polygon
240
+ if (polygonsIntersect(parentCornersInShapeSpace, vertices)) {
241
+ return true
242
+ }
243
+ } else {
244
+ // if the child shape is not closed, intersect as a polyline
245
+ if (polygonIntersectsPolyline(parentCornersInShapeSpace, vertices)) {
246
+ return true
247
+ }
248
+ }
249
+
250
+ // If none of the above checks passed, the shape is outside the parent
251
+ return false
252
+ }
253
+
254
+ /**
255
+ * Get the shapes that will be reparented to new parents when the shapes are dropped.
256
+ *
257
+ * @param editor - The editor instance.
258
+ * @param shapes - The shapes to check.
259
+ * @param cb - A callback to filter out certain shapes.
260
+ * @returns An object with the shapes that will be reparented to new parents and the shapes that will be reparented to the page or their ancestral group.
261
+ *
262
+ * @public
263
+ */
264
+ export function getDroppedShapesToNewParents(
265
+ editor: Editor,
266
+ shapes: Set<TLShape> | TLShape[],
267
+ cb?: (shape: TLShape, parent: TLShape) => boolean
268
+ ) {
269
+ const shapesToActuallyCheck = new Set<TLShape>(shapes)
270
+ const movingGroups = new Set<TLGroupShape>()
271
+
272
+ for (const shape of shapes) {
273
+ const parent = editor.getShapeParent(shape)
274
+ if (parent && editor.isShapeOfType<TLGroupShape>(parent, 'group')) {
275
+ if (!movingGroups.has(parent)) {
276
+ movingGroups.add(parent)
277
+ }
278
+ }
279
+ }
280
+
281
+ // If all of a group's children are moving, then move the group instead
282
+ for (const movingGroup of movingGroups) {
283
+ const children = compact(
284
+ editor.getSortedChildIdsForParent(movingGroup).map((id) => editor.getShape(id))
285
+ )
286
+ for (const child of children) {
287
+ shapesToActuallyCheck.delete(child)
288
+ }
289
+ shapesToActuallyCheck.add(movingGroup)
290
+ }
291
+
292
+ // this could be cached and passed in
293
+ const shapeGroupIds = new Map<TLShapeId, TLShapeId | undefined>()
294
+
295
+ const reparenting = new Map<TLShapeId, TLShape[]>()
296
+
297
+ const remainingShapesToReparent = new Set(shapesToActuallyCheck)
298
+
299
+ const potentialParentShapes = editor
300
+ .getCurrentPageShapesSorted()
301
+ // filter out any shapes that aren't frames or that are included among the provided shapes
302
+ .filter(
303
+ (s) =>
304
+ editor.getShapeUtil(s).canReceiveNewChildrenOfType?.(s, s.type) &&
305
+ !remainingShapesToReparent.has(s)
306
+ )
307
+
308
+ parentCheck: for (let i = potentialParentShapes.length - 1; i >= 0; i--) {
309
+ const parentShape = potentialParentShapes[i]
310
+ const parentShapeContainingGroupId = editor.findShapeAncestor(parentShape, (s) =>
311
+ editor.isShapeOfType<TLGroupShape>(s, 'group')
312
+ )?.id
313
+
314
+ const parentGeometry = editor.getShapeGeometry(parentShape)
315
+ const parentPageTransform = editor.getShapePageTransform(parentShape)
316
+ const parentPageMaskVertices = editor.getShapeMask(parentShape)
317
+ const parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)
318
+ const parentPagePolygon = parentPageMaskVertices
319
+ ? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)
320
+ : parentPageCorners
321
+
322
+ if (!parentPagePolygon) continue parentCheck
323
+
324
+ const childrenToReparent = []
325
+
326
+ // For each of the dropping shapes...
327
+ shapeCheck: for (const shape of remainingShapesToReparent) {
328
+ // Don't reparent a frame to itself
329
+ if (parentShape.id === shape.id) continue shapeCheck
330
+
331
+ // Use the callback to filter out certain shapes
332
+ if (cb && !cb(shape, parentShape)) continue shapeCheck
333
+
334
+ if (!shapeGroupIds.has(shape.id)) {
335
+ shapeGroupIds.set(
336
+ shape.id,
337
+ editor.findShapeAncestor(shape, (s) => editor.isShapeOfType<TLGroupShape>(s, 'group'))?.id
338
+ )
339
+ }
340
+
341
+ const shapeGroupId = shapeGroupIds.get(shape.id)
342
+
343
+ // Are the shape and the parent part of different groups?
344
+ if (shapeGroupId !== parentShapeContainingGroupId) continue shapeCheck
345
+
346
+ // Is the shape is actually the ancestor of the parent?
347
+ if (editor.findShapeAncestor(parentShape, (s) => shape.id === s.id)) continue shapeCheck
348
+
349
+ // Convert the parent polygon to the shape's space
350
+ const parentPolygonInShapeSpace = editor
351
+ .getShapePageTransform(shape)
352
+ .clone()
353
+ .invert()
354
+ .applyToPoints(parentPagePolygon)
355
+
356
+ // If the shape overlaps the parent polygon, reparent it to that parent
357
+ if (doesGeometryOverlapPolygon(editor.getShapeGeometry(shape), parentPolygonInShapeSpace)) {
358
+ // Use the util to check if the shape can be reparented to the parent
359
+ if (
360
+ !editor.getShapeUtil(parentShape).canReceiveNewChildrenOfType?.(parentShape, shape.type)
361
+ )
362
+ continue shapeCheck
363
+
364
+ if (shape.parentId !== parentShape.id) {
365
+ childrenToReparent.push(shape)
366
+ }
367
+ remainingShapesToReparent.delete(shape)
368
+ continue shapeCheck
369
+ }
370
+ }
371
+
372
+ if (childrenToReparent.length) {
373
+ reparenting.set(parentShape.id, childrenToReparent)
374
+ }
375
+ }
376
+
377
+ return {
378
+ // these are the shapes that will be reparented to new parents
379
+ reparenting,
380
+ // these are the shapes that will be reparented to the page or their ancestral group
381
+ remainingShapesToReparent,
382
+ }
383
+ }
@@ -1,10 +1,10 @@
1
1
  import { getSchema, JSONContent, Editor as TTEditor } from '@tiptap/core'
2
- import { Node } from '@tiptap/pm/model'
2
+ import { Node, Schema } from '@tiptap/pm/model'
3
3
  import { EditorProviderProps } from '@tiptap/react'
4
4
  import { TLRichText } from '@tldraw/tlschema'
5
- import { assert } from '@tldraw/utils'
5
+ import { assert, WeakCache } from '@tldraw/utils'
6
6
  import { Editor } from '../editor/Editor'
7
- import { TLFontFace } from '../editor/managers/FontManager'
7
+ import { TLFontFace } from '../editor/managers/FontManager/FontManager'
8
8
 
9
9
  /**
10
10
  * This is the TipTap editor! Docs are {@link https://tiptap.dev/docs}.
@@ -39,6 +39,11 @@ export type RichTextFontVisitor = (
39
39
  addFont: (font: TLFontFace) => void
40
40
  ) => RichTextFontVisitorState
41
41
 
42
+ const schemaCache = new WeakCache<EditorProviderProps, Schema>()
43
+ export function getTipTapSchema(tipTapConfig: EditorProviderProps) {
44
+ return schemaCache.get(tipTapConfig, () => getSchema(tipTapConfig.extensions ?? []))
45
+ }
46
+
42
47
  /** @public */
43
48
  export function getFontsFromRichText(
44
49
  editor: Editor,
@@ -49,7 +54,8 @@ export function getFontsFromRichText(
49
54
  assert(tipTapConfig, 'textOptions.tipTapConfig must be set to use rich text')
50
55
  assert(addFontsFromNode, 'textOptions.addFontsFromNode must be set to use rich text')
51
56
 
52
- const schema = getSchema(tipTapConfig.extensions ?? [])
57
+ const schema = getTipTapSchema(tipTapConfig)
58
+
53
59
  const rootNode = Node.fromJSON(schema, richText as JSONContent)
54
60
 
55
61
  const fonts = new Set<TLFontFace>()
package/src/version.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  // This file is automatically generated by internal/scripts/refresh-assets.ts.
2
2
  // Do not edit manually. Or do, I'm a comment, not a cop.
3
3
 
4
- export const version = '3.14.0-canary.403af9c5d8f2'
4
+ export const version = '3.14.0-canary.4255c71c8c87'
5
5
  export const publishDates = {
6
6
  major: '2024-09-13T14:36:29.063Z',
7
- minor: '2025-06-01T07:14:58.245Z',
8
- patch: '2025-06-01T07:14:58.245Z',
7
+ minor: '2025-06-30T12:25:57.741Z',
8
+ patch: '2025-06-30T12:25:57.741Z',
9
9
  }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../src/lib/editor/managers/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 no-restricted-syntax\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.currentScreenPoint) >\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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",
6
- "names": []
7
- }