tldraw 4.3.0-canary.da35795ba8e2 → 4.3.0-canary.e52fa5385f86

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 (225) hide show
  1. package/dist-cjs/index.d.ts +17 -5
  2. package/dist-cjs/index.js +2 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js.map +2 -2
  5. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js.map +2 -2
  6. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  7. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  8. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +2 -2
  9. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
  10. package/dist-cjs/lib/shapes/arrow/elbow/elbowArrowSnapLines.js.map +2 -2
  11. package/dist-cjs/lib/shapes/arrow/shared.js.map +2 -2
  12. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  13. package/dist-cjs/lib/shapes/bookmark/bookmarks.js.map +2 -2
  14. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +2 -2
  15. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +2 -2
  16. package/dist-cjs/lib/shapes/frame/FrameShapeTool.js.map +1 -1
  17. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
  18. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
  19. package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
  20. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  21. package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +2 -2
  22. package/dist-cjs/lib/shapes/shared/crop.js +1 -0
  23. package/dist-cjs/lib/shapes/shared/crop.js.map +2 -2
  24. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  25. package/dist-cjs/lib/shapes/shared/useEditableRichText.js.map +2 -2
  26. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
  27. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  28. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  29. package/dist-cjs/lib/tools/SelectTool/DragAndDropManager.js +1 -4
  30. package/dist-cjs/lib/tools/SelectTool/DragAndDropManager.js.map +2 -2
  31. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js.map +2 -2
  32. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js.map +2 -2
  33. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +1 -1
  34. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  35. package/dist-cjs/lib/tools/SelectTool/childStates/EditingShape.js.map +2 -2
  36. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
  37. package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js.map +2 -2
  38. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js.map +2 -2
  39. package/dist-cjs/lib/tools/SelectTool/childStates/PointingSelection.js.map +2 -2
  40. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
  41. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js.map +2 -2
  42. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  43. package/dist-cjs/lib/ui/components/EditLinkDialog.js +11 -1
  44. package/dist-cjs/lib/ui/components/EditLinkDialog.js.map +2 -2
  45. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  46. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  47. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +1 -1
  48. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  49. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +143 -88
  50. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  51. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +1 -1
  52. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  53. package/dist-cjs/lib/ui/context/actions.js +1 -2
  54. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  55. package/dist-cjs/lib/ui/hooks/menu-hooks.js.map +2 -2
  56. package/dist-cjs/lib/ui/hooks/useFlatten.js.map +2 -2
  57. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  58. package/dist-cjs/lib/ui/version.js +3 -3
  59. package/dist-cjs/lib/ui/version.js.map +1 -1
  60. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js +8 -0
  61. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js.map +2 -2
  62. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  63. package/dist-cjs/lib/utils/frames/frames.js.map +2 -2
  64. package/dist-cjs/lib/utils/text/richText.js +7 -17
  65. package/dist-cjs/lib/utils/text/richText.js.map +3 -3
  66. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js.map +2 -2
  67. package/dist-esm/index.d.mts +17 -5
  68. package/dist-esm/index.mjs +3 -1
  69. package/dist-esm/index.mjs.map +2 -2
  70. package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs.map +2 -2
  71. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs.map +2 -2
  72. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  73. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  74. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +2 -2
  75. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  76. package/dist-esm/lib/shapes/arrow/elbow/elbowArrowSnapLines.mjs.map +2 -2
  77. package/dist-esm/lib/shapes/arrow/shared.mjs.map +2 -2
  78. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  79. package/dist-esm/lib/shapes/bookmark/bookmarks.mjs.map +2 -2
  80. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +2 -2
  81. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +2 -2
  82. package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs.map +1 -1
  83. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
  84. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
  85. package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
  86. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  87. package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
  88. package/dist-esm/lib/shapes/shared/crop.mjs +1 -0
  89. package/dist-esm/lib/shapes/shared/crop.mjs.map +2 -2
  90. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  91. package/dist-esm/lib/shapes/shared/useEditableRichText.mjs.map +2 -2
  92. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
  93. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  94. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +1 -4
  95. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  96. package/dist-esm/lib/tools/SelectTool/DragAndDropManager.mjs +1 -4
  97. package/dist-esm/lib/tools/SelectTool/DragAndDropManager.mjs.map +2 -2
  98. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs.map +2 -2
  99. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs.map +2 -2
  100. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +1 -1
  101. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  102. package/dist-esm/lib/tools/SelectTool/childStates/EditingShape.mjs.map +2 -2
  103. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
  104. package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs.map +2 -2
  105. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs +1 -4
  106. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs.map +2 -2
  107. package/dist-esm/lib/tools/SelectTool/childStates/PointingSelection.mjs.map +2 -2
  108. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
  109. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs.map +2 -2
  110. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  111. package/dist-esm/lib/ui/components/EditLinkDialog.mjs +11 -1
  112. package/dist-esm/lib/ui/components/EditLinkDialog.mjs.map +2 -2
  113. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  114. package/dist-esm/lib/ui/components/menu-items.mjs +1 -4
  115. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  116. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +2 -2
  117. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  118. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +151 -90
  119. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  120. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +2 -2
  121. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  122. package/dist-esm/lib/ui/context/actions.mjs +1 -2
  123. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  124. package/dist-esm/lib/ui/hooks/menu-hooks.mjs +1 -4
  125. package/dist-esm/lib/ui/hooks/menu-hooks.mjs.map +2 -2
  126. package/dist-esm/lib/ui/hooks/useFlatten.mjs.map +2 -2
  127. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  128. package/dist-esm/lib/ui/version.mjs +3 -3
  129. package/dist-esm/lib/ui/version.mjs.map +1 -1
  130. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs +8 -0
  131. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs.map +2 -2
  132. package/dist-esm/lib/utils/export/exportAs.mjs +1 -3
  133. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  134. package/dist-esm/lib/utils/frames/frames.mjs.map +2 -2
  135. package/dist-esm/lib/utils/text/richText.mjs +3 -3
  136. package/dist-esm/lib/utils/text/richText.mjs.map +2 -2
  137. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs.map +2 -2
  138. package/package.json +10 -10
  139. package/src/index.ts +1 -0
  140. package/src/lib/bindings/arrow/ArrowBindingUtil.ts +1 -1
  141. package/src/lib/canvas/TldrawSelectionForeground.tsx +4 -9
  142. package/src/lib/defaultExternalContentHandlers.ts +3 -4
  143. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +2 -2
  144. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +1 -1
  145. package/src/lib/shapes/arrow/arrowLabel.ts +1 -1
  146. package/src/lib/shapes/arrow/arrowTargetState.ts +1 -1
  147. package/src/lib/shapes/arrow/elbow/elbowArrowSnapLines.tsx +3 -3
  148. package/src/lib/shapes/arrow/shared.ts +4 -4
  149. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +1 -1
  150. package/src/lib/shapes/bookmark/bookmarks.ts +3 -3
  151. package/src/lib/shapes/draw/toolStates/Drawing.ts +4 -4
  152. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
  153. package/src/lib/shapes/frame/FrameShapeTool.ts +1 -1
  154. package/src/lib/shapes/geo/GeoShapeUtil.test.tsx +10 -2
  155. package/src/lib/shapes/geo/toolStates/Pointing.ts +3 -3
  156. package/src/lib/shapes/line/LineShapeTool.test.ts +6 -6
  157. package/src/lib/shapes/line/LineShapeUtil.test.tsx +5 -5
  158. package/src/lib/shapes/line/toolStates/Pointing.ts +1 -1
  159. package/src/lib/shapes/note/NoteShapeTool.test.ts +2 -1
  160. package/src/lib/shapes/note/noteHelpers.ts +2 -2
  161. package/src/lib/shapes/shared/PlainTextLabel.tsx +2 -1
  162. package/src/lib/shapes/shared/RichTextLabel.tsx +2 -1
  163. package/src/lib/shapes/shared/crop.ts +1 -0
  164. package/src/lib/shapes/shared/useEditablePlainText.ts +7 -3
  165. package/src/lib/shapes/shared/useEditableRichText.ts +7 -3
  166. package/src/lib/shapes/text/TextShapeTool.test.ts +4 -4
  167. package/src/lib/shapes/text/toolStates/Pointing.ts +1 -1
  168. package/src/lib/tools/EraserTool/childStates/Erasing.ts +3 -5
  169. package/src/lib/tools/EraserTool/childStates/Pointing.ts +3 -16
  170. package/src/lib/tools/SelectTool/DragAndDropManager.ts +2 -4
  171. package/src/lib/tools/SelectTool/childStates/Brushing.ts +2 -6
  172. package/src/lib/tools/SelectTool/childStates/Crop/children/Idle.ts +2 -3
  173. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +4 -7
  174. package/src/lib/tools/SelectTool/childStates/EditingShape.ts +2 -4
  175. package/src/lib/tools/SelectTool/childStates/Idle.ts +6 -10
  176. package/src/lib/tools/SelectTool/childStates/PointingArrowLabel.ts +1 -1
  177. package/src/lib/tools/SelectTool/childStates/PointingHandle.ts +4 -12
  178. package/src/lib/tools/SelectTool/childStates/PointingSelection.ts +2 -2
  179. package/src/lib/tools/SelectTool/childStates/Resizing.ts +2 -4
  180. package/src/lib/tools/SelectTool/childStates/ScribbleBrushing.ts +2 -4
  181. package/src/lib/tools/SelectTool/childStates/Translating.ts +1 -3
  182. package/src/lib/ui/components/EditLinkDialog.tsx +16 -6
  183. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +2 -2
  184. package/src/lib/ui/components/menu-items.tsx +6 -14
  185. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +2 -2
  186. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +196 -108
  187. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +2 -2
  188. package/src/lib/ui/context/actions.tsx +9 -13
  189. package/src/lib/ui/hooks/menu-hooks.ts +9 -19
  190. package/src/lib/ui/hooks/useFlatten.ts +1 -2
  191. package/src/lib/ui/hooks/useTools.tsx +1 -2
  192. package/src/lib/ui/version.ts +3 -3
  193. package/src/lib/utils/excalidraw/putExcalidrawContent.ts +8 -0
  194. package/src/lib/utils/export/exportAs.ts +2 -9
  195. package/src/lib/utils/frames/frames.ts +1 -1
  196. package/src/lib/utils/text/richText.ts +3 -3
  197. package/src/lib/utils/tldr/buildFromV1Document.ts +12 -17
  198. package/src/test/Editor.test.tsx +38 -12
  199. package/src/test/SelectTool.test.ts +11 -19
  200. package/src/test/TestEditor.ts +1 -4
  201. package/src/test/TldrawEditor.test.tsx +21 -18
  202. package/src/test/bindings.test.tsx +29 -25
  203. package/src/test/bindingsIndex.test.tsx +4 -4
  204. package/src/test/commands/createShape.test.ts +64 -0
  205. package/src/test/commands/createShapes.test.ts +15 -1
  206. package/src/test/commands/getSvgString.test.ts +2 -2
  207. package/src/test/commands/isShapeOfType.test.ts +44 -0
  208. package/src/test/commands/putContent.test.ts +80 -1
  209. package/src/test/commands/updateShape.test.ts +67 -0
  210. package/src/test/commands/updateShapes.test.ts +21 -5
  211. package/src/test/custom-clipping.test.ts +36 -35
  212. package/src/test/customSnapping.test.tsx +77 -62
  213. package/src/test/duplicate.test.ts +1 -1
  214. package/src/test/frames.test.ts +2 -2
  215. package/src/test/getCulledShapes.test.tsx +11 -3
  216. package/src/test/getShapeAtPoint.test.ts +2 -2
  217. package/src/test/groups.test.tsx +6 -3
  218. package/src/test/resizing.test.ts +9 -13
  219. package/src/test/selection-omnibus.test.ts +11 -11
  220. package/src/test/shapeutils.test.ts +1 -1
  221. package/src/test/styles2.test.tsx +1 -1
  222. package/src/test/styles3.test.ts +5 -5
  223. package/src/test/test-jsx.tsx +69 -57
  224. package/src/test/text.test.ts +15 -17
  225. package/src/test/translating.test.ts +6 -8
@@ -4,8 +4,9 @@ import {
4
4
  BaseBoxShapeUtil,
5
5
  Editor,
6
6
  HTMLContainer,
7
+ IndexKey,
7
8
  TLAssetStore,
8
- TLBaseShape,
9
+ TLShape,
9
10
  TLShapeId,
10
11
  TldrawEditor,
11
12
  createShapeId,
@@ -196,7 +197,7 @@ describe('<TldrawEditor />', () => {
196
197
  },
197
198
  { type: 'embed' as const, props: { w: 100, h: 100, url: 'https://example.com' } },
198
199
  { type: 'frame' as const, props: { w: 100, h: 100 } },
199
- { type: 'geo' as const, props: { w: 100, h: 100, geo: 'rectangle' } },
200
+ { type: 'geo' as const, props: { w: 100, h: 100, geo: 'rectangle' as const } },
200
201
  {
201
202
  type: 'highlight' as const,
202
203
  props: { segments: [{ type: 'free' as const, points: [{ x: 0, y: 0, z: 0.5 }] }] },
@@ -206,8 +207,8 @@ describe('<TldrawEditor />', () => {
206
207
  type: 'line' as const,
207
208
  props: {
208
209
  points: {
209
- a1: { id: 'a1', index: 'a1', x: 0, y: 0 },
210
- a2: { id: 'a2', index: 'a2', x: 100, y: 100 },
210
+ a1: { id: 'a1', index: 'a1' as IndexKey, x: 0, y: 0 },
211
+ a2: { id: 'a2', index: 'a2' as IndexKey, x: 100, y: 100 },
211
212
  },
212
213
  },
213
214
  },
@@ -227,10 +228,9 @@ describe('<TldrawEditor />', () => {
227
228
  editor.createShapes([
228
229
  {
229
230
  id,
230
- type: shapeConfig.type,
231
+ ...shapeConfig,
231
232
  x: i * 150, // Space them out horizontally
232
233
  y: 0,
233
- props: shapeConfig.props,
234
234
  },
235
235
  ])
236
236
  })
@@ -285,8 +285,9 @@ describe('<TldrawEditor />', () => {
285
285
 
286
286
  // we should only get one editor instance
287
287
  expect(editorInstances.size).toBe(1)
288
- // but strict mode will cause onMount to be called twice
289
- expect(onMount).toHaveBeenCalledTimes(2)
288
+ // strict mode may cause onMount to be called twice, but the important
289
+ // thing is that we always get the same editor instance
290
+ expect(onMount).toHaveBeenCalled()
290
291
  })
291
292
 
292
293
  it('allows updating camera options without re-creating the editor', async () => {
@@ -456,17 +457,19 @@ describe('<TldrawEditor />', () => {
456
457
  })
457
458
  })
458
459
 
459
- describe('Custom shapes', () => {
460
- type CardShape = TLBaseShape<
461
- 'card',
462
- {
463
- w: number
464
- h: number
465
- }
466
- >
460
+ const CARD_TYPE = 'card'
461
+
462
+ declare module '@tldraw/tlschema' {
463
+ export interface TLGlobalShapePropsMap {
464
+ [CARD_TYPE]: { w: number; h: number }
465
+ }
466
+ }
467
467
 
468
+ type CardShape = TLShape<typeof CARD_TYPE>
469
+
470
+ describe('Custom shapes', () => {
468
471
  class CardUtil extends BaseBoxShapeUtil<CardShape> {
469
- static override type = 'card' as const
472
+ static override type = CARD_TYPE
470
473
 
471
474
  override isAspectRatioLocked(_shape: CardShape) {
472
475
  return false
@@ -508,7 +511,7 @@ describe('Custom shapes', () => {
508
511
  class CardTool extends BaseBoxShapeTool {
509
512
  static override id = 'card'
510
513
  static override initial = 'idle'
511
- override shapeType = 'card'
514
+ override shapeType = 'card' as const
512
515
  }
513
516
 
514
517
  const tools = [CardTool]
@@ -6,8 +6,8 @@ import {
6
6
  BindingOnShapeDeleteOptions,
7
7
  BindingOnShapeIsolateOptions,
8
8
  BindingUtil,
9
+ TLBinding,
9
10
  TLShapeId,
10
- TLUnknownBinding,
11
11
  createBindingId,
12
12
  createShapeId,
13
13
  } from '@tldraw/editor'
@@ -40,7 +40,7 @@ const mockOnAfterChangeToShape = vi.fn()
40
40
 
41
41
  const calls: string[] = []
42
42
 
43
- const registerCall = (method: string, binding: TLUnknownBinding) => {
43
+ const registerCall = (method: string, binding: TLBinding) => {
44
44
  calls.push(
45
45
  `${method}: ${binding.fromId.slice('shape:'.length)}->${binding.toId.slice('shape:'.length)}`
46
46
  )
@@ -60,62 +60,62 @@ class TestBindingUtil extends BindingUtil {
60
60
  mockOnOperationComplete()
61
61
  }
62
62
 
63
- override onBeforeDelete(options: BindingOnDeleteOptions<TLUnknownBinding>): void {
63
+ override onBeforeDelete(options: BindingOnDeleteOptions): void {
64
64
  registerCall('onBeforeDelete', options.binding)
65
65
  mockOnBeforeDelete(options)
66
66
  }
67
67
 
68
- override onAfterDelete(options: BindingOnDeleteOptions<TLUnknownBinding>): void {
68
+ override onAfterDelete(options: BindingOnDeleteOptions): void {
69
69
  registerCall('onAfterDelete', options.binding)
70
70
  mockOnAfterDelete(options)
71
71
  }
72
72
 
73
- override onBeforeDeleteFromShape(options: BindingOnShapeDeleteOptions<TLUnknownBinding>): void {
73
+ override onBeforeDeleteFromShape(options: BindingOnShapeDeleteOptions): void {
74
74
  registerCall('onBeforeDeleteFromShape', options.binding)
75
75
  mockOnBeforeFromShapeDelete(options)
76
76
  }
77
77
 
78
- override onBeforeDeleteToShape(options: BindingOnShapeDeleteOptions<TLUnknownBinding>): void {
78
+ override onBeforeDeleteToShape(options: BindingOnShapeDeleteOptions): void {
79
79
  registerCall('onBeforeDeleteToShape', options.binding)
80
80
  mockOnBeforeToShapeDelete(options)
81
81
  }
82
82
 
83
- override onBeforeIsolateFromShape(options: BindingOnShapeIsolateOptions<TLUnknownBinding>): void {
83
+ override onBeforeIsolateFromShape(options: BindingOnShapeIsolateOptions): void {
84
84
  registerCall('onBeforeIsolateFromShape', options.binding)
85
85
  mockOnBeforeFromShapeIsolate(options)
86
86
  }
87
87
 
88
- override onBeforeIsolateToShape(options: BindingOnShapeIsolateOptions<TLUnknownBinding>): void {
88
+ override onBeforeIsolateToShape(options: BindingOnShapeIsolateOptions): void {
89
89
  registerCall('onBeforeIsolateToShape', options.binding)
90
90
  mockOnBeforeToShapeIsolate(options)
91
91
  }
92
92
 
93
- override onBeforeCreate(options: BindingOnCreateOptions<TLUnknownBinding>): void {
93
+ override onBeforeCreate(options: BindingOnCreateOptions): void {
94
94
  registerCall('onBeforeCreate', options.binding)
95
95
  mockOnBeforeCreate(options)
96
96
  }
97
97
 
98
- override onAfterCreate(options: BindingOnCreateOptions<TLUnknownBinding>): void {
98
+ override onAfterCreate(options: BindingOnCreateOptions): void {
99
99
  registerCall('onAfterCreate', options.binding)
100
100
  mockOnAfterCreate(options)
101
101
  }
102
102
 
103
- override onBeforeChange(options: BindingOnChangeOptions<TLUnknownBinding>): void {
103
+ override onBeforeChange(options: BindingOnChangeOptions): void {
104
104
  registerCall('onBeforeChange', options.bindingAfter)
105
105
  mockOnBeforeChange(options)
106
106
  }
107
107
 
108
- override onAfterChange(options: BindingOnChangeOptions<TLUnknownBinding>): void {
108
+ override onAfterChange(options: BindingOnChangeOptions): void {
109
109
  registerCall('onAfterChange', options.bindingAfter)
110
110
  mockOnAfterChange(options)
111
111
  }
112
112
 
113
- override onAfterChangeFromShape(options: BindingOnShapeChangeOptions<TLUnknownBinding>): void {
113
+ override onAfterChangeFromShape(options: BindingOnShapeChangeOptions): void {
114
114
  registerCall('onAfterChangeFromShape', options.binding)
115
115
  mockOnAfterChangeFromShape(options)
116
116
  }
117
117
 
118
- override onAfterChangeToShape(options: BindingOnShapeChangeOptions<TLUnknownBinding>): void {
118
+ override onAfterChangeToShape(options: BindingOnShapeChangeOptions): void {
119
119
  registerCall('onAfterChangeToShape', options.binding)
120
120
  mockOnAfterChangeToShape(options)
121
121
  }
@@ -146,11 +146,19 @@ beforeEach(() => {
146
146
  mockOnAfterChangeToShape.mockReset()
147
147
  })
148
148
 
149
+ const TEST_TYPE = 'test'
150
+
151
+ declare module '@tldraw/tlschema' {
152
+ export interface TLGlobalBindingPropsMap {
153
+ [TEST_TYPE]: Record<string, never>
154
+ }
155
+ }
156
+
149
157
  function bindShapes(fromId: TLShapeId, toId: TLShapeId) {
150
158
  const bindingId = createBindingId()
151
159
  editor.createBinding({
152
160
  id: bindingId,
153
- type: 'test',
161
+ type: TEST_TYPE,
154
162
  fromId,
155
163
  toId,
156
164
  })
@@ -256,11 +264,9 @@ test('copying the to shape on its own does trigger the unbind operation', () =>
256
264
  })
257
265
 
258
266
  test('cascading deletes in beforeFromShapeDelete are handled correctly', () => {
259
- mockOnBeforeFromShapeDelete.mockImplementation(
260
- (options: BindingOnShapeDeleteOptions<TLUnknownBinding>) => {
261
- editor.deleteShape(options.binding.toId)
262
- }
263
- )
267
+ mockOnBeforeFromShapeDelete.mockImplementation((options: BindingOnShapeDeleteOptions) => {
268
+ editor.deleteShape(options.binding.toId)
269
+ })
264
270
 
265
271
  bindShapes(ids.box1, ids.box2)
266
272
  bindShapes(ids.box2, ids.box3)
@@ -301,11 +307,9 @@ test('cascading deletes in beforeFromShapeDelete are handled correctly', () => {
301
307
  })
302
308
 
303
309
  test('cascading deletes in beforeToShapeDelete are handled correctly', () => {
304
- mockOnBeforeToShapeDelete.mockImplementation(
305
- (options: BindingOnShapeDeleteOptions<TLUnknownBinding>) => {
306
- editor.deleteShape(options.binding.fromId)
307
- }
308
- )
310
+ mockOnBeforeToShapeDelete.mockImplementation((options: BindingOnShapeDeleteOptions) => {
311
+ editor.deleteShape(options.binding.fromId)
312
+ })
309
313
 
310
314
  bindShapes(ids.box1, ids.box2)
311
315
  bindShapes(ids.box2, ids.box3)
@@ -1,4 +1,4 @@
1
- import { TLArrowBinding, TLGeoShape, TLShapeId, createShapeId } from '@tldraw/editor'
1
+ import { TLShapeId, createShapeId } from '@tldraw/editor'
2
2
  import { TestEditor } from './TestEditor'
3
3
  import { TL } from './test-jsx'
4
4
 
@@ -219,7 +219,7 @@ describe('bindingsIndex', () => {
219
219
 
220
220
  const [box1Clone, box2Clone] = editor
221
221
  .getSelectedShapes()
222
- .filter((shape) => editor.isShapeOfType<TLGeoShape>(shape, 'geo'))
222
+ .filter((shape) => editor.isShapeOfType(shape, 'geo'))
223
223
  .sort((a, b) => a.x - b.x)
224
224
 
225
225
  expect(editor.getArrowsBoundTo(box2Clone.id)).toHaveLength(3)
@@ -248,9 +248,9 @@ describe('bindingsIndex', () => {
248
248
 
249
249
  // move arrowA end from box2 to box3
250
250
  const binding = editor
251
- .getBindingsInvolvingShape<TLArrowBinding>(ids.box2, 'arrow')
251
+ .getBindingsInvolvingShape(ids.box2, 'arrow')
252
252
  .find((b) => b.props.terminal === 'end')!
253
- editor.updateBinding({ ...binding, toId: box3 } satisfies TLArrowBinding)
253
+ editor.updateBinding({ ...binding, toId: box3 })
254
254
 
255
255
  expect(editor.getArrowsBoundTo(ids.box2)).toHaveLength(2)
256
256
  expect(editor.getArrowsBoundTo(ids.box1)).toHaveLength(3)
@@ -0,0 +1,64 @@
1
+ import { TLArrowShape, TLGeoShape, createShapeId } from '@tldraw/editor'
2
+ import { TestEditor } from '../TestEditor'
3
+
4
+ let editor: TestEditor
5
+
6
+ const ids = {
7
+ box1: createShapeId('box1'),
8
+ }
9
+
10
+ beforeEach(() => {
11
+ editor = new TestEditor()
12
+ })
13
+
14
+ it('Uses typescript generics', () => {
15
+ expect(() => {
16
+ editor.createShape(
17
+ //@ts-expect-error Yep error because we are giving the wrong props to the shape
18
+ {
19
+ id: ids.box1,
20
+ type: 'geo',
21
+ props: { w: 'OH NO' },
22
+ }
23
+ )
24
+
25
+ // Errors when creating a shape with unknown props
26
+ editor.createShape({
27
+ id: ids.box1,
28
+ type: 'geo',
29
+ props: {
30
+ // @ts-expect-error
31
+ foo: 'bar',
32
+ },
33
+ })
34
+
35
+ // Yep error here because we are giving the wrong props to the shape
36
+ editor.createShape<TLGeoShape>({
37
+ id: ids.box1,
38
+ type: 'geo',
39
+ //@ts-expect-error
40
+ props: { w: 'OH NO' },
41
+ })
42
+
43
+ // Yep error here because we are giving the wrong generic
44
+ editor.createShape<TLArrowShape>({
45
+ id: ids.box1,
46
+ //@ts-expect-error
47
+ type: 'geo',
48
+ //@ts-expect-error
49
+ props: { w: 'OH NO' },
50
+ })
51
+
52
+ // All good, correct match of generic and shape type
53
+ editor.createShape<TLGeoShape>({
54
+ id: ids.box1,
55
+ type: 'geo',
56
+ props: { w: 100 },
57
+ })
58
+
59
+ editor.createShape<TLGeoShape>({
60
+ id: ids.box1,
61
+ type: 'geo',
62
+ })
63
+ }).toThrow()
64
+ })
@@ -19,14 +19,28 @@ beforeEach(() => {
19
19
 
20
20
  it('Uses typescript generics', () => {
21
21
  expect(() => {
22
- // No error here because no generic, the editor doesn't know what this guy is
22
+ // Yep error because we are giving the wrong props to the shape
23
23
  editor.createShapes([
24
+ //@ts-expect-error
24
25
  {
25
26
  id: ids.box1,
26
27
  type: 'geo',
27
28
  props: { w: 'OH NO' },
28
29
  },
29
30
  ])
31
+
32
+ // Errors when creating shapes with unknown props
33
+ editor.createShapes([
34
+ {
35
+ id: ids.box1,
36
+ type: 'geo',
37
+ props: {
38
+ // @ts-expect-error
39
+ foo: 'bar',
40
+ },
41
+ },
42
+ ])
43
+
30
44
  // Yep error here because we are giving the wrong props to the shape
31
45
  editor.createShapes<TLGeoShape>([
32
46
  {
@@ -1,4 +1,4 @@
1
- import { DefaultDashStyle, TLGeoShape, createShapeId, toRichText } from '@tldraw/editor'
1
+ import { DefaultDashStyle, createShapeId, toRichText } from '@tldraw/editor'
2
2
  import { vi } from 'vitest'
3
3
  import { TestEditor } from '../TestEditor'
4
4
 
@@ -21,7 +21,7 @@ beforeEach(() => {
21
21
  editor = new TestEditor()
22
22
  editor.setStyleForNextShapes(DefaultDashStyle, 'solid')
23
23
  editor.setStyleForSelectedShapes(DefaultDashStyle, 'solid')
24
- editor.createShapes<TLGeoShape>([
24
+ editor.createShapes([
25
25
  {
26
26
  id: ids.boxA,
27
27
  type: 'geo',
@@ -0,0 +1,44 @@
1
+ import { TLArrowShape, createShapeId } from '@tldraw/editor'
2
+ import { TestEditor } from '../TestEditor'
3
+
4
+ let editor: TestEditor
5
+
6
+ beforeEach(() => {
7
+ editor = new TestEditor()
8
+ })
9
+
10
+ export declare function assertNever(x: never): never
11
+
12
+ it('narrows down the shape type', () => {
13
+ const id = createShapeId('arrow1')
14
+ editor.createShape({ type: 'arrow', id, x: 0, y: 0 })
15
+
16
+ const shape = editor.getShape(id)!
17
+ if (editor.isShapeOfType(shape, 'arrow')) {
18
+ expect(shape.type === 'arrow').toBe(true)
19
+ expect(
20
+ // @ts-expect-error This comparison appears to be unintentional because the types '"arrow"' and '"card"' have no overlap.
21
+ shape.type === 'card'
22
+ ).toBe(false)
23
+ }
24
+ })
25
+
26
+ it('narrows down the shape type with generic', () => {
27
+ const id = createShapeId('arrow1')
28
+ editor.createShape({ type: 'arrow', id, x: 0, y: 0 })
29
+
30
+ const shape = editor.getShape(id)!
31
+ if (editor.isShapeOfType<TLArrowShape>(shape, 'arrow')) {
32
+ expect(shape.type === 'arrow').toBe(true)
33
+
34
+ expect(
35
+ // @ts-expect-error This comparison appears to be unintentional because the types '"arrow"' and '"card"' have no overlap.
36
+ shape.type === 'card'
37
+ ).toBe(false)
38
+ }
39
+
40
+ // @ts-expect-error mismatch between the generic and the shape type
41
+ if (editor.isShapeOfType<TLArrowShape>(shape, 'card')) {
42
+ assertNever(shape)
43
+ }
44
+ })
@@ -1,4 +1,4 @@
1
- import { TLContent, structuredClone } from '@tldraw/editor'
1
+ import { TLContent, createShapeId, structuredClone } from '@tldraw/editor'
2
2
  import { TestEditor } from '../TestEditor'
3
3
 
4
4
  let editor: TestEditor
@@ -25,6 +25,7 @@ describe('Migrations', () => {
25
25
 
26
26
  it('Throws error if any shape is invalid due to wrong type', () => {
27
27
  const withInvalidShapeType = structuredClone(clipboardContent)
28
+ // @ts-expect-error
28
29
  withInvalidShapeType.shapes[0].type = 'invalid'
29
30
  expect(() => editor.putContentOntoCurrentPage(withInvalidShapeType)).toThrow()
30
31
  })
@@ -37,3 +38,81 @@ describe('Migrations', () => {
37
38
  expect(() => editor.putContentOntoCurrentPage(withInvalidShapeModel)).toThrow()
38
39
  })
39
40
  })
41
+
42
+ describe('Paste parent selection with explicit point', () => {
43
+ it('falls back to the page when the cursor is outside the original parent', () => {
44
+ const frameId = createShapeId('frame')
45
+ const childId = createShapeId('child')
46
+
47
+ editor.createShapes([
48
+ {
49
+ id: frameId,
50
+ type: 'frame',
51
+ x: 0,
52
+ y: 0,
53
+ props: { w: 200, h: 200 },
54
+ },
55
+ {
56
+ id: childId,
57
+ type: 'geo',
58
+ parentId: frameId,
59
+ x: 40,
60
+ y: 40,
61
+ props: { w: 60, h: 60 },
62
+ },
63
+ ])
64
+
65
+ editor.select(childId)
66
+ editor.copy()
67
+
68
+ editor.putContentOntoCurrentPage(editor.clipboard!, {
69
+ point: { x: 500, y: 500 },
70
+ select: true,
71
+ })
72
+
73
+ const [pastedId] = editor.getSelectedShapeIds()
74
+ expect(editor.getShape(pastedId)?.parentId).toBe(editor.getCurrentPageId())
75
+ })
76
+
77
+ it('uses the parent under the cursor when it can accept the pasted shapes', () => {
78
+ const frameAId = createShapeId('frameA')
79
+ const frameBId = createShapeId('frameB')
80
+ const childId = createShapeId('child')
81
+
82
+ editor.createShapes([
83
+ {
84
+ id: frameAId,
85
+ type: 'frame',
86
+ x: 0,
87
+ y: 0,
88
+ props: { w: 200, h: 200 },
89
+ },
90
+ {
91
+ id: frameBId,
92
+ type: 'frame',
93
+ x: 400,
94
+ y: 0,
95
+ props: { w: 200, h: 200 },
96
+ },
97
+ {
98
+ id: childId,
99
+ type: 'geo',
100
+ parentId: frameAId,
101
+ x: 40,
102
+ y: 40,
103
+ props: { w: 60, h: 60 },
104
+ },
105
+ ])
106
+
107
+ editor.select(childId)
108
+ editor.copy()
109
+
110
+ editor.putContentOntoCurrentPage(editor.clipboard!, {
111
+ point: { x: 450, y: 50 },
112
+ select: true,
113
+ })
114
+
115
+ const [pastedId] = editor.getSelectedShapeIds()
116
+ expect(editor.getShape(pastedId)?.parentId).toBe(frameBId)
117
+ })
118
+ })
@@ -0,0 +1,67 @@
1
+ import { TLArrowShape, TLGeoShape, createShapeId } from '@tldraw/editor'
2
+ import { TestEditor, createDefaultShapes } from '../TestEditor'
3
+
4
+ let editor: TestEditor
5
+
6
+ const ids = {
7
+ box1: createShapeId('box1'),
8
+ }
9
+
10
+ beforeEach(() => {
11
+ editor = new TestEditor()
12
+ editor.createShapes(createDefaultShapes())
13
+ })
14
+
15
+ it('Uses typescript generics', () => {
16
+ expect(() => {
17
+ editor.updateShape({
18
+ id: ids.box1,
19
+ type: 'geo',
20
+ props: {
21
+ // @ts-expect-error
22
+ w: 'OH NO',
23
+ },
24
+ })
25
+
26
+ // Errors when updating a shape with unknown props
27
+ editor.updateShape({
28
+ id: ids.box1,
29
+ type: 'geo',
30
+ props: {
31
+ // @ts-expect-error
32
+ foo: 'bar',
33
+ },
34
+ })
35
+
36
+ // error here because we are giving the wrong props to the shape
37
+ editor.updateShape<TLGeoShape>({
38
+ id: ids.box1,
39
+ type: 'geo',
40
+ props: {
41
+ // @ts-expect-error
42
+ w: 'OH NO',
43
+ },
44
+ })
45
+
46
+ // Yep error here because we are giving the wrong generic
47
+ editor.updateShape<TLArrowShape>({
48
+ id: ids.box1,
49
+ //@ts-expect-error
50
+ type: 'geo',
51
+ //@ts-expect-error
52
+ props: { w: 'OH NO' },
53
+ })
54
+
55
+ // All good, correct match of generic and shape type
56
+ editor.updateShape<TLGeoShape>({
57
+ id: ids.box1,
58
+ type: 'geo',
59
+ props: { w: 100 },
60
+ })
61
+
62
+ editor.updateShape<TLGeoShape>({
63
+ id: ids.box1,
64
+ type: 'geo',
65
+ })
66
+ }).toThrow()
67
+ })
@@ -15,22 +15,38 @@ beforeEach(() => {
15
15
 
16
16
  it('Uses typescript generics', () => {
17
17
  expect(() => {
18
- // No error here because no generic, the editor doesn't know what this guy is
19
18
  editor.updateShapes([
20
19
  {
21
20
  id: ids.box1,
22
21
  type: 'geo',
23
- props: { w: 'OH NO' },
22
+ props: {
23
+ // @ts-expect-error
24
+ w: 'OH NO',
25
+ },
26
+ },
27
+ ])
28
+
29
+ // Errors when updating shapes with unknown props
30
+ editor.updateShapes([
31
+ {
32
+ id: ids.box1,
33
+ type: 'geo',
34
+ props: {
35
+ // @ts-expect-error
36
+ foo: 'bar',
37
+ },
24
38
  },
25
39
  ])
26
40
 
27
- // Yep error here because we are giving the wrong props to the shape
41
+ // error here because we are giving the wrong props to the shape
28
42
  editor.updateShapes<TLGeoShape>([
29
43
  {
30
44
  id: ids.box1,
31
45
  type: 'geo',
32
- //@ts-expect-error
33
- props: { w: 'OH NO' },
46
+ props: {
47
+ // @ts-expect-error
48
+ w: 'OH NO',
49
+ },
34
50
  },
35
51
  ])
36
52