@tldraw/editor 3.16.0-canary.5170ef6b6e20 → 3.16.0-canary.5462c7eac75a

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 (126) hide show
  1. package/dist-cjs/index.d.ts +62 -104
  2. package/dist-cjs/index.js +6 -6
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +2 -6
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +11 -1
  7. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  8. package/dist-cjs/lib/editor/Editor.js +12 -103
  9. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  10. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +4 -0
  11. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
  12. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +10 -0
  13. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  14. package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
  15. package/dist-cjs/lib/hooks/useCanvasEvents.js +15 -12
  16. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  17. package/dist-cjs/lib/hooks/useDocumentEvents.js +5 -5
  18. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  19. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -2
  20. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
  21. package/dist-cjs/lib/hooks/useGestureEvents.js +1 -1
  22. package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
  23. package/dist-cjs/lib/hooks/useHandleEvents.js +3 -3
  24. package/dist-cjs/lib/hooks/useHandleEvents.js.map +2 -2
  25. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +4 -1
  26. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
  27. package/dist-cjs/lib/hooks/useSelectionEvents.js +4 -4
  28. package/dist-cjs/lib/hooks/useSelectionEvents.js.map +2 -2
  29. package/dist-cjs/lib/license/LicenseManager.js +133 -38
  30. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  31. package/dist-cjs/lib/license/LicenseProvider.js +36 -3
  32. package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
  33. package/dist-cjs/lib/license/Watermark.js +69 -7
  34. package/dist-cjs/lib/license/Watermark.js.map +3 -3
  35. package/dist-cjs/lib/primitives/Vec.js +0 -4
  36. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  37. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +50 -20
  38. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  39. package/dist-cjs/lib/primitives/geometry/Group2d.js +8 -1
  40. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  41. package/dist-cjs/lib/utils/dom.js +12 -1
  42. package/dist-cjs/lib/utils/dom.js.map +2 -2
  43. package/dist-cjs/lib/utils/getPointerInfo.js +2 -2
  44. package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
  45. package/dist-cjs/lib/utils/reparenting.js +2 -35
  46. package/dist-cjs/lib/utils/reparenting.js.map +3 -3
  47. package/dist-cjs/version.js +3 -3
  48. package/dist-cjs/version.js.map +1 -1
  49. package/dist-esm/index.d.mts +62 -104
  50. package/dist-esm/index.mjs +9 -7
  51. package/dist-esm/index.mjs.map +2 -2
  52. package/dist-esm/lib/TldrawEditor.mjs +3 -7
  53. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  54. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +12 -2
  55. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  56. package/dist-esm/lib/editor/Editor.mjs +12 -103
  57. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  58. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +4 -0
  59. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
  60. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +10 -0
  61. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  62. package/dist-esm/lib/hooks/useCanvasEvents.mjs +17 -13
  63. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  64. package/dist-esm/lib/hooks/useDocumentEvents.mjs +11 -6
  65. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  66. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +2 -3
  67. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
  68. package/dist-esm/lib/hooks/useGestureEvents.mjs +2 -2
  69. package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
  70. package/dist-esm/lib/hooks/useHandleEvents.mjs +9 -4
  71. package/dist-esm/lib/hooks/useHandleEvents.mjs.map +2 -2
  72. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +4 -1
  73. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
  74. package/dist-esm/lib/hooks/useSelectionEvents.mjs +6 -5
  75. package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +2 -2
  76. package/dist-esm/lib/license/LicenseManager.mjs +134 -39
  77. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  78. package/dist-esm/lib/license/LicenseProvider.mjs +36 -4
  79. package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
  80. package/dist-esm/lib/license/Watermark.mjs +70 -8
  81. package/dist-esm/lib/license/Watermark.mjs.map +3 -3
  82. package/dist-esm/lib/primitives/Vec.mjs +0 -4
  83. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  84. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +53 -21
  85. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  86. package/dist-esm/lib/primitives/geometry/Group2d.mjs +8 -1
  87. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  88. package/dist-esm/lib/utils/dom.mjs +12 -1
  89. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  90. package/dist-esm/lib/utils/getPointerInfo.mjs +2 -2
  91. package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
  92. package/dist-esm/lib/utils/reparenting.mjs +3 -40
  93. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  94. package/dist-esm/version.mjs +3 -3
  95. package/dist-esm/version.mjs.map +1 -1
  96. package/editor.css +8 -3
  97. package/package.json +7 -7
  98. package/src/index.ts +3 -9
  99. package/src/lib/TldrawEditor.tsx +3 -15
  100. package/src/lib/components/default-components/DefaultCanvas.tsx +8 -2
  101. package/src/lib/editor/Editor.test.ts +90 -0
  102. package/src/lib/editor/Editor.ts +17 -129
  103. package/src/lib/editor/derivations/notVisibleShapes.ts +6 -0
  104. package/src/lib/editor/shapes/ShapeUtil.ts +11 -0
  105. package/src/lib/editor/types/misc-types.ts +0 -6
  106. package/src/lib/hooks/useCanvasEvents.ts +17 -11
  107. package/src/lib/hooks/useDocumentEvents.ts +11 -6
  108. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +2 -2
  109. package/src/lib/hooks/useGestureEvents.ts +2 -2
  110. package/src/lib/hooks/useHandleEvents.ts +9 -4
  111. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +4 -1
  112. package/src/lib/hooks/useSelectionEvents.ts +6 -5
  113. package/src/lib/license/LicenseManager.test.ts +719 -387
  114. package/src/lib/license/LicenseManager.ts +187 -49
  115. package/src/lib/license/LicenseProvider.tsx +69 -5
  116. package/src/lib/license/Watermark.tsx +75 -8
  117. package/src/lib/primitives/Vec.ts +0 -5
  118. package/src/lib/primitives/geometry/Geometry2d.test.ts +420 -0
  119. package/src/lib/primitives/geometry/Geometry2d.ts +78 -21
  120. package/src/lib/primitives/geometry/Group2d.ts +10 -1
  121. package/src/lib/test/InFrontOfTheCanvas.test.tsx +187 -0
  122. package/src/lib/utils/dom.test.ts +94 -0
  123. package/src/lib/utils/dom.ts +38 -1
  124. package/src/lib/utils/getPointerInfo.ts +2 -1
  125. package/src/lib/utils/reparenting.ts +3 -69
  126. package/src/version.ts +3 -3
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.16.0-canary.5170ef6b6e20'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-08-29T13:37:30.941Z',\n\tpatch: '2025-08-29T13:37:30.941Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.16.0-canary.5462c7eac75a'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-09-16T21:35:37.564Z',\n\tpatch: '2025-09-16T21:35:37.564Z',\n}\n"],
5
5
  "mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
package/editor.css CHANGED
@@ -689,11 +689,17 @@ input,
689
689
  }
690
690
 
691
691
  .tl-text-measure {
692
- position: absolute;
693
692
  z-index: var(--tl-layer-canvas-hidden);
693
+ opacity: 0;
694
+ visibility: hidden;
695
+
696
+ /* pointer-events: all; */
697
+ /* opacity: 1; */
698
+ /* z-index: 99999; */
699
+
700
+ position: absolute;
694
701
  top: 0px;
695
702
  left: 0px;
696
- opacity: 0;
697
703
  width: max-content;
698
704
  box-sizing: border-box;
699
705
  pointer-events: none;
@@ -704,7 +710,6 @@ input,
704
710
  border: none;
705
711
  user-select: none;
706
712
  contain: style paint;
707
- visibility: hidden;
708
713
  /* N.B. This property, while discouraged ("intended for Document Type Definition (DTD) designers") is necessary for ensuring correct mixed RTL/LTR behavior when exporting SVGs. */
709
714
  unicode-bidi: plaintext;
710
715
  -webkit-user-select: none;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tldraw/editor",
3
3
  "description": "tldraw infinite canvas SDK (editor).",
4
- "version": "3.16.0-canary.5170ef6b6e20",
4
+ "version": "3.16.0-canary.5462c7eac75a",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -50,12 +50,12 @@
50
50
  "@tiptap/core": "^2.9.1",
51
51
  "@tiptap/pm": "^2.9.1",
52
52
  "@tiptap/react": "^2.9.1",
53
- "@tldraw/state": "3.16.0-canary.5170ef6b6e20",
54
- "@tldraw/state-react": "3.16.0-canary.5170ef6b6e20",
55
- "@tldraw/store": "3.16.0-canary.5170ef6b6e20",
56
- "@tldraw/tlschema": "3.16.0-canary.5170ef6b6e20",
57
- "@tldraw/utils": "3.16.0-canary.5170ef6b6e20",
58
- "@tldraw/validate": "3.16.0-canary.5170ef6b6e20",
53
+ "@tldraw/state": "3.16.0-canary.5462c7eac75a",
54
+ "@tldraw/state-react": "3.16.0-canary.5462c7eac75a",
55
+ "@tldraw/store": "3.16.0-canary.5462c7eac75a",
56
+ "@tldraw/tlschema": "3.16.0-canary.5462c7eac75a",
57
+ "@tldraw/utils": "3.16.0-canary.5462c7eac75a",
58
+ "@tldraw/validate": "3.16.0-canary.5462c7eac75a",
59
59
  "@types/core-js": "^2.5.8",
60
60
  "@use-gesture/react": "^10.3.1",
61
61
  "classnames": "^2.5.1",
package/src/index.ts CHANGED
@@ -268,7 +268,6 @@ export {
268
268
  type TLGetShapeAtPointOptions,
269
269
  type TLImageExportOptions,
270
270
  type TLSvgExportOptions,
271
- type TLSvgOptions,
272
271
  type TLUpdatePointerOptions,
273
272
  } from './lib/editor/types/misc-types'
274
273
  export {
@@ -335,6 +334,7 @@ export {
335
334
  type TestEnvironment,
336
335
  type ValidLicenseKeyResult,
337
336
  } from './lib/license/LicenseManager'
337
+ export { LICENSE_TIMEOUT } from './lib/license/LicenseProvider'
338
338
  export { defaultTldrawOptions, type TldrawOptions } from './lib/options'
339
339
  export {
340
340
  Box,
@@ -447,10 +447,12 @@ export {
447
447
  export {
448
448
  activeElementShouldCaptureKeys,
449
449
  loopToHtmlElement,
450
+ markEventAsHandled,
450
451
  preventDefault,
451
452
  releasePointerCapture,
452
453
  setPointerCapture,
453
454
  stopEventPropagation,
455
+ wasEventAlreadyHandled,
454
456
  } from './lib/utils/dom'
455
457
  export { EditorAtom } from './lib/utils/EditorAtom'
456
458
  export { getIncrementedName } from './lib/utils/getIncrementedName'
@@ -486,14 +488,6 @@ export { type TLStoreWithStatus } from './lib/utils/sync/StoreWithStatus'
486
488
  export { uniq } from './lib/utils/uniq'
487
489
  export { openWindow } from './lib/utils/window-open'
488
490
 
489
- /**
490
- * @deprecated Licensing is now enabled in the tldraw SDK.
491
- * @public */
492
- export function debugEnableLicensing() {
493
- // noop
494
- return
495
- }
496
-
497
491
  registerTldrawLibraryVersion(
498
492
  (globalThis as any).TLDRAW_LIBRARY_NAME,
499
493
  (globalThis as any).TLDRAW_LIBRARY_VERSION,
@@ -1,6 +1,7 @@
1
1
  import { MigrationSequence, Store } from '@tldraw/store'
2
2
  import { TLShape, TLStore, TLStoreSnapshot } from '@tldraw/tlschema'
3
3
  import { annotateError, Required } from '@tldraw/utils'
4
+ import classNames from 'classnames'
4
5
  import React, {
5
6
  memo,
6
7
  ReactNode,
@@ -12,8 +13,6 @@ import React, {
12
13
  useState,
13
14
  useSyncExternalStore,
14
15
  } from 'react'
15
-
16
- import classNames from 'classnames'
17
16
  import { version } from '../version'
18
17
  import { DefaultErrorFallback } from './components/default-components/DefaultErrorFallback'
19
18
  import { OptionalErrorBoundary } from './components/ErrorBoundary'
@@ -45,7 +44,7 @@ import { LicenseProvider } from './license/LicenseProvider'
45
44
  import { Watermark } from './license/Watermark'
46
45
  import { TldrawOptions } from './options'
47
46
  import { TLDeepLinkOptions } from './utils/deepLinks'
48
- import { stopEventPropagation } from './utils/dom'
47
+ import { markEventAsHandled } from './utils/dom'
49
48
  import { TLTextOptions } from './utils/richText'
50
49
  import { TLStoreWithStatus } from './utils/sync/StoreWithStatus'
51
50
 
@@ -189,13 +188,6 @@ export interface TldrawEditorBaseProps {
189
188
  */
190
189
  deepLinks?: true | TLDeepLinkOptions
191
190
 
192
- /**
193
- * Predicate for whether or not a shape should be hidden.
194
- *
195
- * @deprecated Use {@link TldrawEditorBaseProps#getShapeVisibility} instead.
196
- */
197
- isShapeHidden?(shape: TLShape, editor: Editor): boolean
198
-
199
191
  /**
200
192
  * Provides a way to hide shapes.
201
193
  *
@@ -283,7 +275,7 @@ export const TldrawEditor = memo(function TldrawEditor({
283
275
  data-tldraw={version}
284
276
  draggable={false}
285
277
  className={classNames(`${TL_CONTAINER_CLASS} tl-theme__light`, className)}
286
- onPointerDown={stopEventPropagation}
278
+ onPointerDown={markEventAsHandled}
287
279
  tabIndex={-1}
288
280
  role="application"
289
281
  aria-label={_options?.branding ?? 'tldraw'}
@@ -412,8 +404,6 @@ function TldrawEditorWithReadyStore({
412
404
  options,
413
405
  licenseKey,
414
406
  deepLinks: _deepLinks,
415
- // eslint-disable-next-line @typescript-eslint/no-deprecated
416
- isShapeHidden,
417
407
  getShapeVisibility,
418
408
  assetUrls,
419
409
  }: Required<
@@ -473,7 +463,6 @@ function TldrawEditorWithReadyStore({
473
463
  textOptions,
474
464
  options,
475
465
  licenseKey,
476
- isShapeHidden,
477
466
  getShapeVisibility,
478
467
  fontAssetUrls: assetUrls?.fonts,
479
468
  })
@@ -509,7 +498,6 @@ function TldrawEditorWithReadyStore({
509
498
  user,
510
499
  setEditor,
511
500
  licenseKey,
512
- isShapeHidden,
513
501
  getShapeVisibility,
514
502
  textOptions,
515
503
  assetUrls,
@@ -21,7 +21,7 @@ import { Mat } from '../../primitives/Mat'
21
21
  import { Vec } from '../../primitives/Vec'
22
22
  import { toDomPrecision } from '../../primitives/utils'
23
23
  import { debugFlags } from '../../utils/debug-flags'
24
- import { setStyleProperty } from '../../utils/dom'
24
+ import { markEventAsHandled, setStyleProperty } from '../../utils/dom'
25
25
  import { GeometryDebuggingView } from '../GeometryDebuggingView'
26
26
  import { LiveCollaborators } from '../LiveCollaborators'
27
27
  import { MenuClickCapture } from '../MenuClickCapture'
@@ -172,7 +172,13 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
172
172
  <LiveCollaborators />
173
173
  </div>
174
174
  </div>
175
- <div className="tl-canvas__in-front">
175
+ <div
176
+ className="tl-canvas__in-front"
177
+ onPointerDown={markEventAsHandled}
178
+ onPointerUp={markEventAsHandled}
179
+ onTouchStart={markEventAsHandled}
180
+ onTouchEnd={markEventAsHandled}
181
+ >
176
182
  <InFrontOfTheCanvasWrapper />
177
183
  </div>
178
184
  <MovingCameraHitTestBlocker />
@@ -833,3 +833,93 @@ describe('selectAll', () => {
833
833
  setSelectedShapesSpy.mockRestore()
834
834
  })
835
835
  })
836
+
837
+ describe('putExternalContent', () => {
838
+ let mockHandler: any
839
+
840
+ beforeEach(() => {
841
+ mockHandler = vi.fn()
842
+ editor.registerExternalContentHandler('text', mockHandler)
843
+ })
844
+
845
+ it('calls external content handler when not readonly', async () => {
846
+ vi.spyOn(editor, 'getIsReadonly').mockReturnValue(false)
847
+
848
+ const info = { type: 'text' as const, text: 'test-data' }
849
+ await editor.putExternalContent(info)
850
+
851
+ expect(mockHandler).toHaveBeenCalledWith(info)
852
+ })
853
+
854
+ it('does not call external content handler when readonly', async () => {
855
+ vi.spyOn(editor, 'getIsReadonly').mockReturnValue(true)
856
+
857
+ const info = { type: 'text' as const, text: 'test-data' }
858
+ await editor.putExternalContent(info)
859
+
860
+ expect(mockHandler).not.toHaveBeenCalled()
861
+ })
862
+
863
+ it('calls external content handler when readonly but force is true', async () => {
864
+ vi.spyOn(editor, 'getIsReadonly').mockReturnValue(true)
865
+
866
+ const info = { type: 'text' as const, text: 'test-data' }
867
+ await editor.putExternalContent(info, { force: true })
868
+
869
+ expect(mockHandler).toHaveBeenCalledWith(info)
870
+ })
871
+
872
+ it('calls external content handler when force is false and not readonly', async () => {
873
+ vi.spyOn(editor, 'getIsReadonly').mockReturnValue(false)
874
+
875
+ const info = { type: 'text' as const, text: 'test-data' }
876
+ await editor.putExternalContent(info, { force: false })
877
+
878
+ expect(mockHandler).toHaveBeenCalledWith(info)
879
+ })
880
+ })
881
+
882
+ describe('replaceExternalContent', () => {
883
+ let mockHandler: any
884
+
885
+ beforeEach(() => {
886
+ mockHandler = vi.fn()
887
+ editor.registerExternalContentHandler('text', mockHandler)
888
+ })
889
+
890
+ it('calls external content handler when not readonly', async () => {
891
+ vi.spyOn(editor, 'getIsReadonly').mockReturnValue(false)
892
+
893
+ const info = { type: 'text' as const, text: 'test-data' }
894
+ await editor.replaceExternalContent(info)
895
+
896
+ expect(mockHandler).toHaveBeenCalledWith(info)
897
+ })
898
+
899
+ it('does not call external content handler when readonly', async () => {
900
+ vi.spyOn(editor, 'getIsReadonly').mockReturnValue(true)
901
+
902
+ const info = { type: 'text' as const, text: 'test-data' }
903
+ await editor.replaceExternalContent(info)
904
+
905
+ expect(mockHandler).not.toHaveBeenCalled()
906
+ })
907
+
908
+ it('calls external content handler when readonly but force is true', async () => {
909
+ vi.spyOn(editor, 'getIsReadonly').mockReturnValue(true)
910
+
911
+ const info = { type: 'text' as const, text: 'test-data' }
912
+ await editor.replaceExternalContent(info, { force: true })
913
+
914
+ expect(mockHandler).toHaveBeenCalledWith(info)
915
+ })
916
+
917
+ it('calls external content handler when force is false and not readonly', async () => {
918
+ vi.spyOn(editor, 'getIsReadonly').mockReturnValue(false)
919
+
920
+ const info = { type: 'text' as const, text: 'test-data' }
921
+ await editor.replaceExternalContent(info, { force: false })
922
+
923
+ expect(mockHandler).toHaveBeenCalledWith(info)
924
+ })
925
+ })
@@ -116,7 +116,6 @@ import {
116
116
  } from '../constants'
117
117
  import { exportToSvg } from '../exports/exportToSvg'
118
118
  import { getSvgAsImage } from '../exports/getSvgAsImage'
119
- import { tlenv } from '../globals/environment'
120
119
  import { tlmenus } from '../globals/menus'
121
120
  import { tltime } from '../globals/time'
122
121
  import { TldrawOptions, defaultTldrawOptions } from '../options'
@@ -244,16 +243,6 @@ export interface TLEditorOptions {
244
243
  options?: Partial<TldrawOptions>
245
244
  licenseKey?: string
246
245
  fontAssetUrls?: { [key: string]: string | undefined }
247
- /**
248
- * A predicate that should return true if the given shape should be hidden.
249
- *
250
- * @deprecated Use {@link Editor#getShapeVisibility} instead.
251
- *
252
- * @param shape - The shape to check.
253
- * @param editor - The editor instance.
254
- */
255
- isShapeHidden?(shape: TLShape, editor: Editor): boolean
256
-
257
246
  /**
258
247
  * Provides a way to hide shapes.
259
248
  *
@@ -309,21 +298,12 @@ export class Editor extends EventEmitter<TLEventMap> {
309
298
  autoFocus,
310
299
  inferDarkMode,
311
300
  options,
312
- // eslint-disable-next-line @typescript-eslint/no-deprecated
313
- isShapeHidden,
314
301
  getShapeVisibility,
315
302
  fontAssetUrls,
316
303
  }: TLEditorOptions) {
317
304
  super()
318
- assert(
319
- !(isShapeHidden && getShapeVisibility),
320
- 'Cannot use both isShapeHidden and getShapeVisibility'
321
- )
322
305
 
323
- this._getShapeVisibility = isShapeHidden
324
- ? // eslint-disable-next-line @typescript-eslint/no-deprecated
325
- (shape: TLShape, editor: Editor) => (isShapeHidden(shape, editor) ? 'hidden' : 'inherit')
326
- : getShapeVisibility
306
+ this._getShapeVisibility = getShapeVisibility
327
307
 
328
308
  this.options = { ...defaultTldrawOptions, ...options }
329
309
 
@@ -907,14 +887,6 @@ export class Editor extends EventEmitter<TLEventMap> {
907
887
  */
908
888
  readonly fonts: FontManager
909
889
 
910
- /**
911
- * A manager for the editor's environment.
912
- *
913
- * @deprecated This is deprecated and will be removed in a future version. Use the `tlenv` global export instead.
914
- * @public
915
- */
916
- readonly environment = tlenv
917
-
918
890
  /**
919
891
  * A manager for the editor's scribbles.
920
892
  *
@@ -1119,35 +1091,6 @@ export class Editor extends EventEmitter<TLEventMap> {
1119
1091
  return this.history.getNumRedos() > 0
1120
1092
  }
1121
1093
 
1122
- /**
1123
- * Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
1124
- * any redos.
1125
- *
1126
- * @example
1127
- * ```ts
1128
- * editor.mark()
1129
- * editor.mark('flip shapes')
1130
- * ```
1131
- *
1132
- * @param markId - The mark's id, usually the reason for adding the mark.
1133
- *
1134
- * @public
1135
- * @deprecated use {@link Editor.markHistoryStoppingPoint} instead
1136
- */
1137
- mark(markId?: string): this {
1138
- if (typeof markId === 'string') {
1139
- console.warn(
1140
- `[tldraw] \`editor.history.mark("${markId}")\` is deprecated. Please use \`const myMarkId = editor.markHistoryStoppingPoint()\` instead.`
1141
- )
1142
- } else {
1143
- console.warn(
1144
- '[tldraw] `editor.mark()` is deprecated. Use `editor.markHistoryStoppingPoint()` instead.'
1145
- )
1146
- }
1147
- this.history._mark(markId ?? uniqueId())
1148
- return this
1149
- }
1150
-
1151
1094
  /**
1152
1095
  * Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
1153
1096
  * any redos. You typically want to do this just before a user interaction begins or is handled.
@@ -1272,13 +1215,6 @@ export class Editor extends EventEmitter<TLEventMap> {
1272
1215
  return this
1273
1216
  }
1274
1217
 
1275
- /**
1276
- * @deprecated Use `Editor.run` instead.
1277
- */
1278
- batch(fn: () => void, opts?: TLEditorRunOptions): this {
1279
- return this.run(fn, opts)
1280
- }
1281
-
1282
1218
  /* --------------------- Errors --------------------- */
1283
1219
 
1284
1220
  /** @internal */
@@ -1580,54 +1516,6 @@ export class Editor extends EventEmitter<TLEventMap> {
1580
1516
 
1581
1517
  menus = tlmenus.forContext(this.contextId)
1582
1518
 
1583
- /**
1584
- * @deprecated Use `editor.menus.getOpenMenus` instead.
1585
- *
1586
- * @public
1587
- */
1588
- @computed getOpenMenus(): string[] {
1589
- return this.menus.getOpenMenus()
1590
- }
1591
-
1592
- /**
1593
- * @deprecated Use `editor.menus.addOpenMenu` instead.
1594
- *
1595
- * @public
1596
- */
1597
- addOpenMenu(id: string): this {
1598
- this.menus.addOpenMenu(id)
1599
- return this
1600
- }
1601
-
1602
- /**
1603
- * @deprecated Use `editor.menus.deleteOpenMenu` instead.
1604
- *
1605
- * @public
1606
- */
1607
- deleteOpenMenu(id: string): this {
1608
- this.menus.deleteOpenMenu(id)
1609
- return this
1610
- }
1611
-
1612
- /**
1613
- * @deprecated Use `editor.menus.clearOpenMenus` instead.
1614
- *
1615
- * @public
1616
- */
1617
- clearOpenMenus(): this {
1618
- this.menus.clearOpenMenus()
1619
- return this
1620
- }
1621
-
1622
- /**
1623
- * @deprecated Use `editor.menus.hasAnyOpenMenus` instead.
1624
- *
1625
- * @public
1626
- */
1627
- @computed getIsMenuOpen(): boolean {
1628
- return this.menus.hasAnyOpenMenus()
1629
- }
1630
-
1631
1519
  /* --------------------- Cursor --------------------- */
1632
1520
 
1633
1521
  /**
@@ -4792,8 +4680,10 @@ export class Editor extends EventEmitter<TLEventMap> {
4792
4680
  return this.store.createComputedCache<Box, TLShape>('pageBoundsCache', (shape) => {
4793
4681
  const pageTransform = this.getShapePageTransform(shape)
4794
4682
  if (!pageTransform) return undefined
4795
- const geometry = this.getShapeGeometry(shape)
4796
- return Box.FromPoints(pageTransform.applyToPoints(geometry.vertices))
4683
+
4684
+ return Box.FromPoints(
4685
+ pageTransform.applyToPoints(this.getShapeGeometry(shape).boundsVertices)
4686
+ )
4797
4687
  })
4798
4688
  }
4799
4689
 
@@ -5839,11 +5729,6 @@ export class Editor extends EventEmitter<TLEventMap> {
5839
5729
  return shapeIds
5840
5730
  }
5841
5731
 
5842
- /** @deprecated Use {@link Editor.getDraggingOverShape} instead */
5843
- getDroppingOverShape(point: Vec, droppingShapes: TLShape[]): TLShape | undefined {
5844
- return this.getDraggingOverShape(point, droppingShapes)
5845
- }
5846
-
5847
5732
  /**
5848
5733
  * Get the shape that some shapes should be dropped on at a given point.
5849
5734
  *
@@ -8948,8 +8833,13 @@ export class Editor extends EventEmitter<TLEventMap> {
8948
8833
  * Handle external content, such as files, urls, embeds, or plain text which has been put into the app, for example by pasting external text or dropping external images onto canvas.
8949
8834
  *
8950
8835
  * @param info - Info about the external content.
8836
+ * @param opts - Options for handling external content, including force flag to bypass readonly checks.
8951
8837
  */
8952
- async putExternalContent<E>(info: TLExternalContent<E>): Promise<void> {
8838
+ async putExternalContent<E>(
8839
+ info: TLExternalContent<E>,
8840
+ opts = {} as { force?: boolean }
8841
+ ): Promise<void> {
8842
+ if (!opts.force && this.getIsReadonly()) return
8953
8843
  return this.externalContentHandlers[info.type]?.(info as any)
8954
8844
  }
8955
8845
 
@@ -8957,8 +8847,13 @@ export class Editor extends EventEmitter<TLEventMap> {
8957
8847
  * Handle replacing external content.
8958
8848
  *
8959
8849
  * @param info - Info about the external content.
8850
+ * @param opts - Options for handling external content, including force flag to bypass readonly checks.
8960
8851
  */
8961
- async replaceExternalContent<E>(info: TLExternalContent<E>): Promise<void> {
8852
+ async replaceExternalContent<E>(
8853
+ info: TLExternalContent<E>,
8854
+ opts = {} as { force?: boolean }
8855
+ ): Promise<void> {
8856
+ if (!opts.force && this.getIsReadonly()) return
8962
8857
  return this.externalContentHandlers[info.type]?.(info as any)
8963
8858
  }
8964
8859
 
@@ -9459,13 +9354,6 @@ export class Editor extends EventEmitter<TLEventMap> {
9459
9354
  }
9460
9355
  }
9461
9356
 
9462
- /** @deprecated Use {@link Editor.getSvgString} or {@link Editor.getSvgElement} instead. */
9463
- async getSvg(shapes: TLShapeId[] | TLShape[], opts: TLSvgExportOptions = {}) {
9464
- const result = await this.getSvgElement(shapes, opts)
9465
- if (!result) return undefined
9466
- return result.svg
9467
- }
9468
-
9469
9357
  /**
9470
9358
  * Get an exported image of the given shapes.
9471
9359
  *
@@ -7,6 +7,12 @@ function fromScratch(editor: Editor): Set<TLShapeId> {
7
7
  const viewportPageBounds = editor.getViewportPageBounds()
8
8
  const notVisibleShapes = new Set<TLShapeId>()
9
9
  shapesIds.forEach((id) => {
10
+ const shape = editor.getShape(id)
11
+ if (!shape) return
12
+
13
+ const canCull = editor.getShapeUtil(shape.type).canCull(shape)
14
+ if (!canCull) return
15
+
10
16
  // If the shape is fully outside of the viewport page bounds, add it to the set.
11
17
  // We'll ignore masks here, since they're more expensive to compute and the overhead is not worth it.
12
18
  const pageBounds = editor.getShapePageBounds(id)
@@ -283,6 +283,17 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
283
283
  return true
284
284
  }
285
285
 
286
+ /**
287
+ * Whether this shape can be culled. By default, shapes are culled for
288
+ * performance reasons when they are outside of the viewport. Culled shapes are still rendered
289
+ * to the DOM, but have their `display` property set to `none`.
290
+ *
291
+ * @param shape - The shape.
292
+ */
293
+ canCull(_shape: Shape): boolean {
294
+ return true
295
+ }
296
+
286
297
  /**
287
298
  * Does this shape provide a background for its children? If this is true,
288
299
  * then any children with a `renderBackground` method will have their
@@ -72,12 +72,6 @@ export interface TLImageExportOptions extends TLSvgExportOptions {
72
72
  format?: TLExportType
73
73
  }
74
74
 
75
- /**
76
- * @public
77
- * @deprecated use {@link TLImageExportOptions} instead
78
- */
79
- export type TLSvgOptions = TLImageExportOptions
80
-
81
75
  /** @public */
82
76
  export interface TLCameraMoveOptions {
83
77
  /** Whether to move the camera immediately, rather than on the next tick. */
@@ -2,10 +2,11 @@ import { useValue } from '@tldraw/state-react'
2
2
  import React, { useEffect, useMemo } from 'react'
3
3
  import { RIGHT_MOUSE_BUTTON } from '../constants'
4
4
  import {
5
+ markEventAsHandled,
5
6
  preventDefault,
6
7
  releasePointerCapture,
7
8
  setPointerCapture,
8
- stopEventPropagation,
9
+ wasEventAlreadyHandled,
9
10
  } from '../utils/dom'
10
11
  import { getPointerInfo } from '../utils/getPointerInfo'
11
12
  import { useEditor } from './useEditor'
@@ -17,7 +18,7 @@ export function useCanvasEvents() {
17
18
  const events = useMemo(
18
19
  function canvasEvents() {
19
20
  function onPointerDown(e: React.PointerEvent) {
20
- if ((e as any).isKilled) return
21
+ if (wasEventAlreadyHandled(e)) return
21
22
 
22
23
  if (e.button === RIGHT_MOUSE_BUTTON) {
23
24
  editor.dispatch({
@@ -42,7 +43,7 @@ export function useCanvasEvents() {
42
43
  }
43
44
 
44
45
  function onPointerUp(e: React.PointerEvent) {
45
- if ((e as any).isKilled) return
46
+ if (wasEventAlreadyHandled(e)) return
46
47
  if (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return
47
48
 
48
49
  releasePointerCapture(e.currentTarget, e)
@@ -56,26 +57,28 @@ export function useCanvasEvents() {
56
57
  }
57
58
 
58
59
  function onPointerEnter(e: React.PointerEvent) {
59
- if ((e as any).isKilled) return
60
+ if (wasEventAlreadyHandled(e)) return
60
61
  if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
61
62
  const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
62
63
  editor.updateInstanceState({ isHoveringCanvas: canHover ? true : null })
63
64
  }
64
65
 
65
66
  function onPointerLeave(e: React.PointerEvent) {
66
- if ((e as any).isKilled) return
67
+ if (wasEventAlreadyHandled(e)) return
67
68
  if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
68
69
  const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
69
70
  editor.updateInstanceState({ isHoveringCanvas: canHover ? false : null })
70
71
  }
71
72
 
72
73
  function onTouchStart(e: React.TouchEvent) {
73
- ;(e as any).isKilled = true
74
+ if (wasEventAlreadyHandled(e)) return
75
+ markEventAsHandled(e)
74
76
  preventDefault(e)
75
77
  }
76
78
 
77
79
  function onTouchEnd(e: React.TouchEvent) {
78
- ;(e as any).isKilled = true
80
+ if (wasEventAlreadyHandled(e)) return
81
+ markEventAsHandled(e)
79
82
  // check that e.target is an HTMLElement
80
83
  if (!(e.target instanceof HTMLElement)) return
81
84
 
@@ -94,12 +97,14 @@ export function useCanvasEvents() {
94
97
  }
95
98
 
96
99
  function onDragOver(e: React.DragEvent<Element>) {
100
+ if (wasEventAlreadyHandled(e)) return
97
101
  preventDefault(e)
98
102
  }
99
103
 
100
104
  async function onDrop(e: React.DragEvent<Element>) {
105
+ if (wasEventAlreadyHandled(e)) return
101
106
  preventDefault(e)
102
- stopEventPropagation(e)
107
+ e.stopPropagation()
103
108
 
104
109
  if (e.dataTransfer?.files?.length) {
105
110
  const files = Array.from(e.dataTransfer.files)
@@ -124,7 +129,8 @@ export function useCanvasEvents() {
124
129
  }
125
130
 
126
131
  function onClick(e: React.MouseEvent) {
127
- stopEventPropagation(e)
132
+ if (wasEventAlreadyHandled(e)) return
133
+ e.stopPropagation()
128
134
  }
129
135
 
130
136
  return {
@@ -151,8 +157,8 @@ export function useCanvasEvents() {
151
157
  let lastX: number, lastY: number
152
158
 
153
159
  function onPointerMove(e: PointerEvent) {
154
- if ((e as any).isKilled) return
155
- ;(e as any).isKilled = true
160
+ if (wasEventAlreadyHandled(e)) return
161
+ markEventAsHandled(e)
156
162
 
157
163
  if (e.clientX === lastX && e.clientY === lastY) return
158
164
  lastX = e.clientX