@tldraw/editor 4.6.0-next.30b99cd52fc8 → 4.6.0-next.35cf541abcf9

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 (284) hide show
  1. package/dist-cjs/index.d.ts +758 -96
  2. package/dist-cjs/index.js +18 -3
  3. package/dist-cjs/index.js.map +3 -3
  4. package/dist-cjs/lib/TldrawEditor.js +55 -12
  5. package/dist-cjs/lib/TldrawEditor.js.map +3 -3
  6. package/dist-cjs/lib/components/LiveCollaborators.js +1 -0
  7. package/dist-cjs/lib/components/LiveCollaborators.js.map +2 -2
  8. package/dist-cjs/lib/components/MenuClickCapture.js +99 -38
  9. package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +10 -3
  11. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +3 -3
  12. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +5 -2
  13. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  14. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +1 -1
  15. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  16. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +1 -0
  17. package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +2 -2
  18. package/dist-cjs/lib/config/createTLStore.js +7 -0
  19. package/dist-cjs/lib/config/createTLStore.js.map +2 -2
  20. package/dist-cjs/lib/config/defaultAssets.js +36 -0
  21. package/dist-cjs/lib/config/defaultAssets.js.map +7 -0
  22. package/dist-cjs/lib/editor/Editor.js +279 -10
  23. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  24. package/dist-cjs/lib/editor/assets/AssetUtil.js +67 -0
  25. package/dist-cjs/lib/editor/assets/AssetUtil.js.map +7 -0
  26. package/dist-cjs/lib/editor/bindings/BindingUtil.js +1 -0
  27. package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +1 -1
  28. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +1 -0
  29. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +1 -1
  30. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +1 -0
  31. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +1 -1
  32. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +1 -0
  33. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +1 -1
  34. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +2 -0
  35. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
  36. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +2 -0
  37. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +1 -1
  38. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +12 -0
  39. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
  40. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.js +80 -0
  41. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.js.map +7 -0
  42. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceManager.js +466 -0
  43. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceManager.js.map +7 -0
  44. package/dist-cjs/lib/editor/managers/PerformanceManager/perf-types.js +17 -0
  45. package/dist-cjs/lib/editor/managers/PerformanceManager/perf-types.js.map +7 -0
  46. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +1 -0
  47. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +1 -1
  48. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +1 -0
  49. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +1 -1
  50. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js +1 -0
  51. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +1 -1
  52. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +2 -1
  53. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
  54. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +1 -0
  55. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +1 -1
  56. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +1 -0
  57. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +1 -1
  58. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js +107 -0
  59. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js.map +7 -0
  60. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js +586 -0
  61. package/dist-cjs/lib/editor/managers/ThemeManager/defaultThemes.js.map +7 -0
  62. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +1 -0
  63. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +1 -1
  64. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +8 -4
  65. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  66. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +76 -0
  67. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +7 -0
  68. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +22 -2
  69. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  70. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +1 -1
  71. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  72. package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js +6 -0
  73. package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
  74. package/dist-cjs/lib/editor/tools/StateNode.js +15 -17
  75. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  76. package/dist-cjs/lib/editor/types/SvgExportContext.js.map +2 -2
  77. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  78. package/dist-cjs/lib/exports/ExportDelay.js +1 -0
  79. package/dist-cjs/lib/exports/ExportDelay.js.map +1 -1
  80. package/dist-cjs/lib/exports/StyleEmbedder.js +1 -0
  81. package/dist-cjs/lib/exports/StyleEmbedder.js.map +1 -1
  82. package/dist-cjs/lib/exports/getSvgJsx.js +14 -8
  83. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  84. package/dist-cjs/lib/globals/environment.js +18 -1
  85. package/dist-cjs/lib/globals/environment.js.map +2 -2
  86. package/dist-cjs/lib/hooks/useCanvasEvents.js +25 -4
  87. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  88. package/dist-cjs/lib/hooks/{useIsDarkMode.js → useColorMode.js} +14 -10
  89. package/dist-cjs/lib/hooks/useColorMode.js.map +7 -0
  90. package/dist-cjs/lib/hooks/useCursor.js +3 -7
  91. package/dist-cjs/lib/hooks/useCursor.js.map +2 -2
  92. package/dist-cjs/lib/hooks/useDarkMode.js +4 -4
  93. package/dist-cjs/lib/hooks/useDarkMode.js.map +2 -2
  94. package/dist-cjs/lib/options.js +2 -0
  95. package/dist-cjs/lib/options.js.map +2 -2
  96. package/dist-cjs/lib/primitives/Vec.js +3 -0
  97. package/dist-cjs/lib/primitives/Vec.js.map +1 -1
  98. package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -0
  99. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +1 -1
  100. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +1 -0
  101. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +1 -1
  102. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +2 -0
  103. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +1 -1
  104. package/dist-cjs/lib/primitives/geometry/Stadium2d.js +1 -0
  105. package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +1 -1
  106. package/dist-cjs/lib/utils/EditorAtom.js +2 -0
  107. package/dist-cjs/lib/utils/EditorAtom.js.map +1 -1
  108. package/dist-cjs/lib/utils/reparenting.js +2 -1
  109. package/dist-cjs/lib/utils/reparenting.js.map +2 -2
  110. package/dist-cjs/lib/utils/richText.js.map +2 -2
  111. package/dist-cjs/lib/utils/runtime.js +2 -1
  112. package/dist-cjs/lib/utils/runtime.js.map +2 -2
  113. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +2 -0
  114. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +1 -1
  115. package/dist-cjs/lib/utils/sync/hardReset.js +0 -8
  116. package/dist-cjs/lib/utils/sync/hardReset.js.map +2 -2
  117. package/dist-cjs/version.js +3 -3
  118. package/dist-cjs/version.js.map +1 -1
  119. package/dist-esm/index.d.mts +758 -96
  120. package/dist-esm/index.mjs +19 -6
  121. package/dist-esm/index.mjs.map +2 -2
  122. package/dist-esm/lib/TldrawEditor.mjs +58 -12
  123. package/dist-esm/lib/TldrawEditor.mjs.map +3 -3
  124. package/dist-esm/lib/components/LiveCollaborators.mjs +1 -0
  125. package/dist-esm/lib/components/LiveCollaborators.mjs.map +2 -2
  126. package/dist-esm/lib/components/MenuClickCapture.mjs +100 -39
  127. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  128. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +10 -3
  129. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +3 -3
  130. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +5 -2
  131. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  132. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +1 -1
  133. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  134. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +1 -0
  135. package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +2 -2
  136. package/dist-esm/lib/config/createTLStore.mjs +10 -1
  137. package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
  138. package/dist-esm/lib/config/defaultAssets.mjs +16 -0
  139. package/dist-esm/lib/config/defaultAssets.mjs.map +7 -0
  140. package/dist-esm/lib/editor/Editor.mjs +279 -10
  141. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  142. package/dist-esm/lib/editor/assets/AssetUtil.mjs +47 -0
  143. package/dist-esm/lib/editor/assets/AssetUtil.mjs.map +7 -0
  144. package/dist-esm/lib/editor/bindings/BindingUtil.mjs +1 -0
  145. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +1 -1
  146. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +1 -0
  147. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +1 -1
  148. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +1 -0
  149. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +1 -1
  150. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +1 -0
  151. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +1 -1
  152. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +2 -0
  153. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
  154. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +2 -0
  155. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +1 -1
  156. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +12 -0
  157. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
  158. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.mjs +60 -0
  159. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.mjs.map +7 -0
  160. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceManager.mjs +438 -0
  161. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceManager.mjs.map +7 -0
  162. package/dist-esm/lib/editor/managers/PerformanceManager/perf-types.mjs +1 -0
  163. package/dist-esm/lib/editor/managers/PerformanceManager/perf-types.mjs.map +7 -0
  164. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +1 -0
  165. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +1 -1
  166. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +1 -0
  167. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +1 -1
  168. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs +1 -0
  169. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +1 -1
  170. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +2 -1
  171. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
  172. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +1 -0
  173. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +1 -1
  174. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +1 -0
  175. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +1 -1
  176. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs +89 -0
  177. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs.map +7 -0
  178. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs +568 -0
  179. package/dist-esm/lib/editor/managers/ThemeManager/defaultThemes.mjs.map +7 -0
  180. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +1 -0
  181. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +1 -1
  182. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +8 -4
  183. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  184. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +56 -0
  185. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +7 -0
  186. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +22 -2
  187. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  188. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +1 -1
  189. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  190. package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs +6 -0
  191. package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
  192. package/dist-esm/lib/editor/tools/StateNode.mjs +15 -17
  193. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  194. package/dist-esm/lib/editor/types/SvgExportContext.mjs.map +2 -2
  195. package/dist-esm/lib/exports/ExportDelay.mjs +1 -0
  196. package/dist-esm/lib/exports/ExportDelay.mjs.map +1 -1
  197. package/dist-esm/lib/exports/StyleEmbedder.mjs +1 -0
  198. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +1 -1
  199. package/dist-esm/lib/exports/getSvgJsx.mjs +14 -11
  200. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  201. package/dist-esm/lib/globals/environment.mjs +18 -1
  202. package/dist-esm/lib/globals/environment.mjs.map +2 -2
  203. package/dist-esm/lib/hooks/useCanvasEvents.mjs +25 -4
  204. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  205. package/dist-esm/lib/hooks/useColorMode.mjs +19 -0
  206. package/dist-esm/lib/hooks/useColorMode.mjs.map +7 -0
  207. package/dist-esm/lib/hooks/useCursor.mjs +3 -7
  208. package/dist-esm/lib/hooks/useCursor.mjs.map +2 -2
  209. package/dist-esm/lib/hooks/useDarkMode.mjs +4 -4
  210. package/dist-esm/lib/hooks/useDarkMode.mjs.map +2 -2
  211. package/dist-esm/lib/options.mjs +2 -0
  212. package/dist-esm/lib/options.mjs.map +2 -2
  213. package/dist-esm/lib/primitives/Vec.mjs +3 -0
  214. package/dist-esm/lib/primitives/Vec.mjs.map +1 -1
  215. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +1 -0
  216. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +1 -1
  217. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +1 -0
  218. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +1 -1
  219. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +2 -0
  220. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +1 -1
  221. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +1 -0
  222. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +1 -1
  223. package/dist-esm/lib/utils/EditorAtom.mjs +2 -0
  224. package/dist-esm/lib/utils/EditorAtom.mjs.map +1 -1
  225. package/dist-esm/lib/utils/reparenting.mjs +2 -1
  226. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  227. package/dist-esm/lib/utils/richText.mjs.map +2 -2
  228. package/dist-esm/lib/utils/runtime.mjs +2 -1
  229. package/dist-esm/lib/utils/runtime.mjs.map +2 -2
  230. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +2 -0
  231. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +1 -1
  232. package/dist-esm/lib/utils/sync/hardReset.mjs +0 -8
  233. package/dist-esm/lib/utils/sync/hardReset.mjs.map +2 -2
  234. package/dist-esm/version.mjs +3 -3
  235. package/dist-esm/version.mjs.map +1 -1
  236. package/editor.css +0 -37
  237. package/package.json +7 -7
  238. package/src/index.ts +24 -6
  239. package/src/lib/TldrawEditor.tsx +90 -13
  240. package/src/lib/components/LiveCollaborators.tsx +8 -2
  241. package/src/lib/components/MenuClickCapture.tsx +129 -49
  242. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +14 -3
  243. package/src/lib/components/default-components/DefaultCanvas.tsx +6 -2
  244. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +2 -2
  245. package/src/lib/components/default-components/DefaultShapeIndicators.tsx +2 -0
  246. package/src/lib/config/createTLStore.ts +22 -1
  247. package/src/lib/config/defaultAssets.ts +19 -0
  248. package/src/lib/editor/Editor.ts +387 -40
  249. package/src/lib/editor/assets/AssetUtil.ts +85 -0
  250. package/src/lib/editor/managers/FontManager/FontManager.test.ts +9 -2
  251. package/src/lib/editor/managers/FontManager/FontManager.ts +1 -67
  252. package/src/lib/editor/managers/InputsManager/InputsManager.ts +12 -0
  253. package/src/lib/editor/managers/PerformanceManager/PerformanceApiAdapter.ts +82 -0
  254. package/src/lib/editor/managers/PerformanceManager/PerformanceManager.test.ts +522 -0
  255. package/src/lib/editor/managers/PerformanceManager/PerformanceManager.ts +583 -0
  256. package/src/lib/editor/managers/PerformanceManager/perf-types.ts +196 -0
  257. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +13 -2
  258. package/src/lib/editor/managers/SnapManager/SnapManager.ts +1 -1
  259. package/src/lib/editor/managers/ThemeManager/ThemeManager.ts +116 -0
  260. package/src/lib/editor/managers/ThemeManager/defaultThemes.ts +605 -0
  261. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +23 -29
  262. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +5 -3
  263. package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +121 -0
  264. package/src/lib/editor/shapes/ShapeUtil.ts +39 -3
  265. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -1
  266. package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +7 -0
  267. package/src/lib/editor/tools/StateNode.ts +16 -18
  268. package/src/lib/editor/types/SvgExportContext.tsx +5 -0
  269. package/src/lib/editor/types/external-content.ts +1 -0
  270. package/src/lib/exports/getSvgJsx.tsx +23 -16
  271. package/src/lib/globals/environment.ts +18 -0
  272. package/src/lib/hooks/useCanvasEvents.ts +40 -3
  273. package/src/lib/hooks/{useIsDarkMode.ts → useColorMode.ts} +9 -5
  274. package/src/lib/hooks/useCursor.ts +3 -7
  275. package/src/lib/hooks/useDarkMode.ts +4 -4
  276. package/src/lib/options.ts +14 -0
  277. package/src/lib/utils/reparenting.ts +6 -2
  278. package/src/lib/utils/richText.ts +1 -1
  279. package/src/lib/utils/runtime.ts +3 -1
  280. package/src/lib/utils/sync/hardReset.ts +0 -8
  281. package/src/version.ts +3 -3
  282. package/dist-cjs/lib/hooks/useIsDarkMode.js.map +0 -7
  283. package/dist-esm/lib/hooks/useIsDarkMode.mjs +0 -15
  284. package/dist-esm/lib/hooks/useIsDarkMode.mjs.map +0 -7
@@ -65,6 +65,7 @@ import {
65
65
  } from "@tldraw/utils";
66
66
  import EventEmitter from "eventemitter3";
67
67
  import { createTLCurrentUser } from "../config/createTLCurrentUser.mjs";
68
+ import { checkAssets } from "../config/defaultAssets.mjs";
68
69
  import { checkBindings } from "../config/defaultBindings.mjs";
69
70
  import { checkShapesAndAddCore } from "../config/defaultShapes.mjs";
70
71
  import {
@@ -115,10 +116,12 @@ import { FocusManager } from "./managers/FocusManager/FocusManager.mjs";
115
116
  import { FontManager } from "./managers/FontManager/FontManager.mjs";
116
117
  import { HistoryManager } from "./managers/HistoryManager/HistoryManager.mjs";
117
118
  import { InputsManager } from "./managers/InputsManager/InputsManager.mjs";
119
+ import { PerformanceManager } from "./managers/PerformanceManager/PerformanceManager.mjs";
118
120
  import { ScribbleManager } from "./managers/ScribbleManager/ScribbleManager.mjs";
119
121
  import { SnapManager } from "./managers/SnapManager/SnapManager.mjs";
120
122
  import { SpatialIndexManager } from "./managers/SpatialIndexManager/SpatialIndexManager.mjs";
121
123
  import { TextManager } from "./managers/TextManager/TextManager.mjs";
124
+ import { ThemeManager, resolveThemes } from "./managers/ThemeManager/ThemeManager.mjs";
122
125
  import { TickManager } from "./managers/TickManager/TickManager.mjs";
123
126
  import { UserPreferencesManager } from "./managers/UserPreferencesManager/UserPreferencesManager.mjs";
124
127
  import { RootState } from "./tools/RootState.mjs";
@@ -129,6 +132,7 @@ class Editor extends EventEmitter {
129
132
  user,
130
133
  shapeUtils,
131
134
  bindingUtils,
135
+ assetUtils: assetUtilConstructors,
132
136
  tools,
133
137
  getContainer,
134
138
  // needs to be here for backwards compatibility with TldrawEditor
@@ -136,13 +140,15 @@ class Editor extends EventEmitter {
136
140
  cameraOptions,
137
141
  initialState,
138
142
  autoFocus,
139
- inferDarkMode,
140
143
  options: _options,
141
144
  // needs to be here for backwards compatibility with TldrawEditor
142
145
  // eslint-disable-next-line @typescript-eslint/no-deprecated
143
146
  textOptions: _textOptions,
144
147
  getShapeVisibility,
145
- fontAssetUrls
148
+ colorScheme,
149
+ fontAssetUrls,
150
+ themes,
151
+ initialTheme
146
152
  }) {
147
153
  super();
148
154
  this._getShapeVisibility = getShapeVisibility;
@@ -165,19 +171,27 @@ class Editor extends EventEmitter {
165
171
  ...cameraOptions,
166
172
  ...options?.camera
167
173
  });
174
+ this.getContainer = getContainer;
168
175
  this._textOptions = atom("text options", options?.text ?? null);
169
- this.user = new UserPreferencesManager(user ?? createTLCurrentUser(), inferDarkMode ?? false);
176
+ this.user = new UserPreferencesManager(user ?? createTLCurrentUser(), colorScheme ?? "light");
170
177
  this.disposables.add(() => this.user.dispose());
171
- this.getContainer = getContainer;
172
178
  this.textMeasure = new TextManager(this);
173
179
  this.disposables.add(() => this.textMeasure.dispose());
174
- this.fonts = new FontManager(this, fontAssetUrls);
180
+ this._themeManager = new ThemeManager(this, {
181
+ themes: resolveThemes(themes),
182
+ initial: initialTheme ?? "default"
183
+ });
184
+ this.disposables.add(() => this._themeManager.dispose());
175
185
  this._tickManager = new TickManager(this);
186
+ this.disposables.add(() => this._tickManager.dispose());
176
187
  this.disposables.add(() => {
177
188
  this.off("tick", this._decayCameraStateTimeout);
178
189
  this._setCameraState("idle");
179
190
  });
191
+ this.fonts = new FontManager(this, fontAssetUrls);
180
192
  this.inputs = new InputsManager(this);
193
+ this.performance = new PerformanceManager(this);
194
+ this.disposables.add(() => this.performance.dispose());
181
195
  class NewRoot extends RootState {
182
196
  static initial = initialState ?? "";
183
197
  }
@@ -205,6 +219,16 @@ class Editor extends EventEmitter {
205
219
  }
206
220
  this.shapeUtils = _shapeUtils;
207
221
  this.styleProps = _styleProps;
222
+ const _shapeUtilsByAssetType = {};
223
+ for (const Util of allShapeUtils) {
224
+ const assetTypes = Util.handledAssetTypes;
225
+ if (assetTypes) {
226
+ for (const assetType of assetTypes) {
227
+ _shapeUtilsByAssetType[assetType] = _shapeUtils[Util.type];
228
+ }
229
+ }
230
+ }
231
+ this._shapeUtilsByAssetType = _shapeUtilsByAssetType;
208
232
  const allBindingUtils = checkBindings(bindingUtils);
209
233
  const _bindingUtils = {};
210
234
  for (const Util of allBindingUtils) {
@@ -212,6 +236,15 @@ class Editor extends EventEmitter {
212
236
  _bindingUtils[Util.type] = util;
213
237
  }
214
238
  this.bindingUtils = _bindingUtils;
239
+ if (assetUtilConstructors) {
240
+ const allAssetUtils = checkAssets(assetUtilConstructors);
241
+ const _assetUtils = {};
242
+ for (const Util of allAssetUtils) {
243
+ const util = new Util(this);
244
+ _assetUtils[Util.type] = util;
245
+ }
246
+ this.assetUtils = _assetUtils;
247
+ }
215
248
  for (const Tool of [...tools]) {
216
249
  if (hasOwnProperty(this.root.children, Tool.id)) {
217
250
  throw Error(`Can't override tool with id "${Tool.id}"`);
@@ -652,6 +685,17 @@ class Editor extends EventEmitter {
652
685
  * @public
653
686
  */
654
687
  snaps;
688
+ /**
689
+ * A manager for performance measurement hooks.
690
+ *
691
+ * @public
692
+ */
693
+ performance;
694
+ /**
695
+ * A manager for the spatial index, tracking where shapes exist on the canvas.
696
+ *
697
+ * @internal
698
+ */
655
699
  _spatialIndex;
656
700
  /**
657
701
  * A manager for the any asynchronous events and making sure they're
@@ -666,6 +710,12 @@ class Editor extends EventEmitter {
666
710
  * @public
667
711
  */
668
712
  user;
713
+ /**
714
+ * A manager for the editor's themes.
715
+ *
716
+ * @internal
717
+ */
718
+ _themeManager;
669
719
  /**
670
720
  * A helper for measuring text.
671
721
  *
@@ -737,12 +787,117 @@ class Editor extends EventEmitter {
737
787
  * @public
738
788
  */
739
789
  dispose() {
790
+ this.stopCameraAnimation();
791
+ if (this.getInstanceState().followingUserId) {
792
+ this.stopFollowingUser();
793
+ }
740
794
  this.disposables.forEach((dispose) => dispose());
741
795
  this.disposables.clear();
796
+ this.menus.clearOpenMenus();
742
797
  this.store.dispose();
743
798
  this.isDisposed = true;
744
799
  this.emit("dispose");
745
800
  }
801
+ /* ------------------ Themes (shadowing the theme manager) ------------------ */
802
+ /**
803
+ * Get the current color mode (`'light'` or `'dark'`), based on the user's dark mode preference.
804
+ *
805
+ * @public
806
+ */
807
+ getColorMode() {
808
+ return this._themeManager.getColorMode();
809
+ }
810
+ /**
811
+ * Set the color mode. Note that this is a convenience method that passes the mode to
812
+ * `user.updateUserPreferences`, which is the source of truth for the user's color mode preference.
813
+ *
814
+ * @public
815
+ */
816
+ setColorMode(mode) {
817
+ this.user.updateUserPreferences({ colorScheme: mode });
818
+ return this;
819
+ }
820
+ /**
821
+ * Get the id of the current theme.
822
+ *
823
+ * @public
824
+ */
825
+ getCurrentThemeId() {
826
+ return this._themeManager.getCurrentThemeId();
827
+ }
828
+ /**
829
+ * Get the current theme definition.
830
+ *
831
+ * @public
832
+ */
833
+ getCurrentTheme() {
834
+ return this._themeManager.getCurrentTheme();
835
+ }
836
+ /**
837
+ * Set the current theme by id.
838
+ *
839
+ * @public
840
+ */
841
+ setCurrentTheme(id) {
842
+ this._themeManager.setCurrentTheme(id);
843
+ return this;
844
+ }
845
+ /**
846
+ * Get all registered theme definitions.
847
+ *
848
+ * @public
849
+ */
850
+ getThemes() {
851
+ return this._themeManager.getThemes();
852
+ }
853
+ /**
854
+ * Get a single theme definition by id.
855
+ *
856
+ * @public
857
+ */
858
+ getTheme(id) {
859
+ return this._themeManager.getTheme(id);
860
+ }
861
+ /**
862
+ * Replace all theme definitions, or update them via a callback that receives a deep copy.
863
+ * The `'default'` theme must always be present in the result.
864
+ *
865
+ * @example
866
+ * ```ts
867
+ * // Replace all themes
868
+ * editor.updateThemes({ default: myDefaultTheme, ocean: myOceanTheme })
869
+ *
870
+ * // Update via callback
871
+ * editor.updateThemes((themes) => {
872
+ * delete themes.ocean
873
+ * return themes
874
+ * })
875
+ * ```
876
+ *
877
+ * @public
878
+ */
879
+ updateThemes(themes) {
880
+ this._themeManager.updateThemes(themes);
881
+ return this;
882
+ }
883
+ /**
884
+ * Register or update a single theme definition. The theme is keyed by its `id` property.
885
+ *
886
+ * @example
887
+ * ```ts
888
+ * // Override a property on the default theme
889
+ * editor.updateTheme({ ...editor.getTheme('default')!, fontSize: 24 })
890
+ *
891
+ * // Register a new theme
892
+ * editor.updateTheme({ id: 'ocean', ...myOceanTheme })
893
+ * ```
894
+ *
895
+ * @public
896
+ */
897
+ updateTheme(theme) {
898
+ this._themeManager.updateTheme(theme);
899
+ return this;
900
+ }
746
901
  /* ------------------- Shape Utils ------------------ */
747
902
  /**
748
903
  * A map of shape utility classes (TLShapeUtils) by shape type.
@@ -750,6 +905,8 @@ class Editor extends EventEmitter {
750
905
  * @public
751
906
  */
752
907
  shapeUtils;
908
+ /** @internal */
909
+ _shapeUtilsByAssetType = {};
753
910
  styleProps;
754
911
  getShapeUtil(arg) {
755
912
  const type = typeof arg === "string" ? arg : arg.type;
@@ -761,6 +918,17 @@ class Editor extends EventEmitter {
761
918
  const type = typeof arg === "string" ? arg : arg.type;
762
919
  return hasOwnProperty(this.shapeUtils, type);
763
920
  }
921
+ /**
922
+ * Get the shape util that handles the given asset type.
923
+ * Returns the shape util whose {@link ShapeUtil.handledAssetTypes} includes
924
+ * the given asset type, or undefined if none matches.
925
+ *
926
+ * @param assetType - The asset type string.
927
+ * @public
928
+ */
929
+ getShapeUtilForAssetType(assetType) {
930
+ return getOwnProperty(this._shapeUtilsByAssetType, assetType);
931
+ }
764
932
  /* ------------------- Binding Utils ------------------ */
765
933
  /**
766
934
  * A map of shape utility classes (TLShapeUtils) by shape type.
@@ -774,6 +942,42 @@ class Editor extends EventEmitter {
774
942
  assert(bindingUtil, `No binding util found for type "${type}"`);
775
943
  return bindingUtil;
776
944
  }
945
+ /* ------------------- Asset Utils ------------------ */
946
+ /**
947
+ * A map of asset utility classes by asset type.
948
+ *
949
+ * @public
950
+ */
951
+ assetUtils = {};
952
+ getAssetUtil(arg) {
953
+ const type = typeof arg === "string" ? arg : arg.type;
954
+ const assetUtil = getOwnProperty(this.assetUtils, type);
955
+ assert(assetUtil, `No asset util found for type "${type}"`);
956
+ return assetUtil;
957
+ }
958
+ /**
959
+ * Returns true if the editor has an asset util for the given asset type.
960
+ *
961
+ * @public
962
+ */
963
+ hasAssetUtil(arg) {
964
+ const type = typeof arg === "string" ? arg : arg.type;
965
+ return hasOwnProperty(this.assetUtils, type);
966
+ }
967
+ /**
968
+ * Get the asset util that accepts the given MIME type.
969
+ * Returns null if no registered asset util accepts the MIME type.
970
+ *
971
+ * @public
972
+ */
973
+ getAssetUtilForMimeType(mimeType) {
974
+ for (const util of Object.values(this.assetUtils)) {
975
+ if (util && util.acceptsMimeType(mimeType)) {
976
+ return util;
977
+ }
978
+ }
979
+ return null;
980
+ }
777
981
  /* --------------------- History -------------------- */
778
982
  /**
779
983
  * A manager for the editor's history.
@@ -795,6 +999,7 @@ class Editor extends EventEmitter {
795
999
  this._flushEventsForTick(0);
796
1000
  this.complete();
797
1001
  this.history.undo();
1002
+ this.performance._notifyUndoRedo("undo", this.history.getNumUndos(), this.history.getNumRedos());
798
1003
  return this;
799
1004
  }
800
1005
  canUndo() {
@@ -817,6 +1022,7 @@ class Editor extends EventEmitter {
817
1022
  this._flushEventsForTick(0);
818
1023
  this.complete();
819
1024
  this.history.redo();
1025
+ this.performance._notifyUndoRedo("redo", this.history.getNumUndos(), this.history.getNumRedos());
820
1026
  return this;
821
1027
  }
822
1028
  canRedo() {
@@ -3971,7 +4177,7 @@ class Editor extends EventEmitter {
3971
4177
  const searchMargin = Math.max(innerMargin, outerMargin, this.options.hitTestMargin / zoomLevel);
3972
4178
  const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, searchMargin);
3973
4179
  const shapesToCheck = (opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted()).filter((shape) => {
3974
- if (!candidateIds.has(shape.id) && !this.isShapeOfType(shape, "frame")) return false;
4180
+ if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) return false;
3975
4181
  if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group"))
3976
4182
  return false;
3977
4183
  const pageMask = this.getShapeMask(shape);
@@ -3984,14 +4190,16 @@ class Editor extends EventEmitter {
3984
4190
  const geometry = this.getShapeGeometry(shape);
3985
4191
  const isGroup = geometry instanceof Group2d;
3986
4192
  const pointInShapeSpace = this.getPointInShapeSpace(shape, point);
3987
- if (this.isShapeOfType(shape, "frame") || (this.isShapeOfType(shape, "note") || this.isShapeOfType(shape, "arrow") || this.isShapeOfType(shape, "geo") && shape.props.fill === "none") && this.getShapeUtil(shape).getText(shape)?.trim()) {
4193
+ const shapeUtil = this.getShapeUtil(shape);
4194
+ const isShapeFrameLike = this.isShapeFrameLike(shape);
4195
+ if (isShapeFrameLike || (this.isShapeOfType(shape, "note") || this.isShapeOfType(shape, "arrow") || this.isShapeOfType(shape, "geo") && shape.props.fill === "none") && shapeUtil.getText(shape)?.trim()) {
3988
4196
  for (const childGeometry of geometry.children) {
3989
4197
  if (childGeometry.isLabel && childGeometry.isPointInBounds(pointInShapeSpace)) {
3990
4198
  return shape;
3991
4199
  }
3992
4200
  }
3993
4201
  }
3994
- if (this.isShapeOfType(shape, "frame")) {
4202
+ if (isShapeFrameLike) {
3995
4203
  const distance2 = geometry.distanceToPoint(pointInShapeSpace, hitFrameInside);
3996
4204
  if (hitFrameInside ? distance2 > 0 && distance2 <= outerMargin || distance2 <= 0 && distance2 > -innerMargin : distance2 > 0 && distance2 <= outerMargin) {
3997
4205
  return inMarginClosestToEdgeHit || shape;
@@ -4085,7 +4293,7 @@ class Editor extends EventEmitter {
4085
4293
  const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, margin);
4086
4294
  return this.getCurrentPageShapesSorted().filter((shape) => {
4087
4295
  if (this.isShapeHidden(shape)) return false;
4088
- if (!candidateIds.has(shape.id) && !this.isShapeOfType(shape, "frame")) return false;
4296
+ if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) return false;
4089
4297
  return this.isPointInShape(shape, point, opts);
4090
4298
  }).reverse();
4091
4299
  }
@@ -4198,6 +4406,24 @@ class Editor extends EventEmitter {
4198
4406
  if (!shape) return false;
4199
4407
  return shape.type === type;
4200
4408
  }
4409
+ /**
4410
+ * Get whether a shape behaves like a frame — a container that has child
4411
+ * shapes, requires full-brush selection, blocks erasure from inside, etc.
4412
+ *
4413
+ * @example
4414
+ * ```ts
4415
+ * const isFrameLike = editor.isShapeFrameLike(someShape)
4416
+ * ```
4417
+ *
4418
+ * @param shape - The shape (or shape id) to test.
4419
+ *
4420
+ * @public
4421
+ */
4422
+ isShapeFrameLike(shape) {
4423
+ const _shape = typeof shape === "string" ? this.getShape(shape) : shape;
4424
+ if (!_shape) return false;
4425
+ return this.getShapeUtil(_shape).isFrameLike(_shape);
4426
+ }
4201
4427
  /**
4202
4428
  * Get a shape by its id.
4203
4429
  *
@@ -7723,6 +7949,7 @@ class Editor extends EventEmitter {
7723
7949
  ),
7724
7950
  { immediate: true }
7725
7951
  );
7952
+ this.performance._notifyCameraOperation("zooming");
7726
7953
  this.emit("event", info);
7727
7954
  return;
7728
7955
  }
@@ -7784,6 +8011,7 @@ class Editor extends EventEmitter {
7784
8011
  immediate: true
7785
8012
  });
7786
8013
  this.maybeTrackPerformance("Zooming");
8014
+ this.performance._notifyCameraOperation("zooming");
7787
8015
  this.root.handleEvent(info);
7788
8016
  this.emit("event", info);
7789
8017
  return;
@@ -7793,6 +8021,7 @@ class Editor extends EventEmitter {
7793
8021
  immediate: true
7794
8022
  });
7795
8023
  this.maybeTrackPerformance("Panning");
8024
+ this.performance._notifyCameraOperation("panning");
7796
8025
  this.root.handleEvent(info);
7797
8026
  this.emit("event", info);
7798
8027
  return;
@@ -7839,6 +8068,10 @@ class Editor extends EventEmitter {
7839
8068
  }
7840
8069
  this.inputs.setIsPanning(true);
7841
8070
  clearTimeout(this._longPressTimeout);
8071
+ } else if (info.button === RIGHT_MOUSE_BUTTON && this.options.rightClickPanning) {
8072
+ this.inputs.setIsRightPointing(true);
8073
+ clearTimeout(this._longPressTimeout);
8074
+ return this;
7842
8075
  }
7843
8076
  if (this.inputs.getIsPanning()) {
7844
8077
  this.stopCameraAnimation();
@@ -7850,6 +8083,22 @@ class Editor extends EventEmitter {
7850
8083
  case "pointer_move": {
7851
8084
  if (!isPen && isPenMode) return;
7852
8085
  const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
8086
+ if (this.inputs.getIsRightPointing() && !this.inputs.getIsPanning()) {
8087
+ const currentScreenPoint = this.inputs.getCurrentScreenPoint();
8088
+ const originScreenPoint = this.inputs.getOriginScreenPoint();
8089
+ if (Vec.Dist2(originScreenPoint, currentScreenPoint) > this.options.dragDistanceSquared) {
8090
+ this._prevCursor = this.getInstanceState().cursor.type;
8091
+ this.inputs.setIsPanning(true);
8092
+ this.setCursor({ type: "grabbing", rotation: 0 });
8093
+ this.stopCameraAnimation();
8094
+ const offset = Vec.Sub(currentScreenPoint, originScreenPoint);
8095
+ this.setCamera(new Vec(cx + offset.x / cz, cy + offset.y / cz, cz), {
8096
+ immediate: true
8097
+ });
8098
+ this.maybeTrackPerformance("Panning");
8099
+ }
8100
+ return;
8101
+ }
7853
8102
  if (this.inputs.getIsPanning() && this.inputs.getIsPointing()) {
7854
8103
  const currentScreenPoint = this.inputs.getCurrentScreenPoint();
7855
8104
  const previousScreenPoint = this.inputs.getPreviousScreenPoint();
@@ -7858,6 +8107,7 @@ class Editor extends EventEmitter {
7858
8107
  immediate: true
7859
8108
  });
7860
8109
  this.maybeTrackPerformance("Panning");
8110
+ this.performance._notifyCameraOperation("panning");
7861
8111
  return;
7862
8112
  }
7863
8113
  if (inputs.getIsPointing() && !inputs.getIsDragging() && Vec.Dist2(inputs.getOriginPagePoint(), inputs.getCurrentPagePoint()) * this.getZoomLevel() > (instanceState.isCoarsePointer ? this.options.coarseDragDistanceSquared : this.options.dragDistanceSquared) / cz) {
@@ -7872,6 +8122,12 @@ class Editor extends EventEmitter {
7872
8122
  clearTimeout(this._longPressTimeout);
7873
8123
  inputs.buttons.delete(info.button);
7874
8124
  if (instanceState.isPenMode && !isPen) return;
8125
+ if (this.inputs.getIsRightPointing() && !this.inputs.getIsPanning()) {
8126
+ this.inputs.setIsRightPointing(false);
8127
+ this._selectedShapeIdsAtPointerDown = [];
8128
+ break;
8129
+ }
8130
+ this.inputs.setIsRightPointing(false);
7875
8131
  if (this.capturedPointerId === info.pointerId) {
7876
8132
  this.capturedPointerId = null;
7877
8133
  info.button = 0;
@@ -7889,11 +8145,24 @@ class Editor extends EventEmitter {
7889
8145
  break;
7890
8146
  }
7891
8147
  case MIDDLE_MOUSE_BUTTON: {
7892
- if (this.inputs.keys.has(" ")) {
8148
+ if (this.inputs.keys.has("Space")) {
8149
+ this.setCursor({ type: "grab", rotation: 0 });
8150
+ } else {
8151
+ this.setCursor({ type: this._prevCursor, rotation: 0 });
8152
+ }
8153
+ break;
8154
+ }
8155
+ case RIGHT_MOUSE_BUTTON: {
8156
+ if (this.inputs.keys.has("Space")) {
7893
8157
  this.setCursor({ type: "grab", rotation: 0 });
7894
8158
  } else {
7895
8159
  this.setCursor({ type: this._prevCursor, rotation: 0 });
7896
8160
  }
8161
+ if (slideSpeed > 0) {
8162
+ this.slideCamera({ speed: slideSpeed, direction: slideDirection });
8163
+ }
8164
+ this._selectedShapeIdsAtPointerDown = [];
8165
+ return this;
7897
8166
  }
7898
8167
  }
7899
8168
  if (slideSpeed > 0) {