@tldraw/editor 5.4.0-next.ef99ab47e5ce → 5.5.0-next.6d9e51e9f3f7

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 +184 -296
  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 +193 -297
  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 +273 -386
  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": {
@@ -2828,9 +2799,9 @@ class Editor extends import_eventemitter3.default {
2828
2799
  }
2829
2800
  const remaining = duration - elapsed;
2830
2801
  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;
2802
+ const left = (0, import_utils.lerp)(start.minX, end.minX, t);
2803
+ const top = (0, import_utils.lerp)(start.minY, end.minY, t);
2804
+ const right = (0, import_utils.lerp)(start.maxX, end.maxX, t);
2834
2805
  this._setCamera(new import_Vec.Vec(-left, -top, this.getViewportScreenBounds().width / (right - left)), {
2835
2806
  force: true
2836
2807
  });
@@ -2908,12 +2879,12 @@ class Editor extends import_eventemitter3.default {
2908
2879
  let newCy = cy + dy;
2909
2880
  let newCz = cz;
2910
2881
  if (dirZ !== 0) {
2911
- newCz = cz * (1 + dirZ * currentSpeed * elapsed);
2882
+ newCz = cz * Math.exp(dirZ * currentSpeed * elapsed);
2912
2883
  const center = this.getViewportScreenCenter();
2913
2884
  newCx += center.x / newCz - center.x / cz;
2914
2885
  newCy += center.y / newCz - center.y / cz;
2915
2886
  }
2916
- currentSpeed *= 1 - friction;
2887
+ currentSpeed *= (1 - friction) ** (elapsed / import_constants.FRAME_MS_60HZ);
2917
2888
  if (currentSpeed < speedThreshold) {
2918
2889
  cancel();
2919
2890
  } else {
@@ -3346,12 +3317,12 @@ class Editor extends import_eventemitter3.default {
3346
3317
  const renderingShapes = [];
3347
3318
  let nextIndex = this.options.maxShapesPerPage * 2;
3348
3319
  let nextBackgroundIndex = this.options.maxShapesPerPage;
3349
- const erasingShapeIds = this.getErasingShapeIds();
3320
+ const erasingShapeIds = new Set(this.getErasingShapeIds());
3350
3321
  const addShapeById = (id, opacity, isAncestorErasing) => {
3351
3322
  const shape = this.getShape(id);
3352
3323
  if (!shape) return;
3353
3324
  if (this.isShapeHidden(shape)) {
3354
- const isErasing = isAncestorErasing || erasingShapeIds.includes(id);
3325
+ const isErasing = isAncestorErasing || erasingShapeIds.has(id);
3355
3326
  for (const childId of this.getSortedChildIdsForParent(id)) {
3356
3327
  addShapeById(childId, opacity, isErasing);
3357
3328
  }
@@ -3361,7 +3332,7 @@ class Editor extends import_eventemitter3.default {
3361
3332
  let isShapeErasing = false;
3362
3333
  const util = this.getShapeUtil(shape);
3363
3334
  if (useEditorState) {
3364
- isShapeErasing = !isAncestorErasing && erasingShapeIds.includes(id);
3335
+ isShapeErasing = !isAncestorErasing && erasingShapeIds.has(id);
3365
3336
  if (isShapeErasing) {
3366
3337
  opacity *= 0.32;
3367
3338
  }
@@ -3953,10 +3924,8 @@ class Editor extends import_eventemitter3.default {
3953
3924
  }
3954
3925
  _getShapePageBoundsCache() {
3955
3926
  return this.store.createComputedCache("pageBoundsCache", (shape) => {
3956
- const pageTransform = this.getShapePageTransform(shape);
3957
- if (!pageTransform) return void 0;
3958
3927
  return import_Box.Box.FromPoints(
3959
- pageTransform.applyToPoints(this.getShapeGeometry(shape).boundsVertices)
3928
+ this.getShapePageTransform(shape).applyToPoints(this.getShapeGeometry(shape).boundsVertices)
3960
3929
  );
3961
3930
  });
3962
3931
  }
@@ -4074,7 +4043,9 @@ class Editor extends import_eventemitter3.default {
4074
4043
  if (pageMask) {
4075
4044
  if (pageMask.length === 0) return void 0;
4076
4045
  const { corners } = pageBounds;
4077
- if (corners.every((p, i) => p && import_Vec.Vec.Equals(p, pageMask[i]))) return pageBounds.clone();
4046
+ if (pageMask.length === corners.length && corners.every((p, i) => import_Vec.Vec.Equals(p, pageMask[i]))) {
4047
+ return pageBounds.clone();
4048
+ }
4078
4049
  const intersection = (0, import_intersect.intersectPolygonPolygon)(pageMask, corners);
4079
4050
  if (!intersection) return;
4080
4051
  return import_Box.Box.FromPoints(intersection);
@@ -4298,23 +4269,22 @@ class Editor extends import_eventemitter3.default {
4298
4269
  let inMarginClosestToEdgeHit = null;
4299
4270
  const searchMargin = Math.max(innerMargin, outerMargin, this.getHitTestMargin());
4300
4271
  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
- });
4272
+ const shapesToCheck = opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted();
4310
4273
  for (let i = shapesToCheck.length - 1; i >= 0; i--) {
4311
4274
  const shape = shapesToCheck[i];
4275
+ if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
4276
+ if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group")) {
4277
+ continue;
4278
+ }
4279
+ const pageMask = this.getShapeMask(shape);
4280
+ if (pageMask && !(0, import_utils2.pointInPolygon)(point, pageMask)) continue;
4281
+ if (filter && !filter(shape)) continue;
4312
4282
  const geometry = this.getShapeGeometry(shape);
4313
4283
  const isGroup = geometry instanceof import_Group2d.Group2d;
4314
4284
  const pointInShapeSpace = this.getPointInShapeSpace(shape, point);
4315
4285
  const shapeUtil = this.getShapeUtil(shape);
4316
4286
  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()) {
4287
+ if (isGroup && (isShapeFrameLike || (this.isShapeOfType(shape, "note") || this.isShapeOfType(shape, "arrow") || this.isShapeOfType(shape, "geo") && shape.props.fill === "none") && shapeUtil.getText(shape)?.trim())) {
4318
4288
  for (const childGeometry of geometry.children) {
4319
4289
  if (childGeometry.isLabel && childGeometry.isPointInBounds(pointInShapeSpace)) {
4320
4290
  return shape;
@@ -4413,11 +4383,15 @@ class Editor extends import_eventemitter3.default {
4413
4383
  getShapesAtPoint(point, opts = {}) {
4414
4384
  const margin = opts.margin ?? 0;
4415
4385
  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();
4386
+ const sorted = this.getCurrentPageShapesSorted();
4387
+ const result = [];
4388
+ for (let i = sorted.length - 1; i >= 0; i--) {
4389
+ const shape = sorted[i];
4390
+ if (this.isShapeHidden(shape)) continue;
4391
+ if (!candidateIds.has(shape.id) && !this.isShapeFrameLike(shape)) continue;
4392
+ if (this.isPointInShape(shape, point, opts)) result.push(shape);
4393
+ }
4394
+ return result;
4421
4395
  }
4422
4396
  /**
4423
4397
  * Get shape IDs within the given bounds.
@@ -4502,9 +4476,7 @@ class Editor extends import_eventemitter3.default {
4502
4476
  const freshShape = this.getShape(id);
4503
4477
  if (!freshShape) return new import_Vec.Vec(0, 0);
4504
4478
  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);
4479
+ return this.getShapePageTransform(freshShape.parentId).clone().invert().applyToPoint(point);
4508
4480
  }
4509
4481
  getCurrentPageShapes() {
4510
4482
  return Array.from(this.getCurrentPageShapeIds(), (id) => this.store.get(id));
@@ -4616,23 +4588,7 @@ class Editor extends import_eventemitter3.default {
4616
4588
  * @public
4617
4589
  */
4618
4590
  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;
4591
+ return this.getAncestorPageId(shape) === pageId;
4636
4592
  }
4637
4593
  /**
4638
4594
  * Get the id of the containing page for a given shape.
@@ -4713,10 +4669,7 @@ class Editor extends import_eventemitter3.default {
4713
4669
  for (let i = 0; i < shapesToReparent.length; i++) {
4714
4670
  const shape = shapesToReparent[i];
4715
4671
  const pageTransform = this.getShapePageTransform(shape);
4716
- if (!pageTransform) continue;
4717
- const pagePoint = pageTransform.point();
4718
- if (!pagePoint) continue;
4719
- const newPoint = invertedParentTransform.applyToPoint(pagePoint);
4672
+ const newPoint = invertedParentTransform.applyToPoint(pageTransform.point());
4720
4673
  const newRotation = pageTransform.rotation() - parentPageRotation;
4721
4674
  if (shape.id === parentId) {
4722
4675
  throw Error("Attempted to reparent a shape to itself!");
@@ -4805,7 +4758,7 @@ class Editor extends import_eventemitter3.default {
4805
4758
  */
4806
4759
  getShapeAndDescendantIds(ids) {
4807
4760
  const shapeIds = /* @__PURE__ */ new Set();
4808
- for (const shape of ids.map((id) => this.getShape(id)).sort(import_utils.sortByIndex)) {
4761
+ for (const shape of (0, import_utils.compact)(ids.map((id) => this.getShape(id))).sort(import_utils.sortByIndex)) {
4809
4762
  shapeIds.add(shape.id);
4810
4763
  this.visitDescendants(shape, (descendantId) => {
4811
4764
  shapeIds.add(descendantId);
@@ -4827,11 +4780,12 @@ class Editor extends import_eventemitter3.default {
4827
4780
  const draggingShapes = (0, import_utils.compact)(droppingShapes.map((s) => this.getShape(s))).filter(
4828
4781
  (s) => !s.isLocked && !this.isShapeHidden(s)
4829
4782
  );
4783
+ const excludedIds = this.getShapeAndDescendantIds(draggingShapes.map((s) => s.id));
4830
4784
  const maybeDraggingOverShapes = this.getShapesAtPoint(point, {
4831
4785
  hitInside: true,
4832
4786
  margin: 0
4833
4787
  }).filter(
4834
- (s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !draggingShapes.includes(s)
4788
+ (s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !excludedIds.has(s.id)
4835
4789
  );
4836
4790
  for (const maybeDraggingOverShape of maybeDraggingOverShapes) {
4837
4791
  const shapeUtil = this.getShapeUtil(maybeDraggingOverShape);
@@ -5084,8 +5038,7 @@ class Editor extends import_eventemitter3.default {
5084
5038
  for (const id of ids) {
5085
5039
  const shape = this.getShape(id);
5086
5040
  const localDelta = import_Vec.Vec.From(offset);
5087
- const parentTransform = this.getShapeParentTransform(shape);
5088
- if (parentTransform) localDelta.rot(-parentTransform.rotation());
5041
+ localDelta.rot(-this.getShapeParentTransform(shape).rotation());
5089
5042
  changes.push(this.getChangesToTranslateShape(shape, localDelta.add(shape)));
5090
5043
  }
5091
5044
  this.updateShapes(changes);
@@ -5140,7 +5093,7 @@ class Editor extends import_eventemitter3.default {
5140
5093
  if (!originalShape) continue;
5141
5094
  let ox = 0;
5142
5095
  let oy = 0;
5143
- if (offset && initialIds.has(originalId)) {
5096
+ if (offset && initialIds.has(originalId) && !shapeIdSet.has(originalShape.parentId)) {
5144
5097
  const parentTransform = this.getShapeParentTransform(originalShape);
5145
5098
  const vec = new import_Vec.Vec(offset.x, offset.y).rot(-parentTransform.rotation());
5146
5099
  ox = vec.x;
@@ -5254,26 +5207,17 @@ class Editor extends import_eventemitter3.default {
5254
5207
  toggleLock(shapes) {
5255
5208
  const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5256
5209
  if (this.getIsReadonly() || ids.length === 0) return this;
5257
- let allLocked = true, allUnlocked = true;
5210
+ let allLocked = true;
5258
5211
  const shapesToToggle = [];
5259
5212
  for (const id of ids) {
5260
5213
  const shape = this.getShape(id);
5261
5214
  if (shape) {
5262
5215
  shapesToToggle.push(shape);
5263
- if (shape.isLocked) {
5264
- allUnlocked = false;
5265
- } else {
5266
- allLocked = false;
5267
- }
5216
+ if (!shape.isLocked) allLocked = false;
5268
5217
  }
5269
5218
  }
5270
5219
  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) {
5220
+ if (allLocked) {
5277
5221
  this.updateShapes(
5278
5222
  shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: false }))
5279
5223
  );
@@ -5281,6 +5225,7 @@ class Editor extends import_eventemitter3.default {
5281
5225
  this.updateShapes(
5282
5226
  shapesToToggle.map((shape) => ({ id: shape.id, type: shape.type, isLocked: true }))
5283
5227
  );
5228
+ this.setSelectedShapes([]);
5284
5229
  }
5285
5230
  });
5286
5231
  return this;
@@ -5391,9 +5336,10 @@ class Editor extends import_eventemitter3.default {
5391
5336
  const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5392
5337
  let freshShapes = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
5393
5338
  if (opts?.filterAxisAligned) {
5394
- freshShapes = freshShapes.filter(
5395
- (s) => this.getShapePageTransform(s)?.rotation() % (import_utils2.PI / 2) === 0
5396
- );
5339
+ freshShapes = freshShapes.filter((s) => {
5340
+ const remainder = Math.abs(this.getShapePageTransform(s).rotation() % import_utils2.HALF_PI);
5341
+ return Math.min(remainder, import_utils2.HALF_PI - remainder) < 1e-9;
5342
+ });
5397
5343
  }
5398
5344
  const clusters = [];
5399
5345
  const allBounds = [];
@@ -5558,9 +5504,9 @@ class Editor extends import_eventemitter3.default {
5558
5504
  dim = "height";
5559
5505
  }
5560
5506
  let shapeGap = 0;
5507
+ shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
5561
5508
  if (_gap === 0) {
5562
5509
  const gaps = {};
5563
- shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
5564
5510
  for (let i = 0; i < len - 1; i++) {
5565
5511
  const currCluster = shapeClustersToStack[i];
5566
5512
  const nextCluster = shapeClustersToStack[i + 1];
@@ -5598,8 +5544,7 @@ class Editor extends import_eventemitter3.default {
5598
5544
  const shapeDelta = delta.clone();
5599
5545
  const parent = this.getShapeParent(shape);
5600
5546
  if (parent) {
5601
- const parentTransform = this.getShapePageTransform(parent);
5602
- if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
5547
+ shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5603
5548
  }
5604
5549
  shapeDelta.add(shape);
5605
5550
  changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
@@ -5637,7 +5582,7 @@ class Editor extends import_eventemitter3.default {
5637
5582
  }
5638
5583
  const commonBounds = import_Box.Box.Common(allBounds);
5639
5584
  const maxWidth = commonBounds.width;
5640
- shapeClustersToPack.sort((a, b) => a.pageBounds.width - b.pageBounds.width).sort((a, b) => a.pageBounds.height - b.pageBounds.height);
5585
+ shapeClustersToPack.sort((a, b) => b.pageBounds.width - a.pageBounds.width).sort((a, b) => b.pageBounds.height - a.pageBounds.height);
5641
5586
  const startWidth = Math.max(Math.ceil(Math.sqrt(area / 0.95)), maxWidth);
5642
5587
  const spaces = [new import_Box.Box(commonBounds.x, commonBounds.y, startWidth, Infinity)];
5643
5588
  let width = 0;
@@ -5685,8 +5630,7 @@ class Editor extends import_eventemitter3.default {
5685
5630
  const shapeDelta = delta.clone();
5686
5631
  const parent = this.getShapeParent(shape);
5687
5632
  if (parent) {
5688
- const parentTransform = this.getShapeParentTransform(shape);
5689
- if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
5633
+ shapeDelta.rot(-this.getShapeParentTransform(shape).rotation());
5690
5634
  }
5691
5635
  shapeDelta.add(shape);
5692
5636
  changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
@@ -5752,8 +5696,7 @@ class Editor extends import_eventemitter3.default {
5752
5696
  const shapeDelta = delta.clone();
5753
5697
  const parent = this.getShapeParent(shape);
5754
5698
  if (parent) {
5755
- const parentTransform = this.getShapePageTransform(parent);
5756
- if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
5699
+ shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5757
5700
  }
5758
5701
  shapeDelta.add(shape);
5759
5702
  changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
@@ -5827,8 +5770,7 @@ class Editor extends import_eventemitter3.default {
5827
5770
  const shapeDelta = delta.clone();
5828
5771
  const parent = this.getShapeParent(shape);
5829
5772
  if (parent) {
5830
- const parentTransform = this.getShapePageTransform(parent);
5831
- if (parentTransform) shapeDelta.rot(-parentTransform.rotation());
5773
+ shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5832
5774
  }
5833
5775
  shapeDelta.add(shape);
5834
5776
  changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
@@ -5883,8 +5825,7 @@ class Editor extends import_eventemitter3.default {
5883
5825
  scale[val] = commonBounds[dim] / pageBounds[dim];
5884
5826
  for (const shape of shapes2) {
5885
5827
  const shapeLocalOffset = localOffset.clone();
5886
- const parentTransform = this.getShapeParentTransform(shape);
5887
- if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
5828
+ shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
5888
5829
  shapeLocalOffset.add(shape);
5889
5830
  const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
5890
5831
  this.updateShape(changes);
@@ -5940,8 +5881,7 @@ class Editor extends import_eventemitter3.default {
5940
5881
  );
5941
5882
  for (const shape of shapes2) {
5942
5883
  const shapeLocalOffset = localOffset.clone();
5943
- const parentTransform = this.getShapeParentTransform(shape);
5944
- if (parentTransform) shapeLocalOffset.rot(-parentTransform.rotation());
5884
+ shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
5945
5885
  shapeLocalOffset.add(shape);
5946
5886
  const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
5947
5887
  this.updateShape(changes);
@@ -5990,9 +5930,7 @@ class Editor extends import_eventemitter3.default {
5990
5930
  const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center;
5991
5931
  if (!scaleOrigin) return null;
5992
5932
  const pageTransform = opts.initialPageTransform ? import_Mat.Mat.Cast(opts.initialPageTransform) : this.getShapePageTransform(id);
5993
- if (!pageTransform) return null;
5994
5933
  const pageRotation = pageTransform.rotation();
5995
- if (pageRotation == null) return null;
5996
5934
  const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation;
5997
5935
  const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds;
5998
5936
  if (!initialBounds) return null;
@@ -6143,7 +6081,6 @@ class Editor extends import_eventemitter3.default {
6143
6081
  const currentLocalBounds = this.getShapeGeometry(id).bounds;
6144
6082
  const currentPageCenter = import_Mat.Mat.applyToPoint(pageTransform, currentLocalBounds.center);
6145
6083
  const shapePageTransformOrigin = pageTransform.point();
6146
- if (!currentPageCenter || !shapePageTransformOrigin) return this;
6147
6084
  const pageDelta = import_Vec.Vec.Sub(postScaleShapePageCenter, currentPageCenter);
6148
6085
  const postScaleShapePagePoint = import_Vec.Vec.Add(shapePageTransformOrigin, pageDelta);
6149
6086
  const { x, y } = this.getPointInParentSpace(id, postScaleShapePagePoint);
@@ -6402,10 +6339,10 @@ class Editor extends import_eventemitter3.default {
6402
6339
  if (animationIdForShape !== animationId) continue;
6403
6340
  updates.push({
6404
6341
  ...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,
6342
+ x: (0, import_utils.lerp)(start.x, end.x, t),
6343
+ y: (0, import_utils.lerp)(start.y, end.y, t),
6344
+ opacity: (0, import_utils.lerp)(start.opacity, end.opacity, t),
6345
+ rotation: (0, import_utils.lerp)(start.rotation, end.rotation, t),
6409
6346
  props: this.getShapeUtil(end).getInterpolatedProps?.(start, end, t) ?? end.props
6410
6347
  });
6411
6348
  }
@@ -6531,7 +6468,7 @@ class Editor extends import_eventemitter3.default {
6531
6468
  * @public
6532
6469
  */
6533
6470
  updateShapes(partials) {
6534
- const compactedPartials = Array(partials.length);
6471
+ const compactedPartials = [];
6535
6472
  for (let i = 0, n = partials.length; i < n; i++) {
6536
6473
  const partial = partials[i];
6537
6474
  if (!partial) continue;
@@ -6602,28 +6539,32 @@ class Editor extends import_eventemitter3.default {
6602
6539
  }
6603
6540
  /* --------------------- Styles --------------------- */
6604
6541
  /**
6605
- * Get all the current styles among the users selected shapes
6542
+ * Groups have no styles of their own: a style read or write on a selection applies to the
6543
+ * non-group shapes beneath each group, however deeply nested. Returns those shapes.
6606
6544
  *
6607
6545
  * @internal
6608
6546
  */
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));
6547
+ _getStyleableShapes(shapes) {
6548
+ const result = [];
6549
+ const visit = (shape) => {
6550
+ if (this.isShapeOfType(shape, "group")) {
6551
+ for (const childId of this.getSortedChildIdsForParent(shape.id)) {
6552
+ const child = this.getShape(childId);
6553
+ if (child) visit(child);
6554
+ }
6555
+ } else {
6556
+ result.push(shape);
6619
6557
  }
6620
- }
6558
+ };
6559
+ for (const shape of shapes) visit(shape);
6560
+ return result;
6621
6561
  }
6622
6562
  _getSelectionSharedStyles() {
6623
- const selectedShapes = this.getSelectedShapes();
6624
6563
  const sharedStyles = new import_SharedStylesMap.SharedStyleMap();
6625
- for (const selectedShape of selectedShapes) {
6626
- this._extractSharedStyles(selectedShape, sharedStyles);
6564
+ for (const shape of this._getStyleableShapes(this.getSelectedShapes())) {
6565
+ for (const [style, propKey] of this.styleProps[shape.type]) {
6566
+ sharedStyles.applyValue(style, (0, import_utils.getOwnProperty)(shape.props, propKey));
6567
+ }
6627
6568
  }
6628
6569
  return sharedStyles;
6629
6570
  }
@@ -6655,38 +6596,16 @@ class Editor extends import_eventemitter3.default {
6655
6596
  const styles = new import_SharedStylesMap.SharedStyleMap();
6656
6597
  if (!currentTool) return styles;
6657
6598
  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
- }
6599
+ for (const style of this.styleProps[currentTool.shapeType].keys()) {
6600
+ styles.applyValue(style, this.getStyleForNextShape(style));
6667
6601
  }
6668
6602
  }
6669
6603
  return styles;
6670
6604
  }
6671
6605
  getSharedOpacity() {
6672
6606
  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
6607
  let opacity = null;
6689
- for (const shape of shapesToCheck) {
6608
+ for (const shape of this._getStyleableShapes(this.getSelectedShapes())) {
6690
6609
  if (opacity === null) {
6691
6610
  opacity = shape.opacity;
6692
6611
  } else if (opacity !== shape.opacity) {
@@ -6725,28 +6644,12 @@ class Editor extends import_eventemitter3.default {
6725
6644
  setOpacityForSelectedShapes(opacity) {
6726
6645
  const selectedShapes = this.getSelectedShapes();
6727
6646
  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
6647
  this.updateShapes(
6743
- shapesToUpdate.map((shape) => {
6744
- return {
6745
- id: shape.id,
6746
- type: shape.type,
6747
- opacity
6748
- };
6749
- })
6648
+ this._getStyleableShapes(selectedShapes).map((shape) => ({
6649
+ id: shape.id,
6650
+ type: shape.type,
6651
+ opacity
6652
+ }))
6750
6653
  );
6751
6654
  }
6752
6655
  return this;
@@ -6791,33 +6694,17 @@ class Editor extends import_eventemitter3.default {
6791
6694
  const selectedShapes = this.getSelectedShapes();
6792
6695
  if (selectedShapes.length > 0) {
6793
6696
  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
- }
6697
+ for (const shape of this._getStyleableShapes(selectedShapes)) {
6698
+ const stylePropKey = this.styleProps[shape.type].get(style);
6699
+ if (stylePropKey) {
6700
+ updates.push({
6701
+ id: shape.id,
6702
+ type: shape.type,
6703
+ props: { [stylePropKey]: value }
6704
+ });
6815
6705
  }
6816
- };
6817
- for (const shape of selectedShapes) {
6818
- addShapeById(shape);
6819
6706
  }
6820
- this.updateShapes(updates.map(({ updatePartial }) => updatePartial));
6707
+ this.updateShapes(updates);
6821
6708
  }
6822
6709
  return this;
6823
6710
  }
@@ -7213,7 +7100,6 @@ class Editor extends import_eventemitter3.default {
7213
7100
  if (shapeIdMap.has(newShape.parentId)) {
7214
7101
  newShape.parentId = shapeIdMap.get(oldShape.parentId);
7215
7102
  } else {
7216
- rootShapeIds.push(newShape.id);
7217
7103
  newShape.index = index;
7218
7104
  index = (0, import_utils.getIndexAbove)(index);
7219
7105
  }
@@ -7238,8 +7124,11 @@ class Editor extends import_eventemitter3.default {
7238
7124
  continue;
7239
7125
  }
7240
7126
  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;
7127
+ assetsToUpdate.push(asset);
7128
+ const assetWithoutSrc = (0, import_utils.structuredClone)(asset);
7129
+ assetWithoutSrc.props.src = null;
7130
+ assetsToCreate.push(assetWithoutSrc);
7131
+ continue;
7243
7132
  }
7244
7133
  assetsToCreate.push(asset);
7245
7134
  }
@@ -8066,7 +7955,7 @@ class Editor extends import_eventemitter3.default {
8066
7955
  if (info.type === "misc") {
8067
7956
  if (info.name === "cancel" || info.name === "complete") {
8068
7957
  this.inputs.setIsDragging(false);
8069
- if (this.inputs.getIsPanning()) {
7958
+ if (this.inputs.getIsPanning() && !this.inputs.keys.has("Space")) {
8070
7959
  this.inputs.setIsPanning(false);
8071
7960
  this.inputs.setIsSpacebarPanning(false);
8072
7961
  this.setCursor({ type: this._prevCursor, rotation: 0 });
@@ -8818,10 +8707,9 @@ function withIsolatedShapes(editor, shapeIds, callback) {
8818
8707
  }
8819
8708
  function getCameraFitXFitY(editor, cameraOptions) {
8820
8709
  if (!cameraOptions.constraints) throw Error("Should have constraints here");
8821
- const {
8822
- padding: { x: px, y: py }
8823
- } = cameraOptions.constraints;
8824
8710
  const vsb = editor.getViewportScreenBounds();
8711
+ const px = Math.min(cameraOptions.constraints.padding.x, vsb.w / 2);
8712
+ const py = Math.min(cameraOptions.constraints.padding.y, vsb.h / 2);
8825
8713
  const bounds = import_Box.Box.From(cameraOptions.constraints.bounds);
8826
8714
  const zx = (vsb.w - px * 2) / bounds.w;
8827
8715
  const zy = (vsb.h - py * 2) / bounds.h;