@tldraw/tlschema 4.1.0-canary.a5989c7a02c8 → 4.1.0-canary.ae12c0a5a37b
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,269 @@
|
|
|
1
|
+
import { IndexKey } from '@tldraw/utils'
|
|
2
|
+
import { T } from '@tldraw/validate'
|
|
3
|
+
import { describe, expect, it } from 'vitest'
|
|
4
|
+
import { getTestMigration } from '../__tests__/migrationTestUtils'
|
|
5
|
+
import {
|
|
6
|
+
lineShapeMigrations,
|
|
7
|
+
lineShapeProps,
|
|
8
|
+
LineShapeSplineStyle,
|
|
9
|
+
lineShapeVersions,
|
|
10
|
+
} from './TLLineShape'
|
|
11
|
+
|
|
12
|
+
describe('TLLineShape', () => {
|
|
13
|
+
describe('LineShapeSplineStyle', () => {
|
|
14
|
+
it('should validate correct spline values', () => {
|
|
15
|
+
expect(() => LineShapeSplineStyle.validate('cubic')).not.toThrow()
|
|
16
|
+
expect(() => LineShapeSplineStyle.validate('line')).not.toThrow()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
it('should reject invalid spline values', () => {
|
|
20
|
+
expect(() => LineShapeSplineStyle.validate('bezier')).toThrow()
|
|
21
|
+
expect(() => LineShapeSplineStyle.validate('')).toThrow()
|
|
22
|
+
expect(() => LineShapeSplineStyle.validate(null)).toThrow()
|
|
23
|
+
})
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
describe('lineShapeProps validation schema', () => {
|
|
27
|
+
it('should validate complete props object', () => {
|
|
28
|
+
const fullValidator = T.object(lineShapeProps)
|
|
29
|
+
const validProps = {
|
|
30
|
+
color: 'red' as const,
|
|
31
|
+
dash: 'dotted' as const,
|
|
32
|
+
size: 's' as const,
|
|
33
|
+
spline: 'line' as const,
|
|
34
|
+
points: {
|
|
35
|
+
start: { id: 'start', index: 'a1' as IndexKey, x: 0, y: 0 },
|
|
36
|
+
end: { id: 'end', index: 'a2' as IndexKey, x: 100, y: 50 },
|
|
37
|
+
},
|
|
38
|
+
scale: 1.5,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
expect(() => fullValidator.validate(validProps)).not.toThrow()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should validate points dictionary structure', () => {
|
|
45
|
+
const validPoints = {
|
|
46
|
+
a: { id: 'a', index: 'a1' as IndexKey, x: 0, y: 0 },
|
|
47
|
+
b: { id: 'b', index: 'a2' as IndexKey, x: 100, y: 50 },
|
|
48
|
+
}
|
|
49
|
+
expect(() => lineShapeProps.points.validate(validPoints)).not.toThrow()
|
|
50
|
+
|
|
51
|
+
// Invalid point structures
|
|
52
|
+
expect(() => lineShapeProps.points.validate({ a: { id: 'a', x: 0, y: 0 } })).toThrow() // Missing index
|
|
53
|
+
expect(() => lineShapeProps.points.validate({ a: { index: 'a1', x: 0, y: 0 } })).toThrow() // Missing id
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('should validate scale as nonZeroNumber', () => {
|
|
57
|
+
expect(() => lineShapeProps.scale.validate(1.5)).not.toThrow()
|
|
58
|
+
expect(() => lineShapeProps.scale.validate(0)).toThrow() // Zero should be invalid
|
|
59
|
+
expect(() => lineShapeProps.scale.validate(-1)).toThrow() // Negative should be invalid
|
|
60
|
+
})
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
describe('lineShapeMigrations - AddSnapHandles migration', () => {
|
|
64
|
+
const { up } = getTestMigration(lineShapeVersions.AddSnapHandles)
|
|
65
|
+
|
|
66
|
+
it('should add canSnap property to all handles', () => {
|
|
67
|
+
const oldRecord = {
|
|
68
|
+
id: 'shape:line1',
|
|
69
|
+
props: {
|
|
70
|
+
handles: {
|
|
71
|
+
start: { x: 0, y: 0 },
|
|
72
|
+
end: { x: 100, y: 100 },
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const result = up(oldRecord)
|
|
78
|
+
expect(result.props.handles.start.canSnap).toBe(true)
|
|
79
|
+
expect(result.props.handles.end.canSnap).toBe(true)
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
describe('lineShapeMigrations - RemoveExtraHandleProps migration', () => {
|
|
84
|
+
const { up, down } = getTestMigration(lineShapeVersions.RemoveExtraHandleProps)
|
|
85
|
+
|
|
86
|
+
it('should preserve only x and y properties from handles', () => {
|
|
87
|
+
const oldRecord = {
|
|
88
|
+
id: 'shape:line1',
|
|
89
|
+
props: {
|
|
90
|
+
handles: {
|
|
91
|
+
a1: {
|
|
92
|
+
x: 10,
|
|
93
|
+
y: 20,
|
|
94
|
+
canSnap: true,
|
|
95
|
+
id: 'start',
|
|
96
|
+
type: 'vertex',
|
|
97
|
+
index: 'a1',
|
|
98
|
+
extraProp: 'remove this',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const result = up(oldRecord)
|
|
105
|
+
expect(result.props.handles.a1).toEqual({ x: 10, y: 20 })
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('should restore full handle structure in down migration', () => {
|
|
109
|
+
const newRecord = {
|
|
110
|
+
id: 'shape:line1',
|
|
111
|
+
props: {
|
|
112
|
+
handles: {
|
|
113
|
+
a1: { x: 0, y: 0 },
|
|
114
|
+
a2: { x: 100, y: 100 },
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const result = down(newRecord)
|
|
120
|
+
expect(result.props.handles.start).toEqual({
|
|
121
|
+
id: 'start',
|
|
122
|
+
type: 'vertex',
|
|
123
|
+
canBind: false,
|
|
124
|
+
canSnap: true,
|
|
125
|
+
index: 'a1',
|
|
126
|
+
x: 0,
|
|
127
|
+
y: 0,
|
|
128
|
+
})
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
describe('lineShapeMigrations - HandlesToPoints migration', () => {
|
|
133
|
+
const { up, down } = getTestMigration(lineShapeVersions.HandlesToPoints)
|
|
134
|
+
|
|
135
|
+
it('should convert handles to points array', () => {
|
|
136
|
+
const oldRecord = {
|
|
137
|
+
id: 'shape:line1',
|
|
138
|
+
props: {
|
|
139
|
+
handles: {
|
|
140
|
+
a1: { x: 0, y: 0 },
|
|
141
|
+
a2: { x: 50, y: 25 },
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const result = up(oldRecord)
|
|
147
|
+
expect(result.props.handles).toBeUndefined()
|
|
148
|
+
expect(result.props.points).toEqual([
|
|
149
|
+
{ x: 0, y: 0 },
|
|
150
|
+
{ x: 50, y: 25 },
|
|
151
|
+
])
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
it('should convert points back to handles', () => {
|
|
155
|
+
const newRecord = {
|
|
156
|
+
id: 'shape:line1',
|
|
157
|
+
props: {
|
|
158
|
+
points: [
|
|
159
|
+
{ x: 0, y: 0 },
|
|
160
|
+
{ x: 100, y: 50 },
|
|
161
|
+
],
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const result = down(newRecord)
|
|
166
|
+
expect(result.props.points).toBeUndefined()
|
|
167
|
+
expect(result.props.handles).toBeDefined()
|
|
168
|
+
expect(Object.keys(result.props.handles)).toHaveLength(2)
|
|
169
|
+
})
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
describe('lineShapeMigrations - PointIndexIds migration', () => {
|
|
173
|
+
const { up, down } = getTestMigration(lineShapeVersions.PointIndexIds)
|
|
174
|
+
|
|
175
|
+
it('should convert points array to indexed points object', () => {
|
|
176
|
+
const oldRecord = {
|
|
177
|
+
id: 'shape:line1',
|
|
178
|
+
props: {
|
|
179
|
+
points: [
|
|
180
|
+
{ x: 0, y: 0 },
|
|
181
|
+
{ x: 50, y: 25 },
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const result = up(oldRecord)
|
|
187
|
+
expect(Array.isArray(result.props.points)).toBe(false)
|
|
188
|
+
expect(typeof result.props.points).toBe('object')
|
|
189
|
+
|
|
190
|
+
const pointKeys = Object.keys(result.props.points)
|
|
191
|
+
expect(pointKeys).toHaveLength(2)
|
|
192
|
+
|
|
193
|
+
// Each point should have id, index, x, y
|
|
194
|
+
pointKeys.forEach((key) => {
|
|
195
|
+
const point = result.props.points[key]
|
|
196
|
+
expect(point.id).toBe(key)
|
|
197
|
+
expect(point.index).toBe(key)
|
|
198
|
+
})
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
it('should convert indexed points object back to points array', () => {
|
|
202
|
+
const newRecord = {
|
|
203
|
+
id: 'shape:line1',
|
|
204
|
+
props: {
|
|
205
|
+
points: {
|
|
206
|
+
a1: { id: 'a1', index: 'a1' as IndexKey, x: 0, y: 0 },
|
|
207
|
+
a2: { id: 'a2', index: 'a2' as IndexKey, x: 50, y: 25 },
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const result = down(newRecord)
|
|
213
|
+
expect(Array.isArray(result.props.points)).toBe(true)
|
|
214
|
+
expect(result.props.points).toEqual([
|
|
215
|
+
{ x: 0, y: 0 },
|
|
216
|
+
{ x: 50, y: 25 },
|
|
217
|
+
])
|
|
218
|
+
})
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
describe('lineShapeMigrations - AddScale migration', () => {
|
|
222
|
+
const { up, down } = getTestMigration(lineShapeVersions.AddScale)
|
|
223
|
+
|
|
224
|
+
it('should add scale property with default value 1', () => {
|
|
225
|
+
const oldRecord = {
|
|
226
|
+
id: 'shape:line1',
|
|
227
|
+
props: {
|
|
228
|
+
color: 'blue',
|
|
229
|
+
points: {
|
|
230
|
+
a1: { id: 'a1', index: 'a1' as IndexKey, x: 0, y: 0 },
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const result = up(oldRecord)
|
|
236
|
+
expect(result.props.scale).toBe(1)
|
|
237
|
+
expect(result.props.color).toBe('blue')
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('should remove scale property in down migration', () => {
|
|
241
|
+
const newRecord = {
|
|
242
|
+
id: 'shape:line1',
|
|
243
|
+
props: {
|
|
244
|
+
color: 'blue',
|
|
245
|
+
scale: 1.5,
|
|
246
|
+
points: {},
|
|
247
|
+
},
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const result = down(newRecord)
|
|
251
|
+
expect(result.props.scale).toBeUndefined()
|
|
252
|
+
expect(result.props.color).toBe('blue')
|
|
253
|
+
})
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
describe('migration integration', () => {
|
|
257
|
+
it('should have migrations for all version IDs', () => {
|
|
258
|
+
const migrationIds = lineShapeMigrations.sequence
|
|
259
|
+
.filter((migration) => 'id' in migration)
|
|
260
|
+
.map((migration) => ('id' in migration ? migration.id : ''))
|
|
261
|
+
.filter(Boolean)
|
|
262
|
+
|
|
263
|
+
const versionIds = Object.values(lineShapeVersions)
|
|
264
|
+
versionIds.forEach((versionId) => {
|
|
265
|
+
expect(migrationIds).toContain(versionId)
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
})
|
|
269
|
+
})
|
|
@@ -8,20 +8,57 @@ import { DefaultDashStyle, TLDefaultDashStyle } from '../styles/TLDashStyle'
|
|
|
8
8
|
import { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'
|
|
9
9
|
import { TLBaseShape } from './TLBaseShape'
|
|
10
10
|
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Style property for line shape spline interpolation. Determines how the line is rendered
|
|
13
|
+
* between points - either as straight line segments or smooth cubic curves.
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* // Create a shape with cubic spline interpolation
|
|
19
|
+
* const lineProps = {
|
|
20
|
+
* spline: 'cubic' as TLLineShapeSplineStyle,
|
|
21
|
+
* // other props...
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
12
25
|
export const LineShapeSplineStyle = StyleProp.defineEnum('tldraw:spline', {
|
|
13
26
|
defaultValue: 'line',
|
|
14
27
|
values: ['cubic', 'line'],
|
|
15
28
|
})
|
|
16
29
|
|
|
17
|
-
/**
|
|
30
|
+
/**
|
|
31
|
+
* Type representing the spline style options for line shapes.
|
|
32
|
+
* - 'line': Straight line segments between points
|
|
33
|
+
* - 'cubic': Smooth cubic bezier curves between points
|
|
34
|
+
*
|
|
35
|
+
* @public
|
|
36
|
+
*/
|
|
18
37
|
export type TLLineShapeSplineStyle = T.TypeOf<typeof LineShapeSplineStyle>
|
|
19
38
|
|
|
20
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Represents a single point in a line shape. Line shapes are made up of multiple points
|
|
41
|
+
* that define the path of the line, with each point having coordinates and ordering information.
|
|
42
|
+
*
|
|
43
|
+
* @public
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* const linePoint: TLLineShapePoint = {
|
|
47
|
+
* id: 'a1',
|
|
48
|
+
* index: 'a1' as IndexKey,
|
|
49
|
+
* x: 100,
|
|
50
|
+
* y: 50
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
21
54
|
export interface TLLineShapePoint {
|
|
55
|
+
/** Unique identifier for this point, used for tracking and ordering */
|
|
22
56
|
id: string
|
|
57
|
+
/** Fractional index key used for ordering points along the line */
|
|
23
58
|
index: IndexKey
|
|
59
|
+
/** X coordinate of the point relative to the line shape's origin */
|
|
24
60
|
x: number
|
|
61
|
+
/** Y coordinate of the point relative to the line shape's origin */
|
|
25
62
|
y: number
|
|
26
63
|
}
|
|
27
64
|
|
|
@@ -32,20 +69,91 @@ const lineShapePointValidator: T.ObjectValidator<TLLineShapePoint> = T.object({
|
|
|
32
69
|
y: T.number,
|
|
33
70
|
})
|
|
34
71
|
|
|
35
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Properties for a line shape. Line shapes represent multi-point lines or splines
|
|
74
|
+
* that can be drawn by connecting multiple points with either straight segments or curves.
|
|
75
|
+
*
|
|
76
|
+
* @public
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const lineProps: TLLineShapeProps = {
|
|
80
|
+
* color: 'black',
|
|
81
|
+
* dash: 'solid',
|
|
82
|
+
* size: 'm',
|
|
83
|
+
* spline: 'line',
|
|
84
|
+
* points: {
|
|
85
|
+
* 'a1': { id: 'a1', index: 'a1', x: 0, y: 0 },
|
|
86
|
+
* 'a2': { id: 'a2', index: 'a2', x: 100, y: 50 }
|
|
87
|
+
* },
|
|
88
|
+
* scale: 1
|
|
89
|
+
* }
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
36
92
|
export interface TLLineShapeProps {
|
|
93
|
+
/** Color style of the line stroke */
|
|
37
94
|
color: TLDefaultColorStyle
|
|
95
|
+
/** Dash pattern style for the line (solid, dashed, dotted) */
|
|
38
96
|
dash: TLDefaultDashStyle
|
|
97
|
+
/** Size/thickness style of the line stroke */
|
|
39
98
|
size: TLDefaultSizeStyle
|
|
99
|
+
/** Interpolation style between points (straight lines or curved splines) */
|
|
40
100
|
spline: TLLineShapeSplineStyle
|
|
101
|
+
/** Dictionary of points that make up the line, keyed by point ID */
|
|
41
102
|
points: Record<string, TLLineShapePoint>
|
|
103
|
+
/** Scale factor applied to the line shape for display */
|
|
42
104
|
scale: number
|
|
43
105
|
}
|
|
44
106
|
|
|
45
|
-
/**
|
|
107
|
+
/**
|
|
108
|
+
* A line shape that represents a multi-point line or spline on the canvas. Line shapes
|
|
109
|
+
* allow users to draw connected paths with multiple points, supporting both straight
|
|
110
|
+
* line segments and smooth curved splines.
|
|
111
|
+
*
|
|
112
|
+
* @public
|
|
113
|
+
* @example
|
|
114
|
+
* ```ts
|
|
115
|
+
* const lineShape: TLLineShape = {
|
|
116
|
+
* id: 'shape:line1',
|
|
117
|
+
* type: 'line',
|
|
118
|
+
* x: 100,
|
|
119
|
+
* y: 100,
|
|
120
|
+
* rotation: 0,
|
|
121
|
+
* index: 'a1',
|
|
122
|
+
* parentId: 'page:main',
|
|
123
|
+
* isLocked: false,
|
|
124
|
+
* opacity: 1,
|
|
125
|
+
* props: {
|
|
126
|
+
* color: 'red',
|
|
127
|
+
* dash: 'dashed',
|
|
128
|
+
* size: 'l',
|
|
129
|
+
* spline: 'cubic',
|
|
130
|
+
* points: {
|
|
131
|
+
* 'start': { id: 'start', index: 'a1', x: 0, y: 0 },
|
|
132
|
+
* 'end': { id: 'end', index: 'a2', x: 200, y: 100 }
|
|
133
|
+
* },
|
|
134
|
+
* scale: 1
|
|
135
|
+
* },
|
|
136
|
+
* meta: {},
|
|
137
|
+
* typeName: 'shape'
|
|
138
|
+
* }
|
|
139
|
+
* ```
|
|
140
|
+
*/
|
|
46
141
|
export type TLLineShape = TLBaseShape<'line', TLLineShapeProps>
|
|
47
142
|
|
|
48
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* Validation schema for line shape properties. Defines the runtime validation rules
|
|
145
|
+
* for all properties of line shapes, ensuring data integrity and type safety.
|
|
146
|
+
*
|
|
147
|
+
* @public
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* import { lineShapeProps } from '@tldraw/tlschema'
|
|
151
|
+
*
|
|
152
|
+
* // Used internally by the validation system
|
|
153
|
+
* const validator = T.object(lineShapeProps)
|
|
154
|
+
* const validatedProps = validator.validate(someLineProps)
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
49
157
|
export const lineShapeProps: RecordProps<TLLineShape> = {
|
|
50
158
|
color: DefaultColorStyle,
|
|
51
159
|
dash: DefaultDashStyle,
|
|
@@ -55,7 +163,12 @@ export const lineShapeProps: RecordProps<TLLineShape> = {
|
|
|
55
163
|
scale: T.nonZeroNumber,
|
|
56
164
|
}
|
|
57
165
|
|
|
58
|
-
/**
|
|
166
|
+
/**
|
|
167
|
+
* Version identifiers for line shape migrations. These version numbers track
|
|
168
|
+
* significant schema changes over time, enabling proper data migration between versions.
|
|
169
|
+
*
|
|
170
|
+
* @public
|
|
171
|
+
*/
|
|
59
172
|
export const lineShapeVersions = createShapePropsMigrationIds('line', {
|
|
60
173
|
AddSnapHandles: 1,
|
|
61
174
|
RemoveExtraHandleProps: 2,
|
|
@@ -64,7 +177,14 @@ export const lineShapeVersions = createShapePropsMigrationIds('line', {
|
|
|
64
177
|
AddScale: 5,
|
|
65
178
|
})
|
|
66
179
|
|
|
67
|
-
/**
|
|
180
|
+
/**
|
|
181
|
+
* Migration sequence for line shapes. Handles schema evolution over time by defining
|
|
182
|
+
* how to upgrade and downgrade line shape data between different versions. Includes
|
|
183
|
+
* major structural changes like the transition from handles to points and the addition
|
|
184
|
+
* of scaling support.
|
|
185
|
+
*
|
|
186
|
+
* @public
|
|
187
|
+
*/
|
|
68
188
|
export const lineShapeMigrations = createShapePropsMigrationSequence({
|
|
69
189
|
sequence: [
|
|
70
190
|
{
|