@tldraw/editor 3.16.0-internal.51e99e128bd4 → 3.16.0-internal.a478398270c6

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 (217) hide show
  1. package/dist-cjs/index.d.ts +16 -217
  2. package/dist-cjs/index.js +1 -8
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +1 -3
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/MenuClickCapture.js +5 -0
  7. package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
  8. package/dist-cjs/lib/components/SVGContainer.js +1 -1
  9. package/dist-cjs/lib/components/SVGContainer.js.map +2 -2
  10. package/dist-cjs/lib/components/Shape.js +26 -4
  11. package/dist-cjs/lib/components/Shape.js.map +2 -2
  12. package/dist-cjs/lib/components/default-components/DefaultBrush.js +1 -1
  13. package/dist-cjs/lib/components/default-components/DefaultBrush.js.map +2 -2
  14. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -1
  15. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  16. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +2 -2
  17. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +2 -2
  18. package/dist-cjs/lib/components/default-components/DefaultCursor.js +1 -1
  19. package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +2 -2
  20. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
  21. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
  22. package/dist-cjs/lib/components/default-components/DefaultGrid.js +1 -1
  23. package/dist-cjs/lib/components/default-components/DefaultGrid.js.map +2 -2
  24. package/dist-cjs/lib/components/default-components/DefaultHandles.js +1 -1
  25. package/dist-cjs/lib/components/default-components/DefaultHandles.js.map +2 -2
  26. package/dist-cjs/lib/components/default-components/DefaultScribble.js +1 -1
  27. package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +2 -2
  28. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +1 -9
  29. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  30. package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js +1 -1
  31. package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js.map +2 -2
  32. package/dist-cjs/lib/components/default-components/DefaultSpinner.js +15 -27
  33. package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +3 -3
  34. package/dist-cjs/lib/config/TLUserPreferences.js +3 -15
  35. package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
  36. package/dist-cjs/lib/editor/Editor.js +67 -134
  37. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  38. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +4 -14
  39. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  40. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  41. package/dist-cjs/lib/editor/tools/StateNode.js +1 -20
  42. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  43. package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
  44. package/dist-cjs/lib/exports/getSvgJsx.js +2 -1
  45. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  46. package/dist-cjs/lib/hooks/useCanvasEvents.js +20 -24
  47. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  48. package/dist-cjs/lib/hooks/useEditor.js +4 -1
  49. package/dist-cjs/lib/hooks/useEditor.js.map +2 -2
  50. package/dist-cjs/lib/hooks/useEditorComponents.js +0 -2
  51. package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
  52. package/dist-cjs/lib/license/Watermark.js +8 -8
  53. package/dist-cjs/lib/license/Watermark.js.map +2 -2
  54. package/dist-cjs/lib/options.js +0 -7
  55. package/dist-cjs/lib/options.js.map +2 -2
  56. package/dist-cjs/lib/primitives/geometry/Arc2d.js +1 -1
  57. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  58. package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
  59. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
  60. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +1 -3
  61. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  62. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +1 -1
  63. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
  64. package/dist-cjs/lib/primitives/geometry/geometry-constants.js +2 -2
  65. package/dist-cjs/lib/primitives/geometry/geometry-constants.js.map +2 -2
  66. package/dist-cjs/lib/primitives/intersect.js +4 -4
  67. package/dist-cjs/lib/primitives/intersect.js.map +2 -2
  68. package/dist-cjs/lib/primitives/utils.js +0 -4
  69. package/dist-cjs/lib/primitives/utils.js.map +2 -2
  70. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +1 -0
  71. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
  72. package/dist-cjs/version.js +3 -3
  73. package/dist-cjs/version.js.map +1 -1
  74. package/dist-esm/index.d.mts +16 -217
  75. package/dist-esm/index.mjs +2 -16
  76. package/dist-esm/index.mjs.map +2 -2
  77. package/dist-esm/lib/TldrawEditor.mjs +1 -3
  78. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  79. package/dist-esm/lib/components/MenuClickCapture.mjs +5 -0
  80. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  81. package/dist-esm/lib/components/SVGContainer.mjs +1 -1
  82. package/dist-esm/lib/components/SVGContainer.mjs.map +2 -2
  83. package/dist-esm/lib/components/Shape.mjs +26 -4
  84. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  85. package/dist-esm/lib/components/default-components/DefaultBrush.mjs +1 -1
  86. package/dist-esm/lib/components/default-components/DefaultBrush.mjs.map +2 -2
  87. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -1
  88. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  89. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +2 -2
  90. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +2 -2
  91. package/dist-esm/lib/components/default-components/DefaultCursor.mjs +1 -1
  92. package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +2 -2
  93. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
  94. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
  95. package/dist-esm/lib/components/default-components/DefaultGrid.mjs +1 -1
  96. package/dist-esm/lib/components/default-components/DefaultGrid.mjs.map +2 -2
  97. package/dist-esm/lib/components/default-components/DefaultHandles.mjs +1 -1
  98. package/dist-esm/lib/components/default-components/DefaultHandles.mjs.map +2 -2
  99. package/dist-esm/lib/components/default-components/DefaultScribble.mjs +1 -1
  100. package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +2 -2
  101. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +1 -9
  102. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  103. package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs +1 -1
  104. package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs.map +2 -2
  105. package/dist-esm/lib/components/default-components/DefaultSpinner.mjs +15 -17
  106. package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
  107. package/dist-esm/lib/config/TLUserPreferences.mjs +3 -15
  108. package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
  109. package/dist-esm/lib/editor/Editor.mjs +67 -134
  110. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  111. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +4 -14
  112. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  113. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  114. package/dist-esm/lib/editor/tools/StateNode.mjs +1 -20
  115. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  116. package/dist-esm/lib/exports/getSvgJsx.mjs +2 -2
  117. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  118. package/dist-esm/lib/hooks/useCanvasEvents.mjs +21 -25
  119. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  120. package/dist-esm/lib/hooks/useEditor.mjs +4 -1
  121. package/dist-esm/lib/hooks/useEditor.mjs.map +2 -2
  122. package/dist-esm/lib/hooks/useEditorComponents.mjs +0 -4
  123. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  124. package/dist-esm/lib/license/Watermark.mjs +8 -8
  125. package/dist-esm/lib/license/Watermark.mjs.map +2 -2
  126. package/dist-esm/lib/options.mjs +0 -7
  127. package/dist-esm/lib/options.mjs.map +2 -2
  128. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +2 -2
  129. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  130. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +2 -2
  131. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
  132. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +1 -3
  133. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  134. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +2 -2
  135. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
  136. package/dist-esm/lib/primitives/geometry/geometry-constants.mjs +2 -2
  137. package/dist-esm/lib/primitives/geometry/geometry-constants.mjs.map +2 -2
  138. package/dist-esm/lib/primitives/intersect.mjs +5 -5
  139. package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
  140. package/dist-esm/lib/primitives/utils.mjs +0 -4
  141. package/dist-esm/lib/primitives/utils.mjs.map +2 -2
  142. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +1 -0
  143. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
  144. package/dist-esm/version.mjs +3 -3
  145. package/dist-esm/version.mjs.map +1 -1
  146. package/editor.css +313 -312
  147. package/package.json +38 -16
  148. package/src/index.ts +1 -15
  149. package/src/lib/TldrawEditor.tsx +5 -7
  150. package/src/lib/components/MenuClickCapture.tsx +8 -0
  151. package/src/lib/components/SVGContainer.tsx +1 -1
  152. package/src/lib/components/Shape.tsx +21 -6
  153. package/src/lib/components/default-components/DefaultBrush.tsx +1 -1
  154. package/src/lib/components/default-components/DefaultCanvas.tsx +1 -1
  155. package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +2 -2
  156. package/src/lib/components/default-components/DefaultCursor.tsx +1 -1
  157. package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
  158. package/src/lib/components/default-components/DefaultGrid.tsx +1 -1
  159. package/src/lib/components/default-components/DefaultHandles.tsx +1 -5
  160. package/src/lib/components/default-components/DefaultScribble.tsx +1 -1
  161. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +2 -6
  162. package/src/lib/components/default-components/DefaultSnapIndictor.tsx +1 -1
  163. package/src/lib/components/default-components/DefaultSpinner.tsx +12 -12
  164. package/src/lib/config/TLUserPreferences.ts +1 -15
  165. package/src/lib/editor/Editor.test.ts +8 -416
  166. package/src/lib/editor/Editor.ts +92 -177
  167. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +14 -15
  168. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +15 -16
  169. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +48 -49
  170. package/src/lib/editor/managers/FontManager/FontManager.test.ts +23 -24
  171. package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +6 -7
  172. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +11 -12
  173. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +50 -57
  174. package/src/lib/editor/managers/TextManager/TextManager.test.ts +26 -51
  175. package/src/lib/editor/managers/TickManager/TickManager.test.ts +13 -14
  176. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +26 -55
  177. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +1 -14
  178. package/src/lib/editor/shapes/ShapeUtil.ts +0 -57
  179. package/src/lib/editor/tools/StateNode.ts +1 -27
  180. package/src/lib/editor/types/misc-types.ts +1 -73
  181. package/src/lib/exports/getSvgJsx.tsx +2 -2
  182. package/src/lib/hooks/useCanvasEvents.ts +32 -39
  183. package/src/lib/hooks/useEditor.tsx +5 -6
  184. package/src/lib/hooks/useEditorComponents.tsx +2 -8
  185. package/src/lib/license/LicenseManager.test.ts +1 -3
  186. package/src/lib/license/Watermark.test.tsx +1 -2
  187. package/src/lib/license/Watermark.tsx +8 -8
  188. package/src/lib/options.ts +0 -8
  189. package/src/lib/primitives/geometry/Arc2d.ts +2 -2
  190. package/src/lib/primitives/geometry/Circle2d.ts +2 -2
  191. package/src/lib/primitives/geometry/CubicBezier2d.ts +1 -4
  192. package/src/lib/primitives/geometry/Ellipse2d.ts +2 -2
  193. package/src/lib/primitives/geometry/geometry-constants.ts +1 -2
  194. package/src/lib/primitives/intersect.ts +5 -12
  195. package/src/lib/primitives/utils.ts +0 -11
  196. package/src/lib/test/currentToolIdMask.test.ts +49 -0
  197. package/src/lib/utils/sync/LocalIndexedDb.test.ts +1 -2
  198. package/src/lib/utils/sync/TLLocalSyncClient.test.ts +15 -15
  199. package/src/lib/utils/sync/TLLocalSyncClient.ts +1 -0
  200. package/src/version.ts +3 -3
  201. package/dist-cjs/lib/components/default-components/DefaultShapeWrapper.js +0 -53
  202. package/dist-cjs/lib/components/default-components/DefaultShapeWrapper.js.map +0 -7
  203. package/dist-cjs/lib/hooks/useStateAttribute.js +0 -35
  204. package/dist-cjs/lib/hooks/useStateAttribute.js.map +0 -7
  205. package/dist-cjs/lib/utils/EditorAtom.js +0 -45
  206. package/dist-cjs/lib/utils/EditorAtom.js.map +0 -7
  207. package/dist-esm/lib/components/default-components/DefaultShapeWrapper.mjs +0 -23
  208. package/dist-esm/lib/components/default-components/DefaultShapeWrapper.mjs.map +0 -7
  209. package/dist-esm/lib/hooks/useStateAttribute.mjs +0 -15
  210. package/dist-esm/lib/hooks/useStateAttribute.mjs.map +0 -7
  211. package/dist-esm/lib/utils/EditorAtom.mjs +0 -25
  212. package/dist-esm/lib/utils/EditorAtom.mjs.map +0 -7
  213. package/src/lib/components/default-components/DefaultShapeWrapper.tsx +0 -35
  214. package/src/lib/editor/tools/StateNode.test.ts +0 -285
  215. package/src/lib/hooks/useStateAttribute.ts +0 -15
  216. package/src/lib/primitives/intersect.test.ts +0 -946
  217. package/src/lib/utils/EditorAtom.ts +0 -37
@@ -1,4 +1,3 @@
1
- import { vi } from 'vitest'
2
1
  import {
3
2
  Box,
4
3
  Geometry2d,
@@ -60,8 +59,8 @@ beforeEach(() => {
60
59
  getContainer: () => document.body,
61
60
  })
62
61
  editor.setCameraOptions({ isLocked: true })
63
- editor.setCamera = vi.fn()
64
- editor.user.getAnimationSpeed = vi.fn()
62
+ editor.setCamera = jest.fn()
63
+ editor.user.getAnimationSpeed = jest.fn()
65
64
  })
66
65
 
67
66
  describe('centerOnPoint', () => {
@@ -95,13 +94,13 @@ describe('updateShape', () => {
95
94
 
96
95
  describe('zoomToFit', () => {
97
96
  it('no-op when isLocked is set', () => {
98
- editor.getCurrentPageShapeIds = vi.fn(() => new Set([createShapeId('box1')]))
97
+ editor.getCurrentPageShapeIds = jest.fn(() => new Set([createShapeId('box1')]))
99
98
  editor.zoomToFit()
100
99
  expect(editor.setCamera).not.toHaveBeenCalled()
101
100
  })
102
101
 
103
102
  it('sets camera when isLocked is set and force flag is set', () => {
104
- editor.getCurrentPageShapeIds = vi.fn(() => new Set([createShapeId('box1')]))
103
+ editor.getCurrentPageShapeIds = jest.fn(() => new Set([createShapeId('box1')]))
105
104
  editor.zoomToFit({ force: true })
106
105
  expect(editor.setCamera).toHaveBeenCalled()
107
106
  })
@@ -145,13 +144,13 @@ describe('zoomOut', () => {
145
144
 
146
145
  describe('zoomToSelection', () => {
147
146
  it('no-op when isLocked is set', () => {
148
- editor.getSelectionPageBounds = vi.fn(() => Box.From({ x: 0, y: 0, w: 100, h: 100 }))
147
+ editor.getSelectionPageBounds = jest.fn(() => Box.From({ x: 0, y: 0, w: 100, h: 100 }))
149
148
  editor.zoomToSelection()
150
149
  expect(editor.setCamera).not.toHaveBeenCalled()
151
150
  })
152
151
 
153
152
  it('sets camera when isLocked is set and force flag is set', () => {
154
- editor.getSelectionPageBounds = vi.fn(() => Box.From({ x: 0, y: 0, w: 100, h: 100 }))
153
+ editor.getSelectionPageBounds = jest.fn(() => Box.From({ x: 0, y: 0, w: 100, h: 100 }))
155
154
  editor.zoomToSelection({ force: true })
156
155
  expect(editor.setCamera).toHaveBeenCalled()
157
156
  })
@@ -287,7 +286,7 @@ describe('getShapesAtPoint', () => {
287
286
 
288
287
  it('filters out hidden shapes', () => {
289
288
  // Create a spy to mock isShapeHidden
290
- const isShapeHiddenSpy = vi.spyOn(editor, 'isShapeHidden')
289
+ const isShapeHiddenSpy = jest.spyOn(editor, 'isShapeHidden')
291
290
  isShapeHiddenSpy.mockImplementation((shape) => {
292
291
  return typeof shape === 'string' ? shape === ids.shape3 : shape.id === ids.shape3
293
292
  })
@@ -353,7 +352,7 @@ describe('getShapesAtPoint', () => {
353
352
 
354
353
  it('returns empty array when all shapes are hidden', () => {
355
354
  // Mock all shapes as hidden
356
- const isShapeHiddenSpy = vi.spyOn(editor, 'isShapeHidden')
355
+ const isShapeHiddenSpy = jest.spyOn(editor, 'isShapeHidden')
357
356
  isShapeHiddenSpy.mockReturnValue(true)
358
357
 
359
358
  const shapes = editor.getShapesAtPoint({ x: 50, y: 50 })
@@ -426,410 +425,3 @@ describe('getShapesAtPoint', () => {
426
425
  expect(hollowShapesWithHitInside[0].id).toBe(ids.hollowShape)
427
426
  })
428
427
  })
429
-
430
- describe('selectAll', () => {
431
- const selectAllIds = {
432
- pageShape1: createShapeId('pageShape1'),
433
- pageShape2: createShapeId('pageShape2'),
434
- pageShape3: createShapeId('pageShape3'),
435
- container1: createShapeId('container1'),
436
- containerChild1: createShapeId('containerChild1'),
437
- containerChild2: createShapeId('containerChild2'),
438
- containerChild3: createShapeId('containerChild3'),
439
- containerGrandchild1: createShapeId('containerGrandchild1'),
440
- container2: createShapeId('container2'),
441
- container2Child1: createShapeId('container2Child1'),
442
- container2Child2: createShapeId('container2Child2'),
443
- container2Grandchild1: createShapeId('container2Grandchild1'),
444
- lockedShape: createShapeId('lockedShape'),
445
- }
446
-
447
- beforeEach(() => {
448
- // Clear any existing shapes
449
- editor.selectAll().deleteShapes(editor.getSelectedShapeIds())
450
-
451
- // Create shapes directly on the page (no parentId means they're children of the page)
452
- editor.createShapes([
453
- {
454
- id: selectAllIds.pageShape1,
455
- type: 'my-custom-shape',
456
- x: 100,
457
- y: 100,
458
- props: { w: 100, h: 100 },
459
- },
460
- {
461
- id: selectAllIds.pageShape2,
462
- type: 'my-custom-shape',
463
- x: 300,
464
- y: 100,
465
- props: { w: 100, h: 100 },
466
- },
467
- {
468
- id: selectAllIds.pageShape3,
469
- type: 'my-custom-shape',
470
- x: 500,
471
- y: 100,
472
- props: { w: 100, h: 100 },
473
- },
474
- {
475
- id: selectAllIds.lockedShape,
476
- type: 'my-custom-shape',
477
- x: 700,
478
- y: 100,
479
- props: { w: 100, h: 100 },
480
- isLocked: true,
481
- },
482
- ])
483
-
484
- // Create a container shape (simulating a frame or group)
485
- editor.createShape({
486
- id: selectAllIds.container1,
487
- type: 'my-custom-shape',
488
- x: 100,
489
- y: 300,
490
- props: { w: 400, h: 200 },
491
- })
492
-
493
- // Create children inside the container (parentId set to container1)
494
- editor.createShapes([
495
- {
496
- id: selectAllIds.containerChild1,
497
- type: 'my-custom-shape',
498
- parentId: selectAllIds.container1,
499
- x: 120,
500
- y: 320,
501
- props: { w: 50, h: 50 },
502
- },
503
- {
504
- id: selectAllIds.containerChild2,
505
- type: 'my-custom-shape',
506
- parentId: selectAllIds.container1,
507
- x: 200,
508
- y: 320,
509
- props: { w: 50, h: 50 },
510
- },
511
- {
512
- id: selectAllIds.containerChild3,
513
- type: 'my-custom-shape',
514
- parentId: selectAllIds.container1,
515
- x: 280,
516
- y: 320,
517
- props: { w: 50, h: 50 },
518
- },
519
- ])
520
-
521
- // Create a grandchild inside one of the container children
522
- editor.createShape({
523
- id: selectAllIds.containerGrandchild1,
524
- type: 'my-custom-shape',
525
- parentId: selectAllIds.containerChild3,
526
- x: 290,
527
- y: 330,
528
- props: { w: 30, h: 30 },
529
- })
530
-
531
- // Create a second container (simulating a group)
532
- editor.createShape({
533
- id: selectAllIds.container2,
534
- type: 'my-custom-shape',
535
- x: 600,
536
- y: 300,
537
- props: { w: 200, h: 200 },
538
- })
539
-
540
- // Create children inside the second container
541
- editor.createShapes([
542
- {
543
- id: selectAllIds.container2Child1,
544
- type: 'my-custom-shape',
545
- parentId: selectAllIds.container2,
546
- x: 620,
547
- y: 320,
548
- props: { w: 50, h: 50 },
549
- },
550
- {
551
- id: selectAllIds.container2Child2,
552
- type: 'my-custom-shape',
553
- parentId: selectAllIds.container2,
554
- x: 680,
555
- y: 320,
556
- props: { w: 50, h: 50 },
557
- },
558
- ])
559
-
560
- // Create a grandchild in the second container
561
- editor.createShape({
562
- id: selectAllIds.container2Grandchild1,
563
- type: 'my-custom-shape',
564
- parentId: selectAllIds.container2Child1,
565
- x: 630,
566
- y: 330,
567
- props: { w: 30, h: 30 },
568
- })
569
-
570
- // Clear selection
571
- editor.selectNone()
572
- })
573
-
574
- it('when no shapes are selected, selects all page-level shapes (excluding locked ones)', () => {
575
- // Initially no shapes selected
576
- expect(editor.getSelectedShapeIds()).toEqual([])
577
-
578
- // Call selectAll
579
- editor.selectAll()
580
-
581
- // Should select all page-level shapes (excluding locked ones)
582
- const selectedIds = editor.getSelectedShapeIds()
583
- expect(Array.from(selectedIds).sort()).toEqual(
584
- [
585
- selectAllIds.pageShape1,
586
- selectAllIds.pageShape2,
587
- selectAllIds.pageShape3,
588
- selectAllIds.container1,
589
- selectAllIds.container2,
590
- ].sort()
591
- )
592
-
593
- // Should NOT include locked shape or children/grandchildren
594
- expect(selectedIds).not.toContain(selectAllIds.lockedShape)
595
- expect(selectedIds).not.toContain(selectAllIds.containerChild1)
596
- expect(selectedIds).not.toContain(selectAllIds.containerChild2)
597
- expect(selectedIds).not.toContain(selectAllIds.containerChild3)
598
- expect(selectedIds).not.toContain(selectAllIds.containerGrandchild1)
599
- expect(selectedIds).not.toContain(selectAllIds.container2Child1)
600
- expect(selectedIds).not.toContain(selectAllIds.container2Child2)
601
- expect(selectedIds).not.toContain(selectAllIds.container2Grandchild1)
602
- })
603
-
604
- it('when shapes are selected only on the page, all children of the page should be selected (but not their descendants)', () => {
605
- // Select some page-level shapes
606
- editor.select(selectAllIds.pageShape1, selectAllIds.pageShape2)
607
-
608
- // Call selectAll
609
- editor.selectAll()
610
-
611
- // Should select all page-level shapes (excluding locked ones), but not descendants
612
- const selectedIds = editor.getSelectedShapeIds()
613
- expect(Array.from(selectedIds).sort()).toEqual(
614
- [
615
- selectAllIds.pageShape1,
616
- selectAllIds.pageShape2,
617
- selectAllIds.pageShape3,
618
- selectAllIds.container1,
619
- selectAllIds.container2,
620
- ].sort()
621
- )
622
-
623
- // Should NOT include children or grandchildren or locked shapes
624
- expect(selectedIds).not.toContain(selectAllIds.containerChild1)
625
- expect(selectedIds).not.toContain(selectAllIds.containerChild2)
626
- expect(selectedIds).not.toContain(selectAllIds.containerChild3)
627
- expect(selectedIds).not.toContain(selectAllIds.containerGrandchild1)
628
- expect(selectedIds).not.toContain(selectAllIds.container2Child1)
629
- expect(selectedIds).not.toContain(selectAllIds.container2Child2)
630
- expect(selectedIds).not.toContain(selectAllIds.container2Grandchild1)
631
- expect(selectedIds).not.toContain(selectAllIds.lockedShape)
632
- })
633
-
634
- it('when shapes are selected within a container, only children of the container should be selected (not their descendants)', () => {
635
- // Select some container children
636
- editor.select(selectAllIds.containerChild1, selectAllIds.containerChild2)
637
-
638
- // Call selectAll
639
- editor.selectAll()
640
-
641
- // Should select all container children (but not their descendants)
642
- const selectedIds = editor.getSelectedShapeIds()
643
- expect(Array.from(selectedIds).sort()).toEqual(
644
- [
645
- selectAllIds.containerChild1,
646
- selectAllIds.containerChild2,
647
- selectAllIds.containerChild3,
648
- ].sort()
649
- )
650
-
651
- // Should NOT include page-level shapes or grandchildren
652
- expect(selectedIds).not.toContain(selectAllIds.pageShape1)
653
- expect(selectedIds).not.toContain(selectAllIds.pageShape2)
654
- expect(selectedIds).not.toContain(selectAllIds.pageShape3)
655
- expect(selectedIds).not.toContain(selectAllIds.container1)
656
- expect(selectedIds).not.toContain(selectAllIds.container2)
657
- expect(selectedIds).not.toContain(selectAllIds.containerGrandchild1)
658
- expect(selectedIds).not.toContain(selectAllIds.container2Child1)
659
- expect(selectedIds).not.toContain(selectAllIds.container2Child2)
660
- expect(selectedIds).not.toContain(selectAllIds.container2Grandchild1)
661
- })
662
-
663
- it('when shapes are selected within a second container, only children of that container should be selected', () => {
664
- // Select some second container children
665
- editor.select(selectAllIds.container2Child1)
666
-
667
- // Call selectAll
668
- editor.selectAll()
669
-
670
- // Should select all second container children (but not their descendants)
671
- const selectedIds = editor.getSelectedShapeIds()
672
- expect(Array.from(selectedIds).sort()).toEqual(
673
- [selectAllIds.container2Child1, selectAllIds.container2Child2].sort()
674
- )
675
-
676
- // Should NOT include page-level shapes or other container's children or grandchildren
677
- expect(selectedIds).not.toContain(selectAllIds.pageShape1)
678
- expect(selectedIds).not.toContain(selectAllIds.pageShape2)
679
- expect(selectedIds).not.toContain(selectAllIds.pageShape3)
680
- expect(selectedIds).not.toContain(selectAllIds.container1)
681
- expect(selectedIds).not.toContain(selectAllIds.container2)
682
- expect(selectedIds).not.toContain(selectAllIds.containerChild1)
683
- expect(selectedIds).not.toContain(selectAllIds.containerChild2)
684
- expect(selectedIds).not.toContain(selectAllIds.containerChild3)
685
- expect(selectedIds).not.toContain(selectAllIds.containerGrandchild1)
686
- expect(selectedIds).not.toContain(selectAllIds.container2Grandchild1)
687
- })
688
-
689
- it('when shapes are selected that belong to different parents, no change/history entry should be made', () => {
690
- // Select shapes from different parents (page and container)
691
- editor.select(selectAllIds.pageShape1, selectAllIds.containerChild1)
692
-
693
- const initialSelectedIds = editor.getSelectedShapeIds()
694
-
695
- // Spy on setSelectedShapes to verify it's not called
696
- const setSelectedShapesSpy = vi.spyOn(editor, 'setSelectedShapes')
697
-
698
- // Call selectAll
699
- editor.selectAll()
700
-
701
- // Selection should remain unchanged
702
- expect(editor.getSelectedShapeIds()).toEqual(initialSelectedIds)
703
-
704
- // setSelectedShapes should not have been called (the method returns early)
705
- expect(setSelectedShapesSpy).not.toHaveBeenCalled()
706
-
707
- setSelectedShapesSpy.mockRestore()
708
- })
709
-
710
- it('when shapes are selected that belong to different containers, no change/history entry should be made', () => {
711
- // Select shapes from different containers
712
- editor.select(selectAllIds.containerChild1, selectAllIds.container2Child1)
713
-
714
- const initialSelectedIds = editor.getSelectedShapeIds()
715
-
716
- // Spy on setSelectedShapes to verify it's not called
717
- const setSelectedShapesSpy = vi.spyOn(editor, 'setSelectedShapes')
718
-
719
- // Call selectAll
720
- editor.selectAll()
721
-
722
- // Selection should remain unchanged
723
- expect(editor.getSelectedShapeIds()).toEqual(initialSelectedIds)
724
-
725
- // setSelectedShapes should not have been called
726
- expect(setSelectedShapesSpy).not.toHaveBeenCalled()
727
-
728
- setSelectedShapesSpy.mockRestore()
729
- })
730
-
731
- it('should not select locked shapes', () => {
732
- // Select a page-level shape
733
- editor.select(selectAllIds.pageShape1)
734
-
735
- // Call selectAll
736
- editor.selectAll()
737
-
738
- // Should select all page-level shapes except locked ones
739
- const selectedIds = editor.getSelectedShapeIds()
740
- expect(selectedIds).not.toContain(selectAllIds.lockedShape)
741
- expect(selectedIds).toContain(selectAllIds.pageShape1)
742
- expect(selectedIds).toContain(selectAllIds.pageShape2)
743
- expect(selectedIds).toContain(selectAllIds.pageShape3)
744
- expect(selectedIds).toContain(selectAllIds.container1)
745
- expect(selectedIds).toContain(selectAllIds.container2)
746
- })
747
-
748
- it('should handle empty container by selecting all siblings at the same level', () => {
749
- // Create an empty container
750
- const emptyContainerId = createShapeId('emptyContainer')
751
- editor.createShape({
752
- id: emptyContainerId,
753
- type: 'my-custom-shape',
754
- x: 800,
755
- y: 400,
756
- props: { w: 100, h: 100 },
757
- })
758
-
759
- // Clear selection first
760
- editor.selectNone()
761
-
762
- // Select the empty container
763
- editor.select(emptyContainerId)
764
-
765
- // Call selectAll - since the empty container has no children, it should select all siblings (page-level shapes)
766
- editor.selectAll()
767
-
768
- // Should select all page-level shapes (including the empty container itself)
769
- const selectedIds = editor.getSelectedShapeIds()
770
- expect(Array.from(selectedIds).sort()).toEqual(
771
- [
772
- selectAllIds.pageShape1,
773
- selectAllIds.pageShape2,
774
- selectAllIds.pageShape3,
775
- selectAllIds.container1,
776
- selectAllIds.container2,
777
- emptyContainerId,
778
- ].sort()
779
- )
780
-
781
- // Should NOT include locked shapes or children/grandchildren
782
- expect(selectedIds).not.toContain(selectAllIds.lockedShape)
783
- expect(selectedIds).not.toContain(selectAllIds.containerChild1)
784
- expect(selectedIds).not.toContain(selectAllIds.containerChild2)
785
- expect(selectedIds).not.toContain(selectAllIds.containerChild3)
786
- expect(selectedIds).not.toContain(selectAllIds.containerGrandchild1)
787
- expect(selectedIds).not.toContain(selectAllIds.container2Child1)
788
- expect(selectedIds).not.toContain(selectAllIds.container2Child2)
789
- expect(selectedIds).not.toContain(selectAllIds.container2Grandchild1)
790
- })
791
-
792
- it('should work correctly when selecting all shapes of same parent type', () => {
793
- // Select all container children
794
- editor.select(
795
- selectAllIds.containerChild1,
796
- selectAllIds.containerChild2,
797
- selectAllIds.containerChild3
798
- )
799
-
800
- // Call selectAll - should maintain the same selection since all children are already selected
801
- editor.selectAll()
802
-
803
- // Should still have all container children selected
804
- const selectedIds = editor.getSelectedShapeIds()
805
- expect(Array.from(selectedIds).sort()).toEqual(
806
- [
807
- selectAllIds.containerChild1,
808
- selectAllIds.containerChild2,
809
- selectAllIds.containerChild3,
810
- ].sort()
811
- )
812
- })
813
-
814
- it('should handle mixed selection levels gracefully by doing nothing', () => {
815
- // Select a mix: page shape (parent=page), container (parent=page), and container child (parent=container1)
816
- // These all have different parent IDs so selectAll should do nothing
817
- editor.select(selectAllIds.pageShape1, selectAllIds.containerChild1)
818
-
819
- const initialSelectedIds = Array.from(editor.getSelectedShapeIds())
820
-
821
- // Spy on setSelectedShapes to verify it's not called
822
- const setSelectedShapesSpy = vi.spyOn(editor, 'setSelectedShapes')
823
-
824
- // Call selectAll
825
- editor.selectAll()
826
-
827
- // Selection should remain unchanged since shapes have different parents
828
- expect(Array.from(editor.getSelectedShapeIds())).toEqual(initialSelectedIds)
829
-
830
- // setSelectedShapes should not have been called
831
- expect(setSelectedShapesSpy).not.toHaveBeenCalled()
832
-
833
- setSelectedShapesSpy.mockRestore()
834
- })
835
- })