@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.
- package/dist-cjs/index.d.ts +62 -104
- package/dist-cjs/index.js +6 -6
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +2 -6
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +11 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +12 -103
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +4 -0
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +10 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
- package/dist-cjs/lib/hooks/useCanvasEvents.js +15 -12
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +5 -5
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useGestureEvents.js +1 -1
- package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useHandleEvents.js +3 -3
- package/dist-cjs/lib/hooks/useHandleEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js +4 -1
- package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useSelectionEvents.js +4 -4
- package/dist-cjs/lib/hooks/useSelectionEvents.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +133 -38
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +36 -3
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/license/Watermark.js +69 -7
- package/dist-cjs/lib/license/Watermark.js.map +3 -3
- package/dist-cjs/lib/primitives/Vec.js +0 -4
- package/dist-cjs/lib/primitives/Vec.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js +50 -20
- package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
- package/dist-cjs/lib/primitives/geometry/Group2d.js +8 -1
- package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +12 -1
- package/dist-cjs/lib/utils/dom.js.map +2 -2
- package/dist-cjs/lib/utils/getPointerInfo.js +2 -2
- package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
- package/dist-cjs/lib/utils/reparenting.js +2 -35
- package/dist-cjs/lib/utils/reparenting.js.map +3 -3
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +62 -104
- package/dist-esm/index.mjs +9 -7
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +3 -7
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +12 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +12 -103
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +4 -0
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +10 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +17 -13
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +11 -6
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +2 -3
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs +2 -2
- package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useHandleEvents.mjs +9 -4
- package/dist-esm/lib/hooks/useHandleEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs +4 -1
- package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useSelectionEvents.mjs +6 -5
- package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +134 -39
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +36 -4
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/license/Watermark.mjs +70 -8
- package/dist-esm/lib/license/Watermark.mjs.map +3 -3
- package/dist-esm/lib/primitives/Vec.mjs +0 -4
- package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +53 -21
- package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
- package/dist-esm/lib/primitives/geometry/Group2d.mjs +8 -1
- package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +12 -1
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/lib/utils/getPointerInfo.mjs +2 -2
- package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
- package/dist-esm/lib/utils/reparenting.mjs +3 -40
- package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +8 -3
- package/package.json +7 -7
- package/src/index.ts +3 -9
- package/src/lib/TldrawEditor.tsx +3 -15
- package/src/lib/components/default-components/DefaultCanvas.tsx +8 -2
- package/src/lib/editor/Editor.test.ts +90 -0
- package/src/lib/editor/Editor.ts +17 -129
- package/src/lib/editor/derivations/notVisibleShapes.ts +6 -0
- package/src/lib/editor/shapes/ShapeUtil.ts +11 -0
- package/src/lib/editor/types/misc-types.ts +0 -6
- package/src/lib/hooks/useCanvasEvents.ts +17 -11
- package/src/lib/hooks/useDocumentEvents.ts +11 -6
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +2 -2
- package/src/lib/hooks/useGestureEvents.ts +2 -2
- package/src/lib/hooks/useHandleEvents.ts +9 -4
- package/src/lib/hooks/usePassThroughMouseOverEvents.ts +4 -1
- package/src/lib/hooks/useSelectionEvents.ts +6 -5
- package/src/lib/license/LicenseManager.test.ts +719 -387
- package/src/lib/license/LicenseManager.ts +187 -49
- package/src/lib/license/LicenseProvider.tsx +69 -5
- package/src/lib/license/Watermark.tsx +75 -8
- package/src/lib/primitives/Vec.ts +0 -5
- package/src/lib/primitives/geometry/Geometry2d.test.ts +420 -0
- package/src/lib/primitives/geometry/Geometry2d.ts +78 -21
- package/src/lib/primitives/geometry/Group2d.ts +10 -1
- package/src/lib/test/InFrontOfTheCanvas.test.tsx +187 -0
- package/src/lib/utils/dom.test.ts +94 -0
- package/src/lib/utils/dom.ts +38 -1
- package/src/lib/utils/getPointerInfo.ts +2 -1
- package/src/lib/utils/reparenting.ts +3 -69
- package/src/version.ts +3 -3
package/dist-esm/version.mjs.map
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
54
|
-
"@tldraw/state-react": "3.16.0-canary.
|
|
55
|
-
"@tldraw/store": "3.16.0-canary.
|
|
56
|
-
"@tldraw/tlschema": "3.16.0-canary.
|
|
57
|
-
"@tldraw/utils": "3.16.0-canary.
|
|
58
|
-
"@tldraw/validate": "3.16.0-canary.
|
|
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,
|
package/src/lib/TldrawEditor.tsx
CHANGED
|
@@ -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 {
|
|
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={
|
|
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
|
|
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
|
+
})
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -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 =
|
|
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
|
-
|
|
4796
|
-
return Box.FromPoints(
|
|
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>(
|
|
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>(
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
74
|
+
if (wasEventAlreadyHandled(e)) return
|
|
75
|
+
markEventAsHandled(e)
|
|
74
76
|
preventDefault(e)
|
|
75
77
|
}
|
|
76
78
|
|
|
77
79
|
function onTouchEnd(e: React.TouchEvent) {
|
|
78
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
155
|
-
|
|
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
|