@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.
Files changed (212) hide show
  1. package/dist-cjs/TLStore.js +3 -10
  2. package/dist-cjs/TLStore.js.map +2 -2
  3. package/dist-cjs/assets/TLBaseAsset.js.map +2 -2
  4. package/dist-cjs/assets/TLBookmarkAsset.js.map +2 -2
  5. package/dist-cjs/assets/TLImageAsset.js.map +2 -2
  6. package/dist-cjs/assets/TLVideoAsset.js.map +2 -2
  7. package/dist-cjs/bindings/TLArrowBinding.js.map +2 -2
  8. package/dist-cjs/bindings/TLBaseBinding.js.map +2 -2
  9. package/dist-cjs/createPresenceStateDerivation.js.map +2 -2
  10. package/dist-cjs/createTLSchema.js.map +2 -2
  11. package/dist-cjs/index.d.ts +4416 -223
  12. package/dist-cjs/index.js +1 -1
  13. package/dist-cjs/index.js.map +2 -2
  14. package/dist-cjs/misc/TLColor.js.map +2 -2
  15. package/dist-cjs/misc/TLCursor.js.map +2 -2
  16. package/dist-cjs/misc/TLHandle.js.map +2 -2
  17. package/dist-cjs/misc/TLOpacity.js.map +2 -2
  18. package/dist-cjs/misc/TLRichText.js.map +2 -2
  19. package/dist-cjs/misc/TLScribble.js.map +2 -2
  20. package/dist-cjs/misc/geometry-types.js.map +2 -2
  21. package/dist-cjs/misc/id-validator.js.map +2 -2
  22. package/dist-cjs/records/TLAsset.js.map +2 -2
  23. package/dist-cjs/records/TLBinding.js.map +2 -2
  24. package/dist-cjs/records/TLCamera.js.map +2 -2
  25. package/dist-cjs/records/TLDocument.js.map +2 -2
  26. package/dist-cjs/records/TLInstance.js.map +2 -2
  27. package/dist-cjs/records/TLPage.js.map +2 -2
  28. package/dist-cjs/records/TLPageState.js.map +2 -2
  29. package/dist-cjs/records/TLPointer.js.map +2 -2
  30. package/dist-cjs/records/TLPresence.js.map +2 -2
  31. package/dist-cjs/records/TLRecord.js.map +1 -1
  32. package/dist-cjs/records/TLShape.js.map +2 -2
  33. package/dist-cjs/recordsWithProps.js.map +2 -2
  34. package/dist-cjs/shapes/ShapeWithCrop.js.map +1 -1
  35. package/dist-cjs/shapes/TLArrowShape.js.map +2 -2
  36. package/dist-cjs/shapes/TLBaseShape.js.map +2 -2
  37. package/dist-cjs/shapes/TLBookmarkShape.js.map +2 -2
  38. package/dist-cjs/shapes/TLDrawShape.js.map +2 -2
  39. package/dist-cjs/shapes/TLEmbedShape.js.map +2 -2
  40. package/dist-cjs/shapes/TLFrameShape.js.map +2 -2
  41. package/dist-cjs/shapes/TLGeoShape.js.map +2 -2
  42. package/dist-cjs/shapes/TLGroupShape.js.map +2 -2
  43. package/dist-cjs/shapes/TLHighlightShape.js.map +2 -2
  44. package/dist-cjs/shapes/TLImageShape.js.map +2 -2
  45. package/dist-cjs/shapes/TLLineShape.js.map +2 -2
  46. package/dist-cjs/shapes/TLNoteShape.js.map +2 -2
  47. package/dist-cjs/shapes/TLTextShape.js.map +2 -2
  48. package/dist-cjs/shapes/TLVideoShape.js.map +2 -2
  49. package/dist-cjs/store-migrations.js.map +2 -2
  50. package/dist-cjs/styles/TLColorStyle.js.map +2 -2
  51. package/dist-cjs/styles/TLDashStyle.js.map +2 -2
  52. package/dist-cjs/styles/TLFillStyle.js.map +2 -2
  53. package/dist-cjs/styles/TLFontStyle.js.map +2 -2
  54. package/dist-cjs/styles/TLHorizontalAlignStyle.js.map +2 -2
  55. package/dist-cjs/styles/TLSizeStyle.js.map +2 -2
  56. package/dist-cjs/styles/TLTextAlignStyle.js.map +2 -2
  57. package/dist-cjs/styles/TLVerticalAlignStyle.js.map +2 -2
  58. package/dist-cjs/translations/translations.js +1 -1
  59. package/dist-cjs/translations/translations.js.map +2 -2
  60. package/dist-cjs/util-types.js.map +1 -1
  61. package/dist-esm/TLStore.mjs +3 -10
  62. package/dist-esm/TLStore.mjs.map +2 -2
  63. package/dist-esm/assets/TLBaseAsset.mjs.map +2 -2
  64. package/dist-esm/assets/TLBookmarkAsset.mjs.map +2 -2
  65. package/dist-esm/assets/TLImageAsset.mjs.map +2 -2
  66. package/dist-esm/assets/TLVideoAsset.mjs.map +2 -2
  67. package/dist-esm/bindings/TLArrowBinding.mjs.map +2 -2
  68. package/dist-esm/bindings/TLBaseBinding.mjs.map +2 -2
  69. package/dist-esm/createPresenceStateDerivation.mjs.map +2 -2
  70. package/dist-esm/createTLSchema.mjs.map +2 -2
  71. package/dist-esm/index.d.mts +4416 -223
  72. package/dist-esm/index.mjs +1 -1
  73. package/dist-esm/index.mjs.map +2 -2
  74. package/dist-esm/misc/TLColor.mjs.map +2 -2
  75. package/dist-esm/misc/TLCursor.mjs.map +2 -2
  76. package/dist-esm/misc/TLHandle.mjs.map +2 -2
  77. package/dist-esm/misc/TLOpacity.mjs.map +2 -2
  78. package/dist-esm/misc/TLRichText.mjs.map +2 -2
  79. package/dist-esm/misc/TLScribble.mjs.map +2 -2
  80. package/dist-esm/misc/geometry-types.mjs.map +2 -2
  81. package/dist-esm/misc/id-validator.mjs.map +2 -2
  82. package/dist-esm/records/TLAsset.mjs.map +2 -2
  83. package/dist-esm/records/TLBinding.mjs.map +2 -2
  84. package/dist-esm/records/TLCamera.mjs.map +2 -2
  85. package/dist-esm/records/TLDocument.mjs.map +2 -2
  86. package/dist-esm/records/TLInstance.mjs.map +2 -2
  87. package/dist-esm/records/TLPage.mjs.map +2 -2
  88. package/dist-esm/records/TLPageState.mjs.map +2 -2
  89. package/dist-esm/records/TLPointer.mjs.map +2 -2
  90. package/dist-esm/records/TLPresence.mjs.map +2 -2
  91. package/dist-esm/records/TLShape.mjs.map +2 -2
  92. package/dist-esm/recordsWithProps.mjs.map +2 -2
  93. package/dist-esm/shapes/TLArrowShape.mjs.map +2 -2
  94. package/dist-esm/shapes/TLBaseShape.mjs.map +2 -2
  95. package/dist-esm/shapes/TLBookmarkShape.mjs.map +2 -2
  96. package/dist-esm/shapes/TLDrawShape.mjs.map +2 -2
  97. package/dist-esm/shapes/TLEmbedShape.mjs.map +2 -2
  98. package/dist-esm/shapes/TLFrameShape.mjs.map +2 -2
  99. package/dist-esm/shapes/TLGeoShape.mjs.map +2 -2
  100. package/dist-esm/shapes/TLGroupShape.mjs.map +2 -2
  101. package/dist-esm/shapes/TLHighlightShape.mjs.map +2 -2
  102. package/dist-esm/shapes/TLImageShape.mjs.map +2 -2
  103. package/dist-esm/shapes/TLLineShape.mjs.map +2 -2
  104. package/dist-esm/shapes/TLNoteShape.mjs.map +2 -2
  105. package/dist-esm/shapes/TLTextShape.mjs.map +2 -2
  106. package/dist-esm/shapes/TLVideoShape.mjs.map +2 -2
  107. package/dist-esm/store-migrations.mjs.map +2 -2
  108. package/dist-esm/styles/TLColorStyle.mjs.map +2 -2
  109. package/dist-esm/styles/TLDashStyle.mjs.map +2 -2
  110. package/dist-esm/styles/TLFillStyle.mjs.map +2 -2
  111. package/dist-esm/styles/TLFontStyle.mjs.map +2 -2
  112. package/dist-esm/styles/TLHorizontalAlignStyle.mjs.map +2 -2
  113. package/dist-esm/styles/TLSizeStyle.mjs.map +2 -2
  114. package/dist-esm/styles/TLTextAlignStyle.mjs.map +2 -2
  115. package/dist-esm/styles/TLVerticalAlignStyle.mjs.map +2 -2
  116. package/dist-esm/translations/translations.mjs +1 -1
  117. package/dist-esm/translations/translations.mjs.map +2 -2
  118. package/package.json +5 -5
  119. package/src/TLStore.test.ts +644 -0
  120. package/src/TLStore.ts +205 -20
  121. package/src/assets/TLBaseAsset.ts +90 -7
  122. package/src/assets/TLBookmarkAsset.test.ts +96 -0
  123. package/src/assets/TLBookmarkAsset.ts +52 -2
  124. package/src/assets/TLImageAsset.test.ts +213 -0
  125. package/src/assets/TLImageAsset.ts +60 -2
  126. package/src/assets/TLVideoAsset.test.ts +105 -0
  127. package/src/assets/TLVideoAsset.ts +93 -4
  128. package/src/bindings/TLArrowBinding.test.ts +55 -0
  129. package/src/bindings/TLArrowBinding.ts +132 -10
  130. package/src/bindings/TLBaseBinding.ts +140 -3
  131. package/src/createPresenceStateDerivation.test.ts +158 -0
  132. package/src/createPresenceStateDerivation.ts +71 -2
  133. package/src/createTLSchema.test.ts +181 -0
  134. package/src/createTLSchema.ts +164 -7
  135. package/src/index.ts +32 -0
  136. package/src/misc/TLColor.ts +50 -6
  137. package/src/misc/TLCursor.ts +110 -8
  138. package/src/misc/TLHandle.ts +86 -6
  139. package/src/misc/TLOpacity.ts +51 -2
  140. package/src/misc/TLRichText.ts +56 -3
  141. package/src/misc/TLScribble.ts +105 -5
  142. package/src/misc/geometry-types.ts +30 -2
  143. package/src/misc/id-validator.test.ts +50 -0
  144. package/src/misc/id-validator.ts +20 -1
  145. package/src/records/TLAsset.test.ts +234 -0
  146. package/src/records/TLAsset.ts +165 -8
  147. package/src/records/TLBinding.test.ts +22 -0
  148. package/src/records/TLBinding.ts +277 -11
  149. package/src/records/TLCamera.test.ts +19 -0
  150. package/src/records/TLCamera.ts +118 -7
  151. package/src/records/TLDocument.test.ts +35 -0
  152. package/src/records/TLDocument.ts +148 -8
  153. package/src/records/TLInstance.test.ts +201 -0
  154. package/src/records/TLInstance.ts +117 -9
  155. package/src/records/TLPage.test.ts +110 -0
  156. package/src/records/TLPage.ts +106 -8
  157. package/src/records/TLPageState.test.ts +228 -0
  158. package/src/records/TLPageState.ts +88 -7
  159. package/src/records/TLPointer.test.ts +63 -0
  160. package/src/records/TLPointer.ts +105 -7
  161. package/src/records/TLPresence.test.ts +190 -0
  162. package/src/records/TLPresence.ts +99 -5
  163. package/src/records/TLRecord.test.ts +70 -0
  164. package/src/records/TLRecord.ts +43 -1
  165. package/src/records/TLShape.test.ts +232 -0
  166. package/src/records/TLShape.ts +289 -12
  167. package/src/recordsWithProps.test.ts +188 -0
  168. package/src/recordsWithProps.ts +131 -2
  169. package/src/shapes/ShapeWithCrop.test.ts +18 -0
  170. package/src/shapes/ShapeWithCrop.ts +64 -2
  171. package/src/shapes/TLArrowShape.test.ts +505 -0
  172. package/src/shapes/TLArrowShape.ts +188 -10
  173. package/src/shapes/TLBaseShape.test.ts +142 -0
  174. package/src/shapes/TLBaseShape.ts +103 -4
  175. package/src/shapes/TLBookmarkShape.test.ts +122 -0
  176. package/src/shapes/TLBookmarkShape.ts +58 -4
  177. package/src/shapes/TLDrawShape.test.ts +177 -0
  178. package/src/shapes/TLDrawShape.ts +97 -6
  179. package/src/shapes/TLEmbedShape.test.ts +286 -0
  180. package/src/shapes/TLEmbedShape.ts +57 -4
  181. package/src/shapes/TLFrameShape.test.ts +71 -0
  182. package/src/shapes/TLFrameShape.ts +59 -4
  183. package/src/shapes/TLGeoShape.test.ts +247 -0
  184. package/src/shapes/TLGeoShape.ts +103 -7
  185. package/src/shapes/TLGroupShape.test.ts +59 -0
  186. package/src/shapes/TLGroupShape.ts +52 -4
  187. package/src/shapes/TLHighlightShape.test.ts +325 -0
  188. package/src/shapes/TLHighlightShape.ts +79 -4
  189. package/src/shapes/TLImageShape.test.ts +534 -0
  190. package/src/shapes/TLImageShape.ts +105 -5
  191. package/src/shapes/TLLineShape.test.ts +269 -0
  192. package/src/shapes/TLLineShape.ts +128 -8
  193. package/src/shapes/TLNoteShape.test.ts +1568 -0
  194. package/src/shapes/TLNoteShape.ts +97 -4
  195. package/src/shapes/TLTextShape.test.ts +407 -0
  196. package/src/shapes/TLTextShape.ts +94 -4
  197. package/src/shapes/TLVideoShape.test.ts +112 -0
  198. package/src/shapes/TLVideoShape.ts +99 -4
  199. package/src/store-migrations.test.ts +88 -0
  200. package/src/store-migrations.ts +47 -1
  201. package/src/styles/TLColorStyle.test.ts +439 -0
  202. package/src/styles/TLColorStyle.ts +228 -10
  203. package/src/styles/TLDashStyle.ts +54 -2
  204. package/src/styles/TLFillStyle.ts +54 -2
  205. package/src/styles/TLFontStyle.ts +72 -3
  206. package/src/styles/TLHorizontalAlignStyle.ts +55 -2
  207. package/src/styles/TLSizeStyle.ts +54 -2
  208. package/src/styles/TLTextAlignStyle.ts +52 -2
  209. package/src/styles/TLVerticalAlignStyle.ts +52 -2
  210. package/src/translations/translations.test.ts +378 -35
  211. package/src/translations/translations.ts +157 -10
  212. package/src/util-types.ts +51 -1
@@ -0,0 +1,188 @@
1
+ import { Migration, createMigrationSequence } from '@tldraw/store'
2
+ import { T } from '@tldraw/validate'
3
+ import { describe, expect, it, vi } from 'vitest'
4
+ import { SchemaPropsInfo } from './createTLSchema'
5
+ import {
6
+ TLPropsMigration,
7
+ TLPropsMigrations,
8
+ createPropsMigration,
9
+ processPropsMigrations,
10
+ } from './recordsWithProps'
11
+
12
+ describe('createPropsMigration', () => {
13
+ it('should create a store migration from props migration', () => {
14
+ const propsMigration: TLPropsMigration = {
15
+ id: 'com.test.shape.custom/1' as const,
16
+ up: (props: any) => ({ ...props, newProp: 'added' }),
17
+ down: (props: any) => {
18
+ const { newProp: _newProp, ...rest } = props
19
+ return rest
20
+ },
21
+ }
22
+
23
+ const storeMigration = createPropsMigration('shape', 'custom', propsMigration)
24
+
25
+ expect(storeMigration.id).toBe('com.test.shape.custom/1')
26
+ expect(storeMigration.scope).toBe('record')
27
+ expect(typeof storeMigration.up).toBe('function')
28
+ expect(typeof storeMigration.down).toBe('function')
29
+ expect(typeof (storeMigration as any).filter).toBe('function')
30
+ })
31
+
32
+ it('should apply up migration to record props', () => {
33
+ const propsMigration: TLPropsMigration = {
34
+ id: 'com.test.shape.custom/1' as const,
35
+ up: (props: any) => ({ ...props, newProp: 'added' }),
36
+ }
37
+
38
+ const storeMigration = createPropsMigration('shape', 'custom', propsMigration)
39
+
40
+ const record = {
41
+ id: 'shape:test' as const,
42
+ typeName: 'shape' as const,
43
+ type: 'custom' as const,
44
+ props: { oldProp: 'value' },
45
+ }
46
+
47
+ storeMigration.up(record as any)
48
+
49
+ expect(record.props).toEqual({
50
+ oldProp: 'value',
51
+ newProp: 'added',
52
+ })
53
+ })
54
+
55
+ it('should apply down migration to record props', () => {
56
+ const propsMigration: TLPropsMigration = {
57
+ id: 'com.test.shape.custom/1' as const,
58
+ up: (props: any) => ({ ...props, newProp: 'added' }),
59
+ down: (props: any) => {
60
+ const { newProp: _newProp, ...rest } = props
61
+ return rest
62
+ },
63
+ }
64
+
65
+ const storeMigration = createPropsMigration('shape', 'custom', propsMigration)
66
+
67
+ const record = {
68
+ id: 'shape:test' as const,
69
+ typeName: 'shape' as const,
70
+ type: 'custom' as const,
71
+ props: { oldProp: 'value', newProp: 'added' },
72
+ }
73
+
74
+ if (storeMigration.down) {
75
+ storeMigration.down(record as any)
76
+ }
77
+
78
+ expect(record.props).toEqual({ oldProp: 'value' })
79
+ })
80
+ })
81
+
82
+ describe('processPropsMigrations', () => {
83
+ it('should throw error for mismatched sequenceId', () => {
84
+ const wrongSequenceId = createMigrationSequence({
85
+ sequenceId: 'com.wrong.shape.custom', // Wrong sequence ID
86
+ retroactive: true,
87
+ sequence: [],
88
+ })
89
+
90
+ const records: Record<string, SchemaPropsInfo> = {
91
+ custom: {
92
+ props: { width: T.number },
93
+ migrations: wrongSequenceId,
94
+ },
95
+ }
96
+
97
+ expect(() => processPropsMigrations('shape', records)).toThrow(`sequenceId mismatch for custom`)
98
+ })
99
+
100
+ it('should process TLPropsMigrations format', () => {
101
+ const propsMigrations: TLPropsMigrations = {
102
+ sequence: [
103
+ {
104
+ id: 'com.tldraw.shape.custom/1',
105
+ up: (props: any) => ({ ...props, v: 1 }),
106
+ down: (props: any) => {
107
+ const { v: _v, ...rest } = props
108
+ return rest
109
+ },
110
+ },
111
+ {
112
+ id: 'com.tldraw.shape.custom/2',
113
+ dependsOn: ['com.tldraw.shape.custom/1'],
114
+ up: (props: any) => ({ ...props, v: 2 }),
115
+ down: (props: any) => ({ ...props, v: 1 }),
116
+ },
117
+ ],
118
+ }
119
+
120
+ const records: Record<string, SchemaPropsInfo> = {
121
+ custom: {
122
+ props: { width: T.number },
123
+ migrations: propsMigrations,
124
+ },
125
+ }
126
+
127
+ const result = processPropsMigrations('shape', records)
128
+
129
+ expect(result).toHaveLength(1)
130
+ expect(result[0].sequenceId).toBe('com.tldraw.shape.custom')
131
+ expect(result[0].retroactive).toBe(true)
132
+ expect(result[0].sequence).toHaveLength(2)
133
+
134
+ // Check that props migrations were converted to store migrations
135
+ const storeMigrations = result[0].sequence as Migration[]
136
+ expect(storeMigrations[0].id).toBe('com.tldraw.shape.custom/1')
137
+ expect(storeMigrations[0].scope).toBe('record')
138
+ expect(storeMigrations[1].id).toBe('com.tldraw.shape.custom/2')
139
+ expect(storeMigrations[1].dependsOn).toEqual(['com.tldraw.shape.custom/1'])
140
+ })
141
+
142
+ it('should process legacy migrations format', () => {
143
+ const legacyMigrations = {
144
+ migrators: {
145
+ 1: {
146
+ up: vi.fn((record: any) => ({ ...record, version: 1 })),
147
+ down: vi.fn((record: any) => {
148
+ const { version: _version, ...rest } = record
149
+ return rest
150
+ }),
151
+ },
152
+ 2: {
153
+ up: vi.fn((record: any) => ({ ...record, version: 2 })),
154
+ down: vi.fn((record: any) => ({ ...record, version: 1 })),
155
+ },
156
+ },
157
+ }
158
+
159
+ const records: Record<string, SchemaPropsInfo> = {
160
+ legacy: {
161
+ props: { width: T.number },
162
+ migrations: legacyMigrations as any,
163
+ },
164
+ }
165
+
166
+ const result = processPropsMigrations('shape', records)
167
+
168
+ expect(result).toHaveLength(1)
169
+ expect(result[0].sequenceId).toBe('com.tldraw.shape.legacy')
170
+ expect(result[0].retroactive).toBe(true)
171
+ expect(result[0].sequence).toHaveLength(2)
172
+
173
+ // Check legacy migration conversion
174
+ const migrations = result[0].sequence as Migration[]
175
+ expect(migrations[0].id).toBe('com.tldraw.shape.legacy/1')
176
+ expect(migrations[0].scope).toBe('record')
177
+ expect(migrations[1].id).toBe('com.tldraw.shape.legacy/2')
178
+ expect(migrations[1].scope).toBe('record')
179
+
180
+ // Test filter function - cast to the specific migration type that has filter
181
+ const recordMigration = migrations[0] as any
182
+ const matchingRecord = { typeName: 'shape', type: 'legacy' }
183
+ const nonMatchingRecord = { typeName: 'shape', type: 'other' }
184
+
185
+ expect(recordMigration.filter(matchingRecord)).toBe(true)
186
+ expect(recordMigration.filter(nonMatchingRecord)).toBe(false)
187
+ })
188
+ })
@@ -11,18 +11,78 @@ import { MakeUndefinedOptional, assert } from '@tldraw/utils'
11
11
  import { T } from '@tldraw/validate'
12
12
  import { SchemaPropsInfo } from './createTLSchema'
13
13
 
14
- /** @public */
14
+ /**
15
+ * Maps a record's property types to their corresponding validators.
16
+ *
17
+ * This utility type takes a record type with a `props` object and creates
18
+ * a mapping where each property key maps to a validator for that property's type.
19
+ * This is used to define validation schemas for record properties.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * interface MyShape extends TLBaseShape<'custom', { width: number; color: string }> {}
24
+ *
25
+ * // Define validators for the shape properties
26
+ * const myShapeProps: RecordProps<MyShape> = {
27
+ * width: T.number,
28
+ * color: T.string
29
+ * }
30
+ * ```
31
+ *
32
+ * @public
33
+ */
15
34
  export type RecordProps<R extends UnknownRecord & { props: object }> = {
16
35
  [K in keyof R['props']]: T.Validatable<R['props'][K]>
17
36
  }
18
37
 
19
- /** @public */
38
+ /**
39
+ * Extracts the TypeScript types from a record properties configuration.
40
+ *
41
+ * Takes a configuration object where values are validators and returns the
42
+ * corresponding TypeScript types, with undefined values made optional.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const shapePropsConfig = {
47
+ * width: T.number,
48
+ * height: T.number,
49
+ * color: T.optional(T.string)
50
+ * }
51
+ *
52
+ * type ShapeProps = RecordPropsType<typeof shapePropsConfig>
53
+ * // Result: { width: number; height: number; color?: string }
54
+ * ```
55
+ *
56
+ * @public
57
+ */
20
58
  export type RecordPropsType<Config extends Record<string, T.Validatable<any>>> =
21
59
  MakeUndefinedOptional<{
22
60
  [K in keyof Config]: T.TypeOf<Config[K]>
23
61
  }>
24
62
 
25
63
  /**
64
+ * A migration definition for shape or record properties.
65
+ *
66
+ * Defines how to transform record properties when migrating between schema versions.
67
+ * Each migration has an `up` function to upgrade data and an optional `down` function
68
+ * to downgrade data if needed.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * const addColorMigration: TLPropsMigration = {
73
+ * id: 'com.myapp.shape.custom/1.0.0',
74
+ * up: (props) => {
75
+ * // Add a default color property
76
+ * return { ...props, color: 'black' }
77
+ * },
78
+ * down: (props) => {
79
+ * // Remove the color property
80
+ * const { color, ...rest } = props
81
+ * return rest
82
+ * }
83
+ * }
84
+ * ```
85
+ *
26
86
  * @public
27
87
  */
28
88
  export interface TLPropsMigration {
@@ -43,12 +103,57 @@ export interface TLPropsMigration {
43
103
  }
44
104
 
45
105
  /**
106
+ * A sequence of property migrations for a record type.
107
+ *
108
+ * Contains an ordered array of migrations that should be applied to transform
109
+ * record properties from one version to another. Migrations can include both
110
+ * property-specific migrations and standalone dependency declarations.
111
+ *
112
+ * @example
113
+ * ```ts
114
+ * const myShapeMigrations: TLPropsMigrations = {
115
+ * sequence: [
116
+ * {
117
+ * id: 'com.myapp.shape.custom/1.0.0',
118
+ * up: (props) => ({ ...props, version: 1 })
119
+ * },
120
+ * {
121
+ * id: 'com.myapp.shape.custom/2.0.0',
122
+ * up: (props) => ({ ...props, newFeature: true })
123
+ * }
124
+ * ]
125
+ * }
126
+ * ```
127
+ *
46
128
  * @public
47
129
  */
48
130
  export interface TLPropsMigrations {
49
131
  readonly sequence: Array<StandaloneDependsOn | TLPropsMigration>
50
132
  }
51
133
 
134
+ /**
135
+ * Processes property migrations for all record types in a schema.
136
+ *
137
+ * Takes a collection of record configurations and converts their migrations
138
+ * into proper migration sequences that can be used by the store system.
139
+ * Handles different migration formats including legacy migrations.
140
+ *
141
+ * @param typeName - The base type name for the records (e.g., 'shape', 'binding')
142
+ * @param records - Record of type names to their schema configuration
143
+ * @returns Array of processed migration sequences
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * const shapeRecords = {
148
+ * geo: { props: geoProps, migrations: geoMigrations },
149
+ * arrow: { props: arrowProps, migrations: arrowMigrations }
150
+ * }
151
+ *
152
+ * const sequences = processPropsMigrations('shape', shapeRecords)
153
+ * ```
154
+ *
155
+ * @internal
156
+ */
52
157
  export function processPropsMigrations<R extends UnknownRecord & { type: string; props: object }>(
53
158
  typeName: R['typeName'],
54
159
  records: Record<string, SchemaPropsInfo>
@@ -118,6 +223,30 @@ export function processPropsMigrations<R extends UnknownRecord & { type: string;
118
223
  return result
119
224
  }
120
225
 
226
+ /**
227
+ * Creates a store migration from a props migration definition.
228
+ *
229
+ * Converts a high-level property migration into a low-level store migration
230
+ * that can be applied to records. The resulting migration will only affect
231
+ * records of the specified type and subtype.
232
+ *
233
+ * @param typeName - The base type name (e.g., 'shape', 'binding')
234
+ * @param subType - The specific subtype (e.g., 'geo', 'arrow')
235
+ * @param m - The property migration definition
236
+ * @returns A store migration that applies the property transformation
237
+ *
238
+ * @example
239
+ * ```ts
240
+ * const propsMigration: TLPropsMigration = {
241
+ * id: 'com.myapp.shape.custom/1.0.0',
242
+ * up: (props) => ({ ...props, color: 'blue' })
243
+ * }
244
+ *
245
+ * const storeMigration = createPropsMigration('shape', 'custom', propsMigration)
246
+ * ```
247
+ *
248
+ * @internal
249
+ */
121
250
  export function createPropsMigration<R extends UnknownRecord & { type: string; props: object }>(
122
251
  typeName: R['typeName'],
123
252
  subType: R['type'],
@@ -0,0 +1,18 @@
1
+ import { describe, expect, test } from 'vitest'
2
+ import { TLShapeCrop } from './ShapeWithCrop'
3
+
4
+ describe('TLShapeCrop', () => {
5
+ test('should calculate crop dimensions correctly', () => {
6
+ const crop: TLShapeCrop = {
7
+ topLeft: { x: 0.2, y: 0.3 },
8
+ bottomRight: { x: 0.8, y: 0.7 },
9
+ }
10
+
11
+ // This tests the actual utility of the crop interface - calculating dimensions
12
+ const width = crop.bottomRight.x - crop.topLeft.x
13
+ const height = crop.bottomRight.y - crop.topLeft.y
14
+
15
+ expect(width).toBeCloseTo(0.6)
16
+ expect(height).toBeCloseTo(0.4)
17
+ })
18
+ })
@@ -1,12 +1,74 @@
1
1
  import { VecModel } from '../misc/geometry-types'
2
2
  import { TLBaseShape } from './TLBaseShape'
3
3
 
4
- /** @public */
4
+ /**
5
+ * Defines cropping parameters for shapes that support cropping.
6
+ *
7
+ * Specifies the visible area of an asset (like an image or video) within a shape.
8
+ * The crop is defined by top-left and bottom-right coordinates in normalized space (0-1),
9
+ * where (0,0) is the top-left of the original asset and (1,1) is the bottom-right.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * // Crop the center 50% of an image
14
+ * const centerCrop: TLShapeCrop = {
15
+ * topLeft: { x: 0.25, y: 0.25 },
16
+ * bottomRight: { x: 0.75, y: 0.75 }
17
+ * }
18
+ *
19
+ * // Crop for a circular image shape
20
+ * const circleCrop: TLShapeCrop = {
21
+ * topLeft: { x: 0, y: 0 },
22
+ * bottomRight: { x: 1, y: 1 },
23
+ * isCircle: true
24
+ * }
25
+ * ```
26
+ *
27
+ * @public
28
+ */
5
29
  export interface TLShapeCrop {
6
30
  topLeft: VecModel
7
31
  bottomRight: VecModel
8
32
  isCircle?: boolean
9
33
  }
10
34
 
11
- /** @public */
35
+ /**
36
+ * A shape type that supports cropping functionality.
37
+ *
38
+ * This type represents any shape that can display cropped content, typically media shapes
39
+ * like images and videos. The shape has width, height, and optional crop parameters.
40
+ * When crop is null, the entire asset is displayed.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * // An image shape with cropping
45
+ * const croppedImageShape: ShapeWithCrop = {
46
+ * id: 'shape:image1',
47
+ * type: 'image',
48
+ * x: 100,
49
+ * y: 200,
50
+ * // ... other base shape properties
51
+ * props: {
52
+ * w: 300,
53
+ * h: 200,
54
+ * crop: {
55
+ * topLeft: { x: 0.1, y: 0.1 },
56
+ * bottomRight: { x: 0.9, y: 0.9 }
57
+ * }
58
+ * }
59
+ * }
60
+ *
61
+ * // A shape without cropping (shows full asset)
62
+ * const fullImageShape: ShapeWithCrop = {
63
+ * // ... shape properties
64
+ * props: {
65
+ * w: 400,
66
+ * h: 300,
67
+ * crop: null // Shows entire asset
68
+ * }
69
+ * }
70
+ * ```
71
+ *
72
+ * @public
73
+ */
12
74
  export type ShapeWithCrop = TLBaseShape<string, { w: number; h: number; crop: TLShapeCrop | null }>