tldraw 3.15.0 → 3.16.0-next.c30b1b5e551a

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 (127) hide show
  1. package/dist-cjs/index.d.ts +69 -4
  2. package/dist-cjs/index.js +11 -2
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/canvas/TldrawCropHandles.js.map +2 -2
  5. package/dist-cjs/lib/defaultExternalContentHandlers.js +1 -0
  6. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  7. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +22 -36
  8. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  9. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +16 -4
  10. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +2 -2
  11. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +3 -0
  12. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  13. package/dist-cjs/lib/shapes/line/LineShapeUtil.js +15 -1
  14. package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +2 -2
  15. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +43 -22
  16. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  17. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +2 -15
  18. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
  19. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +5 -0
  20. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
  21. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +8 -0
  22. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
  23. package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js +8 -0
  24. package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js.map +2 -2
  25. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js +8 -0
  26. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  27. package/dist-cjs/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.js.map +2 -2
  28. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +40 -0
  29. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +2 -2
  30. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  31. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +1 -0
  32. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  33. package/dist-cjs/lib/ui/context/actions.js +14 -7
  34. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  35. package/dist-cjs/lib/ui/context/events.js.map +1 -1
  36. package/dist-cjs/lib/ui/hooks/menu-hooks.js.map +2 -2
  37. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  38. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +4 -0
  39. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  40. package/dist-cjs/lib/ui/kbd-utils.js +2 -1
  41. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  42. package/dist-cjs/lib/ui/version.js +3 -3
  43. package/dist-cjs/lib/ui/version.js.map +1 -1
  44. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js +1 -1
  45. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js.map +2 -2
  46. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js +3 -2
  47. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js.map +2 -2
  48. package/dist-esm/index.d.mts +69 -4
  49. package/dist-esm/index.mjs +16 -3
  50. package/dist-esm/index.mjs.map +2 -2
  51. package/dist-esm/lib/canvas/TldrawCropHandles.mjs.map +2 -2
  52. package/dist-esm/lib/defaultExternalContentHandlers.mjs +1 -0
  53. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  54. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +24 -36
  55. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  56. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +19 -5
  57. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +2 -2
  58. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +3 -0
  59. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  60. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +15 -1
  61. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +2 -2
  62. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +43 -22
  63. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  64. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +2 -15
  65. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
  66. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +5 -0
  67. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
  68. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +8 -0
  69. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
  70. package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs +8 -0
  71. package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs.map +2 -2
  72. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs +8 -0
  73. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  74. package/dist-esm/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.mjs.map +2 -2
  75. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +40 -0
  76. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +2 -2
  77. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  78. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +1 -0
  79. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  80. package/dist-esm/lib/ui/context/actions.mjs +14 -7
  81. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  82. package/dist-esm/lib/ui/context/events.mjs.map +1 -1
  83. package/dist-esm/lib/ui/hooks/menu-hooks.mjs.map +2 -2
  84. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +4 -0
  85. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  86. package/dist-esm/lib/ui/kbd-utils.mjs +2 -1
  87. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  88. package/dist-esm/lib/ui/version.mjs +3 -3
  89. package/dist-esm/lib/ui/version.mjs.map +1 -1
  90. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs +1 -1
  91. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs.map +2 -2
  92. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs +3 -2
  93. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs.map +2 -2
  94. package/package.json +3 -3
  95. package/src/index.ts +9 -1
  96. package/src/lib/canvas/TldrawCropHandles.tsx +2 -0
  97. package/src/lib/defaultExternalContentHandlers.ts +2 -1
  98. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +5 -5
  99. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +25 -39
  100. package/src/lib/shapes/arrow/arrowLabel.ts +23 -3
  101. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +3 -0
  102. package/src/lib/shapes/line/LineShapeUtil.tsx +19 -2
  103. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +54 -30
  104. package/src/lib/tools/SelectTool/childStates/Idle.ts +2 -24
  105. package/src/lib/tools/SelectTool/childStates/PointingShape.ts +7 -0
  106. package/src/lib/tools/SelectTool/childStates/Resizing.ts +12 -1
  107. package/src/lib/tools/SelectTool/childStates/Rotating.ts +11 -0
  108. package/src/lib/tools/SelectTool/childStates/Translating.ts +11 -0
  109. package/src/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.ts +1 -0
  110. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +32 -0
  111. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +3 -1
  112. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +1 -0
  113. package/src/lib/ui/context/actions.tsx +14 -7
  114. package/src/lib/ui/context/events.tsx +2 -2
  115. package/src/lib/ui/hooks/menu-hooks.ts +1 -0
  116. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +4 -0
  117. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +4 -0
  118. package/src/lib/ui/kbd-utils.ts +2 -1
  119. package/src/lib/ui/version.ts +3 -3
  120. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +16 -2
  121. package/src/lib/utils/excalidraw/putExcalidrawContent.ts +1 -1
  122. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +24 -3
  123. package/src/lib/utils/tldr/buildFromV1Document.ts +2 -1
  124. package/src/test/SelectTool.test.ts +37 -11
  125. package/src/test/commands/deletePage.test.ts +84 -1
  126. package/src/test/shapeutils.test.ts +394 -45
  127. package/tldraw.css +4 -23
@@ -112,13 +112,20 @@ exports[`buildFromV1Document test fixtures arrow-binding.tldr 1`] = `
112
112
  "kind": "arc",
113
113
  "labelColor": "red",
114
114
  "labelPosition": 0.5,
115
+ "richText": {
116
+ "content": [
117
+ {
118
+ "type": "paragraph",
119
+ },
120
+ ],
121
+ "type": "doc",
122
+ },
115
123
  "scale": 1,
116
124
  "size": "m",
117
125
  "start": {
118
126
  "x": 146.32,
119
127
  "y": 0,
120
128
  },
121
- "text": "",
122
129
  },
123
130
  "rotation": 0,
124
131
  "type": "arrow",
@@ -241,13 +248,20 @@ exports[`buildFromV1Document test fixtures exact-arrow-binding.tldr 1`] = `
241
248
  "kind": "arc",
242
249
  "labelColor": "red",
243
250
  "labelPosition": 0.5,
251
+ "richText": {
252
+ "content": [
253
+ {
254
+ "type": "paragraph",
255
+ },
256
+ ],
257
+ "type": "doc",
258
+ },
244
259
  "scale": 1,
245
260
  "size": "m",
246
261
  "start": {
247
262
  "x": 293.36,
248
263
  "y": 0,
249
264
  },
250
- "text": "",
251
265
  },
252
266
  "rotation": 0,
253
267
  "type": "arrow",
@@ -389,13 +403,20 @@ exports[`buildFromV1Document test fixtures incorrect-arrow-binding.tldr 1`] = `
389
403
  "kind": "arc",
390
404
  "labelColor": "red",
391
405
  "labelPosition": 0.5,
406
+ "richText": {
407
+ "content": [
408
+ {
409
+ "type": "paragraph",
410
+ },
411
+ ],
412
+ "type": "doc",
413
+ },
392
414
  "scale": 1,
393
415
  "size": "m",
394
416
  "start": {
395
417
  "x": 252.64,
396
418
  "y": 0,
397
419
  },
398
- "text": "",
399
420
  },
400
421
  "rotation": 0,
401
422
  "type": "arrow",
@@ -405,7 +405,7 @@ export function buildFromV1Document(editor: Editor, _document: unknown) {
405
405
  ...inCommon,
406
406
  type: 'arrow',
407
407
  props: {
408
- text: v1Shape.label ?? '',
408
+ richText: toRichText(v1Shape.label ?? ''),
409
409
  color: getV2Color(v1Shape.style.color),
410
410
  labelColor: getV2Color(v1Shape.style.color),
411
411
  size: getV2Size(v1Shape.style.size),
@@ -562,6 +562,7 @@ export function buildFromV1Document(editor: Editor, _document: unknown) {
562
562
  y: point.y,
563
563
  },
564
564
  isPrecise: point.x !== 0.5 || point.y !== 0.5,
565
+ isCreatingShape: true,
565
566
  })
566
567
 
567
568
  if (change) {
@@ -275,17 +275,27 @@ describe('PointingLabel', () => {
275
275
  type: 'arrow',
276
276
  x: 100,
277
277
  y: 100,
278
- props: { text: 'Test Label', end: { x: 100, y: 100 } },
278
+ props: {
279
+ richText: toRichText('Test Label'),
280
+ start: { x: 0, y: 0 },
281
+ end: { x: 100, y: 0 },
282
+ },
279
283
  },
280
284
  ])
281
- const shape = editor.getShape(ids.arrow1)
282
- editor.pointerDown(150, 150, {
285
+ const shape = editor.getShape(ids.arrow1)!
286
+ // First select the shape so it's already selected
287
+ editor.select(shape.id)
288
+
289
+ // Click at the middle of the arrow where the label would be and drag to move the label
290
+ editor.pointerDown(150, 100, {
283
291
  target: 'shape',
284
292
  shape,
285
293
  })
286
- editor.pointerMove(100, 100)
294
+ editor.pointerMove(160, 100)
287
295
  editor.expectToBeIn('select.pointing_arrow_label')
288
296
 
297
+ // Continue dragging to actually move the label, then it should go to idle
298
+ editor.pointerMove(170, 100)
289
299
  editor.pointerUp()
290
300
  editor.expectToBeIn('select.idle')
291
301
  })
@@ -297,16 +307,21 @@ describe('PointingLabel', () => {
297
307
  type: 'arrow',
298
308
  x: 100,
299
309
  y: 100,
300
- props: { text: 'Test Label', end: { x: 100, y: 100 } },
310
+ props: {
311
+ richText: toRichText('Test Label'),
312
+ start: { x: 0, y: 0 },
313
+ end: { x: 100, y: 0 },
314
+ },
301
315
  },
302
316
  ])
303
317
  const shape = editor.getShape(ids.arrow1)
304
318
 
305
- editor.pointerDown(150, 150, {
319
+ // Click at the middle of the arrow where the label would be
320
+ editor.pointerDown(150, 100, {
306
321
  target: 'shape',
307
322
  shape,
308
323
  })
309
- editor.pointerMove(100, 100)
324
+ editor.pointerMove(160, 100)
310
325
  editor.expectToBeIn('select.pointing_arrow_label')
311
326
  editor.cancel()
312
327
  editor.expectToBeIn('select.idle')
@@ -314,14 +329,25 @@ describe('PointingLabel', () => {
314
329
 
315
330
  it('Doesnt go into pointing_arrow_label mode if not selecting the arrow shape', () => {
316
331
  editor.createShapes<TLArrowShape>([
317
- { id: ids.arrow1, type: 'arrow', x: 100, y: 100, props: { text: 'Test Label' } },
332
+ {
333
+ id: ids.arrow1,
334
+ type: 'arrow',
335
+ x: 100,
336
+ y: 100,
337
+ props: {
338
+ richText: toRichText(''), // Empty label
339
+ start: { x: 0, y: 0 },
340
+ end: { x: 100, y: 0 },
341
+ },
342
+ },
318
343
  ])
319
- const shape = editor.getShape(ids.arrow1)
320
- editor.pointerDown(0, 150, {
344
+ const shape = editor.getShape(ids.arrow1)!
345
+ // Click anywhere on the arrow - since there's no label, it should go to translating
346
+ editor.pointerDown(150, 100, {
321
347
  target: 'shape',
322
348
  shape,
323
349
  })
324
- editor.pointerMove(100, 100)
350
+ editor.pointerMove(155, 105)
325
351
  editor.expectToBeIn('select.translating')
326
352
 
327
353
  editor.pointerUp()
@@ -1,4 +1,4 @@
1
- import { PageRecordType } from '@tldraw/editor'
1
+ import { PageRecordType, createShapeId } from '@tldraw/editor'
2
2
  import { TestEditor } from '../TestEditor'
3
3
 
4
4
  let editor: TestEditor
@@ -76,4 +76,87 @@ describe('deletePage', () => {
76
76
  expect(editor.getCurrentPageId()).not.toBe(currentPageId)
77
77
  expect(editor.getCurrentPageId()).toBe(editor.getPages()[0].id)
78
78
  })
79
+
80
+ it('deletes all shapes that belong to the deleted page', () => {
81
+ // Create a second page
82
+ const page2Id = PageRecordType.createId('page2')
83
+ editor.createPage({ name: 'Page 2', id: page2Id })
84
+
85
+ // Switch to the second page
86
+ editor.setCurrentPage(page2Id)
87
+
88
+ // Add some shapes to the second page
89
+ const shape1Id = createShapeId('shape1')
90
+ const shape2Id = createShapeId('shape2')
91
+ const shape3Id = createShapeId('shape3')
92
+
93
+ editor.createShape({ id: shape1Id, type: 'text', x: 100, y: 100 })
94
+ editor.createShape({ id: shape2Id, type: 'geo', x: 200, y: 200, props: { geo: 'rectangle' } })
95
+ editor.createShape({ id: shape3Id, type: 'geo', x: 300, y: 300, props: { geo: 'ellipse' } })
96
+
97
+ // Verify shapes were created and belong to the second page
98
+ expect(editor.getShape(shape1Id)).toBeDefined()
99
+ expect(editor.getShape(shape2Id)).toBeDefined()
100
+ expect(editor.getShape(shape3Id)).toBeDefined()
101
+ expect(editor.getShape(shape1Id)?.parentId).toBe(page2Id)
102
+ expect(editor.getShape(shape2Id)?.parentId).toBe(page2Id)
103
+ expect(editor.getShape(shape3Id)?.parentId).toBe(page2Id)
104
+
105
+ // Delete the second page
106
+ editor.deletePage(page2Id)
107
+
108
+ // Verify the page was deleted
109
+ expect(editor.getPages().length).toBe(1)
110
+ expect(editor.getPages()[0].id).not.toBe(page2Id)
111
+
112
+ // Verify all shapes that belonged to the deleted page were also deleted
113
+ expect(editor.getShape(shape1Id)).toBeUndefined()
114
+ expect(editor.getShape(shape2Id)).toBeUndefined()
115
+ expect(editor.getShape(shape3Id)).toBeUndefined()
116
+ })
117
+
118
+ it('deletes locked shapes that belong to the deleted page', () => {
119
+ // Create a second page
120
+ const page2Id = PageRecordType.createId('page2')
121
+ editor.createPage({ name: 'Page 2', id: page2Id })
122
+
123
+ // Switch to the second page
124
+ editor.setCurrentPage(page2Id)
125
+
126
+ // Add some shapes to the second page
127
+ const shape1Id = createShapeId('shape1')
128
+ const shape2Id = createShapeId('shape2')
129
+ const shape3Id = createShapeId('shape3')
130
+
131
+ editor.createShape({ id: shape1Id, type: 'text', x: 100, y: 100 })
132
+ editor.createShape({ id: shape2Id, type: 'geo', x: 200, y: 200, props: { geo: 'rectangle' } })
133
+ editor.createShape({ id: shape3Id, type: 'geo', x: 300, y: 300, props: { geo: 'ellipse' } })
134
+
135
+ // Lock some of the shapes
136
+ editor.updateShape({ id: shape1Id, type: 'text', isLocked: true })
137
+ editor.updateShape({ id: shape2Id, type: 'geo', isLocked: true })
138
+
139
+ // Verify shapes were created and belong to the second page
140
+ expect(editor.getShape(shape1Id)).toBeDefined()
141
+ expect(editor.getShape(shape2Id)).toBeDefined()
142
+ expect(editor.getShape(shape3Id)).toBeDefined()
143
+ expect(editor.getShape(shape1Id)?.parentId).toBe(page2Id)
144
+ expect(editor.getShape(shape2Id)?.parentId).toBe(page2Id)
145
+ expect(editor.getShape(shape3Id)?.parentId).toBe(page2Id)
146
+ expect(editor.getShape(shape1Id)?.isLocked).toBe(true)
147
+ expect(editor.getShape(shape2Id)?.isLocked).toBe(true)
148
+ expect(editor.getShape(shape3Id)?.isLocked).toBe(false)
149
+
150
+ // Delete the second page
151
+ editor.deletePage(page2Id)
152
+
153
+ // Verify the page was deleted
154
+ expect(editor.getPages().length).toBe(1)
155
+ expect(editor.getPages()[0].id).not.toBe(page2Id)
156
+
157
+ // Verify all shapes that belonged to the deleted page were also deleted, including locked ones
158
+ expect(editor.getShape(shape1Id)).toBeUndefined()
159
+ expect(editor.getShape(shape2Id)).toBeUndefined()
160
+ expect(editor.getShape(shape3Id)).toBeUndefined()
161
+ })
79
162
  })