@tldraw/editor 3.8.0-internal.af5331ba6061 → 3.8.1
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/CHANGELOG.md +191 -0
- package/dist-cjs/index.d.ts +169 -52
- package/dist-cjs/index.js +4 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +31 -18
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/TextManager.js +1 -0
- package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +13 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/shared/resizeScaled.js +66 -0
- package/dist-cjs/lib/editor/shapes/shared/resizeScaled.js.map +7 -0
- package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
- package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
- package/dist-cjs/lib/hooks/useCanvasEvents.js +19 -8
- package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/useDocumentEvents.js +1 -3
- package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +4 -0
- package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +3 -3
- package/dist-cjs/lib/options.js +2 -2
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/utils/dom.js +6 -0
- package/dist-cjs/lib/utils/dom.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 +169 -52
- package/dist-esm/index.mjs +5 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +31 -18
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/TextManager.mjs +1 -0
- package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +13 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/shared/resizeScaled.mjs +46 -0
- package/dist-esm/lib/editor/shapes/shared/resizeScaled.mjs.map +7 -0
- package/dist-esm/lib/hooks/useCanvasEvents.mjs +19 -8
- package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/useDocumentEvents.mjs +2 -4
- package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +4 -0
- package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +3 -3
- package/dist-esm/lib/options.mjs +2 -2
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/utils/dom.mjs +6 -0
- package/dist-esm/lib/utils/dom.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +2 -1
- package/package.json +7 -7
- package/src/index.ts +18 -1
- package/src/lib/components/default-components/DefaultCanvas.tsx +1 -1
- package/src/lib/editor/Editor.ts +57 -28
- package/src/lib/editor/managers/TextManager.ts +1 -0
- package/src/lib/editor/shapes/ShapeUtil.ts +49 -1
- package/src/lib/editor/shapes/shared/resizeScaled.ts +61 -0
- package/src/lib/editor/types/emit-types.ts +1 -0
- package/src/lib/editor/types/external-content.ts +104 -50
- package/src/lib/hooks/useCanvasEvents.ts +20 -8
- package/src/lib/hooks/useDocumentEvents.ts +2 -11
- package/src/lib/hooks/usePassThroughWheelEvents.ts +7 -0
- package/src/lib/options.ts +5 -2
- package/src/lib/utils/dom.ts +12 -0
- package/src/version.ts +3 -3
package/dist-esm/version.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/version.ts"],
|
|
4
|
-
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.8.
|
|
4
|
+
"sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.8.1'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-02-12T15:48:24.555Z',\n\tpatch: '2025-02-13T13:35:17.724Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/editor.css
CHANGED
|
@@ -39,9 +39,10 @@
|
|
|
39
39
|
--layer-overlays-user-brush: 50;
|
|
40
40
|
--layer-overlays-user-indicator-selected: 60;
|
|
41
41
|
--layer-overlays-user-indicator-hovered: 70;
|
|
42
|
-
--layer-overlays-user-handles: 80;
|
|
43
42
|
--layer-overlays-user-snapline: 90;
|
|
44
43
|
--layer-overlays-selection-fg: 100;
|
|
44
|
+
/* User handles need to be above selection edges / corners, matters for sticky note clone handles */
|
|
45
|
+
--layer-overlays-user-handles: 105;
|
|
45
46
|
--layer-overlays-user-indicator-hint: 110;
|
|
46
47
|
--layer-overlays-collaborator-cursor-hint: 120;
|
|
47
48
|
--layer-overlays-collaborator-cursor: 130;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "A tiny little drawing app (editor).",
|
|
4
|
-
"version": "3.8.
|
|
4
|
+
"version": "3.8.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
"lint": "yarn run -T tsx ../../internal/scripts/lint.ts"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@tldraw/state": "3.8.
|
|
49
|
-
"@tldraw/state-react": "3.8.
|
|
50
|
-
"@tldraw/store": "3.8.
|
|
51
|
-
"@tldraw/tlschema": "3.8.
|
|
52
|
-
"@tldraw/utils": "3.8.
|
|
53
|
-
"@tldraw/validate": "3.8.
|
|
48
|
+
"@tldraw/state": "3.8.1",
|
|
49
|
+
"@tldraw/state-react": "3.8.1",
|
|
50
|
+
"@tldraw/store": "3.8.1",
|
|
51
|
+
"@tldraw/tlschema": "3.8.1",
|
|
52
|
+
"@tldraw/utils": "3.8.1",
|
|
53
|
+
"@tldraw/validate": "3.8.1",
|
|
54
54
|
"@types/core-js": "^2.5.8",
|
|
55
55
|
"@use-gesture/react": "^10.3.1",
|
|
56
56
|
"canvas-size": "~2.0.0",
|
package/src/index.ts
CHANGED
|
@@ -25,6 +25,7 @@ export {
|
|
|
25
25
|
useStateTracking,
|
|
26
26
|
useValue,
|
|
27
27
|
} from '@tldraw/state-react'
|
|
28
|
+
export { resizeScaled } from './lib/editor/shapes/shared/resizeScaled'
|
|
28
29
|
export { LocalIndexedDb, Table, type StoreName } from './lib/utils/sync/LocalIndexedDb'
|
|
29
30
|
// eslint-disable-next-line local/no-export-star
|
|
30
31
|
export * from '@tldraw/store'
|
|
@@ -182,6 +183,7 @@ export { UserPreferencesManager } from './lib/editor/managers/UserPreferencesMan
|
|
|
182
183
|
export { BaseBoxShapeUtil, type TLBaseBoxShape } from './lib/editor/shapes/BaseBoxShapeUtil'
|
|
183
184
|
export {
|
|
184
185
|
ShapeUtil,
|
|
186
|
+
type TLCropInfo,
|
|
185
187
|
type TLHandleDragInfo,
|
|
186
188
|
type TLResizeInfo,
|
|
187
189
|
type TLResizeMode,
|
|
@@ -238,9 +240,23 @@ export {
|
|
|
238
240
|
type UiEventType,
|
|
239
241
|
} from './lib/editor/types/event-types'
|
|
240
242
|
export {
|
|
241
|
-
type
|
|
243
|
+
type TLBaseExternalContent,
|
|
244
|
+
type TLEmbedExternalContent,
|
|
245
|
+
type TLErrorExternalContentSource,
|
|
246
|
+
type TLExcalidrawExternalContent,
|
|
247
|
+
type TLExcalidrawExternalContentSource,
|
|
248
|
+
type TLExternalAsset,
|
|
242
249
|
type TLExternalContent,
|
|
243
250
|
type TLExternalContentSource,
|
|
251
|
+
type TLFileExternalAsset,
|
|
252
|
+
type TLFilesExternalContent,
|
|
253
|
+
type TLSvgTextExternalContent,
|
|
254
|
+
type TLTextExternalContent,
|
|
255
|
+
type TLTextExternalContentSource,
|
|
256
|
+
type TLTldrawExternalContent,
|
|
257
|
+
type TLTldrawExternalContentSource,
|
|
258
|
+
type TLUrlExternalAsset,
|
|
259
|
+
type TLUrlExternalContent,
|
|
244
260
|
} from './lib/editor/types/external-content'
|
|
245
261
|
export {
|
|
246
262
|
type TLHistoryBatchOptions,
|
|
@@ -399,6 +415,7 @@ export {
|
|
|
399
415
|
type TLDeepLinkOptions,
|
|
400
416
|
} from './lib/utils/deepLinks'
|
|
401
417
|
export {
|
|
418
|
+
activeElementShouldCaptureKeys,
|
|
402
419
|
loopToHtmlElement,
|
|
403
420
|
preventDefault,
|
|
404
421
|
releasePointerCapture,
|
|
@@ -160,7 +160,6 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
|
160
160
|
<div className="tl-overlays">
|
|
161
161
|
<div ref={rHtmlLayer2} className="tl-html-layer">
|
|
162
162
|
{debugGeometry ? <GeometryDebuggingView /> : null}
|
|
163
|
-
<HandlesWrapper />
|
|
164
163
|
<BrushWrapper />
|
|
165
164
|
<ScribbleWrapper />
|
|
166
165
|
<ZoomBrushWrapper />
|
|
@@ -168,6 +167,7 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
|
|
|
168
167
|
<HintedShapeIndicator />
|
|
169
168
|
<SnapIndicatorWrapper />
|
|
170
169
|
<SelectionForegroundWrapper />
|
|
170
|
+
<HandlesWrapper />
|
|
171
171
|
<LiveCollaborators />
|
|
172
172
|
</div>
|
|
173
173
|
</div>
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -155,7 +155,7 @@ import {
|
|
|
155
155
|
TLPointerEventInfo,
|
|
156
156
|
TLWheelEventInfo,
|
|
157
157
|
} from './types/event-types'
|
|
158
|
-
import {
|
|
158
|
+
import { TLExternalAsset, TLExternalContent } from './types/external-content'
|
|
159
159
|
import { TLHistoryBatchOptions } from './types/history-types'
|
|
160
160
|
import {
|
|
161
161
|
OptionalKeys,
|
|
@@ -929,6 +929,21 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
929
929
|
return shapeUtil
|
|
930
930
|
}
|
|
931
931
|
|
|
932
|
+
/**
|
|
933
|
+
* Returns true if the editor has a shape util for the given shape / shape type.
|
|
934
|
+
*
|
|
935
|
+
* @param shape - A shape, shape partial, or shape type.
|
|
936
|
+
*/
|
|
937
|
+
hasShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): boolean
|
|
938
|
+
hasShapeUtil<S extends TLUnknownShape>(type: S['type']): boolean
|
|
939
|
+
hasShapeUtil<T extends ShapeUtil>(
|
|
940
|
+
type: T extends ShapeUtil<infer R> ? R['type'] : string
|
|
941
|
+
): boolean
|
|
942
|
+
hasShapeUtil(arg: string | { type: string }): boolean {
|
|
943
|
+
const type = typeof arg === 'string' ? arg : arg.type
|
|
944
|
+
return hasOwnProperty(this.shapeUtils, type)
|
|
945
|
+
}
|
|
946
|
+
|
|
932
947
|
/* ------------------- Binding Utils ------------------ */
|
|
933
948
|
/**
|
|
934
949
|
* A map of shape utility classes (TLShapeUtils) by shape type.
|
|
@@ -1385,8 +1400,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
1385
1400
|
*
|
|
1386
1401
|
* @example
|
|
1387
1402
|
* ```ts
|
|
1388
|
-
*
|
|
1389
|
-
*
|
|
1403
|
+
* editor.getStateDescendant('select')
|
|
1404
|
+
* editor.getStateDescendant('select.brushing')
|
|
1390
1405
|
* ```
|
|
1391
1406
|
*
|
|
1392
1407
|
* @param path - The descendant's path of state ids, separated by periods.
|
|
@@ -6760,6 +6775,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6760
6775
|
}
|
|
6761
6776
|
}
|
|
6762
6777
|
|
|
6778
|
+
let didResize = false
|
|
6779
|
+
|
|
6763
6780
|
if (util.onResize && util.canResize(initialShape)) {
|
|
6764
6781
|
// get the model changes from the shape util
|
|
6765
6782
|
const newPagePoint = this._scalePagePoint(
|
|
@@ -6798,24 +6815,30 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6798
6815
|
)
|
|
6799
6816
|
}
|
|
6800
6817
|
|
|
6818
|
+
const resizedShape = util.onResize(
|
|
6819
|
+
{ ...initialShape, x, y },
|
|
6820
|
+
{
|
|
6821
|
+
newPoint: newLocalPoint,
|
|
6822
|
+
handle: opts.dragHandle ?? 'bottom_right',
|
|
6823
|
+
// don't set isSingle to true for children
|
|
6824
|
+
mode: opts.mode ?? 'scale_shape',
|
|
6825
|
+
scaleX: myScale.x,
|
|
6826
|
+
scaleY: myScale.y,
|
|
6827
|
+
initialBounds,
|
|
6828
|
+
initialShape,
|
|
6829
|
+
}
|
|
6830
|
+
)
|
|
6831
|
+
|
|
6832
|
+
if (resizedShape) {
|
|
6833
|
+
didResize = true
|
|
6834
|
+
}
|
|
6835
|
+
|
|
6801
6836
|
workingShape = applyPartialToRecordWithProps(workingShape, {
|
|
6802
6837
|
id,
|
|
6803
6838
|
type: initialShape.type as any,
|
|
6804
6839
|
x: newLocalPoint.x,
|
|
6805
6840
|
y: newLocalPoint.y,
|
|
6806
|
-
...
|
|
6807
|
-
{ ...initialShape, x, y },
|
|
6808
|
-
{
|
|
6809
|
-
newPoint: newLocalPoint,
|
|
6810
|
-
handle: opts.dragHandle ?? 'bottom_right',
|
|
6811
|
-
// don't set isSingle to true for children
|
|
6812
|
-
mode: opts.mode ?? 'scale_shape',
|
|
6813
|
-
scaleX: myScale.x,
|
|
6814
|
-
scaleY: myScale.y,
|
|
6815
|
-
initialBounds,
|
|
6816
|
-
initialShape,
|
|
6817
|
-
}
|
|
6818
|
-
),
|
|
6841
|
+
...resizedShape,
|
|
6819
6842
|
})
|
|
6820
6843
|
|
|
6821
6844
|
if (!opts.skipStartAndEndCallbacks) {
|
|
@@ -6826,7 +6849,11 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6826
6849
|
}
|
|
6827
6850
|
|
|
6828
6851
|
this.updateShapes([workingShape])
|
|
6829
|
-
}
|
|
6852
|
+
}
|
|
6853
|
+
|
|
6854
|
+
if (!didResize) {
|
|
6855
|
+
// reposition shape (rather than resizing it) based on where its resized center would be
|
|
6856
|
+
|
|
6830
6857
|
const initialPageCenter = Mat.applyToPoint(pageTransform, initialBounds.center)
|
|
6831
6858
|
// get the model changes from the shape util
|
|
6832
6859
|
const newPageCenter = this._scalePagePoint(
|
|
@@ -7948,10 +7975,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7948
7975
|
|
|
7949
7976
|
/** @internal */
|
|
7950
7977
|
externalAssetContentHandlers: {
|
|
7951
|
-
[K in
|
|
7952
|
-
[Key in K]:
|
|
7953
|
-
| null
|
|
7954
|
-
| ((info: TLExternalAssetContent & { type: Key }) => Promise<TLAsset | undefined>)
|
|
7978
|
+
[K in TLExternalAsset['type']]: {
|
|
7979
|
+
[Key in K]: null | ((info: TLExternalAsset & { type: Key }) => Promise<TLAsset | undefined>)
|
|
7955
7980
|
}[K]
|
|
7956
7981
|
} = {
|
|
7957
7982
|
file: null,
|
|
@@ -7980,9 +8005,9 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
7980
8005
|
*
|
|
7981
8006
|
* @public
|
|
7982
8007
|
*/
|
|
7983
|
-
registerExternalAssetHandler<T extends
|
|
8008
|
+
registerExternalAssetHandler<T extends TLExternalAsset['type']>(
|
|
7984
8009
|
type: T,
|
|
7985
|
-
handler: null | ((info:
|
|
8010
|
+
handler: null | ((info: TLExternalAsset & { type: T }) => Promise<TLAsset>)
|
|
7986
8011
|
): this {
|
|
7987
8012
|
this.externalAssetContentHandlers[type] = handler as any
|
|
7988
8013
|
return this
|
|
@@ -8050,18 +8075,18 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8050
8075
|
* @param info - Info about the external content.
|
|
8051
8076
|
* @returns The asset.
|
|
8052
8077
|
*/
|
|
8053
|
-
async getAssetForExternalContent(info:
|
|
8078
|
+
async getAssetForExternalContent(info: TLExternalAsset): Promise<TLAsset | undefined> {
|
|
8054
8079
|
return await this.externalAssetContentHandlers[info.type]?.(info as any)
|
|
8055
8080
|
}
|
|
8056
8081
|
|
|
8057
|
-
hasExternalAssetHandler(type:
|
|
8082
|
+
hasExternalAssetHandler(type: TLExternalAsset['type']): boolean {
|
|
8058
8083
|
return !!this.externalAssetContentHandlers[type]
|
|
8059
8084
|
}
|
|
8060
8085
|
|
|
8061
8086
|
/** @internal */
|
|
8062
8087
|
externalContentHandlers: {
|
|
8063
8088
|
[K in TLExternalContent<any>['type']]: {
|
|
8064
|
-
[Key in K]: null | ((info: TLExternalContent<any
|
|
8089
|
+
[Key in K]: null | ((info: Extract<TLExternalContent<any>, { type: Key }>) => void)
|
|
8065
8090
|
}[K]
|
|
8066
8091
|
} = {
|
|
8067
8092
|
text: null,
|
|
@@ -8069,6 +8094,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8069
8094
|
embed: null,
|
|
8070
8095
|
'svg-text': null,
|
|
8071
8096
|
url: null,
|
|
8097
|
+
tldraw: null,
|
|
8098
|
+
excalidraw: null,
|
|
8072
8099
|
}
|
|
8073
8100
|
|
|
8074
8101
|
/**
|
|
@@ -8096,7 +8123,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8096
8123
|
| null
|
|
8097
8124
|
| ((
|
|
8098
8125
|
info: T extends TLExternalContent<E>['type']
|
|
8099
|
-
? TLExternalContent<E
|
|
8126
|
+
? Extract<TLExternalContent<E>, { type: T }>
|
|
8100
8127
|
: TLExternalContent<E>
|
|
8101
8128
|
) => void)
|
|
8102
8129
|
): this {
|
|
@@ -8638,7 +8665,7 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
8638
8665
|
switch (withDefaults.format) {
|
|
8639
8666
|
case 'svg':
|
|
8640
8667
|
return {
|
|
8641
|
-
blob: new Blob([result.svg], { type: '
|
|
8668
|
+
blob: new Blob([result.svg], { type: 'image/svg+xml' }),
|
|
8642
8669
|
width: result.width,
|
|
8643
8670
|
height: result.height,
|
|
8644
8671
|
}
|
|
@@ -9342,6 +9369,8 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
9342
9369
|
// todo: replace with new readonly mode?
|
|
9343
9370
|
if (this.getCrashingError()) return this
|
|
9344
9371
|
|
|
9372
|
+
this.emit('before-event', info)
|
|
9373
|
+
|
|
9345
9374
|
const { inputs } = this
|
|
9346
9375
|
const { type } = info
|
|
9347
9376
|
|
|
@@ -230,6 +230,7 @@ export class TextManager {
|
|
|
230
230
|
elm.style.setProperty('font-weight', opts.fontWeight)
|
|
231
231
|
elm.style.setProperty('line-height', `${opts.lineHeight * opts.fontSize}px`)
|
|
232
232
|
elm.style.setProperty('text-align', textAlignmentsForLtr[opts.textAlign])
|
|
233
|
+
elm.style.setProperty('font-style', opts.fontStyle)
|
|
233
234
|
|
|
234
235
|
const shouldTruncateToFirstLine =
|
|
235
236
|
opts.overflow === 'truncate-ellipsis' || opts.overflow === 'truncate-clip'
|
|
@@ -5,11 +5,12 @@ import {
|
|
|
5
5
|
TLHandle,
|
|
6
6
|
TLPropsMigrations,
|
|
7
7
|
TLShape,
|
|
8
|
+
TLShapeCrop,
|
|
8
9
|
TLShapePartial,
|
|
9
10
|
TLUnknownShape,
|
|
10
11
|
} from '@tldraw/tlschema'
|
|
11
12
|
import { ReactElement } from 'react'
|
|
12
|
-
import { Box } from '../../primitives/Box'
|
|
13
|
+
import { Box, SelectionHandle } from '../../primitives/Box'
|
|
13
14
|
import { Vec } from '../../primitives/Vec'
|
|
14
15
|
import { Geometry2d } from '../../primitives/geometry/Geometry2d'
|
|
15
16
|
import type { Editor } from '../Editor'
|
|
@@ -52,8 +53,27 @@ export interface TLShapeUtilCanvasSvgDef {
|
|
|
52
53
|
|
|
53
54
|
/** @public */
|
|
54
55
|
export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
56
|
+
/** Configure this shape utils {@link ShapeUtil.options | `options`}. */
|
|
57
|
+
static configure<T extends TLShapeUtilConstructor<any, any>>(
|
|
58
|
+
this: T,
|
|
59
|
+
options: T extends new (...args: any[]) => { options: infer Options } ? Partial<Options> : never
|
|
60
|
+
): T {
|
|
61
|
+
// @ts-expect-error -- typescript has no idea what's going on here but it's fine
|
|
62
|
+
return class extends this {
|
|
63
|
+
// @ts-expect-error
|
|
64
|
+
options = { ...this.options, ...options }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
55
68
|
constructor(public editor: Editor) {}
|
|
56
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Options for this shape util. If you're implementing a custom shape util, you can override
|
|
72
|
+
* this to provide customization options for your shape. If using an existing shape util, you
|
|
73
|
+
* can customizing this by calling {@link ShapeUtil.configure}.
|
|
74
|
+
*/
|
|
75
|
+
options = {}
|
|
76
|
+
|
|
57
77
|
/**
|
|
58
78
|
* Props allow you to define the shape's properties in a way that the editor can understand.
|
|
59
79
|
* This has two main uses:
|
|
@@ -419,6 +439,19 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
419
439
|
*/
|
|
420
440
|
onBeforeUpdate?(prev: Shape, next: Shape): Shape | void
|
|
421
441
|
|
|
442
|
+
/**
|
|
443
|
+
* A callback called when a shape changes from a crop.
|
|
444
|
+
*
|
|
445
|
+
* @param shape - The shape at the start of the crop.
|
|
446
|
+
* @param info - Info about the crop.
|
|
447
|
+
* @returns A change to apply to the shape, or void.
|
|
448
|
+
* @public
|
|
449
|
+
*/
|
|
450
|
+
onCrop?(
|
|
451
|
+
shape: Shape,
|
|
452
|
+
info: TLCropInfo<Shape>
|
|
453
|
+
): Omit<TLShapePartial<Shape>, 'id' | 'type'> | undefined | void
|
|
454
|
+
|
|
422
455
|
/**
|
|
423
456
|
* A callback called when some other shapes are dragged over this one.
|
|
424
457
|
*
|
|
@@ -616,6 +649,21 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
616
649
|
onEditEnd?(shape: Shape): void
|
|
617
650
|
}
|
|
618
651
|
|
|
652
|
+
/**
|
|
653
|
+
* Info about a crop.
|
|
654
|
+
* @param handle - The handle being dragged.
|
|
655
|
+
* @param change - The distance the handle is moved.
|
|
656
|
+
* @param initialShape - The shape at the start of the resize.
|
|
657
|
+
* @public
|
|
658
|
+
*/
|
|
659
|
+
export interface TLCropInfo<T extends TLShape> {
|
|
660
|
+
handle: SelectionHandle
|
|
661
|
+
change: Vec
|
|
662
|
+
crop: TLShapeCrop
|
|
663
|
+
uncroppedSize: { w: number; h: number }
|
|
664
|
+
initialShape: T
|
|
665
|
+
}
|
|
666
|
+
|
|
619
667
|
/**
|
|
620
668
|
* The type of resize.
|
|
621
669
|
*
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { TLBaseShape } from '@tldraw/tlschema'
|
|
2
|
+
import { exhaustiveSwitchError } from '@tldraw/utils'
|
|
3
|
+
import { Vec } from '../../../primitives/Vec'
|
|
4
|
+
import { TLResizeInfo } from '../ShapeUtil'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Resize a shape that has a scale prop.
|
|
8
|
+
*
|
|
9
|
+
* @param shape - The shape to resize
|
|
10
|
+
* @param info - The resize info
|
|
11
|
+
*
|
|
12
|
+
* @public */
|
|
13
|
+
export function resizeScaled(
|
|
14
|
+
shape: TLBaseShape<any, { scale: number }>,
|
|
15
|
+
{ initialBounds, scaleX, scaleY, newPoint, handle }: TLResizeInfo<any>
|
|
16
|
+
) {
|
|
17
|
+
let scaleDelta: number
|
|
18
|
+
switch (handle) {
|
|
19
|
+
case 'bottom_left':
|
|
20
|
+
case 'bottom_right':
|
|
21
|
+
case 'top_left':
|
|
22
|
+
case 'top_right': {
|
|
23
|
+
scaleDelta = Math.max(0.01, Math.max(Math.abs(scaleX), Math.abs(scaleY)))
|
|
24
|
+
break
|
|
25
|
+
}
|
|
26
|
+
case 'left':
|
|
27
|
+
case 'right': {
|
|
28
|
+
scaleDelta = Math.max(0.01, Math.abs(scaleX))
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
case 'bottom':
|
|
32
|
+
case 'top': {
|
|
33
|
+
scaleDelta = Math.max(0.01, Math.abs(scaleY))
|
|
34
|
+
break
|
|
35
|
+
}
|
|
36
|
+
default: {
|
|
37
|
+
throw exhaustiveSwitchError(handle)
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Compute the offset (if flipped X or flipped Y)
|
|
42
|
+
const offset = new Vec(0, 0)
|
|
43
|
+
|
|
44
|
+
if (scaleX < 0) {
|
|
45
|
+
offset.x = -(initialBounds.width * scaleDelta)
|
|
46
|
+
}
|
|
47
|
+
if (scaleY < 0) {
|
|
48
|
+
offset.y = -(initialBounds.height * scaleDelta)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Apply the offset to the new point
|
|
52
|
+
const { x, y } = Vec.Add(newPoint, offset.rot(shape.rotation))
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
x,
|
|
56
|
+
y,
|
|
57
|
+
props: {
|
|
58
|
+
scale: scaleDelta * shape.props.scale,
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -2,57 +2,111 @@ import { TLAssetId } from '@tldraw/tlschema'
|
|
|
2
2
|
import { VecLike } from '../../primitives/Vec'
|
|
3
3
|
import { TLContent } from './clipboard-types'
|
|
4
4
|
|
|
5
|
+
/** @public */
|
|
6
|
+
export interface TLTldrawExternalContentSource {
|
|
7
|
+
type: 'tldraw'
|
|
8
|
+
data: TLContent
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** @public */
|
|
12
|
+
export interface TLExcalidrawExternalContentSource {
|
|
13
|
+
type: 'excalidraw'
|
|
14
|
+
data: any
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** @public */
|
|
18
|
+
export interface TLTextExternalContentSource {
|
|
19
|
+
type: 'text'
|
|
20
|
+
data: string
|
|
21
|
+
subtype: 'json' | 'html' | 'text' | 'url'
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** @public */
|
|
25
|
+
export interface TLErrorExternalContentSource {
|
|
26
|
+
type: 'error'
|
|
27
|
+
data: string | null
|
|
28
|
+
reason: string
|
|
29
|
+
}
|
|
30
|
+
|
|
5
31
|
/** @public */
|
|
6
32
|
export type TLExternalContentSource =
|
|
7
|
-
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
| {
|
|
16
|
-
type: 'text'
|
|
17
|
-
data: string
|
|
18
|
-
subtype: 'json' | 'html' | 'text' | 'url'
|
|
19
|
-
}
|
|
20
|
-
| {
|
|
21
|
-
type: 'error'
|
|
22
|
-
data: string | null
|
|
23
|
-
reason: string
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** @public */
|
|
27
|
-
export type TLExternalContent<EmbedDefinition> = {
|
|
33
|
+
| TLTldrawExternalContentSource
|
|
34
|
+
| TLExcalidrawExternalContentSource
|
|
35
|
+
| TLTextExternalContentSource
|
|
36
|
+
| TLErrorExternalContentSource
|
|
37
|
+
|
|
38
|
+
/** @public */
|
|
39
|
+
export interface TLBaseExternalContent {
|
|
28
40
|
sources?: TLExternalContentSource[]
|
|
29
41
|
point?: VecLike
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** @public */
|
|
45
|
+
export interface TLTextExternalContent extends TLBaseExternalContent {
|
|
46
|
+
type: 'text'
|
|
47
|
+
text: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** @public */
|
|
51
|
+
export interface TLFilesExternalContent extends TLBaseExternalContent {
|
|
52
|
+
type: 'files'
|
|
53
|
+
files: File[]
|
|
54
|
+
ignoreParent: boolean
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** @public */
|
|
58
|
+
export interface TLUrlExternalContent extends TLBaseExternalContent {
|
|
59
|
+
type: 'url'
|
|
60
|
+
url: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** @public */
|
|
64
|
+
export interface TLSvgTextExternalContent extends TLBaseExternalContent {
|
|
65
|
+
type: 'svg-text'
|
|
66
|
+
text: string
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** @public */
|
|
70
|
+
export interface TLEmbedExternalContent<EmbedDefinition> extends TLBaseExternalContent {
|
|
71
|
+
type: 'embed'
|
|
72
|
+
url: string
|
|
73
|
+
embed: EmbedDefinition
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** @public */
|
|
77
|
+
export interface TLTldrawExternalContent extends TLBaseExternalContent {
|
|
78
|
+
type: 'tldraw'
|
|
79
|
+
content: TLContent
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** @public */
|
|
83
|
+
export interface TLExcalidrawExternalContent extends TLBaseExternalContent {
|
|
84
|
+
type: 'excalidraw'
|
|
85
|
+
content: any
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** @public */
|
|
89
|
+
export type TLExternalContent<EmbedDefinition> =
|
|
90
|
+
| TLTextExternalContent
|
|
91
|
+
| TLFilesExternalContent
|
|
92
|
+
| TLUrlExternalContent
|
|
93
|
+
| TLSvgTextExternalContent
|
|
94
|
+
| TLEmbedExternalContent<EmbedDefinition>
|
|
95
|
+
| TLTldrawExternalContent
|
|
96
|
+
| TLExcalidrawExternalContent
|
|
97
|
+
|
|
98
|
+
/** @public */
|
|
99
|
+
export interface TLFileExternalAsset {
|
|
100
|
+
type: 'file'
|
|
101
|
+
file: File
|
|
102
|
+
assetId?: TLAssetId
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** @public */
|
|
106
|
+
export interface TLUrlExternalAsset {
|
|
107
|
+
type: 'url'
|
|
108
|
+
url: string
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** @public */
|
|
112
|
+
export type TLExternalAsset = TLFileExternalAsset | TLUrlExternalAsset
|
|
@@ -117,16 +117,28 @@ export function useCanvasEvents() {
|
|
|
117
117
|
async function onDrop(e: React.DragEvent<Element>) {
|
|
118
118
|
preventDefault(e)
|
|
119
119
|
stopEventPropagation(e)
|
|
120
|
-
if (!e.dataTransfer?.files?.length) return
|
|
121
120
|
|
|
122
|
-
|
|
121
|
+
if (e.dataTransfer?.files?.length) {
|
|
122
|
+
const files = Array.from(e.dataTransfer.files)
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
124
|
+
await editor.putExternalContent({
|
|
125
|
+
type: 'files',
|
|
126
|
+
files,
|
|
127
|
+
point: editor.screenToPage({ x: e.clientX, y: e.clientY }),
|
|
128
|
+
ignoreParent: false,
|
|
129
|
+
})
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const url = e.dataTransfer.getData('url')
|
|
134
|
+
if (url) {
|
|
135
|
+
await editor.putExternalContent({
|
|
136
|
+
type: 'url',
|
|
137
|
+
url,
|
|
138
|
+
point: editor.screenToPage({ x: e.clientX, y: e.clientY }),
|
|
139
|
+
})
|
|
140
|
+
return
|
|
141
|
+
}
|
|
130
142
|
}
|
|
131
143
|
|
|
132
144
|
function onClick(e: React.MouseEvent) {
|