@tldraw/editor 4.4.0-canary.afdcafe834b3 → 4.4.0-canary.b56b70f6a630

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 (243) hide show
  1. package/dist-cjs/index.d.ts +127 -26
  2. package/dist-cjs/index.js +4 -7
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +20 -8
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/ErrorBoundary.js.map +1 -1
  7. package/dist-cjs/lib/components/Shape.js +12 -17
  8. package/dist-cjs/lib/components/Shape.js.map +2 -2
  9. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +26 -1
  10. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +2 -2
  11. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +31 -16
  12. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  13. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +5 -6
  14. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
  15. package/dist-cjs/lib/components/default-components/DefaultLoadingScreen.js +2 -2
  16. package/dist-cjs/lib/components/default-components/DefaultLoadingScreen.js.map +2 -2
  17. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +2 -2
  18. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  19. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +2 -2
  20. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +2 -2
  21. package/dist-cjs/lib/editor/Editor.js +44 -15
  22. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  23. package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +1 -1
  24. package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +1 -1
  25. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +32 -13
  26. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
  27. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +2 -3
  28. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
  29. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +1 -1
  30. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +1 -1
  31. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +1 -1
  32. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +1 -1
  33. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +1 -1
  34. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +1 -1
  35. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +1 -1
  36. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  37. package/dist-cjs/lib/editor/shapes/shared/resizeBox.js.map +1 -1
  38. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +1 -1
  39. package/dist-cjs/lib/editor/types/SvgExportContext.js.map +1 -1
  40. package/dist-cjs/lib/exports/exportToSvg.js.map +1 -1
  41. package/dist-cjs/lib/exports/getSvgJsx.js.map +1 -1
  42. package/dist-cjs/lib/{utils/hardResetEditor.js → hooks/EditorComponentsContext.js} +14 -8
  43. package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +7 -0
  44. package/dist-cjs/lib/hooks/useCanvasEvents.js +10 -2
  45. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  46. package/dist-cjs/lib/hooks/useEditor.js.map +1 -1
  47. package/dist-cjs/lib/hooks/useEditorComponents.js +4 -10
  48. package/dist-cjs/lib/hooks/useEditorComponents.js.map +3 -3
  49. package/dist-cjs/lib/hooks/usePeerIds.js +8 -2
  50. package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
  51. package/dist-cjs/lib/hooks/useShapeCulling.js +75 -0
  52. package/dist-cjs/lib/hooks/useShapeCulling.js.map +7 -0
  53. package/dist-cjs/lib/license/LicenseManager.js +6 -6
  54. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  55. package/dist-cjs/lib/options.js +7 -1
  56. package/dist-cjs/lib/options.js.map +2 -2
  57. package/dist-cjs/lib/primitives/Vec.js +10 -5
  58. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  59. package/dist-cjs/lib/utils/areShapesContentEqual.js +3 -1
  60. package/dist-cjs/lib/utils/areShapesContentEqual.js.map +2 -2
  61. package/dist-cjs/lib/utils/assets.js +4 -6
  62. package/dist-cjs/lib/utils/assets.js.map +2 -2
  63. package/dist-cjs/lib/utils/browserCanvasMaxSize.js +1 -2
  64. package/dist-cjs/lib/utils/browserCanvasMaxSize.js.map +2 -2
  65. package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
  66. package/dist-cjs/lib/utils/deepLinks.js.map +1 -1
  67. package/dist-cjs/lib/utils/dom.js +3 -3
  68. package/dist-cjs/lib/utils/dom.js.map +2 -2
  69. package/dist-cjs/lib/utils/getIncrementedName.js +1 -1
  70. package/dist-cjs/lib/utils/getIncrementedName.js.map +2 -2
  71. package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
  72. package/dist-cjs/lib/utils/getSvgPathFromPoints.js.map +1 -1
  73. package/dist-cjs/lib/utils/keyboard.js +2 -2
  74. package/dist-cjs/lib/utils/keyboard.js.map +2 -2
  75. package/dist-cjs/lib/utils/normalizeWheel.js +2 -5
  76. package/dist-cjs/lib/utils/normalizeWheel.js.map +2 -2
  77. package/dist-cjs/lib/utils/reorderShapes.js +6 -6
  78. package/dist-cjs/lib/utils/reorderShapes.js.map +2 -2
  79. package/dist-cjs/lib/utils/reparenting.js +3 -4
  80. package/dist-cjs/lib/utils/reparenting.js.map +2 -2
  81. package/dist-cjs/lib/utils/richText.js.map +1 -1
  82. package/dist-cjs/lib/utils/rotation.js.map +1 -1
  83. package/dist-cjs/lib/utils/runtime.js +12 -0
  84. package/dist-cjs/lib/utils/runtime.js.map +2 -2
  85. package/dist-cjs/version.js +3 -3
  86. package/dist-cjs/version.js.map +1 -1
  87. package/dist-esm/index.d.mts +127 -26
  88. package/dist-esm/index.mjs +8 -5
  89. package/dist-esm/index.mjs.map +2 -2
  90. package/dist-esm/lib/TldrawEditor.mjs +20 -8
  91. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  92. package/dist-esm/lib/components/ErrorBoundary.mjs.map +1 -1
  93. package/dist-esm/lib/components/Shape.mjs +12 -17
  94. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  95. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +27 -2
  96. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +2 -2
  97. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +17 -2
  98. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  99. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +2 -3
  100. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
  101. package/dist-esm/lib/components/default-components/DefaultLoadingScreen.mjs +1 -1
  102. package/dist-esm/lib/components/default-components/DefaultLoadingScreen.mjs.map +1 -1
  103. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +1 -1
  104. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  105. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +1 -1
  106. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +2 -2
  107. package/dist-esm/lib/editor/Editor.mjs +44 -15
  108. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  109. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +1 -1
  110. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +1 -1
  111. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +32 -13
  112. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
  113. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +2 -3
  114. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
  115. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +1 -1
  116. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +1 -1
  117. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +1 -1
  118. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +1 -1
  119. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +1 -1
  120. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +1 -1
  121. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +1 -1
  122. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  123. package/dist-esm/lib/editor/shapes/shared/resizeBox.mjs.map +1 -1
  124. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +1 -1
  125. package/dist-esm/lib/editor/types/SvgExportContext.mjs.map +1 -1
  126. package/dist-esm/lib/exports/exportToSvg.mjs.map +1 -1
  127. package/dist-esm/lib/exports/getSvgJsx.mjs.map +1 -1
  128. package/dist-esm/lib/hooks/EditorComponentsContext.mjs +14 -0
  129. package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +7 -0
  130. package/dist-esm/lib/hooks/useCanvasEvents.mjs +10 -2
  131. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  132. package/dist-esm/lib/hooks/useEditor.mjs.map +1 -1
  133. package/dist-esm/lib/hooks/useEditorComponents.mjs +12 -36
  134. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  135. package/dist-esm/lib/hooks/usePeerIds.mjs +8 -2
  136. package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
  137. package/dist-esm/lib/hooks/useShapeCulling.mjs +55 -0
  138. package/dist-esm/lib/hooks/useShapeCulling.mjs.map +7 -0
  139. package/dist-esm/lib/license/LicenseManager.mjs +6 -6
  140. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  141. package/dist-esm/lib/options.mjs +7 -1
  142. package/dist-esm/lib/options.mjs.map +2 -2
  143. package/dist-esm/lib/primitives/Vec.mjs +6 -1
  144. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  145. package/dist-esm/lib/utils/areShapesContentEqual.mjs +3 -1
  146. package/dist-esm/lib/utils/areShapesContentEqual.mjs.map +2 -2
  147. package/dist-esm/lib/utils/assets.mjs +4 -6
  148. package/dist-esm/lib/utils/assets.mjs.map +2 -2
  149. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +1 -2
  150. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs.map +2 -2
  151. package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
  152. package/dist-esm/lib/utils/deepLinks.mjs.map +1 -1
  153. package/dist-esm/lib/utils/dom.mjs +3 -3
  154. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  155. package/dist-esm/lib/utils/getIncrementedName.mjs +1 -1
  156. package/dist-esm/lib/utils/getIncrementedName.mjs.map +2 -2
  157. package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
  158. package/dist-esm/lib/utils/getSvgPathFromPoints.mjs.map +1 -1
  159. package/dist-esm/lib/utils/keyboard.mjs +2 -2
  160. package/dist-esm/lib/utils/keyboard.mjs.map +2 -2
  161. package/dist-esm/lib/utils/normalizeWheel.mjs +2 -5
  162. package/dist-esm/lib/utils/normalizeWheel.mjs.map +2 -2
  163. package/dist-esm/lib/utils/reorderShapes.mjs +6 -6
  164. package/dist-esm/lib/utils/reorderShapes.mjs.map +2 -2
  165. package/dist-esm/lib/utils/reparenting.mjs +3 -4
  166. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  167. package/dist-esm/lib/utils/richText.mjs.map +1 -1
  168. package/dist-esm/lib/utils/rotation.mjs.map +1 -1
  169. package/dist-esm/lib/utils/runtime.mjs +12 -0
  170. package/dist-esm/lib/utils/runtime.mjs.map +2 -2
  171. package/dist-esm/version.mjs +3 -3
  172. package/dist-esm/version.mjs.map +1 -1
  173. package/editor.css +22 -2
  174. package/package.json +10 -11
  175. package/src/index.ts +7 -4
  176. package/src/lib/TldrawEditor.tsx +34 -12
  177. package/src/lib/components/ErrorBoundary.tsx +1 -1
  178. package/src/lib/components/Shape.tsx +15 -16
  179. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +46 -2
  180. package/src/lib/components/default-components/DefaultCanvas.tsx +25 -3
  181. package/src/lib/components/default-components/DefaultErrorFallback.tsx +2 -3
  182. package/src/lib/components/default-components/DefaultLoadingScreen.tsx +1 -1
  183. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +1 -1
  184. package/src/lib/components/default-components/DefaultShapeIndicators.tsx +1 -1
  185. package/src/lib/editor/Editor.ts +74 -16
  186. package/src/lib/editor/bindings/BindingUtil.ts +1 -1
  187. package/src/lib/editor/derivations/bindingsIndex.ts +1 -1
  188. package/src/lib/editor/derivations/notVisibleShapes.ts +40 -18
  189. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +0 -35
  190. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +5 -9
  191. package/src/lib/editor/managers/FontManager/FontManager.ts +1 -1
  192. package/src/lib/editor/managers/InputsManager/InputsManager.ts +1 -1
  193. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +1 -1
  194. package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +2 -2
  195. package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +2 -2
  196. package/src/lib/editor/managers/TextManager/TextManager.ts +1 -1
  197. package/src/lib/editor/managers/TickManager/TickManager.ts +1 -1
  198. package/src/lib/editor/shapes/ShapeUtil.ts +19 -5
  199. package/src/lib/editor/shapes/shared/resizeBox.ts +1 -1
  200. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +2 -2
  201. package/src/lib/editor/types/SvgExportContext.tsx +1 -1
  202. package/src/lib/exports/exportToSvg.tsx +1 -1
  203. package/src/lib/exports/getSvgJsx.tsx +1 -1
  204. package/src/lib/hooks/EditorComponentsContext.tsx +63 -0
  205. package/src/lib/hooks/useCanvasEvents.ts +13 -2
  206. package/src/lib/hooks/useEditor.tsx +1 -1
  207. package/src/lib/hooks/useEditorComponents.tsx +20 -89
  208. package/src/lib/hooks/usePeerIds.ts +9 -2
  209. package/src/lib/hooks/useShapeCulling.tsx +98 -0
  210. package/src/lib/license/LicenseManager.ts +6 -6
  211. package/src/lib/options.ts +52 -2
  212. package/src/lib/primitives/Vec.ts +7 -1
  213. package/src/lib/utils/areShapesContentEqual.ts +9 -2
  214. package/src/lib/utils/assets.ts +15 -10
  215. package/src/lib/utils/browserCanvasMaxSize.ts +4 -2
  216. package/src/lib/utils/debug-flags.ts +0 -20
  217. package/src/lib/utils/deepLinks.ts +1 -1
  218. package/src/lib/utils/dom.ts +6 -7
  219. package/src/lib/utils/getIncrementedName.ts +1 -1
  220. package/src/lib/utils/getPointerInfo.ts +1 -0
  221. package/src/lib/utils/getSvgPathFromPoints.ts +1 -1
  222. package/src/lib/utils/keyboard.ts +6 -4
  223. package/src/lib/utils/normalizeWheel.ts +8 -8
  224. package/src/lib/utils/reorderShapes.ts +17 -8
  225. package/src/lib/utils/reparenting.ts +5 -10
  226. package/src/lib/utils/richText.ts +1 -1
  227. package/src/lib/utils/rotation.ts +1 -1
  228. package/src/lib/utils/runtime.ts +26 -1
  229. package/src/version.ts +3 -3
  230. package/dist-cjs/lib/utils/hardResetEditor.js.map +0 -7
  231. package/dist-cjs/lib/utils/refreshPage.js +0 -28
  232. package/dist-cjs/lib/utils/refreshPage.js.map +0 -7
  233. package/dist-cjs/lib/utils/window-open.js +0 -28
  234. package/dist-cjs/lib/utils/window-open.js.map +0 -7
  235. package/dist-esm/lib/utils/hardResetEditor.mjs +0 -8
  236. package/dist-esm/lib/utils/hardResetEditor.mjs.map +0 -7
  237. package/dist-esm/lib/utils/refreshPage.mjs +0 -8
  238. package/dist-esm/lib/utils/refreshPage.mjs.map +0 -7
  239. package/dist-esm/lib/utils/window-open.mjs +0 -8
  240. package/dist-esm/lib/utils/window-open.mjs.map +0 -7
  241. package/src/lib/utils/hardResetEditor.ts +0 -6
  242. package/src/lib/utils/refreshPage.ts +0 -6
  243. package/src/lib/utils/window-open.ts +0 -16
@@ -5,6 +5,7 @@ import { memo, useCallback, useEffect, useLayoutEffect, useRef } from 'react'
5
5
  import { ShapeUtil } from '../editor/shapes/ShapeUtil'
6
6
  import { useEditor } from '../hooks/useEditor'
7
7
  import { useEditorComponents } from '../hooks/useEditorComponents'
8
+ import { useShapeCulling } from '../hooks/useShapeCulling'
8
9
  import { Mat } from '../primitives/Mat'
9
10
  import { areShapesContentEqual } from '../utils/areShapesContentEqual'
10
11
  import { setStyleProperty } from '../utils/dom'
@@ -57,7 +58,6 @@ export const Shape = memo(function Shape({
57
58
  height: 0,
58
59
  x: 0,
59
60
  y: 0,
60
- isCulled: false,
61
61
  })
62
62
 
63
63
  useQuickReactor(
@@ -118,22 +118,21 @@ export const Shape = memo(function Shape({
118
118
  setStyleProperty(bgContainer, 'z-index', backgroundIndex)
119
119
  }, [opacity, index, backgroundIndex])
120
120
 
121
- useQuickReactor(
122
- 'set display',
123
- () => {
124
- const shape = editor.getShape(id)
125
- if (!shape) return // probably the shape was just deleted
121
+ // Register container refs with the centralized culling context.
122
+ // This runs on mount and handles initial display state.
123
+ const { register, unregister } = useShapeCulling()
124
+ useLayoutEffect(() => {
125
+ const container = containerRef.current
126
+ if (!container) return
126
127
 
127
- const culledShapes = editor.getCulledShapes()
128
- const isCulled = culledShapes.has(id)
129
- if (isCulled !== memoizedStuffRef.current.isCulled) {
130
- setStyleProperty(containerRef.current, 'display', isCulled ? 'none' : 'block')
131
- setStyleProperty(bgContainerRef.current, 'display', isCulled ? 'none' : 'block')
132
- memoizedStuffRef.current.isCulled = isCulled
133
- }
134
- },
135
- [editor]
136
- )
128
+ // Check initial culling state and register with the context
129
+ const isCulled = editor.getCulledShapes().has(id)
130
+ register(id, container, bgContainerRef.current, isCulled)
131
+
132
+ return () => {
133
+ unregister(id)
134
+ }
135
+ }, [editor, id, register, unregister])
137
136
  const annotateError = useCallback(
138
137
  (error: any) => editor.annotateError(error, { origin: 'shape', willCrashApp: false }),
139
138
  [editor]
@@ -1,7 +1,7 @@
1
1
  import { useComputed, useQuickReactor } from '@tldraw/state-react'
2
2
  import { createComputedCache } from '@tldraw/store'
3
3
  import { TLShape, TLShapeId } from '@tldraw/tlschema'
4
- import { dedupe, isEqual } from '@tldraw/utils'
4
+ import { dedupe } from '@tldraw/utils'
5
5
  import { memo, useEffect, useRef } from 'react'
6
6
  import { Editor } from '../../editor/Editor'
7
7
  import { TLIndicatorPath } from '../../editor/shapes/ShapeUtil'
@@ -14,6 +14,50 @@ interface CollaboratorIndicatorData {
14
14
  shapeIds: TLShapeId[]
15
15
  }
16
16
 
17
+ interface RenderData {
18
+ idsToDisplay: Set<TLShapeId>
19
+ renderingShapeIds: Set<TLShapeId>
20
+ hintingShapeIds: TLShapeId[]
21
+ collaboratorIndicators: CollaboratorIndicatorData[]
22
+ }
23
+
24
+ function setsEqual<T>(a: Set<T>, b: Set<T>): boolean {
25
+ if (a.size !== b.size) return false
26
+ for (const item of a) {
27
+ if (!b.has(item)) return false
28
+ }
29
+ return true
30
+ }
31
+
32
+ function arraysEqual<T>(a: readonly T[], b: readonly T[]): boolean {
33
+ if (a.length !== b.length) return false
34
+ for (let i = 0; i < a.length; i++) {
35
+ if (a[i] !== b[i]) return false
36
+ }
37
+ return true
38
+ }
39
+
40
+ function collaboratorIndicatorsEqual(
41
+ a: CollaboratorIndicatorData[],
42
+ b: CollaboratorIndicatorData[]
43
+ ): boolean {
44
+ if (a.length !== b.length) return false
45
+ for (let i = 0; i < a.length; i++) {
46
+ if (a[i].color !== b[i].color) return false
47
+ if (!arraysEqual(a[i].shapeIds, b[i].shapeIds)) return false
48
+ }
49
+ return true
50
+ }
51
+
52
+ function renderDataEqual(a: RenderData, b: RenderData): boolean {
53
+ return (
54
+ setsEqual(a.idsToDisplay, b.idsToDisplay) &&
55
+ setsEqual(a.renderingShapeIds, b.renderingShapeIds) &&
56
+ arraysEqual(a.hintingShapeIds, b.hintingShapeIds) &&
57
+ collaboratorIndicatorsEqual(a.collaboratorIndicators, b.collaboratorIndicators)
58
+ )
59
+ }
60
+
17
61
  const indicatorPathCache = createComputedCache(
18
62
  'indicatorPath',
19
63
  (editor: Editor, shape: TLShape) => {
@@ -162,7 +206,7 @@ export const CanvasShapeIndicators = memo(function CanvasShapeIndicators() {
162
206
  collaboratorIndicators,
163
207
  }
164
208
  },
165
- { isEqual: isEqual },
209
+ { isEqual: renderDataEqual },
166
210
  [editor, activePeerIds$]
167
211
  )
168
212
 
@@ -5,17 +5,18 @@ import { dedupe, modulate, objectMapValues } from '@tldraw/utils'
5
5
  import classNames from 'classnames'
6
6
  import { Fragment, JSX, useEffect, useRef, useState } from 'react'
7
7
  import { tlenv } from '../../globals/environment'
8
+ import { useEditorComponents } from '../../hooks/EditorComponentsContext'
8
9
  import { useCanvasEvents } from '../../hooks/useCanvasEvents'
9
10
  import { useCoarsePointer } from '../../hooks/useCoarsePointer'
10
11
  import { useContainer } from '../../hooks/useContainer'
11
12
  import { useDocumentEvents } from '../../hooks/useDocumentEvents'
12
13
  import { useEditor } from '../../hooks/useEditor'
13
- import { useEditorComponents } from '../../hooks/useEditorComponents'
14
14
  import { useFixSafariDoubleTapZoomPencilEvents } from '../../hooks/useFixSafariDoubleTapZoomPencilEvents'
15
15
  import { useGestureEvents } from '../../hooks/useGestureEvents'
16
16
  import { useHandleEvents } from '../../hooks/useHandleEvents'
17
17
  import { useSharedSafeId } from '../../hooks/useSafeId'
18
18
  import { useScreenBounds } from '../../hooks/useScreenBounds'
19
+ import { ShapeCullingProvider, useShapeCulling } from '../../hooks/useShapeCulling'
19
20
  import { Box } from '../../primitives/Box'
20
21
  import { Mat } from '../../primitives/Mat'
21
22
  import { Vec } from '../../primitives/Vec'
@@ -428,18 +429,39 @@ function ReflowIfNeeded() {
428
429
  return null
429
430
  }
430
431
 
432
+ /**
433
+ * Centralized culling controller that updates shape container visibility.
434
+ * This single reactor replaces per-shape subscriptions for O(1) instead of O(N) subscriptions.
435
+ */
436
+ function CullingController() {
437
+ const editor = useEditor()
438
+ const { updateCulling } = useShapeCulling()
439
+
440
+ useQuickReactor(
441
+ 'update shape culling',
442
+ () => {
443
+ const culledShapes = editor.getCulledShapes()
444
+ updateCulling(culledShapes)
445
+ },
446
+ [editor, updateCulling]
447
+ )
448
+
449
+ return null
450
+ }
451
+
431
452
  function ShapesToDisplay() {
432
453
  const editor = useEditor()
433
454
 
434
455
  const renderingShapes = useValue('rendering shapes', () => editor.getRenderingShapes(), [editor])
435
456
 
436
457
  return (
437
- <>
458
+ <ShapeCullingProvider>
438
459
  {renderingShapes.map((result) => (
439
460
  <Shape key={result.id + '_shape'} {...result} />
440
461
  ))}
462
+ <CullingController />
441
463
  {tlenv.isSafari && <ReflowIfNeeded />}
442
- </>
464
+ </ShapeCullingProvider>
443
465
  )
444
466
  }
445
467
 
@@ -3,10 +3,9 @@ import { noop } from '@tldraw/utils'
3
3
  import classNames from 'classnames'
4
4
  import { ComponentType, useEffect, useLayoutEffect, useRef, useState } from 'react'
5
5
  import { Editor } from '../../editor/Editor'
6
+ import { useEditorComponents } from '../../hooks/EditorComponentsContext'
6
7
  import { EditorProvider } from '../../hooks/useEditor'
7
- import { useEditorComponents } from '../../hooks/useEditorComponents'
8
- import { hardResetEditor } from '../../utils/hardResetEditor'
9
- import { refreshPage } from '../../utils/refreshPage'
8
+ import { hardResetEditor, refreshPage } from '../../utils/runtime'
10
9
  import { ErrorBoundary } from '../ErrorBoundary'
11
10
 
12
11
  const BASE_ERROR_URL = 'https://github.com/tldraw/tldraw/issues/new'
@@ -1,5 +1,5 @@
1
1
  import { LoadingScreen } from '../../TldrawEditor'
2
- import { useEditorComponents } from '../../hooks/useEditorComponents'
2
+ import { useEditorComponents } from '../../hooks/EditorComponentsContext'
3
3
 
4
4
  /** @public @react */
5
5
  export const DefaultLoadingScreen = () => {
@@ -4,8 +4,8 @@ import classNames from 'classnames'
4
4
  import { memo, useLayoutEffect, useRef } from 'react'
5
5
  import type { Editor } from '../../editor/Editor'
6
6
  import { ShapeUtil } from '../../editor/shapes/ShapeUtil'
7
+ import { useEditorComponents } from '../../hooks/EditorComponentsContext'
7
8
  import { useEditor } from '../../hooks/useEditor'
8
- import { useEditorComponents } from '../../hooks/useEditorComponents'
9
9
  import { OptionalErrorBoundary } from '../ErrorBoundary'
10
10
 
11
11
  // need an extra layer of indirection here to allow hooks to be used inside the indicator render
@@ -1,8 +1,8 @@
1
1
  import { useValue } from '@tldraw/state-react'
2
2
  import { TLShapeId } from '@tldraw/tlschema'
3
3
  import { memo, useRef } from 'react'
4
+ import { useEditorComponents } from '../../hooks/EditorComponentsContext'
4
5
  import { useEditor } from '../../hooks/useEditor'
5
- import { useEditorComponents } from '../../hooks/useEditorComponents'
6
6
 
7
7
  /** @public */
8
8
  export interface TLShapeIndicatorsProps {
@@ -134,6 +134,7 @@ import {
134
134
  } from '../utils/deepLinks'
135
135
  import { getIncrementedName } from '../utils/getIncrementedName'
136
136
  import { getReorderingShapesChanges } from '../utils/reorderShapes'
137
+ import { getDroppedShapesToNewParents } from '../utils/reparenting'
137
138
  import { TLTextOptions, TiptapEditor } from '../utils/richText'
138
139
  import { applyRotationToSnapshotShapes, getRotationSnapshot } from '../utils/rotation'
139
140
  import { BindingOnDeleteOptions, BindingUtil } from './bindings/BindingUtil'
@@ -153,7 +154,13 @@ import { SpatialIndexManager } from './managers/SpatialIndexManager/SpatialIndex
153
154
  import { TextManager } from './managers/TextManager/TextManager'
154
155
  import { TickManager } from './managers/TickManager/TickManager'
155
156
  import { UserPreferencesManager } from './managers/UserPreferencesManager/UserPreferencesManager'
156
- import { ShapeUtil, TLEditStartInfo, TLGeometryOpts, TLResizeMode } from './shapes/ShapeUtil'
157
+ import {
158
+ ShapeUtil,
159
+ TLEditStartInfo,
160
+ TLGeometryOpts,
161
+ TLResizeMode,
162
+ TLShapeUtilCanBindOpts,
163
+ } from './shapes/ShapeUtil'
157
164
  import { RootState } from './tools/RootState'
158
165
  import { StateNode, TLStateNodeConstructor } from './tools/StateNode'
159
166
  import { TLContent } from './types/clipboard-types'
@@ -228,10 +235,17 @@ export interface TLEditorOptions {
228
235
  inferDarkMode?: boolean
229
236
  /**
230
237
  * Options for the editor's camera.
238
+ *
239
+ * @deprecated Use `options.cameraOptions` instead. This will be removed in a future release.
231
240
  */
232
241
  cameraOptions?: Partial<TLCameraOptions>
233
- textOptions?: TLTextOptions
234
242
  options?: Partial<TldrawOptions>
243
+ /**
244
+ * Text options for the editor.
245
+ *
246
+ * @deprecated Use `options.text` instead. This prop will be removed in a future release.
247
+ */
248
+ textOptions?: TLTextOptions
235
249
  licenseKey?: string
236
250
  fontAssetUrls?: { [key: string]: string | undefined }
237
251
  /**
@@ -283,12 +297,16 @@ export class Editor extends EventEmitter<TLEventMap> {
283
297
  bindingUtils,
284
298
  tools,
285
299
  getContainer,
300
+ // needs to be here for backwards compatibility with TldrawEditor
301
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
286
302
  cameraOptions,
287
- textOptions,
288
303
  initialState,
289
304
  autoFocus,
290
305
  inferDarkMode,
291
- options,
306
+ options: _options,
307
+ // needs to be here for backwards compatibility with TldrawEditor
308
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
309
+ textOptions: _textOptions,
292
310
  getShapeVisibility,
293
311
  fontAssetUrls,
294
312
  }: TLEditorOptions) {
@@ -296,6 +314,10 @@ export class Editor extends EventEmitter<TLEventMap> {
296
314
 
297
315
  this._getShapeVisibility = getShapeVisibility
298
316
 
317
+ // Merge deprecated textOptions prop with options.text
318
+ // options.text takes precedence over the deprecated textOptions prop
319
+ const options = _textOptions ? { ..._options, text: _options?.text ?? _textOptions } : _options
320
+
299
321
  this.options = { ...defaultTldrawOptions, ...options }
300
322
 
301
323
  this.store = store
@@ -314,9 +336,14 @@ export class Editor extends EventEmitter<TLEventMap> {
314
336
 
315
337
  this.disposables.add(this.timers.dispose)
316
338
 
317
- this._cameraOptions.set({ ...DEFAULT_CAMERA_OPTIONS, ...cameraOptions })
339
+ // Merge camera options: options.cameraOptions takes precedence over deprecated cameraOptions prop
340
+ this._cameraOptions.set({
341
+ ...DEFAULT_CAMERA_OPTIONS,
342
+ ...cameraOptions,
343
+ ...options?.camera,
344
+ })
318
345
 
319
- this._textOptions = atom('text options', textOptions ?? null)
346
+ this._textOptions = atom('text options', options?.text ?? null)
320
347
 
321
348
  this.user = new UserPreferencesManager(user ?? createTLUser(), inferDarkMode ?? false)
322
349
  this.disposables.add(() => this.user.dispose())
@@ -443,6 +470,7 @@ export class Editor extends EventEmitter<TLEventMap> {
443
470
  const deletedShapeIds = new Set<TLShapeId>()
444
471
  const invalidParents = new Set<TLShapeId>()
445
472
  let invalidBindingTypes = new Set<TLBinding['type']>()
473
+
446
474
  this.disposables.add(
447
475
  this.sideEffects.registerOperationCompleteHandler(() => {
448
476
  // this needs to be cleared here because further effects may delete more shapes
@@ -794,6 +822,7 @@ export class Editor extends EventEmitter<TLEventMap> {
794
822
  }
795
823
 
796
824
  private readonly _getShapeVisibility?: TLEditorOptions['getShapeVisibility']
825
+
797
826
  @computed
798
827
  private getIsShapeHiddenCache() {
799
828
  if (!this._getShapeVisibility) return null
@@ -4180,23 +4209,25 @@ export class Editor extends EventEmitter<TLEventMap> {
4180
4209
  // unmount / remount in the DOM, which is expensive; and computing visibility is
4181
4210
  // also expensive in large projects. For this reason, we use a second bounding
4182
4211
  // box just for rendering, and we only update after the camera stops moving.
4183
- private _cameraState = atom('camera state', 'idle' as 'idle' | 'moving')
4184
4212
  private _cameraStateTimeoutRemaining = 0
4185
4213
  private _decayCameraStateTimeout(elapsed: number) {
4186
4214
  this._cameraStateTimeoutRemaining -= elapsed
4187
4215
  if (this._cameraStateTimeoutRemaining > 0) return
4188
4216
  this.off('tick', this._decayCameraStateTimeout)
4189
- this._cameraState.set('idle')
4217
+ this._setCameraState('idle')
4190
4218
  }
4191
4219
  private _tickCameraState() {
4192
4220
  // always reset the timeout
4193
4221
  this._cameraStateTimeoutRemaining = this.options.cameraMovingTimeoutMs
4194
4222
  // If the state is idle, then start the tick
4195
- if (this._cameraState.__unsafe__getWithoutCapture() !== 'idle') return
4196
- this._cameraState.set('moving')
4223
+ if (this.getInstanceState().cameraState !== 'idle') return
4224
+ this._setCameraState('moving')
4197
4225
  this._debouncedZoomLevel.set(unsafe__withoutCapture(() => this.getCamera().z))
4198
4226
  this.on('tick', this._decayCameraStateTimeout)
4199
4227
  }
4228
+ private _setCameraState(cameraState: 'idle' | 'moving') {
4229
+ this.updateInstanceState({ cameraState }, { history: 'ignore' })
4230
+ }
4200
4231
 
4201
4232
  /**
4202
4233
  * Whether the camera is moving or idle.
@@ -4209,7 +4240,7 @@ export class Editor extends EventEmitter<TLEventMap> {
4209
4240
  * @public
4210
4241
  */
4211
4242
  getCameraState() {
4212
- return this._cameraState.get()
4243
+ return this.getInstanceState().cameraState
4213
4244
  }
4214
4245
 
4215
4246
  /**
@@ -5481,7 +5512,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5481
5512
  * @param bounds - The bounds to search within.
5482
5513
  * @returns Unordered set of shape IDs within the given bounds.
5483
5514
  *
5484
- * @internal
5515
+ * @public
5485
5516
  */
5486
5517
  getShapeIdsInsideBounds(bounds: Box): Set<TLShapeId> {
5487
5518
  return this._spatialIndex.getShapeIdsInsideBounds(bounds)
@@ -6246,7 +6277,13 @@ export class Editor extends EventEmitter<TLEventMap> {
6246
6277
  const toShapeType = typeof toShape === 'string' ? toShape : toShape.type
6247
6278
  const bindingType = typeof binding === 'string' ? binding : binding.type
6248
6279
 
6249
- const canBindOpts = { fromShapeType, toShapeType, bindingType } as const
6280
+ const canBindOpts: TLShapeUtilCanBindOpts = {
6281
+ fromShape: typeof fromShape === 'string' ? { type: fromShape } : fromShape,
6282
+ toShape: typeof toShape === 'string' ? { type: toShape } : toShape,
6283
+ bindingType,
6284
+ fromShapeType,
6285
+ toShapeType,
6286
+ }
6250
6287
 
6251
6288
  if (fromShapeType === toShapeType) {
6252
6289
  return this.getShapeUtil(fromShapeType).canBind(canBindOpts)
@@ -7839,6 +7876,7 @@ export class Editor extends EventEmitter<TLEventMap> {
7839
7876
  initialShape: options.initialShape,
7840
7877
  initialBounds: options.initialBounds,
7841
7878
  isAspectRatioLocked: options.isAspectRatioLocked,
7879
+ initialPageTransform: options.initialPageTransform,
7842
7880
  })
7843
7881
 
7844
7882
  // then if the shape is flipped in one axis only, we need to apply an extra rotation
@@ -9595,6 +9633,20 @@ export class Editor extends EventEmitter<TLEventMap> {
9595
9633
  return { id: s.id, type: s.type, x: s.x + localDelta.x, y: s.y + localDelta.y }
9596
9634
  })
9597
9635
  )
9636
+
9637
+ // If shapes were pasted onto the page (not into a specific parent),
9638
+ // check whether they landed inside a frame and reparent if so.
9639
+ if (isPageId(pasteParentId)) {
9640
+ const currentRootShapes = compact(rootShapes.map((s) => this.getShape(s.id)))
9641
+ const { reparenting } = getDroppedShapesToNewParents(this, currentRootShapes)
9642
+ reparenting.forEach((childrenToReparent, newParentId) => {
9643
+ if (childrenToReparent.length === 0) return
9644
+ this.reparentShapes(
9645
+ childrenToReparent.map((s) => s.id),
9646
+ newParentId
9647
+ )
9648
+ })
9649
+ }
9598
9650
  })
9599
9651
 
9600
9652
  return this
@@ -10421,9 +10473,10 @@ export class Editor extends EventEmitter<TLEventMap> {
10421
10473
  if (inputs.getIsPinching()) return
10422
10474
 
10423
10475
  if (!inputs.getIsEditing()) {
10424
- if (!this._selectedShapeIdsAtPointerDown.length) {
10425
- this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds]
10426
- }
10476
+ // Always capture the current selection when pinch starts.
10477
+ // This ensures Safari (which uses gesture events instead of wheel)
10478
+ // doesn't restore a stale selection from an earlier pointer_down.
10479
+ this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds]
10427
10480
 
10428
10481
  this._didPinch = true
10429
10482
 
@@ -10734,6 +10787,11 @@ export class Editor extends EventEmitter<TLEventMap> {
10734
10787
  this.setCurrentTool(this._restoreToolId)
10735
10788
  }
10736
10789
  }
10790
+
10791
+ // Clear the stashed selection so the next pinch captures fresh state.
10792
+ // This fixes Safari pinch zoom restoring outdated selections.
10793
+ this._selectedShapeIdsAtPointerDown = []
10794
+
10737
10795
  break
10738
10796
  }
10739
10797
  }
@@ -5,7 +5,7 @@ import {
5
5
  TLShape,
6
6
  TLUnknownBinding,
7
7
  } from '@tldraw/tlschema'
8
- import { Editor } from '../Editor'
8
+ import type { Editor } from '../Editor'
9
9
 
10
10
  /** @public */
11
11
  export interface TLBindingUtilConstructor<
@@ -1,7 +1,7 @@
1
1
  import { Computed, RESET_VALUE, computed, isUninitialized } from '@tldraw/state'
2
2
  import { TLBinding, TLShapeId } from '@tldraw/tlschema'
3
3
  import { objectMapValues } from '@tldraw/utils'
4
- import { Editor } from '../Editor'
4
+ import type { Editor } from '../Editor'
5
5
 
6
6
  type TLBindingsIndex = Map<TLShapeId, TLBinding[]>
7
7
 
@@ -1,6 +1,6 @@
1
1
  import { computed, isUninitialized } from '@tldraw/state'
2
- import { TLShapeId } from '@tldraw/tlschema'
3
- import { Editor } from '../Editor'
2
+ import { TLShape, TLShapeId } from '@tldraw/tlschema'
3
+ import type { Editor } from '../Editor'
4
4
 
5
5
  /**
6
6
  * Non visible shapes are shapes outside of the viewport page bounds.
@@ -9,34 +9,56 @@ import { Editor } from '../Editor'
9
9
  * @returns Incremental derivation of non visible shapes.
10
10
  */
11
11
  export function notVisibleShapes(editor: Editor) {
12
+ const emptySet = new Set<TLShapeId>()
13
+
12
14
  return computed<Set<TLShapeId>>('notVisibleShapes', function (prevValue) {
13
- const allShapeIds = editor.getCurrentPageShapeIds()
15
+ const allShapes = editor.getCurrentPageShapes()
14
16
  const viewportPageBounds = editor.getViewportPageBounds()
15
17
  const visibleIds = editor.getShapeIdsInsideBounds(viewportPageBounds)
16
18
 
17
- const nextValue = new Set<TLShapeId>()
18
-
19
- // Non-visible shapes are all shapes minus visible shapes
20
- for (const id of allShapeIds) {
21
- if (!visibleIds.has(id)) {
22
- const shape = editor.getShape(id)
23
- if (!shape) continue
19
+ let shape: TLShape | undefined
24
20
 
25
- const canCull = editor.getShapeUtil(shape.type).canCull(shape)
26
- if (!canCull) continue
27
-
28
- nextValue.add(id)
21
+ // Fast path: if all shapes are visible, return empty set
22
+ if (visibleIds.size === allShapes.length) {
23
+ if (isUninitialized(prevValue) || prevValue.size > 0) {
24
+ return emptySet
29
25
  }
26
+ return prevValue
30
27
  }
31
28
 
32
- if (isUninitialized(prevValue) || prevValue.size !== nextValue.size) {
29
+ // First run: compute from scratch
30
+ if (isUninitialized(prevValue)) {
31
+ const nextValue = new Set<TLShapeId>()
32
+ for (let i = 0; i < allShapes.length; i++) {
33
+ shape = allShapes[i]
34
+ if (visibleIds.has(shape.id)) continue
35
+ if (!editor.getShapeUtil(shape.type).canCull(shape)) continue
36
+ nextValue.add(shape.id)
37
+ }
33
38
  return nextValue
34
39
  }
35
40
 
36
- for (const prev of prevValue) {
37
- if (!nextValue.has(prev)) return nextValue
41
+ // Subsequent runs: single pass to collect IDs and detect changes
42
+ const notVisibleIds: TLShapeId[] = []
43
+ for (let i = 0; i < allShapes.length; i++) {
44
+ shape = allShapes[i]
45
+ if (visibleIds.has(shape.id)) continue
46
+ if (!editor.getShapeUtil(shape.type).canCull(shape)) continue
47
+ notVisibleIds.push(shape.id)
48
+ }
49
+
50
+ // Check if the result changed
51
+ if (notVisibleIds.length === prevValue.size) {
52
+ let same = true
53
+ for (let i = 0; i < notVisibleIds.length; i++) {
54
+ if (!prevValue.has(notVisibleIds[i])) {
55
+ same = false
56
+ break
57
+ }
58
+ }
59
+ if (same) return prevValue
38
60
  }
39
61
 
40
- return prevValue
62
+ return new Set(notVisibleIds)
41
63
  })
42
64
  }
@@ -240,41 +240,6 @@ describe('EdgeScrollManager', () => {
240
240
  })
241
241
  })
242
242
 
243
- describe('camera movement conditions', () => {
244
- it('should not move camera when not dragging', () => {
245
- editor.inputs.setIsDragging(false)
246
- mockInputs.setCurrentScreenPoint(new Vec(5, 300))
247
-
248
- edgeScrollManager.updateEdgeScrolling(300)
249
-
250
- expect(editor.setCamera).not.toHaveBeenCalled()
251
- })
252
-
253
- it('should not move camera when panning', () => {
254
- editor.inputs.setIsPanning(true)
255
- mockInputs.setCurrentScreenPoint(new Vec(5, 300))
256
-
257
- edgeScrollManager.updateEdgeScrolling(300)
258
-
259
- expect(editor.setCamera).not.toHaveBeenCalled()
260
- })
261
-
262
- it('should not move camera when camera is locked', () => {
263
- editor.getCameraOptions.mockReturnValue({
264
- isLocked: true,
265
- panSpeed: 1,
266
- zoomSpeed: 1,
267
- zoomSteps: [1],
268
- wheelBehavior: 'pan' as const,
269
- })
270
- mockInputs.setCurrentScreenPoint(new Vec(5, 300))
271
-
272
- edgeScrollManager.updateEdgeScrolling(300)
273
-
274
- expect(editor.setCamera).not.toHaveBeenCalled()
275
- })
276
- })
277
-
278
243
  describe('camera movement calculation', () => {
279
244
  it('should calculate scroll speed based on user preference', () => {
280
245
  editor.user.getEdgeScrollSpeed.mockReturnValue(2)
@@ -1,6 +1,6 @@
1
1
  import { Vec } from '../../../primitives/Vec'
2
2
  import { EASINGS } from '../../../primitives/easings'
3
- import { Editor } from '../../Editor'
3
+ import type { Editor } from '../../Editor'
4
4
 
5
5
  /** @public */
6
6
  export class EdgeScrollManager {
@@ -21,6 +21,9 @@ export class EdgeScrollManager {
21
21
  */
22
22
  updateEdgeScrolling(elapsed: number) {
23
23
  const { editor } = this
24
+
25
+ if (editor.getCameraOptions().isLocked) return
26
+
24
27
  const edgeScrollProximityFactor = this.getEdgeScroll()
25
28
  if (edgeScrollProximityFactor.x === 0 && edgeScrollProximityFactor.y === 0) {
26
29
  if (this._isEdgeScrolling) {
@@ -106,15 +109,8 @@ export class EdgeScrollManager {
106
109
  * @public
107
110
  */
108
111
  private moveCameraWhenCloseToEdge(proximityFactor: { x: number; y: number }) {
109
- const { editor } = this
110
- if (
111
- !editor.inputs.getIsDragging() ||
112
- editor.inputs.getIsPanning() ||
113
- editor.getCameraOptions().isLocked
114
- )
115
- return
116
-
117
112
  if (proximityFactor.x === 0 && proximityFactor.y === 0) return
113
+ const { editor } = this
118
114
 
119
115
  const screenBounds = editor.getViewportScreenBounds()
120
116
 
@@ -8,7 +8,7 @@ import {
8
8
  mapObjectMapValues,
9
9
  objectMapEntries,
10
10
  } from '@tldraw/utils'
11
- import { Editor } from '../../Editor'
11
+ import type { Editor } from '../../Editor'
12
12
 
13
13
  /**
14
14
  * Represents the `src` property of a {@link TLFontFace}.
@@ -4,7 +4,7 @@ import { TLINSTANCE_ID, TLPOINTER_ID } from '@tldraw/tlschema'
4
4
  import { INTERNAL_POINTER_IDS } from '../../../constants'
5
5
  import { Vec } from '../../../primitives/Vec'
6
6
  import { isAccelKey } from '../../../utils/keyboard'
7
- import { Editor } from '../../Editor'
7
+ import type { Editor } from '../../Editor'
8
8
  import { TLPinchEventInfo, TLPointerEventInfo, TLWheelEventInfo } from '../../types/event-types'
9
9
 
10
10
  /** @public */
@@ -1,7 +1,7 @@
1
1
  import { TLScribble, VecModel } from '@tldraw/tlschema'
2
2
  import { uniqueId } from '@tldraw/utils'
3
3
  import { Vec } from '../../../primitives/Vec'
4
- import { Editor } from '../../Editor'
4
+ import type { Editor } from '../../Editor'
5
5
 
6
6
  /** @public */
7
7
  export interface ScribbleItem {
@@ -12,8 +12,8 @@ import {
12
12
  import { Mat } from '../../../primitives/Mat'
13
13
  import { Vec } from '../../../primitives/Vec'
14
14
  import { rangeIntersection, rangesOverlap } from '../../../primitives/utils'
15
- import { Editor } from '../../Editor'
16
- import {
15
+ import type { Editor } from '../../Editor'
16
+ import type {
17
17
  GapsSnapIndicator,
18
18
  PointsSnapIndicator,
19
19
  SnapData,