@tldraw/editor 3.16.0-next.f9f54ec051f3 → 4.0.0
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 +197 -114
- package/dist-cjs/index.js +5 -5
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +9 -9
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +0 -5
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +7 -10
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +14 -23
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +1 -1
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultScribble.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +9 -1
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
- package/dist-cjs/lib/config/TLUserPreferences.js +21 -4
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +121 -138
- 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/managers/UserPreferencesManager/UserPreferencesManager.js +14 -4
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +23 -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/exports/getSvgJsx.js +35 -16
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +47 -38
- 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/usePassThroughWheelEvents.js +4 -1
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.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/{utils/nearestMultiple.js → hooks/useStateAttribute.js} +15 -14
- package/dist-cjs/lib/hooks/useStateAttribute.js.map +7 -0
- 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/options.js +7 -0
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/primitives/Box.js +3 -0
- package/dist-cjs/lib/primitives/Box.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/EditorAtom.js +45 -0
- package/dist-cjs/lib/utils/EditorAtom.js.map +7 -0
- 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 +4 -4
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +197 -114
- package/dist-esm/index.mjs +5 -5
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +9 -9
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +0 -5
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +7 -10
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +14 -23
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +1 -1
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultScribble.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +9 -1
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs +21 -4
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +121 -138
- 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/managers/UserPreferencesManager/UserPreferencesManager.mjs +14 -4
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +23 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgJsx.mjs +36 -16
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +49 -45
- 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/usePassThroughWheelEvents.mjs +4 -1
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.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/hooks/useStateAttribute.mjs +15 -0
- package/dist-esm/lib/hooks/useStateAttribute.mjs.map +7 -0
- 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/options.mjs +7 -0
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/primitives/Box.mjs +4 -1
- package/dist-esm/lib/primitives/Box.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/EditorAtom.mjs +25 -0
- package/dist-esm/lib/utils/EditorAtom.mjs.map +7 -0
- 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 +4 -4
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +308 -290
- package/package.json +14 -37
- package/src/index.ts +4 -9
- package/src/lib/TldrawEditor.tsx +14 -21
- package/src/lib/components/MenuClickCapture.tsx +0 -8
- package/src/lib/components/Shape.tsx +6 -12
- package/src/lib/components/default-components/DefaultCanvas.tsx +11 -22
- package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +1 -1
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
- package/src/lib/components/default-components/DefaultScribble.tsx +1 -1
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +5 -1
- package/src/lib/config/TLUserPreferences.ts +21 -1
- package/src/lib/editor/Editor.test.ts +102 -11
- package/src/lib/editor/Editor.ts +165 -198
- package/src/lib/editor/derivations/notVisibleShapes.ts +6 -0
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +15 -14
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +16 -15
- package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +49 -48
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +6 -2
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +24 -23
- package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +7 -6
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +12 -11
- package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +57 -50
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +51 -26
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +14 -13
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +56 -26
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +13 -1
- package/src/lib/editor/shapes/ShapeUtil.ts +46 -0
- package/src/lib/editor/types/misc-types.ts +54 -7
- package/src/lib/exports/getSvgJsx.test.ts +868 -0
- package/src/lib/exports/getSvgJsx.tsx +78 -21
- package/src/lib/hooks/useCanvasEvents.ts +62 -55
- 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/usePassThroughWheelEvents.ts +6 -1
- package/src/lib/hooks/useSelectionEvents.ts +9 -14
- package/src/lib/hooks/useStateAttribute.ts +15 -0
- package/src/lib/license/LicenseManager.test.ts +724 -383
- package/src/lib/license/LicenseManager.ts +204 -58
- package/src/lib/license/LicenseProvider.tsx +74 -2
- package/src/lib/license/Watermark.test.tsx +2 -1
- package/src/lib/license/Watermark.tsx +152 -77
- package/src/lib/license/useLicenseManagerState.ts +2 -2
- package/src/lib/options.ts +8 -0
- package/src/lib/primitives/Box.test.ts +126 -0
- package/src/lib/primitives/Box.ts +10 -1
- 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/EditorAtom.ts +37 -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/lib/utils/sync/LocalIndexedDb.test.ts +2 -1
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +15 -15
- package/src/version.ts +4 -4
- package/dist-cjs/lib/utils/nearestMultiple.js.map +0 -7
- package/dist-esm/lib/utils/nearestMultiple.mjs +0 -14
- package/dist-esm/lib/utils/nearestMultiple.mjs.map +0 -7
- package/src/lib/utils/nearestMultiple.ts +0 -13
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'
|
|
@@ -176,6 +175,7 @@ import {
|
|
|
176
175
|
RequiredKeys,
|
|
177
176
|
TLCameraMoveOptions,
|
|
178
177
|
TLCameraOptions,
|
|
178
|
+
TLGetShapeAtPointOptions,
|
|
179
179
|
TLImageExportOptions,
|
|
180
180
|
TLSvgExportOptions,
|
|
181
181
|
TLUpdatePointerOptions,
|
|
@@ -243,16 +243,6 @@ export interface TLEditorOptions {
|
|
|
243
243
|
options?: Partial<TldrawOptions>
|
|
244
244
|
licenseKey?: string
|
|
245
245
|
fontAssetUrls?: { [key: string]: string | undefined }
|
|
246
|
-
/**
|
|
247
|
-
* A predicate that should return true if the given shape should be hidden.
|
|
248
|
-
*
|
|
249
|
-
* @deprecated Use {@link Editor#getShapeVisibility} instead.
|
|
250
|
-
*
|
|
251
|
-
* @param shape - The shape to check.
|
|
252
|
-
* @param editor - The editor instance.
|
|
253
|
-
*/
|
|
254
|
-
isShapeHidden?(shape: TLShape, editor: Editor): boolean
|
|
255
|
-
|
|
256
246
|
/**
|
|
257
247
|
* Provides a way to hide shapes.
|
|
258
248
|
*
|
|
@@ -308,21 +298,12 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
308
298
|
autoFocus,
|
|
309
299
|
inferDarkMode,
|
|
310
300
|
options,
|
|
311
|
-
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
312
|
-
isShapeHidden,
|
|
313
301
|
getShapeVisibility,
|
|
314
302
|
fontAssetUrls,
|
|
315
303
|
}: TLEditorOptions) {
|
|
316
304
|
super()
|
|
317
|
-
assert(
|
|
318
|
-
!(isShapeHidden && getShapeVisibility),
|
|
319
|
-
'Cannot use both isShapeHidden and getShapeVisibility'
|
|
320
|
-
)
|
|
321
305
|
|
|
322
|
-
this._getShapeVisibility =
|
|
323
|
-
? // eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
324
|
-
(shape: TLShape, editor: Editor) => (isShapeHidden(shape, editor) ? 'hidden' : 'inherit')
|
|
325
|
-
: getShapeVisibility
|
|
306
|
+
this._getShapeVisibility = getShapeVisibility
|
|
326
307
|
|
|
327
308
|
this.options = { ...defaultTldrawOptions, ...options }
|
|
328
309
|
|
|
@@ -362,6 +343,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
362
343
|
this.root = new NewRoot(this)
|
|
363
344
|
this.root.children = {}
|
|
364
345
|
|
|
346
|
+
this.markEventAsHandled = this.markEventAsHandled.bind(this)
|
|
347
|
+
|
|
365
348
|
const allShapeUtils = checkShapesAndAddCore(shapeUtils)
|
|
366
349
|
|
|
367
350
|
const _shapeUtils = {} as Record<string, ShapeUtil<any>>
|
|
@@ -906,14 +889,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
906
889
|
*/
|
|
907
890
|
readonly fonts: FontManager
|
|
908
891
|
|
|
909
|
-
/**
|
|
910
|
-
* A manager for the editor's environment.
|
|
911
|
-
*
|
|
912
|
-
* @deprecated This is deprecated and will be removed in a future version. Use the `tlenv` global export instead.
|
|
913
|
-
* @public
|
|
914
|
-
*/
|
|
915
|
-
readonly environment = tlenv
|
|
916
|
-
|
|
917
892
|
/**
|
|
918
893
|
* A manager for the editor's scribbles.
|
|
919
894
|
*
|
|
@@ -1118,35 +1093,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1118
1093
|
return this.history.getNumRedos() > 0
|
|
1119
1094
|
}
|
|
1120
1095
|
|
|
1121
|
-
/**
|
|
1122
|
-
* Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
|
|
1123
|
-
* any redos.
|
|
1124
|
-
*
|
|
1125
|
-
* @example
|
|
1126
|
-
* ```ts
|
|
1127
|
-
* editor.mark()
|
|
1128
|
-
* editor.mark('flip shapes')
|
|
1129
|
-
* ```
|
|
1130
|
-
*
|
|
1131
|
-
* @param markId - The mark's id, usually the reason for adding the mark.
|
|
1132
|
-
*
|
|
1133
|
-
* @public
|
|
1134
|
-
* @deprecated use {@link Editor.markHistoryStoppingPoint} instead
|
|
1135
|
-
*/
|
|
1136
|
-
mark(markId?: string): this {
|
|
1137
|
-
if (typeof markId === 'string') {
|
|
1138
|
-
console.warn(
|
|
1139
|
-
`[tldraw] \`editor.history.mark("${markId}")\` is deprecated. Please use \`const myMarkId = editor.markHistoryStoppingPoint()\` instead.`
|
|
1140
|
-
)
|
|
1141
|
-
} else {
|
|
1142
|
-
console.warn(
|
|
1143
|
-
'[tldraw] `editor.mark()` is deprecated. Use `editor.markHistoryStoppingPoint()` instead.'
|
|
1144
|
-
)
|
|
1145
|
-
}
|
|
1146
|
-
this.history._mark(markId ?? uniqueId())
|
|
1147
|
-
return this
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
1096
|
/**
|
|
1151
1097
|
* Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
|
|
1152
1098
|
* any redos. You typically want to do this just before a user interaction begins or is handled.
|
|
@@ -1271,13 +1217,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1271
1217
|
return this
|
|
1272
1218
|
}
|
|
1273
1219
|
|
|
1274
|
-
/**
|
|
1275
|
-
* @deprecated Use `Editor.run` instead.
|
|
1276
|
-
*/
|
|
1277
|
-
batch(fn: () => void, opts?: TLEditorRunOptions): this {
|
|
1278
|
-
return this.run(fn, opts)
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
1220
|
/* --------------------- Errors --------------------- */
|
|
1282
1221
|
|
|
1283
1222
|
/** @internal */
|
|
@@ -1579,54 +1518,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1579
1518
|
|
|
1580
1519
|
menus = tlmenus.forContext(this.contextId)
|
|
1581
1520
|
|
|
1582
|
-
/**
|
|
1583
|
-
* @deprecated Use `editor.menus.getOpenMenus` instead.
|
|
1584
|
-
*
|
|
1585
|
-
* @public
|
|
1586
|
-
*/
|
|
1587
|
-
@computed getOpenMenus(): string[] {
|
|
1588
|
-
return this.menus.getOpenMenus()
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
/**
|
|
1592
|
-
* @deprecated Use `editor.menus.addOpenMenu` instead.
|
|
1593
|
-
*
|
|
1594
|
-
* @public
|
|
1595
|
-
*/
|
|
1596
|
-
addOpenMenu(id: string): this {
|
|
1597
|
-
this.menus.addOpenMenu(id)
|
|
1598
|
-
return this
|
|
1599
|
-
}
|
|
1600
|
-
|
|
1601
|
-
/**
|
|
1602
|
-
* @deprecated Use `editor.menus.deleteOpenMenu` instead.
|
|
1603
|
-
*
|
|
1604
|
-
* @public
|
|
1605
|
-
*/
|
|
1606
|
-
deleteOpenMenu(id: string): this {
|
|
1607
|
-
this.menus.deleteOpenMenu(id)
|
|
1608
|
-
return this
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
/**
|
|
1612
|
-
* @deprecated Use `editor.menus.clearOpenMenus` instead.
|
|
1613
|
-
*
|
|
1614
|
-
* @public
|
|
1615
|
-
*/
|
|
1616
|
-
clearOpenMenus(): this {
|
|
1617
|
-
this.menus.clearOpenMenus()
|
|
1618
|
-
return this
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
/**
|
|
1622
|
-
* @deprecated Use `editor.menus.hasAnyOpenMenus` instead.
|
|
1623
|
-
*
|
|
1624
|
-
* @public
|
|
1625
|
-
*/
|
|
1626
|
-
@computed getIsMenuOpen(): boolean {
|
|
1627
|
-
return this.menus.hasAnyOpenMenus()
|
|
1628
|
-
}
|
|
1629
|
-
|
|
1630
1521
|
/* --------------------- Cursor --------------------- */
|
|
1631
1522
|
|
|
1632
1523
|
/**
|
|
@@ -4791,8 +4682,10 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4791
4682
|
return this.store.createComputedCache<Box, TLShape>('pageBoundsCache', (shape) => {
|
|
4792
4683
|
const pageTransform = this.getShapePageTransform(shape)
|
|
4793
4684
|
if (!pageTransform) return undefined
|
|
4794
|
-
|
|
4795
|
-
return Box.FromPoints(
|
|
4685
|
+
|
|
4686
|
+
return Box.FromPoints(
|
|
4687
|
+
pageTransform.applyToPoints(this.getShapeGeometry(shape).boundsVertices)
|
|
4688
|
+
)
|
|
4796
4689
|
})
|
|
4797
4690
|
}
|
|
4798
4691
|
|
|
@@ -4859,27 +4752,25 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
4859
4752
|
return this.store.createComputedCache('pageMaskCache', (shape) => {
|
|
4860
4753
|
if (isPageId(shape.parentId)) return undefined
|
|
4861
4754
|
|
|
4862
|
-
const
|
|
4863
|
-
|
|
4864
|
-
)
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
return []
|
|
4882
|
-
})
|
|
4755
|
+
const clipPaths: Vec[][] = []
|
|
4756
|
+
// Get all ancestors that can potentially clip this shape
|
|
4757
|
+
for (const ancestor of this.getShapeAncestors(shape.id)) {
|
|
4758
|
+
const util = this.getShapeUtil(ancestor)
|
|
4759
|
+
const clipPath = util.getClipPath?.(ancestor)
|
|
4760
|
+
if (!clipPath) continue
|
|
4761
|
+
if (util.shouldClipChild?.(shape) === false) continue
|
|
4762
|
+
const pageTransform = this.getShapePageTransform(ancestor.id)
|
|
4763
|
+
clipPaths.push(pageTransform.applyToPoints(clipPath))
|
|
4764
|
+
}
|
|
4765
|
+
if (clipPaths.length === 0) return undefined
|
|
4766
|
+
|
|
4767
|
+
const pageMask = clipPaths.reduce((acc, b) => {
|
|
4768
|
+
const intersection = intersectPolygonPolygon(acc, b)
|
|
4769
|
+
if (intersection) {
|
|
4770
|
+
return intersection.map(Vec.Cast)
|
|
4771
|
+
}
|
|
4772
|
+
return []
|
|
4773
|
+
})
|
|
4883
4774
|
|
|
4884
4775
|
return pageMask
|
|
4885
4776
|
})
|
|
@@ -5154,20 +5045,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5154
5045
|
*
|
|
5155
5046
|
* @returns The shape at the given point, or undefined if there is no shape at the point.
|
|
5156
5047
|
*/
|
|
5157
|
-
getShapeAtPoint(
|
|
5158
|
-
point: VecLike,
|
|
5159
|
-
opts = {} as {
|
|
5160
|
-
renderingOnly?: boolean
|
|
5161
|
-
margin?: number
|
|
5162
|
-
hitInside?: boolean
|
|
5163
|
-
hitLocked?: boolean
|
|
5164
|
-
// TODO: we probably need to rename this, we don't quite _always_
|
|
5165
|
-
// respect this esp. in the part below that does "Check labels first"
|
|
5166
|
-
hitLabels?: boolean
|
|
5167
|
-
hitFrameInside?: boolean
|
|
5168
|
-
filter?(shape: TLShape): boolean
|
|
5169
|
-
}
|
|
5170
|
-
): TLShape | undefined {
|
|
5048
|
+
getShapeAtPoint(point: VecLike, opts: TLGetShapeAtPointOptions = {}): TLShape | undefined {
|
|
5171
5049
|
const zoomLevel = this.getZoomLevel()
|
|
5172
5050
|
const viewportPageBounds = this.getViewportPageBounds()
|
|
5173
5051
|
const {
|
|
@@ -5179,6 +5057,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5179
5057
|
hitFrameInside = false,
|
|
5180
5058
|
} = opts
|
|
5181
5059
|
|
|
5060
|
+
const [innerMargin, outerMargin] = Array.isArray(margin) ? margin : [margin, margin]
|
|
5061
|
+
|
|
5182
5062
|
let inHollowSmallestArea = Infinity
|
|
5183
5063
|
let inHollowSmallestAreaHit: TLShape | null = null
|
|
5184
5064
|
|
|
@@ -5198,7 +5078,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5198
5078
|
return false
|
|
5199
5079
|
const pageMask = this.getShapeMask(shape)
|
|
5200
5080
|
if (pageMask && !pointInPolygon(point, pageMask)) return false
|
|
5201
|
-
if (filter
|
|
5081
|
+
if (filter && !filter(shape)) return false
|
|
5202
5082
|
return true
|
|
5203
5083
|
})
|
|
5204
5084
|
|
|
@@ -5224,13 +5104,18 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5224
5104
|
}
|
|
5225
5105
|
}
|
|
5226
5106
|
|
|
5227
|
-
if (this.isShapeOfType(shape, 'frame')) {
|
|
5107
|
+
if (this.isShapeOfType<TLFrameShape>(shape, 'frame')) {
|
|
5228
5108
|
// On the rare case that we've hit a frame (not its label), test again hitInside to be forced true;
|
|
5229
5109
|
// this prevents clicks from passing through the body of a frame to shapes behind it.
|
|
5230
5110
|
|
|
5231
5111
|
// If the hit is within the frame's outer margin, then select the frame
|
|
5232
|
-
const distance = geometry.distanceToPoint(pointInShapeSpace,
|
|
5233
|
-
if (
|
|
5112
|
+
const distance = geometry.distanceToPoint(pointInShapeSpace, hitFrameInside)
|
|
5113
|
+
if (
|
|
5114
|
+
hitFrameInside
|
|
5115
|
+
? (distance > 0 && distance <= outerMargin) ||
|
|
5116
|
+
(distance <= 0 && distance > -innerMargin)
|
|
5117
|
+
: distance > 0 && distance <= outerMargin
|
|
5118
|
+
) {
|
|
5234
5119
|
return inMarginClosestToEdgeHit || shape
|
|
5235
5120
|
}
|
|
5236
5121
|
|
|
@@ -5269,11 +5154,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5269
5154
|
// If the margin is zero and the geometry has a very small width or height,
|
|
5270
5155
|
// then check the actual distance. This is to prevent a bug where straight
|
|
5271
5156
|
// lines would never pass the broad phase (point-in-bounds) check.
|
|
5272
|
-
if (
|
|
5157
|
+
if (outerMargin === 0 && (geometry.bounds.w < 1 || geometry.bounds.h < 1)) {
|
|
5273
5158
|
distance = geometry.distanceToPoint(pointInShapeSpace, hitInside)
|
|
5274
5159
|
} else {
|
|
5275
5160
|
// Broad phase
|
|
5276
|
-
if (geometry.bounds.containsPoint(pointInShapeSpace,
|
|
5161
|
+
if (geometry.bounds.containsPoint(pointInShapeSpace, outerMargin)) {
|
|
5277
5162
|
// Narrow phase (actual distance)
|
|
5278
5163
|
distance = geometry.distanceToPoint(pointInShapeSpace, hitInside)
|
|
5279
5164
|
} else {
|
|
@@ -5288,7 +5173,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5288
5173
|
// the shape or negative if inside of the shape. If the distance
|
|
5289
5174
|
// is greater than the margin, then it's a miss. Otherwise...
|
|
5290
5175
|
|
|
5291
|
-
|
|
5176
|
+
// Are we close to the shape's edge?
|
|
5177
|
+
if (distance <= outerMargin || (hitInside && distance <= 0 && distance > -innerMargin)) {
|
|
5292
5178
|
if (geometry.isFilled || (isGroup && geometry.children[0].isFilled)) {
|
|
5293
5179
|
// If the shape is filled, then it's a hit. Remember, we're
|
|
5294
5180
|
// starting from the TOP-MOST shape in z-index order, so any
|
|
@@ -5298,11 +5184,21 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5298
5184
|
// If the shape is bigger than the viewport, then skip it.
|
|
5299
5185
|
if (this.getShapePageBounds(shape)!.contains(viewportPageBounds)) continue
|
|
5300
5186
|
|
|
5301
|
-
//
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5187
|
+
// If we're close to the edge of the shape, and if it's the closest edge among
|
|
5188
|
+
// all the edges that we've gotten close to so far, then we will want to hit the
|
|
5189
|
+
// shape unless we hit something else or closer in later iterations.
|
|
5190
|
+
if (
|
|
5191
|
+
hitInside
|
|
5192
|
+
? // On hitInside, the distance will be negative for hits inside
|
|
5193
|
+
// If the distance is positive, check against the outer margin
|
|
5194
|
+
(distance > 0 && distance <= outerMargin) ||
|
|
5195
|
+
// If the distance is negative, check against the inner margin
|
|
5196
|
+
(distance <= 0 && distance > -innerMargin)
|
|
5197
|
+
: // If hitInside is false, then sadly _we do not know_ whether the
|
|
5198
|
+
// point is inside or outside of the shape, so we check against
|
|
5199
|
+
// the max of the two margins
|
|
5200
|
+
Math.abs(distance) <= Math.max(innerMargin, outerMargin)
|
|
5201
|
+
) {
|
|
5306
5202
|
if (Math.abs(distance) < inMarginClosestToEdgeDistance) {
|
|
5307
5203
|
inMarginClosestToEdgeDistance = Math.abs(distance)
|
|
5308
5204
|
inMarginClosestToEdgeHit = shape
|
|
@@ -5324,6 +5220,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5324
5220
|
} else {
|
|
5325
5221
|
// For open shapes (e.g. lines or draw shapes) always use the margin.
|
|
5326
5222
|
// If the distance is less than the margin, return the shape as the hit.
|
|
5223
|
+
// Use the editor's configurable hit test margin.
|
|
5327
5224
|
if (distance < this.options.hitTestMargin / zoomLevel) {
|
|
5328
5225
|
return shape
|
|
5329
5226
|
}
|
|
@@ -5834,11 +5731,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
5834
5731
|
return shapeIds
|
|
5835
5732
|
}
|
|
5836
5733
|
|
|
5837
|
-
/** @deprecated Use {@link Editor.getDraggingOverShape} instead */
|
|
5838
|
-
getDroppingOverShape(point: Vec, droppingShapes: TLShape[]): TLShape | undefined {
|
|
5839
|
-
return this.getDraggingOverShape(point, droppingShapes)
|
|
5840
|
-
}
|
|
5841
|
-
|
|
5842
5734
|
/**
|
|
5843
5735
|
* Get the shape that some shapes should be dropped on at a given point.
|
|
5844
5736
|
*
|
|
@@ -6326,7 +6218,17 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6326
6218
|
|
|
6327
6219
|
this.createShapes(shapesToCreate)
|
|
6328
6220
|
this.createBindings(bindingsToCreate)
|
|
6329
|
-
|
|
6221
|
+
|
|
6222
|
+
this.setSelectedShapes(
|
|
6223
|
+
compact(
|
|
6224
|
+
ids.map((oldId) => {
|
|
6225
|
+
const newId = shapeIds.get(oldId)
|
|
6226
|
+
if (!newId) return null
|
|
6227
|
+
if (!this.getShape(newId)) return null
|
|
6228
|
+
return newId
|
|
6229
|
+
})
|
|
6230
|
+
)
|
|
6231
|
+
)
|
|
6330
6232
|
|
|
6331
6233
|
if (offset !== undefined) {
|
|
6332
6234
|
// If we've offset the duplicated shapes, check to see whether their new bounds is entirely
|
|
@@ -7380,7 +7282,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7380
7282
|
if (
|
|
7381
7283
|
!this.getShapeUtil(shape).canBeLaidOut?.(shape, {
|
|
7382
7284
|
type: 'stretch',
|
|
7383
|
-
shapes: shapesToStretchFirstPass,
|
|
7384
7285
|
})
|
|
7385
7286
|
) {
|
|
7386
7287
|
continue
|
|
@@ -7851,25 +7752,32 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7851
7752
|
) {
|
|
7852
7753
|
let parentId: TLParentId = this.getFocusedGroupId()
|
|
7853
7754
|
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
7869
|
-
|
|
7870
|
-
|
|
7871
|
-
|
|
7872
|
-
|
|
7755
|
+
const isPositioned = partial.x !== undefined && partial.y !== undefined
|
|
7756
|
+
|
|
7757
|
+
// If the shape has been explicitly positioned, we'll try to find a parent at
|
|
7758
|
+
// that position. If not, we'll assume the user isn't deliberately placing the
|
|
7759
|
+
// shape and the positioning will be handled later by another system.
|
|
7760
|
+
if (isPositioned) {
|
|
7761
|
+
for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
|
|
7762
|
+
const parent = currentPageShapesSorted[i]
|
|
7763
|
+
const util = this.getShapeUtil(parent)
|
|
7764
|
+
if (
|
|
7765
|
+
util.canReceiveNewChildrenOfType(parent, partial.type) &&
|
|
7766
|
+
!this.isShapeHidden(parent) &&
|
|
7767
|
+
this.isPointInShape(
|
|
7768
|
+
parent,
|
|
7769
|
+
// If no parent is provided, then we can treat the
|
|
7770
|
+
// shape's provided x/y as being in the page's space.
|
|
7771
|
+
{ x: partial.x ?? 0, y: partial.y ?? 0 },
|
|
7772
|
+
{
|
|
7773
|
+
margin: 0,
|
|
7774
|
+
hitInside: true,
|
|
7775
|
+
}
|
|
7776
|
+
)
|
|
7777
|
+
) {
|
|
7778
|
+
parentId = parent.id
|
|
7779
|
+
break
|
|
7780
|
+
}
|
|
7873
7781
|
}
|
|
7874
7782
|
}
|
|
7875
7783
|
|
|
@@ -8927,8 +8835,13 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8927
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.
|
|
8928
8836
|
*
|
|
8929
8837
|
* @param info - Info about the external content.
|
|
8838
|
+
* @param opts - Options for handling external content, including force flag to bypass readonly checks.
|
|
8930
8839
|
*/
|
|
8931
|
-
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
|
|
8932
8845
|
return this.externalContentHandlers[info.type]?.(info as any)
|
|
8933
8846
|
}
|
|
8934
8847
|
|
|
@@ -8936,8 +8849,13 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8936
8849
|
* Handle replacing external content.
|
|
8937
8850
|
*
|
|
8938
8851
|
* @param info - Info about the external content.
|
|
8852
|
+
* @param opts - Options for handling external content, including force flag to bypass readonly checks.
|
|
8939
8853
|
*/
|
|
8940
|
-
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
|
|
8941
8859
|
return this.externalContentHandlers[info.type]?.(info as any)
|
|
8942
8860
|
}
|
|
8943
8861
|
|
|
@@ -9438,13 +9356,6 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9438
9356
|
}
|
|
9439
9357
|
}
|
|
9440
9358
|
|
|
9441
|
-
/** @deprecated Use {@link Editor.getSvgString} or {@link Editor.getSvgElement} instead. */
|
|
9442
|
-
async getSvg(shapes: TLShapeId[] | TLShape[], opts: TLSvgExportOptions = {}) {
|
|
9443
|
-
const result = await this.getSvgElement(shapes, opts)
|
|
9444
|
-
if (!result) return undefined
|
|
9445
|
-
return result.svg
|
|
9446
|
-
}
|
|
9447
|
-
|
|
9448
9359
|
/**
|
|
9449
9360
|
* Get an exported image of the given shapes.
|
|
9450
9361
|
*
|
|
@@ -9496,6 +9407,24 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9496
9407
|
}
|
|
9497
9408
|
}
|
|
9498
9409
|
|
|
9410
|
+
/**
|
|
9411
|
+
* Get an exported image of the given shapes as a data URL.
|
|
9412
|
+
*
|
|
9413
|
+
* @param shapes - The shapes (or shape ids) to export.
|
|
9414
|
+
* @param opts - Options for the export.
|
|
9415
|
+
*
|
|
9416
|
+
* @returns A data URL of the image.
|
|
9417
|
+
* @public
|
|
9418
|
+
*/
|
|
9419
|
+
async toImageDataUrl(shapes: TLShapeId[] | TLShape[], opts: TLImageExportOptions = {}) {
|
|
9420
|
+
const { blob, width, height } = await this.toImage(shapes, opts)
|
|
9421
|
+
return {
|
|
9422
|
+
url: await FileHelpers.blobToDataUrl(blob),
|
|
9423
|
+
width,
|
|
9424
|
+
height,
|
|
9425
|
+
}
|
|
9426
|
+
}
|
|
9427
|
+
|
|
9499
9428
|
/* --------------------- Events --------------------- */
|
|
9500
9429
|
|
|
9501
9430
|
/**
|
|
@@ -10170,6 +10099,37 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10170
10099
|
/** @internal */
|
|
10171
10100
|
private performanceTrackerTimeout = -1 as any
|
|
10172
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
|
+
|
|
10173
10133
|
/**
|
|
10174
10134
|
* Dispatch an event to the editor.
|
|
10175
10135
|
*
|
|
@@ -10374,7 +10334,14 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10374
10334
|
|
|
10375
10335
|
this._updateInputsFromEvent(info)
|
|
10376
10336
|
|
|
10377
|
-
const { panSpeed, zoomSpeed
|
|
10337
|
+
const { panSpeed, zoomSpeed } = cameraOptions
|
|
10338
|
+
let wheelBehavior = cameraOptions.wheelBehavior
|
|
10339
|
+
const inputMode = this.user.getUserPreferences().inputMode
|
|
10340
|
+
|
|
10341
|
+
// If the user has set their input mode preference, then use that to determine the wheel behavior
|
|
10342
|
+
if (inputMode !== null) {
|
|
10343
|
+
wheelBehavior = inputMode === 'trackpad' ? 'pan' : 'zoom'
|
|
10344
|
+
}
|
|
10378
10345
|
|
|
10379
10346
|
if (wheelBehavior !== 'none') {
|
|
10380
10347
|
// Stop any camera animation
|
|
@@ -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)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { Mocked, vi } from 'vitest'
|
|
1
2
|
import { Editor } from '../../Editor'
|
|
2
3
|
import { TLClickEventInfo, TLPointerEventInfo } from '../../types/event-types'
|
|
3
4
|
import { ClickManager } from './ClickManager'
|
|
4
5
|
|
|
5
6
|
// Mock the Editor class
|
|
6
|
-
|
|
7
|
+
vi.mock('../../Editor')
|
|
7
8
|
|
|
8
9
|
describe('ClickManager', () => {
|
|
9
|
-
let editor:
|
|
10
|
+
let editor: Mocked<Editor>
|
|
10
11
|
let clickManager: ClickManager
|
|
11
12
|
let mockTimers: any
|
|
12
13
|
|
|
@@ -29,14 +30,14 @@ describe('ClickManager', () => {
|
|
|
29
30
|
})
|
|
30
31
|
|
|
31
32
|
beforeEach(() => {
|
|
32
|
-
|
|
33
|
+
vi.useFakeTimers()
|
|
33
34
|
mockTimers = {
|
|
34
|
-
setTimeout:
|
|
35
|
+
setTimeout: vi.fn((fn, delay) => setTimeout(fn, delay)),
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
editor = {
|
|
38
39
|
timers: mockTimers,
|
|
39
|
-
dispatch:
|
|
40
|
+
dispatch: vi.fn(),
|
|
40
41
|
options: {
|
|
41
42
|
doubleClickDurationMs: 300,
|
|
42
43
|
multiClickDurationMs: 300,
|
|
@@ -46,7 +47,7 @@ describe('ClickManager', () => {
|
|
|
46
47
|
inputs: {
|
|
47
48
|
currentScreenPoint: { x: 0, y: 0 },
|
|
48
49
|
},
|
|
49
|
-
getInstanceState:
|
|
50
|
+
getInstanceState: vi.fn(() => ({
|
|
50
51
|
isCoarsePointer: false,
|
|
51
52
|
})),
|
|
52
53
|
} as any
|
|
@@ -55,8 +56,8 @@ describe('ClickManager', () => {
|
|
|
55
56
|
})
|
|
56
57
|
|
|
57
58
|
afterEach(() => {
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
vi.useRealTimers()
|
|
60
|
+
vi.clearAllMocks()
|
|
60
61
|
})
|
|
61
62
|
|
|
62
63
|
describe('constructor and initial state', () => {
|
|
@@ -100,7 +101,7 @@ describe('ClickManager', () => {
|
|
|
100
101
|
clickManager.handlePointerEvent(pointerEvent)
|
|
101
102
|
expect(clickManager.clickState).toBe('pendingDouble')
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
vi.advanceTimersByTime(350)
|
|
104
105
|
|
|
105
106
|
expect(clickManager.clickState).toBe('idle')
|
|
106
107
|
})
|
|
@@ -141,7 +142,7 @@ describe('ClickManager', () => {
|
|
|
141
142
|
clickManager.handlePointerEvent(firstDown)
|
|
142
143
|
clickManager.handlePointerEvent(secondDown)
|
|
143
144
|
|
|
144
|
-
|
|
145
|
+
vi.advanceTimersByTime(350)
|
|
145
146
|
|
|
146
147
|
expect(editor.dispatch).toHaveBeenCalledWith(
|
|
147
148
|
expect.objectContaining({
|
|
@@ -235,7 +236,7 @@ describe('ClickManager', () => {
|
|
|
235
236
|
clickManager.handlePointerEvent(pointerDown) // second
|
|
236
237
|
clickManager.handlePointerEvent(pointerDown) // third
|
|
237
238
|
|
|
238
|
-
|
|
239
|
+
vi.advanceTimersByTime(350)
|
|
239
240
|
|
|
240
241
|
expect(editor.dispatch).toHaveBeenCalledWith(
|
|
241
242
|
expect.objectContaining({
|
|
@@ -255,7 +256,7 @@ describe('ClickManager', () => {
|
|
|
255
256
|
clickManager.handlePointerEvent(pointerDown) // third
|
|
256
257
|
clickManager.handlePointerEvent(pointerDown) // fourth
|
|
257
258
|
|
|
258
|
-
|
|
259
|
+
vi.advanceTimersByTime(350)
|
|
259
260
|
|
|
260
261
|
expect(editor.dispatch).toHaveBeenCalledWith(
|
|
261
262
|
expect.objectContaining({
|
|
@@ -277,7 +278,7 @@ describe('ClickManager', () => {
|
|
|
277
278
|
editor.options.doubleClickDurationMs
|
|
278
279
|
)
|
|
279
280
|
|
|
280
|
-
|
|
281
|
+
vi.clearAllMocks()
|
|
281
282
|
|
|
282
283
|
// Second click - should use multiClickDurationMs
|
|
283
284
|
clickManager.handlePointerEvent(pointerDown)
|
|
@@ -392,7 +393,7 @@ describe('ClickManager', () => {
|
|
|
392
393
|
clickManager.cancelDoubleClickTimeout()
|
|
393
394
|
|
|
394
395
|
// Advance time - should not dispatch settle event
|
|
395
|
-
|
|
396
|
+
vi.advanceTimersByTime(350)
|
|
396
397
|
|
|
397
398
|
expect(editor.dispatch).not.toHaveBeenCalled()
|
|
398
399
|
expect(clickManager.clickState).toBe('idle')
|