@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.
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,232 @@
1
+ import { T } from '@tldraw/validate'
2
+ import { describe, expect, it } from 'vitest'
3
+ import { StyleProp } from '../styles/StyleProp'
4
+ import {
5
+ createShapeId,
6
+ createShapePropsMigrationIds,
7
+ createShapeRecordType,
8
+ getShapePropKeysByStyle,
9
+ isShape,
10
+ isShapeId,
11
+ rootShapeMigrations,
12
+ rootShapeVersions,
13
+ TLShapeId,
14
+ } from './TLShape'
15
+
16
+ describe('rootShapeMigrations', () => {
17
+ it('should migrate AddIsLocked correctly', () => {
18
+ const migration = rootShapeMigrations.sequence.find(
19
+ (m) => m.id === rootShapeVersions.AddIsLocked
20
+ )!
21
+ expect(migration.up).toBeDefined()
22
+ expect(migration.down).toBeDefined()
23
+
24
+ const record: any = { id: 'shape:test', typeName: 'shape', type: 'geo' }
25
+ migration.up(record)
26
+ expect(record.isLocked).toBe(false)
27
+
28
+ migration.down!(record)
29
+ expect(record.isLocked).toBeUndefined()
30
+ })
31
+
32
+ it('should migrate HoistOpacity correctly', () => {
33
+ const migration = rootShapeMigrations.sequence.find(
34
+ (m) => m.id === rootShapeVersions.HoistOpacity
35
+ )!
36
+ expect(migration.up).toBeDefined()
37
+ expect(migration.down).toBeDefined()
38
+
39
+ // Test up migration
40
+ const record: any = {
41
+ id: 'shape:test',
42
+ typeName: 'shape',
43
+ type: 'geo',
44
+ props: { opacity: '0.5', color: 'red' },
45
+ }
46
+ migration.up(record)
47
+ expect(record.opacity).toBe(0.5)
48
+ expect(record.props.opacity).toBeUndefined()
49
+ expect(record.props.color).toBe('red')
50
+
51
+ // Test down migration
52
+ migration.down!(record)
53
+ expect(record.props.opacity).toBe('0.5')
54
+ expect(record.opacity).toBeUndefined()
55
+ })
56
+
57
+ it('should migrate AddMeta correctly', () => {
58
+ const migration = rootShapeMigrations.sequence.find((m) => m.id === rootShapeVersions.AddMeta)!
59
+ const record: any = { id: 'shape:test', typeName: 'shape', type: 'geo' }
60
+ migration.up(record)
61
+ expect(record.meta).toEqual({})
62
+ })
63
+
64
+ it('should handle AddWhite migration', () => {
65
+ const migration = rootShapeMigrations.sequence.find((m) => m.id === rootShapeVersions.AddWhite)!
66
+ expect(migration.up).toBeDefined()
67
+ expect(migration.down).toBeDefined()
68
+
69
+ // Up migration is noop
70
+ const record: any = { props: { color: 'white' } }
71
+ const original = { ...record }
72
+ migration.up(record)
73
+ expect(record).toEqual(original)
74
+
75
+ // Down migration converts white to black
76
+ migration.down!(record)
77
+ expect(record.props.color).toBe('black')
78
+ })
79
+ })
80
+
81
+ describe('isShape', () => {
82
+ it('should return true for shape records', () => {
83
+ const shape = {
84
+ id: 'shape:test' as TLShapeId,
85
+ typeName: 'shape',
86
+ type: 'geo',
87
+ x: 0,
88
+ y: 0,
89
+ rotation: 0,
90
+ index: 'a1' as any,
91
+ parentId: 'page:main' as any,
92
+ isLocked: false,
93
+ opacity: 1,
94
+ props: {},
95
+ meta: {},
96
+ }
97
+
98
+ expect(isShape(shape)).toBe(true)
99
+ })
100
+
101
+ it('should return false for non-shape records', () => {
102
+ const notShape = {
103
+ id: 'page:test',
104
+ typeName: 'page',
105
+ name: 'Test Page',
106
+ }
107
+
108
+ expect(isShape(notShape as any)).toBe(false)
109
+ })
110
+ })
111
+
112
+ describe('isShapeId', () => {
113
+ it('should return true for valid shape IDs', () => {
114
+ expect(isShapeId('shape:test')).toBe(true)
115
+ expect(isShapeId('shape:abc123')).toBe(true)
116
+ expect(isShapeId('shape:')).toBe(true)
117
+ })
118
+
119
+ it('should return false for invalid shape IDs', () => {
120
+ expect(isShapeId('page:test')).toBe(false)
121
+ expect(isShapeId('asset:test')).toBe(false)
122
+ expect(isShapeId('invalid')).toBe(false)
123
+ expect(isShapeId('')).toBe(false)
124
+ })
125
+ })
126
+
127
+ describe('createShapeId', () => {
128
+ it('should create shape IDs with auto-generated suffix', () => {
129
+ const id1 = createShapeId()
130
+ const id2 = createShapeId()
131
+
132
+ expect(id1.startsWith('shape:')).toBe(true)
133
+ expect(id2.startsWith('shape:')).toBe(true)
134
+ expect(id1).not.toBe(id2)
135
+ expect(id1.length).toBeGreaterThan(6) // 'shape:' + some ID
136
+ expect(id2.length).toBeGreaterThan(6)
137
+ })
138
+
139
+ it('should create shape IDs with custom suffix', () => {
140
+ const customId = createShapeId('my-custom-id')
141
+ expect(customId).toBe('shape:my-custom-id')
142
+ })
143
+ })
144
+
145
+ describe('getShapePropKeysByStyle', () => {
146
+ it('should map style props to their keys', () => {
147
+ const colorStyle = StyleProp.define('color', { defaultValue: 'black' })
148
+ const sizeStyle = StyleProp.define('size', { defaultValue: 'm' })
149
+
150
+ const props = {
151
+ color: colorStyle,
152
+ size: sizeStyle,
153
+ width: T.number,
154
+ height: T.number,
155
+ }
156
+
157
+ const styleMap = getShapePropKeysByStyle(props)
158
+ expect(styleMap.get(colorStyle)).toBe('color')
159
+ expect(styleMap.get(sizeStyle)).toBe('size')
160
+ expect(styleMap.size).toBe(2) // Only style props
161
+ })
162
+
163
+ it('should throw error for duplicate style props', () => {
164
+ const colorStyle = StyleProp.define('color', { defaultValue: 'black' })
165
+ const props = {
166
+ color1: colorStyle,
167
+ color2: colorStyle, // Same style prop used twice
168
+ width: T.number,
169
+ }
170
+
171
+ expect(() => getShapePropKeysByStyle(props)).toThrow('Duplicate style prop')
172
+ })
173
+ })
174
+
175
+ describe('createShapePropsMigrationIds', () => {
176
+ it('should create formatted migration IDs', () => {
177
+ const ids = createShapePropsMigrationIds('custom', {
178
+ AddColor: 1,
179
+ AddSize: 2,
180
+ RefactorProps: 3,
181
+ })
182
+
183
+ expect(ids.AddColor).toBe('com.tldraw.shape.custom/1')
184
+ expect(ids.AddSize).toBe('com.tldraw.shape.custom/2')
185
+ expect(ids.RefactorProps).toBe('com.tldraw.shape.custom/3')
186
+ })
187
+ })
188
+
189
+ describe('createShapeRecordType', () => {
190
+ it('should create a record type for shapes', () => {
191
+ const shapes = {
192
+ geo: {
193
+ props: {
194
+ w: T.number,
195
+ h: T.number,
196
+ color: StyleProp.define('color', { defaultValue: 'black' }),
197
+ },
198
+ meta: {},
199
+ },
200
+ text: {
201
+ props: {
202
+ text: T.string,
203
+ size: StyleProp.define('size', { defaultValue: 'm' }),
204
+ },
205
+ meta: {},
206
+ },
207
+ }
208
+
209
+ const ShapeRecordType = createShapeRecordType(shapes)
210
+
211
+ expect(ShapeRecordType.typeName).toBe('shape')
212
+ expect(ShapeRecordType.scope).toBe('document')
213
+
214
+ // Should be able to create shapes
215
+ const geoShape = ShapeRecordType.create({
216
+ id: createShapeId(),
217
+ type: 'geo',
218
+ parentId: 'page:main' as any,
219
+ index: 'a1' as any,
220
+ props: {},
221
+ })
222
+
223
+ expect(geoShape.typeName).toBe('shape')
224
+ expect(geoShape.type).toBe('geo')
225
+ expect(geoShape.x).toBe(0) // Default
226
+ expect(geoShape.y).toBe(0) // Default
227
+ expect(geoShape.rotation).toBe(0) // Default
228
+ expect(geoShape.isLocked).toBe(false) // Default
229
+ expect(geoShape.opacity).toBe(1) // Default
230
+ expect(geoShape.meta).toEqual({}) // Default
231
+ })
232
+ })
@@ -29,7 +29,21 @@ import { TLPageId } from './TLPage'
29
29
  /**
30
30
  * The default set of shapes that are available in the editor.
31
31
  *
32
- * @public */
32
+ * This union type represents all the built-in shape types supported by tldraw,
33
+ * including arrows, bookmarks, drawings, embeds, frames, geometry shapes,
34
+ * groups, images, lines, notes, text, videos, and highlights.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * // Check if a shape is a default shape type
39
+ * function isDefaultShape(shape: TLShape): shape is TLDefaultShape {
40
+ * const defaultTypes = ['arrow', 'bookmark', 'draw', 'embed', 'frame', 'geo', 'group', 'image', 'line', 'note', 'text', 'video', 'highlight']
41
+ * return defaultTypes.includes(shape.type)
42
+ * }
43
+ * ```
44
+ *
45
+ * @public
46
+ */
33
47
  export type TLDefaultShape =
34
48
  | TLArrowShape
35
49
  | TLBookmarkShape
@@ -49,17 +63,73 @@ export type TLDefaultShape =
49
63
  * A type for a shape that is available in the editor but whose type is
50
64
  * unknown—either one of the editor's default shapes or else a custom shape.
51
65
  *
52
- * @public */
66
+ * This is useful when working with shapes generically without knowing their specific type.
67
+ * The shape type is a string and props are a generic object.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * // Handle any shape regardless of its specific type
72
+ * function processUnknownShape(shape: TLUnknownShape) {
73
+ * console.log(`Processing shape of type: ${shape.type}`)
74
+ * console.log(`Position: (${shape.x}, ${shape.y})`)
75
+ * }
76
+ * ```
77
+ *
78
+ * @public
79
+ */
53
80
  export type TLUnknownShape = TLBaseShape<string, object>
54
81
 
55
82
  /**
56
83
  * The set of all shapes that are available in the editor, including unknown shapes.
57
84
  *
85
+ * This is the primary shape type used throughout tldraw. It includes both the
86
+ * built-in default shapes and any custom shapes that might be added.
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * // Work with any shape in the editor
91
+ * function moveShape(shape: TLShape, deltaX: number, deltaY: number): TLShape {
92
+ * return {
93
+ * ...shape,
94
+ * x: shape.x + deltaX,
95
+ * y: shape.y + deltaY
96
+ * }
97
+ * }
98
+ * ```
99
+ *
58
100
  * @public
59
101
  */
60
102
  export type TLShape = TLDefaultShape | TLUnknownShape
61
103
 
62
- /** @public */
104
+ /**
105
+ * A partial version of a shape, useful for updates and patches.
106
+ *
107
+ * This type represents a shape where all properties except `id` and `type` are optional.
108
+ * It's commonly used when updating existing shapes or creating shape patches.
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * // Update a shape's position
113
+ * const shapeUpdate: TLShapePartial = {
114
+ * id: 'shape:123',
115
+ * type: 'geo',
116
+ * x: 100,
117
+ * y: 200
118
+ * }
119
+ *
120
+ * // Update shape properties
121
+ * const propsUpdate: TLShapePartial<TLGeoShape> = {
122
+ * id: 'shape:123',
123
+ * type: 'geo',
124
+ * props: {
125
+ * w: 150,
126
+ * h: 100
127
+ * }
128
+ * }
129
+ * ```
130
+ *
131
+ * @public
132
+ */
63
133
  export type TLShapePartial<T extends TLShape = TLShape> = T extends T
64
134
  ? {
65
135
  id: TLShapeId
@@ -69,13 +139,57 @@ export type TLShapePartial<T extends TLShape = TLShape> = T extends T
69
139
  } & Partial<Omit<T, 'type' | 'id' | 'props' | 'meta'>>
70
140
  : never
71
141
 
72
- /** @public */
142
+ /**
143
+ * A unique identifier for a shape record.
144
+ *
145
+ * Shape IDs are branded strings that start with "shape:" followed by a unique identifier.
146
+ * This type-safe approach prevents mixing up different types of record IDs.
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * const shapeId: TLShapeId = createShapeId() // "shape:abc123"
151
+ * const customId: TLShapeId = createShapeId('my-custom-id') // "shape:my-custom-id"
152
+ * ```
153
+ *
154
+ * @public
155
+ */
73
156
  export type TLShapeId = RecordId<TLUnknownShape>
74
157
 
75
- /** @public */
158
+ /**
159
+ * The ID of a shape's parent, which can be either a page or another shape.
160
+ *
161
+ * Shapes can be parented to pages (for top-level shapes) or to other shapes
162
+ * (for shapes inside frames or groups).
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * // Shape parented to a page
167
+ * const pageParentId: TLParentId = 'page:main'
168
+ *
169
+ * // Shape parented to another shape (e.g., inside a frame)
170
+ * const shapeParentId: TLParentId = 'shape:frame123'
171
+ * ```
172
+ *
173
+ * @public
174
+ */
76
175
  export type TLParentId = TLPageId | TLShapeId
77
176
 
78
- /** @public */
177
+ /**
178
+ * Migration version IDs for the root shape schema.
179
+ *
180
+ * These track the evolution of the base shape structure over time, ensuring
181
+ * that shapes created in older versions can be migrated to newer formats.
182
+ *
183
+ * @example
184
+ * ```ts
185
+ * // Check if a migration needs to be applied
186
+ * if (shapeVersion < rootShapeVersions.AddIsLocked) {
187
+ * // Apply isLocked migration
188
+ * }
189
+ * ```
190
+ *
191
+ * @public
192
+ */
79
193
  export const rootShapeVersions = createMigrationIds('com.tldraw.shape', {
80
194
  AddIsLocked: 1,
81
195
  HoistOpacity: 2,
@@ -83,7 +197,15 @@ export const rootShapeVersions = createMigrationIds('com.tldraw.shape', {
83
197
  AddWhite: 4,
84
198
  } as const)
85
199
 
86
- /** @public */
200
+ /**
201
+ * Migration sequence for the root shape record type.
202
+ *
203
+ * This sequence defines how shape records should be transformed when migrating
204
+ * between different schema versions. Each migration handles a specific version
205
+ * upgrade, ensuring data compatibility across tldraw versions.
206
+ *
207
+ * @public
208
+ */
87
209
  export const rootShapeMigrations = createRecordMigrationSequence({
88
210
  sequenceId: 'com.tldraw.shape',
89
211
  recordType: 'shape',
@@ -138,24 +260,115 @@ export const rootShapeMigrations = createRecordMigrationSequence({
138
260
  ],
139
261
  })
140
262
 
141
- /** @public */
263
+ /**
264
+ * Type guard to check if a record is a shape.
265
+ *
266
+ * @param record - The record to check
267
+ * @returns True if the record is a shape, false otherwise
268
+ *
269
+ * @example
270
+ * ```ts
271
+ * const record = store.get('shape:abc123')
272
+ * if (isShape(record)) {
273
+ * console.log(`Shape type: ${record.type}`)
274
+ * console.log(`Position: (${record.x}, ${record.y})`)
275
+ * }
276
+ * ```
277
+ *
278
+ * @public
279
+ */
142
280
  export function isShape(record?: UnknownRecord): record is TLShape {
143
281
  if (!record) return false
144
282
  return record.typeName === 'shape'
145
283
  }
146
284
 
147
- /** @public */
285
+ /**
286
+ * Type guard to check if a string is a valid shape ID.
287
+ *
288
+ * @param id - The string to check
289
+ * @returns True if the string is a valid shape ID, false otherwise
290
+ *
291
+ * @example
292
+ * ```ts
293
+ * const id = 'shape:abc123'
294
+ * if (isShapeId(id)) {
295
+ * const shape = store.get(id) // TypeScript knows id is TLShapeId
296
+ * }
297
+ *
298
+ * // Check user input
299
+ * function selectShape(id: string) {
300
+ * if (isShapeId(id)) {
301
+ * editor.selectShape(id)
302
+ * } else {
303
+ * console.error('Invalid shape ID format')
304
+ * }
305
+ * }
306
+ * ```
307
+ *
308
+ * @public
309
+ */
148
310
  export function isShapeId(id?: string): id is TLShapeId {
149
311
  if (!id) return false
150
312
  return id.startsWith('shape:')
151
313
  }
152
314
 
153
- /** @public */
315
+ /**
316
+ * Creates a new shape ID.
317
+ *
318
+ * @param id - Optional custom ID suffix. If not provided, a unique ID will be generated
319
+ * @returns A new shape ID with the "shape:" prefix
320
+ *
321
+ * @example
322
+ * ```ts
323
+ * // Create a shape with auto-generated ID
324
+ * const shapeId = createShapeId() // "shape:abc123"
325
+ *
326
+ * // Create a shape with custom ID
327
+ * const customShapeId = createShapeId('my-rectangle') // "shape:my-rectangle"
328
+ *
329
+ * // Use in shape creation
330
+ * const newShape: TLGeoShape = {
331
+ * id: createShapeId(),
332
+ * type: 'geo',
333
+ * x: 100,
334
+ * y: 200,
335
+ * // ... other properties
336
+ * }
337
+ * ```
338
+ *
339
+ * @public
340
+ */
154
341
  export function createShapeId(id?: string): TLShapeId {
155
342
  return `shape:${id ?? uniqueId()}` as TLShapeId
156
343
  }
157
344
 
158
- /** @internal */
345
+ /**
346
+ * Extracts style properties from a shape's props definition and maps them to their property keys.
347
+ *
348
+ * This function analyzes shape property validators to identify which ones are style properties
349
+ * and creates a mapping from StyleProp instances to their corresponding property keys.
350
+ * It also validates that each style property is only used once per shape.
351
+ *
352
+ * @param props - Record of property validators for a shape type
353
+ * @returns Map from StyleProp instances to their property keys
354
+ * @throws Error if a style property is used more than once in the same shape
355
+ *
356
+ * @example
357
+ * ```ts
358
+ * const geoShapeProps = {
359
+ * color: DefaultColorStyle,
360
+ * fill: DefaultFillStyle,
361
+ * width: T.number,
362
+ * height: T.number
363
+ * }
364
+ *
365
+ * const styleMap = getShapePropKeysByStyle(geoShapeProps)
366
+ * // styleMap.get(DefaultColorStyle) === 'color'
367
+ * // styleMap.get(DefaultFillStyle) === 'fill'
368
+ * ```
369
+ *
370
+ * @internal
371
+ */
159
372
  export function getShapePropKeysByStyle(props: Record<string, T.Validatable<any>>) {
160
373
  const propKeysByStyle = new Map<StyleProp<unknown>, string>()
161
374
  for (const [key, prop] of Object.entries(props)) {
@@ -172,6 +385,27 @@ export function getShapePropKeysByStyle(props: Record<string, T.Validatable<any>
172
385
  }
173
386
 
174
387
  /**
388
+ * Creates a migration sequence for shape properties.
389
+ *
390
+ * This is a pass-through function that maintains the same structure as the input.
391
+ * It's used for consistency and to provide a clear API for defining shape property migrations.
392
+ *
393
+ * @param migrations - The migration sequence to create
394
+ * @returns The same migration sequence (pass-through)
395
+ *
396
+ * @example
397
+ * ```ts
398
+ * const myShapeMigrations = createShapePropsMigrationSequence({
399
+ * sequence: [
400
+ * {
401
+ * id: 'com.myapp.shape.custom/1.0.0',
402
+ * up: (props) => ({ ...props, newProperty: 'default' }),
403
+ * down: ({ newProperty, ...props }) => props
404
+ * }
405
+ * ]
406
+ * })
407
+ * ```
408
+ *
175
409
  * @public
176
410
  */
177
411
  export function createShapePropsMigrationSequence(
@@ -181,6 +415,29 @@ export function createShapePropsMigrationSequence(
181
415
  }
182
416
 
183
417
  /**
418
+ * Creates properly formatted migration IDs for shape properties.
419
+ *
420
+ * Generates standardized migration IDs following the convention:
421
+ * `com.tldraw.shape.{shapeType}/{version}`
422
+ *
423
+ * @param shapeType - The type of shape these migrations apply to
424
+ * @param ids - Record mapping migration names to version numbers
425
+ * @returns Record with the same keys but formatted migration ID values
426
+ *
427
+ * @example
428
+ * ```ts
429
+ * const myShapeVersions = createShapePropsMigrationIds('custom', {
430
+ * AddColor: 1,
431
+ * AddSize: 2,
432
+ * RefactorProps: 3
433
+ * })
434
+ * // Result: {
435
+ * // AddColor: 'com.tldraw.shape.custom/1',
436
+ * // AddSize: 'com.tldraw.shape.custom/2',
437
+ * // RefactorProps: 'com.tldraw.shape.custom/3'
438
+ * // }
439
+ * ```
440
+ *
184
441
  * @public
185
442
  */
186
443
  export function createShapePropsMigrationIds<
@@ -190,7 +447,27 @@ export function createShapePropsMigrationIds<
190
447
  return mapObjectMapValues(ids, (_k, v) => `com.tldraw.shape.${shapeType}/${v}`) as any
191
448
  }
192
449
 
193
- /** @internal */
450
+ /**
451
+ * Creates the record type definition for shapes.
452
+ *
453
+ * This function generates a complete record type for shapes that includes validation
454
+ * for all registered shape types. It combines the base shape properties with
455
+ * type-specific properties and creates a union validator that can handle any
456
+ * registered shape type.
457
+ *
458
+ * @param shapes - Record of shape type names to their schema configuration
459
+ * @returns A complete RecordType for shapes with proper validation and default properties
460
+ *
461
+ * @example
462
+ * ```ts
463
+ * const shapeRecordType = createShapeRecordType({
464
+ * geo: { props: geoShapeProps, migrations: geoMigrations },
465
+ * arrow: { props: arrowShapeProps, migrations: arrowMigrations }
466
+ * })
467
+ * ```
468
+ *
469
+ * @internal
470
+ */
194
471
  export function createShapeRecordType(shapes: Record<string, SchemaPropsInfo>) {
195
472
  return createRecordType<TLShape>('shape', {
196
473
  scope: 'document',