@tldraw/tlschema 4.1.0-canary.bdf9b3703a3d → 4.1.0-canary.c0b3a5b0ca61
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/TLStore.js +3 -10
- package/dist-cjs/TLStore.js.map +2 -2
- package/dist-cjs/assets/TLBaseAsset.js.map +2 -2
- package/dist-cjs/assets/TLBookmarkAsset.js.map +2 -2
- package/dist-cjs/assets/TLImageAsset.js.map +2 -2
- package/dist-cjs/assets/TLVideoAsset.js.map +2 -2
- package/dist-cjs/bindings/TLArrowBinding.js.map +2 -2
- package/dist-cjs/bindings/TLBaseBinding.js.map +2 -2
- package/dist-cjs/createPresenceStateDerivation.js.map +2 -2
- package/dist-cjs/createTLSchema.js.map +2 -2
- package/dist-cjs/index.d.ts +4416 -223
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/misc/TLColor.js.map +2 -2
- package/dist-cjs/misc/TLCursor.js.map +2 -2
- package/dist-cjs/misc/TLHandle.js.map +2 -2
- package/dist-cjs/misc/TLOpacity.js.map +2 -2
- package/dist-cjs/misc/TLRichText.js.map +2 -2
- package/dist-cjs/misc/TLScribble.js.map +2 -2
- package/dist-cjs/misc/geometry-types.js.map +2 -2
- package/dist-cjs/misc/id-validator.js.map +2 -2
- package/dist-cjs/records/TLAsset.js.map +2 -2
- package/dist-cjs/records/TLBinding.js.map +2 -2
- package/dist-cjs/records/TLCamera.js.map +2 -2
- package/dist-cjs/records/TLDocument.js.map +2 -2
- package/dist-cjs/records/TLInstance.js.map +2 -2
- package/dist-cjs/records/TLPage.js.map +2 -2
- package/dist-cjs/records/TLPageState.js.map +2 -2
- package/dist-cjs/records/TLPointer.js.map +2 -2
- package/dist-cjs/records/TLPresence.js.map +2 -2
- package/dist-cjs/records/TLRecord.js.map +1 -1
- package/dist-cjs/records/TLShape.js.map +2 -2
- package/dist-cjs/recordsWithProps.js.map +2 -2
- package/dist-cjs/shapes/ShapeWithCrop.js.map +1 -1
- package/dist-cjs/shapes/TLArrowShape.js.map +2 -2
- package/dist-cjs/shapes/TLBaseShape.js.map +2 -2
- package/dist-cjs/shapes/TLBookmarkShape.js.map +2 -2
- package/dist-cjs/shapes/TLDrawShape.js.map +2 -2
- package/dist-cjs/shapes/TLEmbedShape.js.map +2 -2
- package/dist-cjs/shapes/TLFrameShape.js.map +2 -2
- package/dist-cjs/shapes/TLGeoShape.js.map +2 -2
- package/dist-cjs/shapes/TLGroupShape.js.map +2 -2
- package/dist-cjs/shapes/TLHighlightShape.js.map +2 -2
- package/dist-cjs/shapes/TLImageShape.js.map +2 -2
- package/dist-cjs/shapes/TLLineShape.js.map +2 -2
- package/dist-cjs/shapes/TLNoteShape.js.map +2 -2
- package/dist-cjs/shapes/TLTextShape.js.map +2 -2
- package/dist-cjs/shapes/TLVideoShape.js.map +2 -2
- package/dist-cjs/store-migrations.js.map +2 -2
- package/dist-cjs/styles/TLColorStyle.js.map +2 -2
- package/dist-cjs/styles/TLDashStyle.js.map +2 -2
- package/dist-cjs/styles/TLFillStyle.js.map +2 -2
- package/dist-cjs/styles/TLFontStyle.js.map +2 -2
- package/dist-cjs/styles/TLHorizontalAlignStyle.js.map +2 -2
- package/dist-cjs/styles/TLSizeStyle.js.map +2 -2
- package/dist-cjs/styles/TLTextAlignStyle.js.map +2 -2
- package/dist-cjs/styles/TLVerticalAlignStyle.js.map +2 -2
- package/dist-cjs/translations/translations.js +1 -1
- package/dist-cjs/translations/translations.js.map +2 -2
- package/dist-cjs/util-types.js.map +1 -1
- package/dist-esm/TLStore.mjs +3 -10
- package/dist-esm/TLStore.mjs.map +2 -2
- package/dist-esm/assets/TLBaseAsset.mjs.map +2 -2
- package/dist-esm/assets/TLBookmarkAsset.mjs.map +2 -2
- package/dist-esm/assets/TLImageAsset.mjs.map +2 -2
- package/dist-esm/assets/TLVideoAsset.mjs.map +2 -2
- package/dist-esm/bindings/TLArrowBinding.mjs.map +2 -2
- package/dist-esm/bindings/TLBaseBinding.mjs.map +2 -2
- package/dist-esm/createPresenceStateDerivation.mjs.map +2 -2
- package/dist-esm/createTLSchema.mjs.map +2 -2
- package/dist-esm/index.d.mts +4416 -223
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/misc/TLColor.mjs.map +2 -2
- package/dist-esm/misc/TLCursor.mjs.map +2 -2
- package/dist-esm/misc/TLHandle.mjs.map +2 -2
- package/dist-esm/misc/TLOpacity.mjs.map +2 -2
- package/dist-esm/misc/TLRichText.mjs.map +2 -2
- package/dist-esm/misc/TLScribble.mjs.map +2 -2
- package/dist-esm/misc/geometry-types.mjs.map +2 -2
- package/dist-esm/misc/id-validator.mjs.map +2 -2
- package/dist-esm/records/TLAsset.mjs.map +2 -2
- package/dist-esm/records/TLBinding.mjs.map +2 -2
- package/dist-esm/records/TLCamera.mjs.map +2 -2
- package/dist-esm/records/TLDocument.mjs.map +2 -2
- package/dist-esm/records/TLInstance.mjs.map +2 -2
- package/dist-esm/records/TLPage.mjs.map +2 -2
- package/dist-esm/records/TLPageState.mjs.map +2 -2
- package/dist-esm/records/TLPointer.mjs.map +2 -2
- package/dist-esm/records/TLPresence.mjs.map +2 -2
- package/dist-esm/records/TLShape.mjs.map +2 -2
- package/dist-esm/recordsWithProps.mjs.map +2 -2
- package/dist-esm/shapes/TLArrowShape.mjs.map +2 -2
- package/dist-esm/shapes/TLBaseShape.mjs.map +2 -2
- package/dist-esm/shapes/TLBookmarkShape.mjs.map +2 -2
- package/dist-esm/shapes/TLDrawShape.mjs.map +2 -2
- package/dist-esm/shapes/TLEmbedShape.mjs.map +2 -2
- package/dist-esm/shapes/TLFrameShape.mjs.map +2 -2
- package/dist-esm/shapes/TLGeoShape.mjs.map +2 -2
- package/dist-esm/shapes/TLGroupShape.mjs.map +2 -2
- package/dist-esm/shapes/TLHighlightShape.mjs.map +2 -2
- package/dist-esm/shapes/TLImageShape.mjs.map +2 -2
- package/dist-esm/shapes/TLLineShape.mjs.map +2 -2
- package/dist-esm/shapes/TLNoteShape.mjs.map +2 -2
- package/dist-esm/shapes/TLTextShape.mjs.map +2 -2
- package/dist-esm/shapes/TLVideoShape.mjs.map +2 -2
- package/dist-esm/store-migrations.mjs.map +2 -2
- package/dist-esm/styles/TLColorStyle.mjs.map +2 -2
- package/dist-esm/styles/TLDashStyle.mjs.map +2 -2
- package/dist-esm/styles/TLFillStyle.mjs.map +2 -2
- package/dist-esm/styles/TLFontStyle.mjs.map +2 -2
- package/dist-esm/styles/TLHorizontalAlignStyle.mjs.map +2 -2
- package/dist-esm/styles/TLSizeStyle.mjs.map +2 -2
- package/dist-esm/styles/TLTextAlignStyle.mjs.map +2 -2
- package/dist-esm/styles/TLVerticalAlignStyle.mjs.map +2 -2
- package/dist-esm/translations/translations.mjs +1 -1
- package/dist-esm/translations/translations.mjs.map +2 -2
- package/package.json +5 -5
- package/src/TLStore.test.ts +644 -0
- package/src/TLStore.ts +205 -20
- package/src/assets/TLBaseAsset.ts +90 -7
- package/src/assets/TLBookmarkAsset.test.ts +96 -0
- package/src/assets/TLBookmarkAsset.ts +52 -2
- package/src/assets/TLImageAsset.test.ts +213 -0
- package/src/assets/TLImageAsset.ts +60 -2
- package/src/assets/TLVideoAsset.test.ts +105 -0
- package/src/assets/TLVideoAsset.ts +93 -4
- package/src/bindings/TLArrowBinding.test.ts +55 -0
- package/src/bindings/TLArrowBinding.ts +132 -10
- package/src/bindings/TLBaseBinding.ts +140 -3
- package/src/createPresenceStateDerivation.test.ts +158 -0
- package/src/createPresenceStateDerivation.ts +71 -2
- package/src/createTLSchema.test.ts +181 -0
- package/src/createTLSchema.ts +164 -7
- package/src/index.ts +32 -0
- package/src/misc/TLColor.ts +50 -6
- package/src/misc/TLCursor.ts +110 -8
- package/src/misc/TLHandle.ts +86 -6
- package/src/misc/TLOpacity.ts +51 -2
- package/src/misc/TLRichText.ts +56 -3
- package/src/misc/TLScribble.ts +105 -5
- package/src/misc/geometry-types.ts +30 -2
- package/src/misc/id-validator.test.ts +50 -0
- package/src/misc/id-validator.ts +20 -1
- package/src/records/TLAsset.test.ts +234 -0
- package/src/records/TLAsset.ts +165 -8
- package/src/records/TLBinding.test.ts +22 -0
- package/src/records/TLBinding.ts +277 -11
- package/src/records/TLCamera.test.ts +19 -0
- package/src/records/TLCamera.ts +118 -7
- package/src/records/TLDocument.test.ts +35 -0
- package/src/records/TLDocument.ts +148 -8
- package/src/records/TLInstance.test.ts +201 -0
- package/src/records/TLInstance.ts +117 -9
- package/src/records/TLPage.test.ts +110 -0
- package/src/records/TLPage.ts +106 -8
- package/src/records/TLPageState.test.ts +228 -0
- package/src/records/TLPageState.ts +88 -7
- package/src/records/TLPointer.test.ts +63 -0
- package/src/records/TLPointer.ts +105 -7
- package/src/records/TLPresence.test.ts +190 -0
- package/src/records/TLPresence.ts +99 -5
- package/src/records/TLRecord.test.ts +70 -0
- package/src/records/TLRecord.ts +43 -1
- package/src/records/TLShape.test.ts +232 -0
- package/src/records/TLShape.ts +289 -12
- package/src/recordsWithProps.test.ts +188 -0
- package/src/recordsWithProps.ts +131 -2
- package/src/shapes/ShapeWithCrop.test.ts +18 -0
- package/src/shapes/ShapeWithCrop.ts +64 -2
- package/src/shapes/TLArrowShape.test.ts +505 -0
- package/src/shapes/TLArrowShape.ts +188 -10
- package/src/shapes/TLBaseShape.test.ts +142 -0
- package/src/shapes/TLBaseShape.ts +103 -4
- package/src/shapes/TLBookmarkShape.test.ts +122 -0
- package/src/shapes/TLBookmarkShape.ts +58 -4
- package/src/shapes/TLDrawShape.test.ts +177 -0
- package/src/shapes/TLDrawShape.ts +97 -6
- package/src/shapes/TLEmbedShape.test.ts +286 -0
- package/src/shapes/TLEmbedShape.ts +57 -4
- package/src/shapes/TLFrameShape.test.ts +71 -0
- package/src/shapes/TLFrameShape.ts +59 -4
- package/src/shapes/TLGeoShape.test.ts +247 -0
- package/src/shapes/TLGeoShape.ts +103 -7
- package/src/shapes/TLGroupShape.test.ts +59 -0
- package/src/shapes/TLGroupShape.ts +52 -4
- package/src/shapes/TLHighlightShape.test.ts +325 -0
- package/src/shapes/TLHighlightShape.ts +79 -4
- package/src/shapes/TLImageShape.test.ts +534 -0
- package/src/shapes/TLImageShape.ts +105 -5
- package/src/shapes/TLLineShape.test.ts +269 -0
- package/src/shapes/TLLineShape.ts +128 -8
- package/src/shapes/TLNoteShape.test.ts +1568 -0
- package/src/shapes/TLNoteShape.ts +97 -4
- package/src/shapes/TLTextShape.test.ts +407 -0
- package/src/shapes/TLTextShape.ts +94 -4
- package/src/shapes/TLVideoShape.test.ts +112 -0
- package/src/shapes/TLVideoShape.ts +99 -4
- package/src/store-migrations.test.ts +88 -0
- package/src/store-migrations.ts +47 -1
- package/src/styles/TLColorStyle.test.ts +439 -0
- package/src/styles/TLColorStyle.ts +228 -10
- package/src/styles/TLDashStyle.ts +54 -2
- package/src/styles/TLFillStyle.ts +54 -2
- package/src/styles/TLFontStyle.ts +72 -3
- package/src/styles/TLHorizontalAlignStyle.ts +55 -2
- package/src/styles/TLSizeStyle.ts +54 -2
- package/src/styles/TLTextAlignStyle.ts +52 -2
- package/src/styles/TLVerticalAlignStyle.ts +52 -2
- package/src/translations/translations.test.ts +378 -35
- package/src/translations/translations.ts +157 -10
- package/src/util-types.ts +51 -1
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { getTestMigration } from '../__tests__/migrationTestUtils'
|
|
3
|
+
import { imageAssetVersions } from './TLImageAsset'
|
|
4
|
+
|
|
5
|
+
describe('TLImageAsset', () => {
|
|
6
|
+
describe('AddIsAnimated migration', () => {
|
|
7
|
+
const { up, down } = getTestMigration(imageAssetVersions.AddIsAnimated)
|
|
8
|
+
|
|
9
|
+
it('should add isAnimated property in up migration', () => {
|
|
10
|
+
const assetWithoutIsAnimated = {
|
|
11
|
+
id: 'asset:image1',
|
|
12
|
+
type: 'image',
|
|
13
|
+
props: {
|
|
14
|
+
w: 100,
|
|
15
|
+
h: 100,
|
|
16
|
+
name: 'test.jpg',
|
|
17
|
+
mimeType: 'image/jpeg',
|
|
18
|
+
src: 'https://example.com/test.jpg',
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const result = up(assetWithoutIsAnimated)
|
|
23
|
+
expect(result.props.isAnimated).toBe(false)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('should remove isAnimated property in down migration', () => {
|
|
27
|
+
const assetWithIsAnimated = {
|
|
28
|
+
id: 'asset:image3',
|
|
29
|
+
type: 'image',
|
|
30
|
+
props: {
|
|
31
|
+
w: 100,
|
|
32
|
+
h: 100,
|
|
33
|
+
name: 'test.jpg',
|
|
34
|
+
mimeType: 'image/jpeg',
|
|
35
|
+
src: 'https://example.com/test.jpg',
|
|
36
|
+
isAnimated: false,
|
|
37
|
+
},
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const result = down(assetWithIsAnimated)
|
|
41
|
+
expect(result.props).not.toHaveProperty('isAnimated')
|
|
42
|
+
})
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
describe('RenameWidthHeight migration', () => {
|
|
46
|
+
const { up, down } = getTestMigration(imageAssetVersions.RenameWidthHeight)
|
|
47
|
+
|
|
48
|
+
it('should rename width and height to w and h in up migration', () => {
|
|
49
|
+
const assetWithWidthHeight = {
|
|
50
|
+
id: 'asset:image1',
|
|
51
|
+
type: 'image',
|
|
52
|
+
props: {
|
|
53
|
+
width: 800,
|
|
54
|
+
height: 600,
|
|
55
|
+
name: 'test.jpg',
|
|
56
|
+
isAnimated: false,
|
|
57
|
+
mimeType: 'image/jpeg',
|
|
58
|
+
src: 'https://example.com/test.jpg',
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const result = up(assetWithWidthHeight)
|
|
63
|
+
expect(result.props.w).toBe(800)
|
|
64
|
+
expect(result.props.h).toBe(600)
|
|
65
|
+
expect(result.props).not.toHaveProperty('width')
|
|
66
|
+
expect(result.props).not.toHaveProperty('height')
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('should rename w and h to width and height in down migration', () => {
|
|
70
|
+
const assetWithWH = {
|
|
71
|
+
id: 'asset:image3',
|
|
72
|
+
type: 'image',
|
|
73
|
+
props: {
|
|
74
|
+
w: 1024,
|
|
75
|
+
h: 768,
|
|
76
|
+
name: 'test.png',
|
|
77
|
+
isAnimated: false,
|
|
78
|
+
mimeType: 'image/png',
|
|
79
|
+
src: 'https://example.com/test.png',
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const result = down(assetWithWH)
|
|
84
|
+
expect(result.props.width).toBe(1024)
|
|
85
|
+
expect(result.props.height).toBe(768)
|
|
86
|
+
expect(result.props).not.toHaveProperty('w')
|
|
87
|
+
expect(result.props).not.toHaveProperty('h')
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
describe('MakeUrlsValid migration', () => {
|
|
92
|
+
const { up, down: _down } = getTestMigration(imageAssetVersions.MakeUrlsValid)
|
|
93
|
+
|
|
94
|
+
it('should clean invalid src URLs in up migration', () => {
|
|
95
|
+
const assetWithInvalidSrc = {
|
|
96
|
+
id: 'asset:image1',
|
|
97
|
+
type: 'image',
|
|
98
|
+
props: {
|
|
99
|
+
w: 100,
|
|
100
|
+
h: 100,
|
|
101
|
+
name: 'test.jpg',
|
|
102
|
+
isAnimated: false,
|
|
103
|
+
mimeType: 'image/jpeg',
|
|
104
|
+
src: 'invalid-url-format',
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const result = up(assetWithInvalidSrc)
|
|
109
|
+
expect(result.props.src).toBe('')
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it('should preserve valid src URLs in up migration', () => {
|
|
113
|
+
const assetWithValidSrc = {
|
|
114
|
+
id: 'asset:image2',
|
|
115
|
+
type: 'image',
|
|
116
|
+
props: {
|
|
117
|
+
w: 100,
|
|
118
|
+
h: 100,
|
|
119
|
+
name: 'test.jpg',
|
|
120
|
+
isAnimated: false,
|
|
121
|
+
mimeType: 'image/jpeg',
|
|
122
|
+
src: 'https://example.com/test.jpg',
|
|
123
|
+
},
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const result = up(assetWithValidSrc)
|
|
127
|
+
expect(result.props.src).toBe('https://example.com/test.jpg')
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
describe('AddFileSize migration', () => {
|
|
132
|
+
const { up, down } = getTestMigration(imageAssetVersions.AddFileSize)
|
|
133
|
+
|
|
134
|
+
it('should add fileSize property with -1 default in up migration', () => {
|
|
135
|
+
const assetWithoutFileSize = {
|
|
136
|
+
id: 'asset:image1',
|
|
137
|
+
type: 'image',
|
|
138
|
+
props: {
|
|
139
|
+
w: 100,
|
|
140
|
+
h: 100,
|
|
141
|
+
name: 'test.jpg',
|
|
142
|
+
isAnimated: false,
|
|
143
|
+
mimeType: 'image/jpeg',
|
|
144
|
+
src: 'https://example.com/test.jpg',
|
|
145
|
+
},
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const result = up(assetWithoutFileSize)
|
|
149
|
+
expect(result.props.fileSize).toBe(-1)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
it('should remove fileSize property in down migration', () => {
|
|
153
|
+
const assetWithFileSize = {
|
|
154
|
+
id: 'asset:image3',
|
|
155
|
+
type: 'image',
|
|
156
|
+
props: {
|
|
157
|
+
w: 100,
|
|
158
|
+
h: 100,
|
|
159
|
+
name: 'test.jpg',
|
|
160
|
+
isAnimated: false,
|
|
161
|
+
mimeType: 'image/jpeg',
|
|
162
|
+
src: 'https://example.com/test.jpg',
|
|
163
|
+
fileSize: 50000,
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const result = down(assetWithFileSize)
|
|
168
|
+
expect(result.props).not.toHaveProperty('fileSize')
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
describe('MakeFileSizeOptional migration', () => {
|
|
173
|
+
const { up, down } = getTestMigration(imageAssetVersions.MakeFileSizeOptional)
|
|
174
|
+
|
|
175
|
+
it('should convert fileSize -1 to undefined in up migration', () => {
|
|
176
|
+
const assetWithNegativeFileSize = {
|
|
177
|
+
id: 'asset:image1',
|
|
178
|
+
type: 'image',
|
|
179
|
+
props: {
|
|
180
|
+
w: 100,
|
|
181
|
+
h: 100,
|
|
182
|
+
name: 'test.jpg',
|
|
183
|
+
isAnimated: false,
|
|
184
|
+
mimeType: 'image/jpeg',
|
|
185
|
+
src: 'https://example.com/test.jpg',
|
|
186
|
+
fileSize: -1,
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const result = up(assetWithNegativeFileSize)
|
|
191
|
+
expect(result.props.fileSize).toBeUndefined()
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it('should convert undefined fileSize to -1 in down migration', () => {
|
|
195
|
+
const assetWithUndefinedFileSize = {
|
|
196
|
+
id: 'asset:image5',
|
|
197
|
+
type: 'image',
|
|
198
|
+
props: {
|
|
199
|
+
w: 100,
|
|
200
|
+
h: 100,
|
|
201
|
+
name: 'test.jpg',
|
|
202
|
+
isAnimated: false,
|
|
203
|
+
mimeType: 'image/jpeg',
|
|
204
|
+
src: 'https://example.com/test.jpg',
|
|
205
|
+
fileSize: undefined,
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const result = down(assetWithUndefinedFileSize)
|
|
210
|
+
expect(result.props.fileSize).toBe(-1)
|
|
211
|
+
})
|
|
212
|
+
})
|
|
213
|
+
})
|
|
@@ -20,7 +20,36 @@ export type TLImageAsset = TLBaseAsset<
|
|
|
20
20
|
}
|
|
21
21
|
>
|
|
22
22
|
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Validator for image assets. Validates the structure and properties of TLImageAsset records
|
|
25
|
+
* to ensure data integrity when image assets are stored or retrieved from the tldraw store.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* import { imageAssetValidator } from '@tldraw/tlschema'
|
|
30
|
+
*
|
|
31
|
+
* const imageAsset = {
|
|
32
|
+
* id: 'asset:image123',
|
|
33
|
+
* typeName: 'asset',
|
|
34
|
+
* type: 'image',
|
|
35
|
+
* props: {
|
|
36
|
+
* w: 800,
|
|
37
|
+
* h: 600,
|
|
38
|
+
* name: 'photo.jpg',
|
|
39
|
+
* isAnimated: false,
|
|
40
|
+
* mimeType: 'image/jpeg',
|
|
41
|
+
* src: 'https://example.com/photo.jpg',
|
|
42
|
+
* fileSize: 156000
|
|
43
|
+
* },
|
|
44
|
+
* meta: {}
|
|
45
|
+
* }
|
|
46
|
+
*
|
|
47
|
+
* // Validate the asset
|
|
48
|
+
* const isValid = imageAssetValidator.validate(imageAsset)
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
24
53
|
export const imageAssetValidator: T.Validator<TLImageAsset> = createAssetValidator(
|
|
25
54
|
'image',
|
|
26
55
|
T.object({
|
|
@@ -42,9 +71,38 @@ const Versions = createMigrationIds('com.tldraw.asset.image', {
|
|
|
42
71
|
MakeFileSizeOptional: 5,
|
|
43
72
|
} as const)
|
|
44
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Migration version identifiers for image assets. These define the different schema versions
|
|
76
|
+
* that image assets have gone through during the evolution of the tldraw data model.
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* import { imageAssetVersions } from '@tldraw/tlschema'
|
|
81
|
+
*
|
|
82
|
+
* // Access specific version IDs
|
|
83
|
+
* console.log(imageAssetVersions.AddIsAnimated) // Version when isAnimated was added
|
|
84
|
+
* console.log(imageAssetVersions.RenameWidthHeight) // Version when width/height became w/h
|
|
85
|
+
* ```
|
|
86
|
+
*
|
|
87
|
+
* @public
|
|
88
|
+
*/
|
|
45
89
|
export { Versions as imageAssetVersions }
|
|
46
90
|
|
|
47
|
-
/**
|
|
91
|
+
/**
|
|
92
|
+
* Migration sequence for image assets. Handles the evolution of the image asset schema
|
|
93
|
+
* over time, providing both forward (up) and backward (down) migration functions to
|
|
94
|
+
* maintain compatibility across different versions of the tldraw data model.
|
|
95
|
+
*
|
|
96
|
+
* The sequence includes migrations for:
|
|
97
|
+
* - Adding the `isAnimated` property to track animated images
|
|
98
|
+
* - Renaming `width`/`height` properties to shorter `w`/`h` names
|
|
99
|
+
* - Ensuring URLs are valid format
|
|
100
|
+
* - Adding file size tracking
|
|
101
|
+
* - Making file size optional
|
|
102
|
+
*
|
|
103
|
+
*
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
48
106
|
export const imageAssetMigrations = createRecordMigrationSequence({
|
|
49
107
|
sequenceId: 'com.tldraw.asset.image',
|
|
50
108
|
recordType: 'asset',
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { getTestMigration } from '../__tests__/migrationTestUtils'
|
|
3
|
+
import { videoAssetVersions } from './TLVideoAsset'
|
|
4
|
+
|
|
5
|
+
describe('TLVideoAsset', () => {
|
|
6
|
+
describe('migrations', () => {
|
|
7
|
+
it('should handle AddIsAnimated migration', () => {
|
|
8
|
+
const { up, down } = getTestMigration(videoAssetVersions.AddIsAnimated)
|
|
9
|
+
|
|
10
|
+
const assetWithoutIsAnimated = {
|
|
11
|
+
id: 'asset:video1',
|
|
12
|
+
type: 'video',
|
|
13
|
+
props: {
|
|
14
|
+
w: 640,
|
|
15
|
+
h: 480,
|
|
16
|
+
name: 'test.mp4',
|
|
17
|
+
mimeType: 'video/mp4',
|
|
18
|
+
src: 'https://example.com/test.mp4',
|
|
19
|
+
},
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const upResult = up(assetWithoutIsAnimated)
|
|
23
|
+
expect(upResult.props.isAnimated).toBe(false)
|
|
24
|
+
|
|
25
|
+
const downResult = down(upResult)
|
|
26
|
+
expect(downResult.props).not.toHaveProperty('isAnimated')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should handle RenameWidthHeight migration', () => {
|
|
30
|
+
const { up, down } = getTestMigration(videoAssetVersions.RenameWidthHeight)
|
|
31
|
+
|
|
32
|
+
const assetWithWidthHeight = {
|
|
33
|
+
id: 'asset:video1',
|
|
34
|
+
type: 'video',
|
|
35
|
+
props: {
|
|
36
|
+
width: 1920,
|
|
37
|
+
height: 1080,
|
|
38
|
+
name: 'test.mp4',
|
|
39
|
+
isAnimated: true,
|
|
40
|
+
mimeType: 'video/mp4',
|
|
41
|
+
src: 'https://example.com/test.mp4',
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const upResult = up(assetWithWidthHeight)
|
|
46
|
+
expect(upResult.props.w).toBe(1920)
|
|
47
|
+
expect(upResult.props.h).toBe(1080)
|
|
48
|
+
expect(upResult.props).not.toHaveProperty('width')
|
|
49
|
+
expect(upResult.props).not.toHaveProperty('height')
|
|
50
|
+
|
|
51
|
+
const downResult = down(upResult)
|
|
52
|
+
expect(downResult.props.width).toBe(1920)
|
|
53
|
+
expect(downResult.props.height).toBe(1080)
|
|
54
|
+
expect(downResult.props).not.toHaveProperty('w')
|
|
55
|
+
expect(downResult.props).not.toHaveProperty('h')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('should handle MakeUrlsValid migration', () => {
|
|
59
|
+
const { up } = getTestMigration(videoAssetVersions.MakeUrlsValid)
|
|
60
|
+
|
|
61
|
+
const assetWithInvalidSrc = {
|
|
62
|
+
id: 'asset:video1',
|
|
63
|
+
type: 'video',
|
|
64
|
+
props: {
|
|
65
|
+
w: 640,
|
|
66
|
+
h: 480,
|
|
67
|
+
name: 'test.mp4',
|
|
68
|
+
isAnimated: true,
|
|
69
|
+
mimeType: 'video/mp4',
|
|
70
|
+
src: 'invalid-url-format',
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const result = up(assetWithInvalidSrc)
|
|
75
|
+
expect(result.props.src).toBe('')
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('should handle MakeFileSizeOptional migration', () => {
|
|
79
|
+
const { up, down } = getTestMigration(videoAssetVersions.MakeFileSizeOptional)
|
|
80
|
+
|
|
81
|
+
const assetWithNegativeFileSize = {
|
|
82
|
+
id: 'asset:video1',
|
|
83
|
+
type: 'video',
|
|
84
|
+
props: {
|
|
85
|
+
w: 640,
|
|
86
|
+
h: 480,
|
|
87
|
+
name: 'test.mp4',
|
|
88
|
+
isAnimated: true,
|
|
89
|
+
mimeType: 'video/mp4',
|
|
90
|
+
src: 'https://example.com/test.mp4',
|
|
91
|
+
fileSize: -1,
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const upResult = up(assetWithNegativeFileSize)
|
|
96
|
+
expect(upResult.props.fileSize).toBeUndefined()
|
|
97
|
+
|
|
98
|
+
const downResult = down({
|
|
99
|
+
...assetWithNegativeFileSize,
|
|
100
|
+
props: { ...assetWithNegativeFileSize.props, fileSize: undefined },
|
|
101
|
+
})
|
|
102
|
+
expect(downResult.props.fileSize).toBe(-1)
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
})
|
|
@@ -4,23 +4,83 @@ import { TLAsset } from '../records/TLAsset'
|
|
|
4
4
|
import { TLBaseAsset, createAssetValidator } from './TLBaseAsset'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* An asset
|
|
7
|
+
* An asset record representing video files that can be displayed in video shapes.
|
|
8
|
+
* Video assets store metadata about video files including dimensions, MIME type,
|
|
9
|
+
* animation status, and file source information. They are referenced by TLVideoShape
|
|
10
|
+
* instances to display video content on the canvas.
|
|
8
11
|
*
|
|
9
|
-
* @
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { TLVideoAsset } from '@tldraw/tlschema'
|
|
15
|
+
*
|
|
16
|
+
* const videoAsset: TLVideoAsset = {
|
|
17
|
+
* id: 'asset:video123',
|
|
18
|
+
* typeName: 'asset',
|
|
19
|
+
* type: 'video',
|
|
20
|
+
* props: {
|
|
21
|
+
* w: 1920,
|
|
22
|
+
* h: 1080,
|
|
23
|
+
* name: 'my-video.mp4',
|
|
24
|
+
* isAnimated: true,
|
|
25
|
+
* mimeType: 'video/mp4',
|
|
26
|
+
* src: 'https://example.com/video.mp4',
|
|
27
|
+
* fileSize: 5242880
|
|
28
|
+
* },
|
|
29
|
+
* meta: {}
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
10
35
|
export type TLVideoAsset = TLBaseAsset<
|
|
11
36
|
'video',
|
|
12
37
|
{
|
|
38
|
+
/** The width of the video in pixels */
|
|
13
39
|
w: number
|
|
40
|
+
/** The height of the video in pixels */
|
|
14
41
|
h: number
|
|
42
|
+
/** The original filename or display name of the video */
|
|
15
43
|
name: string
|
|
44
|
+
/** Whether the video contains animation/motion (true for most videos) */
|
|
16
45
|
isAnimated: boolean
|
|
46
|
+
/** The MIME type of the video file (e.g., 'video/mp4', 'video/webm'), null if unknown */
|
|
17
47
|
mimeType: string | null
|
|
48
|
+
/** The source URL or data URI for the video file, null if not yet available */
|
|
18
49
|
src: string | null
|
|
50
|
+
/** The file size in bytes, optional for backward compatibility */
|
|
19
51
|
fileSize?: number
|
|
20
52
|
}
|
|
21
53
|
>
|
|
22
54
|
|
|
23
|
-
/**
|
|
55
|
+
/**
|
|
56
|
+
* Runtime validator for TLVideoAsset records. This validator ensures that video asset
|
|
57
|
+
* data conforms to the expected structure and types, providing type safety at runtime.
|
|
58
|
+
* It validates dimensions, file metadata, and ensures URLs are properly formatted.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import { videoAssetValidator } from '@tldraw/tlschema'
|
|
63
|
+
*
|
|
64
|
+
* // Validate a video asset object
|
|
65
|
+
* const validAsset = videoAssetValidator.validate({
|
|
66
|
+
* id: 'asset:video123',
|
|
67
|
+
* typeName: 'asset',
|
|
68
|
+
* type: 'video',
|
|
69
|
+
* props: {
|
|
70
|
+
* w: 1920,
|
|
71
|
+
* h: 1080,
|
|
72
|
+
* name: 'video.mp4',
|
|
73
|
+
* isAnimated: true,
|
|
74
|
+
* mimeType: 'video/mp4',
|
|
75
|
+
* src: 'https://example.com/video.mp4',
|
|
76
|
+
* fileSize: 1024000
|
|
77
|
+
* },
|
|
78
|
+
* meta: {}
|
|
79
|
+
* })
|
|
80
|
+
* ```
|
|
81
|
+
*
|
|
82
|
+
* @public
|
|
83
|
+
*/
|
|
24
84
|
export const videoAssetValidator: T.Validator<TLVideoAsset> = createAssetValidator(
|
|
25
85
|
'video',
|
|
26
86
|
T.object({
|
|
@@ -42,9 +102,38 @@ const Versions = createMigrationIds('com.tldraw.asset.video', {
|
|
|
42
102
|
MakeFileSizeOptional: 5,
|
|
43
103
|
} as const)
|
|
44
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Version identifiers for video asset migration sequences. These versions track
|
|
107
|
+
* the evolution of the video asset schema over time, enabling proper data migration
|
|
108
|
+
* when the asset structure changes.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```ts
|
|
112
|
+
* import { videoAssetVersions } from '@tldraw/tlschema'
|
|
113
|
+
*
|
|
114
|
+
* // Check the current version of a specific migration
|
|
115
|
+
* console.log(videoAssetVersions.AddFileSize) // 4
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* @public
|
|
119
|
+
*/
|
|
45
120
|
export { Versions as videoAssetVersions }
|
|
46
121
|
|
|
47
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* Migration sequence for video assets that handles schema evolution over time.
|
|
124
|
+
* This sequence defines how video asset data should be transformed when upgrading
|
|
125
|
+
* or downgrading between different schema versions. Each migration step handles
|
|
126
|
+
* specific changes like adding properties, renaming fields, or changing data formats.
|
|
127
|
+
*
|
|
128
|
+
* The migrations handle:
|
|
129
|
+
* - Adding animation detection (isAnimated property)
|
|
130
|
+
* - Renaming width/height properties to w/h for consistency
|
|
131
|
+
* - Ensuring URL validity for src properties
|
|
132
|
+
* - Adding file size tracking
|
|
133
|
+
* - Making file size optional for backward compatibility
|
|
134
|
+
*
|
|
135
|
+
* @public
|
|
136
|
+
*/
|
|
48
137
|
export const videoAssetMigrations = createRecordMigrationSequence({
|
|
49
138
|
sequenceId: 'com.tldraw.asset.video',
|
|
50
139
|
recordType: 'asset',
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { getTestMigration } from '../__tests__/migrationTestUtils'
|
|
3
|
+
import { arrowBindingVersions } from './TLArrowBinding'
|
|
4
|
+
|
|
5
|
+
describe('TLArrowBinding', () => {
|
|
6
|
+
describe('AddSnap migration', () => {
|
|
7
|
+
const { up, down } = getTestMigration(arrowBindingVersions.AddSnap)
|
|
8
|
+
|
|
9
|
+
it('should add snap property with default value "none"', () => {
|
|
10
|
+
const oldRecord = {
|
|
11
|
+
props: {
|
|
12
|
+
terminal: 'end',
|
|
13
|
+
normalizedAnchor: { x: 0.5, y: 0.5 },
|
|
14
|
+
isExact: true,
|
|
15
|
+
isPrecise: false,
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const result = up(oldRecord)
|
|
20
|
+
expect(result.props.snap).toBe('none')
|
|
21
|
+
expect(result.props.terminal).toBe('end')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should remove snap property on down migration', () => {
|
|
25
|
+
const newRecord = {
|
|
26
|
+
props: {
|
|
27
|
+
terminal: 'end',
|
|
28
|
+
normalizedAnchor: { x: 0.5, y: 0.5 },
|
|
29
|
+
isExact: true,
|
|
30
|
+
isPrecise: false,
|
|
31
|
+
snap: 'center',
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const result = down(newRecord)
|
|
36
|
+
expect(result.props.snap).toBeUndefined()
|
|
37
|
+
expect(result.props.terminal).toBe('end')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should be reversible', () => {
|
|
41
|
+
const originalRecord = {
|
|
42
|
+
props: {
|
|
43
|
+
terminal: 'start',
|
|
44
|
+
normalizedAnchor: { x: 0.5, y: 0.5 },
|
|
45
|
+
isExact: true,
|
|
46
|
+
isPrecise: false,
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const upResult = up(originalRecord)
|
|
51
|
+
const downResult = down(upResult)
|
|
52
|
+
expect(downResult.props).toEqual(originalRecord.props)
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
})
|