@tldraw/editor 4.5.2 → 4.6.0-canary.4ec045c286e1

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 (226) 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/editor/Editor.js +52 -16
  19. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  20. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +62 -6
  21. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
  22. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +4 -3
  23. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
  24. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +5 -0
  25. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
  26. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +2 -2
  27. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  28. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +3 -2
  29. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  30. package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
  31. package/dist-cjs/lib/exports/FontEmbedder.js +9 -8
  32. package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
  33. package/dist-cjs/lib/exports/StyleEmbedder.js +27 -15
  34. package/dist-cjs/lib/exports/StyleEmbedder.js.map +3 -3
  35. package/dist-cjs/lib/exports/domUtils.js +15 -0
  36. package/dist-cjs/lib/exports/domUtils.js.map +2 -2
  37. package/dist-cjs/lib/exports/embedMedia.js +15 -12
  38. package/dist-cjs/lib/exports/embedMedia.js.map +2 -2
  39. package/dist-cjs/lib/exports/exportToSvg.js +8 -7
  40. package/dist-cjs/lib/exports/exportToSvg.js.map +2 -2
  41. package/dist-cjs/lib/exports/getSvgAsImage.js +181 -29
  42. package/dist-cjs/lib/exports/getSvgAsImage.js.map +3 -3
  43. package/dist-cjs/lib/exports/getSvgJsx.js +21 -9
  44. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  45. package/dist-cjs/lib/globals/environment.js +4 -3
  46. package/dist-cjs/lib/globals/environment.js.map +2 -2
  47. package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -2
  48. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  49. package/dist-cjs/lib/hooks/useDocumentEvents.js +13 -11
  50. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  51. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +3 -2
  52. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
  53. package/dist-cjs/lib/hooks/useScreenBounds.js +10 -6
  54. package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
  55. package/dist-cjs/lib/hooks/useViewportHeight.js +13 -11
  56. package/dist-cjs/lib/hooks/useViewportHeight.js.map +3 -3
  57. package/dist-cjs/lib/license/Watermark.js +10 -0
  58. package/dist-cjs/lib/license/Watermark.js.map +2 -2
  59. package/dist-cjs/lib/primitives/Vec.js +35 -22
  60. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  61. package/dist-cjs/lib/primitives/geometry/Arc2d.js +6 -13
  62. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  63. package/dist-cjs/lib/primitives/geometry/Circle2d.js +31 -2
  64. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
  65. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +9 -0
  66. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  67. package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js +9 -0
  68. package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
  69. package/dist-cjs/lib/primitives/geometry/Edge2d.js +32 -18
  70. package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
  71. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +12 -0
  72. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
  73. package/dist-cjs/lib/primitives/geometry/Polyline2d.js +51 -12
  74. package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
  75. package/dist-cjs/lib/primitives/geometry/Stadium2d.js +12 -0
  76. package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
  77. package/dist-cjs/lib/primitives/geometry/geometry.bench.js +133 -0
  78. package/dist-cjs/lib/primitives/geometry/geometry.bench.js.map +7 -0
  79. package/dist-cjs/lib/primitives/intersect.js +16 -15
  80. package/dist-cjs/lib/primitives/intersect.js.map +2 -2
  81. package/dist-cjs/lib/primitives/utils.js +0 -1
  82. package/dist-cjs/lib/primitives/utils.js.map +2 -2
  83. package/dist-cjs/lib/utils/browserCanvasMaxSize.js +3 -2
  84. package/dist-cjs/lib/utils/browserCanvasMaxSize.js.map +2 -2
  85. package/dist-cjs/lib/utils/dom.js +15 -2
  86. package/dist-cjs/lib/utils/dom.js.map +2 -2
  87. package/dist-cjs/version.js +3 -3
  88. package/dist-cjs/version.js.map +1 -1
  89. package/dist-esm/index.d.mts +37 -6
  90. package/dist-esm/index.mjs +8 -1
  91. package/dist-esm/index.mjs.map +2 -2
  92. package/dist-esm/lib/TldrawEditor.mjs +7 -5
  93. package/dist-esm/lib/TldrawEditor.mjs.map +3 -3
  94. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +2 -1
  95. package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +2 -2
  96. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -1
  97. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  98. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +8 -5
  99. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
  100. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs +8 -5
  101. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs.map +2 -2
  102. package/dist-esm/lib/config/TLUserPreferences.mjs +3 -2
  103. package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
  104. package/dist-esm/lib/config/createTLStore.mjs +1 -0
  105. package/dist-esm/lib/config/createTLStore.mjs.map +2 -2
  106. package/dist-esm/lib/editor/Editor.mjs +53 -17
  107. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  108. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +64 -6
  109. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
  110. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +4 -3
  111. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
  112. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +5 -0
  113. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
  114. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +2 -2
  115. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  116. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +3 -2
  117. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  118. package/dist-esm/lib/exports/FontEmbedder.mjs +9 -8
  119. package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
  120. package/dist-esm/lib/exports/StyleEmbedder.mjs +29 -16
  121. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +3 -3
  122. package/dist-esm/lib/exports/domUtils.mjs +15 -0
  123. package/dist-esm/lib/exports/domUtils.mjs.map +2 -2
  124. package/dist-esm/lib/exports/embedMedia.mjs +16 -13
  125. package/dist-esm/lib/exports/embedMedia.mjs.map +2 -2
  126. package/dist-esm/lib/exports/exportToSvg.mjs +8 -7
  127. package/dist-esm/lib/exports/exportToSvg.mjs.map +2 -2
  128. package/dist-esm/lib/exports/getSvgAsImage.mjs +181 -29
  129. package/dist-esm/lib/exports/getSvgAsImage.mjs.map +3 -3
  130. package/dist-esm/lib/exports/getSvgJsx.mjs +21 -9
  131. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  132. package/dist-esm/lib/globals/environment.mjs +4 -3
  133. package/dist-esm/lib/globals/environment.mjs.map +2 -2
  134. package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -2
  135. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  136. package/dist-esm/lib/hooks/useDocumentEvents.mjs +13 -11
  137. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  138. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +3 -2
  139. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
  140. package/dist-esm/lib/hooks/useScreenBounds.mjs +10 -6
  141. package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
  142. package/dist-esm/lib/hooks/useViewportHeight.mjs +13 -11
  143. package/dist-esm/lib/hooks/useViewportHeight.mjs.map +3 -3
  144. package/dist-esm/lib/license/Watermark.mjs +10 -0
  145. package/dist-esm/lib/license/Watermark.mjs.map +2 -2
  146. package/dist-esm/lib/primitives/Vec.mjs +35 -22
  147. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  148. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +6 -13
  149. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  150. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +31 -2
  151. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
  152. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +9 -0
  153. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  154. package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs +9 -0
  155. package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
  156. package/dist-esm/lib/primitives/geometry/Edge2d.mjs +32 -18
  157. package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
  158. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +13 -1
  159. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
  160. package/dist-esm/lib/primitives/geometry/Polyline2d.mjs +51 -12
  161. package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
  162. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs +13 -1
  163. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
  164. package/dist-esm/lib/primitives/geometry/geometry.bench.mjs +132 -0
  165. package/dist-esm/lib/primitives/geometry/geometry.bench.mjs.map +7 -0
  166. package/dist-esm/lib/primitives/intersect.mjs +17 -16
  167. package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
  168. package/dist-esm/lib/primitives/utils.mjs +0 -1
  169. package/dist-esm/lib/primitives/utils.mjs.map +2 -2
  170. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +3 -2
  171. package/dist-esm/lib/utils/browserCanvasMaxSize.mjs.map +2 -2
  172. package/dist-esm/lib/utils/dom.mjs +15 -2
  173. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  174. package/dist-esm/version.mjs +3 -3
  175. package/dist-esm/version.mjs.map +1 -1
  176. package/package.json +7 -7
  177. package/src/index.ts +3 -0
  178. package/src/lib/TldrawEditor.tsx +7 -5
  179. package/src/lib/components/default-components/CanvasShapeIndicators.tsx +2 -1
  180. package/src/lib/components/default-components/DefaultCanvas.tsx +1 -1
  181. package/src/lib/components/default-components/DefaultErrorFallback.tsx +8 -5
  182. package/src/lib/config/TLSessionStateSnapshot.ts +8 -5
  183. package/src/lib/config/TLUserPreferences.ts +3 -2
  184. package/src/lib/config/createTLStore.ts +3 -0
  185. package/src/lib/editor/Editor.ts +53 -15
  186. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +7 -6
  187. package/src/lib/editor/managers/FocusManager/FocusManager.ts +10 -7
  188. package/src/lib/editor/managers/FontManager/FontManager.test.ts +1 -0
  189. package/src/lib/editor/managers/FontManager/FontManager.ts +4 -3
  190. package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +16 -0
  191. package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +7 -2
  192. package/src/lib/editor/managers/TextManager/TextManager.test.ts +4 -5
  193. package/src/lib/editor/managers/TextManager/TextManager.ts +2 -2
  194. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +3 -2
  195. package/src/lib/editor/types/misc-types.ts +8 -2
  196. package/src/lib/exports/FontEmbedder.ts +10 -9
  197. package/src/lib/exports/StyleEmbedder.ts +33 -15
  198. package/src/lib/exports/domUtils.ts +20 -0
  199. package/src/lib/exports/embedMedia.ts +23 -17
  200. package/src/lib/exports/exportToSvg.tsx +8 -7
  201. package/src/lib/exports/getSvgAsImage.ts +292 -32
  202. package/src/lib/exports/getSvgJsx.test.ts +103 -101
  203. package/src/lib/exports/getSvgJsx.tsx +33 -10
  204. package/src/lib/globals/environment.ts +4 -3
  205. package/src/lib/hooks/useCanvasEvents.ts +2 -3
  206. package/src/lib/hooks/useDocumentEvents.ts +16 -11
  207. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +3 -3
  208. package/src/lib/hooks/useScreenBounds.ts +10 -6
  209. package/src/lib/hooks/useViewportHeight.ts +13 -11
  210. package/src/lib/license/Watermark.tsx +10 -0
  211. package/src/lib/primitives/Vec.ts +51 -24
  212. package/src/lib/primitives/geometry/Arc2d.ts +10 -15
  213. package/src/lib/primitives/geometry/Circle2d.ts +40 -2
  214. package/src/lib/primitives/geometry/CubicBezier2d.ts +10 -0
  215. package/src/lib/primitives/geometry/CubicSpline2d.ts +10 -0
  216. package/src/lib/primitives/geometry/Edge2d.ts +41 -18
  217. package/src/lib/primitives/geometry/Ellipse2d.ts +14 -1
  218. package/src/lib/primitives/geometry/Polyline2d.ts +60 -12
  219. package/src/lib/primitives/geometry/Stadium2d.ts +14 -1
  220. package/src/lib/primitives/geometry/geometry.bench.ts +179 -0
  221. package/src/lib/primitives/intersect.ts +27 -27
  222. package/src/lib/primitives/utils.ts +4 -4
  223. package/src/lib/test/TestEditor.ts +1 -0
  224. package/src/lib/utils/browserCanvasMaxSize.ts +4 -2
  225. package/src/lib/utils/dom.ts +34 -2
  226. package/src/version.ts +3 -3
@@ -1,8 +1,15 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
8
+ var __typeError = (msg) => {
9
+ throw TypeError(msg);
10
+ };
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
13
  var __export = (target, all) => {
7
14
  for (var name in all)
8
15
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,14 +23,58 @@ var __copyProps = (to, from, except, desc) => {
16
23
  return to;
17
24
  };
18
25
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
26
+ var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
27
+ var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
28
+ var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
29
+ var __decoratorContext = (kind, name, done, metadata, fns) => ({ kind: __decoratorStrings[kind], name, metadata, addInitializer: (fn) => done._ ? __typeError("Already initialized") : fns.push(__expectFn(fn || null)) });
30
+ var __decoratorMetadata = (array, target) => __defNormalProp(target, __knownSymbol("metadata"), array[3]);
31
+ var __runInitializers = (array, flags, self, value) => {
32
+ for (var i = 0, fns = array[flags >> 1], n = fns && fns.length; i < n; i++) flags & 1 ? fns[i].call(self) : value = fns[i].call(self, value);
33
+ return value;
34
+ };
35
+ var __decorateElement = (array, flags, name, decorators, target, extra) => {
36
+ var fn, it, done, ctx, access, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
37
+ var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
38
+ var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
39
+ var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : { get [name]() {
40
+ return __privateGet(this, extra);
41
+ }, set [name](x) {
42
+ return __privateSet(this, extra, x);
43
+ } }, name));
44
+ k ? p && k < 4 && __name(extra, (k > 2 ? "set " : k > 1 ? "get " : "") + name) : __name(target, name);
45
+ for (var i = decorators.length - 1; i >= 0; i--) {
46
+ ctx = __decoratorContext(k, name, done = {}, array[3], extraInitializers);
47
+ if (k) {
48
+ ctx.static = s, ctx.private = p, access = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => name in x };
49
+ if (k ^ 3) access.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name];
50
+ if (k > 2) access.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name] = y;
51
+ }
52
+ it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? void 0 : { get: desc.get, set: desc.set } : target, ctx), done._ = 1;
53
+ if (k ^ 4 || it === void 0) __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
54
+ else if (typeof it !== "object" || it === null) __typeError("Object expected");
55
+ else __expectFn(fn = it.get) && (desc.get = fn), __expectFn(fn = it.set) && (desc.set = fn), __expectFn(fn = it.init) && initializers.unshift(fn);
56
+ }
57
+ return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
58
+ };
59
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
60
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
61
+ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use the "in" operator on this value') : member.has(obj);
62
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
63
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
64
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
19
65
  var FocusManager_exports = {};
20
66
  __export(FocusManager_exports, {
21
67
  FocusManager: () => FocusManager
22
68
  });
23
69
  module.exports = __toCommonJS(FocusManager_exports);
70
+ var import_utils = require("@tldraw/utils");
71
+ var _handleMouseDown_dec, _handleKeyDown_dec, _init;
72
+ _handleKeyDown_dec = [import_utils.bind], _handleMouseDown_dec = [import_utils.bind];
24
73
  class FocusManager {
25
74
  constructor(editor, autoFocus) {
26
75
  this.editor = editor;
76
+ __runInitializers(_init, 5, this);
77
+ __publicField(this, "disposeSideEffectListener");
27
78
  this.disposeSideEffectListener = editor.sideEffects.registerAfterChangeHandler(
28
79
  "instance",
29
80
  (prev, next) => {
@@ -37,10 +88,10 @@ class FocusManager {
37
88
  editor.updateInstanceState({ isFocused: !!autoFocus });
38
89
  }
39
90
  this.updateContainerClass();
40
- document.body.addEventListener("keydown", this.handleKeyDown.bind(this));
41
- document.body.addEventListener("mousedown", this.handleMouseDown.bind(this));
91
+ const body = editor.getContainerDocument().body;
92
+ body.addEventListener("keydown", this.handleKeyDown);
93
+ body.addEventListener("mousedown", this.handleMouseDown);
42
94
  }
43
- disposeSideEffectListener;
44
95
  /**
45
96
  * The editor's focus state and the container's focus state
46
97
  * are not necessarily always in sync. For that reason we
@@ -62,7 +113,7 @@ class FocusManager {
62
113
  }
63
114
  handleKeyDown(keyEvent) {
64
115
  const container = this.editor.getContainer();
65
- const activeEl = document.activeElement;
116
+ const activeEl = container.ownerDocument.activeElement;
66
117
  if (this.editor.isIn("select.editing_shape") && !activeEl?.closest(".tlui-contextual-toolbar"))
67
118
  return;
68
119
  if (activeEl === container && this.editor.getSelectedShapeIds().length > 0) return;
@@ -82,9 +133,14 @@ class FocusManager {
82
133
  this.editor.getContainer().blur();
83
134
  }
84
135
  dispose() {
85
- document.body.removeEventListener("keydown", this.handleKeyDown.bind(this));
86
- document.body.removeEventListener("mousedown", this.handleMouseDown.bind(this));
136
+ const body = this.editor.getContainerDocument().body;
137
+ body.removeEventListener("keydown", this.handleKeyDown);
138
+ body.removeEventListener("mousedown", this.handleMouseDown);
87
139
  this.disposeSideEffectListener?.();
88
140
  }
89
141
  }
142
+ _init = __decoratorStart(null);
143
+ __decorateElement(_init, 1, "handleKeyDown", _handleKeyDown_dec, FocusManager);
144
+ __decorateElement(_init, 1, "handleMouseDown", _handleMouseDown_dec, FocusManager);
145
+ __decoratorMetadata(_init, FocusManager);
90
146
  //# sourceMappingURL=FocusManager.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/editor/managers/FocusManager/FocusManager.ts"],
4
- "sourcesContent": ["import type { Editor } from '../../Editor'\n\n/**\n * A manager for ensuring correct focus across the editor.\n * It will listen for changes in the instance state to make sure the\n * container is focused when the editor is focused.\n * Also, it will make sure that the focus is on things like text\n * labels when the editor is in editing mode.\n *\n * @internal\n */\nexport class FocusManager {\n\tprivate disposeSideEffectListener?: () => void\n\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tautoFocus?: boolean\n\t) {\n\t\tthis.disposeSideEffectListener = editor.sideEffects.registerAfterChangeHandler(\n\t\t\t'instance',\n\t\t\t(prev, next) => {\n\t\t\t\tif (prev.isFocused !== next.isFocused) {\n\t\t\t\t\tthis.updateContainerClass()\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\n\t\tconst currentFocusState = editor.getInstanceState().isFocused\n\t\tif (autoFocus !== currentFocusState) {\n\t\t\teditor.updateInstanceState({ isFocused: !!autoFocus })\n\t\t}\n\t\tthis.updateContainerClass()\n\n\t\tdocument.body.addEventListener('keydown', this.handleKeyDown.bind(this))\n\t\tdocument.body.addEventListener('mousedown', this.handleMouseDown.bind(this))\n\t}\n\n\t/**\n\t * The editor's focus state and the container's focus state\n\t * are not necessarily always in sync. For that reason we\n\t * can't rely on the css `:focus` or `:focus-within` selectors to style the\n\t * editor when it is in focus.\n\t *\n\t * For that reason we synchronize the editor's focus state with a\n\t * special class on the container: tl-container__focused\n\t */\n\tprivate updateContainerClass() {\n\t\tconst container = this.editor.getContainer()\n\t\tconst instanceState = this.editor.getInstanceState()\n\n\t\tif (instanceState.isFocused) {\n\t\t\tcontainer.classList.add('tl-container__focused')\n\t\t} else {\n\t\t\tcontainer.classList.remove('tl-container__focused')\n\t\t}\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\tprivate handleKeyDown(keyEvent: KeyboardEvent) {\n\t\tconst container = this.editor.getContainer()\n\t\tconst activeEl = document.activeElement\n\t\t// Edit mode should remove the focus ring, however if the active element's\n\t\t// parent is the contextual toolbar, then allow it.\n\t\tif (this.editor.isIn('select.editing_shape') && !activeEl?.closest('.tlui-contextual-toolbar'))\n\t\t\treturn\n\t\tif (activeEl === container && this.editor.getSelectedShapeIds().length > 0) return\n\t\tif (['Tab', 'ArrowUp', 'ArrowDown'].includes(keyEvent.key)) {\n\t\t\tcontainer.classList.remove('tl-container__no-focus-ring')\n\t\t}\n\t}\n\n\tprivate handleMouseDown() {\n\t\tconst container = this.editor.getContainer()\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\tfocus() {\n\t\tthis.editor.getContainer().focus()\n\t}\n\n\tblur() {\n\t\tthis.editor.complete() // stop any interaction\n\t\tthis.editor.getContainer().blur() // blur the container\n\t}\n\n\tdispose() {\n\t\tdocument.body.removeEventListener('keydown', this.handleKeyDown.bind(this))\n\t\tdocument.body.removeEventListener('mousedown', this.handleMouseDown.bind(this))\n\t\tthis.disposeSideEffectListener?.()\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAWO,MAAM,aAAa;AAAA,EAGzB,YACQ,QACP,WACC;AAFM;AAGP,SAAK,4BAA4B,OAAO,YAAY;AAAA,MACnD;AAAA,MACA,CAAC,MAAM,SAAS;AACf,YAAI,KAAK,cAAc,KAAK,WAAW;AACtC,eAAK,qBAAqB;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAEA,UAAM,oBAAoB,OAAO,iBAAiB,EAAE;AACpD,QAAI,cAAc,mBAAmB;AACpC,aAAO,oBAAoB,EAAE,WAAW,CAAC,CAAC,UAAU,CAAC;AAAA,IACtD;AACA,SAAK,qBAAqB;AAE1B,aAAS,KAAK,iBAAiB,WAAW,KAAK,cAAc,KAAK,IAAI,CAAC;AACvE,aAAS,KAAK,iBAAiB,aAAa,KAAK,gBAAgB,KAAK,IAAI,CAAC;AAAA,EAC5E;AAAA,EAvBQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkCA,uBAAuB;AAC9B,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,gBAAgB,KAAK,OAAO,iBAAiB;AAEnD,QAAI,cAAc,WAAW;AAC5B,gBAAU,UAAU,IAAI,uBAAuB;AAAA,IAChD,OAAO;AACN,gBAAU,UAAU,OAAO,uBAAuB;AAAA,IACnD;AACA,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEQ,cAAc,UAAyB;AAC9C,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,WAAW,SAAS;AAG1B,QAAI,KAAK,OAAO,KAAK,sBAAsB,KAAK,CAAC,UAAU,QAAQ,0BAA0B;AAC5F;AACD,QAAI,aAAa,aAAa,KAAK,OAAO,oBAAoB,EAAE,SAAS,EAAG;AAC5E,QAAI,CAAC,OAAO,WAAW,WAAW,EAAE,SAAS,SAAS,GAAG,GAAG;AAC3D,gBAAU,UAAU,OAAO,6BAA6B;AAAA,IACzD;AAAA,EACD;AAAA,EAEQ,kBAAkB;AACzB,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEA,QAAQ;AACP,SAAK,OAAO,aAAa,EAAE,MAAM;AAAA,EAClC;AAAA,EAEA,OAAO;AACN,SAAK,OAAO,SAAS;AACrB,SAAK,OAAO,aAAa,EAAE,KAAK;AAAA,EACjC;AAAA,EAEA,UAAU;AACT,aAAS,KAAK,oBAAoB,WAAW,KAAK,cAAc,KAAK,IAAI,CAAC;AAC1E,aAAS,KAAK,oBAAoB,aAAa,KAAK,gBAAgB,KAAK,IAAI,CAAC;AAC9E,SAAK,4BAA4B;AAAA,EAClC;AACD;",
4
+ "sourcesContent": ["import { bind } from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\n\n/**\n * A manager for ensuring correct focus across the editor.\n * It will listen for changes in the instance state to make sure the\n * container is focused when the editor is focused.\n * Also, it will make sure that the focus is on things like text\n * labels when the editor is in editing mode.\n *\n * @internal\n */\nexport class FocusManager {\n\tprivate disposeSideEffectListener?: () => void\n\n\tconstructor(\n\t\tpublic editor: Editor,\n\t\tautoFocus?: boolean\n\t) {\n\t\tthis.disposeSideEffectListener = editor.sideEffects.registerAfterChangeHandler(\n\t\t\t'instance',\n\t\t\t(prev, next) => {\n\t\t\t\tif (prev.isFocused !== next.isFocused) {\n\t\t\t\t\tthis.updateContainerClass()\n\t\t\t\t}\n\t\t\t}\n\t\t)\n\n\t\tconst currentFocusState = editor.getInstanceState().isFocused\n\t\tif (autoFocus !== currentFocusState) {\n\t\t\teditor.updateInstanceState({ isFocused: !!autoFocus })\n\t\t}\n\t\tthis.updateContainerClass()\n\n\t\tconst body = editor.getContainerDocument().body\n\t\tbody.addEventListener('keydown', this.handleKeyDown)\n\t\tbody.addEventListener('mousedown', this.handleMouseDown)\n\t}\n\n\t/**\n\t * The editor's focus state and the container's focus state\n\t * are not necessarily always in sync. For that reason we\n\t * can't rely on the css `:focus` or `:focus-within` selectors to style the\n\t * editor when it is in focus.\n\t *\n\t * For that reason we synchronize the editor's focus state with a\n\t * special class on the container: tl-container__focused\n\t */\n\tprivate updateContainerClass() {\n\t\tconst container = this.editor.getContainer()\n\t\tconst instanceState = this.editor.getInstanceState()\n\n\t\tif (instanceState.isFocused) {\n\t\t\tcontainer.classList.add('tl-container__focused')\n\t\t} else {\n\t\t\tcontainer.classList.remove('tl-container__focused')\n\t\t}\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\t@bind private handleKeyDown(keyEvent: KeyboardEvent) {\n\t\tconst container = this.editor.getContainer()\n\t\tconst activeEl = container.ownerDocument.activeElement\n\t\t// Edit mode should remove the focus ring, however if the active element's\n\t\t// parent is the contextual toolbar, then allow it.\n\t\tif (this.editor.isIn('select.editing_shape') && !activeEl?.closest('.tlui-contextual-toolbar'))\n\t\t\treturn\n\t\tif (activeEl === container && this.editor.getSelectedShapeIds().length > 0) return\n\t\tif (['Tab', 'ArrowUp', 'ArrowDown'].includes(keyEvent.key)) {\n\t\t\tcontainer.classList.remove('tl-container__no-focus-ring')\n\t\t}\n\t}\n\n\t@bind private handleMouseDown() {\n\t\tconst container = this.editor.getContainer()\n\t\tcontainer.classList.add('tl-container__no-focus-ring')\n\t}\n\n\tfocus() {\n\t\tthis.editor.getContainer().focus()\n\t}\n\n\tblur() {\n\t\tthis.editor.complete() // stop any interaction\n\t\tthis.editor.getContainer().blur() // blur the container\n\t}\n\n\tdispose() {\n\t\tconst body = this.editor.getContainerDocument().body\n\t\tbody.removeEventListener('keydown', this.handleKeyDown)\n\t\tbody.removeEventListener('mousedown', this.handleMouseDown)\n\t\tthis.disposeSideEffectListener?.()\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAqB;AAArB;AA4DC,sBAAC,oBAaD,wBAAC;AA7DK,MAAM,aAAa;AAAA,EAGzB,YACQ,QACP,WACC;AAFM;AAJF;AACN,wBAAQ;AAMP,SAAK,4BAA4B,OAAO,YAAY;AAAA,MACnD;AAAA,MACA,CAAC,MAAM,SAAS;AACf,YAAI,KAAK,cAAc,KAAK,WAAW;AACtC,eAAK,qBAAqB;AAAA,QAC3B;AAAA,MACD;AAAA,IACD;AAEA,UAAM,oBAAoB,OAAO,iBAAiB,EAAE;AACpD,QAAI,cAAc,mBAAmB;AACpC,aAAO,oBAAoB,EAAE,WAAW,CAAC,CAAC,UAAU,CAAC;AAAA,IACtD;AACA,SAAK,qBAAqB;AAE1B,UAAM,OAAO,OAAO,qBAAqB,EAAE;AAC3C,SAAK,iBAAiB,WAAW,KAAK,aAAa;AACnD,SAAK,iBAAiB,aAAa,KAAK,eAAe;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,uBAAuB;AAC9B,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,gBAAgB,KAAK,OAAO,iBAAiB;AAEnD,QAAI,cAAc,WAAW;AAC5B,gBAAU,UAAU,IAAI,uBAAuB;AAAA,IAChD,OAAO;AACN,gBAAU,UAAU,OAAO,uBAAuB;AAAA,IACnD;AACA,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEc,cAAc,UAAyB;AACpD,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,WAAW,UAAU,cAAc;AAGzC,QAAI,KAAK,OAAO,KAAK,sBAAsB,KAAK,CAAC,UAAU,QAAQ,0BAA0B;AAC5F;AACD,QAAI,aAAa,aAAa,KAAK,OAAO,oBAAoB,EAAE,SAAS,EAAG;AAC5E,QAAI,CAAC,OAAO,WAAW,WAAW,EAAE,SAAS,SAAS,GAAG,GAAG;AAC3D,gBAAU,UAAU,OAAO,6BAA6B;AAAA,IACzD;AAAA,EACD;AAAA,EAEc,kBAAkB;AAC/B,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,cAAU,UAAU,IAAI,6BAA6B;AAAA,EACtD;AAAA,EAEA,QAAQ;AACP,SAAK,OAAO,aAAa,EAAE,MAAM;AAAA,EAClC;AAAA,EAEA,OAAO;AACN,SAAK,OAAO,SAAS;AACrB,SAAK,OAAO,aAAa,EAAE,KAAK;AAAA,EACjC;AAAA,EAEA,UAAU;AACT,UAAM,OAAO,KAAK,OAAO,qBAAqB,EAAE;AAChD,SAAK,oBAAoB,WAAW,KAAK,aAAa;AACtD,SAAK,oBAAoB,aAAa,KAAK,eAAe;AAC1D,SAAK,4BAA4B;AAAA,EAClC;AACD;AAjFO;AAgDA,4BAAQ,iBAAd,oBAhDY;AA6DN,4BAAQ,mBAAd,sBA7DY;AAAN,2BAAM;",
6
6
  "names": []
7
7
  }
@@ -88,7 +88,7 @@ class FontManager {
88
88
  state: "loading",
89
89
  instance,
90
90
  loadingPromise: instance.load().then(() => {
91
- document.fonts.add(instance);
91
+ this.editor.getContainerDocument().fonts.add(instance);
92
92
  this.fontStates.update(font, (s) => ({ ...s, state: "ready" }));
93
93
  }).catch((err) => {
94
94
  console.error(err);
@@ -117,7 +117,8 @@ class FontManager {
117
117
  }
118
118
  }
119
119
  findOrCreateFontFace(font) {
120
- for (const existing of document.fonts) {
120
+ const fonts = this.editor.getContainerDocument().fonts;
121
+ for (const existing of fonts) {
121
122
  if (existing.family === font.family && (0, import_utils.objectMapEntries)(defaultFontFaceDescriptors).every(
122
123
  ([key, defaultValue]) => existing[key] === (font[key] ?? defaultValue)
123
124
  )) {
@@ -129,7 +130,7 @@ class FontManager {
129
130
  ...(0, import_utils.mapObjectMapValues)(defaultFontFaceDescriptors, (key) => font[key]),
130
131
  display: "swap"
131
132
  });
132
- document.fonts.add(instance);
133
+ fonts.add(instance);
133
134
  return instance;
134
135
  }
135
136
  async toEmbeddedCssDeclaration(font) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/editor/managers/FontManager/FontManager.ts"],
4
- "sourcesContent": ["import { computed, EMPTY_ARRAY, transact } from '@tldraw/state'\nimport { AtomMap } from '@tldraw/store'\nimport { TLShape, TLShapeId } from '@tldraw/tlschema'\nimport {\n\tareArraysShallowEqual,\n\tcompact,\n\tFileHelpers,\n\tmapObjectMapValues,\n\tobjectMapEntries,\n} from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\n\n/**\n * Represents the `src` property of a {@link TLFontFace}.\n * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src | `src`} for details of the properties here.\n * @public\n */\nexport interface TLFontFaceSource {\n\t/**\n\t * A URL from which to load the font. If the value here is a key in\n\t * {@link tldraw#TLEditorAssetUrls.fonts}, the value from there will be used instead.\n\t */\n\turl: string\n\tformat?: string\n\ttech?: string\n}\n\n/**\n * A font face that can be used in the editor. The properties of this are largely the same as the\n * ones in the\n * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face | css `@font-face` rule}.\n * @public\n */\nexport interface TLFontFace {\n\t/**\n\t * How this font can be referred to in CSS.\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-family | `font-family`}.\n\t */\n\treadonly family: string\n\t/**\n\t * The source of the font. This\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src | `src`}.\n\t */\n\treadonly src: TLFontFaceSource\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/ascent-override | `ascent-override`}.\n\t */\n\treadonly ascentOverride?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/descent-override | `descent-override`}.\n\t */\n\treadonly descentOverride?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-stretch | `font-stretch`}.\n\t */\n\treadonly stretch?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-style | `font-style`}.\n\t */\n\treadonly style?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-weight | `font-weight`}.\n\t */\n\treadonly weight?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-feature-settings | `font-feature-settings`}.\n\t */\n\treadonly featureSettings?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/line-gap-override | `line-gap-override`}.\n\t */\n\treadonly lineGapOverride?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range | `unicode-range`}.\n\t */\n\treadonly unicodeRange?: string\n}\n\ninterface FontState {\n\treadonly state: 'loading' | 'ready' | 'error'\n\treadonly instance: FontFace\n\treadonly loadingPromise: Promise<void>\n}\n\n/** @public */\nexport class FontManager {\n\tconstructor(\n\t\tprivate readonly editor: Editor,\n\t\tprivate readonly assetUrls?: { [key: string]: string | undefined }\n\t) {\n\t\tthis.shapeFontFacesCache = editor.store.createComputedCache(\n\t\t\t'shape font faces',\n\t\t\t(shape: TLShape) => {\n\t\t\t\tconst shapeUtil = this.editor.getShapeUtil(shape)\n\t\t\t\treturn shapeUtil.getFontFaces(shape)\n\t\t\t},\n\t\t\t{\n\t\t\t\tareResultsEqual: areArraysShallowEqual,\n\t\t\t\tareRecordsEqual: (a, b) => a.props === b.props && a.meta === b.meta,\n\t\t\t}\n\t\t)\n\n\t\tthis.shapeFontLoadStateCache = editor.store.createCache<(FontState | null)[], TLShape>(\n\t\t\t(id: TLShapeId) => {\n\t\t\t\tconst fontFacesComputed = computed('font faces', () => this.getShapeFontFaces(id))\n\t\t\t\treturn computed(\n\t\t\t\t\t'font load state',\n\t\t\t\t\t() => {\n\t\t\t\t\t\tconst states = fontFacesComputed.get().map((face) => this.getFontState(face))\n\t\t\t\t\t\treturn states\n\t\t\t\t\t},\n\t\t\t\t\t{ isEqual: areArraysShallowEqual }\n\t\t\t\t)\n\t\t\t}\n\t\t)\n\t}\n\n\tprivate readonly shapeFontFacesCache\n\tprivate readonly shapeFontLoadStateCache\n\n\tgetShapeFontFaces(shape: TLShape | TLShapeId): TLFontFace[] {\n\t\tconst shapeId = typeof shape === 'string' ? shape : shape.id\n\t\treturn this.shapeFontFacesCache.get(shapeId) ?? EMPTY_ARRAY\n\t}\n\n\ttrackFontsForShape(shape: TLShape | TLShapeId) {\n\t\tconst shapeId = typeof shape === 'string' ? shape : shape.id\n\t\tthis.shapeFontLoadStateCache.get(shapeId)\n\t}\n\n\tasync loadRequiredFontsForCurrentPage(limit = Infinity) {\n\t\tconst neededFonts = new Set<TLFontFace>()\n\t\tfor (const shapeId of this.editor.getCurrentPageShapeIds()) {\n\t\t\tfor (const font of this.getShapeFontFaces(this.editor.getShape(shapeId)!)) {\n\t\t\t\tneededFonts.add(font)\n\t\t\t}\n\t\t}\n\n\t\tif (neededFonts.size > limit) {\n\t\t\treturn\n\t\t}\n\n\t\tconst promises = Array.from(neededFonts, (font) => this.ensureFontIsLoaded(font))\n\t\tawait Promise.all(promises)\n\t}\n\n\tprivate readonly fontStates = new AtomMap<TLFontFace, FontState>('font states')\n\tprivate getFontState(font: TLFontFace): FontState | null {\n\t\treturn this.fontStates.get(font) ?? null\n\t}\n\n\tensureFontIsLoaded(font: TLFontFace): Promise<void> {\n\t\tconst existingState = this.getFontState(font)\n\t\tif (existingState) return existingState.loadingPromise\n\n\t\tconst instance = this.findOrCreateFontFace(font)\n\t\tconst state: FontState = {\n\t\t\tstate: 'loading',\n\t\t\tinstance,\n\t\t\tloadingPromise: instance\n\t\t\t\t.load()\n\t\t\t\t.then(() => {\n\t\t\t\t\tdocument.fonts.add(instance)\n\t\t\t\t\tthis.fontStates.update(font, (s) => ({ ...s, state: 'ready' }))\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error(err)\n\t\t\t\t\tthis.fontStates.update(font, (s) => ({ ...s, state: 'error' }))\n\t\t\t\t}),\n\t\t}\n\n\t\tthis.fontStates.set(font, state)\n\t\treturn state.loadingPromise\n\t}\n\n\tprivate fontsToLoad = new Set<TLFontFace>()\n\trequestFonts(fonts: TLFontFace[]) {\n\t\tif (!this.fontsToLoad.size) {\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (this.editor.isDisposed) return\n\t\t\t\tconst toLoad = this.fontsToLoad\n\t\t\t\tthis.fontsToLoad = new Set()\n\t\t\t\ttransact(() => {\n\t\t\t\t\tfor (const font of toLoad) {\n\t\t\t\t\t\tthis.ensureFontIsLoaded(font)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t\tfor (const font of fonts) {\n\t\t\tthis.fontsToLoad.add(font)\n\t\t}\n\t}\n\n\tprivate findOrCreateFontFace(font: TLFontFace) {\n\t\tfor (const existing of document.fonts) {\n\t\t\tif (\n\t\t\t\texisting.family === font.family &&\n\t\t\t\tobjectMapEntries(defaultFontFaceDescriptors).every(\n\t\t\t\t\t([key, defaultValue]) => existing[key] === (font[key] ?? defaultValue)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn existing\n\t\t\t}\n\t\t}\n\n\t\tconst url = this.assetUrls?.[font.src.url] ?? font.src.url\n\t\tconst instance = new FontFace(font.family, `url(${JSON.stringify(url)})`, {\n\t\t\t...mapObjectMapValues(defaultFontFaceDescriptors, (key) => font[key]),\n\t\t\tdisplay: 'swap',\n\t\t})\n\n\t\tdocument.fonts.add(instance)\n\n\t\treturn instance\n\t}\n\n\tasync toEmbeddedCssDeclaration(font: TLFontFace) {\n\t\tconst url = this.assetUrls?.[font.src.url] ?? font.src.url\n\t\tconst dataUrl = await FileHelpers.urlToDataUrl(url)\n\n\t\tconst src = compact([\n\t\t\t`url(\"${dataUrl}\")`,\n\t\t\tfont.src.format ? `format(${font.src.format})` : null,\n\t\t\tfont.src.tech ? `tech(${font.src.tech})` : null,\n\t\t]).join(' ')\n\t\treturn compact([\n\t\t\t`@font-face {`,\n\t\t\t` font-family: \"${font.family}\";`,\n\t\t\tfont.ascentOverride ? ` ascent-override: ${font.ascentOverride};` : null,\n\t\t\tfont.descentOverride ? ` descent-override: ${font.descentOverride};` : null,\n\t\t\tfont.stretch ? ` font-stretch: ${font.stretch};` : null,\n\t\t\tfont.style ? ` font-style: ${font.style};` : null,\n\t\t\tfont.weight ? ` font-weight: ${font.weight};` : null,\n\t\t\tfont.featureSettings ? ` font-feature-settings: ${font.featureSettings};` : null,\n\t\t\tfont.lineGapOverride ? ` line-gap-override: ${font.lineGapOverride};` : null,\n\t\t\tfont.unicodeRange ? ` unicode-range: ${font.unicodeRange};` : null,\n\t\t\t` src: ${src};`,\n\t\t\t`}`,\n\t\t]).join('\\n')\n\t}\n}\n\n// From https://drafts.csswg.org/css-font-loading/#fontface-interface\nconst defaultFontFaceDescriptors = {\n\tstyle: 'normal',\n\tweight: 'normal',\n\tstretch: 'normal',\n\tunicodeRange: 'U+0-10FFFF',\n\tfeatureSettings: 'normal',\n\tascentOverride: 'normal',\n\tdescentOverride: 'normal',\n\tlineGapOverride: 'normal',\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { computed, EMPTY_ARRAY, transact } from '@tldraw/state'\nimport { AtomMap } from '@tldraw/store'\nimport { TLShape, TLShapeId } from '@tldraw/tlschema'\nimport {\n\tareArraysShallowEqual,\n\tcompact,\n\tFileHelpers,\n\tmapObjectMapValues,\n\tobjectMapEntries,\n} from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\n\n/**\n * Represents the `src` property of a {@link TLFontFace}.\n * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src | `src`} for details of the properties here.\n * @public\n */\nexport interface TLFontFaceSource {\n\t/**\n\t * A URL from which to load the font. If the value here is a key in\n\t * {@link tldraw#TLEditorAssetUrls.fonts}, the value from there will be used instead.\n\t */\n\turl: string\n\tformat?: string\n\ttech?: string\n}\n\n/**\n * A font face that can be used in the editor. The properties of this are largely the same as the\n * ones in the\n * {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face | css `@font-face` rule}.\n * @public\n */\nexport interface TLFontFace {\n\t/**\n\t * How this font can be referred to in CSS.\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-family | `font-family`}.\n\t */\n\treadonly family: string\n\t/**\n\t * The source of the font. This\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src | `src`}.\n\t */\n\treadonly src: TLFontFaceSource\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/ascent-override | `ascent-override`}.\n\t */\n\treadonly ascentOverride?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/descent-override | `descent-override`}.\n\t */\n\treadonly descentOverride?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-stretch | `font-stretch`}.\n\t */\n\treadonly stretch?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-style | `font-style`}.\n\t */\n\treadonly style?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-weight | `font-weight`}.\n\t */\n\treadonly weight?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/font-feature-settings | `font-feature-settings`}.\n\t */\n\treadonly featureSettings?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/line-gap-override | `line-gap-override`}.\n\t */\n\treadonly lineGapOverride?: string\n\t/**\n\t * See {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/unicode-range | `unicode-range`}.\n\t */\n\treadonly unicodeRange?: string\n}\n\ninterface FontState {\n\treadonly state: 'loading' | 'ready' | 'error'\n\treadonly instance: FontFace\n\treadonly loadingPromise: Promise<void>\n}\n\n/** @public */\nexport class FontManager {\n\tconstructor(\n\t\tprivate readonly editor: Editor,\n\t\tprivate readonly assetUrls?: { [key: string]: string | undefined }\n\t) {\n\t\tthis.shapeFontFacesCache = editor.store.createComputedCache(\n\t\t\t'shape font faces',\n\t\t\t(shape: TLShape) => {\n\t\t\t\tconst shapeUtil = this.editor.getShapeUtil(shape)\n\t\t\t\treturn shapeUtil.getFontFaces(shape)\n\t\t\t},\n\t\t\t{\n\t\t\t\tareResultsEqual: areArraysShallowEqual,\n\t\t\t\tareRecordsEqual: (a, b) => a.props === b.props && a.meta === b.meta,\n\t\t\t}\n\t\t)\n\n\t\tthis.shapeFontLoadStateCache = editor.store.createCache<(FontState | null)[], TLShape>(\n\t\t\t(id: TLShapeId) => {\n\t\t\t\tconst fontFacesComputed = computed('font faces', () => this.getShapeFontFaces(id))\n\t\t\t\treturn computed(\n\t\t\t\t\t'font load state',\n\t\t\t\t\t() => {\n\t\t\t\t\t\tconst states = fontFacesComputed.get().map((face) => this.getFontState(face))\n\t\t\t\t\t\treturn states\n\t\t\t\t\t},\n\t\t\t\t\t{ isEqual: areArraysShallowEqual }\n\t\t\t\t)\n\t\t\t}\n\t\t)\n\t}\n\n\tprivate readonly shapeFontFacesCache\n\tprivate readonly shapeFontLoadStateCache\n\n\tgetShapeFontFaces(shape: TLShape | TLShapeId): TLFontFace[] {\n\t\tconst shapeId = typeof shape === 'string' ? shape : shape.id\n\t\treturn this.shapeFontFacesCache.get(shapeId) ?? EMPTY_ARRAY\n\t}\n\n\ttrackFontsForShape(shape: TLShape | TLShapeId) {\n\t\tconst shapeId = typeof shape === 'string' ? shape : shape.id\n\t\tthis.shapeFontLoadStateCache.get(shapeId)\n\t}\n\n\tasync loadRequiredFontsForCurrentPage(limit = Infinity) {\n\t\tconst neededFonts = new Set<TLFontFace>()\n\t\tfor (const shapeId of this.editor.getCurrentPageShapeIds()) {\n\t\t\tfor (const font of this.getShapeFontFaces(this.editor.getShape(shapeId)!)) {\n\t\t\t\tneededFonts.add(font)\n\t\t\t}\n\t\t}\n\n\t\tif (neededFonts.size > limit) {\n\t\t\treturn\n\t\t}\n\n\t\tconst promises = Array.from(neededFonts, (font) => this.ensureFontIsLoaded(font))\n\t\tawait Promise.all(promises)\n\t}\n\n\tprivate readonly fontStates = new AtomMap<TLFontFace, FontState>('font states')\n\tprivate getFontState(font: TLFontFace): FontState | null {\n\t\treturn this.fontStates.get(font) ?? null\n\t}\n\n\tensureFontIsLoaded(font: TLFontFace): Promise<void> {\n\t\tconst existingState = this.getFontState(font)\n\t\tif (existingState) return existingState.loadingPromise\n\n\t\tconst instance = this.findOrCreateFontFace(font)\n\t\tconst state: FontState = {\n\t\t\tstate: 'loading',\n\t\t\tinstance,\n\t\t\tloadingPromise: instance\n\t\t\t\t.load()\n\t\t\t\t.then(() => {\n\t\t\t\t\tthis.editor.getContainerDocument().fonts.add(instance)\n\t\t\t\t\tthis.fontStates.update(font, (s) => ({ ...s, state: 'ready' }))\n\t\t\t\t})\n\t\t\t\t.catch((err) => {\n\t\t\t\t\tconsole.error(err)\n\t\t\t\t\tthis.fontStates.update(font, (s) => ({ ...s, state: 'error' }))\n\t\t\t\t}),\n\t\t}\n\n\t\tthis.fontStates.set(font, state)\n\t\treturn state.loadingPromise\n\t}\n\n\tprivate fontsToLoad = new Set<TLFontFace>()\n\trequestFonts(fonts: TLFontFace[]) {\n\t\tif (!this.fontsToLoad.size) {\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (this.editor.isDisposed) return\n\t\t\t\tconst toLoad = this.fontsToLoad\n\t\t\t\tthis.fontsToLoad = new Set()\n\t\t\t\ttransact(() => {\n\t\t\t\t\tfor (const font of toLoad) {\n\t\t\t\t\t\tthis.ensureFontIsLoaded(font)\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\t\tfor (const font of fonts) {\n\t\t\tthis.fontsToLoad.add(font)\n\t\t}\n\t}\n\n\tprivate findOrCreateFontFace(font: TLFontFace) {\n\t\tconst fonts = this.editor.getContainerDocument().fonts\n\t\tfor (const existing of fonts) {\n\t\t\tif (\n\t\t\t\texisting.family === font.family &&\n\t\t\t\tobjectMapEntries(defaultFontFaceDescriptors).every(\n\t\t\t\t\t([key, defaultValue]) => existing[key] === (font[key] ?? defaultValue)\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\treturn existing\n\t\t\t}\n\t\t}\n\n\t\tconst url = this.assetUrls?.[font.src.url] ?? font.src.url\n\t\tconst instance = new FontFace(font.family, `url(${JSON.stringify(url)})`, {\n\t\t\t...mapObjectMapValues(defaultFontFaceDescriptors, (key) => font[key]),\n\t\t\tdisplay: 'swap',\n\t\t})\n\n\t\tfonts.add(instance)\n\n\t\treturn instance\n\t}\n\n\tasync toEmbeddedCssDeclaration(font: TLFontFace) {\n\t\tconst url = this.assetUrls?.[font.src.url] ?? font.src.url\n\t\tconst dataUrl = await FileHelpers.urlToDataUrl(url)\n\n\t\tconst src = compact([\n\t\t\t`url(\"${dataUrl}\")`,\n\t\t\tfont.src.format ? `format(${font.src.format})` : null,\n\t\t\tfont.src.tech ? `tech(${font.src.tech})` : null,\n\t\t]).join(' ')\n\t\treturn compact([\n\t\t\t`@font-face {`,\n\t\t\t` font-family: \"${font.family}\";`,\n\t\t\tfont.ascentOverride ? ` ascent-override: ${font.ascentOverride};` : null,\n\t\t\tfont.descentOverride ? ` descent-override: ${font.descentOverride};` : null,\n\t\t\tfont.stretch ? ` font-stretch: ${font.stretch};` : null,\n\t\t\tfont.style ? ` font-style: ${font.style};` : null,\n\t\t\tfont.weight ? ` font-weight: ${font.weight};` : null,\n\t\t\tfont.featureSettings ? ` font-feature-settings: ${font.featureSettings};` : null,\n\t\t\tfont.lineGapOverride ? ` line-gap-override: ${font.lineGapOverride};` : null,\n\t\t\tfont.unicodeRange ? ` unicode-range: ${font.unicodeRange};` : null,\n\t\t\t` src: ${src};`,\n\t\t\t`}`,\n\t\t]).join('\\n')\n\t}\n}\n\n// From https://drafts.csswg.org/css-font-loading/#fontface-interface\nconst defaultFontFaceDescriptors = {\n\tstyle: 'normal',\n\tweight: 'normal',\n\tstretch: 'normal',\n\tunicodeRange: 'U+0-10FFFF',\n\tfeatureSettings: 'normal',\n\tascentOverride: 'normal',\n\tdescentOverride: 'normal',\n\tlineGapOverride: 'normal',\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -155,6 +155,7 @@ class HistoryManager {
155
155
  }
156
156
  }
157
157
  if (!didFindMark && toMark) {
158
+ this.pendingDiff.restore(pendingDiff);
158
159
  return this;
159
160
  }
160
161
  this.store.applyDiff(diffToUndo, { ignoreEphemeralKeys: true });
@@ -285,6 +286,10 @@ class PendingDiff {
285
286
  this.isEmptyAtom.set(true);
286
287
  return diff;
287
288
  }
289
+ restore(diff) {
290
+ this.diff = diff;
291
+ this.isEmptyAtom.set((0, import_store.isRecordsDiffEmpty)(diff));
292
+ }
288
293
  isEmpty() {
289
294
  return this.isEmptyAtom.get();
290
295
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/editor/managers/HistoryManager/HistoryManager.ts"],
4
- "sourcesContent": ["import { atom, EMPTY_ARRAY, transact } from '@tldraw/state'\nimport {\n\tcreateEmptyRecordsDiff,\n\tisRecordsDiffEmpty,\n\tRecordsDiff,\n\treverseRecordsDiff,\n\tsquashRecordDiffsMutable,\n\tStore,\n\tUnknownRecord,\n} from '@tldraw/store'\nimport { exhaustiveSwitchError, noop } from '@tldraw/utils'\nimport { TLHistoryBatchOptions, TLHistoryEntry } from '../../types/history-types'\n\nconst HistoryRecorderState = {\n\tRecording: 'recording',\n\tRecordingPreserveRedoStack: 'recordingPreserveRedoStack',\n\tPaused: 'paused',\n} as const\ntype HistoryRecorderState = (typeof HistoryRecorderState)[keyof typeof HistoryRecorderState]\n\n/** @public */\nexport class HistoryManager<R extends UnknownRecord> {\n\tprivate readonly store: Store<R>\n\n\treadonly dispose: () => void\n\n\tprivate state: HistoryRecorderState = HistoryRecorderState.Recording\n\tprivate readonly pendingDiff = new PendingDiff<R>()\n\tprivate stacks = atom(\n\t\t'HistoryManager.stacks',\n\t\t{\n\t\t\tundos: stack<TLHistoryEntry<R>>(),\n\t\t\tredos: stack<TLHistoryEntry<R>>(),\n\t\t},\n\t\t{\n\t\t\tisEqual: (a, b) => a.undos === b.undos && a.redos === b.redos,\n\t\t}\n\t)\n\n\tprivate readonly annotateError: (error: unknown) => void\n\n\tconstructor(opts: { store: Store<R>; annotateError?(error: unknown): void }) {\n\t\tthis.store = opts.store\n\t\tthis.annotateError = opts.annotateError ?? noop\n\t\tthis.dispose = this.store.addHistoryInterceptor((entry, source) => {\n\t\t\tif (source !== 'user') return\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase HistoryRecorderState.Recording:\n\t\t\t\t\tthis.pendingDiff.apply(entry.changes)\n\t\t\t\t\tthis.stacks.update(({ undos }) => ({ undos, redos: stack() }))\n\t\t\t\t\tbreak\n\t\t\t\tcase HistoryRecorderState.RecordingPreserveRedoStack:\n\t\t\t\t\tthis.pendingDiff.apply(entry.changes)\n\t\t\t\t\tbreak\n\t\t\t\tcase HistoryRecorderState.Paused:\n\t\t\t\t\tbreak\n\t\t\t\tdefault:\n\t\t\t\t\texhaustiveSwitchError(this.state)\n\t\t\t}\n\t\t})\n\t}\n\n\tprivate flushPendingDiff() {\n\t\tif (this.pendingDiff.isEmpty()) return\n\n\t\tconst diff = this.pendingDiff.clear()\n\t\tthis.stacks.update(({ undos, redos }) => ({\n\t\t\tundos: undos.push({ type: 'diff', diff }),\n\t\t\tredos,\n\t\t}))\n\t}\n\n\tgetNumUndos() {\n\t\treturn this.stacks.get().undos.length + (this.pendingDiff.isEmpty() ? 0 : 1)\n\t}\n\n\tgetNumRedos() {\n\t\treturn this.stacks.get().redos.length\n\t}\n\n\t/** @internal */\n\t_isInBatch = false\n\n\tbatch(fn: () => void, opts?: TLHistoryBatchOptions) {\n\t\tconst previousState = this.state\n\n\t\t// we move to the new state only if we haven't explicitly paused\n\t\tif (previousState !== HistoryRecorderState.Paused && opts?.history) {\n\t\t\tthis.state = modeToState[opts.history]\n\t\t}\n\n\t\ttry {\n\t\t\tif (this._isInBatch) {\n\t\t\t\ttransact(fn)\n\t\t\t\treturn this\n\t\t\t}\n\n\t\t\tthis._isInBatch = true\n\t\t\ttry {\n\t\t\t\ttransact(fn)\n\t\t\t} catch (error) {\n\t\t\t\tthis.annotateError(error)\n\t\t\t\tthrow error\n\t\t\t} finally {\n\t\t\t\tthis._isInBatch = false\n\t\t\t}\n\n\t\t\treturn this\n\t\t} finally {\n\t\t\tthis.state = previousState\n\t\t}\n\t}\n\n\t// History\n\t_undo({ pushToRedoStack, toMark = undefined }: { pushToRedoStack: boolean; toMark?: string }) {\n\t\tconst previousState = this.state\n\t\tthis.state = HistoryRecorderState.Paused\n\t\ttry {\n\t\t\tlet { undos, redos } = this.stacks.get()\n\n\t\t\t// start by collecting the pending diff (everything since the last mark).\n\t\t\t// we'll accumulate the diff to undo in this variable so we can apply it atomically.\n\t\t\tconst pendingDiff = this.pendingDiff.clear()\n\t\t\tconst isPendingDiffEmpty = isRecordsDiffEmpty(pendingDiff)\n\t\t\tconst diffToUndo = reverseRecordsDiff(pendingDiff)\n\n\t\t\tif (pushToRedoStack && !isPendingDiffEmpty) {\n\t\t\t\tredos = redos.push({ type: 'diff', diff: pendingDiff })\n\t\t\t}\n\n\t\t\tlet didFindMark = false\n\t\t\tif (isPendingDiffEmpty) {\n\t\t\t\t// if nothing has happened since the last mark, pop any intermediate marks off the stack\n\t\t\t\twhile (undos.head?.type === 'stop') {\n\t\t\t\t\tconst mark = undos.head\n\t\t\t\t\tundos = undos.tail\n\t\t\t\t\tif (pushToRedoStack) {\n\t\t\t\t\t\tredos = redos.push(mark)\n\t\t\t\t\t}\n\t\t\t\t\tif (mark.id === toMark) {\n\t\t\t\t\t\tdidFindMark = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!didFindMark) {\n\t\t\t\tloop: while (undos.head) {\n\t\t\t\t\tconst undo = undos.head\n\t\t\t\t\tundos = undos.tail\n\n\t\t\t\t\tif (pushToRedoStack) {\n\t\t\t\t\t\tredos = redos.push(undo)\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (undo.type) {\n\t\t\t\t\t\tcase 'diff':\n\t\t\t\t\t\t\tsquashRecordDiffsMutable(diffToUndo, [reverseRecordsDiff(undo.diff)])\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\t\tif (!toMark) break loop\n\t\t\t\t\t\t\tif (undo.id === toMark) {\n\t\t\t\t\t\t\t\tdidFindMark = true\n\t\t\t\t\t\t\t\tbreak loop\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\texhaustiveSwitchError(undo)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!didFindMark && toMark) {\n\t\t\t\t// whoops, we didn't find the mark we were looking for\n\t\t\t\t// don't do anything\n\t\t\t\treturn this\n\t\t\t}\n\n\t\t\tthis.store.applyDiff(diffToUndo, { ignoreEphemeralKeys: true })\n\t\t\tthis.store.ensureStoreIsUsable()\n\t\t\tthis.stacks.set({ undos, redos })\n\t\t} finally {\n\t\t\tthis.state = previousState\n\t\t}\n\n\t\treturn this\n\t}\n\n\tundo() {\n\t\tthis._undo({ pushToRedoStack: true })\n\n\t\treturn this\n\t}\n\n\tredo() {\n\t\tconst previousState = this.state\n\t\tthis.state = HistoryRecorderState.Paused\n\t\ttry {\n\t\t\tthis.flushPendingDiff()\n\n\t\t\tlet { undos, redos } = this.stacks.get()\n\t\t\tif (redos.length === 0) {\n\t\t\t\treturn this\n\t\t\t}\n\n\t\t\t// ignore any intermediate marks - this should take us to the first `diff` entry\n\t\t\twhile (redos.head?.type === 'stop') {\n\t\t\t\tundos = undos.push(redos.head)\n\t\t\t\tredos = redos.tail\n\t\t\t}\n\n\t\t\t// accumulate diffs to be redone so they can be applied atomically\n\t\t\tconst diffToRedo = createEmptyRecordsDiff<R>()\n\n\t\t\twhile (redos.head) {\n\t\t\t\tconst redo = redos.head\n\t\t\t\tundos = undos.push(redo)\n\t\t\t\tredos = redos.tail\n\n\t\t\t\tif (redo.type === 'diff') {\n\t\t\t\t\tsquashRecordDiffsMutable(diffToRedo, [redo.diff])\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.store.applyDiff(diffToRedo, { ignoreEphemeralKeys: true })\n\t\t\tthis.store.ensureStoreIsUsable()\n\t\t\tthis.stacks.set({ undos, redos })\n\t\t} finally {\n\t\t\tthis.state = previousState\n\t\t}\n\n\t\treturn this\n\t}\n\n\tbail() {\n\t\tthis._undo({ pushToRedoStack: false })\n\n\t\treturn this\n\t}\n\n\tbailToMark(id: string) {\n\t\tif (id) {\n\t\t\tthis._undo({ pushToRedoStack: false, toMark: id })\n\t\t}\n\n\t\treturn this\n\t}\n\n\tsquashToMark(id: string) {\n\t\t// remove marks between head and the mark\n\n\t\tlet top = this.stacks.get().undos\n\t\tconst popped: Array<RecordsDiff<R>> = []\n\n\t\twhile (top.head && !(top.head.type === 'stop' && top.head.id === id)) {\n\t\t\tif (top.head.type === 'diff') {\n\t\t\t\tpopped.push(top.head.diff)\n\t\t\t}\n\t\t\ttop = top.tail\n\t\t}\n\n\t\tif (!top.head || top.head?.id !== id) {\n\t\t\tconsole.error('Could not find mark to squash to: ', id)\n\t\t\treturn this\n\t\t}\n\t\tif (popped.length === 0) {\n\t\t\treturn this\n\t\t}\n\n\t\tconst diff = createEmptyRecordsDiff<R>()\n\t\tsquashRecordDiffsMutable(diff, popped.reverse())\n\n\t\tthis.stacks.update(({ redos }) => ({\n\t\t\tundos: top.push({\n\t\t\t\ttype: 'diff',\n\t\t\t\tdiff,\n\t\t\t}),\n\t\t\tredos,\n\t\t}))\n\n\t\treturn this\n\t}\n\n\t/** @internal */\n\t_mark(id: string) {\n\t\ttransact(() => {\n\t\t\tthis.flushPendingDiff()\n\t\t\tthis.stacks.update(({ undos, redos }) => ({ undos: undos.push({ type: 'stop', id }), redos }))\n\t\t})\n\t}\n\n\tclear() {\n\t\tthis.stacks.set({ undos: stack(), redos: stack() })\n\t\tthis.pendingDiff.clear()\n\t}\n\n\t/** @internal */\n\tgetMarkIdMatching(idSubstring: string) {\n\t\tlet top = this.stacks.get().undos\n\t\twhile (top.head) {\n\t\t\tif (top.head.type === 'stop' && top.head.id.includes(idSubstring)) {\n\t\t\t\treturn top.head.id\n\t\t\t}\n\t\t\ttop = top.tail\n\t\t}\n\t\treturn null\n\t}\n\n\t/** @internal */\n\tdebug() {\n\t\tconst { undos, redos } = this.stacks.get()\n\t\treturn {\n\t\t\tundos: stackToArray(undos),\n\t\t\tredos: stackToArray(redos),\n\t\t\tpendingDiff: this.pendingDiff.debug(),\n\t\t\tstate: this.state as string,\n\t\t}\n\t}\n}\n\nconst modeToState = {\n\trecord: HistoryRecorderState.Recording,\n\t'record-preserveRedoStack': HistoryRecorderState.RecordingPreserveRedoStack,\n\tignore: HistoryRecorderState.Paused,\n} as const\n\nclass PendingDiff<R extends UnknownRecord> {\n\tprivate diff = createEmptyRecordsDiff<R>()\n\tprivate isEmptyAtom = atom('PendingDiff.isEmpty', true)\n\n\tclear() {\n\t\tconst diff = this.diff\n\t\tthis.diff = createEmptyRecordsDiff<R>()\n\t\tthis.isEmptyAtom.set(true)\n\t\treturn diff\n\t}\n\n\tisEmpty() {\n\t\treturn this.isEmptyAtom.get()\n\t}\n\n\tapply(diff: RecordsDiff<R>) {\n\t\tsquashRecordDiffsMutable(this.diff, [diff])\n\t\tthis.isEmptyAtom.set(isRecordsDiffEmpty(this.diff))\n\t}\n\n\tdebug() {\n\t\treturn { diff: this.diff, isEmpty: this.isEmpty() }\n\t}\n}\n\ntype Stack<T> = StackItem<T> | EmptyStackItem<T>\n\nfunction stack<T>(): Stack<T> {\n\treturn EMPTY_STACK_ITEM as any\n}\n\nclass EmptyStackItem<T> {\n\treadonly length = 0\n\treadonly head = null\n\treadonly tail: Stack<T> = this\n\n\tpush(head: T): Stack<T> {\n\t\treturn new StackItem<T>(head, this)\n\t}\n}\n\nconst EMPTY_STACK_ITEM = new EmptyStackItem()\n\nclass StackItem<T> {\n\tlength: number\n\tconstructor(\n\t\tpublic readonly head: T,\n\t\tpublic readonly tail: Stack<T>\n\t) {\n\t\tthis.length = tail.length + 1\n\t}\n\n\tpush(head: T): Stack<T> {\n\t\treturn new StackItem(head, this)\n\t}\n}\n\nfunction stackToArray<T>(stack: Stack<T>) {\n\tif (!stack.length) {\n\t\treturn EMPTY_ARRAY\n\t}\n\tconst arr: T[] = []\n\twhile (stack.length) {\n\t\tarr.push(stack.head!)\n\t\tstack = stack.tail\n\t}\n\treturn arr\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { atom, EMPTY_ARRAY, transact } from '@tldraw/state'\nimport {\n\tcreateEmptyRecordsDiff,\n\tisRecordsDiffEmpty,\n\tRecordsDiff,\n\treverseRecordsDiff,\n\tsquashRecordDiffsMutable,\n\tStore,\n\tUnknownRecord,\n} from '@tldraw/store'\nimport { exhaustiveSwitchError, noop } from '@tldraw/utils'\nimport { TLHistoryBatchOptions, TLHistoryEntry } from '../../types/history-types'\n\nconst HistoryRecorderState = {\n\tRecording: 'recording',\n\tRecordingPreserveRedoStack: 'recordingPreserveRedoStack',\n\tPaused: 'paused',\n} as const\ntype HistoryRecorderState = (typeof HistoryRecorderState)[keyof typeof HistoryRecorderState]\n\n/** @public */\nexport class HistoryManager<R extends UnknownRecord> {\n\tprivate readonly store: Store<R>\n\n\treadonly dispose: () => void\n\n\tprivate state: HistoryRecorderState = HistoryRecorderState.Recording\n\tprivate readonly pendingDiff = new PendingDiff<R>()\n\tprivate stacks = atom(\n\t\t'HistoryManager.stacks',\n\t\t{\n\t\t\tundos: stack<TLHistoryEntry<R>>(),\n\t\t\tredos: stack<TLHistoryEntry<R>>(),\n\t\t},\n\t\t{\n\t\t\tisEqual: (a, b) => a.undos === b.undos && a.redos === b.redos,\n\t\t}\n\t)\n\n\tprivate readonly annotateError: (error: unknown) => void\n\n\tconstructor(opts: { store: Store<R>; annotateError?(error: unknown): void }) {\n\t\tthis.store = opts.store\n\t\tthis.annotateError = opts.annotateError ?? noop\n\t\tthis.dispose = this.store.addHistoryInterceptor((entry, source) => {\n\t\t\tif (source !== 'user') return\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase HistoryRecorderState.Recording:\n\t\t\t\t\tthis.pendingDiff.apply(entry.changes)\n\t\t\t\t\tthis.stacks.update(({ undos }) => ({ undos, redos: stack() }))\n\t\t\t\t\tbreak\n\t\t\t\tcase HistoryRecorderState.RecordingPreserveRedoStack:\n\t\t\t\t\tthis.pendingDiff.apply(entry.changes)\n\t\t\t\t\tbreak\n\t\t\t\tcase HistoryRecorderState.Paused:\n\t\t\t\t\tbreak\n\t\t\t\tdefault:\n\t\t\t\t\texhaustiveSwitchError(this.state)\n\t\t\t}\n\t\t})\n\t}\n\n\tprivate flushPendingDiff() {\n\t\tif (this.pendingDiff.isEmpty()) return\n\n\t\tconst diff = this.pendingDiff.clear()\n\t\tthis.stacks.update(({ undos, redos }) => ({\n\t\t\tundos: undos.push({ type: 'diff', diff }),\n\t\t\tredos,\n\t\t}))\n\t}\n\n\tgetNumUndos() {\n\t\treturn this.stacks.get().undos.length + (this.pendingDiff.isEmpty() ? 0 : 1)\n\t}\n\n\tgetNumRedos() {\n\t\treturn this.stacks.get().redos.length\n\t}\n\n\t/** @internal */\n\t_isInBatch = false\n\n\tbatch(fn: () => void, opts?: TLHistoryBatchOptions) {\n\t\tconst previousState = this.state\n\n\t\t// we move to the new state only if we haven't explicitly paused\n\t\tif (previousState !== HistoryRecorderState.Paused && opts?.history) {\n\t\t\tthis.state = modeToState[opts.history]\n\t\t}\n\n\t\ttry {\n\t\t\tif (this._isInBatch) {\n\t\t\t\ttransact(fn)\n\t\t\t\treturn this\n\t\t\t}\n\n\t\t\tthis._isInBatch = true\n\t\t\ttry {\n\t\t\t\ttransact(fn)\n\t\t\t} catch (error) {\n\t\t\t\tthis.annotateError(error)\n\t\t\t\tthrow error\n\t\t\t} finally {\n\t\t\t\tthis._isInBatch = false\n\t\t\t}\n\n\t\t\treturn this\n\t\t} finally {\n\t\t\tthis.state = previousState\n\t\t}\n\t}\n\n\t// History\n\t_undo({ pushToRedoStack, toMark = undefined }: { pushToRedoStack: boolean; toMark?: string }) {\n\t\tconst previousState = this.state\n\t\tthis.state = HistoryRecorderState.Paused\n\t\ttry {\n\t\t\tlet { undos, redos } = this.stacks.get()\n\n\t\t\t// start by collecting the pending diff (everything since the last mark).\n\t\t\t// we'll accumulate the diff to undo in this variable so we can apply it atomically.\n\t\t\tconst pendingDiff = this.pendingDiff.clear()\n\t\t\tconst isPendingDiffEmpty = isRecordsDiffEmpty(pendingDiff)\n\t\t\tconst diffToUndo = reverseRecordsDiff(pendingDiff)\n\n\t\t\tif (pushToRedoStack && !isPendingDiffEmpty) {\n\t\t\t\tredos = redos.push({ type: 'diff', diff: pendingDiff })\n\t\t\t}\n\n\t\t\tlet didFindMark = false\n\t\t\tif (isPendingDiffEmpty) {\n\t\t\t\t// if nothing has happened since the last mark, pop any intermediate marks off the stack\n\t\t\t\twhile (undos.head?.type === 'stop') {\n\t\t\t\t\tconst mark = undos.head\n\t\t\t\t\tundos = undos.tail\n\t\t\t\t\tif (pushToRedoStack) {\n\t\t\t\t\t\tredos = redos.push(mark)\n\t\t\t\t\t}\n\t\t\t\t\tif (mark.id === toMark) {\n\t\t\t\t\t\tdidFindMark = true\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!didFindMark) {\n\t\t\t\tloop: while (undos.head) {\n\t\t\t\t\tconst undo = undos.head\n\t\t\t\t\tundos = undos.tail\n\n\t\t\t\t\tif (pushToRedoStack) {\n\t\t\t\t\t\tredos = redos.push(undo)\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (undo.type) {\n\t\t\t\t\t\tcase 'diff':\n\t\t\t\t\t\t\tsquashRecordDiffsMutable(diffToUndo, [reverseRecordsDiff(undo.diff)])\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tcase 'stop':\n\t\t\t\t\t\t\tif (!toMark) break loop\n\t\t\t\t\t\t\tif (undo.id === toMark) {\n\t\t\t\t\t\t\t\tdidFindMark = true\n\t\t\t\t\t\t\t\tbreak loop\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\texhaustiveSwitchError(undo)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!didFindMark && toMark) {\n\t\t\t\t// we didn't find the mark we were looking for \u2014 restore state and bail\n\t\t\t\tthis.pendingDiff.restore(pendingDiff)\n\t\t\t\treturn this\n\t\t\t}\n\n\t\t\tthis.store.applyDiff(diffToUndo, { ignoreEphemeralKeys: true })\n\t\t\tthis.store.ensureStoreIsUsable()\n\t\t\tthis.stacks.set({ undos, redos })\n\t\t} finally {\n\t\t\tthis.state = previousState\n\t\t}\n\n\t\treturn this\n\t}\n\n\tundo() {\n\t\tthis._undo({ pushToRedoStack: true })\n\n\t\treturn this\n\t}\n\n\tredo() {\n\t\tconst previousState = this.state\n\t\tthis.state = HistoryRecorderState.Paused\n\t\ttry {\n\t\t\tthis.flushPendingDiff()\n\n\t\t\tlet { undos, redos } = this.stacks.get()\n\t\t\tif (redos.length === 0) {\n\t\t\t\treturn this\n\t\t\t}\n\n\t\t\t// ignore any intermediate marks - this should take us to the first `diff` entry\n\t\t\twhile (redos.head?.type === 'stop') {\n\t\t\t\tundos = undos.push(redos.head)\n\t\t\t\tredos = redos.tail\n\t\t\t}\n\n\t\t\t// accumulate diffs to be redone so they can be applied atomically\n\t\t\tconst diffToRedo = createEmptyRecordsDiff<R>()\n\n\t\t\twhile (redos.head) {\n\t\t\t\tconst redo = redos.head\n\t\t\t\tundos = undos.push(redo)\n\t\t\t\tredos = redos.tail\n\n\t\t\t\tif (redo.type === 'diff') {\n\t\t\t\t\tsquashRecordDiffsMutable(diffToRedo, [redo.diff])\n\t\t\t\t} else {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.store.applyDiff(diffToRedo, { ignoreEphemeralKeys: true })\n\t\t\tthis.store.ensureStoreIsUsable()\n\t\t\tthis.stacks.set({ undos, redos })\n\t\t} finally {\n\t\t\tthis.state = previousState\n\t\t}\n\n\t\treturn this\n\t}\n\n\tbail() {\n\t\tthis._undo({ pushToRedoStack: false })\n\n\t\treturn this\n\t}\n\n\tbailToMark(id: string) {\n\t\tif (id) {\n\t\t\tthis._undo({ pushToRedoStack: false, toMark: id })\n\t\t}\n\n\t\treturn this\n\t}\n\n\tsquashToMark(id: string) {\n\t\t// remove marks between head and the mark\n\n\t\tlet top = this.stacks.get().undos\n\t\tconst popped: Array<RecordsDiff<R>> = []\n\n\t\twhile (top.head && !(top.head.type === 'stop' && top.head.id === id)) {\n\t\t\tif (top.head.type === 'diff') {\n\t\t\t\tpopped.push(top.head.diff)\n\t\t\t}\n\t\t\ttop = top.tail\n\t\t}\n\n\t\tif (!top.head || top.head?.id !== id) {\n\t\t\tconsole.error('Could not find mark to squash to: ', id)\n\t\t\treturn this\n\t\t}\n\t\tif (popped.length === 0) {\n\t\t\treturn this\n\t\t}\n\n\t\tconst diff = createEmptyRecordsDiff<R>()\n\t\tsquashRecordDiffsMutable(diff, popped.reverse())\n\n\t\tthis.stacks.update(({ redos }) => ({\n\t\t\tundos: top.push({\n\t\t\t\ttype: 'diff',\n\t\t\t\tdiff,\n\t\t\t}),\n\t\t\tredos,\n\t\t}))\n\n\t\treturn this\n\t}\n\n\t/** @internal */\n\t_mark(id: string) {\n\t\ttransact(() => {\n\t\t\tthis.flushPendingDiff()\n\t\t\tthis.stacks.update(({ undos, redos }) => ({ undos: undos.push({ type: 'stop', id }), redos }))\n\t\t})\n\t}\n\n\tclear() {\n\t\tthis.stacks.set({ undos: stack(), redos: stack() })\n\t\tthis.pendingDiff.clear()\n\t}\n\n\t/** @internal */\n\tgetMarkIdMatching(idSubstring: string) {\n\t\tlet top = this.stacks.get().undos\n\t\twhile (top.head) {\n\t\t\tif (top.head.type === 'stop' && top.head.id.includes(idSubstring)) {\n\t\t\t\treturn top.head.id\n\t\t\t}\n\t\t\ttop = top.tail\n\t\t}\n\t\treturn null\n\t}\n\n\t/** @internal */\n\tdebug() {\n\t\tconst { undos, redos } = this.stacks.get()\n\t\treturn {\n\t\t\tundos: stackToArray(undos),\n\t\t\tredos: stackToArray(redos),\n\t\t\tpendingDiff: this.pendingDiff.debug(),\n\t\t\tstate: this.state as string,\n\t\t}\n\t}\n}\n\nconst modeToState = {\n\trecord: HistoryRecorderState.Recording,\n\t'record-preserveRedoStack': HistoryRecorderState.RecordingPreserveRedoStack,\n\tignore: HistoryRecorderState.Paused,\n} as const\n\nclass PendingDiff<R extends UnknownRecord> {\n\tprivate diff = createEmptyRecordsDiff<R>()\n\tprivate isEmptyAtom = atom('PendingDiff.isEmpty', true)\n\n\tclear() {\n\t\tconst diff = this.diff\n\t\tthis.diff = createEmptyRecordsDiff<R>()\n\t\tthis.isEmptyAtom.set(true)\n\t\treturn diff\n\t}\n\n\trestore(diff: RecordsDiff<R>) {\n\t\tthis.diff = diff\n\t\tthis.isEmptyAtom.set(isRecordsDiffEmpty(diff))\n\t}\n\n\tisEmpty() {\n\t\treturn this.isEmptyAtom.get()\n\t}\n\n\tapply(diff: RecordsDiff<R>) {\n\t\tsquashRecordDiffsMutable(this.diff, [diff])\n\t\tthis.isEmptyAtom.set(isRecordsDiffEmpty(this.diff))\n\t}\n\n\tdebug() {\n\t\treturn { diff: this.diff, isEmpty: this.isEmpty() }\n\t}\n}\n\ntype Stack<T> = StackItem<T> | EmptyStackItem<T>\n\nfunction stack<T>(): Stack<T> {\n\treturn EMPTY_STACK_ITEM as any\n}\n\nclass EmptyStackItem<T> {\n\treadonly length = 0\n\treadonly head = null\n\treadonly tail: Stack<T> = this\n\n\tpush(head: T): Stack<T> {\n\t\treturn new StackItem<T>(head, this)\n\t}\n}\n\nconst EMPTY_STACK_ITEM = new EmptyStackItem()\n\nclass StackItem<T> {\n\tlength: number\n\tconstructor(\n\t\tpublic readonly head: T,\n\t\tpublic readonly tail: Stack<T>\n\t) {\n\t\tthis.length = tail.length + 1\n\t}\n\n\tpush(head: T): Stack<T> {\n\t\treturn new StackItem(head, this)\n\t}\n}\n\nfunction stackToArray<T>(stack: Stack<T>) {\n\tif (!stack.length) {\n\t\treturn EMPTY_ARRAY\n\t}\n\tconst arr: T[] = []\n\twhile (stack.length) {\n\t\tarr.push(stack.head!)\n\t\tstack = stack.tail\n\t}\n\treturn arr\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["stack"]
7
7
  }
@@ -46,7 +46,7 @@ const initialDefaultStyles = Object.freeze({
46
46
  class TextManager {
47
47
  constructor(editor) {
48
48
  this.editor = editor;
49
- const elm = document.createElement("div");
49
+ const elm = editor.getContainerDocument().createElement("div");
50
50
  elm.classList.add("tl-text");
51
51
  elm.classList.add("tl-text-measure");
52
52
  elm.setAttribute("dir", "auto");
@@ -78,7 +78,7 @@ class TextManager {
78
78
  return this.elm.remove();
79
79
  }
80
80
  measureText(textToMeasure, opts) {
81
- const div = document.createElement("div");
81
+ const div = this.editor.getContainerDocument().createElement("div");
82
82
  div.textContent = normalizeTextForDom(textToMeasure);
83
83
  return this.measureHtml(div.innerHTML, opts);
84
84
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/editor/managers/TextManager/TextManager.ts"],
4
- "sourcesContent": ["import { BoxModel, TLDefaultHorizontalAlignStyle } from '@tldraw/tlschema'\nimport { objectMapKeys } from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\n\nconst fixNewLines = /\\r?\\n|\\r/g\n\nfunction normalizeTextForDom(text: string) {\n\treturn text\n\t\t.replace(fixNewLines, '\\n')\n\t\t.split('\\n')\n\t\t.map((x) => x || ' ')\n\t\t.join('\\n')\n}\n\nconst textAlignmentsForLtr = {\n\tstart: 'left',\n\t'start-legacy': 'left',\n\tmiddle: 'center',\n\t'middle-legacy': 'center',\n\tend: 'right',\n\t'end-legacy': 'right',\n}\n\n/** @public */\nexport interface TLMeasureTextOpts {\n\tfontStyle: string\n\tfontWeight: string\n\tfontFamily: string\n\tfontSize: number\n\t/** This must be a number, e.g. 1.35, not a pixel value. */\n\tlineHeight: number\n\t/**\n\t * When maxWidth is a number, the text will be wrapped to that maxWidth. When maxWidth\n\t * is null, the text will be measured without wrapping, but explicit line breaks and\n\t * space are preserved.\n\t */\n\tmaxWidth: null | number\n\tminWidth?: null | number\n\t// todo: make this a number so that it is consistent with other TLMeasureTextSpanOpts\n\tpadding: string\n\totherStyles?: Record<string, string>\n\tdisableOverflowWrapBreaking?: boolean\n\tmeasureScrollWidth?: boolean\n}\n\n/** @public */\nexport interface TLMeasureTextSpanOpts {\n\toverflow: 'wrap' | 'truncate-ellipsis' | 'truncate-clip'\n\twidth: number\n\theight: number\n\tpadding: number\n\tfontSize: number\n\tfontWeight: string\n\tfontFamily: string\n\tfontStyle: string\n\tlineHeight: number\n\ttextAlign: TLDefaultHorizontalAlignStyle\n\totherStyles?: Record<string, string>\n\tmeasureScrollWidth?: boolean\n}\n\nconst spaceCharacterRegex = /\\s/\n\nconst initialDefaultStyles = Object.freeze({\n\t'overflow-wrap': 'break-word',\n\t'word-break': 'auto',\n\twidth: null,\n\theight: null,\n\t'max-width': null,\n\t'min-width': null,\n})\n\n/** @public */\nexport class TextManager {\n\tprivate elm: HTMLDivElement\n\n\tconstructor(public editor: Editor) {\n\t\tconst elm = document.createElement('div')\n\t\telm.classList.add('tl-text')\n\t\telm.classList.add('tl-text-measure')\n\t\telm.setAttribute('dir', 'auto')\n\t\telm.tabIndex = -1\n\t\tthis.editor.getContainer().appendChild(elm)\n\n\t\tthis.elm = elm\n\n\t\tfor (const key of objectMapKeys(initialDefaultStyles)) {\n\t\t\telm.style.setProperty(key, initialDefaultStyles[key])\n\t\t}\n\t}\n\n\tprivate setElementStyles(styles: Record<string, string | undefined>) {\n\t\tconst stylesToReinstate = {} as any\n\t\tfor (const key of objectMapKeys(styles)) {\n\t\t\tif (typeof styles[key] === 'string') {\n\t\t\t\tconst oldValue = this.elm.style.getPropertyValue(key)\n\t\t\t\tif (oldValue === styles[key]) continue\n\t\t\t\tstylesToReinstate[key] = oldValue\n\t\t\t\tthis.elm.style.setProperty(key, styles[key])\n\t\t\t}\n\t\t}\n\t\treturn () => {\n\t\t\tfor (const key of objectMapKeys(stylesToReinstate)) {\n\t\t\t\tthis.elm.style.setProperty(key, stylesToReinstate[key])\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose() {\n\t\treturn this.elm.remove()\n\t}\n\n\tmeasureText(textToMeasure: string, opts: TLMeasureTextOpts): BoxModel & { scrollWidth: number } {\n\t\tconst div = document.createElement('div')\n\t\tdiv.textContent = normalizeTextForDom(textToMeasure)\n\t\treturn this.measureHtml(div.innerHTML, opts)\n\t}\n\n\tmeasureHtml(html: string, opts: TLMeasureTextOpts): BoxModel & { scrollWidth: number } {\n\t\tconst { elm } = this\n\n\t\tconst newStyles = {\n\t\t\t'font-family': opts.fontFamily,\n\t\t\t'font-style': opts.fontStyle,\n\t\t\t'font-weight': opts.fontWeight,\n\t\t\t'font-size': opts.fontSize + 'px',\n\t\t\t'line-height': opts.lineHeight.toString(),\n\t\t\tpadding: opts.padding,\n\t\t\t'max-width': opts.maxWidth ? opts.maxWidth + 'px' : undefined,\n\t\t\t'min-width': opts.minWidth ? opts.minWidth + 'px' : undefined,\n\t\t\t'overflow-wrap': opts.disableOverflowWrapBreaking ? 'normal' : undefined,\n\t\t\t...opts.otherStyles,\n\t\t}\n\n\t\tconst restoreStyles = this.setElementStyles(newStyles)\n\n\t\ttry {\n\t\t\telm.innerHTML = html\n\n\t\t\tconst scrollWidth = opts.measureScrollWidth ? elm.scrollWidth : 0\n\t\t\tconst rect = elm.getBoundingClientRect()\n\n\t\t\treturn {\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t\tw: rect.width,\n\t\t\t\th: rect.height,\n\t\t\t\tscrollWidth,\n\t\t\t}\n\t\t} finally {\n\t\t\trestoreStyles()\n\t\t}\n\t}\n\n\t/**\n\t * Given an html element, measure the position of each span of unbroken\n\t * word/white-space characters within any text nodes it contains.\n\t */\n\tmeasureElementTextNodeSpans(\n\t\telement: HTMLElement,\n\t\t{ shouldTruncateToFirstLine = false }: { shouldTruncateToFirstLine?: boolean } = {}\n\t): { spans: { box: BoxModel; text: string }[]; didTruncate: boolean } {\n\t\tconst spans = []\n\n\t\t// Measurements of individual spans are relative to the containing element\n\t\tconst elmBounds = element.getBoundingClientRect()\n\t\tconst offsetX = -elmBounds.left\n\t\tconst offsetY = -elmBounds.top\n\n\t\t// we measure by creating a range that spans each character in the elements text node\n\t\tconst range = new Range()\n\t\tconst textNode = element.childNodes[0]\n\t\tlet idx = 0\n\n\t\tlet currentSpan = null\n\t\tlet prevCharWasSpaceCharacter = null\n\t\tlet prevCharTop = 0\n\t\tlet prevCharLeftForRTLTest = 0\n\t\tlet didTruncate = false\n\t\tfor (const childNode of element.childNodes) {\n\t\t\tif (childNode.nodeType !== Node.TEXT_NODE) continue\n\n\t\t\tfor (const char of childNode.textContent ?? '') {\n\t\t\t\t// place the range around the characters we're interested in\n\t\t\t\trange.setStart(textNode, idx)\n\t\t\t\trange.setEnd(textNode, idx + char.length)\n\t\t\t\t// measure the range. some browsers return multiple rects for the\n\t\t\t\t// first char in a new line - one for the line break, and one for\n\t\t\t\t// the character itself. we're only interested in the character.\n\t\t\t\tconst rects = range.getClientRects()\n\t\t\t\tconst rect = rects[rects.length - 1]!\n\n\t\t\t\t// calculate the position of the character relative to the element\n\t\t\t\tconst top = rect.top + offsetY\n\t\t\t\tconst left = rect.left + offsetX\n\t\t\t\tconst right = rect.right + offsetX\n\t\t\t\tconst isRTL = left < prevCharLeftForRTLTest\n\n\t\t\t\tconst isSpaceCharacter = spaceCharacterRegex.test(char)\n\t\t\t\tif (\n\t\t\t\t\t// If we're at a word boundary...\n\t\t\t\t\tisSpaceCharacter !== prevCharWasSpaceCharacter ||\n\t\t\t\t\t// ...or we're on a different line...\n\t\t\t\t\ttop !== prevCharTop ||\n\t\t\t\t\t// ...or we're at the start of the text and haven't created a span yet...\n\t\t\t\t\t!currentSpan\n\t\t\t\t) {\n\t\t\t\t\t// ...then we're at a span boundary!\n\n\t\t\t\t\tif (currentSpan) {\n\t\t\t\t\t\t// if we're truncating to a single line & we just finished the first line, stop there\n\t\t\t\t\t\tif (shouldTruncateToFirstLine && top !== prevCharTop) {\n\t\t\t\t\t\t\tdidTruncate = true\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// otherwise add the span to the list ready to start a new one\n\t\t\t\t\t\tspans.push(currentSpan)\n\t\t\t\t\t}\n\n\t\t\t\t\t// start a new span\n\t\t\t\t\tcurrentSpan = {\n\t\t\t\t\t\tbox: { x: left, y: top, w: rect.width, h: rect.height },\n\t\t\t\t\t\ttext: char,\n\t\t\t\t\t}\n\t\t\t\t\tprevCharLeftForRTLTest = left\n\t\t\t\t} else {\n\t\t\t\t\t// Looks like we're in RTL mode, so we need to adjust the left position.\n\t\t\t\t\tif (isRTL) {\n\t\t\t\t\t\tcurrentSpan.box.x = left\n\t\t\t\t\t}\n\n\t\t\t\t\t// otherwise we just need to extend the current span with the next character\n\t\t\t\t\tcurrentSpan.box.w = isRTL ? currentSpan.box.w + rect.width : right - currentSpan.box.x\n\t\t\t\t\tcurrentSpan.text += char\n\t\t\t\t}\n\n\t\t\t\tif (char === '\\n') {\n\t\t\t\t\tprevCharLeftForRTLTest = 0\n\t\t\t\t}\n\n\t\t\t\tprevCharWasSpaceCharacter = isSpaceCharacter\n\t\t\t\tprevCharTop = top\n\t\t\t\tidx += char.length\n\t\t\t}\n\t\t}\n\n\t\t// Add the last span\n\t\tif (currentSpan) {\n\t\t\tspans.push(currentSpan)\n\t\t}\n\n\t\treturn { spans, didTruncate }\n\t}\n\n\t/**\n\t * Measure text into individual spans. Spans are created by rendering the\n\t * text, then dividing it up according to line breaks and word boundaries.\n\t *\n\t * It works by having the browser render the text, then measuring the\n\t * position of each character. You can use this to replicate the text-layout\n\t * algorithm of the current browser in e.g. an SVG export.\n\t */\n\tmeasureTextSpans(\n\t\ttextToMeasure: string,\n\t\topts: TLMeasureTextSpanOpts\n\t): { text: string; box: BoxModel }[] {\n\t\tif (textToMeasure === '') return []\n\n\t\tconst { elm } = this\n\n\t\tconst shouldTruncateToFirstLine =\n\t\t\topts.overflow === 'truncate-ellipsis' || opts.overflow === 'truncate-clip'\n\t\tconst elementWidth = Math.ceil(opts.width - opts.padding * 2)\n\t\tconst newStyles = {\n\t\t\t'font-family': opts.fontFamily,\n\t\t\t'font-style': opts.fontStyle,\n\t\t\t'font-weight': opts.fontWeight,\n\t\t\t'font-size': opts.fontSize + 'px',\n\t\t\t'line-height': opts.lineHeight.toString(),\n\t\t\twidth: `${elementWidth}px`,\n\t\t\theight: 'min-content',\n\t\t\t'text-align': textAlignmentsForLtr[opts.textAlign],\n\t\t\t'overflow-wrap': shouldTruncateToFirstLine ? 'anywhere' : undefined,\n\t\t\t'word-break': shouldTruncateToFirstLine ? 'break-all' : undefined,\n\t\t\t...opts.otherStyles,\n\t\t}\n\t\tconst restoreStyles = this.setElementStyles(newStyles)\n\n\t\ttry {\n\t\t\tconst normalizedText = normalizeTextForDom(textToMeasure)\n\n\t\t\t// Render the text into the measurement element:\n\t\t\telm.textContent = normalizedText\n\n\t\t\t// actually measure the text:\n\t\t\tconst { spans, didTruncate } = this.measureElementTextNodeSpans(elm, {\n\t\t\t\tshouldTruncateToFirstLine,\n\t\t\t})\n\n\t\t\tif (opts.overflow === 'truncate-ellipsis' && didTruncate) {\n\t\t\t\t// we need to measure the ellipsis to know how much space it takes up\n\t\t\t\telm.textContent = '\u2026'\n\t\t\t\tconst ellipsisWidth = Math.ceil(this.measureElementTextNodeSpans(elm).spans[0].box.w)\n\n\t\t\t\t// then, we need to subtract that space from the width we have and measure again:\n\t\t\t\telm.style.setProperty('width', `${elementWidth - ellipsisWidth}px`)\n\t\t\t\telm.textContent = normalizedText\n\t\t\t\tconst truncatedSpans = this.measureElementTextNodeSpans(elm, {\n\t\t\t\t\tshouldTruncateToFirstLine: true,\n\t\t\t\t}).spans\n\n\t\t\t\t// Finally, we add in our ellipsis at the end of the last span. We\n\t\t\t\t// have to do this after measuring, not before, because adding the\n\t\t\t\t// ellipsis changes how whitespace might be getting collapsed by the\n\t\t\t\t// browser.\n\t\t\t\tconst lastSpan = truncatedSpans[truncatedSpans.length - 1]!\n\t\t\t\ttruncatedSpans.push({\n\t\t\t\t\ttext: '\u2026',\n\t\t\t\t\tbox: {\n\t\t\t\t\t\tx: Math.min(lastSpan.box.x + lastSpan.box.w, opts.width - opts.padding - ellipsisWidth),\n\t\t\t\t\t\ty: lastSpan.box.y,\n\t\t\t\t\t\tw: ellipsisWidth,\n\t\t\t\t\t\th: lastSpan.box.h,\n\t\t\t\t\t},\n\t\t\t\t})\n\n\t\t\t\treturn truncatedSpans\n\t\t\t}\n\n\t\t\treturn spans\n\t\t} finally {\n\t\t\trestoreStyles()\n\t\t}\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { BoxModel, TLDefaultHorizontalAlignStyle } from '@tldraw/tlschema'\nimport { objectMapKeys } from '@tldraw/utils'\nimport type { Editor } from '../../Editor'\n\nconst fixNewLines = /\\r?\\n|\\r/g\n\nfunction normalizeTextForDom(text: string) {\n\treturn text\n\t\t.replace(fixNewLines, '\\n')\n\t\t.split('\\n')\n\t\t.map((x) => x || ' ')\n\t\t.join('\\n')\n}\n\nconst textAlignmentsForLtr = {\n\tstart: 'left',\n\t'start-legacy': 'left',\n\tmiddle: 'center',\n\t'middle-legacy': 'center',\n\tend: 'right',\n\t'end-legacy': 'right',\n}\n\n/** @public */\nexport interface TLMeasureTextOpts {\n\tfontStyle: string\n\tfontWeight: string\n\tfontFamily: string\n\tfontSize: number\n\t/** This must be a number, e.g. 1.35, not a pixel value. */\n\tlineHeight: number\n\t/**\n\t * When maxWidth is a number, the text will be wrapped to that maxWidth. When maxWidth\n\t * is null, the text will be measured without wrapping, but explicit line breaks and\n\t * space are preserved.\n\t */\n\tmaxWidth: null | number\n\tminWidth?: null | number\n\t// todo: make this a number so that it is consistent with other TLMeasureTextSpanOpts\n\tpadding: string\n\totherStyles?: Record<string, string>\n\tdisableOverflowWrapBreaking?: boolean\n\tmeasureScrollWidth?: boolean\n}\n\n/** @public */\nexport interface TLMeasureTextSpanOpts {\n\toverflow: 'wrap' | 'truncate-ellipsis' | 'truncate-clip'\n\twidth: number\n\theight: number\n\tpadding: number\n\tfontSize: number\n\tfontWeight: string\n\tfontFamily: string\n\tfontStyle: string\n\tlineHeight: number\n\ttextAlign: TLDefaultHorizontalAlignStyle\n\totherStyles?: Record<string, string>\n\tmeasureScrollWidth?: boolean\n}\n\nconst spaceCharacterRegex = /\\s/\n\nconst initialDefaultStyles = Object.freeze({\n\t'overflow-wrap': 'break-word',\n\t'word-break': 'auto',\n\twidth: null,\n\theight: null,\n\t'max-width': null,\n\t'min-width': null,\n})\n\n/** @public */\nexport class TextManager {\n\tprivate elm: HTMLDivElement\n\n\tconstructor(public editor: Editor) {\n\t\tconst elm = editor.getContainerDocument().createElement('div')\n\t\telm.classList.add('tl-text')\n\t\telm.classList.add('tl-text-measure')\n\t\telm.setAttribute('dir', 'auto')\n\t\telm.tabIndex = -1\n\t\tthis.editor.getContainer().appendChild(elm)\n\n\t\tthis.elm = elm\n\n\t\tfor (const key of objectMapKeys(initialDefaultStyles)) {\n\t\t\telm.style.setProperty(key, initialDefaultStyles[key])\n\t\t}\n\t}\n\n\tprivate setElementStyles(styles: Record<string, string | undefined>) {\n\t\tconst stylesToReinstate = {} as any\n\t\tfor (const key of objectMapKeys(styles)) {\n\t\t\tif (typeof styles[key] === 'string') {\n\t\t\t\tconst oldValue = this.elm.style.getPropertyValue(key)\n\t\t\t\tif (oldValue === styles[key]) continue\n\t\t\t\tstylesToReinstate[key] = oldValue\n\t\t\t\tthis.elm.style.setProperty(key, styles[key])\n\t\t\t}\n\t\t}\n\t\treturn () => {\n\t\t\tfor (const key of objectMapKeys(stylesToReinstate)) {\n\t\t\t\tthis.elm.style.setProperty(key, stylesToReinstate[key])\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose() {\n\t\treturn this.elm.remove()\n\t}\n\n\tmeasureText(textToMeasure: string, opts: TLMeasureTextOpts): BoxModel & { scrollWidth: number } {\n\t\tconst div = this.editor.getContainerDocument().createElement('div')\n\t\tdiv.textContent = normalizeTextForDom(textToMeasure)\n\t\treturn this.measureHtml(div.innerHTML, opts)\n\t}\n\n\tmeasureHtml(html: string, opts: TLMeasureTextOpts): BoxModel & { scrollWidth: number } {\n\t\tconst { elm } = this\n\n\t\tconst newStyles = {\n\t\t\t'font-family': opts.fontFamily,\n\t\t\t'font-style': opts.fontStyle,\n\t\t\t'font-weight': opts.fontWeight,\n\t\t\t'font-size': opts.fontSize + 'px',\n\t\t\t'line-height': opts.lineHeight.toString(),\n\t\t\tpadding: opts.padding,\n\t\t\t'max-width': opts.maxWidth ? opts.maxWidth + 'px' : undefined,\n\t\t\t'min-width': opts.minWidth ? opts.minWidth + 'px' : undefined,\n\t\t\t'overflow-wrap': opts.disableOverflowWrapBreaking ? 'normal' : undefined,\n\t\t\t...opts.otherStyles,\n\t\t}\n\n\t\tconst restoreStyles = this.setElementStyles(newStyles)\n\n\t\ttry {\n\t\t\telm.innerHTML = html\n\n\t\t\tconst scrollWidth = opts.measureScrollWidth ? elm.scrollWidth : 0\n\t\t\tconst rect = elm.getBoundingClientRect()\n\n\t\t\treturn {\n\t\t\t\tx: 0,\n\t\t\t\ty: 0,\n\t\t\t\tw: rect.width,\n\t\t\t\th: rect.height,\n\t\t\t\tscrollWidth,\n\t\t\t}\n\t\t} finally {\n\t\t\trestoreStyles()\n\t\t}\n\t}\n\n\t/**\n\t * Given an html element, measure the position of each span of unbroken\n\t * word/white-space characters within any text nodes it contains.\n\t */\n\tmeasureElementTextNodeSpans(\n\t\telement: HTMLElement,\n\t\t{ shouldTruncateToFirstLine = false }: { shouldTruncateToFirstLine?: boolean } = {}\n\t): { spans: { box: BoxModel; text: string }[]; didTruncate: boolean } {\n\t\tconst spans = []\n\n\t\t// Measurements of individual spans are relative to the containing element\n\t\tconst elmBounds = element.getBoundingClientRect()\n\t\tconst offsetX = -elmBounds.left\n\t\tconst offsetY = -elmBounds.top\n\n\t\t// we measure by creating a range that spans each character in the elements text node\n\t\tconst range = new Range()\n\t\tconst textNode = element.childNodes[0]\n\t\tlet idx = 0\n\n\t\tlet currentSpan = null\n\t\tlet prevCharWasSpaceCharacter = null\n\t\tlet prevCharTop = 0\n\t\tlet prevCharLeftForRTLTest = 0\n\t\tlet didTruncate = false\n\t\tfor (const childNode of element.childNodes) {\n\t\t\tif (childNode.nodeType !== Node.TEXT_NODE) continue\n\n\t\t\tfor (const char of childNode.textContent ?? '') {\n\t\t\t\t// place the range around the characters we're interested in\n\t\t\t\trange.setStart(textNode, idx)\n\t\t\t\trange.setEnd(textNode, idx + char.length)\n\t\t\t\t// measure the range. some browsers return multiple rects for the\n\t\t\t\t// first char in a new line - one for the line break, and one for\n\t\t\t\t// the character itself. we're only interested in the character.\n\t\t\t\tconst rects = range.getClientRects()\n\t\t\t\tconst rect = rects[rects.length - 1]!\n\n\t\t\t\t// calculate the position of the character relative to the element\n\t\t\t\tconst top = rect.top + offsetY\n\t\t\t\tconst left = rect.left + offsetX\n\t\t\t\tconst right = rect.right + offsetX\n\t\t\t\tconst isRTL = left < prevCharLeftForRTLTest\n\n\t\t\t\tconst isSpaceCharacter = spaceCharacterRegex.test(char)\n\t\t\t\tif (\n\t\t\t\t\t// If we're at a word boundary...\n\t\t\t\t\tisSpaceCharacter !== prevCharWasSpaceCharacter ||\n\t\t\t\t\t// ...or we're on a different line...\n\t\t\t\t\ttop !== prevCharTop ||\n\t\t\t\t\t// ...or we're at the start of the text and haven't created a span yet...\n\t\t\t\t\t!currentSpan\n\t\t\t\t) {\n\t\t\t\t\t// ...then we're at a span boundary!\n\n\t\t\t\t\tif (currentSpan) {\n\t\t\t\t\t\t// if we're truncating to a single line & we just finished the first line, stop there\n\t\t\t\t\t\tif (shouldTruncateToFirstLine && top !== prevCharTop) {\n\t\t\t\t\t\t\tdidTruncate = true\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// otherwise add the span to the list ready to start a new one\n\t\t\t\t\t\tspans.push(currentSpan)\n\t\t\t\t\t}\n\n\t\t\t\t\t// start a new span\n\t\t\t\t\tcurrentSpan = {\n\t\t\t\t\t\tbox: { x: left, y: top, w: rect.width, h: rect.height },\n\t\t\t\t\t\ttext: char,\n\t\t\t\t\t}\n\t\t\t\t\tprevCharLeftForRTLTest = left\n\t\t\t\t} else {\n\t\t\t\t\t// Looks like we're in RTL mode, so we need to adjust the left position.\n\t\t\t\t\tif (isRTL) {\n\t\t\t\t\t\tcurrentSpan.box.x = left\n\t\t\t\t\t}\n\n\t\t\t\t\t// otherwise we just need to extend the current span with the next character\n\t\t\t\t\tcurrentSpan.box.w = isRTL ? currentSpan.box.w + rect.width : right - currentSpan.box.x\n\t\t\t\t\tcurrentSpan.text += char\n\t\t\t\t}\n\n\t\t\t\tif (char === '\\n') {\n\t\t\t\t\tprevCharLeftForRTLTest = 0\n\t\t\t\t}\n\n\t\t\t\tprevCharWasSpaceCharacter = isSpaceCharacter\n\t\t\t\tprevCharTop = top\n\t\t\t\tidx += char.length\n\t\t\t}\n\t\t}\n\n\t\t// Add the last span\n\t\tif (currentSpan) {\n\t\t\tspans.push(currentSpan)\n\t\t}\n\n\t\treturn { spans, didTruncate }\n\t}\n\n\t/**\n\t * Measure text into individual spans. Spans are created by rendering the\n\t * text, then dividing it up according to line breaks and word boundaries.\n\t *\n\t * It works by having the browser render the text, then measuring the\n\t * position of each character. You can use this to replicate the text-layout\n\t * algorithm of the current browser in e.g. an SVG export.\n\t */\n\tmeasureTextSpans(\n\t\ttextToMeasure: string,\n\t\topts: TLMeasureTextSpanOpts\n\t): { text: string; box: BoxModel }[] {\n\t\tif (textToMeasure === '') return []\n\n\t\tconst { elm } = this\n\n\t\tconst shouldTruncateToFirstLine =\n\t\t\topts.overflow === 'truncate-ellipsis' || opts.overflow === 'truncate-clip'\n\t\tconst elementWidth = Math.ceil(opts.width - opts.padding * 2)\n\t\tconst newStyles = {\n\t\t\t'font-family': opts.fontFamily,\n\t\t\t'font-style': opts.fontStyle,\n\t\t\t'font-weight': opts.fontWeight,\n\t\t\t'font-size': opts.fontSize + 'px',\n\t\t\t'line-height': opts.lineHeight.toString(),\n\t\t\twidth: `${elementWidth}px`,\n\t\t\theight: 'min-content',\n\t\t\t'text-align': textAlignmentsForLtr[opts.textAlign],\n\t\t\t'overflow-wrap': shouldTruncateToFirstLine ? 'anywhere' : undefined,\n\t\t\t'word-break': shouldTruncateToFirstLine ? 'break-all' : undefined,\n\t\t\t...opts.otherStyles,\n\t\t}\n\t\tconst restoreStyles = this.setElementStyles(newStyles)\n\n\t\ttry {\n\t\t\tconst normalizedText = normalizeTextForDom(textToMeasure)\n\n\t\t\t// Render the text into the measurement element:\n\t\t\telm.textContent = normalizedText\n\n\t\t\t// actually measure the text:\n\t\t\tconst { spans, didTruncate } = this.measureElementTextNodeSpans(elm, {\n\t\t\t\tshouldTruncateToFirstLine,\n\t\t\t})\n\n\t\t\tif (opts.overflow === 'truncate-ellipsis' && didTruncate) {\n\t\t\t\t// we need to measure the ellipsis to know how much space it takes up\n\t\t\t\telm.textContent = '\u2026'\n\t\t\t\tconst ellipsisWidth = Math.ceil(this.measureElementTextNodeSpans(elm).spans[0].box.w)\n\n\t\t\t\t// then, we need to subtract that space from the width we have and measure again:\n\t\t\t\telm.style.setProperty('width', `${elementWidth - ellipsisWidth}px`)\n\t\t\t\telm.textContent = normalizedText\n\t\t\t\tconst truncatedSpans = this.measureElementTextNodeSpans(elm, {\n\t\t\t\t\tshouldTruncateToFirstLine: true,\n\t\t\t\t}).spans\n\n\t\t\t\t// Finally, we add in our ellipsis at the end of the last span. We\n\t\t\t\t// have to do this after measuring, not before, because adding the\n\t\t\t\t// ellipsis changes how whitespace might be getting collapsed by the\n\t\t\t\t// browser.\n\t\t\t\tconst lastSpan = truncatedSpans[truncatedSpans.length - 1]!\n\t\t\t\ttruncatedSpans.push({\n\t\t\t\t\ttext: '\u2026',\n\t\t\t\t\tbox: {\n\t\t\t\t\t\tx: Math.min(lastSpan.box.x + lastSpan.box.w, opts.width - opts.padding - ellipsisWidth),\n\t\t\t\t\t\ty: lastSpan.box.y,\n\t\t\t\t\t\tw: ellipsisWidth,\n\t\t\t\t\t\th: lastSpan.box.h,\n\t\t\t\t\t},\n\t\t\t\t})\n\n\t\t\t\treturn truncatedSpans\n\t\t\t}\n\n\t\t\treturn spans\n\t\t} finally {\n\t\t\trestoreStyles()\n\t\t}\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -69,6 +69,7 @@ __export(UserPreferencesManager_exports, {
69
69
  module.exports = __toCommonJS(UserPreferencesManager_exports);
70
70
  var import_state = require("@tldraw/state");
71
71
  var import_TLUserPreferences = require("../../../config/TLUserPreferences");
72
+ var import_dom = require("../../../utils/dom");
72
73
  var _getIsZoomDirectionInverted_dec, _getInputMode_dec, _getEnhancedA11yMode_dec, _getIsPasteAtCursorMode_dec, _getIsDynamicResizeMode_dec, _getIsWrapMode_dec, _getIsSnapMode_dec, _getColor_dec, _getLocale_dec, _getName_dec, _getId_dec, _getAreKeyboardShortcutsEnabled_dec, _getAnimationSpeed_dec, _getEdgeScrollSpeed_dec, _getIsDarkMode_dec, _getUserPreferences_dec, _init;
73
74
  _getUserPreferences_dec = [import_state.computed], _getIsDarkMode_dec = [import_state.computed], _getEdgeScrollSpeed_dec = [import_state.computed], _getAnimationSpeed_dec = [import_state.computed], _getAreKeyboardShortcutsEnabled_dec = [import_state.computed], _getId_dec = [import_state.computed], _getName_dec = [import_state.computed], _getLocale_dec = [import_state.computed], _getColor_dec = [import_state.computed], _getIsSnapMode_dec = [import_state.computed], _getIsWrapMode_dec = [import_state.computed], _getIsDynamicResizeMode_dec = [import_state.computed], _getIsPasteAtCursorMode_dec = [import_state.computed], _getEnhancedA11yMode_dec = [import_state.computed], _getInputMode_dec = [import_state.computed], _getIsZoomDirectionInverted_dec = [import_state.computed];
74
75
  class UserPreferencesManager {
@@ -78,8 +79,8 @@ class UserPreferencesManager {
78
79
  __runInitializers(_init, 5, this);
79
80
  __publicField(this, "systemColorScheme", (0, import_state.atom)("systemColorScheme", "light"));
80
81
  __publicField(this, "disposables", /* @__PURE__ */ new Set());
81
- if (typeof window === "undefined" || !window.matchMedia) return;
82
- const darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
82
+ if (typeof window === "undefined" || !(0, import_dom.getGlobalWindow)().matchMedia) return;
83
+ const darkModeMediaQuery = (0, import_dom.getGlobalWindow)().matchMedia("(prefers-color-scheme: dark)");
83
84
  if (darkModeMediaQuery?.matches) {
84
85
  this.systemColorScheme.set("dark");
85
86
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts"],
4
- "sourcesContent": ["import { atom, computed } from '@tldraw/state'\nimport { TLUserPreferences, defaultUserPreferences } from '../../../config/TLUserPreferences'\nimport { TLUser } from '../../../config/createTLUser'\n\n/** @public */\nexport class UserPreferencesManager {\n\tsystemColorScheme = atom<'dark' | 'light'>('systemColorScheme', 'light')\n\tdisposables = new Set<() => void>()\n\tdispose() {\n\t\tthis.disposables.forEach((d) => d())\n\t}\n\tconstructor(\n\t\tprivate readonly user: TLUser,\n\t\tprivate readonly inferDarkMode: boolean\n\t) {\n\t\tif (typeof window === 'undefined' || !window.matchMedia) return\n\n\t\tconst darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n\t\tif (darkModeMediaQuery?.matches) {\n\t\t\tthis.systemColorScheme.set('dark')\n\t\t}\n\t\tconst handleChange = (e: MediaQueryListEvent) => {\n\t\t\tif (e.matches) {\n\t\t\t\tthis.systemColorScheme.set('dark')\n\t\t\t} else {\n\t\t\t\tthis.systemColorScheme.set('light')\n\t\t\t}\n\t\t}\n\t\tdarkModeMediaQuery?.addEventListener('change', handleChange)\n\t\tthis.disposables.add(() => darkModeMediaQuery?.removeEventListener('change', handleChange))\n\t}\n\n\tupdateUserPreferences(userPreferences: Partial<TLUserPreferences>) {\n\t\tthis.user.setUserPreferences({\n\t\t\t...this.user.userPreferences.get(),\n\t\t\t...userPreferences,\n\t\t})\n\t}\n\t@computed getUserPreferences() {\n\t\treturn {\n\t\t\tid: this.getId(),\n\t\t\tname: this.getName(),\n\t\t\tlocale: this.getLocale(),\n\t\t\tcolor: this.getColor(),\n\t\t\tanimationSpeed: this.getAnimationSpeed(),\n\t\t\tareKeyboardShortcutsEnabled: this.getAreKeyboardShortcutsEnabled(),\n\t\t\tisSnapMode: this.getIsSnapMode(),\n\t\t\tcolorScheme: this.user.userPreferences.get().colorScheme,\n\t\t\tisDarkMode: this.getIsDarkMode(),\n\t\t\tisWrapMode: this.getIsWrapMode(),\n\t\t\tisDynamicResizeMode: this.getIsDynamicResizeMode(),\n\t\t\tenhancedA11yMode: this.getEnhancedA11yMode(),\n\t\t\tinputMode: this.getInputMode(),\n\t\t\tisZoomDirectionInverted: this.getIsZoomDirectionInverted(),\n\t\t}\n\t}\n\n\t@computed getIsDarkMode() {\n\t\tswitch (this.user.userPreferences.get().colorScheme) {\n\t\t\tcase 'dark':\n\t\t\t\treturn true\n\t\t\tcase 'light':\n\t\t\t\treturn false\n\t\t\tcase 'system':\n\t\t\t\treturn this.systemColorScheme.get() === 'dark'\n\t\t\tdefault:\n\t\t\t\treturn this.inferDarkMode ? this.systemColorScheme.get() === 'dark' : false\n\t\t}\n\t}\n\n\t/**\n\t * The speed at which the user can scroll by dragging toward the edge of the screen.\n\t */\n\t@computed getEdgeScrollSpeed() {\n\t\treturn this.user.userPreferences.get().edgeScrollSpeed ?? defaultUserPreferences.edgeScrollSpeed\n\t}\n\n\t@computed getAnimationSpeed() {\n\t\treturn this.user.userPreferences.get().animationSpeed ?? defaultUserPreferences.animationSpeed\n\t}\n\n\t@computed getAreKeyboardShortcutsEnabled() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().areKeyboardShortcutsEnabled ??\n\t\t\tdefaultUserPreferences.areKeyboardShortcutsEnabled\n\t\t)\n\t}\n\n\t@computed getId() {\n\t\treturn this.user.userPreferences.get().id\n\t}\n\n\t@computed getName() {\n\t\treturn this.user.userPreferences.get().name?.trim() ?? defaultUserPreferences.name\n\t}\n\n\t@computed getLocale() {\n\t\treturn this.user.userPreferences.get().locale ?? defaultUserPreferences.locale\n\t}\n\n\t@computed getColor() {\n\t\treturn this.user.userPreferences.get().color ?? defaultUserPreferences.color\n\t}\n\n\t@computed getIsSnapMode() {\n\t\treturn this.user.userPreferences.get().isSnapMode ?? defaultUserPreferences.isSnapMode\n\t}\n\n\t@computed getIsWrapMode() {\n\t\treturn this.user.userPreferences.get().isWrapMode ?? defaultUserPreferences.isWrapMode\n\t}\n\n\t@computed getIsDynamicResizeMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isDynamicSizeMode ?? defaultUserPreferences.isDynamicSizeMode\n\t\t)\n\t}\n\n\t@computed getIsPasteAtCursorMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isPasteAtCursorMode ??\n\t\t\tdefaultUserPreferences.isPasteAtCursorMode\n\t\t)\n\t}\n\n\t@computed getEnhancedA11yMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().enhancedA11yMode ?? defaultUserPreferences.enhancedA11yMode\n\t\t)\n\t}\n\n\t@computed getInputMode() {\n\t\treturn this.user.userPreferences.get().inputMode ?? defaultUserPreferences.inputMode\n\t}\n\n\t@computed getIsZoomDirectionInverted() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isZoomDirectionInverted ??\n\t\t\tdefaultUserPreferences.isZoomDirectionInverted\n\t\t)\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { atom, computed } from '@tldraw/state'\nimport { TLUserPreferences, defaultUserPreferences } from '../../../config/TLUserPreferences'\nimport { TLUser } from '../../../config/createTLUser'\nimport { getGlobalWindow } from '../../../utils/dom'\n\n/** @public */\nexport class UserPreferencesManager {\n\tsystemColorScheme = atom<'dark' | 'light'>('systemColorScheme', 'light')\n\tdisposables = new Set<() => void>()\n\tdispose() {\n\t\tthis.disposables.forEach((d) => d())\n\t}\n\tconstructor(\n\t\tprivate readonly user: TLUser,\n\t\tprivate readonly inferDarkMode: boolean\n\t) {\n\t\tif (typeof window === 'undefined' || !getGlobalWindow().matchMedia) return\n\n\t\tconst darkModeMediaQuery = getGlobalWindow().matchMedia('(prefers-color-scheme: dark)')\n\t\tif (darkModeMediaQuery?.matches) {\n\t\t\tthis.systemColorScheme.set('dark')\n\t\t}\n\t\tconst handleChange = (e: MediaQueryListEvent) => {\n\t\t\tif (e.matches) {\n\t\t\t\tthis.systemColorScheme.set('dark')\n\t\t\t} else {\n\t\t\t\tthis.systemColorScheme.set('light')\n\t\t\t}\n\t\t}\n\t\tdarkModeMediaQuery?.addEventListener('change', handleChange)\n\t\tthis.disposables.add(() => darkModeMediaQuery?.removeEventListener('change', handleChange))\n\t}\n\n\tupdateUserPreferences(userPreferences: Partial<TLUserPreferences>) {\n\t\tthis.user.setUserPreferences({\n\t\t\t...this.user.userPreferences.get(),\n\t\t\t...userPreferences,\n\t\t})\n\t}\n\t@computed getUserPreferences() {\n\t\treturn {\n\t\t\tid: this.getId(),\n\t\t\tname: this.getName(),\n\t\t\tlocale: this.getLocale(),\n\t\t\tcolor: this.getColor(),\n\t\t\tanimationSpeed: this.getAnimationSpeed(),\n\t\t\tareKeyboardShortcutsEnabled: this.getAreKeyboardShortcutsEnabled(),\n\t\t\tisSnapMode: this.getIsSnapMode(),\n\t\t\tcolorScheme: this.user.userPreferences.get().colorScheme,\n\t\t\tisDarkMode: this.getIsDarkMode(),\n\t\t\tisWrapMode: this.getIsWrapMode(),\n\t\t\tisDynamicResizeMode: this.getIsDynamicResizeMode(),\n\t\t\tenhancedA11yMode: this.getEnhancedA11yMode(),\n\t\t\tinputMode: this.getInputMode(),\n\t\t\tisZoomDirectionInverted: this.getIsZoomDirectionInverted(),\n\t\t}\n\t}\n\n\t@computed getIsDarkMode() {\n\t\tswitch (this.user.userPreferences.get().colorScheme) {\n\t\t\tcase 'dark':\n\t\t\t\treturn true\n\t\t\tcase 'light':\n\t\t\t\treturn false\n\t\t\tcase 'system':\n\t\t\t\treturn this.systemColorScheme.get() === 'dark'\n\t\t\tdefault:\n\t\t\t\treturn this.inferDarkMode ? this.systemColorScheme.get() === 'dark' : false\n\t\t}\n\t}\n\n\t/**\n\t * The speed at which the user can scroll by dragging toward the edge of the screen.\n\t */\n\t@computed getEdgeScrollSpeed() {\n\t\treturn this.user.userPreferences.get().edgeScrollSpeed ?? defaultUserPreferences.edgeScrollSpeed\n\t}\n\n\t@computed getAnimationSpeed() {\n\t\treturn this.user.userPreferences.get().animationSpeed ?? defaultUserPreferences.animationSpeed\n\t}\n\n\t@computed getAreKeyboardShortcutsEnabled() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().areKeyboardShortcutsEnabled ??\n\t\t\tdefaultUserPreferences.areKeyboardShortcutsEnabled\n\t\t)\n\t}\n\n\t@computed getId() {\n\t\treturn this.user.userPreferences.get().id\n\t}\n\n\t@computed getName() {\n\t\treturn this.user.userPreferences.get().name?.trim() ?? defaultUserPreferences.name\n\t}\n\n\t@computed getLocale() {\n\t\treturn this.user.userPreferences.get().locale ?? defaultUserPreferences.locale\n\t}\n\n\t@computed getColor() {\n\t\treturn this.user.userPreferences.get().color ?? defaultUserPreferences.color\n\t}\n\n\t@computed getIsSnapMode() {\n\t\treturn this.user.userPreferences.get().isSnapMode ?? defaultUserPreferences.isSnapMode\n\t}\n\n\t@computed getIsWrapMode() {\n\t\treturn this.user.userPreferences.get().isWrapMode ?? defaultUserPreferences.isWrapMode\n\t}\n\n\t@computed getIsDynamicResizeMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isDynamicSizeMode ?? defaultUserPreferences.isDynamicSizeMode\n\t\t)\n\t}\n\n\t@computed getIsPasteAtCursorMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isPasteAtCursorMode ??\n\t\t\tdefaultUserPreferences.isPasteAtCursorMode\n\t\t)\n\t}\n\n\t@computed getEnhancedA11yMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().enhancedA11yMode ?? defaultUserPreferences.enhancedA11yMode\n\t\t)\n\t}\n\n\t@computed getInputMode() {\n\t\treturn this.user.userPreferences.get().inputMode ?? defaultUserPreferences.inputMode\n\t}\n\n\t@computed getIsZoomDirectionInverted() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isZoomDirectionInverted ??\n\t\t\tdefaultUserPreferences.isZoomDirectionInverted\n\t\t)\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/editor/types/misc-types.ts"],
4
- "sourcesContent": ["import { BoxModel, TLShape } from '@tldraw/tlschema'\nimport { Box } from '../../primitives/Box'\nimport { VecLike } from '../../primitives/Vec'\n\n/** @public */\nexport type RequiredKeys<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>\n/** @public */\nexport type OptionalKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\n/** @public */\nexport type TLExportType = 'svg' | 'png' | 'jpeg' | 'webp'\n\n/** @public */\nexport interface TLSvgExportOptions {\n\t/**\n\t * The bounding box, in page coordinates, of the area being exported.\n\t */\n\tbounds?: Box\n\t/**\n\t * The logical scale of the export. This scales the resulting size of the SVG being generated.\n\t */\n\tscale?: number\n\t/**\n\t * When exporting an SVG, the expected pixel ratio of the export will be passed in to\n\t * {@link @tldraw/tlschema#TLAssetStore.resolve} as the `dpr` property, so that assets can be\n\t * downscaled to the appropriate resolution.\n\t *\n\t * When exporting to a bitmap image format, the size of the resulting image will be multiplied\n\t * by this number.\n\t *\n\t * For SVG exports, this defaults to undefined - which means we'll request original-quality\n\t * assets. For bitmap exports, this defaults to 2.\n\t */\n\tpixelRatio?: number\n\n\t/**\n\t * Should the background color be included in the export? If false, the generated image will be\n\t * transparent (if exporting to a format that supports transparency).\n\t */\n\tbackground?: boolean\n\n\t/**\n\t * How much padding to include around the bounds of exports? Defaults to 32px.\n\t */\n\tpadding?: number\n\n\t/**\n\t * Should the export be rendered in dark mode (true) or light mode (false)? Defaults to the\n\t * current instance's dark mode setting.\n\t */\n\tdarkMode?: boolean\n\n\t/**\n\t * The\n\t * {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio | `preserveAspectRatio` }\n\t * attribute of the SVG element.\n\t */\n\tpreserveAspectRatio?: React.SVGAttributes<SVGSVGElement>['preserveAspectRatio']\n}\n\n/** @public */\nexport interface TLImageExportOptions extends TLSvgExportOptions {\n\t/**\n\t * If the export is being converted to a lossy bitmap format (e.g. jpeg), this is the quality of\n\t * the export. This is a number between 0 and 1.\n\t */\n\tquality?: number\n\n\t/**\n\t * The format to export as. Defaults to 'png'.\n\t */\n\tformat?: TLExportType\n}\n\n/** @public */\nexport interface TLCameraMoveOptions {\n\t/** Whether to move the camera immediately, rather than on the next tick. */\n\timmediate?: boolean\n\t/** Whether to force the camera to move, even if the user's camera options have locked the camera. */\n\tforce?: boolean\n\t/** Whether to reset the camera to its default position and zoom. */\n\treset?: boolean\n\t/** An (optional) animation to use. */\n\tanimation?: {\n\t\t/** The time the animation should take to arrive at the specified camera coordinates. */\n\t\tduration?: number\n\t\t/** An easing function to apply to the animation's progress from start to end. */\n\t\teasing?(t: number): number\n\t}\n}\n\n/** @public */\nexport interface TLCameraOptions {\n\t/** Whether the camera is locked. */\n\tisLocked: boolean\n\t/** The speed of a scroll wheel / trackpad pan. Default is 1. */\n\tpanSpeed: number\n\t/** The speed of a scroll wheel / trackpad zoom. Default is 1. */\n\tzoomSpeed: number\n\t/** The steps that a user can zoom between with zoom in / zoom out. The first and last value will determine the min and max zoom. */\n\tzoomSteps: number[]\n\t/** Controls whether the wheel pans or zooms.\n\t *\n\t * - `zoom`: The wheel will zoom in and out.\n\t * - `pan`: The wheel will pan the camera.\n\t * - `none`: The wheel will do nothing.\n\t */\n\twheelBehavior: 'zoom' | 'pan' | 'none'\n\t/** The camera constraints. */\n\tconstraints?: TLCameraConstraints\n}\n\n/** @public */\nexport interface TLCameraConstraints {\n\t/** The bounds (in page space) of the constrained space */\n\tbounds: BoxModel\n\t/** The padding inside of the viewport (in screen space) */\n\tpadding: VecLike\n\t/** The origin for placement. Used to position the bounds within the viewport when an axis is fixed or contained and zoom is below the axis fit. */\n\torigin: VecLike\n\t/** The camera's initial zoom, used also when the camera is reset.\n\t *\n\t * - `default`: Sets the initial zoom to 100%.\n\t * - `fit-x`: The x axis will completely fill the viewport bounds.\n\t * - `fit-y`: The y axis will completely fill the viewport bounds.\n\t * - `fit-min`: The smaller axis will completely fill the viewport bounds.\n\t * - `fit-max`: The larger axis will completely fill the viewport bounds.\n\t * - `fit-x-100`: The x axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-y-100`: The y axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-min-100`: The smaller axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-max-100`: The larger axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t */\n\tinitialZoom:\n\t\t| 'fit-min'\n\t\t| 'fit-max'\n\t\t| 'fit-x'\n\t\t| 'fit-y'\n\t\t| 'fit-min-100'\n\t\t| 'fit-max-100'\n\t\t| 'fit-x-100'\n\t\t| 'fit-y-100'\n\t\t| 'default'\n\t/** The camera's base for its zoom steps.\n\t *\n\t * - `default`: Sets the initial zoom to 100%.\n\t * - `fit-x`: The x axis will completely fill the viewport bounds.\n\t * - `fit-y`: The y axis will completely fill the viewport bounds.\n\t * - `fit-min`: The smaller axis will completely fill the viewport bounds.\n\t * - `fit-max`: The larger axis will completely fill the viewport bounds.\n\t * - `fit-x-100`: The x axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-y-100`: The y axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-min-100`: The smaller axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-max-100`: The larger axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t */\n\tbaseZoom:\n\t\t| 'fit-min'\n\t\t| 'fit-max'\n\t\t| 'fit-x'\n\t\t| 'fit-y'\n\t\t| 'fit-min-100'\n\t\t| 'fit-max-100'\n\t\t| 'fit-x-100'\n\t\t| 'fit-y-100'\n\t\t| 'default'\n\t/** The behavior for the constraints for both axes or each axis individually.\n\t *\n\t * - `free`: The bounds are ignored when moving the camera.\n\t * - 'fixed': The bounds will be positioned within the viewport based on the origin\n\t * - `contain`: The 'fixed' behavior will be used when the zoom is below the zoom level at which the bounds would fill the viewport; and when above this zoom, the bounds will use the 'inside' behavior.\n\t * - `inside`: The bounds will stay completely within the viewport.\n\t * - `outside`: The bounds will stay touching the viewport.\n\t */\n\tbehavior:\n\t\t| 'free'\n\t\t| 'fixed'\n\t\t| 'inside'\n\t\t| 'outside'\n\t\t| 'contain'\n\t\t| {\n\t\t\t\tx: 'free' | 'fixed' | 'inside' | 'outside' | 'contain'\n\t\t\t\ty: 'free' | 'fixed' | 'inside' | 'outside' | 'contain'\n\t\t }\n}\n\n/** @public */\nexport interface TLUpdatePointerOptions {\n\t/** Whether to update the pointer immediately, rather than on the next tick. */\n\timmediate?: boolean\n\t/**\n\t * The point, in screen-space, to update the pointer to. Defaults to the position of the last\n\t * pointer event.\n\t */\n\tpoint?: VecLike\n\tpointerId?: number\n\tctrlKey?: boolean\n\taltKey?: boolean\n\tshiftKey?: boolean\n\tmetaKey?: boolean\n\taccelKey?: boolean\n\tisPen?: boolean\n\tbutton?: number\n}\n\n/**\n * Options to {@link Editor.getShapeAtPoint}.\n *\n * @public\n */\nexport interface TLGetShapeAtPointOptions {\n\t/**\n\t * The margin to apply to the shape.\n\t * If a number, it will be applied to both the inside and outside of the shape.\n\t * If an array, the first element will be applied to the inside of the shape, and the second element will be applied to the outside.\n\t *\n\t * @example\n\t * ```ts\n\t * // Get the shape at the center of the screen\n\t * const shape = editor.getShapeAtProps({\n\t * margin: 10,\n\t * })\n\t *\n\t * // Get the shape at the center of the screen with a 10px inner margin and a 5px outer margin\n\t * const shape = editor.getShapeAtProps({\n\t * margin: [10, 5],\n\t * })\n\t * ```\n\t */\n\tmargin?: number | [number, number]\n\t/**\n\t * Whether to register hits inside of shapes (beyond the margin), such as the inside of a solid shape.\n\t */\n\thitInside?: boolean\n\t/**\n\t * Whether to register hits on locked shapes.\n\t */\n\thitLocked?: boolean\n\t/**\n\t * Whether to register hits on labels.\n\t */\n\thitLabels?: boolean\n\t/**\n\t * Whether to only return hits on shapes that are currently being rendered.\n\t * todo: rename this to hitCulled or hitNotRendering\n\t */\n\trenderingOnly?: boolean\n\t/**\n\t * Whether to register hits on the inside of frame shapes.\n\t * todo: rename this to hitInsideFrames\n\t */\n\thitFrameInside?: boolean\n\t/**\n\t * A filter function to apply to the shapes.\n\t */\n\tfilter?(shape: TLShape): boolean\n}\n"],
4
+ "sourcesContent": ["import { BoxModel, TLShape } from '@tldraw/tlschema'\nimport { Box } from '../../primitives/Box'\nimport { VecLike } from '../../primitives/Vec'\n\n/** @public */\nexport type RequiredKeys<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>\n/** @public */\nexport type OptionalKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\n/** @public */\nexport type TLExportType = 'svg' | 'png' | 'jpeg' | 'webp'\n\n/** @public */\nexport interface TLSvgExportOptions {\n\t/**\n\t * The bounding box, in page coordinates, of the area being exported.\n\t */\n\tbounds?: Box\n\t/**\n\t * The logical scale of the export. This scales the resulting size of the SVG being generated.\n\t */\n\tscale?: number\n\t/**\n\t * When exporting an SVG, the expected pixel ratio of the export will be passed in to\n\t * {@link @tldraw/tlschema#TLAssetStore.resolve} as the `dpr` property, so that assets can be\n\t * downscaled to the appropriate resolution.\n\t *\n\t * When exporting to a bitmap image format, the size of the resulting image will be multiplied\n\t * by this number.\n\t *\n\t * For SVG exports, this defaults to undefined - which means we'll request original-quality\n\t * assets. For bitmap exports, this defaults to 2.\n\t */\n\tpixelRatio?: number\n\n\t/**\n\t * Should the background color be included in the export? If false, the generated image will be\n\t * transparent (if exporting to a format that supports transparency).\n\t */\n\tbackground?: boolean\n\n\t/**\n\t * How much padding to include around the bounds of exports.\n\t *\n\t * - `'auto'` (default) \u2014 trim to visual content bounds, capturing overflow (like thick\n\t * strokes or arrowheads) without extra whitespace.\n\t * - `number` (e.g. `32`) \u2014 fixed padding in px. No trimming; overflow beyond the padding\n\t * region is clipped.\n\t * - `0` \u2014 no padding, no trimming, overflow is clipped.\n\t */\n\tpadding?: number | 'auto'\n\n\t/**\n\t * Should the export be rendered in dark mode (true) or light mode (false)? Defaults to the\n\t * current instance's dark mode setting.\n\t */\n\tdarkMode?: boolean\n\n\t/**\n\t * The\n\t * {@link https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/preserveAspectRatio | `preserveAspectRatio` }\n\t * attribute of the SVG element.\n\t */\n\tpreserveAspectRatio?: React.SVGAttributes<SVGSVGElement>['preserveAspectRatio']\n}\n\n/** @public */\nexport interface TLImageExportOptions extends TLSvgExportOptions {\n\t/**\n\t * If the export is being converted to a lossy bitmap format (e.g. jpeg), this is the quality of\n\t * the export. This is a number between 0 and 1.\n\t */\n\tquality?: number\n\n\t/**\n\t * The format to export as. Defaults to 'png'.\n\t */\n\tformat?: TLExportType\n}\n\n/** @public */\nexport interface TLCameraMoveOptions {\n\t/** Whether to move the camera immediately, rather than on the next tick. */\n\timmediate?: boolean\n\t/** Whether to force the camera to move, even if the user's camera options have locked the camera. */\n\tforce?: boolean\n\t/** Whether to reset the camera to its default position and zoom. */\n\treset?: boolean\n\t/** An (optional) animation to use. */\n\tanimation?: {\n\t\t/** The time the animation should take to arrive at the specified camera coordinates. */\n\t\tduration?: number\n\t\t/** An easing function to apply to the animation's progress from start to end. */\n\t\teasing?(t: number): number\n\t}\n}\n\n/** @public */\nexport interface TLCameraOptions {\n\t/** Whether the camera is locked. */\n\tisLocked: boolean\n\t/** The speed of a scroll wheel / trackpad pan. Default is 1. */\n\tpanSpeed: number\n\t/** The speed of a scroll wheel / trackpad zoom. Default is 1. */\n\tzoomSpeed: number\n\t/** The steps that a user can zoom between with zoom in / zoom out. The first and last value will determine the min and max zoom. */\n\tzoomSteps: number[]\n\t/** Controls whether the wheel pans or zooms.\n\t *\n\t * - `zoom`: The wheel will zoom in and out.\n\t * - `pan`: The wheel will pan the camera.\n\t * - `none`: The wheel will do nothing.\n\t */\n\twheelBehavior: 'zoom' | 'pan' | 'none'\n\t/** The camera constraints. */\n\tconstraints?: TLCameraConstraints\n}\n\n/** @public */\nexport interface TLCameraConstraints {\n\t/** The bounds (in page space) of the constrained space */\n\tbounds: BoxModel\n\t/** The padding inside of the viewport (in screen space) */\n\tpadding: VecLike\n\t/** The origin for placement. Used to position the bounds within the viewport when an axis is fixed or contained and zoom is below the axis fit. */\n\torigin: VecLike\n\t/** The camera's initial zoom, used also when the camera is reset.\n\t *\n\t * - `default`: Sets the initial zoom to 100%.\n\t * - `fit-x`: The x axis will completely fill the viewport bounds.\n\t * - `fit-y`: The y axis will completely fill the viewport bounds.\n\t * - `fit-min`: The smaller axis will completely fill the viewport bounds.\n\t * - `fit-max`: The larger axis will completely fill the viewport bounds.\n\t * - `fit-x-100`: The x axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-y-100`: The y axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-min-100`: The smaller axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-max-100`: The larger axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t */\n\tinitialZoom:\n\t\t| 'fit-min'\n\t\t| 'fit-max'\n\t\t| 'fit-x'\n\t\t| 'fit-y'\n\t\t| 'fit-min-100'\n\t\t| 'fit-max-100'\n\t\t| 'fit-x-100'\n\t\t| 'fit-y-100'\n\t\t| 'default'\n\t/** The camera's base for its zoom steps.\n\t *\n\t * - `default`: Sets the initial zoom to 100%.\n\t * - `fit-x`: The x axis will completely fill the viewport bounds.\n\t * - `fit-y`: The y axis will completely fill the viewport bounds.\n\t * - `fit-min`: The smaller axis will completely fill the viewport bounds.\n\t * - `fit-max`: The larger axis will completely fill the viewport bounds.\n\t * - `fit-x-100`: The x axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-y-100`: The y axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-min-100`: The smaller axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t * - `fit-max-100`: The larger axis will completely fill the viewport bounds, or 100% zoom, whichever is smaller.\n\t */\n\tbaseZoom:\n\t\t| 'fit-min'\n\t\t| 'fit-max'\n\t\t| 'fit-x'\n\t\t| 'fit-y'\n\t\t| 'fit-min-100'\n\t\t| 'fit-max-100'\n\t\t| 'fit-x-100'\n\t\t| 'fit-y-100'\n\t\t| 'default'\n\t/** The behavior for the constraints for both axes or each axis individually.\n\t *\n\t * - `free`: The bounds are ignored when moving the camera.\n\t * - 'fixed': The bounds will be positioned within the viewport based on the origin\n\t * - `contain`: The 'fixed' behavior will be used when the zoom is below the zoom level at which the bounds would fill the viewport; and when above this zoom, the bounds will use the 'inside' behavior.\n\t * - `inside`: The bounds will stay completely within the viewport.\n\t * - `outside`: The bounds will stay touching the viewport.\n\t */\n\tbehavior:\n\t\t| 'free'\n\t\t| 'fixed'\n\t\t| 'inside'\n\t\t| 'outside'\n\t\t| 'contain'\n\t\t| {\n\t\t\t\tx: 'free' | 'fixed' | 'inside' | 'outside' | 'contain'\n\t\t\t\ty: 'free' | 'fixed' | 'inside' | 'outside' | 'contain'\n\t\t }\n}\n\n/** @public */\nexport interface TLUpdatePointerOptions {\n\t/** Whether to update the pointer immediately, rather than on the next tick. */\n\timmediate?: boolean\n\t/**\n\t * The point, in screen-space, to update the pointer to. Defaults to the position of the last\n\t * pointer event.\n\t */\n\tpoint?: VecLike\n\tpointerId?: number\n\tctrlKey?: boolean\n\taltKey?: boolean\n\tshiftKey?: boolean\n\tmetaKey?: boolean\n\taccelKey?: boolean\n\tisPen?: boolean\n\tbutton?: number\n}\n\n/**\n * Options to {@link Editor.getShapeAtPoint}.\n *\n * @public\n */\nexport interface TLGetShapeAtPointOptions {\n\t/**\n\t * The margin to apply to the shape.\n\t * If a number, it will be applied to both the inside and outside of the shape.\n\t * If an array, the first element will be applied to the inside of the shape, and the second element will be applied to the outside.\n\t *\n\t * @example\n\t * ```ts\n\t * // Get the shape at the center of the screen\n\t * const shape = editor.getShapeAtProps({\n\t * margin: 10,\n\t * })\n\t *\n\t * // Get the shape at the center of the screen with a 10px inner margin and a 5px outer margin\n\t * const shape = editor.getShapeAtProps({\n\t * margin: [10, 5],\n\t * })\n\t * ```\n\t */\n\tmargin?: number | [number, number]\n\t/**\n\t * Whether to register hits inside of shapes (beyond the margin), such as the inside of a solid shape.\n\t */\n\thitInside?: boolean\n\t/**\n\t * Whether to register hits on locked shapes.\n\t */\n\thitLocked?: boolean\n\t/**\n\t * Whether to register hits on labels.\n\t */\n\thitLabels?: boolean\n\t/**\n\t * Whether to only return hits on shapes that are currently being rendered.\n\t * todo: rename this to hitCulled or hitNotRendering\n\t */\n\trenderingOnly?: boolean\n\t/**\n\t * Whether to register hits on the inside of frame shapes.\n\t * todo: rename this to hitInsideFrames\n\t */\n\thitFrameInside?: boolean\n\t/**\n\t * A filter function to apply to the shapes.\n\t */\n\tfilter?(shape: TLShape): boolean\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;AAAA;AAAA;",
6
6
  "names": []
7
7
  }