@tldraw/editor 4.1.1 → 4.2.0-canary.025846da88b7
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 +54 -6
- package/dist-cjs/index.js +2 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/MenuClickCapture.js +30 -15
- package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +11 -11
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +27 -0
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js +3 -7
- package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
- package/dist-cjs/lib/hooks/useCanvasEvents.js +2 -1
- package/dist-cjs/lib/hooks/useCanvasEvents.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 +1 -1
- package/dist-cjs/lib/license/Watermark.js.map +2 -2
- package/dist-cjs/lib/utils/debug-flags.js +1 -0
- package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
- package/dist-cjs/lib/utils/runtime.js +2 -2
- package/dist-cjs/lib/utils/runtime.js.map +2 -2
- package/dist-cjs/lib/utils/window-open.js +2 -2
- package/dist-cjs/lib/utils/window-open.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 +54 -6
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/MenuClickCapture.mjs +30 -15
- package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +11 -11
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +27 -0
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +3 -7
- package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +2 -1
- package/dist-esm/lib/hooks/useCanvasEvents.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 +1 -1
- package/dist-esm/lib/license/Watermark.mjs.map +2 -2
- package/dist-esm/lib/utils/debug-flags.mjs +1 -0
- package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
- package/dist-esm/lib/utils/runtime.mjs +2 -2
- package/dist-esm/lib/utils/runtime.mjs.map +2 -2
- package/dist-esm/lib/utils/window-open.mjs +2 -2
- package/dist-esm/lib/utils/window-open.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +10 -10
- package/src/index.ts +1 -0
- package/src/lib/components/MenuClickCapture.tsx +35 -17
- package/src/lib/components/default-components/DefaultCanvas.tsx +9 -9
- package/src/lib/editor/Editor.ts +29 -0
- package/src/lib/editor/derivations/parentsToChildren.ts +4 -10
- package/src/lib/hooks/useCanvasEvents.ts +8 -1
- package/src/lib/license/LicenseManager.ts +9 -0
- package/src/lib/license/Watermark.tsx +1 -1
- package/src/lib/utils/debug-flags.ts +5 -4
- package/src/lib/utils/runtime.ts +3 -3
- package/src/lib/utils/window-open.ts +13 -3
- package/src/version.ts +3 -3
|
@@ -3,6 +3,7 @@ import { PointerEvent, useCallback, useRef, useState } from 'react'
|
|
|
3
3
|
import { useCanvasEvents } from '../hooks/useCanvasEvents'
|
|
4
4
|
import { useEditor } from '../hooks/useEditor'
|
|
5
5
|
import { Vec } from '../primitives/Vec'
|
|
6
|
+
import { getPointerInfo } from '../utils/getPointerInfo'
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* When a menu is open, this component prevents the user from interacting with the canvas.
|
|
@@ -39,35 +40,51 @@ export function MenuClickCapture() {
|
|
|
39
40
|
isDragging: false,
|
|
40
41
|
start: new Vec(e.clientX, e.clientY),
|
|
41
42
|
}
|
|
43
|
+
rDidAPointerDownAndDragWhileMenuWasOpen.current = false
|
|
42
44
|
}
|
|
43
45
|
editor.menus.clearOpenMenus()
|
|
44
46
|
},
|
|
45
47
|
[editor]
|
|
46
48
|
)
|
|
47
49
|
|
|
50
|
+
const rDidAPointerDownAndDragWhileMenuWasOpen = useRef(false)
|
|
51
|
+
|
|
48
52
|
const handlePointerMove = useCallback(
|
|
49
53
|
(e: PointerEvent) => {
|
|
50
54
|
// Do nothing unless we're pointing
|
|
51
55
|
if (!rPointerState.current.isDown) return
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
// call the onPointerDown with the original pointer position
|
|
58
|
+
const { x, y } = rPointerState.current.start
|
|
59
|
+
|
|
60
|
+
if (!rDidAPointerDownAndDragWhileMenuWasOpen.current) {
|
|
61
|
+
if (
|
|
62
|
+
// We're pointing, but are we dragging?
|
|
63
|
+
Vec.Dist2(rPointerState.current.start, new Vec(e.clientX, e.clientY)) >
|
|
64
|
+
editor.options.dragDistanceSquared
|
|
65
|
+
) {
|
|
66
|
+
rDidAPointerDownAndDragWhileMenuWasOpen.current = true
|
|
67
|
+
// Wehaddaeventitsadrag
|
|
68
|
+
rPointerState.current = {
|
|
69
|
+
...rPointerState.current,
|
|
70
|
+
isDown: true,
|
|
71
|
+
isDragging: true,
|
|
72
|
+
}
|
|
73
|
+
canvasEvents.onPointerDown?.({
|
|
74
|
+
...e,
|
|
75
|
+
clientX: x,
|
|
76
|
+
clientY: y,
|
|
77
|
+
button: 0,
|
|
78
|
+
})
|
|
63
79
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (rDidAPointerDownAndDragWhileMenuWasOpen.current) {
|
|
83
|
+
editor.dispatch({
|
|
84
|
+
type: 'pointer',
|
|
85
|
+
target: 'canvas',
|
|
86
|
+
name: 'pointer_move',
|
|
87
|
+
...getPointerInfo(editor, e),
|
|
71
88
|
})
|
|
72
89
|
}
|
|
73
90
|
},
|
|
@@ -86,6 +103,7 @@ export function MenuClickCapture() {
|
|
|
86
103
|
isDragging: false,
|
|
87
104
|
start: new Vec(e.clientX, e.clientY),
|
|
88
105
|
}
|
|
106
|
+
rDidAPointerDownAndDragWhileMenuWasOpen.current = false
|
|
89
107
|
},
|
|
90
108
|
[canvasEvents]
|
|
91
109
|
)
|
|
@@ -172,17 +172,17 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
|
172
172
|
<LiveCollaborators />
|
|
173
173
|
</div>
|
|
174
174
|
</div>
|
|
175
|
-
<div
|
|
176
|
-
className="tl-canvas__in-front"
|
|
177
|
-
onPointerDown={editor.markEventAsHandled}
|
|
178
|
-
onPointerUp={editor.markEventAsHandled}
|
|
179
|
-
onTouchStart={editor.markEventAsHandled}
|
|
180
|
-
onTouchEnd={editor.markEventAsHandled}
|
|
181
|
-
>
|
|
182
|
-
<InFrontOfTheCanvasWrapper />
|
|
183
|
-
</div>
|
|
184
175
|
<MovingCameraHitTestBlocker />
|
|
185
176
|
</div>
|
|
177
|
+
<div
|
|
178
|
+
className="tl-canvas__in-front"
|
|
179
|
+
onPointerDown={editor.markEventAsHandled}
|
|
180
|
+
onPointerUp={editor.markEventAsHandled}
|
|
181
|
+
onTouchStart={editor.markEventAsHandled}
|
|
182
|
+
onTouchEnd={editor.markEventAsHandled}
|
|
183
|
+
>
|
|
184
|
+
<InFrontOfTheCanvasWrapper />
|
|
185
|
+
</div>
|
|
186
186
|
<MenuClickCapture />
|
|
187
187
|
</>
|
|
188
188
|
)
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -837,6 +837,35 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
837
837
|
*/
|
|
838
838
|
readonly root: StateNode
|
|
839
839
|
|
|
840
|
+
/**
|
|
841
|
+
* Set a tool. Useful if you need to add a tool to the state chart on demand,
|
|
842
|
+
* after the editor has already been initialized.
|
|
843
|
+
*
|
|
844
|
+
* @param Tool - The tool to set.
|
|
845
|
+
*
|
|
846
|
+
* @public
|
|
847
|
+
*/
|
|
848
|
+
setTool(Tool: TLStateNodeConstructor) {
|
|
849
|
+
if (hasOwnProperty(this.root.children!, Tool.id)) {
|
|
850
|
+
throw Error(`Can't override tool with id "${Tool.id}"`)
|
|
851
|
+
}
|
|
852
|
+
this.root.children![Tool.id] = new Tool(this, this.root)
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* Remove a tool. Useful if you need to remove a tool from the state chart on demand,
|
|
857
|
+
* after the editor has already been initialized.
|
|
858
|
+
*
|
|
859
|
+
* @param Tool - The tool to delete.
|
|
860
|
+
*
|
|
861
|
+
* @public
|
|
862
|
+
*/
|
|
863
|
+
removeTool(Tool: TLStateNodeConstructor) {
|
|
864
|
+
if (hasOwnProperty(this.root.children!, Tool.id)) {
|
|
865
|
+
delete this.root.children![Tool.id]
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
|
|
840
869
|
/**
|
|
841
870
|
* A set of functions to call when the app is disposed.
|
|
842
871
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Computed, computed, isUninitialized, RESET_VALUE } from '@tldraw/state'
|
|
2
2
|
import { CollectionDiff, RecordsDiff } from '@tldraw/store'
|
|
3
|
-
import { isShape, TLParentId, TLRecord,
|
|
3
|
+
import { isShape, TLParentId, TLRecord, TLShapeId, TLStore } from '@tldraw/tlschema'
|
|
4
4
|
import { compact, sortByIndex } from '@tldraw/utils'
|
|
5
5
|
|
|
6
6
|
type ParentShapeIdsToChildShapeIds = Record<TLParentId, TLShapeId[]>
|
|
@@ -11,17 +11,11 @@ function fromScratch(
|
|
|
11
11
|
) {
|
|
12
12
|
const result: ParentShapeIdsToChildShapeIds = {}
|
|
13
13
|
const shapeIds = shapeIdsQuery.get()
|
|
14
|
-
const
|
|
15
|
-
shapeIds.forEach((id) => shapes.push(store.get(id)!))
|
|
16
|
-
|
|
17
|
-
// Sort the shapes by index
|
|
18
|
-
shapes.sort(sortByIndex)
|
|
14
|
+
const sortedShapes = Array.from(shapeIds, (id) => store.get(id)!).sort(sortByIndex)
|
|
19
15
|
|
|
20
16
|
// Populate the result object with an array for each parent.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
result[shape.parentId] = []
|
|
24
|
-
}
|
|
17
|
+
sortedShapes.forEach((shape) => {
|
|
18
|
+
result[shape.parentId] ??= []
|
|
25
19
|
result[shape.parentId].push(shape.id)
|
|
26
20
|
})
|
|
27
21
|
|
|
@@ -1,6 +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 { tlenv } from '../globals/environment'
|
|
4
5
|
import { preventDefault, releasePointerCapture, setPointerCapture } from '../utils/dom'
|
|
5
6
|
import { getPointerInfo } from '../utils/getPointerInfo'
|
|
6
7
|
import { useEditor } from './useEditor'
|
|
@@ -161,8 +162,14 @@ export function useCanvasEvents() {
|
|
|
161
162
|
// For tools that benefit from a higher fidelity of events,
|
|
162
163
|
// we dispatch the coalesced events.
|
|
163
164
|
// N.B. Sometimes getCoalescedEvents isn't present on iOS, ugh.
|
|
165
|
+
// Specifically, in local mode (non-https) mode, iOS does not `useCoalescedEvents`
|
|
166
|
+
// so it appears like the ink is working locally, when really it's just that `useCoalescedEvents`
|
|
167
|
+
// is disabled. The intent here is to have `useCoalescedEvents` disabled for iOS.
|
|
164
168
|
const events =
|
|
165
|
-
|
|
169
|
+
!tlenv.isIos && currentTool.useCoalescedEvents && e.getCoalescedEvents
|
|
170
|
+
? e.getCoalescedEvents()
|
|
171
|
+
: [e]
|
|
172
|
+
|
|
166
173
|
for (const singleEvent of events) {
|
|
167
174
|
editor.dispatch({
|
|
168
175
|
type: 'pointer',
|
|
@@ -171,7 +171,16 @@ export class LicenseManager {
|
|
|
171
171
|
url.searchParams.set('license_type', trackType)
|
|
172
172
|
if ('license' in result) {
|
|
173
173
|
url.searchParams.set('license_id', result.license.id)
|
|
174
|
+
const sku = this.isFlagEnabled(result.license.flags, FLAGS.EVALUATION_LICENSE)
|
|
175
|
+
? 'evaluation'
|
|
176
|
+
: this.isFlagEnabled(result.license.flags, FLAGS.ANNUAL_LICENSE)
|
|
177
|
+
? 'annual'
|
|
178
|
+
: this.isFlagEnabled(result.license.flags, FLAGS.PERPETUAL_LICENSE)
|
|
179
|
+
? 'perpetual'
|
|
180
|
+
: 'unknown'
|
|
181
|
+
url.searchParams.set('sku', sku)
|
|
174
182
|
}
|
|
183
|
+
url.searchParams.set('url', window.location.href)
|
|
175
184
|
if (process.env.NODE_ENV) {
|
|
176
185
|
url.searchParams.set('environment', process.env.NODE_ENV)
|
|
177
186
|
}
|
|
@@ -70,7 +70,7 @@ const UnlicensedWatermark = memo(function UnlicensedWatermark({
|
|
|
70
70
|
preventDefault(e)
|
|
71
71
|
}}
|
|
72
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."
|
|
73
|
-
onClick={() => runtime.openWindow(url, '_blank')}
|
|
73
|
+
onClick={() => runtime.openWindow(url, '_blank', true)} // allow referrer
|
|
74
74
|
>
|
|
75
75
|
Get a license for production
|
|
76
76
|
</button>
|
|
@@ -92,7 +92,8 @@ if (typeof Element !== 'undefined') {
|
|
|
92
92
|
|
|
93
93
|
// --- IMPLEMENTATION ---
|
|
94
94
|
// you probably don't need to read this if you're just using the debug values system
|
|
95
|
-
|
|
95
|
+
/** @public */
|
|
96
|
+
export function createDebugValue<T>(
|
|
96
97
|
name: string,
|
|
97
98
|
{
|
|
98
99
|
defaults,
|
|
@@ -193,7 +194,7 @@ function getDefaultValue<T>(def: DebugFlagDef<T>): T {
|
|
|
193
194
|
}
|
|
194
195
|
}
|
|
195
196
|
|
|
196
|
-
/** @
|
|
197
|
+
/** @public */
|
|
197
198
|
export interface DebugFlagDefaults<T> {
|
|
198
199
|
development?: T
|
|
199
200
|
staging?: T
|
|
@@ -201,14 +202,14 @@ export interface DebugFlagDefaults<T> {
|
|
|
201
202
|
all: T
|
|
202
203
|
}
|
|
203
204
|
|
|
204
|
-
/** @
|
|
205
|
+
/** @public */
|
|
205
206
|
export interface DebugFlagDef<T> {
|
|
206
207
|
name: string
|
|
207
208
|
defaults: DebugFlagDefaults<T>
|
|
208
209
|
shouldStoreForSession: boolean
|
|
209
210
|
}
|
|
210
211
|
|
|
211
|
-
/** @
|
|
212
|
+
/** @public */
|
|
212
213
|
export interface DebugFlag<T> extends DebugFlagDef<T>, Atom<T> {
|
|
213
214
|
reset(): void
|
|
214
215
|
}
|
package/src/lib/utils/runtime.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/** @public */
|
|
2
2
|
export const runtime: {
|
|
3
|
-
openWindow(url: string, target: string): void
|
|
3
|
+
openWindow(url: string, target: string, allowReferrer?: boolean): void
|
|
4
4
|
refreshPage(): void
|
|
5
5
|
hardReset(): void
|
|
6
6
|
} = {
|
|
7
|
-
openWindow(url, target) {
|
|
8
|
-
window.open(url, target, 'noopener noreferrer')
|
|
7
|
+
openWindow(url, target, allowReferrer = false) {
|
|
8
|
+
return window.open(url, target, allowReferrer ? 'noopener' : 'noopener noreferrer')
|
|
9
9
|
},
|
|
10
10
|
refreshPage() {
|
|
11
11
|
window.location.reload()
|
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { runtime } from './runtime'
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Open a new window with the given URL and target. Prefer this to the window.open function, as it
|
|
5
|
+
* will work more reliably in embedded scenarios, such as our VS Code extension. See the runtime
|
|
6
|
+
* object in tldraw/editor for more details.
|
|
7
|
+
*
|
|
8
|
+
* @param url - The URL to open.
|
|
9
|
+
* @param target - The target window to open the URL in.
|
|
10
|
+
* @param allowReferrer - Whether to allow the referrer to be sent to the new window.
|
|
11
|
+
* @returns The new window object.
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
export function openWindow(url: string, target = '_blank', allowReferrer?: boolean) {
|
|
15
|
+
return runtime.openWindow(url, target, allowReferrer)
|
|
6
16
|
}
|
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 = '4.
|
|
4
|
+
export const version = '4.2.0-canary.025846da88b7'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2025-09-18T14:39:22.803Z',
|
|
7
|
-
minor: '2025-10-
|
|
8
|
-
patch: '2025-10-
|
|
7
|
+
minor: '2025-10-28T15:00:53.668Z',
|
|
8
|
+
patch: '2025-10-28T15:00:53.668Z',
|
|
9
9
|
}
|