@tldraw/editor 3.16.0-canary.2e83e38fb91b → 3.16.0-canary.344cec0354f3
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 +35 -32
- 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/config/TLUserPreferences.js +15 -4
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +35 -1
- 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/editor/managers/UserPreferencesManager/UserPreferencesManager.js +11 -6
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.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/lib/utils/reparenting.js +5 -1
- package/dist-cjs/lib/utils/reparenting.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 +35 -32
- 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/config/TLUserPreferences.mjs +15 -4
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +35 -1
- 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/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +11 -6
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.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/lib/utils/reparenting.mjs +5 -1
- 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/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/config/TLUserPreferences.ts +16 -3
- package/src/lib/editor/Editor.ts +41 -1
- 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/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/lib/utils/reparenting.ts +7 -1
- package/src/version.ts +3 -3
|
@@ -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
|
})
|
|
@@ -1,18 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TestEditor } from '../test/TestEditor'
|
|
2
2
|
|
|
3
3
|
describe('Event handling utilities', () => {
|
|
4
|
+
let editor: TestEditor
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
editor = new TestEditor()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
editor.dispose()
|
|
12
|
+
})
|
|
4
13
|
describe('markEventAsHandled and wasEventAlreadyHandled', () => {
|
|
5
14
|
it('should track events as handled', () => {
|
|
6
15
|
const mockEvent = new PointerEvent('pointerdown', { pointerId: 1 })
|
|
7
16
|
|
|
8
17
|
// Initially, event should not be marked as handled
|
|
9
|
-
expect(wasEventAlreadyHandled(mockEvent)).toBe(false)
|
|
18
|
+
expect(editor.wasEventAlreadyHandled(mockEvent)).toBe(false)
|
|
10
19
|
|
|
11
20
|
// Mark the event as handled
|
|
12
|
-
markEventAsHandled(mockEvent)
|
|
21
|
+
editor.markEventAsHandled(mockEvent)
|
|
13
22
|
|
|
14
23
|
// Now it should be marked as handled
|
|
15
|
-
expect(wasEventAlreadyHandled(mockEvent)).toBe(true)
|
|
24
|
+
expect(editor.wasEventAlreadyHandled(mockEvent)).toBe(true)
|
|
16
25
|
})
|
|
17
26
|
|
|
18
27
|
it('should work with React synthetic events', () => {
|
|
@@ -20,15 +29,15 @@ describe('Event handling utilities', () => {
|
|
|
20
29
|
const syntheticEvent = { nativeEvent }
|
|
21
30
|
|
|
22
31
|
// Initially not handled
|
|
23
|
-
expect(wasEventAlreadyHandled(syntheticEvent)).toBe(false)
|
|
24
|
-
expect(wasEventAlreadyHandled(nativeEvent)).toBe(false)
|
|
32
|
+
expect(editor.wasEventAlreadyHandled(syntheticEvent)).toBe(false)
|
|
33
|
+
expect(editor.wasEventAlreadyHandled(nativeEvent)).toBe(false)
|
|
25
34
|
|
|
26
35
|
// Mark synthetic event as handled
|
|
27
|
-
markEventAsHandled(syntheticEvent)
|
|
36
|
+
editor.markEventAsHandled(syntheticEvent)
|
|
28
37
|
|
|
29
38
|
// Both synthetic and native should be marked as handled
|
|
30
|
-
expect(wasEventAlreadyHandled(syntheticEvent)).toBe(true)
|
|
31
|
-
expect(wasEventAlreadyHandled(nativeEvent)).toBe(true)
|
|
39
|
+
expect(editor.wasEventAlreadyHandled(syntheticEvent)).toBe(true)
|
|
40
|
+
expect(editor.wasEventAlreadyHandled(nativeEvent)).toBe(true)
|
|
32
41
|
})
|
|
33
42
|
|
|
34
43
|
it('should handle multiple different events independently', () => {
|
|
@@ -37,18 +46,18 @@ describe('Event handling utilities', () => {
|
|
|
37
46
|
const event3 = new MouseEvent('click')
|
|
38
47
|
|
|
39
48
|
// Mark only event1 as handled
|
|
40
|
-
markEventAsHandled(event1)
|
|
49
|
+
editor.markEventAsHandled(event1)
|
|
41
50
|
|
|
42
|
-
expect(wasEventAlreadyHandled(event1)).toBe(true)
|
|
43
|
-
expect(wasEventAlreadyHandled(event2)).toBe(false)
|
|
44
|
-
expect(wasEventAlreadyHandled(event3)).toBe(false)
|
|
51
|
+
expect(editor.wasEventAlreadyHandled(event1)).toBe(true)
|
|
52
|
+
expect(editor.wasEventAlreadyHandled(event2)).toBe(false)
|
|
53
|
+
expect(editor.wasEventAlreadyHandled(event3)).toBe(false)
|
|
45
54
|
|
|
46
55
|
// Mark event2 as handled
|
|
47
|
-
markEventAsHandled(event2)
|
|
56
|
+
editor.markEventAsHandled(event2)
|
|
48
57
|
|
|
49
|
-
expect(wasEventAlreadyHandled(event1)).toBe(true)
|
|
50
|
-
expect(wasEventAlreadyHandled(event2)).toBe(true)
|
|
51
|
-
expect(wasEventAlreadyHandled(event3)).toBe(false)
|
|
58
|
+
expect(editor.wasEventAlreadyHandled(event1)).toBe(true)
|
|
59
|
+
expect(editor.wasEventAlreadyHandled(event2)).toBe(true)
|
|
60
|
+
expect(editor.wasEventAlreadyHandled(event3)).toBe(false)
|
|
52
61
|
})
|
|
53
62
|
|
|
54
63
|
it('should not interfere with event properties', () => {
|
|
@@ -59,7 +68,7 @@ describe('Event handling utilities', () => {
|
|
|
59
68
|
})
|
|
60
69
|
|
|
61
70
|
// Mark as handled
|
|
62
|
-
markEventAsHandled(event)
|
|
71
|
+
editor.markEventAsHandled(event)
|
|
63
72
|
|
|
64
73
|
// Event properties should remain unchanged
|
|
65
74
|
expect(event.pointerId).toBe(1)
|
|
@@ -78,17 +87,17 @@ describe('Event handling utilities', () => {
|
|
|
78
87
|
],
|
|
79
88
|
})
|
|
80
89
|
|
|
81
|
-
expect(wasEventAlreadyHandled(touchEvent)).toBe(false)
|
|
82
|
-
markEventAsHandled(touchEvent)
|
|
83
|
-
expect(wasEventAlreadyHandled(touchEvent)).toBe(true)
|
|
90
|
+
expect(editor.wasEventAlreadyHandled(touchEvent)).toBe(false)
|
|
91
|
+
editor.markEventAsHandled(touchEvent)
|
|
92
|
+
expect(editor.wasEventAlreadyHandled(touchEvent)).toBe(true)
|
|
84
93
|
})
|
|
85
94
|
|
|
86
95
|
it('should work with keyboard events', () => {
|
|
87
96
|
const keyEvent = new KeyboardEvent('keydown', { key: 'Enter' })
|
|
88
97
|
|
|
89
|
-
expect(wasEventAlreadyHandled(keyEvent)).toBe(false)
|
|
90
|
-
markEventAsHandled(keyEvent)
|
|
91
|
-
expect(wasEventAlreadyHandled(keyEvent)).toBe(true)
|
|
98
|
+
expect(editor.wasEventAlreadyHandled(keyEvent)).toBe(false)
|
|
99
|
+
editor.markEventAsHandled(keyEvent)
|
|
100
|
+
expect(editor.wasEventAlreadyHandled(keyEvent)).toBe(true)
|
|
92
101
|
})
|
|
93
102
|
})
|
|
94
103
|
})
|
package/src/lib/utils/dom.ts
CHANGED
|
@@ -81,43 +81,13 @@ export function releasePointerCapture(
|
|
|
81
81
|
/**
|
|
82
82
|
* Calls `event.stopPropagation()`.
|
|
83
83
|
*
|
|
84
|
-
* @deprecated Use {@link markEventAsHandled} instead, or manually call `event.stopPropagation()` if
|
|
84
|
+
* @deprecated Use {@link Editor.markEventAsHandled} instead, or manually call `event.stopPropagation()` if
|
|
85
85
|
* that's what you really want.
|
|
86
86
|
*
|
|
87
87
|
* @public
|
|
88
88
|
*/
|
|
89
89
|
export const stopEventPropagation = (e: any) => e.stopPropagation()
|
|
90
90
|
|
|
91
|
-
const handledEvents = new WeakSet<Event>()
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* In tldraw, events are sometimes handled by multiple components. For example, the shapes might
|
|
95
|
-
* have events, but the canvas handles events too. The way that the canvas handles events can
|
|
96
|
-
* interfere with the with the shapes event handlers - for example, it calls `.preventDefault()` on
|
|
97
|
-
* `pointerDown`, which also prevents `click` events from firing on the shapes.
|
|
98
|
-
*
|
|
99
|
-
* You can use `.stopPropagation()` to prevent the event from propagating to the rest of the DOM,
|
|
100
|
-
* but that can impact non-tldraw event handlers set up elsewhere. By using `markEventAsHandled`,
|
|
101
|
-
* you'll stop other parts of tldraw from handling the event without impacting other, non-tldraw
|
|
102
|
-
* event handlers. See also {@link wasEventAlreadyHandled}.
|
|
103
|
-
*
|
|
104
|
-
* @public
|
|
105
|
-
*/
|
|
106
|
-
export function markEventAsHandled(e: Event | { nativeEvent: Event }) {
|
|
107
|
-
const nativeEvent = 'nativeEvent' in e ? e.nativeEvent : e
|
|
108
|
-
handledEvents.add(nativeEvent)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Checks if an event has already been handled. See {@link markEventAsHandled}.
|
|
113
|
-
*
|
|
114
|
-
* @public
|
|
115
|
-
*/
|
|
116
|
-
export function wasEventAlreadyHandled(e: Event | { nativeEvent: Event }) {
|
|
117
|
-
const nativeEvent = 'nativeEvent' in e ? e.nativeEvent : e
|
|
118
|
-
return handledEvents.has(nativeEvent)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
91
|
/** @internal */
|
|
122
92
|
export const setStyleProperty = (
|
|
123
93
|
elm: HTMLElement | null,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Editor } from '../editor/Editor'
|
|
2
2
|
import { isAccelKey } from './keyboard'
|
|
3
3
|
|
|
4
4
|
/** @public */
|
|
5
|
-
export function getPointerInfo(e: React.PointerEvent | PointerEvent) {
|
|
6
|
-
markEventAsHandled(e)
|
|
5
|
+
export function getPointerInfo(editor: Editor, e: React.PointerEvent | PointerEvent) {
|
|
6
|
+
editor.markEventAsHandled(e)
|
|
7
7
|
|
|
8
8
|
return {
|
|
9
9
|
point: {
|
|
@@ -162,7 +162,13 @@ function getOverlappingShapes<T extends TLShape[] | TLShapeId[]>(
|
|
|
162
162
|
const parentPageTransform = editor.getShapePageTransform(shape)
|
|
163
163
|
const parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)
|
|
164
164
|
|
|
165
|
-
const
|
|
165
|
+
const _shape = editor.getShape(shape)
|
|
166
|
+
if (!_shape) return EMPTY_ARRAY
|
|
167
|
+
|
|
168
|
+
const pageTransform = editor.getShapePageTransform(shape)
|
|
169
|
+
const clipPath = editor.getShapeUtil(_shape.type).getClipPath?.(_shape)
|
|
170
|
+
|
|
171
|
+
const parentPageMaskVertices = clipPath ? pageTransform.applyToPoints(clipPath) : undefined
|
|
166
172
|
const parentPagePolygon = parentPageMaskVertices
|
|
167
173
|
? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)
|
|
168
174
|
: parentPageCorners
|
package/src/version.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This file is automatically generated by internal/scripts/refresh-assets.ts.
|
|
2
2
|
// Do not edit manually. Or do, I'm a comment, not a cop.
|
|
3
3
|
|
|
4
|
-
export const version = '3.16.0-canary.
|
|
4
|
+
export const version = '3.16.0-canary.344cec0354f3'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-09-
|
|
8
|
-
patch: '2025-09-
|
|
7
|
+
minor: '2025-09-18T14:24:07.314Z',
|
|
8
|
+
patch: '2025-09-18T14:24:07.314Z',
|
|
9
9
|
}
|