@tldraw/editor 3.16.0-canary.f56a36d13420 → 3.16.0-canary.f5bf2b535ea7
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 +64 -105
- package/dist-cjs/index.js +3 -5
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +1 -7
- 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 +41 -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/managers/FocusManager/FocusManager.js +4 -2
- package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.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 +19 -16
- 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 +6 -6
- 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 +8 -8
- package/dist-cjs/lib/hooks/useSelectionEvents.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +143 -53
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/LicenseProvider.js +39 -1
- package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
- package/dist-cjs/lib/license/Watermark.js +144 -75
- package/dist-cjs/lib/license/Watermark.js.map +3 -3
- package/dist-cjs/lib/license/useLicenseManagerState.js.map +2 -2
- 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.map +2 -2
- package/dist-cjs/lib/utils/getPointerInfo.js +2 -3
- package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
- package/dist-cjs/lib/utils/reparenting.js +7 -36
- 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 +64 -105
- package/dist-esm/index.mjs +3 -5
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +1 -7
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +11 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +41 -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/managers/FocusManager/FocusManager.mjs +4 -2
- package/dist-esm/lib/editor/managers/FocusManager/FocusManager.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 +20 -22
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +6 -6
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +1 -2
- 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 +6 -6
- 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 +9 -14
- package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +144 -54
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseProvider.mjs +39 -2
- package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
- package/dist-esm/lib/license/Watermark.mjs +145 -76
- package/dist-esm/lib/license/Watermark.mjs.map +3 -3
- package/dist-esm/lib/license/useLicenseManagerState.mjs.map +2 -2
- 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.map +2 -2
- package/dist-esm/lib/utils/getPointerInfo.mjs +2 -3
- package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
- package/dist-esm/lib/utils/reparenting.mjs +8 -41
- 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 +2 -9
- package/src/lib/TldrawEditor.tsx +1 -15
- package/src/lib/components/default-components/DefaultCanvas.tsx +7 -1
- package/src/lib/editor/Editor.test.ts +90 -0
- package/src/lib/editor/Editor.ts +50 -129
- package/src/lib/editor/derivations/notVisibleShapes.ts +6 -0
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +6 -2
- 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 +20 -20
- package/src/lib/hooks/useDocumentEvents.ts +6 -6
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -1
- package/src/lib/hooks/useGestureEvents.ts +2 -2
- package/src/lib/hooks/useHandleEvents.ts +6 -6
- package/src/lib/hooks/usePassThroughMouseOverEvents.ts +4 -1
- package/src/lib/hooks/useSelectionEvents.ts +9 -14
- package/src/lib/license/LicenseManager.test.ts +721 -382
- package/src/lib/license/LicenseManager.ts +204 -58
- package/src/lib/license/LicenseProvider.tsx +74 -2
- package/src/lib/license/Watermark.tsx +152 -77
- package/src/lib/license/useLicenseManagerState.ts +2 -2
- 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 +103 -0
- package/src/lib/utils/dom.ts +8 -1
- package/src/lib/utils/getPointerInfo.ts +3 -2
- package/src/lib/utils/reparenting.ts +10 -70
- package/src/version.ts +3 -3
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
|
|
|
@@ -363,6 +343,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
363
343
|
this.root = new NewRoot(this)
|
|
364
344
|
this.root.children = {}
|
|
365
345
|
|
|
346
|
+
this.markEventAsHandled = this.markEventAsHandled.bind(this)
|
|
347
|
+
|
|
366
348
|
const allShapeUtils = checkShapesAndAddCore(shapeUtils)
|
|
367
349
|
|
|
368
350
|
const _shapeUtils = {} as Record<string, ShapeUtil<any>>
|
|
@@ -907,14 +889,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
907
889
|
*/
|
|
908
890
|
readonly fonts: FontManager
|
|
909
891
|
|
|
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
892
|
/**
|
|
919
893
|
* A manager for the editor's scribbles.
|
|
920
894
|
*
|
|
@@ -1119,35 +1093,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1119
1093
|
return this.history.getNumRedos() > 0
|
|
1120
1094
|
}
|
|
1121
1095
|
|
|
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
1096
|
/**
|
|
1152
1097
|
* Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
|
|
1153
1098
|
* any redos. You typically want to do this just before a user interaction begins or is handled.
|
|
@@ -1272,13 +1217,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1272
1217
|
return this
|
|
1273
1218
|
}
|
|
1274
1219
|
|
|
1275
|
-
/**
|
|
1276
|
-
* @deprecated Use `Editor.run` instead.
|
|
1277
|
-
*/
|
|
1278
|
-
batch(fn: () => void, opts?: TLEditorRunOptions): this {
|
|
1279
|
-
return this.run(fn, opts)
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1282
1220
|
/* --------------------- Errors --------------------- */
|
|
1283
1221
|
|
|
1284
1222
|
/** @internal */
|
|
@@ -1580,54 +1518,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1580
1518
|
|
|
1581
1519
|
menus = tlmenus.forContext(this.contextId)
|
|
1582
1520
|
|
|
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
1521
|
/* --------------------- Cursor --------------------- */
|
|
1632
1522
|
|
|
1633
1523
|
/**
|
|
@@ -4792,8 +4682,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4792
4682
|
return this.store.createComputedCache<Box, TLShape>('pageBoundsCache', (shape) => {
|
|
4793
4683
|
const pageTransform = this.getShapePageTransform(shape)
|
|
4794
4684
|
if (!pageTransform) return undefined
|
|
4795
|
-
|
|
4796
|
-
return Box.FromPoints(
|
|
4685
|
+
|
|
4686
|
+
return Box.FromPoints(
|
|
4687
|
+
pageTransform.applyToPoints(this.getShapeGeometry(shape).boundsVertices)
|
|
4688
|
+
)
|
|
4797
4689
|
})
|
|
4798
4690
|
}
|
|
4799
4691
|
|
|
@@ -5839,11 +5731,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5839
5731
|
return shapeIds
|
|
5840
5732
|
}
|
|
5841
5733
|
|
|
5842
|
-
/** @deprecated Use {@link Editor.getDraggingOverShape} instead */
|
|
5843
|
-
getDroppingOverShape(point: Vec, droppingShapes: TLShape[]): TLShape | undefined {
|
|
5844
|
-
return this.getDraggingOverShape(point, droppingShapes)
|
|
5845
|
-
}
|
|
5846
|
-
|
|
5847
5734
|
/**
|
|
5848
5735
|
* Get the shape that some shapes should be dropped on at a given point.
|
|
5849
5736
|
*
|
|
@@ -8948,8 +8835,13 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8948
8835
|
* 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
8836
|
*
|
|
8950
8837
|
* @param info - Info about the external content.
|
|
8838
|
+
* @param opts - Options for handling external content, including force flag to bypass readonly checks.
|
|
8951
8839
|
*/
|
|
8952
|
-
async putExternalContent<E>(
|
|
8840
|
+
async putExternalContent<E>(
|
|
8841
|
+
info: TLExternalContent<E>,
|
|
8842
|
+
opts = {} as { force?: boolean }
|
|
8843
|
+
): Promise<void> {
|
|
8844
|
+
if (!opts.force && this.getIsReadonly()) return
|
|
8953
8845
|
return this.externalContentHandlers[info.type]?.(info as any)
|
|
8954
8846
|
}
|
|
8955
8847
|
|
|
@@ -8957,8 +8849,13 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8957
8849
|
* Handle replacing external content.
|
|
8958
8850
|
*
|
|
8959
8851
|
* @param info - Info about the external content.
|
|
8852
|
+
* @param opts - Options for handling external content, including force flag to bypass readonly checks.
|
|
8960
8853
|
*/
|
|
8961
|
-
async replaceExternalContent<E>(
|
|
8854
|
+
async replaceExternalContent<E>(
|
|
8855
|
+
info: TLExternalContent<E>,
|
|
8856
|
+
opts = {} as { force?: boolean }
|
|
8857
|
+
): Promise<void> {
|
|
8858
|
+
if (!opts.force && this.getIsReadonly()) return
|
|
8962
8859
|
return this.externalContentHandlers[info.type]?.(info as any)
|
|
8963
8860
|
}
|
|
8964
8861
|
|
|
@@ -9459,13 +9356,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9459
9356
|
}
|
|
9460
9357
|
}
|
|
9461
9358
|
|
|
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
9359
|
/**
|
|
9470
9360
|
* Get an exported image of the given shapes.
|
|
9471
9361
|
*
|
|
@@ -10209,6 +10099,37 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10209
10099
|
/** @internal */
|
|
10210
10100
|
private performanceTrackerTimeout = -1 as any
|
|
10211
10101
|
|
|
10102
|
+
/** @internal */
|
|
10103
|
+
private handledEvents = new WeakSet<Event>()
|
|
10104
|
+
|
|
10105
|
+
/**
|
|
10106
|
+
* In tldraw, events are sometimes handled by multiple components. For example, the shapes might
|
|
10107
|
+
* have events, but the canvas handles events too. The way that the canvas handles events can
|
|
10108
|
+
* interfere with the with the shapes event handlers - for example, it calls `.preventDefault()`
|
|
10109
|
+
* on `pointerDown`, which also prevents `click` events from firing on the shapes.
|
|
10110
|
+
*
|
|
10111
|
+
* You can use `.stopPropagation()` to prevent the event from propagating to the rest of the
|
|
10112
|
+
* DOM, but that can impact non-tldraw event handlers set up elsewhere. By using
|
|
10113
|
+
* `markEventAsHandled`, you'll stop other parts of tldraw from handling the event without
|
|
10114
|
+
* impacting other, non-tldraw event handlers. See also {@link Editor.wasEventAlreadyHandled}.
|
|
10115
|
+
*
|
|
10116
|
+
* @public
|
|
10117
|
+
*/
|
|
10118
|
+
markEventAsHandled(e: Event | { nativeEvent: Event }) {
|
|
10119
|
+
const nativeEvent = 'nativeEvent' in e ? e.nativeEvent : e
|
|
10120
|
+
this.handledEvents.add(nativeEvent)
|
|
10121
|
+
}
|
|
10122
|
+
|
|
10123
|
+
/**
|
|
10124
|
+
* Checks if an event has already been handled. See {@link Editor.markEventAsHandled}.
|
|
10125
|
+
*
|
|
10126
|
+
* @public
|
|
10127
|
+
*/
|
|
10128
|
+
wasEventAlreadyHandled(e: Event | { nativeEvent: Event }) {
|
|
10129
|
+
const nativeEvent = 'nativeEvent' in e ? e.nativeEvent : e
|
|
10130
|
+
return this.handledEvents.has(nativeEvent)
|
|
10131
|
+
}
|
|
10132
|
+
|
|
10212
10133
|
/**
|
|
10213
10134
|
* Dispatch an event to the editor.
|
|
10214
10135
|
*
|
|
@@ -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)
|
|
@@ -58,8 +58,12 @@ export class FocusManager {
|
|
|
58
58
|
|
|
59
59
|
private handleKeyDown(keyEvent: KeyboardEvent) {
|
|
60
60
|
const container = this.editor.getContainer()
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
const activeEl = document.activeElement
|
|
62
|
+
// Edit mode should remove the focus ring, however if the active element's
|
|
63
|
+
// parent is the contextual toolbar, then allow it.
|
|
64
|
+
if (this.editor.isIn('select.editing_shape') && !activeEl?.closest('.tlui-contextual-toolbar'))
|
|
65
|
+
return
|
|
66
|
+
if (activeEl === container && this.editor.getSelectedShapeIds().length > 0) return
|
|
63
67
|
if (['Tab', 'ArrowUp', 'ArrowDown'].includes(keyEvent.key)) {
|
|
64
68
|
container.classList.remove('tl-container__no-focus-ring')
|
|
65
69
|
}
|
|
@@ -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. */
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { useValue } from '@tldraw/state-react'
|
|
2
2
|
import React, { useEffect, useMemo } from 'react'
|
|
3
3
|
import { RIGHT_MOUSE_BUTTON } from '../constants'
|
|
4
|
-
import {
|
|
5
|
-
preventDefault,
|
|
6
|
-
releasePointerCapture,
|
|
7
|
-
setPointerCapture,
|
|
8
|
-
stopEventPropagation,
|
|
9
|
-
} from '../utils/dom'
|
|
4
|
+
import { preventDefault, releasePointerCapture, setPointerCapture } from '../utils/dom'
|
|
10
5
|
import { getPointerInfo } from '../utils/getPointerInfo'
|
|
11
6
|
import { useEditor } from './useEditor'
|
|
12
7
|
|
|
@@ -17,14 +12,14 @@ export function useCanvasEvents() {
|
|
|
17
12
|
const events = useMemo(
|
|
18
13
|
function canvasEvents() {
|
|
19
14
|
function onPointerDown(e: React.PointerEvent) {
|
|
20
|
-
if ((e
|
|
15
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
21
16
|
|
|
22
17
|
if (e.button === RIGHT_MOUSE_BUTTON) {
|
|
23
18
|
editor.dispatch({
|
|
24
19
|
type: 'pointer',
|
|
25
20
|
target: 'canvas',
|
|
26
21
|
name: 'right_click',
|
|
27
|
-
...getPointerInfo(e),
|
|
22
|
+
...getPointerInfo(editor, e),
|
|
28
23
|
})
|
|
29
24
|
return
|
|
30
25
|
}
|
|
@@ -37,12 +32,12 @@ export function useCanvasEvents() {
|
|
|
37
32
|
type: 'pointer',
|
|
38
33
|
target: 'canvas',
|
|
39
34
|
name: 'pointer_down',
|
|
40
|
-
...getPointerInfo(e),
|
|
35
|
+
...getPointerInfo(editor, e),
|
|
41
36
|
})
|
|
42
37
|
}
|
|
43
38
|
|
|
44
39
|
function onPointerUp(e: React.PointerEvent) {
|
|
45
|
-
if ((e
|
|
40
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
46
41
|
if (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return
|
|
47
42
|
|
|
48
43
|
releasePointerCapture(e.currentTarget, e)
|
|
@@ -51,31 +46,33 @@ export function useCanvasEvents() {
|
|
|
51
46
|
type: 'pointer',
|
|
52
47
|
target: 'canvas',
|
|
53
48
|
name: 'pointer_up',
|
|
54
|
-
...getPointerInfo(e),
|
|
49
|
+
...getPointerInfo(editor, e),
|
|
55
50
|
})
|
|
56
51
|
}
|
|
57
52
|
|
|
58
53
|
function onPointerEnter(e: React.PointerEvent) {
|
|
59
|
-
if ((e
|
|
54
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
60
55
|
if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
|
|
61
56
|
const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
|
|
62
57
|
editor.updateInstanceState({ isHoveringCanvas: canHover ? true : null })
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
function onPointerLeave(e: React.PointerEvent) {
|
|
66
|
-
if ((e
|
|
61
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
67
62
|
if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
|
|
68
63
|
const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
|
|
69
64
|
editor.updateInstanceState({ isHoveringCanvas: canHover ? false : null })
|
|
70
65
|
}
|
|
71
66
|
|
|
72
67
|
function onTouchStart(e: React.TouchEvent) {
|
|
73
|
-
|
|
68
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
69
|
+
editor.markEventAsHandled(e)
|
|
74
70
|
preventDefault(e)
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
function onTouchEnd(e: React.TouchEvent) {
|
|
78
|
-
|
|
74
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
75
|
+
editor.markEventAsHandled(e)
|
|
79
76
|
// check that e.target is an HTMLElement
|
|
80
77
|
if (!(e.target instanceof HTMLElement)) return
|
|
81
78
|
|
|
@@ -94,12 +91,14 @@ export function useCanvasEvents() {
|
|
|
94
91
|
}
|
|
95
92
|
|
|
96
93
|
function onDragOver(e: React.DragEvent<Element>) {
|
|
94
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
97
95
|
preventDefault(e)
|
|
98
96
|
}
|
|
99
97
|
|
|
100
98
|
async function onDrop(e: React.DragEvent<Element>) {
|
|
99
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
101
100
|
preventDefault(e)
|
|
102
|
-
|
|
101
|
+
e.stopPropagation()
|
|
103
102
|
|
|
104
103
|
if (e.dataTransfer?.files?.length) {
|
|
105
104
|
const files = Array.from(e.dataTransfer.files)
|
|
@@ -124,7 +123,8 @@ export function useCanvasEvents() {
|
|
|
124
123
|
}
|
|
125
124
|
|
|
126
125
|
function onClick(e: React.MouseEvent) {
|
|
127
|
-
|
|
126
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
127
|
+
e.stopPropagation()
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
return {
|
|
@@ -151,8 +151,8 @@ export function useCanvasEvents() {
|
|
|
151
151
|
let lastX: number, lastY: number
|
|
152
152
|
|
|
153
153
|
function onPointerMove(e: PointerEvent) {
|
|
154
|
-
if ((e
|
|
155
|
-
|
|
154
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
155
|
+
editor.markEventAsHandled(e)
|
|
156
156
|
|
|
157
157
|
if (e.clientX === lastX && e.clientY === lastY) return
|
|
158
158
|
lastX = e.clientX
|
|
@@ -168,7 +168,7 @@ export function useCanvasEvents() {
|
|
|
168
168
|
type: 'pointer',
|
|
169
169
|
target: 'canvas',
|
|
170
170
|
name: 'pointer_move',
|
|
171
|
-
...getPointerInfo(singleEvent),
|
|
171
|
+
...getPointerInfo(editor, singleEvent),
|
|
172
172
|
})
|
|
173
173
|
}
|
|
174
174
|
}
|
|
@@ -2,7 +2,7 @@ import { useValue } from '@tldraw/state-react'
|
|
|
2
2
|
import { useEffect } from 'react'
|
|
3
3
|
import { Editor } from '../editor/Editor'
|
|
4
4
|
import { TLKeyboardEventInfo } from '../editor/types/event-types'
|
|
5
|
-
import { activeElementShouldCaptureKeys, preventDefault
|
|
5
|
+
import { activeElementShouldCaptureKeys, preventDefault } from '../utils/dom'
|
|
6
6
|
import { isAccelKey } from '../utils/keyboard'
|
|
7
7
|
import { useContainer } from './useContainer'
|
|
8
8
|
import { useEditor } from './useEditor'
|
|
@@ -29,7 +29,7 @@ export function useDocumentEvents() {
|
|
|
29
29
|
// re-dispatched, which would lead to an infinite loop.
|
|
30
30
|
if ((e as any).isSpecialRedispatchedEvent) return
|
|
31
31
|
preventDefault(e)
|
|
32
|
-
|
|
32
|
+
e.stopPropagation()
|
|
33
33
|
const cvs = container.querySelector('.tl-canvas')
|
|
34
34
|
if (!cvs) return
|
|
35
35
|
const newEvent = new DragEvent(e.type, e)
|
|
@@ -103,8 +103,8 @@ export function useDocumentEvents() {
|
|
|
103
103
|
preventDefault(e)
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
if ((e
|
|
107
|
-
|
|
106
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
107
|
+
editor.markEventAsHandled(e)
|
|
108
108
|
const hasSelectedShapes = !!editor.getSelectedShapeIds().length
|
|
109
109
|
|
|
110
110
|
switch (e.key) {
|
|
@@ -211,8 +211,8 @@ export function useDocumentEvents() {
|
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
const handleKeyUp = (e: KeyboardEvent) => {
|
|
214
|
-
if ((e
|
|
215
|
-
|
|
214
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
215
|
+
editor.markEventAsHandled(e)
|
|
216
216
|
|
|
217
217
|
if (areShortcutsDisabled(editor)) {
|
|
218
218
|
return
|
|
@@ -19,7 +19,7 @@ export function useFixSafariDoubleTapZoomPencilEvents(ref: React.RefObject<HTMLE
|
|
|
19
19
|
|
|
20
20
|
const handleEvent = (e: PointerEvent | TouchEvent) => {
|
|
21
21
|
if (e instanceof PointerEvent && e.pointerType === 'pen') {
|
|
22
|
-
|
|
22
|
+
editor.markEventAsHandled(e)
|
|
23
23
|
const { target } = e
|
|
24
24
|
|
|
25
25
|
// Allow events to propagate if the app is editing a shape, or if the event is occurring in a text area or input
|
|
@@ -3,7 +3,7 @@ import { createUseGesture, pinchAction, wheelAction } from '@use-gesture/react'
|
|
|
3
3
|
import * as React from 'react'
|
|
4
4
|
import { TLWheelEventInfo } from '../editor/types/event-types'
|
|
5
5
|
import { Vec } from '../primitives/Vec'
|
|
6
|
-
import { preventDefault
|
|
6
|
+
import { preventDefault } from '../utils/dom'
|
|
7
7
|
import { isAccelKey } from '../utils/keyboard'
|
|
8
8
|
import { normalizeWheel } from '../utils/normalizeWheel'
|
|
9
9
|
import { useEditor } from './useEditor'
|
|
@@ -113,7 +113,7 @@ export function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
preventDefault(event)
|
|
116
|
-
|
|
116
|
+
event.stopPropagation()
|
|
117
117
|
const delta = normalizeWheel(event)
|
|
118
118
|
|
|
119
119
|
if (delta.x === 0 && delta.y === 0) return
|
|
@@ -16,7 +16,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
16
16
|
|
|
17
17
|
return React.useMemo(() => {
|
|
18
18
|
const onPointerDown = (e: React.PointerEvent) => {
|
|
19
|
-
if ((e
|
|
19
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
20
20
|
|
|
21
21
|
// Must set pointer capture on an HTML element!
|
|
22
22
|
const target = loopToHtmlElement(e.currentTarget)
|
|
@@ -32,7 +32,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
32
32
|
handle,
|
|
33
33
|
shape,
|
|
34
34
|
name: 'pointer_down',
|
|
35
|
-
...getPointerInfo(e),
|
|
35
|
+
...getPointerInfo(editor, e),
|
|
36
36
|
})
|
|
37
37
|
}
|
|
38
38
|
|
|
@@ -40,7 +40,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
40
40
|
let lastX: number, lastY: number
|
|
41
41
|
|
|
42
42
|
const onPointerMove = (e: React.PointerEvent) => {
|
|
43
|
-
if ((e
|
|
43
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
44
44
|
if (e.clientX === lastX && e.clientY === lastY) return
|
|
45
45
|
lastX = e.clientX
|
|
46
46
|
lastY = e.clientY
|
|
@@ -55,12 +55,12 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
55
55
|
handle,
|
|
56
56
|
shape,
|
|
57
57
|
name: 'pointer_move',
|
|
58
|
-
...getPointerInfo(e),
|
|
58
|
+
...getPointerInfo(editor, e),
|
|
59
59
|
})
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
const onPointerUp = (e: React.PointerEvent) => {
|
|
63
|
-
if ((e
|
|
63
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
64
64
|
|
|
65
65
|
const target = loopToHtmlElement(e.currentTarget)
|
|
66
66
|
releasePointerCapture(target, e)
|
|
@@ -75,7 +75,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
75
75
|
handle,
|
|
76
76
|
shape,
|
|
77
77
|
name: 'pointer_up',
|
|
78
|
-
...getPointerInfo(e),
|
|
78
|
+
...getPointerInfo(editor, e),
|
|
79
79
|
})
|
|
80
80
|
}
|
|
81
81
|
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { RefObject, useEffect } from 'react'
|
|
2
2
|
import { preventDefault } from '../utils/dom'
|
|
3
3
|
import { useContainer } from './useContainer'
|
|
4
|
+
import { useMaybeEditor } from './useEditor'
|
|
4
5
|
|
|
5
6
|
/** @public */
|
|
6
7
|
export function usePassThroughMouseOverEvents(ref: RefObject<HTMLElement>) {
|
|
7
8
|
if (!ref) throw Error('usePassThroughWheelEvents must be passed a ref')
|
|
8
9
|
const container = useContainer()
|
|
10
|
+
const editor = useMaybeEditor()
|
|
9
11
|
|
|
10
12
|
useEffect(() => {
|
|
11
13
|
function onMouseOver(e: MouseEvent) {
|
|
14
|
+
if (!editor?.getInstanceState().isFocused) return
|
|
12
15
|
if ((e as any).isSpecialRedispatchedEvent) return
|
|
13
16
|
preventDefault(e)
|
|
14
17
|
const cvs = container.querySelector('.tl-canvas')
|
|
@@ -25,5 +28,5 @@ export function usePassThroughMouseOverEvents(ref: RefObject<HTMLElement>) {
|
|
|
25
28
|
return () => {
|
|
26
29
|
elm.removeEventListener('mouseover', onMouseOver)
|
|
27
30
|
}
|
|
28
|
-
}, [container, ref])
|
|
31
|
+
}, [container, editor, ref])
|
|
29
32
|
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { useMemo } from 'react'
|
|
2
2
|
import { RIGHT_MOUSE_BUTTON } from '../constants'
|
|
3
3
|
import { TLSelectionHandle } from '../editor/types/selection-types'
|
|
4
|
-
import {
|
|
5
|
-
loopToHtmlElement,
|
|
6
|
-
releasePointerCapture,
|
|
7
|
-
setPointerCapture,
|
|
8
|
-
stopEventPropagation,
|
|
9
|
-
} from '../utils/dom'
|
|
4
|
+
import { loopToHtmlElement, releasePointerCapture, setPointerCapture } from '../utils/dom'
|
|
10
5
|
import { getPointerInfo } from '../utils/getPointerInfo'
|
|
11
6
|
import { useEditor } from './useEditor'
|
|
12
7
|
|
|
@@ -17,7 +12,7 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
17
12
|
const events = useMemo(
|
|
18
13
|
function selectionEvents() {
|
|
19
14
|
const onPointerDown: React.PointerEventHandler = (e) => {
|
|
20
|
-
if ((e
|
|
15
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
21
16
|
|
|
22
17
|
if (e.button === RIGHT_MOUSE_BUTTON) {
|
|
23
18
|
editor.dispatch({
|
|
@@ -25,7 +20,7 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
25
20
|
target: 'selection',
|
|
26
21
|
handle,
|
|
27
22
|
name: 'right_click',
|
|
28
|
-
...getPointerInfo(e),
|
|
23
|
+
...getPointerInfo(editor, e),
|
|
29
24
|
})
|
|
30
25
|
return
|
|
31
26
|
}
|
|
@@ -52,16 +47,16 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
52
47
|
type: 'pointer',
|
|
53
48
|
target: 'selection',
|
|
54
49
|
handle,
|
|
55
|
-
...getPointerInfo(e),
|
|
50
|
+
...getPointerInfo(editor, e),
|
|
56
51
|
})
|
|
57
|
-
|
|
52
|
+
editor.markEventAsHandled(e)
|
|
58
53
|
}
|
|
59
54
|
|
|
60
55
|
// Track the last screen point
|
|
61
56
|
let lastX: number, lastY: number
|
|
62
57
|
|
|
63
58
|
function onPointerMove(e: React.PointerEvent) {
|
|
64
|
-
if ((e
|
|
59
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
65
60
|
if (e.button !== 0) return
|
|
66
61
|
if (e.clientX === lastX && e.clientY === lastY) return
|
|
67
62
|
lastX = e.clientX
|
|
@@ -72,12 +67,12 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
72
67
|
type: 'pointer',
|
|
73
68
|
target: 'selection',
|
|
74
69
|
handle,
|
|
75
|
-
...getPointerInfo(e),
|
|
70
|
+
...getPointerInfo(editor, e),
|
|
76
71
|
})
|
|
77
72
|
}
|
|
78
73
|
|
|
79
74
|
const onPointerUp: React.PointerEventHandler = (e) => {
|
|
80
|
-
if ((e
|
|
75
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
81
76
|
if (e.button !== 0) return
|
|
82
77
|
|
|
83
78
|
editor.dispatch({
|
|
@@ -85,7 +80,7 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
85
80
|
type: 'pointer',
|
|
86
81
|
target: 'selection',
|
|
87
82
|
handle,
|
|
88
|
-
...getPointerInfo(e),
|
|
83
|
+
...getPointerInfo(editor, e),
|
|
89
84
|
})
|
|
90
85
|
}
|
|
91
86
|
|