@tldraw/editor 4.3.0-next.82cfddd7ee89 → 4.3.0-next.842fb21476f2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/dist-cjs/index.d.ts +498 -155
  2. package/dist-cjs/index.js +6 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/components/ErrorBoundary.js.map +1 -1
  5. package/dist-cjs/lib/components/GeometryDebuggingView.js +1 -17
  6. package/dist-cjs/lib/components/GeometryDebuggingView.js.map +2 -2
  7. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +3 -3
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  9. package/dist-cjs/lib/constants.js +1 -3
  10. package/dist-cjs/lib/constants.js.map +2 -2
  11. package/dist-cjs/lib/editor/Editor.js +292 -286
  12. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  13. package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +2 -2
  14. package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
  15. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +18 -17
  16. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +3 -3
  17. package/dist-cjs/lib/editor/derivations/parentsToChildren.js +12 -3
  18. package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
  19. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +1 -1
  20. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
  21. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +5 -6
  22. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
  23. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +591 -0
  24. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +7 -0
  25. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +1 -1
  26. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
  27. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +1 -22
  28. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
  29. package/dist-cjs/lib/editor/shapes/BaseBoxShapeUtil.js.map +1 -1
  30. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +31 -23
  31. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  32. package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js +1 -1
  33. package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js.map +2 -2
  34. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  35. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.js.map +2 -2
  36. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +3 -3
  37. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
  38. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  39. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  40. package/dist-cjs/lib/exports/parseCss.js +1 -1
  41. package/dist-cjs/lib/exports/parseCss.js.map +2 -2
  42. package/dist-cjs/lib/globals/environment.js +45 -9
  43. package/dist-cjs/lib/globals/environment.js.map +2 -2
  44. package/dist-cjs/lib/globals/menus.js +1 -1
  45. package/dist-cjs/lib/globals/menus.js.map +2 -2
  46. package/dist-cjs/lib/hooks/useCoarsePointer.js +14 -29
  47. package/dist-cjs/lib/hooks/useCoarsePointer.js.map +2 -2
  48. package/dist-cjs/lib/hooks/useEvent.js +1 -1
  49. package/dist-cjs/lib/hooks/useEvent.js.map +2 -2
  50. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
  51. package/dist-cjs/lib/hooks/useGestureEvents.js +1 -1
  52. package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
  53. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
  54. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
  55. package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
  56. package/dist-cjs/lib/hooks/useStateAttribute.js +4 -1
  57. package/dist-cjs/lib/hooks/useStateAttribute.js.map +2 -2
  58. package/dist-cjs/lib/hooks/useTransform.js.map +1 -1
  59. package/dist-cjs/lib/hooks/useZoomCss.js +4 -8
  60. package/dist-cjs/lib/hooks/useZoomCss.js.map +2 -2
  61. package/dist-cjs/lib/options.js +6 -1
  62. package/dist-cjs/lib/options.js.map +2 -2
  63. package/dist-cjs/lib/primitives/Box.js +3 -0
  64. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  65. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +1 -0
  66. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  67. package/dist-cjs/lib/utils/reparenting.js.map +2 -2
  68. package/dist-cjs/lib/utils/rotation.js +1 -1
  69. package/dist-cjs/lib/utils/rotation.js.map +2 -2
  70. package/dist-cjs/version.js +3 -3
  71. package/dist-cjs/version.js.map +1 -1
  72. package/dist-esm/index.d.mts +498 -155
  73. package/dist-esm/index.mjs +7 -2
  74. package/dist-esm/index.mjs.map +2 -2
  75. package/dist-esm/lib/components/ErrorBoundary.mjs.map +1 -1
  76. package/dist-esm/lib/components/GeometryDebuggingView.mjs +1 -17
  77. package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +2 -2
  78. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +3 -3
  79. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  80. package/dist-esm/lib/constants.mjs +1 -3
  81. package/dist-esm/lib/constants.mjs.map +2 -2
  82. package/dist-esm/lib/editor/Editor.mjs +293 -289
  83. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  84. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +2 -2
  85. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
  86. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +18 -17
  87. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +3 -3
  88. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +13 -4
  89. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
  90. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +1 -1
  91. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
  92. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +5 -6
  93. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
  94. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +573 -0
  95. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +7 -0
  96. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +1 -1
  97. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
  98. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +1 -22
  99. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
  100. package/dist-esm/lib/editor/shapes/BaseBoxShapeUtil.mjs.map +1 -1
  101. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +31 -23
  102. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  103. package/dist-esm/lib/editor/shapes/group/DashedOutlineBox.mjs +1 -1
  104. package/dist-esm/lib/editor/shapes/group/DashedOutlineBox.mjs.map +2 -2
  105. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  106. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.mjs.map +2 -2
  107. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +3 -3
  108. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
  109. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  110. package/dist-esm/lib/exports/parseCss.mjs +1 -1
  111. package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
  112. package/dist-esm/lib/globals/environment.mjs +45 -9
  113. package/dist-esm/lib/globals/environment.mjs.map +2 -2
  114. package/dist-esm/lib/globals/menus.mjs +1 -1
  115. package/dist-esm/lib/globals/menus.mjs.map +2 -2
  116. package/dist-esm/lib/hooks/useCoarsePointer.mjs +15 -30
  117. package/dist-esm/lib/hooks/useCoarsePointer.mjs.map +2 -2
  118. package/dist-esm/lib/hooks/useEvent.mjs +1 -1
  119. package/dist-esm/lib/hooks/useEvent.mjs.map +2 -2
  120. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
  121. package/dist-esm/lib/hooks/useGestureEvents.mjs +1 -1
  122. package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
  123. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
  124. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
  125. package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
  126. package/dist-esm/lib/hooks/useStateAttribute.mjs +4 -1
  127. package/dist-esm/lib/hooks/useStateAttribute.mjs.map +2 -2
  128. package/dist-esm/lib/hooks/useTransform.mjs.map +1 -1
  129. package/dist-esm/lib/hooks/useZoomCss.mjs +4 -8
  130. package/dist-esm/lib/hooks/useZoomCss.mjs.map +2 -2
  131. package/dist-esm/lib/options.mjs +6 -1
  132. package/dist-esm/lib/options.mjs.map +2 -2
  133. package/dist-esm/lib/primitives/Box.mjs +3 -0
  134. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  135. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +1 -0
  136. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  137. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  138. package/dist-esm/lib/utils/rotation.mjs +1 -1
  139. package/dist-esm/lib/utils/rotation.mjs.map +2 -2
  140. package/dist-esm/version.mjs +3 -3
  141. package/dist-esm/version.mjs.map +1 -1
  142. package/editor.css +14 -12
  143. package/package.json +18 -16
  144. package/src/index.ts +4 -1
  145. package/src/lib/components/ErrorBoundary.tsx +1 -1
  146. package/src/lib/components/GeometryDebuggingView.tsx +1 -19
  147. package/src/lib/components/default-components/DefaultCanvas.tsx +4 -3
  148. package/src/lib/config/TLUserPreferences.test.ts +40 -0
  149. package/src/lib/constants.ts +0 -2
  150. package/src/lib/editor/Editor.test.ts +150 -10
  151. package/src/lib/editor/Editor.ts +459 -379
  152. package/src/lib/editor/bindings/BindingUtil.ts +15 -9
  153. package/src/lib/editor/derivations/bindingsIndex.ts +2 -2
  154. package/src/lib/editor/derivations/notVisibleShapes.ts +37 -23
  155. package/src/lib/editor/derivations/parentsToChildren.ts +18 -7
  156. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +17 -31
  157. package/src/lib/editor/managers/ClickManager/ClickManager.ts +1 -1
  158. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +129 -79
  159. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +10 -6
  160. package/src/lib/editor/managers/FontManager/FontManager.test.ts +14 -4
  161. package/src/lib/editor/managers/InputsManager/InputsManager.ts +566 -0
  162. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +0 -4
  163. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +12 -0
  164. package/src/lib/editor/managers/SnapManager/SnapManager.ts +4 -4
  165. package/src/lib/editor/managers/TickManager/TickManager.test.ts +40 -107
  166. package/src/lib/editor/managers/TickManager/TickManager.ts +2 -32
  167. package/src/lib/editor/shapes/BaseBoxShapeUtil.tsx +2 -2
  168. package/src/lib/editor/shapes/ShapeUtil.ts +72 -32
  169. package/src/lib/editor/shapes/group/DashedOutlineBox.tsx +1 -1
  170. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -3
  171. package/src/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.ts +2 -1
  172. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +6 -6
  173. package/src/lib/editor/types/emit-types.ts +3 -1
  174. package/src/lib/exports/getSvgJsx.test.ts +10 -19
  175. package/src/lib/exports/getSvgJsx.tsx +2 -5
  176. package/src/lib/exports/parseCss.test.ts +1 -0
  177. package/src/lib/exports/parseCss.ts +1 -1
  178. package/src/lib/globals/environment.ts +65 -10
  179. package/src/lib/globals/menus.ts +1 -1
  180. package/src/lib/hooks/useCoarsePointer.ts +16 -59
  181. package/src/lib/hooks/useEvent.tsx +1 -1
  182. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -1
  183. package/src/lib/hooks/useGestureEvents.ts +2 -2
  184. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +1 -1
  185. package/src/lib/hooks/usePassThroughWheelEvents.ts +1 -1
  186. package/src/lib/hooks/useScreenBounds.ts +1 -1
  187. package/src/lib/hooks/useStateAttribute.ts +4 -1
  188. package/src/lib/hooks/useTransform.ts +1 -1
  189. package/src/lib/hooks/useZoomCss.ts +3 -8
  190. package/src/lib/options.ts +32 -0
  191. package/src/lib/primitives/Box.ts +9 -0
  192. package/src/lib/primitives/geometry/Geometry2d.ts +1 -0
  193. package/src/lib/utils/reparenting.ts +5 -5
  194. package/src/lib/utils/rotation.ts +1 -1
  195. package/src/version.ts +3 -3
@@ -1,9 +1,15 @@
1
- import { RecordProps, TLPropsMigrations, TLShape, TLUnknownBinding } from '@tldraw/tlschema'
1
+ import {
2
+ RecordProps,
3
+ TLBinding,
4
+ TLPropsMigrations,
5
+ TLShape,
6
+ TLUnknownBinding,
7
+ } from '@tldraw/tlschema'
2
8
  import { Editor } from '../Editor'
3
9
 
4
10
  /** @public */
5
11
  export interface TLBindingUtilConstructor<
6
- T extends TLUnknownBinding,
12
+ T extends TLBinding,
7
13
  U extends BindingUtil<T> = BindingUtil<T>,
8
14
  > {
9
15
  new (editor: Editor): U
@@ -20,7 +26,7 @@ export interface TLBindingUtilConstructor<
20
26
  *
21
27
  * @public
22
28
  */
23
- export interface BindingOnCreateOptions<Binding extends TLUnknownBinding> {
29
+ export interface BindingOnCreateOptions<Binding extends TLBinding = TLBinding> {
24
30
  /** The binding being created. */
25
31
  binding: Binding
26
32
  }
@@ -31,7 +37,7 @@ export interface BindingOnCreateOptions<Binding extends TLUnknownBinding> {
31
37
  *
32
38
  * @public
33
39
  */
34
- export interface BindingOnChangeOptions<Binding extends TLUnknownBinding> {
40
+ export interface BindingOnChangeOptions<Binding extends TLBinding = TLBinding> {
35
41
  /** The binding record before the change is made. */
36
42
  bindingBefore: Binding
37
43
  /** The binding record after the change is made. */
@@ -44,7 +50,7 @@ export interface BindingOnChangeOptions<Binding extends TLUnknownBinding> {
44
50
  *
45
51
  * @public
46
52
  */
47
- export interface BindingOnDeleteOptions<Binding extends TLUnknownBinding> {
53
+ export interface BindingOnDeleteOptions<Binding extends TLBinding = TLBinding> {
48
54
  /** The binding being deleted. */
49
55
  binding: Binding
50
56
  }
@@ -55,7 +61,7 @@ export interface BindingOnDeleteOptions<Binding extends TLUnknownBinding> {
55
61
  *
56
62
  * @public
57
63
  */
58
- export interface BindingOnShapeChangeOptions<Binding extends TLUnknownBinding> {
64
+ export interface BindingOnShapeChangeOptions<Binding extends TLBinding = TLBinding> {
59
65
  /** The binding record linking these two shapes. */
60
66
  binding: Binding
61
67
  /** The shape record before the change is made. */
@@ -95,7 +101,7 @@ export interface BindingOnShapeChangeOptions<Binding extends TLUnknownBinding> {
95
101
  *
96
102
  * @public
97
103
  */
98
- export interface BindingOnShapeIsolateOptions<Binding extends TLUnknownBinding> {
104
+ export interface BindingOnShapeIsolateOptions<Binding extends TLBinding = TLBinding> {
99
105
  /** The binding record that refers to the shape in question. */
100
106
  binding: Binding
101
107
  /**
@@ -114,7 +120,7 @@ export interface BindingOnShapeIsolateOptions<Binding extends TLUnknownBinding>
114
120
  *
115
121
  * @public
116
122
  */
117
- export interface BindingOnShapeDeleteOptions<Binding extends TLUnknownBinding> {
123
+ export interface BindingOnShapeDeleteOptions<Binding extends TLBinding = TLBinding> {
118
124
  /** The binding record that refers to the shape in question. */
119
125
  binding: Binding
120
126
  /** The shape that is about to be deleted. */
@@ -122,7 +128,7 @@ export interface BindingOnShapeDeleteOptions<Binding extends TLUnknownBinding> {
122
128
  }
123
129
 
124
130
  /** @public */
125
- export abstract class BindingUtil<Binding extends TLUnknownBinding = TLUnknownBinding> {
131
+ export abstract class BindingUtil<Binding extends TLBinding = TLBinding> {
126
132
  constructor(public editor: Editor) {}
127
133
  static props?: RecordProps<TLUnknownBinding>
128
134
  static migrations?: TLPropsMigrations
@@ -1,11 +1,11 @@
1
1
  import { Computed, RESET_VALUE, computed, isUninitialized } from '@tldraw/state'
2
- import { TLArrowBinding, TLBinding, TLShapeId, TLUnknownBinding } from '@tldraw/tlschema'
2
+ import { TLBinding, TLShapeId } 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
- function fromScratch(bindingsQuery: Computed<(TLArrowBinding | TLUnknownBinding)[], unknown>) {
8
+ function fromScratch(bindingsQuery: Computed<TLBinding[], unknown>) {
9
9
  const allBindings = bindingsQuery.get() as TLBinding[]
10
10
 
11
11
  const shapesToBindings: TLBindingsIndex = new Map()
@@ -2,29 +2,7 @@ import { computed, isUninitialized } from '@tldraw/state'
2
2
  import { TLShapeId } from '@tldraw/tlschema'
3
3
  import { Editor } from '../Editor'
4
4
 
5
- function fromScratch(editor: Editor): Set<TLShapeId> {
6
- const shapesIds = editor.getCurrentPageShapeIds()
7
- const viewportPageBounds = editor.getViewportPageBounds()
8
- const notVisibleShapes = new Set<TLShapeId>()
9
- shapesIds.forEach((id) => {
10
- const shape = editor.getShape(id)
11
- if (!shape) return
12
-
13
- const canCull = editor.getShapeUtil(shape.type).canCull(shape)
14
- if (!canCull) return
15
-
16
- // If the shape is fully outside of the viewport page bounds, add it to the set.
17
- // We'll ignore masks here, since they're more expensive to compute and the overhead is not worth it.
18
- const pageBounds = editor.getShapePageBounds(id)
19
- if (pageBounds === undefined || !viewportPageBounds.includes(pageBounds)) {
20
- notVisibleShapes.add(id)
21
- }
22
- })
23
- return notVisibleShapes
24
- }
25
-
26
5
  /**
27
- * Incremental derivation of not visible shapes.
28
6
  * Non visible shapes are shapes outside of the viewport page bounds.
29
7
  *
30
8
  * @param editor - Instance of the tldraw Editor.
@@ -32,7 +10,43 @@ function fromScratch(editor: Editor): Set<TLShapeId> {
32
10
  */
33
11
  export function notVisibleShapes(editor: Editor) {
34
12
  return computed<Set<TLShapeId>>('notVisibleShapes', function updateNotVisibleShapes(prevValue) {
35
- const nextValue = fromScratch(editor)
13
+ const shapeIds = editor.getCurrentPageShapeIds()
14
+ const nextValue = new Set<TLShapeId>()
15
+
16
+ // Extract viewport bounds once to avoid repeated property access
17
+ const viewportPageBounds = editor.getViewportPageBounds()
18
+ const viewMinX = viewportPageBounds.minX
19
+ const viewMinY = viewportPageBounds.minY
20
+ const viewMaxX = viewportPageBounds.maxX
21
+ const viewMaxY = viewportPageBounds.maxY
22
+
23
+ for (const id of shapeIds) {
24
+ const pageBounds = editor.getShapePageBounds(id)
25
+
26
+ // Hybrid check: if bounds exist and shape overlaps viewport, it's visible.
27
+ // This inlines Box.Collides to avoid function call overhead and the
28
+ // redundant Contains check that Box.Includes was doing.
29
+ if (
30
+ pageBounds !== undefined &&
31
+ pageBounds.maxX >= viewMinX &&
32
+ pageBounds.minX <= viewMaxX &&
33
+ pageBounds.maxY >= viewMinY &&
34
+ pageBounds.minY <= viewMaxY
35
+ ) {
36
+ continue
37
+ }
38
+
39
+ // Shape is outside viewport or has no bounds - check if it can be culled.
40
+ // We defer getShape and canCull checks until here since most shapes are
41
+ // typically visible and we can skip these calls for them.
42
+ const shape = editor.getShape(id)
43
+ if (!shape) continue
44
+
45
+ const canCull = editor.getShapeUtil(shape.type).canCull(shape)
46
+ if (!canCull) continue
47
+
48
+ nextValue.add(id)
49
+ }
36
50
 
37
51
  if (isUninitialized(prevValue)) {
38
52
  return nextValue
@@ -1,7 +1,7 @@
1
1
  import { Computed, computed, isUninitialized, RESET_VALUE } from '@tldraw/state'
2
2
  import { CollectionDiff, RecordsDiff } from '@tldraw/store'
3
- import { isShape, TLParentId, TLRecord, TLShapeId, TLStore } from '@tldraw/tlschema'
4
- import { compact, sortByIndex } from '@tldraw/utils'
3
+ import { isShape, TLParentId, TLRecord, TLShape, TLShapeId, TLStore } from '@tldraw/tlschema'
4
+ import { sortByIndex } from '@tldraw/utils'
5
5
 
6
6
  type ParentShapeIdsToChildShapeIds = Record<TLParentId, TLShapeId[]>
7
7
 
@@ -98,12 +98,23 @@ export const parentsToChildren = (store: TLStore) => {
98
98
  }
99
99
  }
100
100
 
101
- // Sort the arrays that have been marked for sorting
101
+ // Sort the arrays that have been marked for sorting (in-place to avoid intermediate arrays)
102
102
  for (const arr of toSort) {
103
- // It's possible that some of the shapes may be deleted. But in which case would this be so?
104
- const shapesInArr = compact(arr.map((id) => store.get(id)))
105
- shapesInArr.sort(sortByIndex)
106
- arr.splice(0, arr.length, ...shapesInArr.map((shape) => shape.id))
103
+ // Filter out any deleted shapes in-place
104
+ let writeIdx = 0
105
+ for (let readIdx = 0; readIdx < arr.length; readIdx++) {
106
+ if (store.get(arr[readIdx])) {
107
+ arr[writeIdx++] = arr[readIdx]
108
+ }
109
+ }
110
+ arr.length = writeIdx
111
+
112
+ // Sort in-place by index
113
+ arr.sort((a, b) => {
114
+ const shapeA = store.get(a) as TLShape
115
+ const shapeB = store.get(b) as TLShape
116
+ return sortByIndex(shapeA, shapeB)
117
+ })
107
118
  }
108
119
 
109
120
  return newValue ?? lastValue
@@ -1,4 +1,5 @@
1
1
  import { Mocked, vi } from 'vitest'
2
+ import { Vec } from '../../../primitives/Vec'
2
3
  import { Editor } from '../../Editor'
3
4
  import { TLClickEventInfo, TLPointerEventInfo } from '../../types/event-types'
4
5
  import { ClickManager } from './ClickManager'
@@ -35,6 +36,8 @@ describe('ClickManager', () => {
35
36
  setTimeout: vi.fn((fn, delay) => setTimeout(fn, delay)),
36
37
  }
37
38
 
39
+ const mockCurrentScreenPoint = new Vec(0, 0)
40
+
38
41
  editor = {
39
42
  timers: mockTimers,
40
43
  dispatch: vi.fn(),
@@ -45,7 +48,8 @@ describe('ClickManager', () => {
45
48
  coarseDragDistanceSquared: 36,
46
49
  },
47
50
  inputs: {
48
- currentScreenPoint: { x: 0, y: 0 },
51
+ getCurrentScreenPoint: vi.fn(() => mockCurrentScreenPoint),
52
+ currentScreenPoint: mockCurrentScreenPoint, // deprecated getter for compatibility
49
53
  },
50
54
  getInstanceState: vi.fn(() => ({
51
55
  isCoarsePointer: false,
@@ -321,8 +325,9 @@ describe('ClickManager', () => {
321
325
  const downEvent = createPointerEvent('pointer_down', { x: 0, y: 0 })
322
326
  const moveEvent = createPointerEvent('pointer_move', { x: 10, y: 10 })
323
327
 
324
- editor.inputs.currentScreenPoint.x = 10
325
- editor.inputs.currentScreenPoint.y = 10
328
+ const currentScreenPoint = editor.inputs.getCurrentScreenPoint()
329
+ currentScreenPoint.x = 10
330
+ currentScreenPoint.y = 10
326
331
 
327
332
  clickManager.handlePointerEvent(downEvent)
328
333
  expect(clickManager.clickState).toBe('pendingDouble')
@@ -347,13 +352,15 @@ describe('ClickManager', () => {
347
352
  expect(clickManager.clickState).toBe('pendingDouble')
348
353
 
349
354
  // Should not cancel for coarse pointer with small movement
350
- editor.inputs.currentScreenPoint.x = 1
351
- editor.inputs.currentScreenPoint.y = 1
355
+ const currentScreenPoint1 = editor.inputs.getCurrentScreenPoint()
356
+ currentScreenPoint1.x = 1
357
+ currentScreenPoint1.y = 1
352
358
  clickManager.handlePointerEvent(moveEvent1)
353
359
  expect(clickManager.clickState).toBe('pendingDouble')
354
360
 
355
- editor.inputs.currentScreenPoint.x = 5
356
- editor.inputs.currentScreenPoint.y = 5
361
+ const currentScreenPoint2 = editor.inputs.getCurrentScreenPoint()
362
+ currentScreenPoint2.x = 5
363
+ currentScreenPoint2.y = 5
357
364
  clickManager.handlePointerEvent(moveEvent2)
358
365
 
359
366
  expect(clickManager.clickState).toBe('idle')
@@ -362,8 +369,9 @@ describe('ClickManager', () => {
362
369
  it('should not cancel in idle state', () => {
363
370
  const moveEvent = createPointerEvent('pointer_move', { x: 100, y: 100 })
364
371
 
365
- editor.inputs.currentScreenPoint.x = 100
366
- editor.inputs.currentScreenPoint.y = 100
372
+ const currentScreenPoint = editor.inputs.getCurrentScreenPoint()
373
+ currentScreenPoint.x = 100
374
+ currentScreenPoint.y = 100
367
375
 
368
376
  clickManager.handlePointerEvent(moveEvent)
369
377
 
@@ -401,28 +409,6 @@ describe('ClickManager', () => {
401
409
  })
402
410
 
403
411
  describe('edge cases', () => {
404
- it('should handle null click state gracefully', () => {
405
- // Force null state
406
- ;(clickManager as any)._clickState = null
407
-
408
- const pointerEvent = createPointerEvent('pointer_down', { x: 100, y: 100 })
409
- const result = clickManager.handlePointerEvent(pointerEvent)
410
-
411
- expect(result).toBe(pointerEvent)
412
- })
413
-
414
- it('should handle missing previous screen point', () => {
415
- const firstDown = createPointerEvent('pointer_down', { x: 0, y: 0 })
416
-
417
- // Clear previous point
418
- ;(clickManager as any)._previousScreenPoint = undefined
419
-
420
- const result = clickManager.handlePointerEvent(firstDown)
421
-
422
- expect(result).toBe(firstDown)
423
- expect(clickManager.clickState).toBe('pendingDouble')
424
- })
425
-
426
412
  it('should handle overflow state correctly', () => {
427
413
  const pointerDown = createPointerEvent('pointer_down', { x: 100, y: 100 })
428
414
  const pointerUp = createPointerEvent('pointer_up', { x: 100, y: 100 })
@@ -197,7 +197,7 @@ export class ClickManager {
197
197
  if (
198
198
  this._clickState !== 'idle' &&
199
199
  this._clickScreenPoint &&
200
- Vec.Dist2(this._clickScreenPoint, this.editor.inputs.currentScreenPoint) >
200
+ Vec.Dist2(this._clickScreenPoint, this.editor.inputs.getCurrentScreenPoint()) >
201
201
  (this.editor.getInstanceState().isCoarsePointer
202
202
  ? this.editor.options.coarseDragDistanceSquared
203
203
  : this.editor.options.dragDistanceSquared)