@tldraw/editor 3.14.0-canary.f6a0206007b3 → 3.14.0-canary.f907ed7d9ee5

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 (148) hide show
  1. package/dist-cjs/index.d.ts +17 -26
  2. package/dist-cjs/index.js +8 -10
  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 +50 -76
  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} +64 -6
  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/TextManager.js.map +7 -0
  25. package/dist-cjs/lib/editor/managers/{TickManager.js → TickManager/TickManager.js} +1 -1
  26. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +7 -0
  27. package/dist-cjs/lib/editor/managers/{UserPreferencesManager.js → UserPreferencesManager/UserPreferencesManager.js} +1 -1
  28. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +7 -0
  29. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +1 -1
  30. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +1 -1
  31. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +1 -1
  32. package/dist-cjs/lib/exports/getSvgJsx.js.map +1 -1
  33. package/dist-cjs/lib/primitives/Box.js +33 -39
  34. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  35. package/dist-cjs/lib/utils/areShapesContentEqual.js +1 -1
  36. package/dist-cjs/lib/utils/areShapesContentEqual.js.map +2 -2
  37. package/dist-cjs/lib/utils/reorderShapes.js +11 -10
  38. package/dist-cjs/lib/utils/reorderShapes.js.map +2 -2
  39. package/dist-cjs/lib/utils/richText.js +7 -2
  40. package/dist-cjs/lib/utils/richText.js.map +2 -2
  41. package/dist-cjs/version.js +3 -3
  42. package/dist-cjs/version.js.map +1 -1
  43. package/dist-esm/index.d.mts +17 -26
  44. package/dist-esm/index.mjs +12 -10
  45. package/dist-esm/index.mjs.map +2 -2
  46. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs +1 -1
  47. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs.map +2 -2
  48. package/dist-esm/lib/editor/Editor.mjs +50 -76
  49. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  50. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +2 -2
  51. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +22 -22
  52. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
  53. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +16 -16
  54. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
  55. package/dist-esm/lib/editor/managers/{ClickManager.mjs → ClickManager/ClickManager.mjs} +1 -1
  56. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +7 -0
  57. package/dist-esm/lib/editor/managers/{EdgeScrollManager.mjs → EdgeScrollManager/EdgeScrollManager.mjs} +2 -2
  58. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +7 -0
  59. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +7 -0
  60. package/dist-esm/lib/editor/managers/{FontManager.mjs → FontManager/FontManager.mjs} +4 -1
  61. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +7 -0
  62. package/dist-esm/lib/editor/managers/{HistoryManager.mjs → HistoryManager/HistoryManager.mjs} +60 -2
  63. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +7 -0
  64. package/dist-esm/lib/editor/managers/{ScribbleManager.mjs → ScribbleManager/ScribbleManager.mjs} +1 -1
  65. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +7 -0
  66. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +7 -0
  67. package/dist-esm/lib/editor/managers/{TickManager.mjs → TickManager/TickManager.mjs} +1 -1
  68. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +7 -0
  69. package/dist-esm/lib/editor/managers/{UserPreferencesManager.mjs → UserPreferencesManager/UserPreferencesManager.mjs} +1 -1
  70. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +7 -0
  71. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +1 -1
  72. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +1 -1
  73. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +1 -1
  74. package/dist-esm/lib/exports/getSvgJsx.mjs.map +1 -1
  75. package/dist-esm/lib/primitives/Box.mjs +33 -39
  76. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  77. package/dist-esm/lib/utils/areShapesContentEqual.mjs +1 -1
  78. package/dist-esm/lib/utils/areShapesContentEqual.mjs.map +2 -2
  79. package/dist-esm/lib/utils/reorderShapes.mjs +11 -10
  80. package/dist-esm/lib/utils/reorderShapes.mjs.map +2 -2
  81. package/dist-esm/lib/utils/richText.mjs +8 -3
  82. package/dist-esm/lib/utils/richText.mjs.map +2 -2
  83. package/dist-esm/version.mjs +3 -3
  84. package/dist-esm/version.mjs.map +1 -1
  85. package/package.json +8 -9
  86. package/src/index.ts +13 -8
  87. package/src/lib/config/TLSessionStateSnapshot.ts +1 -1
  88. package/src/lib/editor/Editor.test.ts +252 -3
  89. package/src/lib/editor/Editor.ts +48 -75
  90. package/src/lib/editor/bindings/BindingUtil.ts +6 -0
  91. package/src/lib/editor/derivations/bindingsIndex.ts +27 -26
  92. package/src/lib/editor/derivations/parentsToChildren.ts +28 -25
  93. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +442 -0
  94. package/src/lib/editor/managers/{ClickManager.ts → ClickManager/ClickManager.ts} +3 -3
  95. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +374 -0
  96. package/src/lib/editor/managers/{EdgeScrollManager.ts → EdgeScrollManager/EdgeScrollManager.ts} +3 -3
  97. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +455 -0
  98. package/src/lib/editor/managers/{FocusManager.ts → FocusManager/FocusManager.ts} +1 -1
  99. package/src/lib/editor/managers/FontManager/FontManager.test.ts +263 -0
  100. package/src/lib/editor/managers/{FontManager.ts → FontManager/FontManager.ts} +5 -2
  101. package/src/lib/editor/managers/{HistoryManager.test.ts → HistoryManager/HistoryManager.test.ts} +388 -1
  102. package/src/lib/editor/managers/{HistoryManager.ts → HistoryManager/HistoryManager.ts} +73 -2
  103. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +624 -0
  104. package/src/lib/editor/managers/{ScribbleManager.ts → ScribbleManager/ScribbleManager.ts} +2 -2
  105. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +485 -0
  106. package/src/lib/editor/managers/TextManager/TextManager.test.ts +411 -0
  107. package/src/lib/editor/managers/{TextManager.ts → TextManager/TextManager.ts} +1 -1
  108. package/src/lib/editor/managers/TickManager/TickManager.test.ts +314 -0
  109. package/src/lib/editor/managers/{TickManager.ts → TickManager/TickManager.ts} +2 -2
  110. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +591 -0
  111. package/src/lib/editor/managers/{UserPreferencesManager.ts → UserPreferencesManager/UserPreferencesManager.ts} +2 -2
  112. package/src/lib/editor/shapes/ShapeUtil.ts +1 -1
  113. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -1
  114. package/src/lib/exports/getSvgJsx.tsx +1 -1
  115. package/src/lib/primitives/Box.test.ts +588 -7
  116. package/src/lib/primitives/Box.ts +33 -41
  117. package/src/lib/utils/areShapesContentEqual.ts +1 -2
  118. package/src/lib/utils/reorderShapes.ts +10 -13
  119. package/src/lib/utils/richText.ts +10 -4
  120. package/src/version.ts +3 -3
  121. package/dist-cjs/lib/editor/managers/ClickManager.js.map +0 -7
  122. package/dist-cjs/lib/editor/managers/EdgeScrollManager.js.map +0 -7
  123. package/dist-cjs/lib/editor/managers/FocusManager.js.map +0 -7
  124. package/dist-cjs/lib/editor/managers/FontManager.js.map +0 -7
  125. package/dist-cjs/lib/editor/managers/HistoryManager.js.map +0 -7
  126. package/dist-cjs/lib/editor/managers/ScribbleManager.js.map +0 -7
  127. package/dist-cjs/lib/editor/managers/Stack.js +0 -82
  128. package/dist-cjs/lib/editor/managers/Stack.js.map +0 -7
  129. package/dist-cjs/lib/editor/managers/TextManager.js.map +0 -7
  130. package/dist-cjs/lib/editor/managers/TickManager.js.map +0 -7
  131. package/dist-cjs/lib/editor/managers/UserPreferencesManager.js.map +0 -7
  132. package/dist-esm/lib/editor/managers/ClickManager.mjs.map +0 -7
  133. package/dist-esm/lib/editor/managers/EdgeScrollManager.mjs.map +0 -7
  134. package/dist-esm/lib/editor/managers/FocusManager.mjs.map +0 -7
  135. package/dist-esm/lib/editor/managers/FontManager.mjs.map +0 -7
  136. package/dist-esm/lib/editor/managers/HistoryManager.mjs.map +0 -7
  137. package/dist-esm/lib/editor/managers/ScribbleManager.mjs.map +0 -7
  138. package/dist-esm/lib/editor/managers/Stack.mjs +0 -62
  139. package/dist-esm/lib/editor/managers/Stack.mjs.map +0 -7
  140. package/dist-esm/lib/editor/managers/TextManager.mjs.map +0 -7
  141. package/dist-esm/lib/editor/managers/TickManager.mjs.map +0 -7
  142. package/dist-esm/lib/editor/managers/UserPreferencesManager.mjs.map +0 -7
  143. package/src/lib/editor/managers/ScribbleManager.test.ts +0 -32
  144. package/src/lib/editor/managers/Stack.ts +0 -71
  145. /package/dist-cjs/lib/editor/managers/{FocusManager.js → FocusManager/FocusManager.js} +0 -0
  146. /package/dist-cjs/lib/editor/managers/{TextManager.js → TextManager/TextManager.js} +0 -0
  147. /package/dist-esm/lib/editor/managers/{FocusManager.mjs → FocusManager/FocusManager.mjs} +0 -0
  148. /package/dist-esm/lib/editor/managers/{TextManager.mjs → TextManager/TextManager.mjs} +0 -0
@@ -148,16 +148,16 @@ import { bindingsIndex } from './derivations/bindingsIndex'
148
148
  import { notVisibleShapes } from './derivations/notVisibleShapes'
149
149
  import { parentsToChildren } from './derivations/parentsToChildren'
150
150
  import { deriveShapeIdsInCurrentPage } from './derivations/shapeIdsInCurrentPage'
151
- import { ClickManager } from './managers/ClickManager'
152
- import { EdgeScrollManager } from './managers/EdgeScrollManager'
153
- import { FocusManager } from './managers/FocusManager'
154
- import { FontManager } from './managers/FontManager'
155
- import { HistoryManager } from './managers/HistoryManager'
156
- import { ScribbleManager } from './managers/ScribbleManager'
151
+ import { ClickManager } from './managers/ClickManager/ClickManager'
152
+ import { EdgeScrollManager } from './managers/EdgeScrollManager/EdgeScrollManager'
153
+ import { FocusManager } from './managers/FocusManager/FocusManager'
154
+ import { FontManager } from './managers/FontManager/FontManager'
155
+ import { HistoryManager } from './managers/HistoryManager/HistoryManager'
156
+ import { ScribbleManager } from './managers/ScribbleManager/ScribbleManager'
157
157
  import { SnapManager } from './managers/SnapManager/SnapManager'
158
- import { TextManager } from './managers/TextManager'
159
- import { TickManager } from './managers/TickManager'
160
- import { UserPreferencesManager } from './managers/UserPreferencesManager'
158
+ import { TextManager } from './managers/TextManager/TextManager'
159
+ import { TickManager } from './managers/TickManager/TickManager'
160
+ import { UserPreferencesManager } from './managers/UserPreferencesManager/UserPreferencesManager'
161
161
  import { ShapeUtil, TLGeometryOpts, TLResizeMode } from './shapes/ShapeUtil'
162
162
  import { RootState } from './tools/RootState'
163
163
  import { StateNode, TLStateNodeConstructor } from './tools/StateNode'
@@ -328,7 +328,7 @@ export class Editor extends EventEmitter<TLEventMap> {
328
328
  this.store = store
329
329
  this.history = new HistoryManager<TLRecord>({
330
330
  store,
331
- annotateError: (error) => {
331
+ annotateError: (error: any) => {
332
332
  this.annotateError(error, { origin: 'history.batch', willCrashApp: true })
333
333
  this.crash(error)
334
334
  },
@@ -506,14 +506,13 @@ export class Editor extends EventEmitter<TLEventMap> {
506
506
  shape: {
507
507
  afterChange: (shapeBefore, shapeAfter) => {
508
508
  for (const binding of this.getBindingsInvolvingShape(shapeAfter)) {
509
- if (areShapesContentEqual(shapeBefore, shapeAfter)) continue
510
-
511
509
  invalidBindingTypes.add(binding.type)
512
510
  if (binding.fromId === shapeAfter.id) {
513
511
  this.getBindingUtil(binding).onAfterChangeFromShape?.({
514
512
  binding,
515
513
  shapeBefore,
516
514
  shapeAfter,
515
+ reason: 'self',
517
516
  })
518
517
  }
519
518
  if (binding.toId === shapeAfter.id) {
@@ -521,6 +520,7 @@ export class Editor extends EventEmitter<TLEventMap> {
521
520
  binding,
522
521
  shapeBefore,
523
522
  shapeAfter,
523
+ reason: 'self',
524
524
  })
525
525
  }
526
526
  }
@@ -539,6 +539,7 @@ export class Editor extends EventEmitter<TLEventMap> {
539
539
  binding,
540
540
  shapeBefore: descendantShape,
541
541
  shapeAfter: descendantShape,
542
+ reason: 'ancestry',
542
543
  })
543
544
  }
544
545
  if (binding.toId === descendantShape.id) {
@@ -546,6 +547,7 @@ export class Editor extends EventEmitter<TLEventMap> {
546
547
  binding,
547
548
  shapeBefore: descendantShape,
548
549
  shapeAfter: descendantShape,
550
+ reason: 'ancestry',
549
551
  })
550
552
  }
551
553
  }
@@ -3717,10 +3719,7 @@ export class Editor extends EventEmitter<TLEventMap> {
3717
3719
  */
3718
3720
  @computed getViewportScreenCenter() {
3719
3721
  const viewportScreenBounds = this.getViewportScreenBounds()
3720
- return new Vec(
3721
- viewportScreenBounds.midX - viewportScreenBounds.minX,
3722
- viewportScreenBounds.midY - viewportScreenBounds.minY
3723
- )
3722
+ return new Vec(viewportScreenBounds.w / 2, viewportScreenBounds.h / 2)
3724
3723
  }
3725
3724
 
3726
3725
  /**
@@ -4646,44 +4645,6 @@ export class Editor extends EventEmitter<TLEventMap> {
4646
4645
  )! as T
4647
4646
  }
4648
4647
 
4649
- private _shapePageGeometryCaches: Record<string, ComputedCache<Geometry2d, TLShape>> = {}
4650
-
4651
- /**
4652
- * Get the geometry of a shape in page-space.
4653
- *
4654
- * @example
4655
- * ```ts
4656
- * editor.getShapePageGeometry(myShape)
4657
- * editor.getShapePageGeometry(myShapeId)
4658
- * editor.getShapePageGeometry(myShapeId, { context: "arrow" })
4659
- * ```
4660
- *
4661
- * @param shape - The shape (or shape id) to get the geometry for.
4662
- * @param opts - Additional options about the request for geometry. Passed to {@link ShapeUtil.getGeometry}.
4663
- *
4664
- * @public
4665
- */
4666
- getShapePageGeometry<T extends Geometry2d>(shape: TLShape | TLShapeId, opts?: TLGeometryOpts): T {
4667
- const context = opts?.context ?? 'none'
4668
- if (!this._shapePageGeometryCaches[context]) {
4669
- this._shapePageGeometryCaches[context] = this.store.createComputedCache(
4670
- 'bounds',
4671
- (shape) => {
4672
- const geometry = this.getShapeGeometry(shape.id, opts)
4673
- const pageTransform = this.getShapePageTransform(shape.id)
4674
- return geometry.transform(pageTransform)
4675
- },
4676
- {
4677
- // we only depend directly on the shape id, and changing geometry/transform will update us anyway
4678
- areRecordsEqual: () => true,
4679
- }
4680
- )
4681
- }
4682
- return this._shapePageGeometryCaches[context].get(
4683
- typeof shape === 'string' ? shape : shape.id
4684
- )! as T
4685
- }
4686
-
4687
4648
  /** @internal */
4688
4649
  @computed private _getShapeHandlesCache(): ComputedCache<TLHandle[] | undefined, TLShape> {
4689
4650
  return this.store.createComputedCache(
@@ -4796,7 +4757,10 @@ export class Editor extends EventEmitter<TLEventMap> {
4796
4757
  /** @internal */
4797
4758
  @computed private _getShapePageBoundsCache(): ComputedCache<Box, TLShape> {
4798
4759
  return this.store.createComputedCache<Box, TLShape>('pageBoundsCache', (shape) => {
4799
- return this.getShapePageGeometry(shape).bounds
4760
+ const pageTransform = this.getShapePageTransform(shape)
4761
+ if (!pageTransform) return undefined
4762
+ const geometry = this.getShapeGeometry(shape)
4763
+ return Box.FromPoints(pageTransform.applyToPoints(geometry.vertices))
4800
4764
  })
4801
4765
  }
4802
4766
 
@@ -4870,11 +4834,12 @@ export class Editor extends EventEmitter<TLEventMap> {
4870
4834
  if (frameAncestors.length === 0) return undefined
4871
4835
 
4872
4836
  const pageMask = frameAncestors
4873
- .map<Vec[] | undefined>(
4874
- (s) =>
4875
- // Apply the frame transform to the frame outline to get the frame outline in the current page space
4876
- this.getShapePageGeometry(s.id).vertices
4877
- )
4837
+ .map<Vec[] | undefined>((s) => {
4838
+ // Apply the frame transform to the frame outline to get the frame outline in the current page space
4839
+ const geometry = this.getShapeGeometry(s.id)
4840
+ const pageTransform = this.getShapePageTransform(s.id)
4841
+ return pageTransform.applyToPoints(geometry.vertices)
4842
+ })
4878
4843
  .reduce((acc, b) => {
4879
4844
  if (!(b && acc)) return undefined
4880
4845
  const intersection = intersectPolygonPolygon(acc, b)
@@ -5072,28 +5037,33 @@ export class Editor extends EventEmitter<TLEventMap> {
5072
5037
  *
5073
5038
  * @public
5074
5039
  */
5075
- isShapeOrAncestorLocked(shape?: TLShape): boolean
5076
- isShapeOrAncestorLocked(id?: TLShapeId): boolean
5077
- isShapeOrAncestorLocked(arg?: TLShape | TLShapeId): boolean {
5078
- const shape = typeof arg === 'string' ? this.getShape(arg) : arg
5079
- if (shape === undefined) return false
5080
- if (shape.isLocked) return true
5081
- return this.isShapeOrAncestorLocked(this.getShapeParent(shape))
5040
+ isShapeOrAncestorLocked(shape?: TLShape | TLShapeId): boolean {
5041
+ const _shape = shape && this.getShape(shape)
5042
+ if (_shape === undefined) return false
5043
+ if (_shape.isLocked) return true
5044
+ return this.isShapeOrAncestorLocked(this.getShapeParent(_shape))
5082
5045
  }
5083
5046
 
5047
+ /**
5048
+ * Get shapes that are outside of the viewport.
5049
+ *
5050
+ * @public
5051
+ */
5084
5052
  @computed
5085
- private _notVisibleShapes() {
5086
- return notVisibleShapes(this)
5053
+ getNotVisibleShapes() {
5054
+ return this._notVisibleShapes.get()
5087
5055
  }
5088
5056
 
5057
+ private _notVisibleShapes = notVisibleShapes(this)
5058
+
5089
5059
  /**
5090
- * Get culled shapes.
5060
+ * Get culled shapes (those that should not render), taking into account which shapes are selected or editing.
5091
5061
  *
5092
5062
  * @public
5093
5063
  */
5094
5064
  @computed
5095
5065
  getCulledShapes() {
5096
- const notVisibleShapes = this._notVisibleShapes().get()
5066
+ const notVisibleShapes = this.getNotVisibleShapes()
5097
5067
  const selectedShapeIds = this.getSelectedShapeIds()
5098
5068
  const editingId = this.getEditingShapeId()
5099
5069
  const culledShapes = new Set<TLShapeId>(notVisibleShapes)
@@ -5342,21 +5312,23 @@ export class Editor extends EventEmitter<TLEventMap> {
5342
5312
  * @example
5343
5313
  * ```ts
5344
5314
  * editor.getShapesAtPoint({ x: 100, y: 100 })
5345
- * editor.getShapesAtPoint({ x: 100, y: 100 }, { hitInside: true, exact: true })
5315
+ * editor.getShapesAtPoint({ x: 100, y: 100 }, { hitInside: true, margin: 8 })
5346
5316
  * ```
5347
5317
  *
5348
5318
  * @param point - The page point to test.
5349
5319
  * @param opts - The options for the hit point testing.
5350
5320
  *
5321
+ * @returns An array of shapes at the given point, sorted in reverse order of their absolute z-index (top-most shape first).
5322
+ *
5351
5323
  * @public
5352
5324
  */
5353
5325
  getShapesAtPoint(
5354
5326
  point: VecLike,
5355
5327
  opts = {} as { margin?: number; hitInside?: boolean }
5356
5328
  ): TLShape[] {
5357
- return this.getCurrentPageShapes().filter(
5358
- (shape) => !this.isShapeHidden(shape) && this.isPointInShape(shape, point, opts)
5359
- )
5329
+ return this.getCurrentPageShapesSorted()
5330
+ .filter((shape) => !this.isShapeHidden(shape) && this.isPointInShape(shape, point, opts))
5331
+ .reverse()
5360
5332
  }
5361
5333
 
5362
5334
  /**
@@ -9305,6 +9277,7 @@ export class Editor extends EventEmitter<TLEventMap> {
9305
9277
  if (rootShapes.length === 1) {
9306
9278
  const onlyRoot = rootShapes[0] as TLFrameShape
9307
9279
  // If the old bounds are in the viewport...
9280
+ // todo: replace frame references with shapes that can accept children
9308
9281
  if (this.isShapeOfType<TLFrameShape>(onlyRoot, 'frame')) {
9309
9282
  while (
9310
9283
  this.getShapesAtPoint(point).some(
@@ -62,6 +62,12 @@ export interface BindingOnShapeChangeOptions<Binding extends TLUnknownBinding> {
62
62
  shapeBefore: TLShape
63
63
  /** The shape record after the change is made. */
64
64
  shapeAfter: TLShape
65
+ /**
66
+ * Why did this shape change?
67
+ * - 'self': the shape itself changed
68
+ * - 'ancestry': the ancestry of the shape changed, but the shape itself may not have done
69
+ */
70
+ reason: 'self' | 'ancestry'
65
71
  }
66
72
 
67
73
  /**
@@ -1,41 +1,42 @@
1
1
  import { Computed, RESET_VALUE, computed, isUninitialized } from '@tldraw/state'
2
- import { TLBinding, TLShapeId } from '@tldraw/tlschema'
2
+ import { TLArrowBinding, TLBinding, TLShapeId, TLUnknownBinding } from '@tldraw/tlschema'
3
3
  import { objectMapValues } from '@tldraw/utils'
4
4
  import { Editor } from '../Editor'
5
5
 
6
6
  type TLBindingsIndex = Map<TLShapeId, TLBinding[]>
7
7
 
8
- export const bindingsIndex = (editor: Editor): Computed<TLBindingsIndex> => {
9
- const { store } = editor
10
- const bindingsHistory = store.query.filterHistory('binding')
11
- const bindingsQuery = store.query.records('binding')
12
- function fromScratch() {
13
- const allBindings = bindingsQuery.get() as TLBinding[]
8
+ function fromScratch(bindingsQuery: Computed<(TLArrowBinding | TLUnknownBinding)[], unknown>) {
9
+ const allBindings = bindingsQuery.get() as TLBinding[]
14
10
 
15
- const shape2Binding: TLBindingsIndex = new Map()
11
+ const shapesToBindings: TLBindingsIndex = new Map()
16
12
 
17
- for (const binding of allBindings) {
18
- const { fromId, toId } = binding
19
- const bindingsForFromShape = shape2Binding.get(fromId)
20
- if (!bindingsForFromShape) {
21
- shape2Binding.set(fromId, [binding])
22
- } else {
23
- bindingsForFromShape.push(binding)
24
- }
25
- const bindingsForToShape = shape2Binding.get(toId)
26
- if (!bindingsForToShape) {
27
- shape2Binding.set(toId, [binding])
28
- } else {
29
- bindingsForToShape.push(binding)
30
- }
13
+ for (const binding of allBindings) {
14
+ const { fromId, toId } = binding
15
+ const bindingsForFromShape = shapesToBindings.get(fromId)
16
+ if (!bindingsForFromShape) {
17
+ shapesToBindings.set(fromId, [binding])
18
+ } else {
19
+ bindingsForFromShape.push(binding)
20
+ }
21
+ const bindingsForToShape = shapesToBindings.get(toId)
22
+ if (!bindingsForToShape) {
23
+ shapesToBindings.set(toId, [binding])
24
+ } else {
25
+ bindingsForToShape.push(binding)
31
26
  }
32
-
33
- return shape2Binding
34
27
  }
35
28
 
29
+ return shapesToBindings
30
+ }
31
+
32
+ export const bindingsIndex = (editor: Editor): Computed<TLBindingsIndex> => {
33
+ const { store } = editor
34
+ const bindingsHistory = store.query.filterHistory('binding')
35
+ const bindingsQuery = store.query.records('binding')
36
+
36
37
  return computed<TLBindingsIndex>('arrowBindingsIndex', (_lastValue, lastComputedEpoch) => {
37
38
  if (isUninitialized(_lastValue)) {
38
- return fromScratch()
39
+ return fromScratch(bindingsQuery)
39
40
  }
40
41
 
41
42
  const lastValue = _lastValue
@@ -43,7 +44,7 @@ export const bindingsIndex = (editor: Editor): Computed<TLBindingsIndex> => {
43
44
  const diff = bindingsHistory.getDiffSince(lastComputedEpoch)
44
45
 
45
46
  if (diff === RESET_VALUE) {
46
- return fromScratch()
47
+ return fromScratch(bindingsQuery)
47
48
  }
48
49
 
49
50
  let nextValue: TLBindingsIndex | undefined = undefined
@@ -1,45 +1,48 @@
1
- import { computed, isUninitialized, RESET_VALUE } from '@tldraw/state'
2
- import { RecordsDiff } from '@tldraw/store'
1
+ import { Computed, computed, isUninitialized, RESET_VALUE } from '@tldraw/state'
2
+ import { CollectionDiff, RecordsDiff } from '@tldraw/store'
3
3
  import { isShape, TLParentId, TLRecord, TLShape, TLShapeId, TLStore } from '@tldraw/tlschema'
4
4
  import { compact, sortByIndex } from '@tldraw/utils'
5
5
 
6
- type Parents2Children = Record<TLParentId, TLShapeId[]>
6
+ type ParentShapeIdsToChildShapeIds = Record<TLParentId, TLShapeId[]>
7
7
 
8
- export const parentsToChildren = (store: TLStore) => {
9
- const shapeIdsQuery = store.query.ids<'shape'>('shape')
10
- const shapeHistory = store.query.filterHistory('shape')
8
+ function fromScratch(
9
+ shapeIdsQuery: Computed<Set<TLShapeId>, CollectionDiff<TLShapeId>>,
10
+ store: TLStore
11
+ ) {
12
+ const result: ParentShapeIdsToChildShapeIds = {}
13
+ const shapeIds = shapeIdsQuery.get()
14
+ const shapes = Array(shapeIds.size) as TLShape[]
15
+ shapeIds.forEach((id) => shapes.push(store.get(id)!))
11
16
 
12
- function fromScratch() {
13
- const result: Parents2Children = {}
14
- const shapeIds = shapeIdsQuery.get()
15
- const shapes = Array(shapeIds.size) as TLShape[]
16
- shapeIds.forEach((id) => shapes.push(store.get(id)!))
17
+ // Sort the shapes by index
18
+ shapes.sort(sortByIndex)
17
19
 
18
- // Sort the shapes by index
19
- shapes.sort(sortByIndex)
20
+ // Populate the result object with an array for each parent.
21
+ shapes.forEach((shape) => {
22
+ if (!result[shape.parentId]) {
23
+ result[shape.parentId] = []
24
+ }
25
+ result[shape.parentId].push(shape.id)
26
+ })
20
27
 
21
- // Populate the result object with an array for each parent.
22
- shapes.forEach((shape) => {
23
- if (!result[shape.parentId]) {
24
- result[shape.parentId] = []
25
- }
26
- result[shape.parentId].push(shape.id)
27
- })
28
+ return result
29
+ }
28
30
 
29
- return result
30
- }
31
+ export const parentsToChildren = (store: TLStore) => {
32
+ const shapeIdsQuery = store.query.ids<'shape'>('shape')
33
+ const shapeHistory = store.query.filterHistory('shape')
31
34
 
32
- return computed<Parents2Children>(
35
+ return computed<ParentShapeIdsToChildShapeIds>(
33
36
  'parentsToChildrenWithIndexes',
34
37
  (lastValue, lastComputedEpoch) => {
35
38
  if (isUninitialized(lastValue)) {
36
- return fromScratch()
39
+ return fromScratch(shapeIdsQuery, store)
37
40
  }
38
41
 
39
42
  const diff = shapeHistory.getDiffSince(lastComputedEpoch)
40
43
 
41
44
  if (diff === RESET_VALUE) {
42
- return fromScratch()
45
+ return fromScratch(shapeIdsQuery, store)
43
46
  }
44
47
 
45
48
  if (diff.length === 0) return lastValue