tldraw 4.3.0-next.921f0bb64804 → 4.3.0-next.a109a0fbe064

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 (202) hide show
  1. package/dist-cjs/index.d.ts +14 -5
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js.map +2 -2
  4. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js.map +2 -2
  5. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  6. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  7. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +2 -2
  8. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
  9. package/dist-cjs/lib/shapes/arrow/elbow/elbowArrowSnapLines.js.map +2 -2
  10. package/dist-cjs/lib/shapes/arrow/shared.js.map +2 -2
  11. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  12. package/dist-cjs/lib/shapes/bookmark/bookmarks.js.map +2 -2
  13. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +2 -2
  14. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +2 -2
  15. package/dist-cjs/lib/shapes/frame/FrameShapeTool.js.map +1 -1
  16. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
  17. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
  18. package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
  19. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  20. package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +2 -2
  21. package/dist-cjs/lib/shapes/shared/crop.js +1 -0
  22. package/dist-cjs/lib/shapes/shared/crop.js.map +2 -2
  23. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  24. package/dist-cjs/lib/shapes/shared/useEditableRichText.js.map +2 -2
  25. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
  26. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  27. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  28. package/dist-cjs/lib/tools/SelectTool/DragAndDropManager.js +1 -4
  29. package/dist-cjs/lib/tools/SelectTool/DragAndDropManager.js.map +2 -2
  30. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js.map +2 -2
  31. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js.map +2 -2
  32. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +1 -1
  33. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  34. package/dist-cjs/lib/tools/SelectTool/childStates/EditingShape.js.map +2 -2
  35. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
  36. package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js.map +2 -2
  37. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js.map +2 -2
  38. package/dist-cjs/lib/tools/SelectTool/childStates/PointingSelection.js.map +2 -2
  39. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
  40. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js.map +2 -2
  41. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  42. package/dist-cjs/lib/ui/components/EditLinkDialog.js +11 -1
  43. package/dist-cjs/lib/ui/components/EditLinkDialog.js.map +2 -2
  44. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  45. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  46. package/dist-cjs/lib/ui/context/actions.js +1 -2
  47. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  48. package/dist-cjs/lib/ui/hooks/menu-hooks.js.map +2 -2
  49. package/dist-cjs/lib/ui/hooks/useFlatten.js.map +2 -2
  50. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  51. package/dist-cjs/lib/ui/version.js +3 -3
  52. package/dist-cjs/lib/ui/version.js.map +1 -1
  53. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js +8 -0
  54. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js.map +2 -2
  55. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  56. package/dist-cjs/lib/utils/frames/frames.js.map +2 -2
  57. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js.map +2 -2
  58. package/dist-esm/index.d.mts +14 -5
  59. package/dist-esm/index.mjs +1 -1
  60. package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs.map +2 -2
  61. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs.map +2 -2
  62. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  63. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  64. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +2 -2
  65. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  66. package/dist-esm/lib/shapes/arrow/elbow/elbowArrowSnapLines.mjs.map +2 -2
  67. package/dist-esm/lib/shapes/arrow/shared.mjs.map +2 -2
  68. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  69. package/dist-esm/lib/shapes/bookmark/bookmarks.mjs.map +2 -2
  70. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +2 -2
  71. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +2 -2
  72. package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs.map +1 -1
  73. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
  74. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
  75. package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
  76. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  77. package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
  78. package/dist-esm/lib/shapes/shared/crop.mjs +1 -0
  79. package/dist-esm/lib/shapes/shared/crop.mjs.map +2 -2
  80. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  81. package/dist-esm/lib/shapes/shared/useEditableRichText.mjs.map +2 -2
  82. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
  83. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  84. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +1 -4
  85. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  86. package/dist-esm/lib/tools/SelectTool/DragAndDropManager.mjs +1 -4
  87. package/dist-esm/lib/tools/SelectTool/DragAndDropManager.mjs.map +2 -2
  88. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs.map +2 -2
  89. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs.map +2 -2
  90. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +1 -1
  91. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  92. package/dist-esm/lib/tools/SelectTool/childStates/EditingShape.mjs.map +2 -2
  93. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
  94. package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs.map +2 -2
  95. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs +1 -4
  96. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs.map +2 -2
  97. package/dist-esm/lib/tools/SelectTool/childStates/PointingSelection.mjs.map +2 -2
  98. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
  99. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs.map +2 -2
  100. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  101. package/dist-esm/lib/ui/components/EditLinkDialog.mjs +11 -1
  102. package/dist-esm/lib/ui/components/EditLinkDialog.mjs.map +2 -2
  103. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  104. package/dist-esm/lib/ui/components/menu-items.mjs +1 -4
  105. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  106. package/dist-esm/lib/ui/context/actions.mjs +1 -2
  107. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  108. package/dist-esm/lib/ui/hooks/menu-hooks.mjs +1 -4
  109. package/dist-esm/lib/ui/hooks/menu-hooks.mjs.map +2 -2
  110. package/dist-esm/lib/ui/hooks/useFlatten.mjs.map +2 -2
  111. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  112. package/dist-esm/lib/ui/version.mjs +3 -3
  113. package/dist-esm/lib/ui/version.mjs.map +1 -1
  114. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs +8 -0
  115. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs.map +2 -2
  116. package/dist-esm/lib/utils/export/exportAs.mjs +1 -3
  117. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  118. package/dist-esm/lib/utils/frames/frames.mjs.map +2 -2
  119. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs.map +2 -2
  120. package/package.json +10 -10
  121. package/src/lib/bindings/arrow/ArrowBindingUtil.ts +1 -1
  122. package/src/lib/canvas/TldrawSelectionForeground.tsx +4 -9
  123. package/src/lib/defaultExternalContentHandlers.ts +3 -4
  124. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +2 -2
  125. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +1 -1
  126. package/src/lib/shapes/arrow/arrowLabel.ts +1 -1
  127. package/src/lib/shapes/arrow/arrowTargetState.ts +1 -1
  128. package/src/lib/shapes/arrow/elbow/elbowArrowSnapLines.tsx +3 -3
  129. package/src/lib/shapes/arrow/shared.ts +4 -4
  130. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +1 -1
  131. package/src/lib/shapes/bookmark/bookmarks.ts +3 -3
  132. package/src/lib/shapes/draw/toolStates/Drawing.ts +4 -4
  133. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
  134. package/src/lib/shapes/frame/FrameShapeTool.ts +1 -1
  135. package/src/lib/shapes/geo/GeoShapeUtil.test.tsx +10 -2
  136. package/src/lib/shapes/geo/toolStates/Pointing.ts +3 -3
  137. package/src/lib/shapes/line/LineShapeTool.test.ts +6 -6
  138. package/src/lib/shapes/line/LineShapeUtil.test.tsx +5 -5
  139. package/src/lib/shapes/line/toolStates/Pointing.ts +1 -1
  140. package/src/lib/shapes/note/NoteShapeTool.test.ts +2 -1
  141. package/src/lib/shapes/note/noteHelpers.ts +2 -2
  142. package/src/lib/shapes/shared/PlainTextLabel.tsx +2 -1
  143. package/src/lib/shapes/shared/RichTextLabel.tsx +2 -1
  144. package/src/lib/shapes/shared/crop.ts +1 -0
  145. package/src/lib/shapes/shared/useEditablePlainText.ts +7 -3
  146. package/src/lib/shapes/shared/useEditableRichText.ts +7 -3
  147. package/src/lib/shapes/text/TextShapeTool.test.ts +4 -4
  148. package/src/lib/shapes/text/toolStates/Pointing.ts +1 -1
  149. package/src/lib/tools/EraserTool/childStates/Erasing.ts +3 -5
  150. package/src/lib/tools/EraserTool/childStates/Pointing.ts +3 -16
  151. package/src/lib/tools/SelectTool/DragAndDropManager.ts +2 -4
  152. package/src/lib/tools/SelectTool/childStates/Brushing.ts +2 -6
  153. package/src/lib/tools/SelectTool/childStates/Crop/children/Idle.ts +2 -3
  154. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +4 -7
  155. package/src/lib/tools/SelectTool/childStates/EditingShape.ts +2 -4
  156. package/src/lib/tools/SelectTool/childStates/Idle.ts +6 -10
  157. package/src/lib/tools/SelectTool/childStates/PointingArrowLabel.ts +1 -1
  158. package/src/lib/tools/SelectTool/childStates/PointingHandle.ts +4 -12
  159. package/src/lib/tools/SelectTool/childStates/PointingSelection.ts +2 -2
  160. package/src/lib/tools/SelectTool/childStates/Resizing.ts +2 -4
  161. package/src/lib/tools/SelectTool/childStates/ScribbleBrushing.ts +2 -4
  162. package/src/lib/tools/SelectTool/childStates/Translating.ts +1 -3
  163. package/src/lib/ui/components/EditLinkDialog.tsx +16 -6
  164. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +2 -2
  165. package/src/lib/ui/components/menu-items.tsx +6 -14
  166. package/src/lib/ui/context/actions.tsx +9 -13
  167. package/src/lib/ui/hooks/menu-hooks.ts +9 -19
  168. package/src/lib/ui/hooks/useFlatten.ts +1 -2
  169. package/src/lib/ui/hooks/useTools.tsx +1 -2
  170. package/src/lib/ui/version.ts +3 -3
  171. package/src/lib/utils/excalidraw/putExcalidrawContent.ts +8 -0
  172. package/src/lib/utils/export/exportAs.ts +2 -9
  173. package/src/lib/utils/frames/frames.ts +1 -1
  174. package/src/lib/utils/tldr/buildFromV1Document.ts +12 -17
  175. package/src/test/Editor.test.tsx +38 -12
  176. package/src/test/SelectTool.test.ts +11 -19
  177. package/src/test/TestEditor.ts +1 -4
  178. package/src/test/TldrawEditor.test.tsx +21 -18
  179. package/src/test/bindings.test.tsx +29 -25
  180. package/src/test/bindingsIndex.test.tsx +4 -4
  181. package/src/test/commands/createShape.test.ts +64 -0
  182. package/src/test/commands/createShapes.test.ts +15 -1
  183. package/src/test/commands/getSvgString.test.ts +2 -2
  184. package/src/test/commands/isShapeOfType.test.ts +44 -0
  185. package/src/test/commands/putContent.test.ts +1 -0
  186. package/src/test/commands/updateShape.test.ts +67 -0
  187. package/src/test/commands/updateShapes.test.ts +21 -5
  188. package/src/test/custom-clipping.test.ts +36 -35
  189. package/src/test/customSnapping.test.tsx +77 -62
  190. package/src/test/duplicate.test.ts +1 -1
  191. package/src/test/frames.test.ts +2 -2
  192. package/src/test/getCulledShapes.test.tsx +11 -3
  193. package/src/test/getShapeAtPoint.test.ts +2 -2
  194. package/src/test/groups.test.tsx +6 -3
  195. package/src/test/resizing.test.ts +9 -13
  196. package/src/test/selection-omnibus.test.ts +11 -11
  197. package/src/test/shapeutils.test.ts +1 -1
  198. package/src/test/styles2.test.tsx +1 -1
  199. package/src/test/styles3.test.ts +5 -5
  200. package/src/test/test-jsx.tsx +69 -57
  201. package/src/test/text.test.ts +15 -17
  202. package/src/test/translating.test.ts +6 -8
@@ -3876,10 +3876,8 @@ it('uses the cross cursor when create resizing', () => {
3876
3876
  describe('Resizing text from the right edge', () => {
3877
3877
  it('Resizes text from the right edge', () => {
3878
3878
  const id = createShapeId()
3879
- editor.createShapes<TLTextShape>([{ id, type: 'text', props: { richText: toRichText('H') } }])
3880
- editor.updateShapes<TLTextShape>([
3881
- { id, type: 'text', props: { richText: toRichText('Hello World') } },
3882
- ]) // auto size
3879
+ editor.createShapes([{ id, type: 'text', props: { richText: toRichText('H') } }])
3880
+ editor.updateShapes([{ id, type: 'text', props: { richText: toRichText('Hello World') } }]) // auto size
3883
3881
 
3884
3882
  editor.select(id)
3885
3883
 
@@ -3905,10 +3903,8 @@ describe('Resizing text from the right edge', () => {
3905
3903
  editor.updateInstanceState({ isCoarsePointer: true })
3906
3904
 
3907
3905
  const id = createShapeId()
3908
- editor.createShapes<TLTextShape>([{ id, type: 'text', props: { richText: toRichText('H') } }])
3909
- editor.updateShapes<TLTextShape>([
3910
- { id, type: 'text', props: { richText: toRichText('Hello World') } },
3911
- ]) // auto size
3906
+ editor.createShapes([{ id, type: 'text', props: { richText: toRichText('H') } }])
3907
+ editor.updateShapes([{ id, type: 'text', props: { richText: toRichText('Hello World') } }]) // auto size
3912
3908
 
3913
3909
  editor.select(id)
3914
3910
 
@@ -3954,7 +3950,7 @@ describe('When resizing near the edges of the screen', () => {
3954
3950
 
3955
3951
  describe('resizing text with autosize true', () => {
3956
3952
  it('resizes text from the right side', () => {
3957
- editor.createShape<TLTextShape>({
3953
+ editor.createShape({
3958
3954
  type: 'text',
3959
3955
  x: 0,
3960
3956
  y: 0,
@@ -3980,7 +3976,7 @@ describe('resizing text with autosize true', () => {
3980
3976
  })
3981
3977
 
3982
3978
  it('resizes text from the right side when alt key is pressed', () => {
3983
- editor.createShape<TLTextShape>({
3979
+ editor.createShape({
3984
3980
  type: 'text',
3985
3981
  x: 0,
3986
3982
  y: 0,
@@ -4007,7 +4003,7 @@ describe('resizing text with autosize true', () => {
4007
4003
  })
4008
4004
 
4009
4005
  it('resizes text from the left side', () => {
4010
- editor.createShape<TLTextShape>({
4006
+ editor.createShape({
4011
4007
  type: 'text',
4012
4008
  x: 0,
4013
4009
  y: 0,
@@ -4033,7 +4029,7 @@ describe('resizing text with autosize true', () => {
4033
4029
  })
4034
4030
 
4035
4031
  it('resizes text from the left side when alt is pressed', () => {
4036
- editor.createShape<TLTextShape>({
4032
+ editor.createShape({
4037
4033
  type: 'text',
4038
4034
  x: 0,
4039
4035
  y: 0,
@@ -4062,7 +4058,7 @@ describe('resizing text with autosize true', () => {
4062
4058
 
4063
4059
  describe('cancelling a resize operation', () => {
4064
4060
  it('undoes any changes since the start of the resize operation', () => {
4065
- editor.createShape<TLGeoShape>({
4061
+ editor.createShape({
4066
4062
  type: 'geo',
4067
4063
  x: 0,
4068
4064
  y: 0,
@@ -76,7 +76,7 @@ describe('Hovering shapes', () => {
76
76
  editor.pointerMove(50, 50)
77
77
  expect(editor.getHoveredShapeId()).toBe(null)
78
78
 
79
- editor.updateShape<TLGeoShape>({
79
+ editor.updateShape({
80
80
  id: ids.box1,
81
81
  type: 'geo',
82
82
  props: { richText: toRichText('hello') },
@@ -88,7 +88,7 @@ describe('Hovering shapes', () => {
88
88
  })
89
89
 
90
90
  it('selects a shape with a full label on pointer down', () => {
91
- editor.updateShape<TLGeoShape>({
91
+ editor.updateShape({
92
92
  id: ids.box1,
93
93
  type: 'geo',
94
94
  props: { richText: toRichText('hello') },
@@ -462,7 +462,7 @@ describe('when shape is hollow', () => {
462
462
  describe('when shape is a frame', () => {
463
463
  let frame1: TLFrameShape
464
464
  beforeEach(() => {
465
- editor.createShape<TLFrameShape>({ id: ids.frame1, type: 'frame', props: { w: 100, h: 100 } })
465
+ editor.createShape({ id: ids.frame1, type: 'frame', props: { w: 100, h: 100 } })
466
466
  frame1 = editor.getShape<TLFrameShape>(ids.frame1)!
467
467
  })
468
468
 
@@ -517,8 +517,8 @@ describe('when shape is a frame', () => {
517
517
  describe('When a shape is behind a frame', () => {
518
518
  beforeEach(() => {
519
519
  editor.selectAll().deleteShapes(editor.getSelectedShapeIds())
520
- editor.createShape<TLGeoShape>({ id: ids.box1, type: 'geo', x: 25, y: 25 })
521
- editor.createShape<TLFrameShape>({ id: ids.frame1, type: 'frame', props: { w: 100, h: 100 } })
520
+ editor.createShape({ id: ids.box1, type: 'geo', x: 25, y: 25 })
521
+ editor.createShape({ id: ids.frame1, type: 'frame', props: { w: 100, h: 100 } })
522
522
  })
523
523
 
524
524
  it('does not select the shape when clicked inside', () => {
@@ -548,8 +548,8 @@ describe('when shape is inside of a frame', () => {
548
548
  let frame1: TLFrameShape
549
549
  let box1: TLGeoShape
550
550
  beforeEach(() => {
551
- editor.createShape<TLFrameShape>({ id: ids.frame1, type: 'frame', props: { w: 100, h: 100 } })
552
- editor.createShape<TLGeoShape>({
551
+ editor.createShape({ id: ids.frame1, type: 'frame', props: { w: 100, h: 100 } })
552
+ editor.createShape({
553
553
  id: ids.box1,
554
554
  parentId: ids.frame1,
555
555
  type: 'geo',
@@ -703,15 +703,15 @@ describe('when a frame has multiple children', () => {
703
703
  let box2: TLGeoShape
704
704
  beforeEach(() => {
705
705
  editor
706
- .createShape<TLFrameShape>({ id: ids.frame1, type: 'frame', props: { w: 100, h: 100 } })
707
- .createShape<TLGeoShape>({
706
+ .createShape({ id: ids.frame1, type: 'frame', props: { w: 100, h: 100 } })
707
+ .createShape({
708
708
  id: ids.box1,
709
709
  parentId: ids.frame1,
710
710
  type: 'geo',
711
711
  x: 25,
712
712
  y: 25,
713
713
  })
714
- .createShape<TLGeoShape>({
714
+ .createShape({
715
715
  id: ids.box2,
716
716
  parentId: ids.frame1,
717
717
  type: 'geo',
@@ -849,7 +849,7 @@ describe('When shapes are overlapping', () => {
849
849
  let box4: TLGeoShape
850
850
  let box5: TLGeoShape
851
851
  beforeEach(() => {
852
- editor.createShapes<TLGeoShape>([
852
+ editor.createShapes([
853
853
  {
854
854
  id: ids.box1,
855
855
  type: 'geo',
@@ -470,7 +470,7 @@ describe('When interacting with a shape...', () => {
470
470
  })
471
471
 
472
472
  it('Fires handle dragging cancel events', () => {
473
- const util = editor.getShapeUtil<TLLineShape>('line')
473
+ const util = editor.getShapeUtil('line')
474
474
 
475
475
  const calls: string[] = []
476
476
 
@@ -88,7 +88,7 @@ describe('Editor.styles', () => {
88
88
  })
89
89
 
90
90
  it('should return mixed for all mixed styles', () => {
91
- editor.updateShapes<TLGeoShape>([
91
+ editor.updateShapes([
92
92
  {
93
93
  id: defaultShapesIds.box1,
94
94
  type: 'geo',
@@ -1,4 +1,4 @@
1
- import { TLGeoShape, createShapeId, toRichText } from '@tldraw/editor'
1
+ import { createShapeId, toRichText } from '@tldraw/editor'
2
2
  import { TestEditor } from './TestEditor'
3
3
 
4
4
  let editor: TestEditor
@@ -14,7 +14,7 @@ afterEach(() => {
14
14
  it("When changing the style of a geo shape, if the text label is empty, don't measure it", () => {
15
15
  const id = createShapeId()
16
16
 
17
- editor.createShapes<TLGeoShape>([
17
+ editor.createShapes([
18
18
  {
19
19
  id,
20
20
  type: 'geo',
@@ -29,7 +29,7 @@ it("When changing the style of a geo shape, if the text label is empty, don't me
29
29
 
30
30
  const boundsBefore = editor.getShapeGeometry(id).bounds
31
31
 
32
- editor.updateShapes<TLGeoShape>([
32
+ editor.updateShapes([
33
33
  {
34
34
  id,
35
35
  type: 'geo',
@@ -43,7 +43,7 @@ it("When changing the style of a geo shape, if the text label is empty, don't me
43
43
  it('When changing the style of a geo shape, if the text label has text, measure it and possibly update the size', () => {
44
44
  const id = createShapeId()
45
45
 
46
- editor.createShapes<TLGeoShape>([
46
+ editor.createShapes([
47
47
  {
48
48
  id,
49
49
  type: 'geo',
@@ -58,7 +58,7 @@ it('When changing the style of a geo shape, if the text label has text, measure
58
58
 
59
59
  const boundsBefore = editor.getShapeGeometry(id).bounds!
60
60
 
61
- editor.updateShapes<TLGeoShape>([
61
+ editor.updateShapes([
62
62
  {
63
63
  id,
64
64
  type: 'geo',
@@ -5,8 +5,7 @@ import {
5
5
  TLBinding,
6
6
  TLBindingCreate,
7
7
  TLBindingId,
8
- TLDefaultBinding,
9
- TLDefaultShape,
8
+ TLShape,
10
9
  TLShapeId,
11
10
  TLShapePartial,
12
11
  ZERO_INDEX_KEY,
@@ -23,6 +22,7 @@ import React, { Fragment } from 'react'
23
22
  const shapeTypeSymbol = Symbol('shapeJsx')
24
23
  const assetTypeSymbol = Symbol('assetJsx')
25
24
  const bindingTypeSymbol = Symbol('bindingJsx')
25
+
26
26
  interface CommonShapeProps {
27
27
  x?: number
28
28
  y?: number
@@ -34,7 +34,6 @@ interface CommonShapeProps {
34
34
  opacity?: number
35
35
  }
36
36
 
37
- type ShapeByType<Type extends TLDefaultShape['type']> = Extract<TLDefaultShape, { type: Type }>
38
37
  type FormatShapeProps<Props extends object> = {
39
38
  [K in keyof Props]?: Props[K] extends TLAssetId
40
39
  ? TLAssetId | React.JSX.Element
@@ -42,24 +41,39 @@ type FormatShapeProps<Props extends object> = {
42
41
  ? TLAssetId | React.JSX.Element | null
43
42
  : Props[K]
44
43
  }
45
- type PropsForShape<Type extends string> = Type extends TLDefaultShape['type']
46
- ? CommonShapeProps & FormatShapeProps<ShapeByType<Type>['props']>
47
- : CommonShapeProps & Record<string, unknown>
44
+ type PropsForShape<Type extends TLShape['type']> = CommonShapeProps &
45
+ FormatShapeProps<TLShape<Type>['props']>
48
46
 
49
47
  type AssetByType<Type extends TLAsset['type']> = Extract<TLAsset, { type: Type }>
50
48
  type PropsForAsset<Type extends string> = Type extends TLAsset['type']
51
49
  ? Partial<AssetByType<Type>['props']>
52
50
  : Record<string, unknown>
53
51
 
54
- interface CommonBindingProps {
52
+ interface BindingReactConnections {
55
53
  from?: string | TLShapeId
56
54
  to: string | TLShapeId
57
55
  }
58
56
 
59
- type BindingByType<Type extends TLBinding['type']> = Extract<TLBinding, { type: Type }>
60
- type PropsForBinding<Type extends string> = Type extends TLBinding['type']
61
- ? CommonBindingProps & Partial<BindingByType<Type>['props']>
62
- : CommonBindingProps & Record<string, unknown>
57
+ interface CommonBindingReactProps extends BindingReactConnections {
58
+ ref?: string
59
+ id?: TLBindingId
60
+ }
61
+
62
+ type ReactPropsForBinding<Type extends TLBinding['type']> = CommonBindingReactProps &
63
+ Partial<TLBinding<Type>['props']>
64
+
65
+ type BindingToCreate = TLBinding extends infer E
66
+ ? E extends TLBinding
67
+ ? {
68
+ type: E['type']
69
+ props: Partial<TLBinding<E['type']>['props']>
70
+ id: TLBindingId | undefined
71
+ parentId: TLShapeId | undefined
72
+ ref: string | undefined
73
+ connections: BindingReactConnections
74
+ }
75
+ : never
76
+ : never
63
77
 
64
78
  const createElement = (
65
79
  type: typeof shapeTypeSymbol | typeof assetTypeSymbol | typeof bindingTypeSymbol,
@@ -90,10 +104,9 @@ const tlBinding = new Proxy(
90
104
  return createElement(bindingTypeSymbol, key as string)
91
105
  },
92
106
  }
93
- ) as { [K in TLDefaultBinding['type']]: (props: PropsForBinding<K>) => null } & Record<
94
- string,
95
- (props: PropsForBinding<string>) => null
96
- >
107
+ ) as {
108
+ [K in TLBinding['type']]: (props: ReactPropsForBinding<K>) => null
109
+ }
97
110
 
98
111
  /**
99
112
  * TL - jsx helpers for creating tldraw shapes in test cases
@@ -112,8 +125,8 @@ export const TL = new Proxy(
112
125
  },
113
126
  }
114
127
  ) as { asset: typeof tlAsset; binding: typeof tlBinding } & {
115
- [K in TLDefaultShape['type']]: (props: PropsForShape<K>) => null
116
- } & Record<string, (props: PropsForShape<string>) => null>
128
+ [K in TLShape['type']]: (props: PropsForShape<K>) => null
129
+ }
117
130
 
118
131
  export function shapesFromJsx(shapes: React.JSX.Element | Array<React.JSX.Element>, idPrefix = '') {
119
132
  const ids = { bindings: {} } as Record<string, TLShapeId> & {
@@ -122,12 +135,7 @@ export function shapesFromJsx(shapes: React.JSX.Element | Array<React.JSX.Elemen
122
135
  const currentPageShapes: Array<TLShapePartial> = []
123
136
  const assets: Array<TLAsset> = []
124
137
 
125
- const bindingsToCreate: Array<{
126
- type: string
127
- props: Record<string, unknown>
128
- parentId: TLShapeId | undefined
129
- ref: string | undefined
130
- }> = []
138
+ const bindingsToCreate: Array<BindingToCreate> = []
131
139
 
132
140
  function addChildren(
133
141
  children: React.JSX.Element | Array<React.JSX.Element>,
@@ -152,10 +160,21 @@ export function shapesFromJsx(shapes: React.JSX.Element | Array<React.JSX.Elemen
152
160
  }
153
161
 
154
162
  if (el.type[bindingTypeSymbol]) {
155
- const bindingType = (el.type as any)[bindingTypeSymbol] as string
156
- const ref = ((el as any).ref || el.props.ref) as string | undefined
157
- assert(ref === undefined || typeof ref === 'string', 'ref must be string or undefined')
158
- bindingsToCreate.push({ type: bindingType, props: el.props, parentId, ref })
163
+ const bindingType = (el.type as any)[bindingTypeSymbol] as TLBinding['type']
164
+ const { id, from, to, ref, ...props } = el.props
165
+ const bindingRef: unknown = (el as any).ref || ref
166
+ assert(
167
+ bindingRef === undefined || typeof bindingRef === 'string',
168
+ 'ref must be string or undefined'
169
+ )
170
+ bindingsToCreate.push({
171
+ type: bindingType,
172
+ props,
173
+ id,
174
+ parentId,
175
+ ref: bindingRef,
176
+ connections: { from, to },
177
+ })
159
178
  } else {
160
179
  const shapeType = (el.type as any)[shapeTypeSymbol] as string
161
180
  if (!shapeType) {
@@ -239,55 +258,48 @@ export function shapesFromJsx(shapes: React.JSX.Element | Array<React.JSX.Elemen
239
258
  addChildren(shapes)
240
259
 
241
260
  const bindings: TLBindingCreate[] = []
242
- for (const binding of bindingsToCreate) {
261
+ for (const { id, parentId, ref, connections, ...binding } of bindingsToCreate) {
243
262
  let fromId: TLShapeId, toId: TLShapeId
244
- if (binding.props.from) {
245
- assert(typeof binding.props.from === 'string', 'from must be a ref string or a shape id')
246
- if (isShapeId(binding.props.from)) {
247
- fromId = binding.props.from
263
+ if (connections.from) {
264
+ assert(typeof connections.from === 'string', 'from must be a ref string or a shape id')
265
+ if (isShapeId(connections.from)) {
266
+ fromId = connections.from
248
267
  } else {
249
- assert(ids[binding.props.from], `Ref not found: ${binding.props.from}`)
250
- fromId = ids[binding.props.from]
268
+ assert(ids[connections.from], `Ref not found: ${connections.from}`)
269
+ fromId = ids[connections.from]
251
270
  }
252
- } else if (binding.parentId) {
253
- fromId = binding.parentId
271
+ } else if (parentId) {
272
+ fromId = parentId
254
273
  } else {
255
274
  throw new Error('from must be specified, or binding must be a child of a shape')
256
275
  }
257
276
 
258
- assert(binding.props.to, 'to must be specified')
259
- assert(typeof binding.props.to === 'string', 'to must be a ref string or a shape id')
260
- if (isShapeId(binding.props.to)) {
261
- toId = binding.props.to
277
+ assert(connections.to, 'to must be specified')
278
+ assert(typeof connections.to === 'string', 'to must be a ref string or a shape id')
279
+ if (isShapeId(connections.to)) {
280
+ toId = connections.to
262
281
  } else {
263
- assert(ids[binding.props.to], `Ref not found: ${binding.props.to}`)
264
- toId = ids[binding.props.to]
282
+ assert(ids[connections.to], `Ref not found: ${connections.to}`)
283
+ toId = ids[connections.to]
265
284
  }
266
285
 
267
- let bindingId: TLBindingId = binding.props.id as TLBindingId
268
- if (binding.ref) {
269
- assert(typeof binding.ref === 'string', 'binding ref must be string')
270
- assert(!ids.bindings[binding.ref], `Duplicate ref: ${binding.ref}`)
271
- assert(!bindingId, `Cannot use both ref and id on binding: ${binding.ref}`)
272
- bindingId = createBindingId(`${idPrefix}${binding.ref}`)
273
- ids.bindings[binding.ref] = bindingId
286
+ let bindingId = id
287
+ if (ref) {
288
+ assert(typeof ref === 'string', 'binding ref must be string')
289
+ assert(!ids.bindings[ref], `Duplicate ref: ${ref}`)
290
+ assert(!bindingId, `Cannot use both ref and id on binding: ${ref}`)
291
+ bindingId = createBindingId(`${idPrefix}${ref}`)
292
+ ids.bindings[ref] = bindingId
274
293
  }
275
294
  if (!bindingId) {
276
295
  bindingId = createBindingId()
277
296
  }
278
297
 
279
- const props = { ...binding.props }
280
- delete props.ref
281
- delete props.id
282
- delete props.from
283
- delete props.to
284
-
285
298
  bindings.push({
299
+ ...binding,
286
300
  id: bindingId,
287
- type: binding.type,
288
301
  fromId,
289
302
  toId,
290
- props,
291
303
  })
292
304
  }
293
305
 
@@ -1,4 +1,4 @@
1
- import { TLTextShape, createShapeId, toRichText } from '@tldraw/editor'
1
+ import { createShapeId, toRichText } from '@tldraw/editor'
2
2
  import { TestEditor } from './TestEditor'
3
3
 
4
4
  let editor: TestEditor
@@ -13,7 +13,7 @@ afterEach(() => {
13
13
  describe('When editing text', () => {
14
14
  it('preserves the top center when center aligned', () => {
15
15
  const id = createShapeId()
16
- editor.createShapes<TLTextShape>([
16
+ editor.createShapes([
17
17
  {
18
18
  id,
19
19
  type: 'text',
@@ -27,7 +27,7 @@ describe('When editing text', () => {
27
27
  },
28
28
  ])
29
29
  const boundsA = editor.getShapePageBounds(id)
30
- editor.updateShapes<TLTextShape>([
30
+ editor.updateShapes([
31
31
  {
32
32
  id,
33
33
  type: 'text',
@@ -47,7 +47,7 @@ describe('When editing text', () => {
47
47
 
48
48
  it('preserved the right center when center aligned and rotated 90deg', () => {
49
49
  const id = createShapeId()
50
- editor.createShapes<TLTextShape>([
50
+ editor.createShapes([
51
51
  {
52
52
  id,
53
53
  type: 'text',
@@ -63,9 +63,7 @@ describe('When editing text', () => {
63
63
  ])
64
64
 
65
65
  const boundsA = editor.getShapePageBounds(id)!
66
- editor.updateShapes<TLTextShape>([
67
- { id, type: 'text', props: { richText: toRichText('Hello, world!') } },
68
- ])
66
+ editor.updateShapes([{ id, type: 'text', props: { richText: toRichText('Hello, world!') } }])
69
67
  const boundsB = editor.getShapePageBounds(id)!
70
68
  expect(boundsA.x).toBeCloseTo(boundsB.x)
71
69
  expect(boundsA.y).not.toBeCloseTo(boundsB.y)
@@ -75,7 +73,7 @@ describe('When editing text', () => {
75
73
 
76
74
  it('preserves the top left corner when start aligned', () => {
77
75
  const id = createShapeId()
78
- editor.createShapes<TLTextShape>([
76
+ editor.createShapes([
79
77
  {
80
78
  id,
81
79
  type: 'text',
@@ -89,7 +87,7 @@ describe('When editing text', () => {
89
87
  },
90
88
  ])
91
89
  const boundsA = editor.getShapePageBounds(id)
92
- editor.updateShapes<TLTextShape>([
90
+ editor.updateShapes([
93
91
  {
94
92
  id,
95
93
  type: 'text',
@@ -109,7 +107,7 @@ describe('When editing text', () => {
109
107
 
110
108
  it('preserves the top right edge when end aligned', () => {
111
109
  const id = createShapeId()
112
- editor.createShapes<TLTextShape>([
110
+ editor.createShapes([
113
111
  {
114
112
  id,
115
113
  type: 'text',
@@ -123,7 +121,7 @@ describe('When editing text', () => {
123
121
  },
124
122
  ])
125
123
  const boundsA = editor.getShapePageBounds(id)
126
- editor.updateShapes<TLTextShape>([
124
+ editor.updateShapes([
127
125
  {
128
126
  id,
129
127
  type: 'text',
@@ -145,7 +143,7 @@ describe('When editing text', () => {
145
143
  describe('When changing text size', () => {
146
144
  it('preserves the center when center aligned', () => {
147
145
  const id = createShapeId()
148
- editor.createShapes<TLTextShape>([
146
+ editor.createShapes([
149
147
  {
150
148
  id,
151
149
  type: 'text',
@@ -160,7 +158,7 @@ describe('When changing text size', () => {
160
158
  },
161
159
  ])
162
160
  const boundsA = editor.getShapePageBounds(id)
163
- editor.updateShapes<TLTextShape>([
161
+ editor.updateShapes([
164
162
  {
165
163
  id,
166
164
  type: 'text',
@@ -180,7 +178,7 @@ describe('When changing text size', () => {
180
178
 
181
179
  it('preserves the center left point when start aligned', () => {
182
180
  const id = createShapeId()
183
- editor.createShapes<TLTextShape>([
181
+ editor.createShapes([
184
182
  {
185
183
  id,
186
184
  type: 'text',
@@ -195,7 +193,7 @@ describe('When changing text size', () => {
195
193
  },
196
194
  ])
197
195
  const boundsA = editor.getShapePageBounds(id)
198
- editor.updateShapes<TLTextShape>([
196
+ editor.updateShapes([
199
197
  {
200
198
  id,
201
199
  type: 'text',
@@ -215,7 +213,7 @@ describe('When changing text size', () => {
215
213
 
216
214
  it('preserves the top right edge when end aligned', () => {
217
215
  const id = createShapeId()
218
- editor.createShapes<TLTextShape>([
216
+ editor.createShapes([
219
217
  {
220
218
  id,
221
219
  type: 'text',
@@ -230,7 +228,7 @@ describe('When changing text size', () => {
230
228
  },
231
229
  ])
232
230
  const boundsA = editor.getShapePageBounds(id)
233
- editor.updateShapes<TLTextShape>([
231
+ editor.updateShapes([
234
232
  {
235
233
  id,
236
234
  type: 'text',
@@ -1749,9 +1749,7 @@ describe('translating a shape with a bound shape', () => {
1749
1749
 
1750
1750
  const newArrow = editor
1751
1751
  .getCurrentPageShapes()
1752
- .find(
1753
- (s) => editor.isShapeOfType<TLArrowShape>(s, 'arrow') && s.id !== arrow1
1754
- )! as TLArrowShape
1752
+ .find((s) => editor.isShapeOfType(s, 'arrow') && s.id !== arrow1)! as TLArrowShape
1755
1753
  expect(getArrowBindings(editor, newArrow)).toMatchObject({
1756
1754
  start: { type: 'arrow' },
1757
1755
  end: undefined,
@@ -2061,7 +2059,7 @@ describe('Note shape grid helper positions / pits', () => {
2061
2059
  editor
2062
2060
  .createShape({ type: 'note' })
2063
2061
  .createShape({ type: 'note', x: 500, y: 500 })
2064
- .updateShape({ ...editor.getLastCreatedShape(), props: { growY: 100 } })
2062
+ .updateShape({ ...editor.getLastCreatedShape<TLNoteShape>(), props: { growY: 100 } })
2065
2063
  .pointerMove(600, 600)
2066
2064
  // start translating
2067
2065
  .pointerDown()
@@ -2080,7 +2078,7 @@ describe('Note shape grid helper positions / pits', () => {
2080
2078
  it('Snaps correctly to the bottom when the not-translating shape has growY', () => {
2081
2079
  editor
2082
2080
  .createShape({ type: 'note' })
2083
- .updateShape({ ...editor.getLastCreatedShape(), props: { growY: 100 } })
2081
+ .updateShape({ ...editor.getLastCreatedShape<TLNoteShape>(), props: { growY: 100 } })
2084
2082
  .createShape({ type: 'note', x: 500, y: 500 })
2085
2083
  .pointerMove(600, 600)
2086
2084
  // start translating
@@ -2183,7 +2181,7 @@ describe('Note shape grid helper positions / pits', () => {
2183
2181
 
2184
2182
  describe('cancelling a translate operation', () => {
2185
2183
  it('undoes any changes since the start of the translate operation', () => {
2186
- editor.createShape<TLGeoShape>({
2184
+ editor.createShape({
2187
2185
  type: 'geo',
2188
2186
  x: 0,
2189
2187
  y: 0,
@@ -2220,7 +2218,7 @@ describe('cancelling a translate operation', () => {
2220
2218
  const shapeId = createShapeId()
2221
2219
 
2222
2220
  editor
2223
- .createShape<TLGeoShape>({
2221
+ .createShape({
2224
2222
  id: shapeId,
2225
2223
  type: 'geo',
2226
2224
  x: 0,
@@ -2268,7 +2266,7 @@ describe('cancelling a translate operation', () => {
2268
2266
  const shapeId = createShapeId()
2269
2267
 
2270
2268
  editor
2271
- .createShape<TLGeoShape>({
2269
+ .createShape({
2272
2270
  id: shapeId,
2273
2271
  type: 'geo',
2274
2272
  x: 0,