tldraw 4.1.1 → 4.2.0-next.d76c345101d5
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 +15 -11
- package/dist-cjs/index.js +3 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/defaultEmbedDefinitions.js +2 -25
- package/dist-cjs/lib/defaultEmbedDefinitions.js.map +2 -2
- package/dist-cjs/lib/defaultExternalContentHandlers.js +8 -31
- package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +31 -101
- package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js +138 -0
- package/dist-cjs/lib/shapes/bookmark/bookmarks.js.map +7 -0
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +25 -3
- package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Cropping.js +20 -4
- package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Cropping.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.js +23 -11
- package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +18 -5
- package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js +21 -9
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingResizeHandle.js +24 -8
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingResizeHandle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingRotateHandle.js +21 -9
- package/dist-cjs/lib/tools/SelectTool/childStates/PointingRotateHandle.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +23 -8
- package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js +21 -9
- package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js.map +2 -2
- package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js +26 -11
- package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
- package/dist-cjs/lib/ui/components/DebugMenu/DefaultDebugMenuContent.js +2 -2
- package/dist-cjs/lib/ui/components/DebugMenu/DefaultDebugMenuContent.js.map +1 -1
- package/dist-cjs/lib/ui/components/menu-items.js +2 -2
- package/dist-cjs/lib/ui/components/menu-items.js.map +1 -1
- package/dist-cjs/lib/ui/context/actions.js +23 -29
- package/dist-cjs/lib/ui/context/actions.js.map +2 -2
- package/dist-cjs/lib/ui/hooks/useEditorEvents.js +1 -1
- package/dist-cjs/lib/ui/hooks/useEditorEvents.js.map +1 -1
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +4 -4
- package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +1 -1
- package/dist-cjs/lib/ui/version.js +3 -3
- package/dist-cjs/lib/ui/version.js.map +1 -1
- package/dist-esm/index.d.mts +15 -11
- package/dist-esm/index.mjs +3 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/defaultEmbedDefinitions.mjs +2 -25
- package/dist-esm/lib/defaultEmbedDefinitions.mjs.map +2 -2
- package/dist-esm/lib/defaultExternalContentHandlers.mjs +8 -31
- package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +34 -101
- package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs +124 -0
- package/dist-esm/lib/shapes/bookmark/bookmarks.mjs.map +7 -0
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +26 -3
- package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Cropping.mjs +20 -4
- package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Cropping.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.mjs +23 -11
- package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +18 -5
- package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs +21 -9
- package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingResizeHandle.mjs +24 -8
- package/dist-esm/lib/tools/SelectTool/childStates/PointingResizeHandle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/PointingRotateHandle.mjs +21 -9
- package/dist-esm/lib/tools/SelectTool/childStates/PointingRotateHandle.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +23 -8
- package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs +21 -9
- package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs.map +2 -2
- package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs +26 -11
- package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
- package/dist-esm/lib/ui/components/DebugMenu/DefaultDebugMenuContent.mjs +2 -2
- package/dist-esm/lib/ui/components/DebugMenu/DefaultDebugMenuContent.mjs.map +1 -1
- package/dist-esm/lib/ui/components/menu-items.mjs +2 -2
- package/dist-esm/lib/ui/components/menu-items.mjs.map +1 -1
- package/dist-esm/lib/ui/context/actions.mjs +23 -29
- package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
- package/dist-esm/lib/ui/hooks/useEditorEvents.mjs +1 -1
- package/dist-esm/lib/ui/hooks/useEditorEvents.mjs.map +1 -1
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +4 -4
- package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +1 -1
- package/dist-esm/lib/ui/version.mjs +3 -3
- package/dist-esm/lib/ui/version.mjs.map +1 -1
- package/package.json +3 -3
- package/src/index.ts +1 -0
- package/src/lib/defaultEmbedDefinitions.ts +2 -25
- package/src/lib/defaultExternalContentHandlers.ts +10 -35
- package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +39 -133
- package/src/lib/shapes/bookmark/bookmarks.ts +170 -0
- package/src/lib/shapes/embed/EmbedShapeUtil.tsx +28 -2
- package/src/lib/tools/SelectTool/childStates/Crop/children/Cropping.ts +23 -6
- package/src/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.ts +24 -12
- package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +21 -10
- package/src/lib/tools/SelectTool/childStates/PointingArrowLabel.ts +23 -11
- package/src/lib/tools/SelectTool/childStates/PointingResizeHandle.ts +26 -9
- package/src/lib/tools/SelectTool/childStates/PointingRotateHandle.ts +23 -10
- package/src/lib/tools/SelectTool/childStates/Resizing.ts +24 -9
- package/src/lib/tools/SelectTool/childStates/Rotating.ts +27 -11
- package/src/lib/tools/SelectTool/childStates/Translating.ts +28 -12
- package/src/lib/ui/components/DebugMenu/DefaultDebugMenuContent.tsx +2 -2
- package/src/lib/ui/components/menu-items.tsx +2 -2
- package/src/lib/ui/context/actions.tsx +27 -31
- package/src/lib/ui/hooks/useEditorEvents.ts +1 -1
- package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +4 -4
- package/src/lib/ui/version.ts +3 -3
- package/src/lib/utils/embeds/embeds.test.ts +16 -34
- package/src/test/SelectTool.test.ts +251 -0
- package/src/test/bookmark-shapes.test.ts +129 -7
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AssetRecordType,
|
|
3
|
+
Editor,
|
|
4
|
+
Result,
|
|
5
|
+
TLAssetId,
|
|
6
|
+
TLBookmarkAsset,
|
|
7
|
+
TLBookmarkShape,
|
|
8
|
+
TLShapePartial,
|
|
9
|
+
createShapeId,
|
|
10
|
+
debounce,
|
|
11
|
+
getHashForString,
|
|
12
|
+
} from '@tldraw/editor'
|
|
13
|
+
|
|
14
|
+
export const BOOKMARK_WIDTH = 300
|
|
15
|
+
export const BOOKMARK_HEIGHT = 320
|
|
16
|
+
export const BOOKMARK_JUST_URL_HEIGHT = 46
|
|
17
|
+
const SHORT_BOOKMARK_HEIGHT = 101
|
|
18
|
+
|
|
19
|
+
export function getBookmarkHeight(editor: Editor, assetId?: TLAssetId | null) {
|
|
20
|
+
const asset = (assetId ? editor.getAsset(assetId) : null) as TLBookmarkAsset | null
|
|
21
|
+
|
|
22
|
+
if (asset) {
|
|
23
|
+
if (!asset.props.image) {
|
|
24
|
+
if (!asset.props.title) {
|
|
25
|
+
return BOOKMARK_JUST_URL_HEIGHT
|
|
26
|
+
} else {
|
|
27
|
+
return SHORT_BOOKMARK_HEIGHT
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return BOOKMARK_HEIGHT
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function setBookmarkHeight(editor: Editor, shape: TLBookmarkShape) {
|
|
36
|
+
return {
|
|
37
|
+
...shape,
|
|
38
|
+
props: { ...shape.props, h: getBookmarkHeight(editor, shape.props.assetId) },
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** @internal */
|
|
43
|
+
export const getHumanReadableAddress = (url: string) => {
|
|
44
|
+
try {
|
|
45
|
+
const objUrl = new URL(url)
|
|
46
|
+
// we want the hostname without any www
|
|
47
|
+
return objUrl.hostname.replace(/^www\./, '')
|
|
48
|
+
} catch {
|
|
49
|
+
return url
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function updateBookmarkAssetOnUrlChange(editor: Editor, shape: TLBookmarkShape) {
|
|
54
|
+
const { url } = shape.props
|
|
55
|
+
|
|
56
|
+
// Derive the asset id from the URL
|
|
57
|
+
const assetId: TLAssetId = AssetRecordType.createId(getHashForString(url))
|
|
58
|
+
|
|
59
|
+
if (editor.getAsset(assetId)) {
|
|
60
|
+
// Existing asset for this URL?
|
|
61
|
+
if (shape.props.assetId !== assetId) {
|
|
62
|
+
editor.updateShapes<TLBookmarkShape>([
|
|
63
|
+
{
|
|
64
|
+
id: shape.id,
|
|
65
|
+
type: shape.type,
|
|
66
|
+
props: { assetId },
|
|
67
|
+
},
|
|
68
|
+
])
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
// No asset for this URL?
|
|
72
|
+
|
|
73
|
+
// First, clear out the existing asset reference
|
|
74
|
+
editor.updateShapes<TLBookmarkShape>([
|
|
75
|
+
{
|
|
76
|
+
id: shape.id,
|
|
77
|
+
type: shape.type,
|
|
78
|
+
props: { assetId: null },
|
|
79
|
+
},
|
|
80
|
+
])
|
|
81
|
+
|
|
82
|
+
// Then try to asyncronously create a new one
|
|
83
|
+
createBookmarkAssetOnUrlChange(editor, shape)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const createBookmarkAssetOnUrlChange = debounce(async (editor: Editor, shape: TLBookmarkShape) => {
|
|
88
|
+
if (editor.isDisposed) return
|
|
89
|
+
|
|
90
|
+
const { url } = shape.props
|
|
91
|
+
|
|
92
|
+
// Create the asset using the external content manager's createAssetFromUrl method.
|
|
93
|
+
// This may be overwritten by the user (for example, we overwrite it on tldraw.com)
|
|
94
|
+
const asset = await editor.getAssetForExternalContent({ type: 'url', url })
|
|
95
|
+
|
|
96
|
+
if (!asset) {
|
|
97
|
+
// No asset? Just leave the bookmark as a null assetId.
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
editor.run(() => {
|
|
102
|
+
// Create the new asset
|
|
103
|
+
editor.createAssets([asset])
|
|
104
|
+
|
|
105
|
+
// And update the shape
|
|
106
|
+
editor.updateShapes<TLBookmarkShape>([
|
|
107
|
+
{
|
|
108
|
+
id: shape.id,
|
|
109
|
+
type: shape.type,
|
|
110
|
+
props: { assetId: asset.id },
|
|
111
|
+
},
|
|
112
|
+
])
|
|
113
|
+
})
|
|
114
|
+
}, 500)
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Creates a bookmark shape from a URL with unfurled metadata.
|
|
118
|
+
*
|
|
119
|
+
* @returns A Result containing the created bookmark shape or an error
|
|
120
|
+
* @public
|
|
121
|
+
*/
|
|
122
|
+
|
|
123
|
+
export async function createBookmarkFromUrl(
|
|
124
|
+
editor: Editor,
|
|
125
|
+
{
|
|
126
|
+
url,
|
|
127
|
+
center = editor.getViewportPageBounds().center,
|
|
128
|
+
}: {
|
|
129
|
+
url: string
|
|
130
|
+
center?: { x: number; y: number }
|
|
131
|
+
}
|
|
132
|
+
): Promise<Result<TLBookmarkShape, string>> {
|
|
133
|
+
try {
|
|
134
|
+
// Create the bookmark asset with unfurled metadata
|
|
135
|
+
const asset = await editor.getAssetForExternalContent({ type: 'url', url })
|
|
136
|
+
|
|
137
|
+
// Create the bookmark shape
|
|
138
|
+
const shapeId = createShapeId()
|
|
139
|
+
const shapePartial: TLShapePartial<TLBookmarkShape> = {
|
|
140
|
+
id: shapeId,
|
|
141
|
+
type: 'bookmark',
|
|
142
|
+
x: center.x - BOOKMARK_WIDTH / 2,
|
|
143
|
+
y: center.y - BOOKMARK_HEIGHT / 2,
|
|
144
|
+
rotation: 0,
|
|
145
|
+
opacity: 1,
|
|
146
|
+
props: {
|
|
147
|
+
url,
|
|
148
|
+
assetId: asset?.id || null,
|
|
149
|
+
w: BOOKMARK_WIDTH,
|
|
150
|
+
h: getBookmarkHeight(editor, asset?.id),
|
|
151
|
+
},
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
editor.run(() => {
|
|
155
|
+
// Create the asset if we have one
|
|
156
|
+
if (asset) {
|
|
157
|
+
editor.createAssets([asset])
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Create the shape
|
|
161
|
+
editor.createShapes([shapePartial])
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
// Get the created shape
|
|
165
|
+
const createdShape = editor.getShape(shapeId) as TLBookmarkShape
|
|
166
|
+
return Result.ok(createdShape)
|
|
167
|
+
} catch (error) {
|
|
168
|
+
return Result.err(error instanceof Error ? error.message : 'Failed to create bookmark')
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import {
|
|
4
4
|
BaseBoxShapeUtil,
|
|
5
5
|
HTMLContainer,
|
|
6
|
+
Rectangle2d,
|
|
6
7
|
TLEmbedShape,
|
|
7
8
|
TLEmbedShapeProps,
|
|
8
9
|
TLResizeInfo,
|
|
@@ -24,6 +25,8 @@ import {
|
|
|
24
25
|
embedShapePermissionDefaults,
|
|
25
26
|
} from '../../defaultEmbedDefinitions'
|
|
26
27
|
import { TLEmbedResult, getEmbedInfo } from '../../utils/embeds/embeds'
|
|
28
|
+
import { BookmarkIndicatorComponent, BookmarkShapeComponent } from '../bookmark/BookmarkShapeUtil'
|
|
29
|
+
import { BOOKMARK_JUST_URL_HEIGHT, BOOKMARK_WIDTH } from '../bookmark/bookmarks'
|
|
27
30
|
import { getRotatedBoxShadow } from '../shared/rotated-box-shadow'
|
|
28
31
|
|
|
29
32
|
const getSandboxPermissions = (permissions: TLEmbedShapePermissions) => {
|
|
@@ -82,6 +85,18 @@ export class EmbedShapeUtil extends BaseBoxShapeUtil<TLEmbedShape> {
|
|
|
82
85
|
}
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
override getGeometry(shape: TLEmbedShape) {
|
|
89
|
+
const embedInfo = this.getEmbedDefinition(shape.props.url)
|
|
90
|
+
if (!embedInfo?.definition) {
|
|
91
|
+
return new Rectangle2d({
|
|
92
|
+
width: BOOKMARK_WIDTH,
|
|
93
|
+
height: BOOKMARK_JUST_URL_HEIGHT,
|
|
94
|
+
isFilled: true,
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
return super.getGeometry(shape)
|
|
98
|
+
}
|
|
99
|
+
|
|
85
100
|
override isAspectRatioLocked(shape: TLEmbedShape) {
|
|
86
101
|
const embedInfo = this.getEmbedDefinition(shape.props.url)
|
|
87
102
|
return embedInfo?.definition.isAspectRatioLocked ?? false
|
|
@@ -206,20 +221,31 @@ export class EmbedShapeUtil extends BaseBoxShapeUtil<TLEmbedShape> {
|
|
|
206
221
|
background: embedInfo?.definition.backgroundColor,
|
|
207
222
|
}}
|
|
208
223
|
/>
|
|
209
|
-
) :
|
|
224
|
+
) : (
|
|
225
|
+
<BookmarkShapeComponent
|
|
226
|
+
url={url}
|
|
227
|
+
h={h}
|
|
228
|
+
rotation={pageRotation}
|
|
229
|
+
assetId={null}
|
|
230
|
+
showImageContainer={false}
|
|
231
|
+
/>
|
|
232
|
+
)}
|
|
210
233
|
</HTMLContainer>
|
|
211
234
|
)
|
|
212
235
|
}
|
|
213
236
|
|
|
214
237
|
override indicator(shape: TLEmbedShape) {
|
|
215
238
|
const embedInfo = this.getEmbedDefinition(shape.props.url)
|
|
216
|
-
|
|
239
|
+
|
|
240
|
+
return embedInfo?.definition ? (
|
|
217
241
|
<rect
|
|
218
242
|
width={toDomPrecision(shape.props.w)}
|
|
219
243
|
height={toDomPrecision(shape.props.h)}
|
|
220
244
|
rx={embedInfo?.definition.overrideOutlineRadius ?? 8}
|
|
221
245
|
ry={embedInfo?.definition.overrideOutlineRadius ?? 8}
|
|
222
246
|
/>
|
|
247
|
+
) : (
|
|
248
|
+
<BookmarkIndicatorComponent w={BOOKMARK_WIDTH} h={BOOKMARK_JUST_URL_HEIGHT} />
|
|
223
249
|
)
|
|
224
250
|
}
|
|
225
251
|
override getInterpolatedProps(
|
|
@@ -17,7 +17,7 @@ export class Cropping extends StateNode {
|
|
|
17
17
|
info = {} as TLPointerEventInfo & {
|
|
18
18
|
target: 'selection'
|
|
19
19
|
handle: SelectionHandle
|
|
20
|
-
onInteractionEnd?: string
|
|
20
|
+
onInteractionEnd?: string | (() => void)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
markId = ''
|
|
@@ -28,10 +28,13 @@ export class Cropping extends StateNode {
|
|
|
28
28
|
info: TLPointerEventInfo & {
|
|
29
29
|
target: 'selection'
|
|
30
30
|
handle: SelectionHandle
|
|
31
|
-
onInteractionEnd?: string
|
|
31
|
+
onInteractionEnd?: string | (() => void)
|
|
32
32
|
}
|
|
33
33
|
) {
|
|
34
34
|
this.info = info
|
|
35
|
+
if (typeof info.onInteractionEnd === 'string') {
|
|
36
|
+
this.parent.setCurrentToolIdMask(info.onInteractionEnd)
|
|
37
|
+
}
|
|
35
38
|
this.markId = this.editor.markHistoryStoppingPoint('cropping')
|
|
36
39
|
this.snapshot = this.createSnapshot()
|
|
37
40
|
this.updateShapes()
|
|
@@ -61,6 +64,10 @@ export class Cropping extends StateNode {
|
|
|
61
64
|
this.cancel()
|
|
62
65
|
}
|
|
63
66
|
|
|
67
|
+
override onExit() {
|
|
68
|
+
this.parent.setCurrentToolIdMask(undefined)
|
|
69
|
+
}
|
|
70
|
+
|
|
64
71
|
private updateCursor() {
|
|
65
72
|
const selectedShape = this.editor.getSelectedShapes()[0]
|
|
66
73
|
if (!selectedShape) return
|
|
@@ -108,8 +115,13 @@ export class Cropping extends StateNode {
|
|
|
108
115
|
private complete() {
|
|
109
116
|
this.updateShapes()
|
|
110
117
|
kickoutOccludedShapes(this.editor, [this.snapshot.shape.id])
|
|
111
|
-
|
|
112
|
-
|
|
118
|
+
const { onInteractionEnd } = this.info
|
|
119
|
+
if (onInteractionEnd) {
|
|
120
|
+
if (typeof onInteractionEnd === 'string') {
|
|
121
|
+
this.editor.setCurrentTool(onInteractionEnd, this.info)
|
|
122
|
+
} else {
|
|
123
|
+
onInteractionEnd()
|
|
124
|
+
}
|
|
113
125
|
} else {
|
|
114
126
|
this.editor.setCroppingShape(null)
|
|
115
127
|
this.editor.setCurrentTool('select.idle')
|
|
@@ -118,8 +130,13 @@ export class Cropping extends StateNode {
|
|
|
118
130
|
|
|
119
131
|
private cancel() {
|
|
120
132
|
this.editor.bailToMark(this.markId)
|
|
121
|
-
|
|
122
|
-
|
|
133
|
+
const { onInteractionEnd } = this.info
|
|
134
|
+
if (onInteractionEnd) {
|
|
135
|
+
if (typeof onInteractionEnd === 'string') {
|
|
136
|
+
this.editor.setCurrentTool(onInteractionEnd, this.info)
|
|
137
|
+
} else {
|
|
138
|
+
onInteractionEnd()
|
|
139
|
+
}
|
|
123
140
|
} else {
|
|
124
141
|
this.editor.setCroppingShape(null)
|
|
125
142
|
this.editor.setCurrentTool('select.idle')
|
|
@@ -4,7 +4,7 @@ import { CursorTypeMap } from '../../PointingResizeHandle'
|
|
|
4
4
|
type TLPointingCropHandleInfo = TLPointerEventInfo & {
|
|
5
5
|
target: 'selection'
|
|
6
6
|
} & {
|
|
7
|
-
onInteractionEnd?: string
|
|
7
|
+
onInteractionEnd?: string | (() => void)
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export class PointingCropHandle extends StateNode {
|
|
@@ -14,7 +14,9 @@ export class PointingCropHandle extends StateNode {
|
|
|
14
14
|
|
|
15
15
|
override onEnter(info: TLPointingCropHandleInfo) {
|
|
16
16
|
this.info = info
|
|
17
|
-
|
|
17
|
+
if (typeof info.onInteractionEnd === 'string') {
|
|
18
|
+
this.parent.setCurrentToolIdMask(info.onInteractionEnd)
|
|
19
|
+
}
|
|
18
20
|
const selectedShape = this.editor.getSelectedShapes()[0]
|
|
19
21
|
if (!selectedShape) return
|
|
20
22
|
|
|
@@ -47,12 +49,17 @@ export class PointingCropHandle extends StateNode {
|
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
override onPointerUp() {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
const { onInteractionEnd } = this.info
|
|
53
|
+
if (onInteractionEnd) {
|
|
54
|
+
if (typeof onInteractionEnd === 'string') {
|
|
55
|
+
this.editor.setCurrentTool(onInteractionEnd, this.info)
|
|
56
|
+
} else {
|
|
57
|
+
onInteractionEnd()
|
|
58
|
+
}
|
|
59
|
+
return
|
|
55
60
|
}
|
|
61
|
+
this.editor.setCroppingShape(null)
|
|
62
|
+
this.editor.setCurrentTool('select.idle')
|
|
56
63
|
}
|
|
57
64
|
|
|
58
65
|
override onCancel() {
|
|
@@ -68,11 +75,16 @@ export class PointingCropHandle extends StateNode {
|
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
private cancel() {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
const { onInteractionEnd } = this.info
|
|
79
|
+
if (onInteractionEnd) {
|
|
80
|
+
if (typeof onInteractionEnd === 'string') {
|
|
81
|
+
this.editor.setCurrentTool(onInteractionEnd, this.info)
|
|
82
|
+
} else {
|
|
83
|
+
onInteractionEnd()
|
|
84
|
+
}
|
|
85
|
+
return
|
|
76
86
|
}
|
|
87
|
+
this.editor.setCroppingShape(null)
|
|
88
|
+
this.editor.setCurrentTool('select.idle')
|
|
77
89
|
}
|
|
78
90
|
}
|
|
@@ -21,7 +21,7 @@ import { getArrowBindings } from '../../../shapes/arrow/shared'
|
|
|
21
21
|
export type DraggingHandleInfo = TLPointerEventInfo & {
|
|
22
22
|
shape: TLArrowShape | TLLineShape
|
|
23
23
|
target: 'handle'
|
|
24
|
-
onInteractionEnd?: string
|
|
24
|
+
onInteractionEnd?: string | (() => void)
|
|
25
25
|
isCreating?: boolean
|
|
26
26
|
creatingMarkId?: string
|
|
27
27
|
}
|
|
@@ -47,7 +47,9 @@ export class DraggingHandle extends StateNode {
|
|
|
47
47
|
override onEnter(info: DraggingHandleInfo) {
|
|
48
48
|
const { shape, isCreating, creatingMarkId, handle } = info
|
|
49
49
|
this.info = info
|
|
50
|
-
|
|
50
|
+
if (typeof info.onInteractionEnd === 'string') {
|
|
51
|
+
this.parent.setCurrentToolIdMask(info.onInteractionEnd)
|
|
52
|
+
}
|
|
51
53
|
this.shapeId = shape.id
|
|
52
54
|
this.markId = ''
|
|
53
55
|
|
|
@@ -220,11 +222,17 @@ export class DraggingHandle extends StateNode {
|
|
|
220
222
|
}
|
|
221
223
|
|
|
222
224
|
const { onInteractionEnd } = this.info
|
|
223
|
-
if (
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
225
|
+
if (onInteractionEnd) {
|
|
226
|
+
if (typeof onInteractionEnd === 'string') {
|
|
227
|
+
if (this.editor.getInstanceState().isToolLocked && onInteractionEnd) {
|
|
228
|
+
// Return to the tool that was active before this one but only if tool lock is turned on!
|
|
229
|
+
this.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })
|
|
230
|
+
return
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
onInteractionEnd?.()
|
|
234
|
+
return
|
|
235
|
+
}
|
|
228
236
|
}
|
|
229
237
|
|
|
230
238
|
this.parent.transition('idle')
|
|
@@ -249,9 +257,12 @@ export class DraggingHandle extends StateNode {
|
|
|
249
257
|
|
|
250
258
|
const { onInteractionEnd } = this.info
|
|
251
259
|
if (onInteractionEnd) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
260
|
+
if (typeof onInteractionEnd === 'string') {
|
|
261
|
+
// Return to the tool that was active before this one, whether tool lock is turned on or not!
|
|
262
|
+
this.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })
|
|
263
|
+
} else {
|
|
264
|
+
onInteractionEnd?.()
|
|
265
|
+
}
|
|
255
266
|
return
|
|
256
267
|
}
|
|
257
268
|
|
|
@@ -23,7 +23,7 @@ export class PointingArrowLabel extends StateNode {
|
|
|
23
23
|
|
|
24
24
|
private info = {} as TLPointerEventInfo & {
|
|
25
25
|
shape: TLArrowShape
|
|
26
|
-
onInteractionEnd?: string
|
|
26
|
+
onInteractionEnd?: string | (() => void)
|
|
27
27
|
isCreating: boolean
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -34,12 +34,14 @@ export class PointingArrowLabel extends StateNode {
|
|
|
34
34
|
override onEnter(
|
|
35
35
|
info: TLPointerEventInfo & {
|
|
36
36
|
shape: TLArrowShape
|
|
37
|
-
onInteractionEnd?: string
|
|
37
|
+
onInteractionEnd?: string | (() => void)
|
|
38
38
|
isCreating: boolean
|
|
39
39
|
}
|
|
40
40
|
) {
|
|
41
41
|
const { shape } = info
|
|
42
|
-
|
|
42
|
+
if (typeof info.onInteractionEnd === 'string') {
|
|
43
|
+
this.parent.setCurrentToolIdMask(info.onInteractionEnd)
|
|
44
|
+
}
|
|
43
45
|
this.info = info
|
|
44
46
|
this.shapeId = shape.id
|
|
45
47
|
this.didDrag = false
|
|
@@ -155,20 +157,30 @@ export class PointingArrowLabel extends StateNode {
|
|
|
155
157
|
}
|
|
156
158
|
|
|
157
159
|
private complete() {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
const { onInteractionEnd } = this.info
|
|
161
|
+
if (onInteractionEnd) {
|
|
162
|
+
if (typeof onInteractionEnd === 'string') {
|
|
163
|
+
this.editor.setCurrentTool(onInteractionEnd, {})
|
|
164
|
+
} else {
|
|
165
|
+
onInteractionEnd()
|
|
166
|
+
}
|
|
167
|
+
return
|
|
162
168
|
}
|
|
169
|
+
this.parent.transition('idle')
|
|
163
170
|
}
|
|
164
171
|
|
|
165
172
|
private cancel() {
|
|
166
173
|
this.editor.bailToMark(this.markId)
|
|
167
174
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
175
|
+
const { onInteractionEnd } = this.info
|
|
176
|
+
if (onInteractionEnd) {
|
|
177
|
+
if (typeof onInteractionEnd === 'string') {
|
|
178
|
+
this.editor.setCurrentTool(onInteractionEnd, {})
|
|
179
|
+
} else {
|
|
180
|
+
onInteractionEnd()
|
|
181
|
+
}
|
|
182
|
+
return
|
|
172
183
|
}
|
|
184
|
+
this.parent.transition('idle')
|
|
173
185
|
}
|
|
174
186
|
}
|
|
@@ -17,7 +17,7 @@ export const CursorTypeMap: Record<TLSelectionHandle, TLCursorType> = {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
type PointingResizeHandleInfo = Extract<TLPointerEventInfo, { target: 'selection' }> & {
|
|
20
|
-
onInteractionEnd?: string
|
|
20
|
+
onInteractionEnd?: string | (() => void)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export class PointingResizeHandle extends StateNode {
|
|
@@ -36,9 +36,16 @@ export class PointingResizeHandle extends StateNode {
|
|
|
36
36
|
|
|
37
37
|
override onEnter(info: PointingResizeHandleInfo) {
|
|
38
38
|
this.info = info
|
|
39
|
+
if (typeof info.onInteractionEnd === 'string') {
|
|
40
|
+
this.parent.setCurrentToolIdMask(info.onInteractionEnd)
|
|
41
|
+
}
|
|
39
42
|
this.updateCursor()
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
override onExit() {
|
|
46
|
+
this.parent.setCurrentToolIdMask(undefined)
|
|
47
|
+
}
|
|
48
|
+
|
|
42
49
|
override onPointerMove() {
|
|
43
50
|
if (this.editor.inputs.isDragging) {
|
|
44
51
|
this.startResizing()
|
|
@@ -71,18 +78,28 @@ export class PointingResizeHandle extends StateNode {
|
|
|
71
78
|
}
|
|
72
79
|
|
|
73
80
|
private complete() {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
const { onInteractionEnd } = this.info
|
|
82
|
+
if (onInteractionEnd) {
|
|
83
|
+
if (typeof onInteractionEnd === 'string') {
|
|
84
|
+
this.editor.setCurrentTool(onInteractionEnd, {})
|
|
85
|
+
} else {
|
|
86
|
+
onInteractionEnd()
|
|
87
|
+
}
|
|
88
|
+
return
|
|
78
89
|
}
|
|
90
|
+
this.parent.transition('idle')
|
|
79
91
|
}
|
|
80
92
|
|
|
81
93
|
private cancel() {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
94
|
+
const { onInteractionEnd } = this.info
|
|
95
|
+
if (onInteractionEnd) {
|
|
96
|
+
if (typeof onInteractionEnd === 'string') {
|
|
97
|
+
this.editor.setCurrentTool(onInteractionEnd, {})
|
|
98
|
+
} else {
|
|
99
|
+
onInteractionEnd()
|
|
100
|
+
}
|
|
101
|
+
return
|
|
86
102
|
}
|
|
103
|
+
this.parent.transition('idle')
|
|
87
104
|
}
|
|
88
105
|
}
|
|
@@ -2,7 +2,7 @@ import { RotateCorner, StateNode, TLPointerEventInfo } from '@tldraw/editor'
|
|
|
2
2
|
import { CursorTypeMap } from './PointingResizeHandle'
|
|
3
3
|
|
|
4
4
|
type PointingRotateHandleInfo = Extract<TLPointerEventInfo, { target: 'selection' }> & {
|
|
5
|
-
onInteractionEnd?: string
|
|
5
|
+
onInteractionEnd?: string | (() => void)
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export class PointingRotateHandle extends StateNode {
|
|
@@ -18,8 +18,10 @@ export class PointingRotateHandle extends StateNode {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
override onEnter(info: PointingRotateHandleInfo) {
|
|
21
|
-
this.parent.setCurrentToolIdMask(info.onInteractionEnd)
|
|
22
21
|
this.info = info
|
|
22
|
+
if (typeof info.onInteractionEnd === 'string') {
|
|
23
|
+
this.parent.setCurrentToolIdMask(info.onInteractionEnd)
|
|
24
|
+
}
|
|
23
25
|
this.updateCursor()
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -60,18 +62,29 @@ export class PointingRotateHandle extends StateNode {
|
|
|
60
62
|
}
|
|
61
63
|
|
|
62
64
|
private complete() {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
const { onInteractionEnd } = this.info
|
|
66
|
+
if (onInteractionEnd) {
|
|
67
|
+
if (typeof onInteractionEnd === 'string') {
|
|
68
|
+
// Return to the tool that was active before this one, whether tool lock is turned on or not!
|
|
69
|
+
this.editor.setCurrentTool(onInteractionEnd, {})
|
|
70
|
+
} else {
|
|
71
|
+
onInteractionEnd?.()
|
|
72
|
+
}
|
|
73
|
+
return
|
|
67
74
|
}
|
|
75
|
+
this.parent.transition('idle')
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
private cancel() {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
79
|
+
const { onInteractionEnd } = this.info
|
|
80
|
+
if (onInteractionEnd) {
|
|
81
|
+
if (typeof onInteractionEnd === 'string') {
|
|
82
|
+
this.editor.setCurrentTool(onInteractionEnd, {})
|
|
83
|
+
} else {
|
|
84
|
+
onInteractionEnd()
|
|
85
|
+
}
|
|
86
|
+
return
|
|
75
87
|
}
|
|
88
|
+
this.parent.transition('idle')
|
|
76
89
|
}
|
|
77
90
|
}
|
|
@@ -29,7 +29,7 @@ export type ResizingInfo = TLPointerEventInfo & {
|
|
|
29
29
|
creatingMarkId?: string
|
|
30
30
|
onCreate?(shape: TLShape | null): void
|
|
31
31
|
creationCursorOffset?: VecLike
|
|
32
|
-
onInteractionEnd?: string
|
|
32
|
+
onInteractionEnd?: string | (() => void)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export class Resizing extends StateNode {
|
|
@@ -55,7 +55,9 @@ export class Resizing extends StateNode {
|
|
|
55
55
|
this.info = info
|
|
56
56
|
this.didHoldCommand = false
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
if (typeof info.onInteractionEnd === 'string') {
|
|
59
|
+
this.parent.setCurrentToolIdMask(info.onInteractionEnd)
|
|
60
|
+
}
|
|
59
61
|
this.creationCursorOffset = creationCursorOffset
|
|
60
62
|
|
|
61
63
|
try {
|
|
@@ -135,11 +137,16 @@ export class Resizing extends StateNode {
|
|
|
135
137
|
|
|
136
138
|
this.editor.bailToMark(this.markId)
|
|
137
139
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
const { onInteractionEnd } = this.info
|
|
141
|
+
if (onInteractionEnd) {
|
|
142
|
+
if (typeof onInteractionEnd === 'string') {
|
|
143
|
+
this.editor.setCurrentTool(onInteractionEnd, {})
|
|
144
|
+
} else {
|
|
145
|
+
onInteractionEnd()
|
|
146
|
+
}
|
|
147
|
+
return
|
|
142
148
|
}
|
|
149
|
+
this.parent.transition('idle')
|
|
143
150
|
}
|
|
144
151
|
|
|
145
152
|
private complete() {
|
|
@@ -152,9 +159,17 @@ export class Resizing extends StateNode {
|
|
|
152
159
|
return
|
|
153
160
|
}
|
|
154
161
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
const { onInteractionEnd } = this.info
|
|
163
|
+
if (onInteractionEnd) {
|
|
164
|
+
if (typeof onInteractionEnd === 'string') {
|
|
165
|
+
if (this.editor.getInstanceState().isToolLocked) {
|
|
166
|
+
this.editor.setCurrentTool(onInteractionEnd, {})
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
} else {
|
|
170
|
+
onInteractionEnd()
|
|
171
|
+
return
|
|
172
|
+
}
|
|
158
173
|
}
|
|
159
174
|
|
|
160
175
|
this.parent.transition('idle')
|