@tldraw/editor 4.2.0-next.f100cedfc45b → 4.3.0-canary.03ae87dcc44b

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 (58) hide show
  1. package/dist-cjs/index.d.ts +59 -37
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/editor/Editor.js +11 -18
  4. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  5. package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +2 -2
  6. package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
  7. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
  8. package/dist-cjs/lib/editor/shapes/BaseBoxShapeUtil.js.map +1 -1
  9. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  10. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  11. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.js.map +2 -2
  12. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
  13. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  14. package/dist-cjs/lib/hooks/useCanvasEvents.js +4 -3
  15. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  16. package/dist-cjs/lib/license/Watermark.js +8 -4
  17. package/dist-cjs/lib/license/Watermark.js.map +2 -2
  18. package/dist-cjs/lib/utils/reparenting.js.map +2 -2
  19. package/dist-cjs/version.js +3 -3
  20. package/dist-cjs/version.js.map +1 -1
  21. package/dist-esm/index.d.mts +59 -37
  22. package/dist-esm/index.mjs +1 -1
  23. package/dist-esm/lib/editor/Editor.mjs +11 -18
  24. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  25. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +2 -2
  26. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
  27. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
  28. package/dist-esm/lib/editor/shapes/BaseBoxShapeUtil.mjs.map +1 -1
  29. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  30. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  31. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.mjs.map +2 -2
  32. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
  33. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  34. package/dist-esm/lib/hooks/useCanvasEvents.mjs +4 -3
  35. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  36. package/dist-esm/lib/license/Watermark.mjs +8 -4
  37. package/dist-esm/lib/license/Watermark.mjs.map +2 -2
  38. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  39. package/dist-esm/version.mjs +3 -3
  40. package/dist-esm/version.mjs.map +1 -1
  41. package/package.json +10 -10
  42. package/src/lib/editor/Editor.test.ts +278 -10
  43. package/src/lib/editor/Editor.ts +92 -65
  44. package/src/lib/editor/bindings/BindingUtil.ts +15 -9
  45. package/src/lib/editor/derivations/bindingsIndex.ts +2 -2
  46. package/src/lib/editor/managers/FontManager/FontManager.test.ts +14 -4
  47. package/src/lib/editor/managers/SnapManager/SnapManager.ts +3 -3
  48. package/src/lib/editor/shapes/BaseBoxShapeUtil.tsx +2 -2
  49. package/src/lib/editor/shapes/ShapeUtil.ts +5 -8
  50. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -3
  51. package/src/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.ts +2 -1
  52. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +3 -3
  53. package/src/lib/exports/getSvgJsx.test.ts +10 -19
  54. package/src/lib/exports/getSvgJsx.tsx +2 -5
  55. package/src/lib/hooks/useCanvasEvents.ts +4 -3
  56. package/src/lib/license/Watermark.tsx +8 -5
  57. package/src/lib/utils/reparenting.ts +5 -5
  58. package/src/version.ts +3 -3
@@ -21,7 +21,6 @@ import {
21
21
  PageRecordType,
22
22
  StyleProp,
23
23
  StylePropValue,
24
- TLArrowShape,
25
24
  TLAsset,
26
25
  TLAssetId,
27
26
  TLAssetPartial,
@@ -30,12 +29,12 @@ import {
30
29
  TLBindingId,
31
30
  TLBindingUpdate,
32
31
  TLCamera,
32
+ TLCreateShapePartial,
33
33
  TLCursor,
34
34
  TLCursorType,
35
35
  TLDOCUMENT_ID,
36
36
  TLDocument,
37
37
  TLFrameShape,
38
- TLGeoShape,
39
38
  TLGroupShape,
40
39
  TLHandle,
41
40
  TLINSTANCE_ID,
@@ -43,7 +42,6 @@ import {
43
42
  TLInstance,
44
43
  TLInstancePageState,
45
44
  TLInstancePresence,
46
- TLNoteShape,
47
45
  TLPOINTER_ID,
48
46
  TLPage,
49
47
  TLPageId,
@@ -54,8 +52,6 @@ import {
54
52
  TLShapePartial,
55
53
  TLStore,
56
54
  TLStoreSnapshot,
57
- TLUnknownBinding,
58
- TLUnknownShape,
59
55
  TLVideoAsset,
60
56
  createBindingId,
61
57
  createShapeId,
@@ -447,7 +443,7 @@ export class Editor extends EventEmitter<TLEventMap> {
447
443
  let deletedBindings = new Map<TLBindingId, BindingOnDeleteOptions<any>>()
448
444
  const deletedShapeIds = new Set<TLShapeId>()
449
445
  const invalidParents = new Set<TLShapeId>()
450
- let invalidBindingTypes = new Set<string>()
446
+ let invalidBindingTypes = new Set<TLBinding['type']>()
451
447
  this.disposables.add(
452
448
  this.sideEffects.registerOperationCompleteHandler(() => {
453
449
  // this needs to be cleared here because further effects may delete more shapes
@@ -710,7 +706,7 @@ export class Editor extends EventEmitter<TLEventMap> {
710
706
  if (filtered.length > 0) {
711
707
  const commonGroupAncestor = this.findCommonAncestor(
712
708
  compact(filtered.map((id) => this.getShape(id))),
713
- (shape) => this.isShapeOfType<TLGroupShape>(shape, 'group')
709
+ (shape) => this.isShapeOfType(shape, 'group')
714
710
  )
715
711
 
716
712
  if (commonGroupAncestor) {
@@ -842,14 +838,16 @@ export class Editor extends EventEmitter<TLEventMap> {
842
838
  * after the editor has already been initialized.
843
839
  *
844
840
  * @param Tool - The tool to set.
841
+ * @param parent - The parent state node to set the tool on.
845
842
  *
846
843
  * @public
847
844
  */
848
- setTool(Tool: TLStateNodeConstructor) {
849
- if (hasOwnProperty(this.root.children!, Tool.id)) {
845
+ setTool(Tool: TLStateNodeConstructor, parent?: StateNode) {
846
+ parent ??= this.root
847
+ if (hasOwnProperty(parent.children!, Tool.id)) {
850
848
  throw Error(`Can't override tool with id "${Tool.id}"`)
851
849
  }
852
- this.root.children![Tool.id] = new Tool(this, this.root)
850
+ parent.children![Tool.id] = new Tool(this, parent)
853
851
  }
854
852
 
855
853
  /**
@@ -857,12 +855,14 @@ export class Editor extends EventEmitter<TLEventMap> {
857
855
  * after the editor has already been initialized.
858
856
  *
859
857
  * @param Tool - The tool to delete.
858
+ * @param parent - The parent state node to remove the tool from.
860
859
  *
861
860
  * @public
862
861
  */
863
- removeTool(Tool: TLStateNodeConstructor) {
864
- if (hasOwnProperty(this.root.children!, Tool.id)) {
865
- delete this.root.children![Tool.id]
862
+ removeTool(Tool: TLStateNodeConstructor, parent?: StateNode) {
863
+ parent ??= this.root
864
+ if (hasOwnProperty(parent.children!, Tool.id)) {
865
+ delete parent.children![Tool.id]
866
866
  }
867
867
  }
868
868
 
@@ -978,7 +978,7 @@ export class Editor extends EventEmitter<TLEventMap> {
978
978
  *
979
979
  * @public
980
980
  */
981
- shapeUtils: { readonly [K in string]?: ShapeUtil<TLUnknownShape> }
981
+ shapeUtils: { readonly [K in string]?: ShapeUtil<TLShape> }
982
982
 
983
983
  styleProps: { [key: string]: Map<StyleProp<any>, string> }
984
984
 
@@ -997,8 +997,8 @@ export class Editor extends EventEmitter<TLEventMap> {
997
997
  *
998
998
  * @public
999
999
  */
1000
- getShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): ShapeUtil<S>
1001
- getShapeUtil<S extends TLUnknownShape>(type: S['type']): ShapeUtil<S>
1000
+ getShapeUtil<K extends TLShape['type']>(type: K): ShapeUtil<Extract<TLShape, { type: K }>>
1001
+ getShapeUtil<S extends TLShape>(shape: S | TLShapePartial<S> | S['type']): ShapeUtil<S>
1002
1002
  getShapeUtil<T extends ShapeUtil>(type: T extends ShapeUtil<infer R> ? R['type'] : string): T
1003
1003
  getShapeUtil(arg: string | { type: string }) {
1004
1004
  const type = typeof arg === 'string' ? arg : arg.type
@@ -1012,8 +1012,8 @@ export class Editor extends EventEmitter<TLEventMap> {
1012
1012
  *
1013
1013
  * @param shape - A shape, shape partial, or shape type.
1014
1014
  */
1015
- hasShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): boolean
1016
- hasShapeUtil<S extends TLUnknownShape>(type: S['type']): boolean
1015
+ hasShapeUtil(shape: TLShape | TLShapePartial<TLShape>): boolean
1016
+ hasShapeUtil(type: TLShape['type']): boolean
1017
1017
  hasShapeUtil<T extends ShapeUtil>(
1018
1018
  type: T extends ShapeUtil<infer R> ? R['type'] : string
1019
1019
  ): boolean
@@ -1028,7 +1028,7 @@ export class Editor extends EventEmitter<TLEventMap> {
1028
1028
  *
1029
1029
  * @public
1030
1030
  */
1031
- bindingUtils: { readonly [K in string]?: BindingUtil<TLUnknownBinding> }
1031
+ bindingUtils: { readonly [K in string]?: BindingUtil<TLBinding> }
1032
1032
 
1033
1033
  /**
1034
1034
  * Get a binding util from a binding itself.
@@ -1045,8 +1045,8 @@ export class Editor extends EventEmitter<TLEventMap> {
1045
1045
  *
1046
1046
  * @public
1047
1047
  */
1048
- getBindingUtil<S extends TLUnknownBinding>(binding: S | { type: S['type'] }): BindingUtil<S>
1049
- getBindingUtil<S extends TLUnknownBinding>(type: S['type']): BindingUtil<S>
1048
+ getBindingUtil<K extends TLBinding['type']>(type: K): BindingUtil<Extract<TLBinding, { type: K }>>
1049
+ getBindingUtil<S extends TLBinding>(binding: S | { type: S['type'] }): BindingUtil<S>
1050
1050
  getBindingUtil<T extends BindingUtil>(
1051
1051
  type: T extends BindingUtil<infer R> ? R['type'] : string
1052
1052
  ): T
@@ -2216,7 +2216,7 @@ export class Editor extends EventEmitter<TLEventMap> {
2216
2216
  throw Error(`Editor.setFocusedGroup: Shape with id ${id} does not exist`)
2217
2217
  }
2218
2218
 
2219
- if (!this.isShapeOfType<TLGroupShape>(shape, 'group')) {
2219
+ if (!this.isShapeOfType(shape, 'group')) {
2220
2220
  throw Error(
2221
2221
  `Editor.setFocusedGroup: Cannot set focused group to shape of type ${shape.type}`
2222
2222
  )
@@ -2244,7 +2244,7 @@ export class Editor extends EventEmitter<TLEventMap> {
2244
2244
  if (focusedGroup) {
2245
2245
  // If we have a focused layer, look for an ancestor of the focused shape that is a group
2246
2246
  const match = this.findShapeAncestor(focusedGroup, (shape) =>
2247
- this.isShapeOfType<TLGroupShape>(shape, 'group')
2247
+ this.isShapeOfType(shape, 'group')
2248
2248
  )
2249
2249
  // If we have an ancestor that can become a focused layer, set it as the focused layer
2250
2250
  this.setFocusedGroup(match?.id ?? null)
@@ -5123,10 +5123,10 @@ export class Editor extends EventEmitter<TLEventMap> {
5123
5123
 
5124
5124
  // Check labels first
5125
5125
  if (
5126
- this.isShapeOfType<TLFrameShape>(shape, 'frame') ||
5127
- ((this.isShapeOfType<TLNoteShape>(shape, 'note') ||
5128
- this.isShapeOfType<TLArrowShape>(shape, 'arrow') ||
5129
- (this.isShapeOfType<TLGeoShape>(shape, 'geo') && shape.props.fill === 'none')) &&
5126
+ this.isShapeOfType(shape, 'frame') ||
5127
+ ((this.isShapeOfType(shape, 'note') ||
5128
+ this.isShapeOfType(shape, 'arrow') ||
5129
+ (this.isShapeOfType(shape, 'geo') && shape.props.fill === 'none')) &&
5130
5130
  this.getShapeUtil(shape).getText(shape)?.trim())
5131
5131
  ) {
5132
5132
  for (const childGeometry of (geometry as Group2d).children) {
@@ -5136,7 +5136,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5136
5136
  }
5137
5137
  }
5138
5138
 
5139
- if (this.isShapeOfType<TLFrameShape>(shape, 'frame')) {
5139
+ if (this.isShapeOfType(shape, 'frame')) {
5140
5140
  // On the rare case that we've hit a frame (not its label), test again hitInside to be forced true;
5141
5141
  // this prevents clicks from passing through the body of a frame to shapes behind it.
5142
5142
 
@@ -5417,7 +5417,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5417
5417
  *
5418
5418
  * @example
5419
5419
  * ```ts
5420
- * const isArrowShape = isShapeOfType<TLArrowShape>(someShape, 'arrow')
5420
+ * const isArrowShape = isShapeOfType(someShape, 'arrow')
5421
5421
  * ```
5422
5422
  *
5423
5423
  * @param util - the TLShapeUtil constructor to test against
@@ -5425,15 +5425,16 @@ export class Editor extends EventEmitter<TLEventMap> {
5425
5425
  *
5426
5426
  * @public
5427
5427
  */
5428
- isShapeOfType<T extends TLUnknownShape>(shape: TLUnknownShape, type: T['type']): shape is T
5429
- isShapeOfType<T extends TLUnknownShape>(
5430
- shapeId: TLUnknownShape['id'],
5431
- type: T['type']
5432
- ): shapeId is T['id']
5433
- isShapeOfType<T extends TLUnknownShape>(
5434
- arg: TLUnknownShape | TLUnknownShape['id'],
5428
+ isShapeOfType<K extends TLShape['type']>(
5429
+ shape: TLShape,
5430
+ type: K
5431
+ ): shape is Extract<TLShape, { type: K }>
5432
+ isShapeOfType<T extends TLShape>(
5433
+ shape: TLShape,
5435
5434
  type: T['type']
5436
- ) {
5435
+ ): shape is Extract<TLShape, { type: T['type'] }>
5436
+ isShapeOfType<T extends TLShape = TLShape>(shapeId: TLShapeId, type: T['type']): boolean
5437
+ isShapeOfType(arg: TLShape | TLShapeId, type: TLShape['type']) {
5437
5438
  const shape = typeof arg === 'string' ? this.getShape(arg) : arg
5438
5439
  if (!shape) return false
5439
5440
  return shape.type === type
@@ -5829,7 +5830,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5829
5830
 
5830
5831
  while (node) {
5831
5832
  if (
5832
- this.isShapeOfType<TLGroupShape>(node, 'group') &&
5833
+ this.isShapeOfType(node, 'group') &&
5833
5834
  focusedGroup?.id !== node.id &&
5834
5835
  !this.hasAncestor(focusedGroup, node.id) &&
5835
5836
  (filter?.(node) ?? true)
@@ -5871,7 +5872,15 @@ export class Editor extends EventEmitter<TLEventMap> {
5871
5872
  * Get all bindings of a certain type _from_ a particular shape. These are the bindings whose
5872
5873
  * `fromId` matched the shape's ID.
5873
5874
  */
5874
- getBindingsFromShape<Binding extends TLUnknownBinding = TLBinding>(
5875
+ getBindingsFromShape<K extends TLBinding['type']>(
5876
+ shape: TLShape | TLShapeId,
5877
+ type: K
5878
+ ): Extract<TLBinding, { type: K }>[]
5879
+ getBindingsFromShape<Binding extends TLBinding = TLBinding>(
5880
+ shape: TLShape | TLShapeId,
5881
+ type: Binding['type']
5882
+ ): Binding[]
5883
+ getBindingsFromShape<Binding extends TLBinding = TLBinding>(
5875
5884
  shape: TLShape | TLShapeId,
5876
5885
  type: Binding['type']
5877
5886
  ): Binding[] {
@@ -5885,7 +5894,15 @@ export class Editor extends EventEmitter<TLEventMap> {
5885
5894
  * Get all bindings of a certain type _to_ a particular shape. These are the bindings whose
5886
5895
  * `toId` matches the shape's ID.
5887
5896
  */
5888
- getBindingsToShape<Binding extends TLUnknownBinding = TLBinding>(
5897
+ getBindingsToShape<K extends TLBinding['type']>(
5898
+ shape: TLShape | TLShapeId,
5899
+ type: K
5900
+ ): Extract<TLBinding, { type: K }>[]
5901
+ getBindingsToShape<Binding extends TLBinding = TLBinding>(
5902
+ shape: TLShape | TLShapeId,
5903
+ type: Binding['type']
5904
+ ): Binding[]
5905
+ getBindingsToShape<Binding extends TLBinding = TLBinding>(
5889
5906
  shape: TLShape | TLShapeId,
5890
5907
  type: Binding['type']
5891
5908
  ): Binding[] {
@@ -5899,7 +5916,15 @@ export class Editor extends EventEmitter<TLEventMap> {
5899
5916
  * Get all bindings involving a particular shape. This includes bindings where the shape is the
5900
5917
  * `fromId` or `toId`. If a type is provided, only bindings of that type are returned.
5901
5918
  */
5902
- getBindingsInvolvingShape<Binding extends TLUnknownBinding = TLBinding>(
5919
+ getBindingsInvolvingShape<K extends TLBinding['type']>(
5920
+ shape: TLShape | TLShapeId,
5921
+ type: K
5922
+ ): Extract<TLBinding, { type: K }>[]
5923
+ getBindingsInvolvingShape<Binding extends TLBinding = TLBinding>(
5924
+ shape: TLShape | TLShapeId,
5925
+ type?: Binding['type']
5926
+ ): Binding[]
5927
+ getBindingsInvolvingShape<Binding extends TLBinding = TLBinding>(
5903
5928
  shape: TLShape | TLShapeId,
5904
5929
  type?: Binding['type']
5905
5930
  ): Binding[] {
@@ -5921,7 +5946,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5921
5946
  if (!fromShape || !toShape) continue
5922
5947
  if (!this.canBindShapes({ fromShape, toShape, binding: partial })) continue
5923
5948
 
5924
- const util = this.getBindingUtil<TLUnknownBinding>(partial.type)
5949
+ const util = this.getBindingUtil(partial.type)
5925
5950
  const defaultProps = util.getDefaultProps()
5926
5951
  const binding = this.store.schema.types.binding.create({
5927
5952
  ...partial,
@@ -6026,7 +6051,7 @@ export class Editor extends EventEmitter<TLEventMap> {
6026
6051
  const toShapeType = typeof toShape === 'string' ? toShape : toShape.type
6027
6052
  const bindingType = typeof binding === 'string' ? binding : binding.type
6028
6053
 
6029
- const canBindOpts = { fromShapeType, toShapeType, bindingType }
6054
+ const canBindOpts = { fromShapeType, toShapeType, bindingType } as const
6030
6055
 
6031
6056
  if (fromShapeType === toShapeType) {
6032
6057
  return this.getShapeUtil(fromShapeType).canBind(canBindOpts)
@@ -6567,7 +6592,7 @@ export class Editor extends EventEmitter<TLEventMap> {
6567
6592
  const shapesToFlipFirstPass = compact(ids.map((id) => this.getShape(id)))
6568
6593
 
6569
6594
  for (const shape of shapesToFlipFirstPass) {
6570
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
6595
+ if (this.isShapeOfType(shape, 'group')) {
6571
6596
  const childrenOfGroups = compact(
6572
6597
  this.getSortedChildIdsForParent(shape.id).map((id) => this.getShape(id))
6573
6598
  )
@@ -7688,9 +7713,7 @@ export class Editor extends EventEmitter<TLEventMap> {
7688
7713
  *
7689
7714
  * @public
7690
7715
  */
7691
- canCreateShape<T extends TLUnknownShape>(
7692
- shape: OptionalKeys<TLShapePartial<T>, 'id'> | T['id']
7693
- ): boolean {
7716
+ canCreateShape(shape: OptionalKeys<TLShapePartial<TLShape>, 'id'> | TLShape['id']): boolean {
7694
7717
  return this.canCreateShapes([shape])
7695
7718
  }
7696
7719
 
@@ -7701,8 +7724,8 @@ export class Editor extends EventEmitter<TLEventMap> {
7701
7724
  *
7702
7725
  * @public
7703
7726
  */
7704
- canCreateShapes<T extends TLUnknownShape>(
7705
- shapes: (T['id'] | OptionalKeys<TLShapePartial<T>, 'id'>)[]
7727
+ canCreateShapes(
7728
+ shapes: (TLShape['id'] | OptionalKeys<TLShapePartial<TLShape>, 'id'>)[]
7706
7729
  ): boolean {
7707
7730
  return shapes.length + this.getCurrentPageShapeIds().size <= this.options.maxShapesPerPage
7708
7731
  }
@@ -7720,7 +7743,7 @@ export class Editor extends EventEmitter<TLEventMap> {
7720
7743
  *
7721
7744
  * @public
7722
7745
  */
7723
- createShape<T extends TLUnknownShape>(shape: OptionalKeys<TLShapePartial<T>, 'id'>): this {
7746
+ createShape<TShape extends TLShape>(shape: TLCreateShapePartial<TShape>): this {
7724
7747
  this.createShapes([shape])
7725
7748
  return this
7726
7749
  }
@@ -7738,7 +7761,7 @@ export class Editor extends EventEmitter<TLEventMap> {
7738
7761
  *
7739
7762
  * @public
7740
7763
  */
7741
- createShapes<T extends TLUnknownShape>(shapes: OptionalKeys<TLShapePartial<T>, 'id'>[]): this {
7764
+ createShapes<TShape extends TLShape = TLShape>(shapes: TLCreateShapePartial<TShape>[]): this {
7742
7765
  if (!Array.isArray(shapes)) {
7743
7766
  throw Error('Editor.createShapes: must provide an array of shapes or shape partials')
7744
7767
  }
@@ -8119,7 +8142,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8119
8142
  const highestIndex = shapesWithRootParent[shapesWithRootParent.length - 1]?.index
8120
8143
 
8121
8144
  this.run(() => {
8122
- this.createShapes<TLGroupShape>([
8145
+ this.createShapes([
8123
8146
  {
8124
8147
  id: groupId,
8125
8148
  type: 'group',
@@ -8189,7 +8212,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8189
8212
  const groups: TLGroupShape[] = []
8190
8213
 
8191
8214
  shapesToUngroup.forEach((shape) => {
8192
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8215
+ if (this.isShapeOfType(shape, 'group')) {
8193
8216
  groups.push(shape)
8194
8217
  } else {
8195
8218
  idsToSelect.add(shape.id)
@@ -8235,7 +8258,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8235
8258
  *
8236
8259
  * @public
8237
8260
  */
8238
- updateShape<T extends TLUnknownShape>(partial: TLShapePartial<T> | null | undefined) {
8261
+ updateShape<T extends TLShape = TLShape>(partial: TLShapePartial<T> | null | undefined) {
8239
8262
  this.updateShapes([partial])
8240
8263
  return this
8241
8264
  }
@@ -8252,7 +8275,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8252
8275
  *
8253
8276
  * @public
8254
8277
  */
8255
- updateShapes<T extends TLUnknownShape>(partials: (TLShapePartial<T> | null | undefined)[]) {
8278
+ updateShapes<T extends TLShape>(partials: (TLShapePartial<T> | null | undefined)[]) {
8256
8279
  const compactedPartials: TLShapePartial<T>[] = Array(partials.length)
8257
8280
 
8258
8281
  for (let i = 0, n = partials.length; i < n; i++) {
@@ -8404,7 +8427,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8404
8427
  * @internal
8405
8428
  */
8406
8429
  private _extractSharedStyles(shape: TLShape, sharedStyleMap: SharedStyleMap) {
8407
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8430
+ if (this.isShapeOfType(shape, 'group')) {
8408
8431
  // For groups, ignore the styles of the group shape and instead include the styles of the
8409
8432
  // group's children. These are the shapes that would have their styles changed if the
8410
8433
  // user called `setStyle` on the current selection.
@@ -8524,7 +8547,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8524
8547
  // For groups, ignore the opacity of the group shape and instead include
8525
8548
  // the opacity of the group's children. These are the shapes that would have
8526
8549
  // their opacity changed if the user called `setOpacity` on the current selection.
8527
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8550
+ if (this.isShapeOfType(shape, 'group')) {
8528
8551
  for (const childId of this.getSortedChildIdsForParent(shape.id)) {
8529
8552
  addShape(childId)
8530
8553
  }
@@ -8585,7 +8608,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8585
8608
  // We can have many deep levels of grouped shape
8586
8609
  // Making a recursive function to look through all the levels
8587
8610
  const addShapeById = (shape: TLShape) => {
8588
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8611
+ if (this.isShapeOfType(shape, 'group')) {
8589
8612
  const childIds = this.getSortedChildIdsForParent(shape)
8590
8613
  for (const childId of childIds) {
8591
8614
  addShapeById(this.getShape(childId)!)
@@ -8669,7 +8692,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8669
8692
  // We can have many deep levels of grouped shape
8670
8693
  // Making a recursive function to look through all the levels
8671
8694
  const addShapeById = (shape: TLShape) => {
8672
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8695
+ if (this.isShapeOfType(shape, 'group')) {
8673
8696
  const childIds = this.getSortedChildIdsForParent(shape.id)
8674
8697
  for (const childId of childIds) {
8675
8698
  addShapeById(this.getShape(childId)!)
@@ -9094,7 +9117,7 @@ export class Editor extends EventEmitter<TLEventMap> {
9094
9117
  for (const shape of this.getSelectedShapes()) {
9095
9118
  if (lowestDepth === 0) break
9096
9119
 
9097
- const isFrame = this.isShapeOfType<TLFrameShape>(shape, 'frame')
9120
+ const isFrame = this.isShapeOfType(shape, 'frame')
9098
9121
  const ancestors = this.getShapeAncestors(shape)
9099
9122
  if (isFrame) ancestors.push(shape)
9100
9123
 
@@ -9133,8 +9156,8 @@ export class Editor extends EventEmitter<TLEventMap> {
9133
9156
  if (rootShapeIds.length === 1) {
9134
9157
  const rootShape = shapes.find((s) => s.id === rootShapeIds[0])!
9135
9158
  if (
9136
- this.isShapeOfType<TLFrameShape>(parent, 'frame') &&
9137
- this.isShapeOfType<TLFrameShape>(rootShape, 'frame') &&
9159
+ this.isShapeOfType(parent, 'frame') &&
9160
+ this.isShapeOfType(rootShape, 'frame') &&
9138
9161
  rootShape.props.w === parent?.props.w &&
9139
9162
  rootShape.props.h === parent?.props.h
9140
9163
  ) {
@@ -9309,11 +9332,11 @@ export class Editor extends EventEmitter<TLEventMap> {
9309
9332
  const onlyRoot = rootShapes[0] as TLFrameShape
9310
9333
  // If the old bounds are in the viewport...
9311
9334
  // todo: replace frame references with shapes that can accept children
9312
- if (this.isShapeOfType<TLFrameShape>(onlyRoot, 'frame')) {
9335
+ if (this.isShapeOfType(onlyRoot, 'frame')) {
9313
9336
  while (
9314
9337
  this.getShapesAtPoint(point).some(
9315
9338
  (shape) =>
9316
- this.isShapeOfType<TLFrameShape>(shape, 'frame') &&
9339
+ this.isShapeOfType(shape, 'frame') &&
9317
9340
  shape.props.w === onlyRoot.props.w &&
9318
9341
  shape.props.h === onlyRoot.props.h
9319
9342
  )
@@ -10228,6 +10251,7 @@ export class Editor extends EventEmitter<TLEventMap> {
10228
10251
  }
10229
10252
  }
10230
10253
 
10254
+ this.emit('event', info)
10231
10255
  this.root.handleEvent(info)
10232
10256
  return
10233
10257
  }
@@ -10726,7 +10750,10 @@ function alertMaxShapes(editor: Editor, pageId = editor.getCurrentPageId()) {
10726
10750
 
10727
10751
  function applyPartialToRecordWithProps<
10728
10752
  T extends UnknownRecord & { type: string; props: object; meta: object },
10729
- >(prev: T, partial?: Partial<T> & { props?: Partial<T['props']> }): T {
10753
+ >(
10754
+ prev: T,
10755
+ partial?: T extends T ? Omit<Partial<T>, 'props'> & { props?: Partial<T['props']> } : never
10756
+ ): T {
10730
10757
  if (!partial) return prev
10731
10758
  let next = null as null | T
10732
10759
  const entries = Object.entries(partial)
@@ -1,9 +1,15 @@
1
- import { RecordProps, TLPropsMigrations, TLShape, TLUnknownBinding } from '@tldraw/tlschema'
1
+ import {
2
+ RecordProps,
3
+ TLBinding,
4
+ TLPropsMigrations,
5
+ TLShape,
6
+ TLUnknownBinding,
7
+ } from '@tldraw/tlschema'
2
8
  import { Editor } from '../Editor'
3
9
 
4
10
  /** @public */
5
11
  export interface TLBindingUtilConstructor<
6
- T extends TLUnknownBinding,
12
+ T extends TLBinding,
7
13
  U extends BindingUtil<T> = BindingUtil<T>,
8
14
  > {
9
15
  new (editor: Editor): U
@@ -20,7 +26,7 @@ export interface TLBindingUtilConstructor<
20
26
  *
21
27
  * @public
22
28
  */
23
- export interface BindingOnCreateOptions<Binding extends TLUnknownBinding> {
29
+ export interface BindingOnCreateOptions<Binding extends TLBinding = TLBinding> {
24
30
  /** The binding being created. */
25
31
  binding: Binding
26
32
  }
@@ -31,7 +37,7 @@ export interface BindingOnCreateOptions<Binding extends TLUnknownBinding> {
31
37
  *
32
38
  * @public
33
39
  */
34
- export interface BindingOnChangeOptions<Binding extends TLUnknownBinding> {
40
+ export interface BindingOnChangeOptions<Binding extends TLBinding = TLBinding> {
35
41
  /** The binding record before the change is made. */
36
42
  bindingBefore: Binding
37
43
  /** The binding record after the change is made. */
@@ -44,7 +50,7 @@ export interface BindingOnChangeOptions<Binding extends TLUnknownBinding> {
44
50
  *
45
51
  * @public
46
52
  */
47
- export interface BindingOnDeleteOptions<Binding extends TLUnknownBinding> {
53
+ export interface BindingOnDeleteOptions<Binding extends TLBinding = TLBinding> {
48
54
  /** The binding being deleted. */
49
55
  binding: Binding
50
56
  }
@@ -55,7 +61,7 @@ export interface BindingOnDeleteOptions<Binding extends TLUnknownBinding> {
55
61
  *
56
62
  * @public
57
63
  */
58
- export interface BindingOnShapeChangeOptions<Binding extends TLUnknownBinding> {
64
+ export interface BindingOnShapeChangeOptions<Binding extends TLBinding = TLBinding> {
59
65
  /** The binding record linking these two shapes. */
60
66
  binding: Binding
61
67
  /** The shape record before the change is made. */
@@ -95,7 +101,7 @@ export interface BindingOnShapeChangeOptions<Binding extends TLUnknownBinding> {
95
101
  *
96
102
  * @public
97
103
  */
98
- export interface BindingOnShapeIsolateOptions<Binding extends TLUnknownBinding> {
104
+ export interface BindingOnShapeIsolateOptions<Binding extends TLBinding = TLBinding> {
99
105
  /** The binding record that refers to the shape in question. */
100
106
  binding: Binding
101
107
  /**
@@ -114,7 +120,7 @@ export interface BindingOnShapeIsolateOptions<Binding extends TLUnknownBinding>
114
120
  *
115
121
  * @public
116
122
  */
117
- export interface BindingOnShapeDeleteOptions<Binding extends TLUnknownBinding> {
123
+ export interface BindingOnShapeDeleteOptions<Binding extends TLBinding = TLBinding> {
118
124
  /** The binding record that refers to the shape in question. */
119
125
  binding: Binding
120
126
  /** The shape that is about to be deleted. */
@@ -122,7 +128,7 @@ export interface BindingOnShapeDeleteOptions<Binding extends TLUnknownBinding> {
122
128
  }
123
129
 
124
130
  /** @public */
125
- export abstract class BindingUtil<Binding extends TLUnknownBinding = TLUnknownBinding> {
131
+ export abstract class BindingUtil<Binding extends TLBinding = TLBinding> {
126
132
  constructor(public editor: Editor) {}
127
133
  static props?: RecordProps<TLUnknownBinding>
128
134
  static migrations?: TLPropsMigrations
@@ -1,11 +1,11 @@
1
1
  import { Computed, RESET_VALUE, computed, isUninitialized } from '@tldraw/state'
2
- import { TLArrowBinding, TLBinding, TLShapeId, TLUnknownBinding } from '@tldraw/tlschema'
2
+ import { TLBinding, TLShapeId } from '@tldraw/tlschema'
3
3
  import { objectMapValues } from '@tldraw/utils'
4
4
  import { Editor } from '../Editor'
5
5
 
6
6
  type TLBindingsIndex = Map<TLShapeId, TLBinding[]>
7
7
 
8
- function fromScratch(bindingsQuery: Computed<(TLArrowBinding | TLUnknownBinding)[], unknown>) {
8
+ function fromScratch(bindingsQuery: Computed<TLBinding[], unknown>) {
9
9
  const allBindings = bindingsQuery.get() as TLBinding[]
10
10
 
11
11
  const shapesToBindings: TLBindingsIndex = new Map()
@@ -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,5 +1,5 @@
1
1
  import { EMPTY_ARRAY, atom, computed } from '@tldraw/state'
2
- import { TLFrameShape, TLGroupShape, TLParentId, TLShapeId, isShapeId } from '@tldraw/tlschema'
2
+ import { TLParentId, TLShapeId, isShapeId } from '@tldraw/tlschema'
3
3
  import { Vec, VecLike } from '../../../primitives/Vec'
4
4
  import type { Editor } from '../../Editor'
5
5
  import { BoundsSnaps } from './BoundsSnaps'
@@ -72,7 +72,7 @@ export class SnapManager {
72
72
  const collectSnappableShapesFromParent = (parentId: TLParentId) => {
73
73
  if (isShapeId(parentId)) {
74
74
  const parent = editor.getShape(parentId)
75
- if (parent && editor.isShapeOfType<TLFrameShape>(parent, 'frame')) {
75
+ if (parent && editor.isShapeOfType(parent, 'frame')) {
76
76
  snappableShapes.add(parentId)
77
77
  }
78
78
  }
@@ -89,7 +89,7 @@ export class SnapManager {
89
89
  const pageBounds = editor.getShapePageBounds(childId)
90
90
  if (!(pageBounds && renderingBounds.includes(pageBounds))) continue
91
91
  // Snap to children of groups but not group itself
92
- if (editor.isShapeOfType<TLGroupShape>(childShape, 'group')) {
92
+ if (editor.isShapeOfType(childShape, 'group')) {
93
93
  collectSnappableShapesFromParent(childId)
94
94
  continue
95
95
  }
@@ -1,4 +1,4 @@
1
- import { TLBaseShape } from '@tldraw/tlschema'
1
+ import { ExtractShapeByProps } 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 = ExtractShapeByProps<{ 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,