@tldraw/editor 5.4.0-next.ef99ab47e5ce → 5.5.0-canary.078a77321dc3

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 (288) hide show
  1. package/dist-cjs/index.d.ts +119 -49
  2. package/dist-cjs/index.js +4 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +7 -2
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/MenuClickCapture.js +6 -8
  7. package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/CanvasOverlays.js +1 -3
  9. package/dist-cjs/lib/components/default-components/CanvasOverlays.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
  11. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +1 -1
  12. package/dist-cjs/lib/config/TLUserPreferences.js +6 -2
  13. package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
  14. package/dist-cjs/lib/config/createTLStore.js +1 -1
  15. package/dist-cjs/lib/config/createTLStore.js.map +2 -2
  16. package/dist-cjs/lib/constants.js +2 -0
  17. package/dist-cjs/lib/constants.js.map +2 -2
  18. package/dist-cjs/lib/editor/Editor.js +190 -300
  19. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  20. package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js +7 -3
  21. package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js.map +2 -2
  22. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +3 -3
  23. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
  24. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +8 -8
  25. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
  26. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +10 -6
  27. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
  28. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +2 -1
  29. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
  30. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +79 -6
  31. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
  32. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +7 -0
  33. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +2 -2
  34. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +0 -2
  35. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +2 -2
  36. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +1 -2
  37. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  38. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js +7 -3
  39. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js.map +2 -2
  40. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +6 -3
  41. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
  42. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +12 -1
  43. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  44. package/dist-cjs/lib/editor/overlays/OverlayManager.js +3 -7
  45. package/dist-cjs/lib/editor/overlays/OverlayManager.js.map +2 -2
  46. package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +0 -1
  47. package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +2 -2
  48. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js +3 -1
  49. package/dist-cjs/lib/editor/shapes/BaseFrameLikeShapeUtil.js.map +2 -2
  50. package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js +1 -0
  51. package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
  52. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +1 -1
  53. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
  54. package/dist-cjs/lib/editor/tools/StateNode.js +3 -2
  55. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  56. package/dist-cjs/lib/globals/editors.js +57 -0
  57. package/dist-cjs/lib/globals/editors.js.map +7 -0
  58. package/dist-cjs/lib/globals/menus.js +9 -4
  59. package/dist-cjs/lib/globals/menus.js.map +2 -2
  60. package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -0
  61. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  62. package/dist-cjs/lib/hooks/useDocumentEvents.js +39 -9
  63. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  64. package/dist-cjs/lib/hooks/useLocalStore.js +10 -6
  65. package/dist-cjs/lib/hooks/useLocalStore.js.map +2 -2
  66. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +1 -0
  67. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
  68. package/dist-cjs/lib/hooks/usePeerIds.js +2 -1
  69. package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
  70. package/dist-cjs/lib/license/LicenseManager.js +9 -2
  71. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  72. package/dist-cjs/lib/license/LicenseProvider.js +16 -3
  73. package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
  74. package/dist-cjs/lib/license/useLicenseManagerState.js +5 -4
  75. package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
  76. package/dist-cjs/lib/primitives/Box.js +2 -1
  77. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  78. package/dist-cjs/lib/primitives/Vec.js +4 -3
  79. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  80. package/dist-cjs/lib/primitives/geometry/Arc2d.js +1 -1
  81. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  82. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +1 -1
  83. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  84. package/dist-cjs/lib/primitives/geometry/Edge2d.js +1 -1
  85. package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
  86. package/dist-cjs/lib/primitives/geometry/Group2d.js +71 -26
  87. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  88. package/dist-cjs/lib/primitives/geometry/Point2d.js +1 -1
  89. package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
  90. package/dist-cjs/lib/primitives/utils.js +2 -1
  91. package/dist-cjs/lib/primitives/utils.js.map +2 -2
  92. package/dist-cjs/lib/utils/deepLinks.js +5 -1
  93. package/dist-cjs/lib/utils/deepLinks.js.map +2 -2
  94. package/dist-cjs/lib/utils/normalizeWheel.js +2 -0
  95. package/dist-cjs/lib/utils/normalizeWheel.js.map +2 -2
  96. package/dist-cjs/lib/utils/rotation.js +1 -9
  97. package/dist-cjs/lib/utils/rotation.js.map +2 -2
  98. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +17 -0
  99. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
  100. package/dist-cjs/lib/utils/sync/alerts.js +1 -1
  101. package/dist-cjs/lib/utils/sync/alerts.js.map +1 -1
  102. package/dist-cjs/version.js +3 -3
  103. package/dist-cjs/version.js.map +1 -1
  104. package/dist-esm/index.d.mts +119 -49
  105. package/dist-esm/index.mjs +9 -2
  106. package/dist-esm/index.mjs.map +2 -2
  107. package/dist-esm/lib/TldrawEditor.mjs +9 -4
  108. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  109. package/dist-esm/lib/components/MenuClickCapture.mjs +6 -8
  110. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  111. package/dist-esm/lib/components/default-components/CanvasOverlays.mjs +1 -3
  112. package/dist-esm/lib/components/default-components/CanvasOverlays.mjs.map +2 -2
  113. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
  114. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +1 -1
  115. package/dist-esm/lib/config/TLUserPreferences.mjs +6 -2
  116. package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
  117. package/dist-esm/lib/config/createTLStore.mjs +1 -1
  118. package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
  119. package/dist-esm/lib/constants.mjs +2 -0
  120. package/dist-esm/lib/constants.mjs.map +2 -2
  121. package/dist-esm/lib/editor/Editor.mjs +199 -301
  122. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  123. package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs +7 -3
  124. package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs.map +2 -2
  125. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +3 -3
  126. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
  127. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +9 -9
  128. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
  129. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +10 -6
  130. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
  131. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +2 -1
  132. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
  133. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +81 -8
  134. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
  135. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +7 -0
  136. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +2 -2
  137. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +0 -2
  138. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +2 -2
  139. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +2 -3
  140. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  141. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs +7 -3
  142. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs.map +2 -2
  143. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +6 -3
  144. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
  145. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +12 -1
  146. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  147. package/dist-esm/lib/editor/overlays/OverlayManager.mjs +3 -7
  148. package/dist-esm/lib/editor/overlays/OverlayManager.mjs.map +2 -2
  149. package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +0 -1
  150. package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +2 -2
  151. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs +3 -1
  152. package/dist-esm/lib/editor/shapes/BaseFrameLikeShapeUtil.mjs.map +2 -2
  153. package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs +1 -0
  154. package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
  155. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +1 -1
  156. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
  157. package/dist-esm/lib/editor/tools/StateNode.mjs +3 -2
  158. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  159. package/dist-esm/lib/globals/editors.mjs +37 -0
  160. package/dist-esm/lib/globals/editors.mjs.map +7 -0
  161. package/dist-esm/lib/globals/menus.mjs +9 -4
  162. package/dist-esm/lib/globals/menus.mjs.map +2 -2
  163. package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -0
  164. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  165. package/dist-esm/lib/hooks/useDocumentEvents.mjs +40 -10
  166. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  167. package/dist-esm/lib/hooks/useLocalStore.mjs +11 -7
  168. package/dist-esm/lib/hooks/useLocalStore.mjs.map +2 -2
  169. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +1 -0
  170. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
  171. package/dist-esm/lib/hooks/usePeerIds.mjs +2 -1
  172. package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
  173. package/dist-esm/lib/license/LicenseManager.mjs +9 -2
  174. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  175. package/dist-esm/lib/license/LicenseProvider.mjs +16 -3
  176. package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
  177. package/dist-esm/lib/license/useLicenseManagerState.mjs +5 -4
  178. package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
  179. package/dist-esm/lib/primitives/Box.mjs +2 -1
  180. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  181. package/dist-esm/lib/primitives/Vec.mjs +4 -3
  182. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  183. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +1 -1
  184. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  185. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +1 -1
  186. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  187. package/dist-esm/lib/primitives/geometry/Edge2d.mjs +1 -1
  188. package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
  189. package/dist-esm/lib/primitives/geometry/Group2d.mjs +75 -27
  190. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  191. package/dist-esm/lib/primitives/geometry/Point2d.mjs +1 -1
  192. package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
  193. package/dist-esm/lib/primitives/utils.mjs +2 -1
  194. package/dist-esm/lib/primitives/utils.mjs.map +2 -2
  195. package/dist-esm/lib/utils/deepLinks.mjs +5 -1
  196. package/dist-esm/lib/utils/deepLinks.mjs.map +2 -2
  197. package/dist-esm/lib/utils/normalizeWheel.mjs +2 -0
  198. package/dist-esm/lib/utils/normalizeWheel.mjs.map +2 -2
  199. package/dist-esm/lib/utils/rotation.mjs +1 -9
  200. package/dist-esm/lib/utils/rotation.mjs.map +2 -2
  201. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +17 -0
  202. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
  203. package/dist-esm/lib/utils/sync/alerts.mjs +1 -1
  204. package/dist-esm/lib/utils/sync/alerts.mjs.map +1 -1
  205. package/dist-esm/version.mjs +3 -3
  206. package/dist-esm/version.mjs.map +1 -1
  207. package/package.json +13 -7
  208. package/src/index.ts +6 -1
  209. package/src/lib/TldrawEditor.tsx +16 -4
  210. package/src/lib/components/MenuClickCapture.tsx +19 -18
  211. package/src/lib/components/default-components/CanvasOverlays.tsx +1 -3
  212. package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
  213. package/src/lib/config/TLUserPreferences.test.ts +18 -1
  214. package/src/lib/config/TLUserPreferences.ts +8 -4
  215. package/src/lib/config/createTLStore.ts +1 -1
  216. package/src/lib/constants.ts +8 -0
  217. package/src/lib/editor/Editor.ts +285 -392
  218. package/src/lib/editor/derivations/shapeIdsInCurrentPage.ts +7 -3
  219. package/src/lib/editor/managers/ClickManager/ClickManager.ts +5 -3
  220. package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +9 -9
  221. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +35 -4
  222. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +13 -7
  223. package/src/lib/editor/managers/FontManager/FontManager.ts +2 -1
  224. package/src/lib/editor/managers/InputsManager/InputsManager.test.ts +199 -3
  225. package/src/lib/editor/managers/InputsManager/InputsManager.ts +128 -9
  226. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +12 -1
  227. package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +0 -2
  228. package/src/lib/editor/managers/TextManager/TextManager.ts +2 -6
  229. package/src/lib/editor/managers/ThemeManager/ThemeManager.test.ts +53 -0
  230. package/src/lib/editor/managers/ThemeManager/ThemeManager.ts +9 -3
  231. package/src/lib/editor/managers/TickManager/TickManager.test.ts +13 -0
  232. package/src/lib/editor/managers/TickManager/TickManager.ts +9 -3
  233. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +64 -3
  234. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +18 -1
  235. package/src/lib/editor/overlays/OverlayManager.ts +3 -7
  236. package/src/lib/editor/overlays/strokeShapeIndicators.ts +0 -1
  237. package/src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx +5 -1
  238. package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +3 -0
  239. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +4 -1
  240. package/src/lib/editor/tools/StateNode.test.ts +64 -0
  241. package/src/lib/editor/tools/StateNode.ts +12 -2
  242. package/src/lib/globals/editors.test.ts +76 -0
  243. package/src/lib/globals/editors.ts +53 -0
  244. package/src/lib/globals/menus.test.ts +33 -0
  245. package/src/lib/globals/menus.ts +11 -4
  246. package/src/lib/hooks/useCanvasEvents.ts +2 -0
  247. package/src/lib/hooks/useDocumentEvents.ts +60 -16
  248. package/src/lib/hooks/useLocalStore.ts +16 -8
  249. package/src/lib/hooks/usePassThroughWheelEvents.ts +3 -0
  250. package/src/lib/hooks/usePeerIds.ts +2 -1
  251. package/src/lib/license/LicenseManager.test.ts +160 -0
  252. package/src/lib/license/LicenseManager.ts +13 -4
  253. package/src/lib/license/LicenseProvider.tsx +24 -3
  254. package/src/lib/license/useLicenseManagerState.ts +8 -6
  255. package/src/lib/primitives/Box.test.ts +9 -1
  256. package/src/lib/primitives/Box.ts +3 -1
  257. package/src/lib/primitives/Vec.test.ts +10 -0
  258. package/src/lib/primitives/Vec.ts +4 -4
  259. package/src/lib/primitives/geometry/Arc2d.test.ts +235 -3
  260. package/src/lib/primitives/geometry/Arc2d.ts +1 -1
  261. package/src/lib/primitives/geometry/CubicBezier2d.test.ts +186 -3
  262. package/src/lib/primitives/geometry/CubicBezier2d.ts +1 -1
  263. package/src/lib/primitives/geometry/CubicSpline2d.test.ts +160 -3
  264. package/src/lib/primitives/geometry/Edge2d.test.ts +21 -3
  265. package/src/lib/primitives/geometry/Edge2d.ts +1 -1
  266. package/src/lib/primitives/geometry/Ellipse2d.test.ts +243 -3
  267. package/src/lib/primitives/geometry/Geometry2d.test.ts +553 -1
  268. package/src/lib/primitives/geometry/Group2d.test.ts +419 -3
  269. package/src/lib/primitives/geometry/Group2d.ts +81 -34
  270. package/src/lib/primitives/geometry/Point2d.test.ts +14 -3
  271. package/src/lib/primitives/geometry/Point2d.ts +1 -1
  272. package/src/lib/primitives/geometry/Polyline2d.test.ts +207 -0
  273. package/src/lib/primitives/geometry/Stadium2d.test.ts +191 -3
  274. package/src/lib/primitives/utils.test.ts +10 -1
  275. package/src/lib/primitives/utils.ts +4 -1
  276. package/src/lib/test/useCanvasEvents.test.tsx +74 -0
  277. package/src/lib/test/useDocumentEvents.test.tsx +107 -0
  278. package/src/lib/test/usePassThroughWheelEvents.test.tsx +25 -2
  279. package/src/lib/utils/deepLinks.test.ts +15 -0
  280. package/src/lib/utils/deepLinks.ts +7 -1
  281. package/src/lib/utils/normalizeWheel.test.ts +39 -0
  282. package/src/lib/utils/normalizeWheel.ts +6 -0
  283. package/src/lib/utils/rotation.ts +4 -12
  284. package/src/lib/utils/sync/TLLocalSyncClient.test.ts +56 -0
  285. package/src/lib/utils/sync/TLLocalSyncClient.ts +24 -0
  286. package/src/lib/utils/sync/alerts.ts +1 -1
  287. package/src/version.ts +3 -3
  288. package/src/lib/primitives/geometry/Polyline.test.ts +0 -5
@@ -53,6 +53,7 @@ var import_constants = require("../constants");
53
53
  var import_domUtils = require("../exports/domUtils");
54
54
  var import_exportToSvg = require("../exports/exportToSvg");
55
55
  var import_getSvgAsImage = require("../exports/getSvgAsImage");
56
+ var import_editors = require("../globals/editors");
56
57
  var import_menus = require("../globals/menus");
57
58
  var import_time = require("../globals/time");
58
59
  var import_options = require("../options");
@@ -256,6 +257,10 @@ class Editor extends import_eventemitter3.default {
256
257
  if (!nextPageState) nextPageState = { ...prevPageState };
257
258
  nextPageState.editingShapeId = null;
258
259
  }
260
+ if (prevPageState.croppingShapeId && shapesNoLongerInPage.has(prevPageState.croppingShapeId)) {
261
+ if (!nextPageState) nextPageState = { ...prevPageState };
262
+ nextPageState.croppingShapeId = null;
263
+ }
259
264
  const hintingShapeIds = prevPageState.hintingShapeIds.filter(
260
265
  (id) => !shapesNoLongerInPage.has(id)
261
266
  );
@@ -498,10 +503,11 @@ class Editor extends import_eventemitter3.default {
498
503
  this.cancelDoubleClick();
499
504
  }
500
505
  if (prev?.selectedShapeIds !== next?.selectedShapeIds) {
506
+ const selectedShapeIds = new Set(next.selectedShapeIds);
501
507
  const filtered = next.selectedShapeIds.filter((id) => {
502
508
  let parentId = this.getShape(id)?.parentId;
503
509
  while ((0, import_tlschema.isShapeId)(parentId)) {
504
- if (next.selectedShapeIds.includes(parentId)) {
510
+ if (selectedShapeIds.has(parentId)) {
505
511
  return false;
506
512
  }
507
513
  parentId = this.getShape(parentId)?.parentId;
@@ -571,9 +577,11 @@ class Editor extends import_eventemitter3.default {
571
577
  this.on("tick", this._flushEventsForTick);
572
578
  this.on("mount", () => {
573
579
  this._isMounted.set(true);
580
+ (0, import_editors.registerMountedEditor)(this);
574
581
  });
575
582
  this.on("unmount", () => {
576
583
  this._isMounted.set(false);
584
+ (0, import_editors.unregisterMountedEditor)(this);
577
585
  });
578
586
  this.timers.requestAnimationFrame(() => {
579
587
  this._tickManager.start();
@@ -583,7 +591,10 @@ class Editor extends import_eventemitter3.default {
583
591
  const mode = this.store.props.collaboration.mode;
584
592
  this.disposables.add(
585
593
  (0, import_state.react)("update collaboration mode", () => {
586
- this.store.put([{ ...this.getInstanceState(), isReadonly: mode.get() === "readonly" }]);
594
+ const isReadonly = mode.get() === "readonly";
595
+ (0, import_state.unsafe__withoutCapture)(
596
+ () => this._updateInstanceState({ isReadonly }, { history: "ignore" })
597
+ );
587
598
  })
588
599
  );
589
600
  }
@@ -613,6 +624,14 @@ class Editor extends import_eventemitter3.default {
613
624
  );
614
625
  }
615
626
  options;
627
+ /**
628
+ * The license manager whose feature flags apply to this editor. Assigned by `<TldrawEditor />`
629
+ * when it creates the editor, so that UI rendered outside the editor tree can resolve the
630
+ * editor's license through the editor instance. Undefined for editors created directly.
631
+ *
632
+ * @internal
633
+ */
634
+ licenseManager;
616
635
  contextId = (0, import_utils.uniqueId)();
617
636
  /**
618
637
  * The editor's store
@@ -807,6 +826,7 @@ class Editor extends import_eventemitter3.default {
807
826
  if (this._isMounted.get()) {
808
827
  this.emit("unmount");
809
828
  }
829
+ (0, import_editors.unregisterMountedEditor)(this);
810
830
  this.stopCameraAnimation();
811
831
  if (this.getInstanceState().followingUserId) {
812
832
  this.stopFollowingUser();
@@ -932,7 +952,7 @@ class Editor extends import_eventemitter3.default {
932
952
  getShapeUtil(arg) {
933
953
  const type = typeof arg === "string" ? arg : arg.type;
934
954
  const shapeUtil = (0, import_utils.getOwnProperty)(this.shapeUtils, type);
935
- (0, import_utils.assert)(shapeUtil, `No shape util found for type "${type}"`);
955
+ if (!shapeUtil) throw new Error(`No shape util found for type "${type}"`);
936
956
  return shapeUtil;
937
957
  }
938
958
  hasShapeUtil(arg) {
@@ -1597,7 +1617,8 @@ class Editor extends import_eventemitter3.default {
1597
1617
  if (direction === "next" || direction === "prev") {
1598
1618
  const shapeIds = readingOrderShapes.map((shape2) => shape2.id);
1599
1619
  const currentIndex = currentShapeId ? shapeIds.indexOf(currentShapeId) : -1;
1600
- const adjacentIndex = (currentIndex + (direction === "next" ? 1 : -1) + shapeIds.length) % shapeIds.length;
1620
+ const startIndex = currentIndex === -1 && direction === "prev" ? 0 : currentIndex;
1621
+ const adjacentIndex = (startIndex + (direction === "next" ? 1 : -1) + shapeIds.length) % shapeIds.length;
1601
1622
  adjacentShapeId = shapeIds[adjacentIndex];
1602
1623
  } else {
1603
1624
  if (!currentShapeId) return;
@@ -1721,7 +1742,9 @@ class Editor extends import_eventemitter3.default {
1721
1742
  const selectedShapes = this.getSelectedShapes();
1722
1743
  if (!selectedShapes.length) return;
1723
1744
  const selectedShape = selectedShapes[0];
1724
- const children = this.getSortedChildIdsForParent(selectedShape.id).map((id) => this.getShape(id)).filter((i) => i);
1745
+ const children = (0, import_utils.compact)(
1746
+ this.getSortedChildIdsForParent(selectedShape.id).map((id) => this.getShape(id))
1747
+ );
1725
1748
  const sortedChildren = this._getShapesInReadingOrder(children);
1726
1749
  if (sortedChildren.length === 0) return;
1727
1750
  this._selectShapesAndZoom([sortedChildren[0].id]);
@@ -1788,18 +1811,13 @@ class Editor extends import_eventemitter3.default {
1788
1811
  * @internal
1789
1812
  */
1790
1813
  getShapesSharedRotation(shapeIds) {
1791
- let foundFirst = false;
1792
1814
  let rotation = 0;
1793
1815
  for (let i = 0, n = shapeIds.length; i < n; i++) {
1794
- const pageTransform = this.getShapePageTransform(shapeIds[i]);
1795
- if (!pageTransform) continue;
1796
- if (foundFirst) {
1797
- if (pageTransform.rotation() !== rotation) {
1798
- return 0;
1799
- }
1800
- } else {
1801
- foundFirst = true;
1802
- rotation = pageTransform.rotation();
1816
+ const pageRotation = this.getShapePageTransform(shapeIds[i]).rotation();
1817
+ if (i === 0) {
1818
+ rotation = pageRotation;
1819
+ } else if (pageRotation !== rotation) {
1820
+ return 0;
1803
1821
  }
1804
1822
  }
1805
1823
  return rotation;
@@ -1825,11 +1843,9 @@ class Editor extends import_eventemitter3.default {
1825
1843
  return bounds;
1826
1844
  }
1827
1845
  const boxFromRotatedVertices = import_Box.Box.FromPoints(
1828
- shapeIds.flatMap((id) => {
1829
- const pageTransform = this.getShapePageTransform(id);
1830
- if (!pageTransform) return [];
1831
- return pageTransform.applyToPoints(this.getShapeGeometry(id).bounds.corners);
1832
- }).map((p) => p.rot(-selectionRotation))
1846
+ shapeIds.flatMap(
1847
+ (id) => this.getShapePageTransform(id).applyToPoints(this.getShapeGeometry(id).bounds.corners)
1848
+ ).map((p) => p.rot(-selectionRotation))
1833
1849
  );
1834
1850
  boxFromRotatedVertices.point = boxFromRotatedVertices.point.rot(selectionRotation);
1835
1851
  return boxFromRotatedVertices;
@@ -1840,9 +1856,14 @@ class Editor extends import_eventemitter3.default {
1840
1856
  getSelectionRotatedScreenBounds() {
1841
1857
  const bounds = this.getSelectionRotatedPageBounds();
1842
1858
  if (!bounds) return void 0;
1843
- const { x, y } = this.pageToScreen(bounds.point);
1844
- const zoom = this.getZoomLevel();
1845
- return new import_Box.Box(x, y, bounds.width * zoom, bounds.height * zoom);
1859
+ const screenBounds = this.getViewportScreenBounds();
1860
+ const { x: cx, y: cy, z: zoom } = this.getCamera();
1861
+ return new import_Box.Box(
1862
+ (bounds.x + cx) * zoom + screenBounds.x,
1863
+ (bounds.y + cy) * zoom + screenBounds.y,
1864
+ bounds.width * zoom,
1865
+ bounds.height * zoom
1866
+ );
1846
1867
  }
1847
1868
  getFocusedGroupId() {
1848
1869
  return this.getCurrentPageState().focusedGroupId ?? this.getCurrentPageId();
@@ -1943,42 +1964,28 @@ class Editor extends import_eventemitter3.default {
1943
1964
  */
1944
1965
  setEditingShape(shape) {
1945
1966
  const id = typeof shape === "string" ? shape : shape?.id ?? null;
1946
- if (!id) {
1967
+ if (id && !this.canEditShape(id)) return this;
1968
+ this.run(() => {
1969
+ const prevEditingShapeId = this.getEditingShapeId();
1970
+ if (prevEditingShapeId) {
1971
+ const prevEditingShape = this.getShape(prevEditingShapeId);
1972
+ if (prevEditingShape) {
1973
+ this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1974
+ }
1975
+ }
1947
1976
  this.run(
1948
1977
  () => {
1949
- const prevEditingShapeId = this.getEditingShapeId();
1950
- if (prevEditingShapeId) {
1951
- const prevEditingShape = this.getShape(prevEditingShapeId);
1952
- if (prevEditingShape) {
1953
- this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1954
- }
1955
- }
1956
1978
  this._updateCurrentPageState({ editingShapeId: null });
1957
1979
  this._currentRichTextEditor.set(null);
1980
+ if (!id) return;
1981
+ this.select(id);
1982
+ this._updateCurrentPageState({ editingShapeId: id });
1983
+ const nextEditingShape = this.getShape(id);
1984
+ this.getShapeUtil(nextEditingShape).onEditStart?.(nextEditingShape);
1958
1985
  },
1959
1986
  { history: "ignore" }
1960
1987
  );
1961
- return this;
1962
- }
1963
- if (!this.canEditShape(id)) return this;
1964
- this.run(
1965
- () => {
1966
- const prevEditingShapeId = this.getEditingShapeId();
1967
- if (prevEditingShapeId) {
1968
- const prevEditingShape = this.getShape(prevEditingShapeId);
1969
- if (prevEditingShape) {
1970
- this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1971
- }
1972
- }
1973
- this._updateCurrentPageState({ editingShapeId: null });
1974
- this._currentRichTextEditor.set(null);
1975
- this.select(id);
1976
- this._updateCurrentPageState({ editingShapeId: id });
1977
- const nextEditingShape = this.getShape(id);
1978
- this.getShapeUtil(nextEditingShape).onEditStart?.(nextEditingShape);
1979
- },
1980
- { history: "ignore" }
1981
- );
1988
+ });
1982
1989
  return this;
1983
1990
  }
1984
1991
  // Rich text editor
@@ -2084,19 +2091,12 @@ class Editor extends import_eventemitter3.default {
2084
2091
  * @public
2085
2092
  */
2086
2093
  setErasingShapes(shapes) {
2087
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
2094
+ const ids = typeof shapes[0] === "string" ? shapes.slice() : shapes.map((shape) => shape.id);
2088
2095
  ids.sort();
2089
2096
  const erasingShapeIds = this.getErasingShapeIds();
2090
2097
  this.run(
2091
2098
  () => {
2092
- if (ids.length === erasingShapeIds.length) {
2093
- for (let i = 0; i < ids.length; i++) {
2094
- if (ids[i] !== erasingShapeIds[i]) {
2095
- this._updateCurrentPageState({ erasingShapeIds: ids });
2096
- break;
2097
- }
2098
- }
2099
- } else {
2099
+ if (!(0, import_utils.areArraysShallowEqual)(ids, erasingShapeIds)) {
2100
2100
  this._updateCurrentPageState({ erasingShapeIds: ids });
2101
2101
  }
2102
2102
  },
@@ -2129,6 +2129,7 @@ class Editor extends import_eventemitter3.default {
2129
2129
  if (!_shape) return false;
2130
2130
  const util = this.getShapeUtil(_shape);
2131
2131
  if (!util.canCrop(_shape)) return false;
2132
+ if (this.getIsReadonly()) return false;
2132
2133
  if (this.isShapeOrAncestorLocked(_shape)) return false;
2133
2134
  return true;
2134
2135
  }
@@ -2193,11 +2194,11 @@ class Editor extends import_eventemitter3.default {
2193
2194
  const collaborators = this.getCollaborators();
2194
2195
  let leaderPresence = null;
2195
2196
  while (targetUserId && !visited.includes(targetUserId)) {
2196
- leaderPresence = collaborators.find((c) => c.userId === targetUserId) ?? null;
2197
- targetUserId = leaderPresence?.followingUserId ?? null;
2198
- if (leaderPresence) {
2199
- visited.push(leaderPresence.userId);
2200
- }
2197
+ const nextPresence = collaborators.find((c) => c.userId === targetUserId);
2198
+ if (!nextPresence) break;
2199
+ leaderPresence = nextPresence;
2200
+ targetUserId = nextPresence.followingUserId ?? null;
2201
+ visited.push(nextPresence.userId);
2201
2202
  }
2202
2203
  return leaderPresence;
2203
2204
  }
@@ -2260,39 +2261,7 @@ class Editor extends import_eventemitter3.default {
2260
2261
  *
2261
2262
  * @public */
2262
2263
  getInitialZoom() {
2263
- const cameraOptions = this.getCameraOptions();
2264
- if (!cameraOptions.constraints) return 1;
2265
- if (cameraOptions.constraints.initialZoom === "default") return 1;
2266
- const { zx, zy } = getCameraFitXFitY(this, cameraOptions);
2267
- switch (cameraOptions.constraints.initialZoom) {
2268
- case "fit-min": {
2269
- return Math.max(zx, zy);
2270
- }
2271
- case "fit-max": {
2272
- return Math.min(zx, zy);
2273
- }
2274
- case "fit-x": {
2275
- return zx;
2276
- }
2277
- case "fit-y": {
2278
- return zy;
2279
- }
2280
- case "fit-min-100": {
2281
- return Math.min(1, Math.max(zx, zy));
2282
- }
2283
- case "fit-max-100": {
2284
- return Math.min(1, Math.min(zx, zy));
2285
- }
2286
- case "fit-x-100": {
2287
- return Math.min(1, zx);
2288
- }
2289
- case "fit-y-100": {
2290
- return Math.min(1, zy);
2291
- }
2292
- default: {
2293
- throw (0, import_utils.exhaustiveSwitchError)(cameraOptions.constraints.initialZoom);
2294
- }
2295
- }
2264
+ return this._getFitZoom(this.getCameraOptions().constraints?.initialZoom ?? "default");
2296
2265
  }
2297
2266
  /**
2298
2267
  * Get the camera's base level for calculating actual zoom levels based on the zoom steps.
@@ -2304,11 +2273,13 @@ class Editor extends import_eventemitter3.default {
2304
2273
  *
2305
2274
  * @public */
2306
2275
  getBaseZoom() {
2276
+ return this._getFitZoom(this.getCameraOptions().constraints?.baseZoom ?? "default");
2277
+ }
2278
+ _getFitZoom(fit) {
2307
2279
  const cameraOptions = this.getCameraOptions();
2308
- if (!cameraOptions.constraints) return 1;
2309
- if (cameraOptions.constraints.baseZoom === "default") return 1;
2280
+ if (!cameraOptions.constraints || fit === "default") return 1;
2310
2281
  const { zx, zy } = getCameraFitXFitY(this, cameraOptions);
2311
- switch (cameraOptions.constraints.baseZoom) {
2282
+ switch (fit) {
2312
2283
  case "fit-min": {
2313
2284
  return Math.max(zx, zy);
2314
2285
  }
@@ -2334,7 +2305,7 @@ class Editor extends import_eventemitter3.default {
2334
2305
  return Math.min(1, zy);
2335
2306
  }
2336
2307
  default: {
2337
- throw (0, import_utils.exhaustiveSwitchError)(cameraOptions.constraints.baseZoom);
2308
+ throw (0, import_utils.exhaustiveSwitchError)(fit);
2338
2309
  }
2339
2310
  }
2340
2311
  }
@@ -2368,7 +2339,7 @@ class Editor extends import_eventemitter3.default {
2368
2339
  ...this._cameraOptions.__unsafe__getWithoutCapture(),
2369
2340
  ...opts
2370
2341
  });
2371
- if (next.zoomSteps?.length < 1) next.zoomSteps = [1];
2342
+ if (!next.zoomSteps || next.zoomSteps.length < 1) next.zoomSteps = [1];
2372
2343
  this._cameraOptions.set(next);
2373
2344
  this.setCamera(this.getCamera());
2374
2345
  return this;
@@ -2389,8 +2360,8 @@ class Editor extends import_eventemitter3.default {
2389
2360
  const vsb = this.getViewportScreenBounds();
2390
2361
  if (cameraOptions.constraints) {
2391
2362
  const { constraints } = cameraOptions;
2392
- const py = Math.min(constraints.padding.y, vsb.w / 2);
2393
- const px = Math.min(constraints.padding.x, vsb.h / 2);
2363
+ const px = Math.min(constraints.padding.x, vsb.w / 2);
2364
+ const py = Math.min(constraints.padding.y, vsb.h / 2);
2394
2365
  const bounds = import_Box.Box.From(cameraOptions.constraints.bounds);
2395
2366
  const zx = (vsb.w - px * 2) / bounds.w;
2396
2367
  const zy = (vsb.h - py * 2) / bounds.h;
@@ -2429,12 +2400,12 @@ class Editor extends import_eventemitter3.default {
2429
2400
  break;
2430
2401
  }
2431
2402
  case "inside": {
2432
- if (z < zx) x = (0, import_utils2.clamp)(x, minX, (vsb.w - px) / z - bounds.w);
2403
+ if (z < zx) x = (0, import_utils2.clamp)(x, minX, (vsb.w - px) / z - bounds.w - bounds.x);
2433
2404
  else x = (0, import_utils2.clamp)(x, minX + freeW, minX);
2434
2405
  break;
2435
2406
  }
2436
2407
  case "outside": {
2437
- x = (0, import_utils2.clamp)(x, px / z - bounds.w, (vsb.w - px) / z);
2408
+ x = (0, import_utils2.clamp)(x, px / z - bounds.w - bounds.x, (vsb.w - px) / z - bounds.x);
2438
2409
  break;
2439
2410
  }
2440
2411
  case "free": {
@@ -2455,12 +2426,12 @@ class Editor extends import_eventemitter3.default {
2455
2426
  break;
2456
2427
  }
2457
2428
  case "inside": {
2458
- if (z < zy) y = (0, import_utils2.clamp)(y, minY, (vsb.h - py) / z - bounds.h);
2429
+ if (z < zy) y = (0, import_utils2.clamp)(y, minY, (vsb.h - py) / z - bounds.h - bounds.y);
2459
2430
  else y = (0, import_utils2.clamp)(y, minY + freeH, minY);
2460
2431
  break;
2461
2432
  }
2462
2433
  case "outside": {
2463
- y = (0, import_utils2.clamp)(y, py / z - bounds.h, (vsb.h - py) / z);
2434
+ y = (0, import_utils2.clamp)(y, py / z - bounds.h - bounds.y, (vsb.h - py) / z - bounds.y);
2464
2435
  break;
2465
2436
  }
2466
2437
  case "free": {
@@ -2527,14 +2498,16 @@ class Editor extends import_eventemitter3.default {
2527
2498
  setCamera(point, opts) {
2528
2499
  const { isLocked } = this._cameraOptions.__unsafe__getWithoutCapture();
2529
2500
  if (isLocked && !opts?.force) return this;
2501
+ const _point = import_Vec.Vec.Cast(point);
2502
+ if (!Number.isFinite(_point.x) || !Number.isFinite(_point.y) || !Number.isFinite(_point.z)) {
2503
+ throw Error(
2504
+ `Editor.setCamera: expected finite values, got (${_point.x}, ${_point.y}, ${_point.z}).`
2505
+ );
2506
+ }
2530
2507
  this.stopCameraAnimation();
2531
2508
  if (this.getInstanceState().followingUserId) {
2532
2509
  this.stopFollowingUser();
2533
2510
  }
2534
- const _point = import_Vec.Vec.Cast(point);
2535
- if (!Number.isFinite(_point.x)) _point.x = 0;
2536
- if (!Number.isFinite(_point.y)) _point.y = 0;
2537
- if (_point.z === void 0 || !Number.isFinite(_point.z)) point.z = this.getZoomLevel();
2538
2511
  const camera = this.getConstrainedCamera(_point, opts);
2539
2512
  if (opts?.animation) {
2540
2513
  const { width, height } = this.getViewportScreenBounds();
@@ -2828,9 +2801,9 @@ class Editor extends import_eventemitter3.default {
2828
2801
  }
2829
2802
  const remaining = duration - elapsed;
2830
2803
  const t = easing(1 - remaining / duration);
2831
- const left = start.minX + (end.minX - start.minX) * t;
2832
- const top = start.minY + (end.minY - start.minY) * t;
2833
- const right = start.maxX + (end.maxX - start.maxX) * t;
2804
+ const left = (0, import_utils.lerp)(start.minX, end.minX, t);
2805
+ const top = (0, import_utils.lerp)(start.minY, end.minY, t);
2806
+ const right = (0, import_utils.lerp)(start.maxX, end.maxX, t);
2834
2807
  this._setCamera(new import_Vec.Vec(-left, -top, this.getViewportScreenBounds().width / (right - left)), {
2835
2808
  force: true
2836
2809
  });
@@ -2908,12 +2881,12 @@ class Editor extends import_eventemitter3.default {
2908
2881
  let newCy = cy + dy;
2909
2882
  let newCz = cz;
2910
2883
  if (dirZ !== 0) {
2911
- newCz = cz * (1 + dirZ * currentSpeed * elapsed);
2884
+ newCz = cz * Math.exp(dirZ * currentSpeed * elapsed);
2912
2885
  const center = this.getViewportScreenCenter();
2913
2886
  newCx += center.x / newCz - center.x / cz;
2914
2887
  newCy += center.y / newCz - center.y / cz;
2915
2888
  }
2916
- currentSpeed *= 1 - friction;
2889
+ currentSpeed *= (1 - friction) ** (elapsed / import_constants.FRAME_MS_60HZ);
2917
2890
  if (currentSpeed < speedThreshold) {
2918
2891
  cancel();
2919
2892
  } else {
@@ -3346,12 +3319,12 @@ class Editor extends import_eventemitter3.default {
3346
3319
  const renderingShapes = [];
3347
3320
  let nextIndex = this.options.maxShapesPerPage * 2;
3348
3321
  let nextBackgroundIndex = this.options.maxShapesPerPage;
3349
- const erasingShapeIds = this.getErasingShapeIds();
3322
+ const erasingShapeIds = new Set(this.getErasingShapeIds());
3350
3323
  const addShapeById = (id, opacity, isAncestorErasing) => {
3351
3324
  const shape = this.getShape(id);
3352
3325
  if (!shape) return;
3353
3326
  if (this.isShapeHidden(shape)) {
3354
- const isErasing = isAncestorErasing || erasingShapeIds.includes(id);
3327
+ const isErasing = isAncestorErasing || erasingShapeIds.has(id);
3355
3328
  for (const childId of this.getSortedChildIdsForParent(id)) {
3356
3329
  addShapeById(childId, opacity, isErasing);
3357
3330
  }
@@ -3361,7 +3334,7 @@ class Editor extends import_eventemitter3.default {
3361
3334
  let isShapeErasing = false;
3362
3335
  const util = this.getShapeUtil(shape);
3363
3336
  if (useEditorState) {
3364
- isShapeErasing = !isAncestorErasing && erasingShapeIds.includes(id);
3337
+ isShapeErasing = !isAncestorErasing && erasingShapeIds.has(id);
3365
3338
  if (isShapeErasing) {
3366
3339
  opacity *= 0.32;
3367
3340
  }
@@ -3953,10 +3926,8 @@ class Editor extends import_eventemitter3.default {
3953
3926
  }
3954
3927
  _getShapePageBoundsCache() {
3955
3928
  return this.store.createComputedCache("pageBoundsCache", (shape) => {
3956
- const pageTransform = this.getShapePageTransform(shape);
3957
- if (!pageTransform) return void 0;
3958
3929
  return import_Box.Box.FromPoints(
3959
- pageTransform.applyToPoints(this.getShapeGeometry(shape).boundsVertices)
3930
+ this.getShapePageTransform(shape).applyToPoints(this.getShapeGeometry(shape).boundsVertices)
3960
3931
  );
3961
3932
  });
3962
3933
  }
@@ -4074,7 +4045,9 @@ class Editor extends import_eventemitter3.default {
4074
4045
  if (pageMask) {
4075
4046
  if (pageMask.length === 0) return void 0;
4076
4047
  const { corners } = pageBounds;
4077
- if (corners.every((p, i) => p && import_Vec.Vec.Equals(p, pageMask[i]))) return pageBounds.clone();
4048
+ if (pageMask.length === corners.length && corners.every((p, i) => import_Vec.Vec.Equals(p, pageMask[i]))) {
4049
+ return pageBounds.clone();
4050
+ }
4078
4051
  const intersection = (0, import_intersect.intersectPolygonPolygon)(pageMask, corners);
4079
4052
  if (!intersection) return;
4080
4053
  return import_Box.Box.FromPoints(intersection);
@@ -4298,23 +4271,22 @@ class Editor extends import_eventemitter3.default {
4298
4271
  let inMarginClosestToEdgeHit = null;
4299
4272
  const searchMargin = Math.max(innerMargin, outerMargin, this.getHitTestMargin());
4300
4273
  const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, searchMargin);
4301
- const shapesToCheck = (opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted()).filter((shape) => {
4302
- if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) return false;
4303
- if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group"))
4304
- return false;
4305
- const pageMask = this.getShapeMask(shape);
4306
- if (pageMask && !(0, import_utils2.pointInPolygon)(point, pageMask)) return false;
4307
- if (filter && !filter(shape)) return false;
4308
- return true;
4309
- });
4274
+ const shapesToCheck = opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted();
4310
4275
  for (let i = shapesToCheck.length - 1; i >= 0; i--) {
4311
4276
  const shape = shapesToCheck[i];
4277
+ if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
4278
+ if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group")) {
4279
+ continue;
4280
+ }
4281
+ const pageMask = this.getShapeMask(shape);
4282
+ if (pageMask && !(0, import_utils2.pointInPolygon)(point, pageMask)) continue;
4283
+ if (filter && !filter(shape)) continue;
4312
4284
  const geometry = this.getShapeGeometry(shape);
4313
4285
  const isGroup = geometry instanceof import_Group2d.Group2d;
4314
4286
  const pointInShapeSpace = this.getPointInShapeSpace(shape, point);
4315
4287
  const shapeUtil = this.getShapeUtil(shape);
4316
4288
  const isShapeFrameLike = this.isShapeFrameLike(shape);
4317
- if (isShapeFrameLike || (this.isShapeOfType(shape, "note") || this.isShapeOfType(shape, "arrow") || this.isShapeOfType(shape, "geo") && shape.props.fill === "none") && shapeUtil.getText(shape)?.trim()) {
4289
+ if (isGroup && (isShapeFrameLike || (this.isShapeOfType(shape, "note") || this.isShapeOfType(shape, "arrow") || this.isShapeOfType(shape, "geo") && shape.props.fill === "none") && shapeUtil.getText(shape)?.trim())) {
4318
4290
  for (const childGeometry of geometry.children) {
4319
4291
  if (childGeometry.isLabel && childGeometry.isPointInBounds(pointInShapeSpace)) {
4320
4292
  return shape;
@@ -4413,11 +4385,15 @@ class Editor extends import_eventemitter3.default {
4413
4385
  getShapesAtPoint(point, opts = {}) {
4414
4386
  const margin = opts.margin ?? 0;
4415
4387
  const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, margin);
4416
- return this.getCurrentPageShapesSorted().filter((shape) => {
4417
- if (this.isShapeHidden(shape)) return false;
4418
- if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) return false;
4419
- return this.isPointInShape(shape, point, opts);
4420
- }).reverse();
4388
+ const sorted = this.getCurrentPageShapesSorted();
4389
+ const result = [];
4390
+ for (let i = sorted.length - 1; i >= 0; i--) {
4391
+ const shape = sorted[i];
4392
+ if (this.isShapeHidden(shape)) continue;
4393
+ if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
4394
+ if (this.isPointInShape(shape, point, opts)) result.push(shape);
4395
+ }
4396
+ return result;
4421
4397
  }
4422
4398
  /**
4423
4399
  * Get shape IDs within the given bounds.
@@ -4502,9 +4478,7 @@ class Editor extends import_eventemitter3.default {
4502
4478
  const freshShape = this.getShape(id);
4503
4479
  if (!freshShape) return new import_Vec.Vec(0, 0);
4504
4480
  if ((0, import_tlschema.isPageId)(freshShape.parentId)) return import_Vec.Vec.From(point);
4505
- const parentTransform = this.getShapePageTransform(freshShape.parentId);
4506
- if (!parentTransform) return import_Vec.Vec.From(point);
4507
- return parentTransform.clone().invert().applyToPoint(point);
4481
+ return this.getShapePageTransform(freshShape.parentId).clone().invert().applyToPoint(point);
4508
4482
  }
4509
4483
  getCurrentPageShapes() {
4510
4484
  return Array.from(this.getCurrentPageShapeIds(), (id) => this.store.get(id));
@@ -4616,23 +4590,7 @@ class Editor extends import_eventemitter3.default {
4616
4590
  * @public
4617
4591
  */
4618
4592
  isShapeInPage(shape, pageId = this.getCurrentPageId()) {
4619
- const id = typeof shape === "string" ? shape : shape.id;
4620
- const shapeToCheck = this.getShape(id);
4621
- if (!shapeToCheck) return false;
4622
- let shapeIsInPage = false;
4623
- if (shapeToCheck.parentId === pageId) {
4624
- shapeIsInPage = true;
4625
- } else {
4626
- let parent = this.getShape(shapeToCheck.parentId);
4627
- isInPageSearch: while (parent) {
4628
- if (parent.parentId === pageId) {
4629
- shapeIsInPage = true;
4630
- break isInPageSearch;
4631
- }
4632
- parent = this.getShape(parent.parentId);
4633
- }
4634
- }
4635
- return shapeIsInPage;
4593
+ return this.getAncestorPageId(shape) === pageId;
4636
4594
  }
4637
4595
  /**
4638
4596
  * Get the id of the containing page for a given shape.
@@ -4713,10 +4671,7 @@ class Editor extends import_eventemitter3.default {
4713
4671
  for (let i = 0; i < shapesToReparent.length; i++) {
4714
4672
  const shape = shapesToReparent[i];
4715
4673
  const pageTransform = this.getShapePageTransform(shape);
4716
- if (!pageTransform) continue;
4717
- const pagePoint = pageTransform.point();
4718
- if (!pagePoint) continue;
4719
- const newPoint = invertedParentTransform.applyToPoint(pagePoint);
4674
+ const newPoint = invertedParentTransform.applyToPoint(pageTransform.point());
4720
4675
  const newRotation = pageTransform.rotation() - parentPageRotation;
4721
4676
  if (shape.id === parentId) {
4722
4677
  throw Error("Attempted to reparent a shape to itself!");
@@ -4805,7 +4760,7 @@ class Editor extends import_eventemitter3.default {
4805
4760
  */
4806
4761
  getShapeAndDescendantIds(ids) {
4807
4762
  const shapeIds = /* @__PURE__ */ new Set();
4808
- for (const shape of ids.map((id) => this.getShape(id)).sort(import_utils.sortByIndex)) {
4763
+ for (const shape of (0, import_utils.compact)(ids.map((id) => this.getShape(id))).sort(import_utils.sortByIndex)) {
4809
4764
  shapeIds.add(shape.id);
4810
4765
  this.visitDescendants(shape, (descendantId) => {
4811
4766
  shapeIds.add(descendantId);
@@ -4827,11 +4782,12 @@ class Editor extends import_eventemitter3.default {
4827
4782
  const draggingShapes = (0, import_utils.compact)(droppingShapes.map((s) => this.getShape(s))).filter(
4828
4783
  (s) => !s.isLocked && !this.isShapeHidden(s)
4829
4784
  );
4785
+ const excludedIds = this.getShapeAndDescendantIds(draggingShapes.map((s) => s.id));
4830
4786
  const maybeDraggingOverShapes = this.getShapesAtPoint(point, {
4831
4787
  hitInside: true,
4832
4788
  margin: 0
4833
4789
  }).filter(
4834
- (s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !draggingShapes.includes(s)
4790
+ (s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !excludedIds.has(s.id)
4835
4791
  );
4836
4792
  for (const maybeDraggingOverShape of maybeDraggingOverShapes) {
4837
4793
  const shapeUtil = this.getShapeUtil(maybeDraggingOverShape);
@@ -5084,8 +5040,7 @@ class Editor extends import_eventemitter3.default {
5084
5040
  for (const id of ids) {
5085
5041
  const shape = this.getShape(id);
5086
5042
  const localDelta = import_Vec.Vec.From(offset);
5087
- const parentTransform = this.getShapeParentTransform(shape);
5088
- if (parentTransform) localDelta.rot(-parentTransform.rotation());
5043
+ localDelta.rot(-this.getShapeParentTransform(shape).rotation());
5089
5044
  changes.push(this.getChangesToTranslateShape(shape, localDelta.add(shape)));
5090
5045
  }
5091
5046
  this.updateShapes(changes);
@@ -5140,7 +5095,7 @@ class Editor extends import_eventemitter3.default {
5140
5095
  if (!originalShape) continue;
5141
5096
  let ox = 0;
5142
5097
  let oy = 0;
5143
- if (offset && initialIds.has(originalId)) {
5098
+ if (offset && initialIds.has(originalId) && !shapeIdSet.has(originalShape.parentId)) {
5144
5099
  const parentTransform = this.getShapeParentTransform(originalShape);
5145
5100
  const vec = new import_Vec.Vec(offset.x, offset.y).rot(-parentTransform.rotation());
5146
5101
  ox = vec.x;
@@ -5254,26 +5209,17 @@ class Editor extends import_eventemitter3.default {
5254
5209
  toggleLock(shapes) {
5255
5210
  const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5256
5211
  if (this.getIsReadonly() || ids.length === 0) return this;
5257
- let allLocked = true, allUnlocked = true;
5212
+ let allLocked = true;
5258
5213
  const shapesToToggle = [];
5259
5214
  for (const id of ids) {
5260
5215
  const shape = this.getShape(id);
5261
5216
  if (shape) {
5262
5217
  shapesToToggle.push(shape);
5263
- if (shape.isLocked) {
5264
- allUnlocked = false;
5265
- } else {
5266
- allLocked = false;
5267
- }
5218
+ if (!shape.isLocked) allLocked = false;
5268
5219
  }
5269
5220
  }
5270
5221
  this.run(() => {
5271
- if (allUnlocked) {
5272
- this.updateShapes(
5273
- shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: true }))
5274
- );
5275
- this.setSelectedShapes([]);
5276
- } else if (allLocked) {
5222
+ if (allLocked) {
5277
5223
  this.updateShapes(
5278
5224
  shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: false }))
5279
5225
  );
@@ -5281,6 +5227,7 @@ class Editor extends import_eventemitter3.default {
5281
5227
  this.updateShapes(
5282
5228
  shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: true }))
5283
5229
  );
5230
+ this.setSelectedShapes([]);
5284
5231
  }
5285
5232
  });
5286
5233
  return this;
@@ -5391,9 +5338,10 @@ class Editor extends import_eventemitter3.default {
5391
5338
  const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5392
5339
  let freshShapes = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
5393
5340
  if (opts?.filterAxisAligned) {
5394
- freshShapes = freshShapes.filter(
5395
- (s) => this.getShapePageTransform(s)?.rotation() % (import_utils2.PI / 2) === 0
5396
- );
5341
+ freshShapes = freshShapes.filter((s) => {
5342
+ const remainder = Math.abs(this.getShapePageTransform(s).rotation() % import_utils2.HALF_PI);
5343
+ return Math.min(remainder, import_utils2.HALF_PI - remainder) < 1e-9;
5344
+ });
5397
5345
  }
5398
5346
  const clusters = [];
5399
5347
  const allBounds = [];
@@ -5558,9 +5506,9 @@ class Editor extends import_eventemitter3.default {
5558
5506
  dim = "height";
5559
5507
  }
5560
5508
  let shapeGap = 0;
5509
+ shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
5561
5510
  if (_gap === 0) {
5562
5511
  const gaps = {};
5563
- shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
5564
5512
  for (let i = 0; i < len - 1; i++) {
5565
5513
  const currCluster = shapeClustersToStack[i];
5566
5514
  const nextCluster = shapeClustersToStack[i + 1];
@@ -5598,8 +5546,7 @@ class Editor extends import_eventemitter3.default {
5598
5546
  const shapeDelta = delta.clone();
5599
5547
  const parent = this.getShapeParent(shape);
5600
5548
  if (parent) {
5601
- const parentTransform = this.getShapePageTransform(parent);
5602
- if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
5549
+ shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5603
5550
  }
5604
5551
  shapeDelta.add(shape);
5605
5552
  changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
@@ -5637,7 +5584,7 @@ class Editor extends import_eventemitter3.default {
5637
5584
  }
5638
5585
  const commonBounds = import_Box.Box.Common(allBounds);
5639
5586
  const maxWidth = commonBounds.width;
5640
- shapeClustersToPack.sort((a, b) => a.pageBounds.width - b.pageBounds.width).sort((a, b) => a.pageBounds.height - b.pageBounds.height);
5587
+ shapeClustersToPack.sort((a, b) => b.pageBounds.width - a.pageBounds.width).sort((a, b) => b.pageBounds.height - a.pageBounds.height);
5641
5588
  const startWidth = Math.max(Math.ceil(Math.sqrt(area / 0.95)), maxWidth);
5642
5589
  const spaces = [new import_Box.Box(commonBounds.x, commonBounds.y, startWidth, Infinity)];
5643
5590
  let width = 0;
@@ -5685,8 +5632,7 @@ class Editor extends import_eventemitter3.default {
5685
5632
  const shapeDelta = delta.clone();
5686
5633
  const parent = this.getShapeParent(shape);
5687
5634
  if (parent) {
5688
- const parentTransform = this.getShapeParentTransform(shape);
5689
- if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
5635
+ shapeDelta.rot(-this.getShapeParentTransform(shape).rotation());
5690
5636
  }
5691
5637
  shapeDelta.add(shape);
5692
5638
  changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
@@ -5752,8 +5698,7 @@ class Editor extends import_eventemitter3.default {
5752
5698
  const shapeDelta = delta.clone();
5753
5699
  const parent = this.getShapeParent(shape);
5754
5700
  if (parent) {
5755
- const parentTransform = this.getShapePageTransform(parent);
5756
- if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
5701
+ shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5757
5702
  }
5758
5703
  shapeDelta.add(shape);
5759
5704
  changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
@@ -5827,8 +5772,7 @@ class Editor extends import_eventemitter3.default {
5827
5772
  const shapeDelta = delta.clone();
5828
5773
  const parent = this.getShapeParent(shape);
5829
5774
  if (parent) {
5830
- const parentTransform = this.getShapePageTransform(parent);
5831
- if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
5775
+ shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5832
5776
  }
5833
5777
  shapeDelta.add(shape);
5834
5778
  changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
@@ -5883,8 +5827,7 @@ class Editor extends import_eventemitter3.default {
5883
5827
  scale[val] = commonBounds[dim] / pageBounds[dim];
5884
5828
  for (const shape of shapes2) {
5885
5829
  const shapeLocalOffset = localOffset.clone();
5886
- const parentTransform = this.getShapeParentTransform(shape);
5887
- if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
5830
+ shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
5888
5831
  shapeLocalOffset.add(shape);
5889
5832
  const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
5890
5833
  this.updateShape(changes);
@@ -5940,8 +5883,7 @@ class Editor extends import_eventemitter3.default {
5940
5883
  );
5941
5884
  for (const shape of shapes2) {
5942
5885
  const shapeLocalOffset = localOffset.clone();
5943
- const parentTransform = this.getShapeParentTransform(shape);
5944
- if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
5886
+ shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
5945
5887
  shapeLocalOffset.add(shape);
5946
5888
  const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
5947
5889
  this.updateShape(changes);
@@ -5990,9 +5932,7 @@ class Editor extends import_eventemitter3.default {
5990
5932
  const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center;
5991
5933
  if (!scaleOrigin) return null;
5992
5934
  const pageTransform = opts.initialPageTransform ? import_Mat.Mat.Cast(opts.initialPageTransform) : this.getShapePageTransform(id);
5993
- if (!pageTransform) return null;
5994
5935
  const pageRotation = pageTransform.rotation();
5995
- if (pageRotation == null) return null;
5996
5936
  const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation;
5997
5937
  const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds;
5998
5938
  if (!initialBounds) return null;
@@ -6143,7 +6083,6 @@ class Editor extends import_eventemitter3.default {
6143
6083
  const currentLocalBounds = this.getShapeGeometry(id).bounds;
6144
6084
  const currentPageCenter = import_Mat.Mat.applyToPoint(pageTransform, currentLocalBounds.center);
6145
6085
  const shapePageTransformOrigin = pageTransform.point();
6146
- if (!currentPageCenter || !shapePageTransformOrigin) return this;
6147
6086
  const pageDelta = import_Vec.Vec.Sub(postScaleShapePageCenter, currentPageCenter);
6148
6087
  const postScaleShapePagePoint = import_Vec.Vec.Add(shapePageTransformOrigin, pageDelta);
6149
6088
  const { x, y } = this.getPointInParentSpace(id, postScaleShapePagePoint);
@@ -6402,10 +6341,10 @@ class Editor extends import_eventemitter3.default {
6402
6341
  if (animationIdForShape !== animationId) continue;
6403
6342
  updates.push({
6404
6343
  ...end,
6405
- x: start.x + (end.x - start.x) * t,
6406
- y: start.y + (end.y - start.y) * t,
6407
- opacity: start.opacity + (end.opacity - start.opacity) * t,
6408
- rotation: start.rotation + (end.rotation - start.rotation) * t,
6344
+ x: (0, import_utils.lerp)(start.x, end.x, t),
6345
+ y: (0, import_utils.lerp)(start.y, end.y, t),
6346
+ opacity: (0, import_utils.lerp)(start.opacity, end.opacity, t),
6347
+ rotation: (0, import_utils.lerp)(start.rotation, end.rotation, t),
6409
6348
  props: this.getShapeUtil(end).getInterpolatedProps?.(start, end, t) ?? end.props
6410
6349
  });
6411
6350
  }
@@ -6531,7 +6470,7 @@ class Editor extends import_eventemitter3.default {
6531
6470
  * @public
6532
6471
  */
6533
6472
  updateShapes(partials) {
6534
- const compactedPartials = Array(partials.length);
6473
+ const compactedPartials = [];
6535
6474
  for (let i = 0, n = partials.length; i < n; i++) {
6536
6475
  const partial = partials[i];
6537
6476
  if (!partial) continue;
@@ -6602,28 +6541,32 @@ class Editor extends import_eventemitter3.default {
6602
6541
  }
6603
6542
  /* --------------------- Styles --------------------- */
6604
6543
  /**
6605
- * Get all the current styles among the users selected shapes
6544
+ * Groups have no styles of their own: a style read or write on a selection applies to the
6545
+ * non-group shapes beneath each group, however deeply nested. Returns those shapes.
6606
6546
  *
6607
6547
  * @internal
6608
6548
  */
6609
- _extractSharedStyles(shape, sharedStyleMap) {
6610
- if (this.isShapeOfType(shape, "group")) {
6611
- const childIds = this._parentIdsToChildIds.get()[shape.id];
6612
- if (!childIds) return;
6613
- for (let i = 0, n = childIds.length; i < n; i++) {
6614
- this._extractSharedStyles(this.getShape(childIds[i]), sharedStyleMap);
6615
- }
6616
- } else {
6617
- for (const [style, propKey] of this.styleProps[shape.type]) {
6618
- sharedStyleMap.applyValue(style, (0, import_utils.getOwnProperty)(shape.props, propKey));
6549
+ _getStyleableShapes(shapes) {
6550
+ const result = [];
6551
+ const visit = (shape) => {
6552
+ if (this.isShapeOfType(shape, "group")) {
6553
+ for (const childId of this.getSortedChildIdsForParent(shape.id)) {
6554
+ const child = this.getShape(childId);
6555
+ if (child) visit(child);
6556
+ }
6557
+ } else {
6558
+ result.push(shape);
6619
6559
  }
6620
- }
6560
+ };
6561
+ for (const shape of shapes) visit(shape);
6562
+ return result;
6621
6563
  }
6622
6564
  _getSelectionSharedStyles() {
6623
- const selectedShapes = this.getSelectedShapes();
6624
6565
  const sharedStyles = new import_SharedStylesMap.SharedStyleMap();
6625
- for (const selectedShape of selectedShapes) {
6626
- this._extractSharedStyles(selectedShape, sharedStyles);
6566
+ for (const shape of this._getStyleableShapes(this.getSelectedShapes())) {
6567
+ for (const [style, propKey] of this.styleProps[shape.type]) {
6568
+ sharedStyles.applyValue(style, (0, import_utils.getOwnProperty)(shape.props, propKey));
6569
+ }
6627
6570
  }
6628
6571
  return sharedStyles;
6629
6572
  }
@@ -6655,38 +6598,16 @@ class Editor extends import_eventemitter3.default {
6655
6598
  const styles = new import_SharedStylesMap.SharedStyleMap();
6656
6599
  if (!currentTool) return styles;
6657
6600
  if (currentTool.shapeType) {
6658
- if (currentTool.shapeType === "frame" && !this.getShapeUtil("frame").options.showColors) {
6659
- for (const style of this.styleProps[currentTool.shapeType].keys()) {
6660
- if (style.id === "tldraw:color") continue;
6661
- styles.applyValue(style, this.getStyleForNextShape(style));
6662
- }
6663
- } else {
6664
- for (const style of this.styleProps[currentTool.shapeType].keys()) {
6665
- styles.applyValue(style, this.getStyleForNextShape(style));
6666
- }
6601
+ for (const style of this.styleProps[currentTool.shapeType].keys()) {
6602
+ styles.applyValue(style, this.getStyleForNextShape(style));
6667
6603
  }
6668
6604
  }
6669
6605
  return styles;
6670
6606
  }
6671
6607
  getSharedOpacity() {
6672
6608
  if (this.isIn("select") && this.getSelectedShapeIds().length > 0) {
6673
- const shapesToCheck = [];
6674
- const addShape = (shapeId) => {
6675
- const shape = this.getShape(shapeId);
6676
- if (!shape) return;
6677
- if (this.isShapeOfType(shape, "group")) {
6678
- for (const childId of this.getSortedChildIdsForParent(shape.id)) {
6679
- addShape(childId);
6680
- }
6681
- } else {
6682
- shapesToCheck.push(shape);
6683
- }
6684
- };
6685
- for (const shapeId of this.getSelectedShapeIds()) {
6686
- addShape(shapeId);
6687
- }
6688
6609
  let opacity = null;
6689
- for (const shape of shapesToCheck) {
6610
+ for (const shape of this._getStyleableShapes(this.getSelectedShapes())) {
6690
6611
  if (opacity === null) {
6691
6612
  opacity = shape.opacity;
6692
6613
  } else if (opacity !== shape.opacity) {
@@ -6725,28 +6646,12 @@ class Editor extends import_eventemitter3.default {
6725
6646
  setOpacityForSelectedShapes(opacity) {
6726
6647
  const selectedShapes = this.getSelectedShapes();
6727
6648
  if (selectedShapes.length > 0) {
6728
- const shapesToUpdate = [];
6729
- const addShapeById = (shape) => {
6730
- if (this.isShapeOfType(shape, "group")) {
6731
- const childIds = this.getSortedChildIdsForParent(shape);
6732
- for (const childId of childIds) {
6733
- addShapeById(this.getShape(childId));
6734
- }
6735
- } else {
6736
- shapesToUpdate.push(shape);
6737
- }
6738
- };
6739
- for (const id of selectedShapes) {
6740
- addShapeById(id);
6741
- }
6742
6649
  this.updateShapes(
6743
- shapesToUpdate.map((shape) => {
6744
- return {
6745
- id: shape.id,
6746
- type: shape.type,
6747
- opacity
6748
- };
6749
- })
6650
+ this._getStyleableShapes(selectedShapes).map((shape) => ({
6651
+ id: shape.id,
6652
+ type: shape.type,
6653
+ opacity
6654
+ }))
6750
6655
  );
6751
6656
  }
6752
6657
  return this;
@@ -6791,33 +6696,17 @@ class Editor extends import_eventemitter3.default {
6791
6696
  const selectedShapes = this.getSelectedShapes();
6792
6697
  if (selectedShapes.length > 0) {
6793
6698
  const updates = [];
6794
- const addShapeById = (shape) => {
6795
- if (this.isShapeOfType(shape, "group")) {
6796
- const childIds = this.getSortedChildIdsForParent(shape.id);
6797
- for (const childId of childIds) {
6798
- addShapeById(this.getShape(childId));
6799
- }
6800
- } else {
6801
- const util = this.getShapeUtil(shape);
6802
- const stylePropKey = this.styleProps[shape.type].get(style);
6803
- if (stylePropKey) {
6804
- const shapePartial = {
6805
- id: shape.id,
6806
- type: shape.type,
6807
- props: { [stylePropKey]: value }
6808
- };
6809
- updates.push({
6810
- util,
6811
- originalShape: shape,
6812
- updatePartial: shapePartial
6813
- });
6814
- }
6699
+ for (const shape of this._getStyleableShapes(selectedShapes)) {
6700
+ const stylePropKey = this.styleProps[shape.type].get(style);
6701
+ if (stylePropKey) {
6702
+ updates.push({
6703
+ id: shape.id,
6704
+ type: shape.type,
6705
+ props: { [stylePropKey]: value }
6706
+ });
6815
6707
  }
6816
- };
6817
- for (const shape of selectedShapes) {
6818
- addShapeById(shape);
6819
6708
  }
6820
- this.updateShapes(updates.map(({ updatePartial }) => updatePartial));
6709
+ this.updateShapes(updates);
6821
6710
  }
6822
6711
  return this;
6823
6712
  }
@@ -7213,7 +7102,6 @@ class Editor extends import_eventemitter3.default {
7213
7102
  if (shapeIdMap.has(newShape.parentId)) {
7214
7103
  newShape.parentId = shapeIdMap.get(oldShape.parentId);
7215
7104
  } else {
7216
- rootShapeIds.push(newShape.id);
7217
7105
  newShape.index = index;
7218
7106
  index = (0, import_utils.getIndexAbove)(index);
7219
7107
  }
@@ -7238,8 +7126,11 @@ class Editor extends import_eventemitter3.default {
7238
7126
  continue;
7239
7127
  }
7240
7128
  if (asset.type === "image" && asset.props.src?.startsWith("data:image") || asset.type === "video" && asset.props.src?.startsWith("data:video")) {
7241
- assetsToUpdate.push((0, import_utils.structuredClone)(asset));
7242
- asset.props.src = null;
7129
+ assetsToUpdate.push(asset);
7130
+ const assetWithoutSrc = (0, import_utils.structuredClone)(asset);
7131
+ assetWithoutSrc.props.src = null;
7132
+ assetsToCreate.push(assetWithoutSrc);
7133
+ continue;
7243
7134
  }
7244
7135
  assetsToCreate.push(asset);
7245
7136
  }
@@ -8066,7 +7957,7 @@ class Editor extends import_eventemitter3.default {
8066
7957
  if (info.type === "misc") {
8067
7958
  if (info.name === "cancel" || info.name === "complete") {
8068
7959
  this.inputs.setIsDragging(false);
8069
- if (this.inputs.getIsPanning()) {
7960
+ if (this.inputs.getIsPanning() && !this.inputs.keys.has("Space")) {
8070
7961
  this.inputs.setIsPanning(false);
8071
7962
  this.inputs.setIsSpacebarPanning(false);
8072
7963
  this.setCursor({ type: this._prevCursor, rotation: 0 });
@@ -8818,10 +8709,9 @@ function withIsolatedShapes(editor, shapeIds, callback) {
8818
8709
  }
8819
8710
  function getCameraFitXFitY(editor, cameraOptions) {
8820
8711
  if (!cameraOptions.constraints) throw Error("Should have constraints here");
8821
- const {
8822
- padding: { x: px, y: py }
8823
- } = cameraOptions.constraints;
8824
8712
  const vsb = editor.getViewportScreenBounds();
8713
+ const px = Math.min(cameraOptions.constraints.padding.x, vsb.w / 2);
8714
+ const py = Math.min(cameraOptions.constraints.padding.y, vsb.h / 2);
8825
8715
  const bounds = import_Box.Box.From(cameraOptions.constraints.bounds);
8826
8716
  const zx = (vsb.w - px * 2) / bounds.w;
8827
8717
  const zy = (vsb.h - py * 2) / bounds.h;