@tldraw/tlschema 4.1.0-next.542f014c3fac → 4.1.0-next.cb6f90590225
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
|
@@ -2,15 +2,63 @@ import { createShapePropsMigrationSequence } from '../records/TLShape'
|
|
|
2
2
|
import { RecordProps } from '../recordsWithProps'
|
|
3
3
|
import { TLBaseShape } from './TLBaseShape'
|
|
4
4
|
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Properties for a group shape. Group shapes are used to organize and manage collections of shapes as a single unit.
|
|
7
|
+
* Group shapes themselves have no visual properties and serve only as containers.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const groupProps: TLGroupShapeProps = {}
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
6
15
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
7
16
|
export interface TLGroupShapeProps {}
|
|
8
17
|
|
|
9
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* A group shape that acts as a container for organizing multiple shapes into a single logical unit.
|
|
20
|
+
* Groups enable users to move, transform, and manage collections of shapes together while maintaining
|
|
21
|
+
* their relative positions and properties.
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const groupShape: TLGroupShape = {
|
|
27
|
+
* id: 'shape:group1',
|
|
28
|
+
* type: 'group',
|
|
29
|
+
* x: 100,
|
|
30
|
+
* y: 100,
|
|
31
|
+
* rotation: 0,
|
|
32
|
+
* index: 'a1',
|
|
33
|
+
* parentId: 'page:main',
|
|
34
|
+
* isLocked: false,
|
|
35
|
+
* opacity: 1,
|
|
36
|
+
* props: {},
|
|
37
|
+
* meta: {},
|
|
38
|
+
* typeName: 'shape'
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
10
42
|
export type TLGroupShape = TLBaseShape<'group', TLGroupShapeProps>
|
|
11
43
|
|
|
12
|
-
/**
|
|
44
|
+
/**
|
|
45
|
+
* Validation schema for group shape properties. Since group shapes have no visual properties,
|
|
46
|
+
* this is an empty object that serves as a placeholder for the schema system.
|
|
47
|
+
*
|
|
48
|
+
* @public
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* import { groupShapeProps } from '@tldraw/tlschema'
|
|
52
|
+
*
|
|
53
|
+
* // Used internally by the validation system
|
|
54
|
+
* const validator = T.object(groupShapeProps)
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
13
57
|
export const groupShapeProps: RecordProps<TLGroupShape> = {}
|
|
14
58
|
|
|
15
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Migration sequence for group shapes. Currently contains no migrations.
|
|
61
|
+
*
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
16
64
|
export const groupShapeMigrations = createShapePropsMigrationSequence({ sequence: [] })
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { T } from '@tldraw/validate'
|
|
2
|
+
import { describe, expect, it, test } from 'vitest'
|
|
3
|
+
import { getTestMigration } from '../__tests__/migrationTestUtils'
|
|
4
|
+
import {
|
|
5
|
+
highlightShapeMigrations,
|
|
6
|
+
highlightShapeProps,
|
|
7
|
+
highlightShapeVersions,
|
|
8
|
+
} from './TLHighlightShape'
|
|
9
|
+
|
|
10
|
+
describe('TLHighlightShape', () => {
|
|
11
|
+
describe('highlightShapeProps validation schema', () => {
|
|
12
|
+
it('should validate valid highlight shape properties', () => {
|
|
13
|
+
const validProps = {
|
|
14
|
+
color: 'yellow' as const,
|
|
15
|
+
size: 'l' as const,
|
|
16
|
+
segments: [
|
|
17
|
+
{
|
|
18
|
+
type: 'free' as const,
|
|
19
|
+
points: [{ x: 0, y: 0, z: 0.5 }],
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
isComplete: true,
|
|
23
|
+
isPen: false,
|
|
24
|
+
scale: 1,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const fullValidator = T.object(highlightShapeProps)
|
|
28
|
+
expect(() => fullValidator.validate(validProps)).not.toThrow()
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
it('should reject invalid color values', () => {
|
|
32
|
+
const invalidColors = ['purple', 'YELLOW', 'neon', '', null, undefined, 123, {}, []]
|
|
33
|
+
|
|
34
|
+
invalidColors.forEach((color) => {
|
|
35
|
+
expect(() => highlightShapeProps.color.validate(color)).toThrow()
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should reject invalid size values', () => {
|
|
40
|
+
const invalidSizes = ['medium', 'SM', 'large', 'xxl', '', null, undefined, 123]
|
|
41
|
+
|
|
42
|
+
invalidSizes.forEach((size) => {
|
|
43
|
+
expect(() => highlightShapeProps.size.validate(size)).toThrow()
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should validate segments array', () => {
|
|
48
|
+
const validSegmentArrays = [
|
|
49
|
+
[], // Empty array
|
|
50
|
+
[
|
|
51
|
+
{
|
|
52
|
+
type: 'free' as const,
|
|
53
|
+
points: [{ x: 0, y: 0, z: 0.5 }],
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
validSegmentArrays.forEach((segments) => {
|
|
59
|
+
expect(() => highlightShapeProps.segments.validate(segments)).not.toThrow()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const invalidSegmentArrays = [
|
|
63
|
+
'not-array',
|
|
64
|
+
null,
|
|
65
|
+
undefined,
|
|
66
|
+
[{ type: 'invalid', points: [] }], // Invalid segment type
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
invalidSegmentArrays.forEach((segments) => {
|
|
70
|
+
expect(() => highlightShapeProps.segments.validate(segments)).toThrow()
|
|
71
|
+
})
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('should validate boolean properties', () => {
|
|
75
|
+
// Valid boolean values
|
|
76
|
+
expect(() => highlightShapeProps.isComplete.validate(true)).not.toThrow()
|
|
77
|
+
expect(() => highlightShapeProps.isComplete.validate(false)).not.toThrow()
|
|
78
|
+
expect(() => highlightShapeProps.isPen.validate(true)).not.toThrow()
|
|
79
|
+
expect(() => highlightShapeProps.isPen.validate(false)).not.toThrow()
|
|
80
|
+
|
|
81
|
+
// Invalid boolean values
|
|
82
|
+
const invalidBooleans = ['true', 'false', 1, 0, null, undefined, {}, []]
|
|
83
|
+
invalidBooleans.forEach((value) => {
|
|
84
|
+
expect(() => highlightShapeProps.isComplete.validate(value)).toThrow()
|
|
85
|
+
expect(() => highlightShapeProps.isPen.validate(value)).toThrow()
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should validate scale as nonZeroNumber', () => {
|
|
90
|
+
// Valid non-zero positive numbers
|
|
91
|
+
expect(() => highlightShapeProps.scale.validate(0.1)).not.toThrow()
|
|
92
|
+
expect(() => highlightShapeProps.scale.validate(1)).not.toThrow()
|
|
93
|
+
expect(() => highlightShapeProps.scale.validate(2)).not.toThrow()
|
|
94
|
+
|
|
95
|
+
// Invalid scales (zero, negative, and non-numbers)
|
|
96
|
+
expect(() => highlightShapeProps.scale.validate(0)).toThrow()
|
|
97
|
+
expect(() => highlightShapeProps.scale.validate(-1)).toThrow()
|
|
98
|
+
expect(() => highlightShapeProps.scale.validate('not-number')).toThrow()
|
|
99
|
+
expect(() => highlightShapeProps.scale.validate(null)).toThrow()
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('should reject objects with missing properties', () => {
|
|
103
|
+
const fullValidator = T.object(highlightShapeProps)
|
|
104
|
+
|
|
105
|
+
expect(() => fullValidator.validate({})).toThrow()
|
|
106
|
+
expect(() => fullValidator.validate({ color: 'yellow' })).toThrow()
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
it('should reject objects with extra properties', () => {
|
|
110
|
+
const fullValidator = T.object(highlightShapeProps)
|
|
111
|
+
|
|
112
|
+
const objectWithExtraProps = {
|
|
113
|
+
color: 'yellow',
|
|
114
|
+
size: 'm',
|
|
115
|
+
segments: [],
|
|
116
|
+
isComplete: true,
|
|
117
|
+
isPen: false,
|
|
118
|
+
scale: 1,
|
|
119
|
+
extraProp: 'extra',
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
expect(() => fullValidator.validate(objectWithExtraProps)).toThrow()
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
describe('highlightShapeVersions', () => {
|
|
127
|
+
it('should contain expected migration version IDs', () => {
|
|
128
|
+
expect(highlightShapeVersions).toBeDefined()
|
|
129
|
+
expect(typeof highlightShapeVersions).toBe('object')
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('should have all expected migration versions', () => {
|
|
133
|
+
const expectedVersions: Array<keyof typeof highlightShapeVersions> = ['AddScale']
|
|
134
|
+
|
|
135
|
+
expectedVersions.forEach((version) => {
|
|
136
|
+
expect(highlightShapeVersions[version]).toBeDefined()
|
|
137
|
+
expect(typeof highlightShapeVersions[version]).toBe('string')
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it('should have properly formatted migration IDs', () => {
|
|
142
|
+
Object.values(highlightShapeVersions).forEach((versionId) => {
|
|
143
|
+
expect(versionId).toMatch(/^com\.tldraw\.shape\.highlight\//)
|
|
144
|
+
expect(versionId).toMatch(/\/\d+$/) // Should end with /number
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
describe('highlightShapeMigrations', () => {
|
|
150
|
+
it('should be defined and have required structure', () => {
|
|
151
|
+
expect(highlightShapeMigrations).toBeDefined()
|
|
152
|
+
expect(highlightShapeMigrations.sequence).toBeDefined()
|
|
153
|
+
expect(Array.isArray(highlightShapeMigrations.sequence)).toBe(true)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
it('should have migrations for all version IDs', () => {
|
|
157
|
+
const migrationIds = highlightShapeMigrations.sequence
|
|
158
|
+
.filter((migration) => 'id' in migration)
|
|
159
|
+
.map((migration) => ('id' in migration ? migration.id : null))
|
|
160
|
+
.filter(Boolean)
|
|
161
|
+
|
|
162
|
+
const versionIds = Object.values(highlightShapeVersions)
|
|
163
|
+
|
|
164
|
+
versionIds.forEach((versionId) => {
|
|
165
|
+
expect(migrationIds).toContain(versionId)
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
describe('highlightShapeMigrations - AddScale migration', () => {
|
|
171
|
+
const { up, down } = getTestMigration(highlightShapeVersions.AddScale)
|
|
172
|
+
|
|
173
|
+
describe('AddScale up migration', () => {
|
|
174
|
+
it('should add scale property with default value 1', () => {
|
|
175
|
+
const oldRecord = {
|
|
176
|
+
id: 'shape:highlight1',
|
|
177
|
+
props: {
|
|
178
|
+
color: 'yellow',
|
|
179
|
+
size: 'm',
|
|
180
|
+
segments: [
|
|
181
|
+
{
|
|
182
|
+
type: 'free',
|
|
183
|
+
points: [{ x: 0, y: 0, z: 0.5 }],
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
isComplete: true,
|
|
187
|
+
isPen: false,
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const result = up(oldRecord)
|
|
192
|
+
expect(result.props.scale).toBe(1)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('should preserve existing properties during migration', () => {
|
|
196
|
+
const oldRecord = {
|
|
197
|
+
id: 'shape:highlight1',
|
|
198
|
+
props: {
|
|
199
|
+
color: 'green',
|
|
200
|
+
size: 'l',
|
|
201
|
+
segments: [
|
|
202
|
+
{
|
|
203
|
+
type: 'straight',
|
|
204
|
+
points: [
|
|
205
|
+
{ x: 10, y: 20 },
|
|
206
|
+
{ x: 100, y: 150 },
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
isComplete: true,
|
|
211
|
+
isPen: true,
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const result = up(oldRecord)
|
|
216
|
+
expect(result.props.scale).toBe(1)
|
|
217
|
+
expect(result.props.color).toBe('green')
|
|
218
|
+
expect(result.props.size).toBe('l')
|
|
219
|
+
expect(result.props.segments).toEqual(oldRecord.props.segments)
|
|
220
|
+
expect(result.props.isComplete).toBe(true)
|
|
221
|
+
expect(result.props.isPen).toBe(true)
|
|
222
|
+
})
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
describe('AddScale down migration', () => {
|
|
226
|
+
it('should remove scale property', () => {
|
|
227
|
+
const newRecord = {
|
|
228
|
+
id: 'shape:highlight1',
|
|
229
|
+
props: {
|
|
230
|
+
color: 'yellow',
|
|
231
|
+
size: 'm',
|
|
232
|
+
segments: [
|
|
233
|
+
{
|
|
234
|
+
type: 'free',
|
|
235
|
+
points: [{ x: 0, y: 0, z: 0.5 }],
|
|
236
|
+
},
|
|
237
|
+
],
|
|
238
|
+
isComplete: true,
|
|
239
|
+
isPen: false,
|
|
240
|
+
scale: 1.5,
|
|
241
|
+
},
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const result = down(newRecord)
|
|
245
|
+
expect(result.props.scale).toBeUndefined()
|
|
246
|
+
expect(result.props.color).toBe('yellow') // Preserve other props
|
|
247
|
+
expect(result.props.isPen).toBe(false) // Preserve other props
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
it('should preserve all other properties during down migration', () => {
|
|
251
|
+
const newRecord = {
|
|
252
|
+
id: 'shape:highlight1',
|
|
253
|
+
props: {
|
|
254
|
+
color: 'red',
|
|
255
|
+
size: 'xl',
|
|
256
|
+
segments: [
|
|
257
|
+
{
|
|
258
|
+
type: 'straight',
|
|
259
|
+
points: [
|
|
260
|
+
{ x: 0, y: 0 },
|
|
261
|
+
{ x: 200, y: 0 },
|
|
262
|
+
],
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
isComplete: true,
|
|
266
|
+
isPen: false,
|
|
267
|
+
scale: 2.0,
|
|
268
|
+
},
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const result = down(newRecord)
|
|
272
|
+
expect(result.props.scale).toBeUndefined()
|
|
273
|
+
expect(result.props.color).toBe('red')
|
|
274
|
+
expect(result.props.size).toBe('xl')
|
|
275
|
+
expect(result.props.segments).toEqual(newRecord.props.segments)
|
|
276
|
+
expect(result.props.isComplete).toBe(true)
|
|
277
|
+
expect(result.props.isPen).toBe(false)
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
it('should support round-trip migration (up then down)', () => {
|
|
282
|
+
const originalRecord = {
|
|
283
|
+
id: 'shape:highlight1',
|
|
284
|
+
props: {
|
|
285
|
+
color: 'green',
|
|
286
|
+
size: 'l',
|
|
287
|
+
segments: [
|
|
288
|
+
{
|
|
289
|
+
type: 'free',
|
|
290
|
+
points: [{ x: 0, y: 0, z: 0.5 }],
|
|
291
|
+
},
|
|
292
|
+
],
|
|
293
|
+
isComplete: true,
|
|
294
|
+
isPen: true,
|
|
295
|
+
},
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Apply up migration
|
|
299
|
+
const upResult = up(originalRecord)
|
|
300
|
+
expect(upResult.props.scale).toBe(1)
|
|
301
|
+
|
|
302
|
+
// Apply down migration
|
|
303
|
+
const downResult = down(upResult)
|
|
304
|
+
expect(downResult.props.scale).toBeUndefined()
|
|
305
|
+
expect(downResult.props.color).toBe('green')
|
|
306
|
+
expect(downResult.props.size).toBe('l')
|
|
307
|
+
expect(downResult.props.isComplete).toBe(true)
|
|
308
|
+
expect(downResult.props.isPen).toBe(true)
|
|
309
|
+
})
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
test('should handle all migration versions in correct order', () => {
|
|
313
|
+
const expectedOrder: Array<keyof typeof highlightShapeVersions> = ['AddScale']
|
|
314
|
+
|
|
315
|
+
const migrationIds = highlightShapeMigrations.sequence
|
|
316
|
+
.filter((migration) => 'id' in migration)
|
|
317
|
+
.map((migration) => ('id' in migration ? migration.id : ''))
|
|
318
|
+
.filter(Boolean)
|
|
319
|
+
|
|
320
|
+
expectedOrder.forEach((expectedVersion) => {
|
|
321
|
+
const versionId = highlightShapeVersions[expectedVersion]
|
|
322
|
+
expect(migrationIds).toContain(versionId)
|
|
323
|
+
})
|
|
324
|
+
})
|
|
325
|
+
})
|
|
@@ -6,20 +6,84 @@ import { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'
|
|
|
6
6
|
import { TLBaseShape } from './TLBaseShape'
|
|
7
7
|
import { DrawShapeSegment, TLDrawShapeSegment } from './TLDrawShape'
|
|
8
8
|
|
|
9
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Properties for a highlight shape. Highlight shapes represent highlighting strokes made with
|
|
11
|
+
* a highlighting tool, typically used to emphasize or mark up content.
|
|
12
|
+
*
|
|
13
|
+
* @public
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const highlightProps: TLHighlightShapeProps = {
|
|
17
|
+
* color: 'yellow',
|
|
18
|
+
* size: 'm',
|
|
19
|
+
* segments: [{ type: 'straight', points: [{ x: 0, y: 0, z: 0.5 }] }],
|
|
20
|
+
* isComplete: true,
|
|
21
|
+
* isPen: false,
|
|
22
|
+
* scale: 1
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
10
26
|
export interface TLHighlightShapeProps {
|
|
27
|
+
/** The color style of the highlight stroke */
|
|
11
28
|
color: TLDefaultColorStyle
|
|
29
|
+
/** The size style determining the thickness of the highlight stroke */
|
|
12
30
|
size: TLDefaultSizeStyle
|
|
31
|
+
/** Array of segments that make up the highlight stroke path */
|
|
13
32
|
segments: TLDrawShapeSegment[]
|
|
33
|
+
/** Whether the highlight stroke has been completed by the user */
|
|
14
34
|
isComplete: boolean
|
|
35
|
+
/** Whether the highlight was drawn with a pen/stylus (affects rendering style) */
|
|
15
36
|
isPen: boolean
|
|
37
|
+
/** Scale factor applied to the highlight shape for display */
|
|
16
38
|
scale: number
|
|
17
39
|
}
|
|
18
40
|
|
|
19
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* A highlight shape representing a highlighting stroke drawn by the user. Highlight shapes
|
|
43
|
+
* are typically semi-transparent and used for marking up or emphasizing content on the canvas.
|
|
44
|
+
*
|
|
45
|
+
* @public
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const highlightShape: TLHighlightShape = {
|
|
49
|
+
* id: 'shape:highlight1',
|
|
50
|
+
* type: 'highlight',
|
|
51
|
+
* x: 100,
|
|
52
|
+
* y: 50,
|
|
53
|
+
* rotation: 0,
|
|
54
|
+
* index: 'a1',
|
|
55
|
+
* parentId: 'page:main',
|
|
56
|
+
* isLocked: false,
|
|
57
|
+
* opacity: 0.7,
|
|
58
|
+
* props: {
|
|
59
|
+
* color: 'yellow',
|
|
60
|
+
* size: 'l',
|
|
61
|
+
* segments: [],
|
|
62
|
+
* isComplete: false,
|
|
63
|
+
* isPen: false,
|
|
64
|
+
* scale: 1
|
|
65
|
+
* },
|
|
66
|
+
* meta: {},
|
|
67
|
+
* typeName: 'shape'
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
20
71
|
export type TLHighlightShape = TLBaseShape<'highlight', TLHighlightShapeProps>
|
|
21
72
|
|
|
22
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Validation schema for highlight shape properties. Defines the runtime validation rules
|
|
75
|
+
* for all properties of highlight shapes.
|
|
76
|
+
*
|
|
77
|
+
* @public
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* import { highlightShapeProps } from '@tldraw/tlschema'
|
|
81
|
+
*
|
|
82
|
+
* // Used internally by the validation system
|
|
83
|
+
* const validator = T.object(highlightShapeProps)
|
|
84
|
+
* const validatedProps = validator.validate(someHighlightProps)
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
23
87
|
export const highlightShapeProps: RecordProps<TLHighlightShape> = {
|
|
24
88
|
color: DefaultColorStyle,
|
|
25
89
|
size: DefaultSizeStyle,
|
|
@@ -33,9 +97,20 @@ const Versions = createShapePropsMigrationIds('highlight', {
|
|
|
33
97
|
AddScale: 1,
|
|
34
98
|
})
|
|
35
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Version identifiers for highlight shape migrations. These version numbers track
|
|
102
|
+
* schema changes over time to enable proper data migration.
|
|
103
|
+
*
|
|
104
|
+
* @public
|
|
105
|
+
*/
|
|
36
106
|
export { Versions as highlightShapeVersions }
|
|
37
107
|
|
|
38
|
-
/**
|
|
108
|
+
/**
|
|
109
|
+
* Migration sequence for highlight shapes. Handles schema evolution over time by defining
|
|
110
|
+
* how to upgrade and downgrade highlight shape data between different versions.
|
|
111
|
+
*
|
|
112
|
+
* @public
|
|
113
|
+
*/
|
|
39
114
|
export const highlightShapeMigrations = createShapePropsMigrationSequence({
|
|
40
115
|
sequence: [
|
|
41
116
|
{
|