@tldraw/editor 3.9.0-canary.c5400ad6b312 → 3.9.0-canary.d260c3bc7305
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 +39 -7
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +430 -248
- package/dist-cjs/lib/editor/Editor.js.map +3 -3
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +7 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/exports/getSvgAsImage.js +1 -1
- package/dist-cjs/lib/exports/getSvgAsImage.js.map +2 -2
- package/dist-cjs/lib/globals/environment.js +3 -1
- package/dist-cjs/lib/globals/environment.js.map +2 -2
- package/dist-cjs/lib/license/LicenseManager.js +1 -1
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/utils/browserCanvasMaxSize.js +104 -28
- package/dist-cjs/lib/utils/browserCanvasMaxSize.js.map +3 -3
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +39 -7
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +426 -244
- package/dist-esm/lib/editor/Editor.mjs.map +3 -3
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +7 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/exports/getSvgAsImage.mjs +1 -1
- package/dist-esm/lib/exports/getSvgAsImage.mjs.map +2 -2
- package/dist-esm/lib/globals/environment.mjs +3 -1
- package/dist-esm/lib/globals/environment.mjs.map +2 -2
- package/dist-esm/lib/license/LicenseManager.mjs +1 -1
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/utils/browserCanvasMaxSize.mjs +104 -18
- package/dist-esm/lib/utils/browserCanvasMaxSize.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +7 -9
- package/src/index.ts +2 -0
- package/src/lib/editor/Editor.ts +555 -272
- package/src/lib/editor/shapes/ShapeUtil.ts +32 -5
- package/src/lib/exports/getSvgAsImage.ts +1 -1
- package/src/lib/globals/environment.ts +3 -0
- package/src/lib/license/LicenseManager.test.ts +16 -13
- package/src/lib/license/LicenseManager.ts +2 -2
- package/src/lib/utils/browserCanvasMaxSize.ts +121 -21
- package/src/version.ts +3 -3
|
@@ -36,7 +36,7 @@ export interface TLShapeUtilConstructor<
|
|
|
36
36
|
*
|
|
37
37
|
* @public
|
|
38
38
|
*/
|
|
39
|
-
export interface TLShapeUtilCanBindOpts<Shape extends TLUnknownShape =
|
|
39
|
+
export interface TLShapeUtilCanBindOpts<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
40
40
|
/** The type of shape referenced by the `fromId` of the binding. */
|
|
41
41
|
fromShapeType: string
|
|
42
42
|
/** The type of shape referenced by the `toId` of the binding. */
|
|
@@ -45,6 +45,27 @@ export interface TLShapeUtilCanBindOpts<Shape extends TLUnknownShape = TLShape>
|
|
|
45
45
|
bindingType: string
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Options passed to {@link ShapeUtil.canBeLaidOut}.
|
|
50
|
+
*
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
export interface TLShapeUtilCanBeLaidOutOpts {
|
|
54
|
+
/** The type of action causing the layout. */
|
|
55
|
+
type?: 'align' | 'distribute' | 'pack' | 'stack' | 'flip' | 'stretch'
|
|
56
|
+
/** The other shapes being laid out */
|
|
57
|
+
shapes?: TLShape[]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Additional options for the {@link ShapeUtil.getGeometry} method.
|
|
61
|
+
*
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
export interface TLGeometryOpts {
|
|
65
|
+
/** The context in which the geometry is being requested. */
|
|
66
|
+
context?: string
|
|
67
|
+
}
|
|
68
|
+
|
|
48
69
|
/** @public */
|
|
49
70
|
export interface TLShapeUtilCanvasSvgDef {
|
|
50
71
|
key: string
|
|
@@ -128,9 +149,10 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
128
149
|
* Get the shape's geometry.
|
|
129
150
|
*
|
|
130
151
|
* @param shape - The shape.
|
|
152
|
+
* @param opts - Additional options for the request.
|
|
131
153
|
* @public
|
|
132
154
|
*/
|
|
133
|
-
abstract getGeometry(shape: Shape): Geometry2d
|
|
155
|
+
abstract getGeometry(shape: Shape, opts?: TLGeometryOpts): Geometry2d
|
|
134
156
|
|
|
135
157
|
/**
|
|
136
158
|
* Get a JSX element for the shape (as an HTML element).
|
|
@@ -151,6 +173,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
151
173
|
/**
|
|
152
174
|
* Whether the shape can be snapped to by another shape.
|
|
153
175
|
*
|
|
176
|
+
* @param shape - The shape.
|
|
154
177
|
* @public
|
|
155
178
|
*/
|
|
156
179
|
canSnap(_shape: Shape): boolean {
|
|
@@ -171,7 +194,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
171
194
|
*
|
|
172
195
|
* @public
|
|
173
196
|
*/
|
|
174
|
-
canBind(_opts: TLShapeUtilCanBindOpts
|
|
197
|
+
canBind(_opts: TLShapeUtilCanBindOpts): boolean {
|
|
175
198
|
return true
|
|
176
199
|
}
|
|
177
200
|
|
|
@@ -212,11 +235,15 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
|
|
|
212
235
|
}
|
|
213
236
|
|
|
214
237
|
/**
|
|
215
|
-
* Whether the shape
|
|
238
|
+
* Whether the shape can participate in layout functions such as alignment or distribution.
|
|
239
|
+
*
|
|
240
|
+
* @param shape - The shape.
|
|
241
|
+
* @param info - Additional context information: the type of action causing the layout and the
|
|
242
|
+
* @public
|
|
216
243
|
*
|
|
217
244
|
* @public
|
|
218
245
|
*/
|
|
219
|
-
canBeLaidOut(_shape: Shape): boolean {
|
|
246
|
+
canBeLaidOut(_shape: Shape, _info: TLShapeUtilCanBeLaidOutOpts): boolean {
|
|
220
247
|
return true
|
|
221
248
|
}
|
|
222
249
|
|
|
@@ -16,7 +16,7 @@ export async function getSvgAsImage(
|
|
|
16
16
|
) {
|
|
17
17
|
const { type, width, height, quality = 1, pixelRatio = 2 } = options
|
|
18
18
|
|
|
19
|
-
let [clampedWidth, clampedHeight] =
|
|
19
|
+
let [clampedWidth, clampedHeight] = clampToBrowserMaxCanvasSize(
|
|
20
20
|
width * pixelRatio,
|
|
21
21
|
height * pixelRatio
|
|
22
22
|
)
|
|
@@ -11,6 +11,7 @@ const tlenv = {
|
|
|
11
11
|
isAndroid: false,
|
|
12
12
|
isWebview: false,
|
|
13
13
|
isDarwin: false,
|
|
14
|
+
hasCanvasSupport: false,
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
if (typeof window !== 'undefined' && 'navigator' in window) {
|
|
@@ -20,6 +21,8 @@ if (typeof window !== 'undefined' && 'navigator' in window) {
|
|
|
20
21
|
tlenv.isFirefox = /firefox/i.test(navigator.userAgent)
|
|
21
22
|
tlenv.isAndroid = /android/i.test(navigator.userAgent)
|
|
22
23
|
tlenv.isDarwin = window.navigator.userAgent.toLowerCase().indexOf('mac') > -1
|
|
24
|
+
tlenv.hasCanvasSupport =
|
|
25
|
+
typeof window !== 'undefined' && 'Promise' in window && 'HTMLCanvasElement' in window
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export { tlenv }
|
|
@@ -56,19 +56,22 @@ describe('LicenseManager', () => {
|
|
|
56
56
|
})
|
|
57
57
|
|
|
58
58
|
it('Signals that it is development mode when appropriate', async () => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
59
|
+
const schemes = ['http', 'https']
|
|
60
|
+
for (const scheme of schemes) {
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
delete window.location
|
|
63
|
+
// @ts-ignore
|
|
64
|
+
window.location = new URL(`${scheme}://localhost:3000`)
|
|
65
|
+
|
|
66
|
+
const testEnvLicenseManager = new LicenseManager('', keyPair.publicKey, 'development')
|
|
67
|
+
const licenseKey = await generateLicenseKey(STANDARD_LICENSE_INFO, keyPair)
|
|
68
|
+
const result = await testEnvLicenseManager.getLicenseFromKey(licenseKey)
|
|
69
|
+
expect(result).toMatchObject({
|
|
70
|
+
isLicenseParseable: true,
|
|
71
|
+
isDomainValid: false,
|
|
72
|
+
isDevelopment: true,
|
|
73
|
+
})
|
|
74
|
+
}
|
|
72
75
|
})
|
|
73
76
|
|
|
74
77
|
it('Cleanses out valid keys that accidentally have zero-width characters or newlines', async () => {
|
|
@@ -110,8 +110,8 @@ export class LicenseManager {
|
|
|
110
110
|
if (testEnvironment === 'development') return true
|
|
111
111
|
if (testEnvironment === 'production') return false
|
|
112
112
|
|
|
113
|
-
// If we are using https we assume it's a production env and a development one otherwise
|
|
114
|
-
return window.location.protocol !== 'https:'
|
|
113
|
+
// If we are using https on a non-localhost domain we assume it's a production env and a development one otherwise
|
|
114
|
+
return window.location.protocol !== 'https:' || window.location.hostname === 'localhost'
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
private async extractLicenseKey(licenseKey: string): Promise<LicenseInfo> {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import canvasSize from 'canvas-size'
|
|
2
|
-
|
|
3
1
|
/** @internal */
|
|
4
2
|
export interface CanvasMaxSize {
|
|
5
3
|
maxWidth: number
|
|
@@ -7,33 +5,135 @@ export interface CanvasMaxSize {
|
|
|
7
5
|
maxArea: number
|
|
8
6
|
}
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
// Cache this, only want to do this once per browser session
|
|
9
|
+
let maxCanvasSizes: CanvasMaxSize | null = null
|
|
11
10
|
|
|
12
|
-
function getBrowserCanvasMaxSize() {
|
|
13
|
-
if (!
|
|
14
|
-
|
|
11
|
+
function getBrowserCanvasMaxSize(): CanvasMaxSize {
|
|
12
|
+
if (!maxCanvasSizes) {
|
|
13
|
+
maxCanvasSizes = {
|
|
14
|
+
maxWidth: getCanvasSize('width'), // test very wide but 1 pixel tall canvases
|
|
15
|
+
maxHeight: getCanvasSize('height'), // test very tall but 1 pixel wide canvases
|
|
16
|
+
maxArea: getCanvasSize('area'), // test square canvases
|
|
17
|
+
}
|
|
15
18
|
}
|
|
16
|
-
|
|
17
|
-
return maxSizePromise
|
|
19
|
+
return maxCanvasSizes
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const maxArea = await canvasSize.maxArea({ usePromise: true })
|
|
24
|
-
return {
|
|
25
|
-
maxWidth: maxWidth.width,
|
|
26
|
-
maxHeight: maxHeight.height,
|
|
27
|
-
maxArea: maxArea.width * maxArea.height,
|
|
28
|
-
}
|
|
29
|
-
}
|
|
22
|
+
// Extracted from https://github.com/jhildenbiddle/canvas-size
|
|
23
|
+
// MIT License: https://github.com/jhildenbiddle/canvas-size/blob/master/LICENSE
|
|
24
|
+
// Copyright (c) John Hildenbiddle
|
|
30
25
|
|
|
31
|
-
// https://github.com/jhildenbiddle/canvas-size?tab=readme-ov-file#test-results
|
|
32
26
|
const MAX_SAFE_CANVAS_DIMENSION = 8192
|
|
33
27
|
const MAX_SAFE_CANVAS_AREA = 4096 * 4096
|
|
34
28
|
|
|
29
|
+
const TEST_SIZES = {
|
|
30
|
+
area: [
|
|
31
|
+
// Chrome 70 (Mac, Win)
|
|
32
|
+
// Chrome 68 (Android 4.4)
|
|
33
|
+
// Edge 17 (Win)
|
|
34
|
+
// Safari 7-12 (Mac)
|
|
35
|
+
16384,
|
|
36
|
+
// Chrome 68 (Android 7.1-9)
|
|
37
|
+
14188,
|
|
38
|
+
// Chrome 68 (Android 5)
|
|
39
|
+
11402,
|
|
40
|
+
// Firefox 63 (Mac, Win)
|
|
41
|
+
11180,
|
|
42
|
+
// Chrome 68 (Android 6)
|
|
43
|
+
10836,
|
|
44
|
+
// IE 9-11 (Win)
|
|
45
|
+
8192,
|
|
46
|
+
// IE Mobile (Windows Phone 8.x)
|
|
47
|
+
// Safari (iOS 9 - 12)
|
|
48
|
+
4096,
|
|
49
|
+
],
|
|
50
|
+
height: [
|
|
51
|
+
// Safari 7-12 (Mac)
|
|
52
|
+
// Safari (iOS 9-12)
|
|
53
|
+
8388607,
|
|
54
|
+
// Chrome 83 (Mac, Win)
|
|
55
|
+
65535,
|
|
56
|
+
// Chrome 70 (Mac, Win)
|
|
57
|
+
// Chrome 68 (Android 4.4-9)
|
|
58
|
+
// Firefox 63 (Mac, Win)
|
|
59
|
+
32767,
|
|
60
|
+
// Edge 17 (Win)
|
|
61
|
+
// IE11 (Win)
|
|
62
|
+
16384,
|
|
63
|
+
// IE 9-10 (Win)
|
|
64
|
+
8192,
|
|
65
|
+
// IE Mobile (Windows Phone 8.x)
|
|
66
|
+
4096,
|
|
67
|
+
],
|
|
68
|
+
width: [
|
|
69
|
+
// Safari 7-12 (Mac)
|
|
70
|
+
// Safari (iOS 9-12)
|
|
71
|
+
4194303,
|
|
72
|
+
// Chrome 83 (Mac, Win)
|
|
73
|
+
65535,
|
|
74
|
+
// Chrome 70 (Mac, Win)
|
|
75
|
+
// Chrome 68 (Android 4.4-9)
|
|
76
|
+
// Firefox 63 (Mac, Win)
|
|
77
|
+
32767,
|
|
78
|
+
// Edge 17 (Win)
|
|
79
|
+
// IE11 (Win)
|
|
80
|
+
16384,
|
|
81
|
+
// IE 9-10 (Win)
|
|
82
|
+
8192,
|
|
83
|
+
// IE Mobile (Windows Phone 8.x)
|
|
84
|
+
4096,
|
|
85
|
+
],
|
|
86
|
+
} as const
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Tests ability to read pixel data from canvas elements of various dimensions
|
|
90
|
+
* by decreasing canvas height and/or width until a test succeeds.
|
|
91
|
+
*/
|
|
92
|
+
export function getCanvasSize(dimension: 'width' | 'height' | 'area') {
|
|
93
|
+
const cropCvs = document.createElement('canvas')
|
|
94
|
+
cropCvs.width = 1
|
|
95
|
+
cropCvs.height = 1
|
|
96
|
+
const cropCtx = cropCvs.getContext('2d')!
|
|
97
|
+
|
|
98
|
+
for (const size of TEST_SIZES[dimension]) {
|
|
99
|
+
const w = dimension === 'height' ? 1 : size
|
|
100
|
+
const h = dimension === 'width' ? 1 : size
|
|
101
|
+
|
|
102
|
+
const testCvs = document.createElement('canvas')
|
|
103
|
+
testCvs.width = w
|
|
104
|
+
testCvs.height = h
|
|
105
|
+
const testCtx = testCvs.getContext('2d')!
|
|
106
|
+
|
|
107
|
+
testCtx.fillRect(w - 1, h - 1, 1, 1)
|
|
108
|
+
cropCtx.drawImage(testCvs, w - 1, h - 1, 1, 1, 0, 0, 1, 1)
|
|
109
|
+
|
|
110
|
+
const isTestPassed = cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0
|
|
111
|
+
// release memory
|
|
112
|
+
testCvs.width = 0
|
|
113
|
+
testCvs.height = 0
|
|
114
|
+
|
|
115
|
+
if (isTestPassed) {
|
|
116
|
+
// release memory
|
|
117
|
+
cropCvs.width = 0
|
|
118
|
+
cropCvs.height = 0
|
|
119
|
+
|
|
120
|
+
if (dimension === 'area') {
|
|
121
|
+
return size * size
|
|
122
|
+
} else {
|
|
123
|
+
return size
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// didn't find a good size, release memory and error
|
|
129
|
+
cropCvs.width = 0
|
|
130
|
+
cropCvs.height = 0
|
|
131
|
+
|
|
132
|
+
throw Error('Failed to determine maximum canvas dimension')
|
|
133
|
+
}
|
|
134
|
+
|
|
35
135
|
/** @internal */
|
|
36
|
-
export
|
|
136
|
+
export function clampToBrowserMaxCanvasSize(width: number, height: number) {
|
|
37
137
|
if (
|
|
38
138
|
width <= MAX_SAFE_CANVAS_DIMENSION &&
|
|
39
139
|
height <= MAX_SAFE_CANVAS_DIMENSION &&
|
|
@@ -42,7 +142,7 @@ export async function clampToBrowserMaxCanvasSize(width: number, height: number)
|
|
|
42
142
|
return [width, height]
|
|
43
143
|
}
|
|
44
144
|
|
|
45
|
-
const { maxWidth, maxHeight, maxArea } =
|
|
145
|
+
const { maxWidth, maxHeight, maxArea } = getBrowserCanvasMaxSize()
|
|
46
146
|
const aspectRatio = width / height
|
|
47
147
|
|
|
48
148
|
if (width > maxWidth) {
|
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.9.0-canary.
|
|
4
|
+
export const version = '3.9.0-canary.d260c3bc7305'
|
|
5
5
|
export const publishDates = {
|
|
6
6
|
major: '2024-09-13T14:36:29.063Z',
|
|
7
|
-
minor: '2025-02-
|
|
8
|
-
patch: '2025-02-
|
|
7
|
+
minor: '2025-02-25T16:50:55.846Z',
|
|
8
|
+
patch: '2025-02-25T16:50:55.846Z',
|
|
9
9
|
}
|