@tldraw/editor 4.5.3 → 4.6.0-canary.00a8c03b5687

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 (279) hide show
  1. package/dist-cjs/index.d.ts +37 -6
  2. package/dist-cjs/index.js +6 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +7 -5
  5. package/dist-cjs/lib/TldrawEditor.js.map +3 -3
  6. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +3 -2
  7. package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -1
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +8 -5
  11. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
  12. package/dist-cjs/lib/config/TLSessionStateSnapshot.js +8 -5
  13. package/dist-cjs/lib/config/TLSessionStateSnapshot.js.map +2 -2
  14. package/dist-cjs/lib/config/TLUserPreferences.js +3 -2
  15. package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
  16. package/dist-cjs/lib/config/createTLStore.js +1 -0
  17. package/dist-cjs/lib/config/createTLStore.js.map +2 -2
  18. package/dist-cjs/lib/config/createTLUser.js.map +1 -1
  19. package/dist-cjs/lib/editor/Editor.js +511 -366
  20. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  21. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +25 -64
  22. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
  23. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +22 -5
  24. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
  25. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +4 -3
  26. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
  27. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +5 -0
  28. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
  29. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +71 -112
  30. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
  31. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +20 -55
  32. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +1 -1
  33. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js +11 -52
  34. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +1 -1
  35. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +19 -56
  36. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +1 -1
  37. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +2 -2
  38. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  39. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +16 -55
  40. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +1 -1
  41. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +60 -70
  42. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  43. package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
  44. package/dist-cjs/lib/exports/ExportDelay.js +12 -53
  45. package/dist-cjs/lib/exports/ExportDelay.js.map +1 -1
  46. package/dist-cjs/lib/exports/FontEmbedder.js +23 -65
  47. package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
  48. package/dist-cjs/lib/exports/StyleEmbedder.js +27 -15
  49. package/dist-cjs/lib/exports/StyleEmbedder.js.map +3 -3
  50. package/dist-cjs/lib/exports/domUtils.js +15 -0
  51. package/dist-cjs/lib/exports/domUtils.js.map +2 -2
  52. package/dist-cjs/lib/exports/embedMedia.js +15 -12
  53. package/dist-cjs/lib/exports/embedMedia.js.map +2 -2
  54. package/dist-cjs/lib/exports/exportToSvg.js +8 -7
  55. package/dist-cjs/lib/exports/exportToSvg.js.map +2 -2
  56. package/dist-cjs/lib/exports/getSvgAsImage.js +181 -29
  57. package/dist-cjs/lib/exports/getSvgAsImage.js.map +3 -3
  58. package/dist-cjs/lib/exports/getSvgJsx.js +21 -9
  59. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  60. package/dist-cjs/lib/globals/environment.js +4 -3
  61. package/dist-cjs/lib/globals/environment.js.map +2 -2
  62. package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -2
  63. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  64. package/dist-cjs/lib/hooks/useDocumentEvents.js +13 -11
  65. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  66. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +3 -2
  67. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
  68. package/dist-cjs/lib/hooks/useScreenBounds.js +10 -6
  69. package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
  70. package/dist-cjs/lib/hooks/useViewportHeight.js +13 -11
  71. package/dist-cjs/lib/hooks/useViewportHeight.js.map +3 -3
  72. package/dist-cjs/lib/license/Watermark.js +10 -0
  73. package/dist-cjs/lib/license/Watermark.js.map +2 -2
  74. package/dist-cjs/lib/primitives/Box.js +25 -25
  75. package/dist-cjs/lib/primitives/Box.js.map +1 -1
  76. package/dist-cjs/lib/primitives/Vec.js +36 -23
  77. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  78. package/dist-cjs/lib/primitives/geometry/Arc2d.js +6 -13
  79. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  80. package/dist-cjs/lib/primitives/geometry/Circle2d.js +31 -2
  81. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
  82. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +9 -0
  83. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  84. package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js +10 -1
  85. package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
  86. package/dist-cjs/lib/primitives/geometry/Edge2d.js +32 -18
  87. package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
  88. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +13 -1
  89. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
  90. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +6 -6
  91. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +1 -1
  92. package/dist-cjs/lib/primitives/geometry/Polyline2d.js +52 -13
  93. package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
  94. package/dist-cjs/lib/primitives/geometry/Stadium2d.js +12 -0
  95. package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
  96. package/dist-cjs/lib/primitives/geometry/geometry.bench.js +133 -0
  97. package/dist-cjs/lib/primitives/geometry/geometry.bench.js.map +7 -0
  98. package/dist-cjs/lib/primitives/intersect.js +16 -15
  99. package/dist-cjs/lib/primitives/intersect.js.map +2 -2
  100. package/dist-cjs/lib/primitives/utils.js +0 -1
  101. package/dist-cjs/lib/primitives/utils.js.map +2 -2
  102. package/dist-cjs/lib/utils/SharedStylesMap.js +1 -1
  103. package/dist-cjs/lib/utils/SharedStylesMap.js.map +1 -1
  104. package/dist-cjs/lib/utils/browserCanvasMaxSize.js +3 -2
  105. package/dist-cjs/lib/utils/browserCanvasMaxSize.js.map +2 -2
  106. package/dist-cjs/lib/utils/dom.js +15 -2
  107. package/dist-cjs/lib/utils/dom.js.map +2 -2
  108. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +2 -1
  109. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
  110. package/dist-cjs/version.js +3 -3
  111. package/dist-cjs/version.js.map +1 -1
  112. package/dist-esm/index.d.mts +37 -6
  113. package/dist-esm/index.mjs +8 -1
  114. package/dist-esm/index.mjs.map +2 -2
  115. package/dist-esm/lib/TldrawEditor.mjs +7 -5
  116. package/dist-esm/lib/TldrawEditor.mjs.map +3 -3
  117. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +2 -1
  118. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +2 -2
  119. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -1
  120. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  121. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +8 -5
  122. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
  123. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs +8 -5
  124. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs.map +2 -2
  125. package/dist-esm/lib/config/TLUserPreferences.mjs +3 -2
  126. package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
  127. package/dist-esm/lib/config/createTLStore.mjs +1 -0
  128. package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
  129. package/dist-esm/lib/config/createTLUser.mjs.map +1 -1
  130. package/dist-esm/lib/editor/Editor.mjs +512 -368
  131. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  132. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +25 -64
  133. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
  134. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +24 -5
  135. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
  136. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +4 -3
  137. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
  138. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +5 -0
  139. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
  140. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +71 -112
  141. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
  142. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +20 -55
  143. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +1 -1
  144. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs +11 -52
  145. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +1 -1
  146. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +19 -56
  147. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +1 -1
  148. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +2 -2
  149. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  150. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +16 -55
  151. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +1 -1
  152. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +60 -70
  153. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  154. package/dist-esm/lib/exports/ExportDelay.mjs +12 -53
  155. package/dist-esm/lib/exports/ExportDelay.mjs.map +1 -1
  156. package/dist-esm/lib/exports/FontEmbedder.mjs +23 -65
  157. package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
  158. package/dist-esm/lib/exports/StyleEmbedder.mjs +29 -16
  159. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +3 -3
  160. package/dist-esm/lib/exports/domUtils.mjs +15 -0
  161. package/dist-esm/lib/exports/domUtils.mjs.map +2 -2
  162. package/dist-esm/lib/exports/embedMedia.mjs +16 -13
  163. package/dist-esm/lib/exports/embedMedia.mjs.map +2 -2
  164. package/dist-esm/lib/exports/exportToSvg.mjs +8 -7
  165. package/dist-esm/lib/exports/exportToSvg.mjs.map +2 -2
  166. package/dist-esm/lib/exports/getSvgAsImage.mjs +181 -29
  167. package/dist-esm/lib/exports/getSvgAsImage.mjs.map +3 -3
  168. package/dist-esm/lib/exports/getSvgJsx.mjs +21 -9
  169. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  170. package/dist-esm/lib/globals/environment.mjs +4 -3
  171. package/dist-esm/lib/globals/environment.mjs.map +2 -2
  172. package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -2
  173. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  174. package/dist-esm/lib/hooks/useDocumentEvents.mjs +13 -11
  175. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  176. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +3 -2
  177. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
  178. package/dist-esm/lib/hooks/useScreenBounds.mjs +10 -6
  179. package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
  180. package/dist-esm/lib/hooks/useViewportHeight.mjs +13 -11
  181. package/dist-esm/lib/hooks/useViewportHeight.mjs.map +3 -3
  182. package/dist-esm/lib/license/Watermark.mjs +10 -0
  183. package/dist-esm/lib/license/Watermark.mjs.map +2 -2
  184. package/dist-esm/lib/primitives/Box.mjs +25 -25
  185. package/dist-esm/lib/primitives/Box.mjs.map +1 -1
  186. package/dist-esm/lib/primitives/Vec.mjs +36 -23
  187. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  188. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +6 -13
  189. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  190. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +31 -2
  191. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
  192. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +9 -0
  193. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  194. package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs +10 -1
  195. package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
  196. package/dist-esm/lib/primitives/geometry/Edge2d.mjs +32 -18
  197. package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
  198. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +14 -2
  199. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
  200. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +6 -6
  201. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +1 -1
  202. package/dist-esm/lib/primitives/geometry/Polyline2d.mjs +52 -13
  203. package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
  204. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +13 -1
  205. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
  206. package/dist-esm/lib/primitives/geometry/geometry.bench.mjs +132 -0
  207. package/dist-esm/lib/primitives/geometry/geometry.bench.mjs.map +7 -0
  208. package/dist-esm/lib/primitives/intersect.mjs +17 -16
  209. package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
  210. package/dist-esm/lib/primitives/utils.mjs +0 -1
  211. package/dist-esm/lib/primitives/utils.mjs.map +2 -2
  212. package/dist-esm/lib/utils/SharedStylesMap.mjs +1 -1
  213. package/dist-esm/lib/utils/SharedStylesMap.mjs.map +1 -1
  214. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +3 -2
  215. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs.map +2 -2
  216. package/dist-esm/lib/utils/dom.mjs +15 -2
  217. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  218. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +2 -1
  219. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
  220. package/dist-esm/version.mjs +3 -3
  221. package/dist-esm/version.mjs.map +1 -1
  222. package/package.json +8 -8
  223. package/src/index.ts +10 -6
  224. package/src/lib/TldrawEditor.tsx +7 -5
  225. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +2 -1
  226. package/src/lib/components/default-components/DefaultCanvas.tsx +1 -1
  227. package/src/lib/components/default-components/DefaultErrorFallback.tsx +9 -5
  228. package/src/lib/config/TLSessionStateSnapshot.ts +8 -5
  229. package/src/lib/config/TLUserPreferences.ts +3 -2
  230. package/src/lib/config/createTLStore.ts +3 -0
  231. package/src/lib/config/createTLUser.ts +3 -3
  232. package/src/lib/editor/Editor.ts +53 -15
  233. package/src/lib/editor/managers/ClickManager/ClickManager.ts +1 -1
  234. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +7 -6
  235. package/src/lib/editor/managers/FocusManager/FocusManager.ts +10 -7
  236. package/src/lib/editor/managers/FontManager/FontManager.test.ts +1 -0
  237. package/src/lib/editor/managers/FontManager/FontManager.ts +4 -3
  238. package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +16 -0
  239. package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +7 -2
  240. package/src/lib/editor/managers/InputsManager/InputsManager.ts +30 -30
  241. package/src/lib/editor/managers/TextManager/TextManager.test.ts +4 -5
  242. package/src/lib/editor/managers/TextManager/TextManager.ts +2 -2
  243. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +3 -2
  244. package/src/lib/editor/types/misc-types.ts +8 -2
  245. package/src/lib/exports/FontEmbedder.ts +10 -9
  246. package/src/lib/exports/StyleEmbedder.ts +33 -15
  247. package/src/lib/exports/domUtils.ts +20 -0
  248. package/src/lib/exports/embedMedia.ts +23 -17
  249. package/src/lib/exports/exportToSvg.tsx +8 -7
  250. package/src/lib/exports/getSvgAsImage.ts +292 -32
  251. package/src/lib/exports/getSvgJsx.test.ts +103 -101
  252. package/src/lib/exports/getSvgJsx.tsx +33 -10
  253. package/src/lib/globals/environment.ts +4 -3
  254. package/src/lib/hooks/useCanvasEvents.ts +2 -3
  255. package/src/lib/hooks/useDocumentEvents.ts +16 -11
  256. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +3 -3
  257. package/src/lib/hooks/useScreenBounds.ts +10 -6
  258. package/src/lib/hooks/useViewportHeight.ts +13 -11
  259. package/src/lib/license/Watermark.tsx +10 -0
  260. package/src/lib/primitives/Box.ts +25 -25
  261. package/src/lib/primitives/Vec.ts +52 -25
  262. package/src/lib/primitives/geometry/Arc2d.ts +10 -15
  263. package/src/lib/primitives/geometry/Circle2d.ts +40 -2
  264. package/src/lib/primitives/geometry/CubicBezier2d.ts +10 -0
  265. package/src/lib/primitives/geometry/CubicSpline2d.ts +11 -1
  266. package/src/lib/primitives/geometry/Edge2d.ts +41 -18
  267. package/src/lib/primitives/geometry/Ellipse2d.ts +15 -2
  268. package/src/lib/primitives/geometry/Geometry2d.ts +6 -6
  269. package/src/lib/primitives/geometry/Polyline2d.ts +61 -13
  270. package/src/lib/primitives/geometry/Stadium2d.ts +14 -1
  271. package/src/lib/primitives/geometry/geometry.bench.ts +179 -0
  272. package/src/lib/primitives/intersect.ts +27 -27
  273. package/src/lib/primitives/utils.ts +4 -4
  274. package/src/lib/test/TestEditor.ts +1 -0
  275. package/src/lib/utils/SharedStylesMap.ts +1 -1
  276. package/src/lib/utils/browserCanvasMaxSize.ts +4 -2
  277. package/src/lib/utils/dom.ts +34 -2
  278. package/src/lib/utils/sync/TLLocalSyncClient.ts +1 -0
  279. package/src/version.ts +3 -3
@@ -85,6 +85,7 @@ describe('FontManager', () => {
85
85
  getShapeUtil: vi.fn(() => mockShapeUtil),
86
86
  getCurrentPageShapeIds: vi.fn(() => new Set()),
87
87
  getShape: vi.fn(),
88
+ getContainerDocument: vi.fn(() => document),
88
89
  isDisposed: false,
89
90
  } as any
90
91
 
@@ -160,7 +160,7 @@ export class FontManager {
160
160
  loadingPromise: instance
161
161
  .load()
162
162
  .then(() => {
163
- document.fonts.add(instance)
163
+ this.editor.getContainerDocument().fonts.add(instance)
164
164
  this.fontStates.update(font, (s) => ({ ...s, state: 'ready' }))
165
165
  })
166
166
  .catch((err) => {
@@ -193,7 +193,8 @@ export class FontManager {
193
193
  }
194
194
 
195
195
  private findOrCreateFontFace(font: TLFontFace) {
196
- for (const existing of document.fonts) {
196
+ const fonts = this.editor.getContainerDocument().fonts
197
+ for (const existing of fonts) {
197
198
  if (
198
199
  existing.family === font.family &&
199
200
  objectMapEntries(defaultFontFaceDescriptors).every(
@@ -210,7 +211,7 @@ export class FontManager {
210
211
  display: 'swap',
211
212
  })
212
213
 
213
- document.fonts.add(instance)
214
+ fonts.add(instance)
214
215
 
215
216
  return instance
216
217
  }
@@ -736,6 +736,22 @@ describe('HistoryManager error scenarios and edge cases', () => {
736
736
  expect(store.get(ids.a)!.value).toBe(originalValue)
737
737
  })
738
738
 
739
+ it('should preserve pending diff when mark is not found', () => {
740
+ manager._mark('real-mark')
741
+ store.update(ids.a, (s) => ({ ...s, value: 1 }))
742
+
743
+ // bail to a mark that doesn't exist
744
+ manager.bailToMark('non-existent-mark')
745
+
746
+ // the pending diff should still be intact
747
+ expect(store.get(ids.a)!.value).toBe(1)
748
+ expect(manager.getNumUndos()).toBeGreaterThan(0)
749
+
750
+ // a subsequent bail to the real mark should still work
751
+ manager.bailToMark('real-mark')
752
+ expect(store.get(ids.a)!.value).toBe(0)
753
+ })
754
+
739
755
  it('should find mark correctly when it exists', () => {
740
756
  manager._mark('existing-mark')
741
757
  store.update(ids.a, (s) => ({ ...s, value: 1 }))
@@ -172,8 +172,8 @@ export class HistoryManager<R extends UnknownRecord> {
172
172
  }
173
173
 
174
174
  if (!didFindMark && toMark) {
175
- // whoops, we didn't find the mark we were looking for
176
- // don't do anything
175
+ // we didn't find the mark we were looking for — restore state and bail
176
+ this.pendingDiff.restore(pendingDiff)
177
177
  return this
178
178
  }
179
179
 
@@ -338,6 +338,11 @@ class PendingDiff<R extends UnknownRecord> {
338
338
  return diff
339
339
  }
340
340
 
341
+ restore(diff: RecordsDiff<R>) {
342
+ this.diff = diff
343
+ this.isEmptyAtom.set(isRecordsDiffEmpty(diff))
344
+ }
345
+
341
346
  isEmpty() {
342
347
  return this.isEmptyAtom.get()
343
348
  }
@@ -21,7 +21,7 @@ export class InputsManager {
21
21
  /**
22
22
  * @deprecated Use `getOriginPagePoint()` instead.
23
23
  */
24
- // eslint-disable-next-line no-restricted-syntax
24
+ // eslint-disable-next-line tldraw/no-setter-getter
25
25
  get originPagePoint() {
26
26
  return this.getOriginPagePoint()
27
27
  }
@@ -36,7 +36,7 @@ export class InputsManager {
36
36
  /**
37
37
  * @deprecated Use `getOriginScreenPoint()` instead.
38
38
  */
39
- // eslint-disable-next-line no-restricted-syntax
39
+ // eslint-disable-next-line tldraw/no-setter-getter
40
40
  get originScreenPoint() {
41
41
  return this.getOriginScreenPoint()
42
42
  }
@@ -51,7 +51,7 @@ export class InputsManager {
51
51
  /**
52
52
  * @deprecated Use `getPreviousPagePoint()` instead.
53
53
  */
54
- // eslint-disable-next-line no-restricted-syntax
54
+ // eslint-disable-next-line tldraw/no-setter-getter
55
55
  get previousPagePoint() {
56
56
  return this.getPreviousPagePoint()
57
57
  }
@@ -66,7 +66,7 @@ export class InputsManager {
66
66
  /**
67
67
  * @deprecated Use `getPreviousScreenPoint()` instead.
68
68
  */
69
- // eslint-disable-next-line no-restricted-syntax
69
+ // eslint-disable-next-line tldraw/no-setter-getter
70
70
  get previousScreenPoint() {
71
71
  return this.getPreviousScreenPoint()
72
72
  }
@@ -81,7 +81,7 @@ export class InputsManager {
81
81
  /**
82
82
  * @deprecated Use `getCurrentPagePoint()` instead.
83
83
  */
84
- // eslint-disable-next-line no-restricted-syntax
84
+ // eslint-disable-next-line tldraw/no-setter-getter
85
85
  get currentPagePoint() {
86
86
  return this.getCurrentPagePoint()
87
87
  }
@@ -96,7 +96,7 @@ export class InputsManager {
96
96
  /**
97
97
  * @deprecated Use `getCurrentScreenPoint()` instead.
98
98
  */
99
- // eslint-disable-next-line no-restricted-syntax
99
+ // eslint-disable-next-line tldraw/no-setter-getter
100
100
  get currentScreenPoint() {
101
101
  return this.getCurrentScreenPoint()
102
102
  }
@@ -111,7 +111,7 @@ export class InputsManager {
111
111
  /**
112
112
  * @deprecated Use `getPointerVelocity()` instead.
113
113
  */
114
- // eslint-disable-next-line no-restricted-syntax
114
+ // eslint-disable-next-line tldraw/no-setter-getter
115
115
  get pointerVelocity() {
116
116
  return this.getPointerVelocity()
117
117
  }
@@ -147,11 +147,11 @@ export class InputsManager {
147
147
  /**
148
148
  * @deprecated Use `getIsPen()` instead.
149
149
  */
150
- // eslint-disable-next-line no-restricted-syntax
150
+ // eslint-disable-next-line tldraw/no-setter-getter
151
151
  get isPen() {
152
152
  return this.getIsPen()
153
153
  }
154
- // eslint-disable-next-line no-restricted-syntax
154
+ // eslint-disable-next-line tldraw/no-setter-getter
155
155
  set isPen(isPen: boolean) {
156
156
  this.setIsPen(isPen)
157
157
  }
@@ -172,11 +172,11 @@ export class InputsManager {
172
172
  /**
173
173
  * @deprecated Use `getShiftKey()` instead.
174
174
  */
175
- // eslint-disable-next-line no-restricted-syntax
175
+ // eslint-disable-next-line tldraw/no-setter-getter
176
176
  get shiftKey() {
177
177
  return this.getShiftKey()
178
178
  }
179
- // eslint-disable-next-line no-restricted-syntax
179
+ // eslint-disable-next-line tldraw/no-setter-getter
180
180
  set shiftKey(shiftKey: boolean) {
181
181
  this.setShiftKey(shiftKey)
182
182
  }
@@ -198,11 +198,11 @@ export class InputsManager {
198
198
  /**
199
199
  * @deprecated Use `getMetaKey()` instead.
200
200
  */
201
- // eslint-disable-next-line no-restricted-syntax
201
+ // eslint-disable-next-line tldraw/no-setter-getter
202
202
  get metaKey() {
203
203
  return this.getMetaKey()
204
204
  }
205
- // eslint-disable-next-line no-restricted-syntax
205
+ // eslint-disable-next-line tldraw/no-setter-getter
206
206
  set metaKey(metaKey: boolean) {
207
207
  this.setMetaKey(metaKey)
208
208
  }
@@ -224,11 +224,11 @@ export class InputsManager {
224
224
  /**
225
225
  * @deprecated Use `getCtrlKey()` instead.
226
226
  */
227
- // eslint-disable-next-line no-restricted-syntax
227
+ // eslint-disable-next-line tldraw/no-setter-getter
228
228
  get ctrlKey() {
229
229
  return this.getCtrlKey()
230
230
  }
231
- // eslint-disable-next-line no-restricted-syntax
231
+ // eslint-disable-next-line tldraw/no-setter-getter
232
232
  set ctrlKey(ctrlKey: boolean) {
233
233
  this.setCtrlKey(ctrlKey)
234
234
  }
@@ -250,11 +250,11 @@ export class InputsManager {
250
250
  /**
251
251
  * @deprecated Use `getAltKey()` instead.
252
252
  */
253
- // eslint-disable-next-line no-restricted-syntax
253
+ // eslint-disable-next-line tldraw/no-setter-getter
254
254
  get altKey() {
255
255
  return this.getAltKey()
256
256
  }
257
- // eslint-disable-next-line no-restricted-syntax
257
+ // eslint-disable-next-line tldraw/no-setter-getter
258
258
  set altKey(altKey: boolean) {
259
259
  this.setAltKey(altKey)
260
260
  }
@@ -275,7 +275,7 @@ export class InputsManager {
275
275
  /**
276
276
  * @deprecated Use `getAccelKey()` instead.
277
277
  */
278
- // eslint-disable-next-line no-restricted-syntax
278
+ // eslint-disable-next-line tldraw/no-setter-getter
279
279
  get accelKey() {
280
280
  return this.getAccelKey()
281
281
  }
@@ -290,11 +290,11 @@ export class InputsManager {
290
290
  /**
291
291
  * Soon to be deprecated, use `getIsDragging()` instead.
292
292
  */
293
- // eslint-disable-next-line no-restricted-syntax
293
+ // eslint-disable-next-line tldraw/no-setter-getter
294
294
  get isDragging() {
295
295
  return this.getIsDragging()
296
296
  }
297
- // eslint-disable-next-line no-restricted-syntax
297
+ // eslint-disable-next-line tldraw/no-setter-getter
298
298
  set isDragging(isDragging: boolean) {
299
299
  this.setIsDragging(isDragging)
300
300
  }
@@ -315,11 +315,11 @@ export class InputsManager {
315
315
  /**
316
316
  * @deprecated Use `getIsPointing()` instead.
317
317
  */
318
- // eslint-disable-next-line no-restricted-syntax
318
+ // eslint-disable-next-line tldraw/no-setter-getter
319
319
  get isPointing() {
320
320
  return this.getIsPointing()
321
321
  }
322
- // eslint-disable-next-line no-restricted-syntax
322
+ // eslint-disable-next-line tldraw/no-setter-getter
323
323
  set isPointing(isPointing: boolean) {
324
324
  this.setIsPointing(isPointing)
325
325
  }
@@ -341,11 +341,11 @@ export class InputsManager {
341
341
  /**
342
342
  * @deprecated Use `getIsPinching()` instead.
343
343
  */
344
- // eslint-disable-next-line no-restricted-syntax
344
+ // eslint-disable-next-line tldraw/no-setter-getter
345
345
  get isPinching() {
346
346
  return this.getIsPinching()
347
347
  }
348
- // eslint-disable-next-line no-restricted-syntax
348
+ // eslint-disable-next-line tldraw/no-setter-getter
349
349
  set isPinching(isPinching: boolean) {
350
350
  this.setIsPinching(isPinching)
351
351
  }
@@ -367,11 +367,11 @@ export class InputsManager {
367
367
  /**
368
368
  * @deprecated Use `getIsEditing()` instead.
369
369
  */
370
- // eslint-disable-next-line no-restricted-syntax
370
+ // eslint-disable-next-line tldraw/no-setter-getter
371
371
  get isEditing() {
372
372
  return this.getIsEditing()
373
373
  }
374
- // eslint-disable-next-line no-restricted-syntax
374
+ // eslint-disable-next-line tldraw/no-setter-getter
375
375
  set isEditing(isEditing: boolean) {
376
376
  this.setIsEditing(isEditing)
377
377
  }
@@ -392,11 +392,11 @@ export class InputsManager {
392
392
  /**
393
393
  * @deprecated Use `getIsPanning()` instead.
394
394
  */
395
- // eslint-disable-next-line no-restricted-syntax
395
+ // eslint-disable-next-line tldraw/no-setter-getter
396
396
  get isPanning() {
397
397
  return this.getIsPanning()
398
398
  }
399
- // eslint-disable-next-line no-restricted-syntax
399
+ // eslint-disable-next-line tldraw/no-setter-getter
400
400
  set isPanning(isPanning: boolean) {
401
401
  this.setIsPanning(isPanning)
402
402
  }
@@ -418,11 +418,11 @@ export class InputsManager {
418
418
  /**
419
419
  * @deprecated Use `getIsSpacebarPanning()` instead.
420
420
  */
421
- // eslint-disable-next-line no-restricted-syntax
421
+ // eslint-disable-next-line tldraw/no-setter-getter
422
422
  get isSpacebarPanning() {
423
423
  return this.getIsSpacebarPanning()
424
424
  }
425
- // eslint-disable-next-line no-restricted-syntax
425
+ // eslint-disable-next-line tldraw/no-setter-getter
426
426
  set isSpacebarPanning(isSpacebarPanning: boolean) {
427
427
  this.setIsSpacebarPanning(isSpacebarPanning)
428
428
  }
@@ -58,17 +58,16 @@ const mockCreateElement = vi.fn(() => {
58
58
  })
59
59
 
60
60
  // Mock editor
61
+ const mockDocument = {
62
+ createElement: mockCreateElement,
63
+ }
61
64
  const mockEditor = {
62
65
  getContainer: vi.fn(() => ({
63
66
  appendChild: vi.fn(),
64
67
  })),
68
+ getContainerDocument: vi.fn(() => mockDocument),
65
69
  } as unknown as Editor
66
70
 
67
- // Setup global mocks
68
- global.document = {
69
- createElement: mockCreateElement,
70
- } as any
71
-
72
71
  global.Range = vi.fn(() => ({
73
72
  setStart: vi.fn(),
74
73
  setEnd: vi.fn(),
@@ -75,7 +75,7 @@ export class TextManager {
75
75
  private elm: HTMLDivElement
76
76
 
77
77
  constructor(public editor: Editor) {
78
- const elm = document.createElement('div')
78
+ const elm = editor.getContainerDocument().createElement('div')
79
79
  elm.classList.add('tl-text')
80
80
  elm.classList.add('tl-text-measure')
81
81
  elm.setAttribute('dir', 'auto')
@@ -111,7 +111,7 @@ export class TextManager {
111
111
  }
112
112
 
113
113
  measureText(textToMeasure: string, opts: TLMeasureTextOpts): BoxModel & { scrollWidth: number } {
114
- const div = document.createElement('div')
114
+ const div = this.editor.getContainerDocument().createElement('div')
115
115
  div.textContent = normalizeTextForDom(textToMeasure)
116
116
  return this.measureHtml(div.innerHTML, opts)
117
117
  }
@@ -1,6 +1,7 @@
1
1
  import { atom, computed } from '@tldraw/state'
2
2
  import { TLUserPreferences, defaultUserPreferences } from '../../../config/TLUserPreferences'
3
3
  import { TLUser } from '../../../config/createTLUser'
4
+ import { getGlobalWindow } from '../../../utils/dom'
4
5
 
5
6
  /** @public */
6
7
  export class UserPreferencesManager {
@@ -13,9 +14,9 @@ export class UserPreferencesManager {
13
14
  private readonly user: TLUser,
14
15
  private readonly inferDarkMode: boolean
15
16
  ) {
16
- if (typeof window === 'undefined' || !window.matchMedia) return
17
+ if (typeof window === 'undefined' || !getGlobalWindow().matchMedia) return
17
18
 
18
- const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
19
+ const darkModeMediaQuery = getGlobalWindow().matchMedia('(prefers-color-scheme: dark)')
19
20
  if (darkModeMediaQuery?.matches) {
20
21
  this.systemColorScheme.set('dark')
21
22
  }
@@ -40,9 +40,15 @@ export interface TLSvgExportOptions {
40
40
  background?: boolean
41
41
 
42
42
  /**
43
- * How much padding to include around the bounds of exports? Defaults to 32px.
43
+ * How much padding to include around the bounds of exports.
44
+ *
45
+ * - `'auto'` (default) — trim to visual content bounds, capturing overflow (like thick
46
+ * strokes or arrowheads) without extra whitespace.
47
+ * - `number` (e.g. `32`) — fixed padding in px. No trimming; overflow beyond the padding
48
+ * region is clipped.
49
+ * - `0` — no padding, no trimming, overflow is clipped.
44
50
  */
45
- padding?: number
51
+ padding?: number | 'auto'
46
52
 
47
53
  /**
48
54
  * Should the export be rendered in dark mode (true) or light mode (false)? Defaults to the
@@ -11,7 +11,7 @@ export const SVG_EXPORT_CLASSNAME = 'tldraw-svg-export'
11
11
  * SVG.
12
12
  *
13
13
  * It works in three steps:
14
- * 1. `startFindingCurrentDocumentFontFaces` - this traverses the current document, finding all the
14
+ * 1. `startFindingDocumentFontFaces` - this traverses the given document, finding all the
15
15
  * stylesheets in use (including those imported via `@import` rules etc) and extracting the
16
16
  * @font-face declarations from them.
17
17
  * 2. `onFontFamilyValue` - as `StyleEmbedder` traverses the SVG, it will call this method with the
@@ -26,9 +26,9 @@ export class FontEmbedder {
26
26
  private readonly fontFacesToEmbed = new Set<ParsedFontFace>()
27
27
  private readonly pendingPromises: Promise<void>[] = []
28
28
 
29
- startFindingCurrentDocumentFontFaces() {
29
+ startFindingDocumentFontFaces(doc: Document) {
30
30
  assert(!this.fontFacesPromise, 'FontEmbedder already started')
31
- this.fontFacesPromise = getCurrentDocumentFontFaces()
31
+ this.fontFacesPromise = getDocumentFontFaces(doc)
32
32
  }
33
33
 
34
34
  @bind onFontFamilyValue(fontFamilyValue: string) {
@@ -80,7 +80,8 @@ export class FontEmbedder {
80
80
  }
81
81
  }
82
82
 
83
- async function getCurrentDocumentFontFaces() {
83
+ async function getDocumentFontFaces(doc: Document) {
84
+ const win = doc.defaultView ?? globalThis
84
85
  const fontFaces: (ParsedFontFace[] | Promise<ParsedFontFace[] | null>)[] = []
85
86
 
86
87
  // In exportToSvg we add the exported node to the DOM temporarily.
@@ -88,7 +89,7 @@ async function getCurrentDocumentFontFaces() {
88
89
  // DOM, when looking at document.styleSheets the number of nodes and stylesheets
89
90
  // can grow unbounded (especially when using "Debug svg" and moving shapes around).
90
91
  // To avoid this, we filter out the stylesheets that are part of the SVG export.
91
- const styleSheetsWithoutSvgExports = Array.from(document.styleSheets).filter(
92
+ const styleSheetsWithoutSvgExports = Array.from(doc.styleSheets).filter(
92
93
  (styleSheet) =>
93
94
  !(styleSheet.ownerNode as HTMLElement | null)?.closest(`.${SVG_EXPORT_CLASSNAME}`)
94
95
  )
@@ -103,10 +104,10 @@ async function getCurrentDocumentFontFaces() {
103
104
 
104
105
  if (cssRules) {
105
106
  for (const rule of styleSheet.cssRules) {
106
- if (rule instanceof CSSFontFaceRule) {
107
- fontFaces.push(parseCssFontFaces(rule.cssText, styleSheet.href ?? document.baseURI))
108
- } else if (rule instanceof CSSImportRule) {
109
- const absoluteUrl = new URL(rule.href, rule.parentStyleSheet?.href ?? document.baseURI)
107
+ if (rule instanceof win.CSSFontFaceRule) {
108
+ fontFaces.push(parseCssFontFaces(rule.cssText, styleSheet.href ?? doc.baseURI))
109
+ } else if (rule instanceof win.CSSImportRule) {
110
+ const absoluteUrl = new URL(rule.href, rule.parentStyleSheet?.href ?? doc.baseURI)
110
111
  fontFaces.push(fetchCssFontFaces(absoluteUrl.href))
111
112
  }
112
113
  }
@@ -6,6 +6,7 @@ import {
6
6
  getComputedStyle,
7
7
  getRenderedChildNodes,
8
8
  getRenderedChildren,
9
+ isElement,
9
10
  } from './domUtils'
10
11
  import { resourceToDataUrl } from './fetchCache'
11
12
  import { parseCssValueUrls, shouldIncludeCssProperty } from './parseCss'
@@ -49,7 +50,7 @@ export class StyleEmbedder {
49
50
  { shouldRespectDefaults = true, shouldSkipInheritedParentStyles = true }
50
51
  ) {
51
52
  const defaultStyles = shouldRespectDefaults
52
- ? getDefaultStylesForTagName(element.tagName.toLowerCase())
53
+ ? getDefaultStylesForTagName(element.ownerDocument, element.tagName.toLowerCase())
53
54
  : NO_STYLES
54
55
 
55
56
  const parentStyles = Object.assign({}, NO_STYLES) as Styles
@@ -116,14 +117,14 @@ export class StyleEmbedder {
116
117
  const shadowRoot = element.shadowRoot
117
118
 
118
119
  if (shadowRoot) {
119
- const clonedCustomEl = document.createElement('div')
120
+ const clonedCustomEl = element.ownerDocument.createElement('div')
120
121
  this.styles.set(clonedCustomEl, this.styles.get(element)!)
121
122
 
122
123
  clonedCustomEl.setAttribute('data-tl-custom-element', element.tagName)
123
124
  ;(clonedParent ?? element.parentElement!).appendChild(clonedCustomEl)
124
125
 
125
126
  for (const child of shadowRoot.childNodes) {
126
- if (child instanceof Element) {
127
+ if (isElement(child)) {
127
128
  visit(child, clonedCustomEl)
128
129
  } else {
129
130
  clonedCustomEl.appendChild(child.cloneNode(true))
@@ -144,7 +145,7 @@ export class StyleEmbedder {
144
145
  clonedParent.appendChild(clonedEl)
145
146
 
146
147
  for (const child of getRenderedChildNodes(element)) {
147
- if (child instanceof Element) {
148
+ if (isElement(child)) {
148
149
  visit(child, clonedEl)
149
150
  } else {
150
151
  clonedEl.appendChild(child.cloneNode(true))
@@ -295,36 +296,53 @@ function formatCss(style: ReadonlyStyles) {
295
296
  // when we're figuring out the default values for a tag, we need read them from a separate document
296
297
  // so they're not affected by the current document's styles
297
298
  let defaultStyleFrame:
298
- | { iframe: HTMLIFrameElement; foreignObject: SVGForeignObjectElement; document: Document }
299
+ | {
300
+ iframe: HTMLIFrameElement
301
+ foreignObject: SVGForeignObjectElement
302
+ document: Document
303
+ ownerDocument: Document
304
+ }
299
305
  | undefined
300
306
  const defaultStylesByTagName: Record<string, ReadonlyStyles> = {}
301
- function getDefaultStyleFrame() {
302
- if (!defaultStyleFrame) {
303
- const frame = document.createElement('iframe')
307
+ function getDefaultStyleFrame(ownerDoc: Document) {
308
+ if (!defaultStyleFrame || defaultStyleFrame.ownerDocument !== ownerDoc) {
309
+ destroyDefaultStyleFrame()
310
+ const frame = ownerDoc.createElement('iframe')
304
311
  frame.style.display = 'none'
305
- document.body.appendChild(frame)
312
+ ownerDoc.body.appendChild(frame)
306
313
  const frameDocument = assertExists(frame.contentDocument, 'frame must have a document')
307
- const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
308
- const foreignObject = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')
314
+ const svg = frameDocument.createElementNS('http://www.w3.org/2000/svg', 'svg')
315
+ const foreignObject = frameDocument.createElementNS(
316
+ 'http://www.w3.org/2000/svg',
317
+ 'foreignObject'
318
+ )
309
319
  svg.appendChild(foreignObject)
310
320
  frameDocument.body.appendChild(svg)
311
- defaultStyleFrame = { iframe: frame, foreignObject, document: frameDocument }
321
+ defaultStyleFrame = {
322
+ iframe: frame,
323
+ foreignObject,
324
+ document: frameDocument,
325
+ ownerDocument: ownerDoc,
326
+ }
312
327
  }
313
328
  return defaultStyleFrame
314
329
  }
315
330
 
316
331
  function destroyDefaultStyleFrame() {
317
332
  if (defaultStyleFrame) {
318
- document.body.removeChild(defaultStyleFrame.iframe)
333
+ defaultStyleFrame.iframe.remove()
319
334
  defaultStyleFrame = undefined
320
335
  }
336
+ for (const tagName in defaultStylesByTagName) {
337
+ delete defaultStylesByTagName[tagName]
338
+ }
321
339
  }
322
340
 
323
341
  const defaultStyleReadOptions: ReadStyleOpts = { defaultStyles: NO_STYLES, parentStyles: NO_STYLES }
324
- function getDefaultStylesForTagName(tagName: string) {
342
+ function getDefaultStylesForTagName(ownerDoc: Document, tagName: string) {
325
343
  let existing = defaultStylesByTagName[tagName]
326
344
  if (!existing) {
327
- const { foreignObject, document } = getDefaultStyleFrame()
345
+ const { foreignObject, document } = getDefaultStyleFrame(ownerDoc)
328
346
  const element = document.createElement(tagName)
329
347
  foreignObject.appendChild(element)
330
348
  existing = element.computedStyleMap
@@ -22,6 +22,26 @@ export function* getRenderedChildren(node: Element) {
22
22
  }
23
23
  }
24
24
 
25
+ /** @internal */
26
+ export function getOwnerWindow(
27
+ nodeOrDocument: Node | Document | null | undefined
28
+ ): Window & typeof globalThis {
29
+ if (!nodeOrDocument) return globalThis as Window & typeof globalThis
30
+ const doc = isDocument(nodeOrDocument) ? nodeOrDocument : nodeOrDocument.ownerDocument
31
+ return (doc?.defaultView ?? globalThis) as Window & typeof globalThis
32
+ }
33
+
34
+ /** @internal */
35
+ export function getOwnerDocument(nodeOrDocument: Node | Document | null | undefined): Document {
36
+ if (!nodeOrDocument) return globalThis.document
37
+ if (isDocument(nodeOrDocument)) return nodeOrDocument
38
+ return nodeOrDocument.ownerDocument ?? globalThis.document
39
+ }
40
+
41
+ function isDocument(node: Node | Document): node is Document {
42
+ return node.nodeType === Node.DOCUMENT_NODE
43
+ }
44
+
25
45
  function getWindow(node: Node) {
26
46
  return node.ownerDocument?.defaultView ?? globalThis
27
47
  }
@@ -1,5 +1,5 @@
1
1
  import { MediaHelpers } from '@tldraw/utils'
2
- import { getRenderedChildren } from './domUtils'
2
+ import { getOwnerWindow, getRenderedChildren } from './domUtils'
3
3
  import { resourceToDataUrl } from './fetchCache'
4
4
 
5
5
  function copyAttrs(source: Element, target: Element) {
@@ -14,8 +14,12 @@ function replace(original: HTMLElement, replacement: HTMLElement) {
14
14
  return replacement
15
15
  }
16
16
 
17
- async function createImage(dataUrl: string | null, cloneAttributesFrom?: HTMLElement) {
18
- const image = document.createElement('img')
17
+ async function createImage(
18
+ doc: Document,
19
+ dataUrl: string | null,
20
+ cloneAttributesFrom?: HTMLElement
21
+ ) {
22
+ const image = doc.createElement('img')
19
23
 
20
24
  if (cloneAttributesFrom) {
21
25
  copyAttrs(cloneAttributesFrom, image)
@@ -34,52 +38,54 @@ async function createImage(dataUrl: string | null, cloneAttributesFrom?: HTMLEle
34
38
  }
35
39
 
36
40
  async function getCanvasReplacement(canvas: HTMLCanvasElement) {
41
+ const doc = canvas.ownerDocument
37
42
  try {
38
43
  const dataURL = canvas.toDataURL()
39
- return await createImage(dataURL, canvas)
44
+ return await createImage(doc, dataURL, canvas)
40
45
  } catch {
41
- return await createImage(null, canvas)
46
+ return await createImage(doc, null, canvas)
42
47
  }
43
48
  }
44
49
 
45
50
  async function getVideoReplacement(video: HTMLVideoElement) {
51
+ const doc = video.ownerDocument
46
52
  try {
47
53
  const dataUrl = await MediaHelpers.getVideoFrameAsDataUrl(video)
48
- return createImage(dataUrl, video)
54
+ return createImage(doc, dataUrl, video)
49
55
  } catch (err) {
50
56
  console.error('Could not get video frame', err)
51
57
  }
52
58
 
53
59
  if (video.poster) {
54
60
  const dataUrl = await resourceToDataUrl(video.poster)
55
- return createImage(dataUrl, video)
61
+ return createImage(doc, dataUrl, video)
56
62
  }
57
63
 
58
- return createImage(null, video)
64
+ return createImage(doc, null, video)
59
65
  }
60
66
 
61
67
  export async function embedMedia(node: HTMLElement) {
62
- if (node instanceof HTMLCanvasElement) {
68
+ const win = getOwnerWindow(node)
69
+ if (node instanceof win.HTMLCanvasElement) {
63
70
  return replace(node, await getCanvasReplacement(node))
64
- } else if (node instanceof HTMLVideoElement) {
71
+ } else if (node instanceof win.HTMLVideoElement) {
65
72
  return replace(node, await getVideoReplacement(node))
66
- } else if (node instanceof HTMLImageElement) {
73
+ } else if (node instanceof win.HTMLImageElement) {
67
74
  const src = node.currentSrc || node.src
68
75
  const dataUrl = await resourceToDataUrl(src)
69
76
  node.setAttribute('src', dataUrl ?? 'data:')
70
77
  node.setAttribute('decoding', 'sync')
71
78
  node.setAttribute('loading', 'eager')
72
79
  try {
73
- await node.decode()
80
+ await (node as HTMLImageElement).decode()
74
81
  } catch {
75
82
  // this is fine
76
83
  }
77
84
  return node
78
- } else if (node instanceof HTMLInputElement) {
79
- // if an input has a value, make sure it's serialized when we convert to svg
80
- node.setAttribute('value', node.value)
81
- } else if (node instanceof HTMLTextAreaElement) {
82
- node.textContent = node.value
85
+ } else if (node instanceof win.HTMLInputElement) {
86
+ node.setAttribute('value', (node as HTMLInputElement).value)
87
+ } else if (node instanceof win.HTMLTextAreaElement) {
88
+ node.textContent = (node as HTMLTextAreaElement).value
83
89
  }
84
90
 
85
91
  await Promise.all(