@tldraw/editor 3.16.0-next.6611943ca24a → 3.16.0-next.8eb6d5c2d8f4
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 +117 -109
- package/dist-cjs/index.js +3 -5
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +6 -8
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +12 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/config/TLUserPreferences.js +15 -4
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +75 -114
- 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 +11 -6
- 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 +34 -14
- package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +26 -21
- 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/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/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/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 +117 -109
- package/dist-esm/index.mjs +3 -5
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +6 -8
- 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/config/TLUserPreferences.mjs +15 -4
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +75 -114
- 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 +11 -6
- 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 +34 -14
- package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +27 -27
- 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/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/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/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 +16 -3
- package/package.json +7 -7
- package/src/index.ts +2 -9
- package/src/lib/TldrawEditor.tsx +7 -16
- package/src/lib/components/default-components/DefaultCanvas.tsx +9 -1
- package/src/lib/config/TLUserPreferences.ts +16 -3
- package/src/lib/editor/Editor.test.ts +90 -0
- package/src/lib/editor/Editor.ts +95 -151
- package/src/lib/editor/derivations/notVisibleShapes.ts +6 -0
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +6 -2
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +30 -8
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +10 -3
- package/src/lib/editor/shapes/ShapeUtil.ts +46 -0
- package/src/lib/editor/types/misc-types.ts +0 -6
- package/src/lib/exports/getSvgJsx.test.ts +868 -0
- package/src/lib/exports/getSvgJsx.tsx +76 -19
- package/src/lib/hooks/useCanvasEvents.ts +26 -26
- 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/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/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/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
|
@@ -57,33 +57,21 @@ export function getSvgJsx(editor: Editor, ids: TLShapeId[], opts: TLImageExportO
|
|
|
57
57
|
.filter(({ id }) => shapeIdsToInclude.has(id))
|
|
58
58
|
|
|
59
59
|
// --- Common bounding box of all shapes
|
|
60
|
+
const singleFrameShapeId =
|
|
61
|
+
ids.length === 1 && editor.isShapeOfType<TLFrameShape>(editor.getShape(ids[0])!, 'frame')
|
|
62
|
+
? ids[0]
|
|
63
|
+
: null
|
|
64
|
+
|
|
60
65
|
let bbox: null | Box = null
|
|
61
66
|
if (opts.bounds) {
|
|
62
|
-
bbox = opts.bounds
|
|
67
|
+
bbox = opts.bounds.clone().expandBy(padding)
|
|
63
68
|
} else {
|
|
64
|
-
|
|
65
|
-
const maskedPageBounds = editor.getShapeMaskedPageBounds(id)
|
|
66
|
-
if (!maskedPageBounds) continue
|
|
67
|
-
if (bbox) {
|
|
68
|
-
bbox.union(maskedPageBounds)
|
|
69
|
-
} else {
|
|
70
|
-
bbox = maskedPageBounds.clone()
|
|
71
|
-
}
|
|
72
|
-
}
|
|
69
|
+
bbox = getExportDefaultBounds(editor, renderingShapes, padding, singleFrameShapeId)
|
|
73
70
|
}
|
|
74
71
|
|
|
75
72
|
// no unmasked shapes to export
|
|
76
73
|
if (!bbox) return
|
|
77
74
|
|
|
78
|
-
const singleFrameShapeId =
|
|
79
|
-
ids.length === 1 && editor.isShapeOfType<TLFrameShape>(editor.getShape(ids[0])!, 'frame')
|
|
80
|
-
? ids[0]
|
|
81
|
-
: null
|
|
82
|
-
if (!singleFrameShapeId) {
|
|
83
|
-
// Expand by an extra 32 pixels
|
|
84
|
-
bbox.expandBy(padding)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
75
|
// We want the svg image to be BIGGER THAN USUAL to account for image quality
|
|
88
76
|
const w = bbox.width * scale
|
|
89
77
|
const h = bbox.height * scale
|
|
@@ -120,6 +108,75 @@ export function getSvgJsx(editor: Editor, ids: TLShapeId[], opts: TLImageExportO
|
|
|
120
108
|
return { jsx: svg, width: w, height: h, exportDelay }
|
|
121
109
|
}
|
|
122
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Calculates the default bounds for an SVG export. This function handles:
|
|
113
|
+
* 1. Computing masked page bounds for each shape
|
|
114
|
+
* 2. Container logic: if a shape is marked as an export bounds container and it
|
|
115
|
+
* contains all other shapes, use its bounds and skip padding
|
|
116
|
+
* 3. Otherwise, create a union of all shape bounds and apply padding
|
|
117
|
+
*
|
|
118
|
+
* The container logic is useful for cases like annotating on an image - if the image
|
|
119
|
+
* contains all annotations, we want to export exactly the image bounds without extra padding.
|
|
120
|
+
*
|
|
121
|
+
* @param editor - The editor instance
|
|
122
|
+
* @param renderingShapes - The shapes to include in the export
|
|
123
|
+
* @param padding - Padding to add around the bounds (only applied if no container bounds)
|
|
124
|
+
* @param singleFrameShapeId - If exporting a single frame, this is its ID (skips padding)
|
|
125
|
+
* @returns The calculated bounds box, or null if no shapes to export
|
|
126
|
+
*/
|
|
127
|
+
export function getExportDefaultBounds(
|
|
128
|
+
editor: Editor,
|
|
129
|
+
renderingShapes: TLRenderingShape[],
|
|
130
|
+
padding: number,
|
|
131
|
+
singleFrameShapeId: TLShapeId | null
|
|
132
|
+
) {
|
|
133
|
+
let isBoundedByContainer = false
|
|
134
|
+
let bbox: null | Box = null
|
|
135
|
+
|
|
136
|
+
for (const { id } of renderingShapes) {
|
|
137
|
+
const maskedPageBounds = editor.getShapeMaskedPageBounds(id)
|
|
138
|
+
if (!maskedPageBounds) continue
|
|
139
|
+
|
|
140
|
+
// Check if this shape is an export bounds container (e.g., an image being annotated)
|
|
141
|
+
const shape = editor.getShape(id)!
|
|
142
|
+
const isContainer = editor.getShapeUtil(shape).isExportBoundsContainer(shape)
|
|
143
|
+
|
|
144
|
+
if (bbox) {
|
|
145
|
+
// Container logic: if this is a container and it contains all shapes processed so far,
|
|
146
|
+
// use the container's bounds instead of the union. This prevents extra padding around
|
|
147
|
+
// things like annotated images.
|
|
148
|
+
if (isContainer && Box.ContainsApproximately(maskedPageBounds, bbox)) {
|
|
149
|
+
isBoundedByContainer = true
|
|
150
|
+
bbox = maskedPageBounds.clone()
|
|
151
|
+
} else {
|
|
152
|
+
// If we were previously bounded by a container but this shape extends outside it,
|
|
153
|
+
// we're no longer bounded by a container
|
|
154
|
+
if (isBoundedByContainer && !Box.ContainsApproximately(bbox, maskedPageBounds)) {
|
|
155
|
+
isBoundedByContainer = false
|
|
156
|
+
}
|
|
157
|
+
// Expand the bounding box to include this shape
|
|
158
|
+
bbox.union(maskedPageBounds)
|
|
159
|
+
}
|
|
160
|
+
} else {
|
|
161
|
+
// First shape sets the initial bounds
|
|
162
|
+
isBoundedByContainer = isContainer
|
|
163
|
+
bbox = maskedPageBounds.clone()
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// No unmasked shapes to export
|
|
168
|
+
if (!bbox) return null
|
|
169
|
+
|
|
170
|
+
// Only apply padding if:
|
|
171
|
+
// - Not exporting a single frame (frames have their own padding rules)
|
|
172
|
+
// - Not bounded by a container (containers define their own bounds precisely)
|
|
173
|
+
if (!singleFrameShapeId && !isBoundedByContainer) {
|
|
174
|
+
bbox.expandBy(padding)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return bbox
|
|
178
|
+
}
|
|
179
|
+
|
|
123
180
|
function SvgExport({
|
|
124
181
|
editor,
|
|
125
182
|
preserveAspectRatio,
|
|
@@ -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,55 +46,59 @@ 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
|
|
|
79
|
+
const editingShapeId = editor.getEditingShape()?.id
|
|
82
80
|
if (
|
|
81
|
+
// if the target is not inside the editing shape
|
|
82
|
+
!(editingShapeId && e.target.closest(`[data-shape-id="${editingShapeId}"]`)) &&
|
|
83
|
+
// and the target is not an clickable element
|
|
83
84
|
e.target.tagName !== 'A' &&
|
|
85
|
+
// or a TextArea.tsx ?
|
|
84
86
|
e.target.tagName !== 'TEXTAREA' &&
|
|
85
|
-
!e.target.isContentEditable
|
|
86
|
-
// When in EditingShape state, we are actually clicking on a 'DIV'
|
|
87
|
-
// not A/TEXTAREA/contenteditable element yet. So, to preserve cursor position
|
|
88
|
-
// for edit mode on mobile we need to not preventDefault.
|
|
89
|
-
// TODO: Find out if we still need this preventDefault in general though.
|
|
90
|
-
!(editor.getEditingShape() && e.target.className.includes('tl-text-content'))
|
|
87
|
+
!e.target.isContentEditable
|
|
91
88
|
) {
|
|
92
89
|
preventDefault(e)
|
|
93
90
|
}
|
|
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,14 +1,19 @@
|
|
|
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 usePassThroughWheelEvents(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 onWheel(e: WheelEvent) {
|
|
14
|
+
// Only pass through wheel events if the editor is focused
|
|
15
|
+
if (!editor?.getInstanceState().isFocused) return
|
|
16
|
+
|
|
12
17
|
if ((e as any).isSpecialRedispatchedEvent) return
|
|
13
18
|
|
|
14
19
|
// if the element is scrollable, don't redispatch the event
|
|
@@ -32,5 +37,5 @@ export function usePassThroughWheelEvents(ref: RefObject<HTMLElement>) {
|
|
|
32
37
|
return () => {
|
|
33
38
|
elm.removeEventListener('wheel', onWheel)
|
|
34
39
|
}
|
|
35
|
-
}, [container, ref])
|
|
40
|
+
}, [container, editor, ref])
|
|
36
41
|
}
|
|
@@ -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
|
|