@tldraw/tlschema 4.1.0-canary.8e597b345c40 → 4.1.0-canary.95d46c96eb30
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 +4412 -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 +4412 -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 +82 -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,234 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { getTestMigration } from '../__tests__/migrationTestUtils'
|
|
3
|
+
import {
|
|
4
|
+
assetMigrations,
|
|
5
|
+
AssetRecordType,
|
|
6
|
+
assetValidator,
|
|
7
|
+
assetVersions,
|
|
8
|
+
TLAssetId,
|
|
9
|
+
} from './TLAsset'
|
|
10
|
+
|
|
11
|
+
describe('TLAsset', () => {
|
|
12
|
+
describe('assetValidator', () => {
|
|
13
|
+
it('should validate different asset types using discriminated union', () => {
|
|
14
|
+
const imageAsset = {
|
|
15
|
+
id: 'asset:test_image',
|
|
16
|
+
typeName: 'asset' as const,
|
|
17
|
+
type: 'image' as const,
|
|
18
|
+
props: {
|
|
19
|
+
w: 100,
|
|
20
|
+
h: 100,
|
|
21
|
+
name: 'test.jpg',
|
|
22
|
+
isAnimated: false,
|
|
23
|
+
mimeType: 'image/jpeg',
|
|
24
|
+
src: 'https://example.com/test.jpg',
|
|
25
|
+
},
|
|
26
|
+
meta: {},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const videoAsset = {
|
|
30
|
+
id: 'asset:test_video',
|
|
31
|
+
typeName: 'asset' as const,
|
|
32
|
+
type: 'video' as const,
|
|
33
|
+
props: {
|
|
34
|
+
w: 640,
|
|
35
|
+
h: 480,
|
|
36
|
+
name: 'test.mp4',
|
|
37
|
+
isAnimated: true,
|
|
38
|
+
mimeType: 'video/mp4',
|
|
39
|
+
src: 'https://example.com/test.mp4',
|
|
40
|
+
},
|
|
41
|
+
meta: {},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const bookmarkAsset = {
|
|
45
|
+
id: 'asset:test_bookmark',
|
|
46
|
+
typeName: 'asset' as const,
|
|
47
|
+
type: 'bookmark' as const,
|
|
48
|
+
props: {
|
|
49
|
+
title: 'Test Site',
|
|
50
|
+
description: 'A test bookmark',
|
|
51
|
+
image: 'https://example.com/image.png',
|
|
52
|
+
favicon: 'https://example.com/favicon.ico',
|
|
53
|
+
src: 'https://example.com',
|
|
54
|
+
},
|
|
55
|
+
meta: {},
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
expect(() => assetValidator.validate(imageAsset)).not.toThrow()
|
|
59
|
+
expect(() => assetValidator.validate(videoAsset)).not.toThrow()
|
|
60
|
+
expect(() => assetValidator.validate(bookmarkAsset)).not.toThrow()
|
|
61
|
+
|
|
62
|
+
expect(assetValidator.validate(imageAsset).type).toBe('image')
|
|
63
|
+
expect(assetValidator.validate(videoAsset).type).toBe('video')
|
|
64
|
+
expect(assetValidator.validate(bookmarkAsset).type).toBe('bookmark')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('should reject invalid asset types', () => {
|
|
68
|
+
const invalidAsset = {
|
|
69
|
+
id: 'asset:invalid',
|
|
70
|
+
typeName: 'asset' as const,
|
|
71
|
+
type: 'invalid_type' as any,
|
|
72
|
+
props: {
|
|
73
|
+
w: 100,
|
|
74
|
+
h: 100,
|
|
75
|
+
name: 'test.jpg',
|
|
76
|
+
},
|
|
77
|
+
meta: {},
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
expect(() => assetValidator.validate(invalidAsset)).toThrow()
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('should require valid asset structure', () => {
|
|
84
|
+
// Wrong typeName
|
|
85
|
+
const wrongTypeName = {
|
|
86
|
+
id: 'asset:wrong_typename',
|
|
87
|
+
typeName: 'shape' as const,
|
|
88
|
+
type: 'image' as const,
|
|
89
|
+
props: {
|
|
90
|
+
w: 100,
|
|
91
|
+
h: 100,
|
|
92
|
+
name: 'test.jpg',
|
|
93
|
+
isAnimated: false,
|
|
94
|
+
mimeType: 'image/jpeg',
|
|
95
|
+
src: 'https://example.com/test.jpg',
|
|
96
|
+
},
|
|
97
|
+
meta: {},
|
|
98
|
+
}
|
|
99
|
+
expect(() => assetValidator.validate(wrongTypeName)).toThrow()
|
|
100
|
+
|
|
101
|
+
// Missing meta
|
|
102
|
+
const noMeta = {
|
|
103
|
+
id: 'asset:no_meta',
|
|
104
|
+
typeName: 'asset' as const,
|
|
105
|
+
type: 'image' as const,
|
|
106
|
+
props: {
|
|
107
|
+
w: 100,
|
|
108
|
+
h: 100,
|
|
109
|
+
name: 'test.jpg',
|
|
110
|
+
isAnimated: false,
|
|
111
|
+
mimeType: 'image/jpeg',
|
|
112
|
+
src: 'https://example.com/test.jpg',
|
|
113
|
+
},
|
|
114
|
+
}
|
|
115
|
+
expect(() => assetValidator.validate(noMeta)).toThrow()
|
|
116
|
+
|
|
117
|
+
// Wrong ID prefix
|
|
118
|
+
const wrongId = {
|
|
119
|
+
id: 'shape:wrong_prefix',
|
|
120
|
+
typeName: 'asset' as const,
|
|
121
|
+
type: 'image' as const,
|
|
122
|
+
props: {
|
|
123
|
+
w: 100,
|
|
124
|
+
h: 100,
|
|
125
|
+
name: 'test.jpg',
|
|
126
|
+
isAnimated: false,
|
|
127
|
+
mimeType: 'image/jpeg',
|
|
128
|
+
src: 'https://example.com/test.jpg',
|
|
129
|
+
},
|
|
130
|
+
meta: {},
|
|
131
|
+
}
|
|
132
|
+
expect(() => assetValidator.validate(wrongId)).toThrow()
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
describe('assetMigrations', () => {
|
|
137
|
+
it('should have correct migration structure', () => {
|
|
138
|
+
expect(assetMigrations.sequenceId).toBe('com.tldraw.asset')
|
|
139
|
+
expect(assetMigrations.sequence).toHaveLength(1)
|
|
140
|
+
expect(assetMigrations.sequence[0].id).toBe(assetVersions.AddMeta)
|
|
141
|
+
})
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
describe('AddMeta migration', () => {
|
|
145
|
+
const { up } = getTestMigration(assetVersions.AddMeta)
|
|
146
|
+
|
|
147
|
+
it('should add empty meta property', () => {
|
|
148
|
+
const assetWithoutMeta = {
|
|
149
|
+
id: 'asset:test',
|
|
150
|
+
typeName: 'asset',
|
|
151
|
+
type: 'image',
|
|
152
|
+
props: {
|
|
153
|
+
w: 100,
|
|
154
|
+
h: 100,
|
|
155
|
+
name: 'test.jpg',
|
|
156
|
+
isAnimated: false,
|
|
157
|
+
mimeType: 'image/jpeg',
|
|
158
|
+
src: 'https://example.com/test.jpg',
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const result = up(assetWithoutMeta)
|
|
163
|
+
expect(result.meta).toEqual({})
|
|
164
|
+
expect(result.props).toEqual(assetWithoutMeta.props)
|
|
165
|
+
})
|
|
166
|
+
|
|
167
|
+
it('should overwrite existing meta property', () => {
|
|
168
|
+
const assetWithMeta = {
|
|
169
|
+
id: 'asset:test',
|
|
170
|
+
typeName: 'asset',
|
|
171
|
+
type: 'image',
|
|
172
|
+
props: {
|
|
173
|
+
w: 100,
|
|
174
|
+
h: 100,
|
|
175
|
+
name: 'test.jpg',
|
|
176
|
+
isAnimated: false,
|
|
177
|
+
mimeType: 'image/jpeg',
|
|
178
|
+
src: 'https://example.com/test.jpg',
|
|
179
|
+
},
|
|
180
|
+
meta: { existing: 'data' },
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const result = up(assetWithMeta)
|
|
184
|
+
expect(result.meta).toEqual({}) // Migration always sets to empty object
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('should preserve other properties during migration', () => {
|
|
188
|
+
const assetWithExtraProps = {
|
|
189
|
+
id: 'asset:extra_props',
|
|
190
|
+
typeName: 'asset',
|
|
191
|
+
type: 'image',
|
|
192
|
+
props: {
|
|
193
|
+
w: 200,
|
|
194
|
+
h: 150,
|
|
195
|
+
name: 'extra.png',
|
|
196
|
+
isAnimated: false,
|
|
197
|
+
mimeType: 'image/png',
|
|
198
|
+
src: 'https://example.com/extra.png',
|
|
199
|
+
},
|
|
200
|
+
customProperty: 'should be preserved',
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const result = up(assetWithExtraProps)
|
|
204
|
+
expect(result.meta).toEqual({})
|
|
205
|
+
expect(result.customProperty).toBe('should be preserved')
|
|
206
|
+
})
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
describe('AssetRecordType', () => {
|
|
210
|
+
it('should have correct configuration', () => {
|
|
211
|
+
expect(AssetRecordType.typeName).toBe('asset')
|
|
212
|
+
expect(AssetRecordType.scope).toBe('document')
|
|
213
|
+
expect(AssetRecordType.validator).toBe(assetValidator)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
it('should create records with default meta property', () => {
|
|
217
|
+
const assetRecord = AssetRecordType.create({
|
|
218
|
+
id: 'asset:test' as TLAssetId,
|
|
219
|
+
type: 'image',
|
|
220
|
+
props: {
|
|
221
|
+
w: 100,
|
|
222
|
+
h: 100,
|
|
223
|
+
name: 'test.jpg',
|
|
224
|
+
isAnimated: false,
|
|
225
|
+
mimeType: 'image/jpeg',
|
|
226
|
+
src: 'https://example.com/test.jpg',
|
|
227
|
+
},
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
expect(assetRecord.meta).toEqual({})
|
|
231
|
+
expect(assetRecord.typeName).toBe('asset')
|
|
232
|
+
})
|
|
233
|
+
})
|
|
234
|
+
})
|
package/src/records/TLAsset.ts
CHANGED
|
@@ -11,10 +11,48 @@ import { imageAssetValidator, TLImageAsset } from '../assets/TLImageAsset'
|
|
|
11
11
|
import { TLVideoAsset, videoAssetValidator } from '../assets/TLVideoAsset'
|
|
12
12
|
import { TLShape } from './TLShape'
|
|
13
13
|
|
|
14
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Union type representing all possible asset types in tldraw.
|
|
16
|
+
* Assets represent external resources like images, videos, or bookmarks that can be referenced by shapes.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const imageAsset: TLAsset = {
|
|
21
|
+
* id: 'asset:image123',
|
|
22
|
+
* typeName: 'asset',
|
|
23
|
+
* type: 'image',
|
|
24
|
+
* props: {
|
|
25
|
+
* src: 'https://example.com/image.jpg',
|
|
26
|
+
* w: 800,
|
|
27
|
+
* h: 600,
|
|
28
|
+
* mimeType: 'image/jpeg',
|
|
29
|
+
* isAnimated: false
|
|
30
|
+
* },
|
|
31
|
+
* meta: {}
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
15
37
|
export type TLAsset = TLImageAsset | TLVideoAsset | TLBookmarkAsset
|
|
16
38
|
|
|
17
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Validator for TLAsset records that ensures runtime type safety.
|
|
41
|
+
* Uses a discriminated union based on the 'type' field to validate different asset types.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* // Validation happens automatically when assets are stored
|
|
46
|
+
* try {
|
|
47
|
+
* const validatedAsset = assetValidator.validate(assetData)
|
|
48
|
+
* store.put([validatedAsset])
|
|
49
|
+
* } catch (error) {
|
|
50
|
+
* console.error('Asset validation failed:', error.message)
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @public
|
|
55
|
+
*/
|
|
18
56
|
export const assetValidator: T.Validator<TLAsset> = T.model(
|
|
19
57
|
'asset',
|
|
20
58
|
T.union('type', {
|
|
@@ -24,12 +62,37 @@ export const assetValidator: T.Validator<TLAsset> = T.model(
|
|
|
24
62
|
})
|
|
25
63
|
)
|
|
26
64
|
|
|
27
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Migration version identifiers for asset record schema evolution.
|
|
67
|
+
* Each version represents a breaking change that requires data migration.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* // Check if a migration is needed
|
|
72
|
+
* const needsMigration = currentVersion < assetVersions.AddMeta
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @public
|
|
76
|
+
*/
|
|
28
77
|
export const assetVersions = createMigrationIds('com.tldraw.asset', {
|
|
29
78
|
AddMeta: 1,
|
|
30
79
|
} as const)
|
|
31
80
|
|
|
32
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Migration sequence for evolving asset record structure over time.
|
|
83
|
+
* Handles converting asset records from older schema versions to current format.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* // Migration is applied automatically when loading old documents
|
|
88
|
+
* const migratedStore = migrator.migrateStoreSnapshot({
|
|
89
|
+
* schema: oldSchema,
|
|
90
|
+
* store: oldStoreSnapshot
|
|
91
|
+
* })
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @public
|
|
95
|
+
*/
|
|
33
96
|
export const assetMigrations = createRecordMigrationSequence({
|
|
34
97
|
sequenceId: 'com.tldraw.asset',
|
|
35
98
|
recordType: 'asset',
|
|
@@ -43,7 +106,27 @@ export const assetMigrations = createRecordMigrationSequence({
|
|
|
43
106
|
],
|
|
44
107
|
})
|
|
45
108
|
|
|
46
|
-
/**
|
|
109
|
+
/**
|
|
110
|
+
* Partial type for TLAsset allowing optional properties except id and type.
|
|
111
|
+
* Useful for creating or updating assets where not all properties need to be specified.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* // Create a partial asset for updating
|
|
116
|
+
* const partialAsset: TLAssetPartial<TLImageAsset> = {
|
|
117
|
+
* id: 'asset:image123',
|
|
118
|
+
* type: 'image',
|
|
119
|
+
* props: {
|
|
120
|
+
* w: 800 // Only updating width
|
|
121
|
+
* }
|
|
122
|
+
* }
|
|
123
|
+
*
|
|
124
|
+
* // Use in asset updates
|
|
125
|
+
* editor.updateAssets([partialAsset])
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* @public
|
|
129
|
+
*/
|
|
47
130
|
export type TLAssetPartial<T extends TLAsset = TLAsset> = T extends T
|
|
48
131
|
? {
|
|
49
132
|
id: TLAssetId
|
|
@@ -53,7 +136,31 @@ export type TLAssetPartial<T extends TLAsset = TLAsset> = T extends T
|
|
|
53
136
|
} & Partial<Omit<T, 'type' | 'id' | 'props' | 'meta'>>
|
|
54
137
|
: never
|
|
55
138
|
|
|
56
|
-
/**
|
|
139
|
+
/**
|
|
140
|
+
* Record type definition for TLAsset with validation and default properties.
|
|
141
|
+
* Configures assets as document-scoped records that persist across sessions.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* // Create a new asset record
|
|
146
|
+
* const assetRecord = AssetRecordType.create({
|
|
147
|
+
* id: 'asset:image123',
|
|
148
|
+
* type: 'image',
|
|
149
|
+
* props: {
|
|
150
|
+
* src: 'https://example.com/image.jpg',
|
|
151
|
+
* w: 800,
|
|
152
|
+
* h: 600,
|
|
153
|
+
* mimeType: 'image/jpeg',
|
|
154
|
+
* isAnimated: false
|
|
155
|
+
* }
|
|
156
|
+
* })
|
|
157
|
+
*
|
|
158
|
+
* // Store the asset
|
|
159
|
+
* store.put([assetRecord])
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* @public
|
|
163
|
+
*/
|
|
57
164
|
export const AssetRecordType = createRecordType<TLAsset>('asset', {
|
|
58
165
|
validator: assetValidator,
|
|
59
166
|
scope: 'document',
|
|
@@ -61,8 +168,58 @@ export const AssetRecordType = createRecordType<TLAsset>('asset', {
|
|
|
61
168
|
meta: {},
|
|
62
169
|
}))
|
|
63
170
|
|
|
64
|
-
/**
|
|
171
|
+
/**
|
|
172
|
+
* Branded string type for asset record identifiers.
|
|
173
|
+
* Prevents mixing asset IDs with other types of record IDs at compile time.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```ts
|
|
177
|
+
* import { createAssetId } from '@tldraw/tlschema'
|
|
178
|
+
*
|
|
179
|
+
* // Create a new asset ID
|
|
180
|
+
* const assetId: TLAssetId = createAssetId()
|
|
181
|
+
*
|
|
182
|
+
* // Use in asset records
|
|
183
|
+
* const asset: TLAsset = {
|
|
184
|
+
* id: assetId,
|
|
185
|
+
* // ... other properties
|
|
186
|
+
* }
|
|
187
|
+
*
|
|
188
|
+
* // Reference in shapes
|
|
189
|
+
* const imageShape: TLImageShape = {
|
|
190
|
+
* props: {
|
|
191
|
+
* assetId: assetId,
|
|
192
|
+
* // ... other properties
|
|
193
|
+
* }
|
|
194
|
+
* }
|
|
195
|
+
* ```
|
|
196
|
+
*
|
|
197
|
+
* @public
|
|
198
|
+
*/
|
|
65
199
|
export type TLAssetId = RecordId<TLBaseAsset<any, any>>
|
|
66
200
|
|
|
67
|
-
/**
|
|
201
|
+
/**
|
|
202
|
+
* Union type of all shapes that reference assets through an assetId property.
|
|
203
|
+
* Includes image shapes, video shapes, and any other shapes that depend on external assets.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```ts
|
|
207
|
+
* // Function that works with any asset-based shape
|
|
208
|
+
* function handleAssetShape(shape: TLAssetShape) {
|
|
209
|
+
* const assetId = shape.props.assetId
|
|
210
|
+
* if (assetId) {
|
|
211
|
+
* const asset = editor.getAsset(assetId)
|
|
212
|
+
* // Handle the asset...
|
|
213
|
+
* }
|
|
214
|
+
* }
|
|
215
|
+
*
|
|
216
|
+
* // Use with image or video shapes
|
|
217
|
+
* const imageShape: TLImageShape = { props: { assetId: 'asset:img1' } }
|
|
218
|
+
* const videoShape: TLVideoShape = { props: { assetId: 'asset:vid1' } }
|
|
219
|
+
* handleAssetShape(imageShape) // Works
|
|
220
|
+
* handleAssetShape(videoShape) // Works
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* @public
|
|
224
|
+
*/
|
|
68
225
|
export type TLAssetShape = Extract<TLShape, { props: { assetId: TLAssetId } }>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { createBindingId, rootBindingMigrations } from './TLBinding'
|
|
3
|
+
|
|
4
|
+
describe('TLBinding', () => {
|
|
5
|
+
describe('createBindingId function', () => {
|
|
6
|
+
it('should generate IDs starting with binding:', () => {
|
|
7
|
+
const id = createBindingId()
|
|
8
|
+
expect(id.startsWith('binding:')).toBe(true)
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
it('should use custom ID when provided', () => {
|
|
12
|
+
expect(createBindingId('test')).toBe('binding:test')
|
|
13
|
+
})
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
describe('rootBindingMigrations', () => {
|
|
17
|
+
it('should have correct structure', () => {
|
|
18
|
+
expect(rootBindingMigrations.sequenceId).toBe('com.tldraw.binding')
|
|
19
|
+
expect(Array.isArray(rootBindingMigrations.sequence)).toBe(true)
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
})
|