@tldraw/editor 3.16.0-internal.51e99e128bd4 → 3.16.0-internal.71f83a8a571b

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 (166) hide show
  1. package/dist-cjs/index.d.ts +133 -126
  2. package/dist-cjs/index.js +6 -6
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +7 -7
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/Shape.js +7 -10
  7. package/dist-cjs/lib/components/Shape.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +14 -23
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  10. package/dist-cjs/lib/editor/Editor.js +40 -113
  11. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  12. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +4 -0
  13. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
  14. package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
  15. package/dist-cjs/lib/editor/shapes/BaseBoxShapeUtil.js.map +1 -1
  16. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +23 -0
  17. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.js.map +2 -2
  19. package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
  20. package/dist-cjs/lib/exports/getSvgJsx.js +34 -14
  21. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  22. package/dist-cjs/lib/hooks/useCanvasEvents.js +22 -17
  23. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  24. package/dist-cjs/lib/hooks/useDocumentEvents.js +5 -5
  25. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  26. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -2
  27. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
  28. package/dist-cjs/lib/hooks/useGestureEvents.js +1 -1
  29. package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
  30. package/dist-cjs/lib/hooks/useHandleEvents.js +3 -3
  31. package/dist-cjs/lib/hooks/useHandleEvents.js.map +2 -2
  32. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +4 -1
  33. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
  34. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +4 -1
  35. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
  36. package/dist-cjs/lib/hooks/useSelectionEvents.js +4 -4
  37. package/dist-cjs/lib/hooks/useSelectionEvents.js.map +2 -2
  38. package/dist-cjs/lib/license/LicenseManager.js +140 -53
  39. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  40. package/dist-cjs/lib/license/LicenseProvider.js +39 -1
  41. package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
  42. package/dist-cjs/lib/license/Watermark.js +69 -7
  43. package/dist-cjs/lib/license/Watermark.js.map +3 -3
  44. package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
  45. package/dist-cjs/lib/primitives/Box.js +3 -0
  46. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  47. package/dist-cjs/lib/primitives/Vec.js +0 -4
  48. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  49. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +50 -20
  50. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  51. package/dist-cjs/lib/primitives/geometry/Group2d.js +8 -1
  52. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  53. package/dist-cjs/lib/utils/dom.js +12 -1
  54. package/dist-cjs/lib/utils/dom.js.map +2 -2
  55. package/dist-cjs/lib/utils/getPointerInfo.js +2 -2
  56. package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
  57. package/dist-cjs/lib/utils/reparenting.js +2 -35
  58. package/dist-cjs/lib/utils/reparenting.js.map +3 -3
  59. package/dist-cjs/version.js +3 -3
  60. package/dist-cjs/version.js.map +1 -1
  61. package/dist-esm/index.d.mts +133 -126
  62. package/dist-esm/index.mjs +9 -7
  63. package/dist-esm/index.mjs.map +2 -2
  64. package/dist-esm/lib/TldrawEditor.mjs +8 -8
  65. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  66. package/dist-esm/lib/components/Shape.mjs +7 -10
  67. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  68. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +15 -24
  69. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  70. package/dist-esm/lib/editor/Editor.mjs +40 -113
  71. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  72. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +4 -0
  73. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
  74. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
  75. package/dist-esm/lib/editor/shapes/BaseBoxShapeUtil.mjs.map +1 -1
  76. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +23 -0
  77. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  78. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.mjs.map +2 -2
  79. package/dist-esm/lib/exports/getSvgJsx.mjs +34 -14
  80. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  81. package/dist-esm/lib/hooks/useCanvasEvents.mjs +24 -18
  82. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  83. package/dist-esm/lib/hooks/useDocumentEvents.mjs +11 -6
  84. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  85. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +2 -3
  86. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
  87. package/dist-esm/lib/hooks/useGestureEvents.mjs +2 -2
  88. package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
  89. package/dist-esm/lib/hooks/useHandleEvents.mjs +9 -4
  90. package/dist-esm/lib/hooks/useHandleEvents.mjs.map +2 -2
  91. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +4 -1
  92. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
  93. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +4 -1
  94. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
  95. package/dist-esm/lib/hooks/useSelectionEvents.mjs +6 -5
  96. package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +2 -2
  97. package/dist-esm/lib/license/LicenseManager.mjs +141 -54
  98. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  99. package/dist-esm/lib/license/LicenseProvider.mjs +39 -2
  100. package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
  101. package/dist-esm/lib/license/Watermark.mjs +70 -8
  102. package/dist-esm/lib/license/Watermark.mjs.map +3 -3
  103. package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
  104. package/dist-esm/lib/primitives/Box.mjs +4 -1
  105. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  106. package/dist-esm/lib/primitives/Vec.mjs +0 -4
  107. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  108. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +53 -21
  109. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  110. package/dist-esm/lib/primitives/geometry/Group2d.mjs +8 -1
  111. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  112. package/dist-esm/lib/utils/dom.mjs +12 -1
  113. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  114. package/dist-esm/lib/utils/getPointerInfo.mjs +2 -2
  115. package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
  116. package/dist-esm/lib/utils/reparenting.mjs +3 -40
  117. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  118. package/dist-esm/version.mjs +3 -3
  119. package/dist-esm/version.mjs.map +1 -1
  120. package/editor.css +16 -3
  121. package/package.json +7 -7
  122. package/src/index.ts +4 -9
  123. package/src/lib/TldrawEditor.tsx +9 -16
  124. package/src/lib/components/Shape.tsx +6 -12
  125. package/src/lib/components/default-components/DefaultCanvas.tsx +12 -23
  126. package/src/lib/editor/Editor.test.ts +96 -0
  127. package/src/lib/editor/Editor.ts +75 -175
  128. package/src/lib/editor/derivations/notVisibleShapes.ts +6 -0
  129. package/src/lib/editor/derivations/parentsToChildren.ts +1 -1
  130. package/src/lib/editor/managers/FontManager/FontManager.test.ts +14 -4
  131. package/src/lib/editor/shapes/BaseBoxShapeUtil.tsx +2 -2
  132. package/src/lib/editor/shapes/ShapeUtil.ts +51 -8
  133. package/src/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.ts +2 -1
  134. package/src/lib/editor/types/misc-types.ts +0 -6
  135. package/src/lib/exports/getSvgJsx.test.ts +874 -0
  136. package/src/lib/exports/getSvgJsx.tsx +76 -19
  137. package/src/lib/hooks/useCanvasEvents.ts +23 -17
  138. package/src/lib/hooks/useDocumentEvents.ts +11 -6
  139. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +2 -2
  140. package/src/lib/hooks/useGestureEvents.ts +2 -2
  141. package/src/lib/hooks/useHandleEvents.ts +9 -4
  142. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +4 -1
  143. package/src/lib/hooks/usePassThroughWheelEvents.ts +6 -1
  144. package/src/lib/hooks/useSelectionEvents.ts +6 -5
  145. package/src/lib/license/LicenseManager.test.ts +721 -382
  146. package/src/lib/license/LicenseManager.ts +201 -58
  147. package/src/lib/license/LicenseProvider.tsx +74 -2
  148. package/src/lib/license/Watermark.tsx +75 -8
  149. package/src/lib/license/useLicenseManagerState.ts +2 -2
  150. package/src/lib/primitives/Box.test.ts +126 -0
  151. package/src/lib/primitives/Box.ts +10 -1
  152. package/src/lib/primitives/Vec.ts +0 -5
  153. package/src/lib/primitives/geometry/Geometry2d.test.ts +420 -0
  154. package/src/lib/primitives/geometry/Geometry2d.ts +78 -21
  155. package/src/lib/primitives/geometry/Group2d.ts +10 -1
  156. package/src/lib/test/InFrontOfTheCanvas.test.tsx +187 -0
  157. package/src/lib/utils/dom.test.ts +94 -0
  158. package/src/lib/utils/dom.ts +38 -1
  159. package/src/lib/utils/getPointerInfo.ts +2 -1
  160. package/src/lib/utils/reparenting.ts +3 -69
  161. package/src/version.ts +3 -3
  162. package/dist-cjs/lib/utils/nearestMultiple.js +0 -34
  163. package/dist-cjs/lib/utils/nearestMultiple.js.map +0 -7
  164. package/dist-esm/lib/utils/nearestMultiple.mjs +0 -14
  165. package/dist-esm/lib/utils/nearestMultiple.mjs.map +0 -7
  166. package/src/lib/utils/nearestMultiple.ts +0 -13
@@ -55,7 +55,6 @@ import {
55
55
  TLStore,
56
56
  TLStoreSnapshot,
57
57
  TLUnknownBinding,
58
- TLUnknownShape,
59
58
  TLVideoAsset,
60
59
  createBindingId,
61
60
  createShapeId,
@@ -116,7 +115,6 @@ import {
116
115
  } from '../constants'
117
116
  import { exportToSvg } from '../exports/exportToSvg'
118
117
  import { getSvgAsImage } from '../exports/getSvgAsImage'
119
- import { tlenv } from '../globals/environment'
120
118
  import { tlmenus } from '../globals/menus'
121
119
  import { tltime } from '../globals/time'
122
120
  import { TldrawOptions, defaultTldrawOptions } from '../options'
@@ -244,16 +242,6 @@ export interface TLEditorOptions {
244
242
  options?: Partial<TldrawOptions>
245
243
  licenseKey?: string
246
244
  fontAssetUrls?: { [key: string]: string | undefined }
247
- /**
248
- * A predicate that should return true if the given shape should be hidden.
249
- *
250
- * @deprecated Use {@link Editor#getShapeVisibility} instead.
251
- *
252
- * @param shape - The shape to check.
253
- * @param editor - The editor instance.
254
- */
255
- isShapeHidden?(shape: TLShape, editor: Editor): boolean
256
-
257
245
  /**
258
246
  * Provides a way to hide shapes.
259
247
  *
@@ -309,21 +297,12 @@ export class Editor extends EventEmitter<TLEventMap> {
309
297
  autoFocus,
310
298
  inferDarkMode,
311
299
  options,
312
- // eslint-disable-next-line @typescript-eslint/no-deprecated
313
- isShapeHidden,
314
300
  getShapeVisibility,
315
301
  fontAssetUrls,
316
302
  }: TLEditorOptions) {
317
303
  super()
318
- assert(
319
- !(isShapeHidden && getShapeVisibility),
320
- 'Cannot use both isShapeHidden and getShapeVisibility'
321
- )
322
304
 
323
- this._getShapeVisibility = isShapeHidden
324
- ? // eslint-disable-next-line @typescript-eslint/no-deprecated
325
- (shape: TLShape, editor: Editor) => (isShapeHidden(shape, editor) ? 'hidden' : 'inherit')
326
- : getShapeVisibility
305
+ this._getShapeVisibility = getShapeVisibility
327
306
 
328
307
  this.options = { ...defaultTldrawOptions, ...options }
329
308
 
@@ -907,14 +886,6 @@ export class Editor extends EventEmitter<TLEventMap> {
907
886
  */
908
887
  readonly fonts: FontManager
909
888
 
910
- /**
911
- * A manager for the editor's environment.
912
- *
913
- * @deprecated This is deprecated and will be removed in a future version. Use the `tlenv` global export instead.
914
- * @public
915
- */
916
- readonly environment = tlenv
917
-
918
889
  /**
919
890
  * A manager for the editor's scribbles.
920
891
  *
@@ -974,7 +945,7 @@ export class Editor extends EventEmitter<TLEventMap> {
974
945
  *
975
946
  * @public
976
947
  */
977
- shapeUtils: { readonly [K in string]?: ShapeUtil<TLUnknownShape> }
948
+ shapeUtils: { readonly [K in string]?: ShapeUtil<TLShape> }
978
949
 
979
950
  styleProps: { [key: string]: Map<StyleProp<any>, string> }
980
951
 
@@ -993,8 +964,8 @@ export class Editor extends EventEmitter<TLEventMap> {
993
964
  *
994
965
  * @public
995
966
  */
996
- getShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): ShapeUtil<S>
997
- getShapeUtil<S extends TLUnknownShape>(type: S['type']): ShapeUtil<S>
967
+ getShapeUtil<S extends TLShape>(shape: S | TLShapePartial<S>): ShapeUtil<S>
968
+ getShapeUtil<S extends TLShape>(type: S['type']): ShapeUtil<S>
998
969
  getShapeUtil<T extends ShapeUtil>(type: T extends ShapeUtil<infer R> ? R['type'] : string): T
999
970
  getShapeUtil(arg: string | { type: string }) {
1000
971
  const type = typeof arg === 'string' ? arg : arg.type
@@ -1008,8 +979,8 @@ export class Editor extends EventEmitter<TLEventMap> {
1008
979
  *
1009
980
  * @param shape - A shape, shape partial, or shape type.
1010
981
  */
1011
- hasShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): boolean
1012
- hasShapeUtil<S extends TLUnknownShape>(type: S['type']): boolean
982
+ hasShapeUtil(shape: TLShape | TLShapePartial<TLShape>): boolean
983
+ hasShapeUtil(type: TLShape['type']): boolean
1013
984
  hasShapeUtil<T extends ShapeUtil>(
1014
985
  type: T extends ShapeUtil<infer R> ? R['type'] : string
1015
986
  ): boolean
@@ -1119,35 +1090,6 @@ export class Editor extends EventEmitter<TLEventMap> {
1119
1090
  return this.history.getNumRedos() > 0
1120
1091
  }
1121
1092
 
1122
- /**
1123
- * Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
1124
- * any redos.
1125
- *
1126
- * @example
1127
- * ```ts
1128
- * editor.mark()
1129
- * editor.mark('flip shapes')
1130
- * ```
1131
- *
1132
- * @param markId - The mark's id, usually the reason for adding the mark.
1133
- *
1134
- * @public
1135
- * @deprecated use {@link Editor.markHistoryStoppingPoint} instead
1136
- */
1137
- mark(markId?: string): this {
1138
- if (typeof markId === 'string') {
1139
- console.warn(
1140
- `[tldraw] \`editor.history.mark("${markId}")\` is deprecated. Please use \`const myMarkId = editor.markHistoryStoppingPoint()\` instead.`
1141
- )
1142
- } else {
1143
- console.warn(
1144
- '[tldraw] `editor.mark()` is deprecated. Use `editor.markHistoryStoppingPoint()` instead.'
1145
- )
1146
- }
1147
- this.history._mark(markId ?? uniqueId())
1148
- return this
1149
- }
1150
-
1151
1093
  /**
1152
1094
  * Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
1153
1095
  * any redos. You typically want to do this just before a user interaction begins or is handled.
@@ -1272,13 +1214,6 @@ export class Editor extends EventEmitter<TLEventMap> {
1272
1214
  return this
1273
1215
  }
1274
1216
 
1275
- /**
1276
- * @deprecated Use `Editor.run` instead.
1277
- */
1278
- batch(fn: () => void, opts?: TLEditorRunOptions): this {
1279
- return this.run(fn, opts)
1280
- }
1281
-
1282
1217
  /* --------------------- Errors --------------------- */
1283
1218
 
1284
1219
  /** @internal */
@@ -1580,54 +1515,6 @@ export class Editor extends EventEmitter<TLEventMap> {
1580
1515
 
1581
1516
  menus = tlmenus.forContext(this.contextId)
1582
1517
 
1583
- /**
1584
- * @deprecated Use `editor.menus.getOpenMenus` instead.
1585
- *
1586
- * @public
1587
- */
1588
- @computed getOpenMenus(): string[] {
1589
- return this.menus.getOpenMenus()
1590
- }
1591
-
1592
- /**
1593
- * @deprecated Use `editor.menus.addOpenMenu` instead.
1594
- *
1595
- * @public
1596
- */
1597
- addOpenMenu(id: string): this {
1598
- this.menus.addOpenMenu(id)
1599
- return this
1600
- }
1601
-
1602
- /**
1603
- * @deprecated Use `editor.menus.deleteOpenMenu` instead.
1604
- *
1605
- * @public
1606
- */
1607
- deleteOpenMenu(id: string): this {
1608
- this.menus.deleteOpenMenu(id)
1609
- return this
1610
- }
1611
-
1612
- /**
1613
- * @deprecated Use `editor.menus.clearOpenMenus` instead.
1614
- *
1615
- * @public
1616
- */
1617
- clearOpenMenus(): this {
1618
- this.menus.clearOpenMenus()
1619
- return this
1620
- }
1621
-
1622
- /**
1623
- * @deprecated Use `editor.menus.hasAnyOpenMenus` instead.
1624
- *
1625
- * @public
1626
- */
1627
- @computed getIsMenuOpen(): boolean {
1628
- return this.menus.hasAnyOpenMenus()
1629
- }
1630
-
1631
1518
  /* --------------------- Cursor --------------------- */
1632
1519
 
1633
1520
  /**
@@ -4792,8 +4679,10 @@ export class Editor extends EventEmitter<TLEventMap> {
4792
4679
  return this.store.createComputedCache<Box, TLShape>('pageBoundsCache', (shape) => {
4793
4680
  const pageTransform = this.getShapePageTransform(shape)
4794
4681
  if (!pageTransform) return undefined
4795
- const geometry = this.getShapeGeometry(shape)
4796
- return Box.FromPoints(pageTransform.applyToPoints(geometry.vertices))
4682
+
4683
+ return Box.FromPoints(
4684
+ pageTransform.applyToPoints(this.getShapeGeometry(shape).boundsVertices)
4685
+ )
4797
4686
  })
4798
4687
  }
4799
4688
 
@@ -4860,27 +4749,25 @@ export class Editor extends EventEmitter<TLEventMap> {
4860
4749
  return this.store.createComputedCache('pageMaskCache', (shape) => {
4861
4750
  if (isPageId(shape.parentId)) return undefined
4862
4751
 
4863
- const frameAncestors = this.getShapeAncestors(shape.id).filter((shape) =>
4864
- this.isShapeOfType<TLFrameShape>(shape, 'frame')
4865
- )
4866
-
4867
- if (frameAncestors.length === 0) return undefined
4868
-
4869
- const pageMask = frameAncestors
4870
- .map<Vec[] | undefined>((s) => {
4871
- // Apply the frame transform to the frame outline to get the frame outline in the current page space
4872
- const geometry = this.getShapeGeometry(s.id)
4873
- const pageTransform = this.getShapePageTransform(s.id)
4874
- return pageTransform.applyToPoints(geometry.vertices)
4875
- })
4876
- .reduce((acc, b) => {
4877
- if (!(b && acc)) return undefined
4878
- const intersection = intersectPolygonPolygon(acc, b)
4879
- if (intersection) {
4880
- return intersection.map(Vec.Cast)
4881
- }
4882
- return []
4883
- })
4752
+ const clipPaths: Vec[][] = []
4753
+ // Get all ancestors that can potentially clip this shape
4754
+ for (const ancestor of this.getShapeAncestors(shape.id)) {
4755
+ const util = this.getShapeUtil(ancestor)
4756
+ const clipPath = util.getClipPath?.(ancestor)
4757
+ if (!clipPath) continue
4758
+ if (util.shouldClipChild?.(shape) === false) continue
4759
+ const pageTransform = this.getShapePageTransform(ancestor.id)
4760
+ clipPaths.push(pageTransform.applyToPoints(clipPath))
4761
+ }
4762
+ if (clipPaths.length === 0) return undefined
4763
+
4764
+ const pageMask = clipPaths.reduce((acc, b) => {
4765
+ const intersection = intersectPolygonPolygon(acc, b)
4766
+ if (intersection) {
4767
+ return intersection.map(Vec.Cast)
4768
+ }
4769
+ return []
4770
+ })
4884
4771
 
4885
4772
  return pageMask
4886
4773
  })
@@ -5503,15 +5390,9 @@ export class Editor extends EventEmitter<TLEventMap> {
5503
5390
  *
5504
5391
  * @public
5505
5392
  */
5506
- isShapeOfType<T extends TLUnknownShape>(shape: TLUnknownShape, type: T['type']): shape is T
5507
- isShapeOfType<T extends TLUnknownShape>(
5508
- shapeId: TLUnknownShape['id'],
5509
- type: T['type']
5510
- ): shapeId is T['id']
5511
- isShapeOfType<T extends TLUnknownShape>(
5512
- arg: TLUnknownShape | TLUnknownShape['id'],
5513
- type: T['type']
5514
- ) {
5393
+ isShapeOfType<T extends TLShape>(shape: TLShape, type: T['type']): shape is T
5394
+ isShapeOfType<T extends TLShape = TLShape>(shapeId: TLShapeId, type: T['type']): boolean
5395
+ isShapeOfType(arg: TLShape | TLShapeId, type: TLShape['type']) {
5515
5396
  const shape = typeof arg === 'string' ? this.getShape(arg) : arg
5516
5397
  if (!shape) return false
5517
5398
  return shape.type === type
@@ -5841,11 +5722,6 @@ export class Editor extends EventEmitter<TLEventMap> {
5841
5722
  return shapeIds
5842
5723
  }
5843
5724
 
5844
- /** @deprecated Use {@link Editor.getDraggingOverShape} instead */
5845
- getDroppingOverShape(point: Vec, droppingShapes: TLShape[]): TLShape | undefined {
5846
- return this.getDraggingOverShape(point, droppingShapes)
5847
- }
5848
-
5849
5725
  /**
5850
5726
  * Get the shape that some shapes should be dropped on at a given point.
5851
5727
  *
@@ -7771,9 +7647,7 @@ export class Editor extends EventEmitter<TLEventMap> {
7771
7647
  *
7772
7648
  * @public
7773
7649
  */
7774
- canCreateShape<T extends TLUnknownShape>(
7775
- shape: OptionalKeys<TLShapePartial<T>, 'id'> | T['id']
7776
- ): boolean {
7650
+ canCreateShape(shape: OptionalKeys<TLShapePartial<TLShape>, 'id'> | TLShape['id']): boolean {
7777
7651
  return this.canCreateShapes([shape])
7778
7652
  }
7779
7653
 
@@ -7784,8 +7658,8 @@ export class Editor extends EventEmitter<TLEventMap> {
7784
7658
  *
7785
7659
  * @public
7786
7660
  */
7787
- canCreateShapes<T extends TLUnknownShape>(
7788
- shapes: (T['id'] | OptionalKeys<TLShapePartial<T>, 'id'>)[]
7661
+ canCreateShapes(
7662
+ shapes: (TLShape['id'] | OptionalKeys<TLShapePartial<TLShape>, 'id'>)[]
7789
7663
  ): boolean {
7790
7664
  return shapes.length + this.getCurrentPageShapeIds().size <= this.options.maxShapesPerPage
7791
7665
  }
@@ -7803,7 +7677,7 @@ export class Editor extends EventEmitter<TLEventMap> {
7803
7677
  *
7804
7678
  * @public
7805
7679
  */
7806
- createShape<T extends TLUnknownShape>(shape: OptionalKeys<TLShapePartial<T>, 'id'>): this {
7680
+ createShape<TShape extends TLShape>(shape: OptionalKeys<TLShapePartial<TShape>, 'id'>): this {
7807
7681
  this.createShapes([shape])
7808
7682
  return this
7809
7683
  }
@@ -7821,7 +7695,9 @@ export class Editor extends EventEmitter<TLEventMap> {
7821
7695
  *
7822
7696
  * @public
7823
7697
  */
7824
- createShapes<T extends TLUnknownShape>(shapes: OptionalKeys<TLShapePartial<T>, 'id'>[]): this {
7698
+ createShapes<TShape extends TLShape = TLShape>(
7699
+ shapes: OptionalKeys<TLShapePartial<TShape>, 'id'>[]
7700
+ ): this {
7825
7701
  if (!Array.isArray(shapes)) {
7826
7702
  throw Error('Editor.createShapes: must provide an array of shapes or shape partials')
7827
7703
  }
@@ -8318,7 +8194,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8318
8194
  *
8319
8195
  * @public
8320
8196
  */
8321
- updateShape<T extends TLUnknownShape>(partial: TLShapePartial<T> | null | undefined) {
8197
+ updateShape<T extends TLShape = TLShape>(partial: TLShapePartial<T> | null | undefined) {
8322
8198
  this.updateShapes([partial])
8323
8199
  return this
8324
8200
  }
@@ -8335,7 +8211,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8335
8211
  *
8336
8212
  * @public
8337
8213
  */
8338
- updateShapes<T extends TLUnknownShape>(partials: (TLShapePartial<T> | null | undefined)[]) {
8214
+ updateShapes<T extends TLShape>(partials: (TLShapePartial<T> | null | undefined)[]) {
8339
8215
  const compactedPartials: TLShapePartial<T>[] = Array(partials.length)
8340
8216
 
8341
8217
  for (let i = 0, n = partials.length; i < n; i++) {
@@ -8950,8 +8826,13 @@ export class Editor extends EventEmitter<TLEventMap> {
8950
8826
  * Handle external content, such as files, urls, embeds, or plain text which has been put into the app, for example by pasting external text or dropping external images onto canvas.
8951
8827
  *
8952
8828
  * @param info - Info about the external content.
8829
+ * @param opts - Options for handling external content, including force flag to bypass readonly checks.
8953
8830
  */
8954
- async putExternalContent<E>(info: TLExternalContent<E>): Promise<void> {
8831
+ async putExternalContent<E>(
8832
+ info: TLExternalContent<E>,
8833
+ opts = {} as { force?: boolean }
8834
+ ): Promise<void> {
8835
+ if (!opts.force && this.getIsReadonly()) return
8955
8836
  return this.externalContentHandlers[info.type]?.(info as any)
8956
8837
  }
8957
8838
 
@@ -8959,8 +8840,13 @@ export class Editor extends EventEmitter<TLEventMap> {
8959
8840
  * Handle replacing external content.
8960
8841
  *
8961
8842
  * @param info - Info about the external content.
8843
+ * @param opts - Options for handling external content, including force flag to bypass readonly checks.
8962
8844
  */
8963
- async replaceExternalContent<E>(info: TLExternalContent<E>): Promise<void> {
8845
+ async replaceExternalContent<E>(
8846
+ info: TLExternalContent<E>,
8847
+ opts = {} as { force?: boolean }
8848
+ ): Promise<void> {
8849
+ if (!opts.force && this.getIsReadonly()) return
8964
8850
  return this.externalContentHandlers[info.type]?.(info as any)
8965
8851
  }
8966
8852
 
@@ -9461,13 +9347,6 @@ export class Editor extends EventEmitter<TLEventMap> {
9461
9347
  }
9462
9348
  }
9463
9349
 
9464
- /** @deprecated Use {@link Editor.getSvgString} or {@link Editor.getSvgElement} instead. */
9465
- async getSvg(shapes: TLShapeId[] | TLShape[], opts: TLSvgExportOptions = {}) {
9466
- const result = await this.getSvgElement(shapes, opts)
9467
- if (!result) return undefined
9468
- return result.svg
9469
- }
9470
-
9471
9350
  /**
9472
9351
  * Get an exported image of the given shapes.
9473
9352
  *
@@ -9519,6 +9398,24 @@ export class Editor extends EventEmitter<TLEventMap> {
9519
9398
  }
9520
9399
  }
9521
9400
 
9401
+ /**
9402
+ * Get an exported image of the given shapes as a data URL.
9403
+ *
9404
+ * @param shapes - The shapes (or shape ids) to export.
9405
+ * @param opts - Options for the export.
9406
+ *
9407
+ * @returns A data URL of the image.
9408
+ * @public
9409
+ */
9410
+ async toImageDataUrl(shapes: TLShapeId[] | TLShape[], opts: TLImageExportOptions = {}) {
9411
+ const { blob, width, height } = await this.toImage(shapes, opts)
9412
+ return {
9413
+ url: await FileHelpers.blobToDataUrl(blob),
9414
+ width,
9415
+ height,
9416
+ }
9417
+ }
9418
+
9522
9419
  /* --------------------- Events --------------------- */
9523
9420
 
9524
9421
  /**
@@ -10750,7 +10647,10 @@ function alertMaxShapes(editor: Editor, pageId = editor.getCurrentPageId()) {
10750
10647
 
10751
10648
  function applyPartialToRecordWithProps<
10752
10649
  T extends UnknownRecord & { type: string; props: object; meta: object },
10753
- >(prev: T, partial?: Partial<T> & { props?: Partial<T['props']> }): T {
10650
+ >(
10651
+ prev: T,
10652
+ partial?: T extends T ? Omit<Partial<T>, 'props'> & { props?: Partial<T['props']> } : never
10653
+ ): T {
10754
10654
  if (!partial) return prev
10755
10655
  let next = null as null | T
10756
10656
  const entries = Object.entries(partial)
@@ -7,6 +7,12 @@ function fromScratch(editor: Editor): Set<TLShapeId> {
7
7
  const viewportPageBounds = editor.getViewportPageBounds()
8
8
  const notVisibleShapes = new Set<TLShapeId>()
9
9
  shapesIds.forEach((id) => {
10
+ const shape = editor.getShape(id)
11
+ if (!shape) return
12
+
13
+ const canCull = editor.getShapeUtil(shape.type).canCull(shape)
14
+ if (!canCull) return
15
+
10
16
  // If the shape is fully outside of the viewport page bounds, add it to the set.
11
17
  // We'll ignore masks here, since they're more expensive to compute and the overhead is not worth it.
12
18
  const pageBounds = editor.getShapePageBounds(id)
@@ -11,7 +11,7 @@ function fromScratch(
11
11
  ) {
12
12
  const result: ParentShapeIdsToChildShapeIds = {}
13
13
  const shapeIds = shapeIdsQuery.get()
14
- const shapes = Array(shapeIds.size) as TLShape[]
14
+ const shapes = Array<TLShape>(shapeIds.size)
15
15
  shapeIds.forEach((id) => shapes.push(store.get(id)!))
16
16
 
17
17
  // Sort the shapes by index
@@ -1,4 +1,5 @@
1
- import { TLShape, TLShapeId, createShapeId } from '@tldraw/tlschema'
1
+ import { TLParentId, TLShape, TLShapeId, createShapeId, toRichText } from '@tldraw/tlschema'
2
+ import { IndexKey } from '@tldraw/utils'
2
3
  import { Mock, Mocked, vi } from 'vitest'
3
4
  import { Editor } from '../../Editor'
4
5
  import { FontManager, TLFontFace } from './FontManager'
@@ -41,12 +42,21 @@ describe('FontManager', () => {
41
42
  x: 0,
42
43
  y: 0,
43
44
  rotation: 0,
44
- index: 'a1' as any,
45
- parentId: 'page:page' as any,
45
+ index: 'a1' as IndexKey,
46
+ parentId: 'page:page' as TLParentId,
46
47
  opacity: 1,
47
48
  isLocked: false,
48
49
  meta: {},
49
- props: {},
50
+ props: {
51
+ color: 'black',
52
+ size: 'xl',
53
+ font: 'serif',
54
+ textAlign: 'middle',
55
+ w: 100,
56
+ richText: toRichText('❤️'),
57
+ scale: 2,
58
+ autoSize: true,
59
+ },
50
60
  typeName: 'shape' as const,
51
61
  })
52
62
 
@@ -1,4 +1,4 @@
1
- import { TLBaseShape } from '@tldraw/tlschema'
1
+ import { TLShape } from '@tldraw/tlschema'
2
2
  import { lerp } from '@tldraw/utils'
3
3
  import { Geometry2d } from '../../primitives/geometry/Geometry2d'
4
4
  import { Rectangle2d } from '../../primitives/geometry/Rectangle2d'
@@ -7,7 +7,7 @@ import { ShapeUtil, TLResizeInfo } from './ShapeUtil'
7
7
  import { resizeBox } from './shared/resizeBox'
8
8
 
9
9
  /** @public */
10
- export type TLBaseBoxShape = TLBaseShape<string, { w: number; h: number }>
10
+ export type TLBaseBoxShape = Extract<TLShape, { props: { w: number; h: number } }>
11
11
 
12
12
  /** @public */
13
13
  export abstract class BaseBoxShapeUtil<Shape extends TLBaseBoxShape> extends ShapeUtil<Shape> {
@@ -26,10 +26,7 @@ import { TLClickEventInfo } from '../types/event-types'
26
26
  import { TLResizeHandle } from '../types/selection-types'
27
27
 
28
28
  /** @public */
29
- export interface TLShapeUtilConstructor<
30
- T extends TLUnknownShape,
31
- U extends ShapeUtil<T> = ShapeUtil<T>,
32
- > {
29
+ export interface TLShapeUtilConstructor<T extends TLShape, U extends ShapeUtil<T> = ShapeUtil<T>> {
33
30
  new (editor: Editor): U
34
31
  type: T['type']
35
32
  props?: RecordProps<T>
@@ -42,11 +39,11 @@ export interface TLShapeUtilConstructor<
42
39
  *
43
40
  * @public
44
41
  */
45
- export interface TLShapeUtilCanBindOpts<Shape extends TLUnknownShape = TLUnknownShape> {
42
+ export interface TLShapeUtilCanBindOpts<Shape extends TLShape = TLShape> {
46
43
  /** The type of shape referenced by the `fromId` of the binding. */
47
- fromShapeType: string
44
+ fromShapeType: TLShape['type']
48
45
  /** The type of shape referenced by the `toId` of the binding. */
49
- toShapeType: string
46
+ toShapeType: TLShape['type']
50
47
  /** The type of binding. */
51
48
  bindingType: string
52
49
  }
@@ -79,7 +76,7 @@ export interface TLShapeUtilCanvasSvgDef {
79
76
  }
80
77
 
81
78
  /** @public */
82
- export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
79
+ export abstract class ShapeUtil<Shape extends TLShape = TLShape> {
83
80
  /** Configure this shape utils {@link ShapeUtil.options | `options`}. */
84
81
  static configure<T extends TLShapeUtilConstructor<any, any>>(
85
82
  this: T,
@@ -283,6 +280,17 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
283
280
  return true
284
281
  }
285
282
 
283
+ /**
284
+ * Whether this shape can be culled. By default, shapes are culled for
285
+ * performance reasons when they are outside of the viewport. Culled shapes are still rendered
286
+ * to the DOM, but have their `display` property set to `none`.
287
+ *
288
+ * @param shape - The shape.
289
+ */
290
+ canCull(_shape: Shape): boolean {
291
+ return true
292
+ }
293
+
286
294
  /**
287
295
  * Does this shape provide a background for its children? If this is true,
288
296
  * then any children with a `renderBackground` method will have their
@@ -296,6 +304,27 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
296
304
  return false
297
305
  }
298
306
 
307
+ /**
308
+ * Get the clip path to apply to this shape's children.
309
+ *
310
+ * @param shape - The shape to get the clip path for
311
+ * @returns Array of points defining the clipping polygon in local coordinates, or undefined if no clipping
312
+ * @public
313
+ */
314
+ getClipPath?(shape: Shape): Vec[] | undefined
315
+
316
+ /**
317
+ * Whether a specific child shape should be clipped by this shape.
318
+ * Only called if getClipPath returns a valid polygon.
319
+ *
320
+ * If not defined, the default behavior is to clip all children.
321
+ *
322
+ * @param child - The child shape to check
323
+ * @returns boolean indicating if this child should be clipped
324
+ * @public
325
+ */
326
+ shouldClipChild?(child: TLShape): boolean
327
+
299
328
  /**
300
329
  * Whether the shape should hide its resize handles when selected.
301
330
  *
@@ -341,6 +370,20 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
341
370
  return false
342
371
  }
343
372
 
373
+ /**
374
+ * By default, the bounds of an image export are the bounds of all the shapes it contains, plus
375
+ * some padding. If an export includes a shape where `isExportBoundsContainer` is true, then the
376
+ * padding is skipped _if the bounds of that shape contains all the other shapes_. This is
377
+ * useful in cases like annotating on top of an image, where you usually want to avoid extra
378
+ * padding around the image if you don't need it.
379
+ *
380
+ * @param _shape - The shape to check
381
+ * @returns True if this shape should be treated as an export bounds container
382
+ */
383
+ isExportBoundsContainer(_shape: Shape): boolean {
384
+ return false
385
+ }
386
+
344
387
  /**
345
388
  * Get a JSX element for the shape (as an HTML element) to be rendered as part of the canvas background - behind any other shape content.
346
389
  *
@@ -1,4 +1,5 @@
1
1
  import { TLShape } from '@tldraw/tlschema'
2
+ import { TLBaseBoxShape } from '../../shapes/BaseBoxShapeUtil'
2
3
  import { StateNode, TLStateNodeConstructor } from '../StateNode'
3
4
  import { Idle } from './children/Idle'
4
5
  import { Pointing } from './children/Pointing'
@@ -11,7 +12,7 @@ export abstract class BaseBoxShapeTool extends StateNode {
11
12
  return [Idle, Pointing]
12
13
  }
13
14
 
14
- abstract override shapeType: string
15
+ abstract override shapeType: TLBaseBoxShape['type']
15
16
 
16
17
  onCreate?(_shape: TLShape | null): void | null
17
18
  }
@@ -72,12 +72,6 @@ export interface TLImageExportOptions extends TLSvgExportOptions {
72
72
  format?: TLExportType
73
73
  }
74
74
 
75
- /**
76
- * @public
77
- * @deprecated use {@link TLImageExportOptions} instead
78
- */
79
- export type TLSvgOptions = TLImageExportOptions
80
-
81
75
  /** @public */
82
76
  export interface TLCameraMoveOptions {
83
77
  /** Whether to move the camera immediately, rather than on the next tick. */