@tldraw/editor 3.16.0-canary.e372fad80b6d → 3.16.0-canary.e455ab838b8f
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 +27 -28
- package/dist-cjs/index.js +2 -4
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/TldrawEditor.js +0 -2
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +4 -4
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +29 -0
- package/dist-cjs/lib/editor/Editor.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/hooks/useCanvasEvents.js +17 -17
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +4 -4
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js +1 -1
- package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.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/useSelectionEvents.js +8 -8
- package/dist-cjs/lib/hooks/useSelectionEvents.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +3 -0
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/license/Watermark.js +97 -90
- package/dist-cjs/lib/license/Watermark.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +1 -12
- 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/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +27 -28
- package/dist-esm/index.mjs +3 -7
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +0 -2
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +5 -5
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +29 -0
- package/dist-esm/lib/editor/Editor.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/hooks/useCanvasEvents.mjs +18 -24
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +5 -10
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs +2 -2
- package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useHandleEvents.mjs +7 -12
- package/dist-esm/lib/hooks/useHandleEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useSelectionEvents.mjs +9 -15
- package/dist-esm/lib/hooks/useSelectionEvents.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +3 -0
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/license/Watermark.mjs +98 -91
- package/dist-esm/lib/license/Watermark.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +1 -12
- 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/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -7
- package/src/index.ts +0 -2
- package/src/lib/TldrawEditor.tsx +0 -2
- package/src/lib/components/default-components/DefaultCanvas.tsx +5 -5
- package/src/lib/editor/Editor.ts +33 -0
- package/src/lib/editor/managers/FocusManager/FocusManager.ts +6 -2
- package/src/lib/hooks/useCanvasEvents.ts +18 -24
- package/src/lib/hooks/useDocumentEvents.ts +5 -10
- package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +2 -2
- package/src/lib/hooks/useHandleEvents.ts +7 -12
- package/src/lib/hooks/useSelectionEvents.ts +9 -15
- package/src/lib/license/LicenseManager.ts +3 -0
- package/src/lib/license/Watermark.tsx +100 -92
- package/src/lib/utils/dom.test.ts +33 -24
- package/src/lib/utils/dom.ts +1 -31
- package/src/lib/utils/getPointerInfo.ts +3 -3
- package/src/version.ts +3 -3
|
@@ -21,7 +21,7 @@ import { Mat } from '../../primitives/Mat'
|
|
|
21
21
|
import { Vec } from '../../primitives/Vec'
|
|
22
22
|
import { toDomPrecision } from '../../primitives/utils'
|
|
23
23
|
import { debugFlags } from '../../utils/debug-flags'
|
|
24
|
-
import {
|
|
24
|
+
import { setStyleProperty } from '../../utils/dom'
|
|
25
25
|
import { GeometryDebuggingView } from '../GeometryDebuggingView'
|
|
26
26
|
import { LiveCollaborators } from '../LiveCollaborators'
|
|
27
27
|
import { MenuClickCapture } from '../MenuClickCapture'
|
|
@@ -174,10 +174,10 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
|
174
174
|
</div>
|
|
175
175
|
<div
|
|
176
176
|
className="tl-canvas__in-front"
|
|
177
|
-
onPointerDown={markEventAsHandled}
|
|
178
|
-
onPointerUp={markEventAsHandled}
|
|
179
|
-
onTouchStart={markEventAsHandled}
|
|
180
|
-
onTouchEnd={markEventAsHandled}
|
|
177
|
+
onPointerDown={editor.markEventAsHandled}
|
|
178
|
+
onPointerUp={editor.markEventAsHandled}
|
|
179
|
+
onTouchStart={editor.markEventAsHandled}
|
|
180
|
+
onTouchEnd={editor.markEventAsHandled}
|
|
181
181
|
>
|
|
182
182
|
<InFrontOfTheCanvasWrapper />
|
|
183
183
|
</div>
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -343,6 +343,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
343
343
|
this.root = new NewRoot(this)
|
|
344
344
|
this.root.children = {}
|
|
345
345
|
|
|
346
|
+
this.markEventAsHandled = this.markEventAsHandled.bind(this)
|
|
347
|
+
|
|
346
348
|
const allShapeUtils = checkShapesAndAddCore(shapeUtils)
|
|
347
349
|
|
|
348
350
|
const _shapeUtils = {} as Record<string, ShapeUtil<any>>
|
|
@@ -10097,6 +10099,37 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
10097
10099
|
/** @internal */
|
|
10098
10100
|
private performanceTrackerTimeout = -1 as any
|
|
10099
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
|
+
|
|
10100
10133
|
/**
|
|
10101
10134
|
* Dispatch an event to the editor.
|
|
10102
10135
|
*
|
|
@@ -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
|
}
|
|
@@ -1,13 +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
|
-
markEventAsHandled,
|
|
6
|
-
preventDefault,
|
|
7
|
-
releasePointerCapture,
|
|
8
|
-
setPointerCapture,
|
|
9
|
-
wasEventAlreadyHandled,
|
|
10
|
-
} from '../utils/dom'
|
|
4
|
+
import { preventDefault, releasePointerCapture, setPointerCapture } from '../utils/dom'
|
|
11
5
|
import { getPointerInfo } from '../utils/getPointerInfo'
|
|
12
6
|
import { useEditor } from './useEditor'
|
|
13
7
|
|
|
@@ -18,14 +12,14 @@ export function useCanvasEvents() {
|
|
|
18
12
|
const events = useMemo(
|
|
19
13
|
function canvasEvents() {
|
|
20
14
|
function onPointerDown(e: React.PointerEvent) {
|
|
21
|
-
if (wasEventAlreadyHandled(e)) return
|
|
15
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
22
16
|
|
|
23
17
|
if (e.button === RIGHT_MOUSE_BUTTON) {
|
|
24
18
|
editor.dispatch({
|
|
25
19
|
type: 'pointer',
|
|
26
20
|
target: 'canvas',
|
|
27
21
|
name: 'right_click',
|
|
28
|
-
...getPointerInfo(e),
|
|
22
|
+
...getPointerInfo(editor, e),
|
|
29
23
|
})
|
|
30
24
|
return
|
|
31
25
|
}
|
|
@@ -38,12 +32,12 @@ export function useCanvasEvents() {
|
|
|
38
32
|
type: 'pointer',
|
|
39
33
|
target: 'canvas',
|
|
40
34
|
name: 'pointer_down',
|
|
41
|
-
...getPointerInfo(e),
|
|
35
|
+
...getPointerInfo(editor, e),
|
|
42
36
|
})
|
|
43
37
|
}
|
|
44
38
|
|
|
45
39
|
function onPointerUp(e: React.PointerEvent) {
|
|
46
|
-
if (wasEventAlreadyHandled(e)) return
|
|
40
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
47
41
|
if (e.button !== 0 && e.button !== 1 && e.button !== 2 && e.button !== 5) return
|
|
48
42
|
|
|
49
43
|
releasePointerCapture(e.currentTarget, e)
|
|
@@ -52,33 +46,33 @@ export function useCanvasEvents() {
|
|
|
52
46
|
type: 'pointer',
|
|
53
47
|
target: 'canvas',
|
|
54
48
|
name: 'pointer_up',
|
|
55
|
-
...getPointerInfo(e),
|
|
49
|
+
...getPointerInfo(editor, e),
|
|
56
50
|
})
|
|
57
51
|
}
|
|
58
52
|
|
|
59
53
|
function onPointerEnter(e: React.PointerEvent) {
|
|
60
|
-
if (wasEventAlreadyHandled(e)) return
|
|
54
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
61
55
|
if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
|
|
62
56
|
const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
|
|
63
57
|
editor.updateInstanceState({ isHoveringCanvas: canHover ? true : null })
|
|
64
58
|
}
|
|
65
59
|
|
|
66
60
|
function onPointerLeave(e: React.PointerEvent) {
|
|
67
|
-
if (wasEventAlreadyHandled(e)) return
|
|
61
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
68
62
|
if (editor.getInstanceState().isPenMode && e.pointerType !== 'pen') return
|
|
69
63
|
const canHover = e.pointerType === 'mouse' || e.pointerType === 'pen'
|
|
70
64
|
editor.updateInstanceState({ isHoveringCanvas: canHover ? false : null })
|
|
71
65
|
}
|
|
72
66
|
|
|
73
67
|
function onTouchStart(e: React.TouchEvent) {
|
|
74
|
-
if (wasEventAlreadyHandled(e)) return
|
|
75
|
-
markEventAsHandled(e)
|
|
68
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
69
|
+
editor.markEventAsHandled(e)
|
|
76
70
|
preventDefault(e)
|
|
77
71
|
}
|
|
78
72
|
|
|
79
73
|
function onTouchEnd(e: React.TouchEvent) {
|
|
80
|
-
if (wasEventAlreadyHandled(e)) return
|
|
81
|
-
markEventAsHandled(e)
|
|
74
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
75
|
+
editor.markEventAsHandled(e)
|
|
82
76
|
// check that e.target is an HTMLElement
|
|
83
77
|
if (!(e.target instanceof HTMLElement)) return
|
|
84
78
|
|
|
@@ -97,12 +91,12 @@ export function useCanvasEvents() {
|
|
|
97
91
|
}
|
|
98
92
|
|
|
99
93
|
function onDragOver(e: React.DragEvent<Element>) {
|
|
100
|
-
if (wasEventAlreadyHandled(e)) return
|
|
94
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
101
95
|
preventDefault(e)
|
|
102
96
|
}
|
|
103
97
|
|
|
104
98
|
async function onDrop(e: React.DragEvent<Element>) {
|
|
105
|
-
if (wasEventAlreadyHandled(e)) return
|
|
99
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
106
100
|
preventDefault(e)
|
|
107
101
|
e.stopPropagation()
|
|
108
102
|
|
|
@@ -129,7 +123,7 @@ export function useCanvasEvents() {
|
|
|
129
123
|
}
|
|
130
124
|
|
|
131
125
|
function onClick(e: React.MouseEvent) {
|
|
132
|
-
if (wasEventAlreadyHandled(e)) return
|
|
126
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
133
127
|
e.stopPropagation()
|
|
134
128
|
}
|
|
135
129
|
|
|
@@ -157,8 +151,8 @@ export function useCanvasEvents() {
|
|
|
157
151
|
let lastX: number, lastY: number
|
|
158
152
|
|
|
159
153
|
function onPointerMove(e: PointerEvent) {
|
|
160
|
-
if (wasEventAlreadyHandled(e)) return
|
|
161
|
-
markEventAsHandled(e)
|
|
154
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
155
|
+
editor.markEventAsHandled(e)
|
|
162
156
|
|
|
163
157
|
if (e.clientX === lastX && e.clientY === lastY) return
|
|
164
158
|
lastX = e.clientX
|
|
@@ -174,7 +168,7 @@ export function useCanvasEvents() {
|
|
|
174
168
|
type: 'pointer',
|
|
175
169
|
target: 'canvas',
|
|
176
170
|
name: 'pointer_move',
|
|
177
|
-
...getPointerInfo(singleEvent),
|
|
171
|
+
...getPointerInfo(editor, singleEvent),
|
|
178
172
|
})
|
|
179
173
|
}
|
|
180
174
|
}
|
|
@@ -2,12 +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 {
|
|
6
|
-
activeElementShouldCaptureKeys,
|
|
7
|
-
markEventAsHandled,
|
|
8
|
-
preventDefault,
|
|
9
|
-
wasEventAlreadyHandled,
|
|
10
|
-
} from '../utils/dom'
|
|
5
|
+
import { activeElementShouldCaptureKeys, preventDefault } from '../utils/dom'
|
|
11
6
|
import { isAccelKey } from '../utils/keyboard'
|
|
12
7
|
import { useContainer } from './useContainer'
|
|
13
8
|
import { useEditor } from './useEditor'
|
|
@@ -108,8 +103,8 @@ export function useDocumentEvents() {
|
|
|
108
103
|
preventDefault(e)
|
|
109
104
|
}
|
|
110
105
|
|
|
111
|
-
if (wasEventAlreadyHandled(e)) return
|
|
112
|
-
markEventAsHandled(e)
|
|
106
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
107
|
+
editor.markEventAsHandled(e)
|
|
113
108
|
const hasSelectedShapes = !!editor.getSelectedShapeIds().length
|
|
114
109
|
|
|
115
110
|
switch (e.key) {
|
|
@@ -216,8 +211,8 @@ export function useDocumentEvents() {
|
|
|
216
211
|
}
|
|
217
212
|
|
|
218
213
|
const handleKeyUp = (e: KeyboardEvent) => {
|
|
219
|
-
if (wasEventAlreadyHandled(e)) return
|
|
220
|
-
markEventAsHandled(e)
|
|
214
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
215
|
+
editor.markEventAsHandled(e)
|
|
221
216
|
|
|
222
217
|
if (areShortcutsDisabled(editor)) {
|
|
223
218
|
return
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { preventDefault } from '../utils/dom'
|
|
3
3
|
import { useEditor } from './useEditor'
|
|
4
4
|
|
|
5
5
|
const IGNORED_TAGS = ['textarea', 'input']
|
|
@@ -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
|
-
markEventAsHandled(e)
|
|
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
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { TLArrowShape, TLLineShape, TLShapeId } from '@tldraw/tlschema'
|
|
2
2
|
import * as React from 'react'
|
|
3
3
|
import { Editor } from '../editor/Editor'
|
|
4
|
-
import {
|
|
5
|
-
loopToHtmlElement,
|
|
6
|
-
releasePointerCapture,
|
|
7
|
-
setPointerCapture,
|
|
8
|
-
wasEventAlreadyHandled,
|
|
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
|
|
|
@@ -21,7 +16,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
21
16
|
|
|
22
17
|
return React.useMemo(() => {
|
|
23
18
|
const onPointerDown = (e: React.PointerEvent) => {
|
|
24
|
-
if (wasEventAlreadyHandled(e)) return
|
|
19
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
25
20
|
|
|
26
21
|
// Must set pointer capture on an HTML element!
|
|
27
22
|
const target = loopToHtmlElement(e.currentTarget)
|
|
@@ -37,7 +32,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
37
32
|
handle,
|
|
38
33
|
shape,
|
|
39
34
|
name: 'pointer_down',
|
|
40
|
-
...getPointerInfo(e),
|
|
35
|
+
...getPointerInfo(editor, e),
|
|
41
36
|
})
|
|
42
37
|
}
|
|
43
38
|
|
|
@@ -45,7 +40,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
45
40
|
let lastX: number, lastY: number
|
|
46
41
|
|
|
47
42
|
const onPointerMove = (e: React.PointerEvent) => {
|
|
48
|
-
if (wasEventAlreadyHandled(e)) return
|
|
43
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
49
44
|
if (e.clientX === lastX && e.clientY === lastY) return
|
|
50
45
|
lastX = e.clientX
|
|
51
46
|
lastY = e.clientY
|
|
@@ -60,12 +55,12 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
60
55
|
handle,
|
|
61
56
|
shape,
|
|
62
57
|
name: 'pointer_move',
|
|
63
|
-
...getPointerInfo(e),
|
|
58
|
+
...getPointerInfo(editor, e),
|
|
64
59
|
})
|
|
65
60
|
}
|
|
66
61
|
|
|
67
62
|
const onPointerUp = (e: React.PointerEvent) => {
|
|
68
|
-
if (wasEventAlreadyHandled(e)) return
|
|
63
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
69
64
|
|
|
70
65
|
const target = loopToHtmlElement(e.currentTarget)
|
|
71
66
|
releasePointerCapture(target, e)
|
|
@@ -80,7 +75,7 @@ export function useHandleEvents(id: TLShapeId, handleId: string) {
|
|
|
80
75
|
handle,
|
|
81
76
|
shape,
|
|
82
77
|
name: 'pointer_up',
|
|
83
|
-
...getPointerInfo(e),
|
|
78
|
+
...getPointerInfo(editor, e),
|
|
84
79
|
})
|
|
85
80
|
}
|
|
86
81
|
|
|
@@ -1,13 +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
|
-
markEventAsHandled,
|
|
7
|
-
releasePointerCapture,
|
|
8
|
-
setPointerCapture,
|
|
9
|
-
wasEventAlreadyHandled,
|
|
10
|
-
} from '../utils/dom'
|
|
4
|
+
import { loopToHtmlElement, releasePointerCapture, setPointerCapture } from '../utils/dom'
|
|
11
5
|
import { getPointerInfo } from '../utils/getPointerInfo'
|
|
12
6
|
import { useEditor } from './useEditor'
|
|
13
7
|
|
|
@@ -18,7 +12,7 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
18
12
|
const events = useMemo(
|
|
19
13
|
function selectionEvents() {
|
|
20
14
|
const onPointerDown: React.PointerEventHandler = (e) => {
|
|
21
|
-
if (wasEventAlreadyHandled(e)) return
|
|
15
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
22
16
|
|
|
23
17
|
if (e.button === RIGHT_MOUSE_BUTTON) {
|
|
24
18
|
editor.dispatch({
|
|
@@ -26,7 +20,7 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
26
20
|
target: 'selection',
|
|
27
21
|
handle,
|
|
28
22
|
name: 'right_click',
|
|
29
|
-
...getPointerInfo(e),
|
|
23
|
+
...getPointerInfo(editor, e),
|
|
30
24
|
})
|
|
31
25
|
return
|
|
32
26
|
}
|
|
@@ -53,16 +47,16 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
53
47
|
type: 'pointer',
|
|
54
48
|
target: 'selection',
|
|
55
49
|
handle,
|
|
56
|
-
...getPointerInfo(e),
|
|
50
|
+
...getPointerInfo(editor, e),
|
|
57
51
|
})
|
|
58
|
-
markEventAsHandled(e)
|
|
52
|
+
editor.markEventAsHandled(e)
|
|
59
53
|
}
|
|
60
54
|
|
|
61
55
|
// Track the last screen point
|
|
62
56
|
let lastX: number, lastY: number
|
|
63
57
|
|
|
64
58
|
function onPointerMove(e: React.PointerEvent) {
|
|
65
|
-
if (wasEventAlreadyHandled(e)) return
|
|
59
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
66
60
|
if (e.button !== 0) return
|
|
67
61
|
if (e.clientX === lastX && e.clientY === lastY) return
|
|
68
62
|
lastX = e.clientX
|
|
@@ -73,12 +67,12 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
73
67
|
type: 'pointer',
|
|
74
68
|
target: 'selection',
|
|
75
69
|
handle,
|
|
76
|
-
...getPointerInfo(e),
|
|
70
|
+
...getPointerInfo(editor, e),
|
|
77
71
|
})
|
|
78
72
|
}
|
|
79
73
|
|
|
80
74
|
const onPointerUp: React.PointerEventHandler = (e) => {
|
|
81
|
-
if (wasEventAlreadyHandled(e)) return
|
|
75
|
+
if (editor.wasEventAlreadyHandled(e)) return
|
|
82
76
|
if (e.button !== 0) return
|
|
83
77
|
|
|
84
78
|
editor.dispatch({
|
|
@@ -86,7 +80,7 @@ export function useSelectionEvents(handle: TLSelectionHandle) {
|
|
|
86
80
|
type: 'pointer',
|
|
87
81
|
target: 'selection',
|
|
88
82
|
handle,
|
|
89
|
-
...getPointerInfo(e),
|
|
83
|
+
...getPointerInfo(editor, e),
|
|
90
84
|
})
|
|
91
85
|
}
|
|
92
86
|
|
|
@@ -178,6 +178,9 @@ export class LicenseManager {
|
|
|
178
178
|
const url = new URL(WATERMARK_TRACK_SRC)
|
|
179
179
|
url.searchParams.set('version', version)
|
|
180
180
|
url.searchParams.set('license_type', trackType)
|
|
181
|
+
if ('license' in result) {
|
|
182
|
+
url.searchParams.set('license_id', result.license.id)
|
|
183
|
+
}
|
|
181
184
|
|
|
182
185
|
// eslint-disable-next-line no-restricted-globals
|
|
183
186
|
fetch(url.toString())
|
|
@@ -3,7 +3,7 @@ import { memo, useRef } from 'react'
|
|
|
3
3
|
import { useCanvasEvents } from '../hooks/useCanvasEvents'
|
|
4
4
|
import { useEditor } from '../hooks/useEditor'
|
|
5
5
|
import { usePassThroughWheelEvents } from '../hooks/usePassThroughWheelEvents'
|
|
6
|
-
import {
|
|
6
|
+
import { preventDefault } from '../utils/dom'
|
|
7
7
|
import { runtime } from '../utils/runtime'
|
|
8
8
|
import { watermarkDesktopSvg, watermarkMobileSvg } from '../watermarks'
|
|
9
9
|
import { LicenseManager } from './LicenseManager'
|
|
@@ -43,11 +43,13 @@ const UnlicensedWatermark = memo(function UnlicensedWatermark({
|
|
|
43
43
|
isDebugMode: boolean
|
|
44
44
|
isMobile: boolean
|
|
45
45
|
}) {
|
|
46
|
+
const editor = useEditor()
|
|
46
47
|
const events = useCanvasEvents()
|
|
47
48
|
const ref = useRef<HTMLDivElement>(null)
|
|
48
49
|
usePassThroughWheelEvents(ref)
|
|
49
50
|
|
|
50
|
-
const url =
|
|
51
|
+
const url =
|
|
52
|
+
'https://tldraw.dev/pricing?utm_source=dotcom&utm_medium=organic&utm_campaign=watermark'
|
|
51
53
|
|
|
52
54
|
return (
|
|
53
55
|
<div
|
|
@@ -64,26 +66,13 @@ const UnlicensedWatermark = memo(function UnlicensedWatermark({
|
|
|
64
66
|
draggable={false}
|
|
65
67
|
role="button"
|
|
66
68
|
onPointerDown={(e) => {
|
|
67
|
-
markEventAsHandled(e)
|
|
69
|
+
editor.markEventAsHandled(e)
|
|
68
70
|
preventDefault(e)
|
|
69
71
|
}}
|
|
70
|
-
title="
|
|
72
|
+
title="The tldraw SDK requires a license key to work in production. You can get a free 100-day trial license at tldraw.dev/pricing."
|
|
71
73
|
onClick={() => runtime.openWindow(url, '_blank')}
|
|
72
|
-
style={{
|
|
73
|
-
position: 'absolute',
|
|
74
|
-
pointerEvents: 'all',
|
|
75
|
-
cursor: 'pointer',
|
|
76
|
-
color: 'var(--tl-color-text)',
|
|
77
|
-
opacity: 0.8,
|
|
78
|
-
border: 0,
|
|
79
|
-
padding: 0,
|
|
80
|
-
backgroundColor: 'transparent',
|
|
81
|
-
fontSize: '11px',
|
|
82
|
-
fontWeight: '600',
|
|
83
|
-
textAlign: 'center',
|
|
84
|
-
}}
|
|
85
74
|
>
|
|
86
|
-
|
|
75
|
+
Get a license for production
|
|
87
76
|
</button>
|
|
88
77
|
</div>
|
|
89
78
|
)
|
|
@@ -127,10 +116,10 @@ const WatermarkInner = memo(function WatermarkInner({
|
|
|
127
116
|
draggable={false}
|
|
128
117
|
role="button"
|
|
129
118
|
onPointerDown={(e) => {
|
|
130
|
-
markEventAsHandled(e)
|
|
119
|
+
editor.markEventAsHandled(e)
|
|
131
120
|
preventDefault(e)
|
|
132
121
|
}}
|
|
133
|
-
title="
|
|
122
|
+
title="Build infinite canvas applications with the tldraw SDK. Learn more at https://tldraw.dev."
|
|
134
123
|
onClick={() => runtime.openWindow(url, '_blank')}
|
|
135
124
|
style={{ mask: maskCss, WebkitMask: maskCss }}
|
|
136
125
|
/>
|
|
@@ -142,7 +131,8 @@ const LicenseStyles = memo(function LicenseStyles() {
|
|
|
142
131
|
const editor = useEditor()
|
|
143
132
|
const className = LicenseManager.className
|
|
144
133
|
|
|
145
|
-
const CSS =
|
|
134
|
+
const CSS = `
|
|
135
|
+
/* ------------------- SEE LICENSE -------------------
|
|
146
136
|
The tldraw watermark is part of tldraw's license. It is shown for unlicensed
|
|
147
137
|
or "licensed-with-watermark" users. By using this library, you agree to
|
|
148
138
|
preserve the watermark's behavior, keeping it visible, unobscured, and
|
|
@@ -151,87 +141,105 @@ available to user-interaction.
|
|
|
151
141
|
To remove the watermark, please purchase a license at tldraw.dev.
|
|
152
142
|
*/
|
|
153
143
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
144
|
+
.${className} {
|
|
145
|
+
position: absolute;
|
|
146
|
+
bottom: max(var(--tl-space-2), env(safe-area-inset-bottom));
|
|
147
|
+
right: max(var(--tl-space-2), env(safe-area-inset-right));
|
|
148
|
+
width: 96px;
|
|
149
|
+
height: 32px;
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
justify-content: center;
|
|
153
|
+
z-index: var(--tl-layer-watermark) !important;
|
|
154
|
+
background-color: color-mix(in srgb, var(--tl-color-background) 62%, transparent);
|
|
155
|
+
opacity: 1;
|
|
156
|
+
border-radius: 5px;
|
|
157
|
+
pointer-events: all;
|
|
158
|
+
padding: 2px;
|
|
159
|
+
box-sizing: content-box;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.${className} > button {
|
|
163
|
+
position: absolute;
|
|
164
|
+
width: 96px;
|
|
165
|
+
height: 32px;
|
|
166
|
+
pointer-events: all;
|
|
167
|
+
cursor: inherit;
|
|
168
|
+
color: var(--tl-color-text);
|
|
169
|
+
opacity: .38;
|
|
170
|
+
border: 0;
|
|
171
|
+
padding: 0;
|
|
172
|
+
background-color: currentColor;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.${className}[data-debug='true'] {
|
|
176
|
+
bottom: max(46px, env(safe-area-inset-bottom));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.${className}[data-mobile='true'] {
|
|
180
|
+
border-radius: 4px 0px 0px 4px;
|
|
181
|
+
right: max(-2px, calc(env(safe-area-inset-right) - 2px));
|
|
182
|
+
width: 8px;
|
|
183
|
+
height: 48px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.${className}[data-mobile='true'] > button {
|
|
187
|
+
width: 8px;
|
|
188
|
+
height: 32px;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.${className}[data-unlicensed='true'] > button {
|
|
192
|
+
font-size: 100px;
|
|
193
|
+
position: absolute;
|
|
194
|
+
pointer-events: all;
|
|
195
|
+
cursor: pointer;
|
|
196
|
+
color: var(--tl-color-text);
|
|
197
|
+
opacity: 0.8;
|
|
198
|
+
border: 0;
|
|
199
|
+
padding: 0;
|
|
200
|
+
background-color: transparent;
|
|
201
|
+
font-size: 11px;
|
|
202
|
+
font-weight: 600;
|
|
203
|
+
text-align: center;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.${className}[data-mobile='true'][data-unlicensed='true'] > button {
|
|
207
|
+
display: none;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
@media (hover: hover) {
|
|
211
|
+
.${className}[data-licensed='false'] > button {
|
|
212
|
+
pointer-events: none;
|
|
170
213
|
}
|
|
171
214
|
|
|
172
|
-
.${className}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
pointer-events: all;
|
|
177
|
-
cursor: inherit;
|
|
178
|
-
color: var(--tl-color-text);
|
|
179
|
-
opacity: .38;
|
|
180
|
-
border: 0;
|
|
181
|
-
padding: 0;
|
|
182
|
-
background-color: currentColor;
|
|
215
|
+
.${className}[data-licensed='false']:hover {
|
|
216
|
+
background-color: var(--tl-color-background);
|
|
217
|
+
transition: background-color 0.2s ease-in-out;
|
|
218
|
+
transition-delay: 0.32s;
|
|
183
219
|
}
|
|
184
220
|
|
|
185
|
-
.${className}[data-
|
|
186
|
-
|
|
221
|
+
.${className}[data-licensed='false']:hover > button {
|
|
222
|
+
animation: ${className}_delayed_link 0.2s forwards ease-in-out;
|
|
223
|
+
animation-delay: 0.32s;
|
|
187
224
|
}
|
|
188
225
|
|
|
189
|
-
.${className}[data-
|
|
190
|
-
|
|
191
|
-
right: max(-2px, calc(env(safe-area-inset-right) - 2px));
|
|
192
|
-
width: 8px;
|
|
193
|
-
height: 48px;
|
|
226
|
+
.${className}[data-licensed='false'] > button:focus-visible {
|
|
227
|
+
opacity: 1;
|
|
194
228
|
}
|
|
229
|
+
}
|
|
195
230
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
231
|
+
@keyframes ${className}_delayed_link {
|
|
232
|
+
0% {
|
|
233
|
+
cursor: inherit;
|
|
234
|
+
opacity: .38;
|
|
235
|
+
pointer-events: none;
|
|
199
236
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
.${className}:hover {
|
|
207
|
-
background-color: var(--tl-color-background);
|
|
208
|
-
transition: background-color 0.2s ease-in-out;
|
|
209
|
-
transition-delay: 0.32s;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
.${className}:hover > button {
|
|
213
|
-
animation: ${className}_delayed_link 0.2s forwards ease-in-out;
|
|
214
|
-
animation-delay: 0.32s;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
.${className} > button:focus-visible {
|
|
218
|
-
opacity: 1;
|
|
219
|
-
}
|
|
237
|
+
100% {
|
|
238
|
+
cursor: pointer;
|
|
239
|
+
opacity: 1;
|
|
240
|
+
pointer-events: all;
|
|
220
241
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
@keyframes ${className}_delayed_link {
|
|
224
|
-
0% {
|
|
225
|
-
cursor: inherit;
|
|
226
|
-
opacity: .38;
|
|
227
|
-
pointer-events: none;
|
|
228
|
-
}
|
|
229
|
-
100% {
|
|
230
|
-
cursor: pointer;
|
|
231
|
-
opacity: 1;
|
|
232
|
-
pointer-events: all;
|
|
233
|
-
}
|
|
234
|
-
}`
|
|
242
|
+
}`
|
|
235
243
|
|
|
236
244
|
return <style nonce={editor.options.nonce}>{CSS}</style>
|
|
237
245
|
})
|