@tldraw/tlschema 5.2.0-next.ee0fa4d6244f → 5.2.1

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 (47) hide show
  1. package/DOCS.md +682 -0
  2. package/README.md +9 -1
  3. package/dist-cjs/index.d.ts +85 -11
  4. package/dist-cjs/index.js +3 -1
  5. package/dist-cjs/index.js.map +2 -2
  6. package/dist-cjs/misc/b64Vecs.js +175 -10
  7. package/dist-cjs/misc/b64Vecs.js.map +2 -2
  8. package/dist-cjs/records/TLInstance.js +3 -2
  9. package/dist-cjs/records/TLInstance.js.map +2 -2
  10. package/dist-cjs/records/TLPageState.js +5 -1
  11. package/dist-cjs/records/TLPageState.js.map +2 -2
  12. package/dist-cjs/records/TLPresence.js +3 -2
  13. package/dist-cjs/records/TLPresence.js.map +2 -2
  14. package/dist-cjs/shapes/TLDrawShape.js +16 -2
  15. package/dist-cjs/shapes/TLDrawShape.js.map +2 -2
  16. package/dist-cjs/shapes/TLHighlightShape.js +14 -1
  17. package/dist-cjs/shapes/TLHighlightShape.js.map +2 -2
  18. package/dist-cjs/shapes/TLNoteShape.js +14 -2
  19. package/dist-cjs/shapes/TLNoteShape.js.map +2 -2
  20. package/dist-esm/index.d.mts +85 -11
  21. package/dist-esm/index.mjs +4 -2
  22. package/dist-esm/index.mjs.map +2 -2
  23. package/dist-esm/misc/b64Vecs.mjs +175 -10
  24. package/dist-esm/misc/b64Vecs.mjs.map +2 -2
  25. package/dist-esm/records/TLInstance.mjs +3 -2
  26. package/dist-esm/records/TLInstance.mjs.map +2 -2
  27. package/dist-esm/records/TLPageState.mjs +5 -1
  28. package/dist-esm/records/TLPageState.mjs.map +2 -2
  29. package/dist-esm/records/TLPresence.mjs +3 -2
  30. package/dist-esm/records/TLPresence.mjs.map +2 -2
  31. package/dist-esm/shapes/TLDrawShape.mjs +17 -3
  32. package/dist-esm/shapes/TLDrawShape.mjs.map +2 -2
  33. package/dist-esm/shapes/TLHighlightShape.mjs +15 -2
  34. package/dist-esm/shapes/TLHighlightShape.mjs.map +2 -2
  35. package/dist-esm/shapes/TLNoteShape.mjs +14 -2
  36. package/dist-esm/shapes/TLNoteShape.mjs.map +2 -2
  37. package/package.json +11 -7
  38. package/src/index.ts +1 -1
  39. package/src/migrations.test.ts +136 -1
  40. package/src/misc/b64Vecs.test.ts +112 -0
  41. package/src/misc/b64Vecs.ts +230 -15
  42. package/src/records/TLInstance.ts +5 -4
  43. package/src/records/TLPageState.ts +5 -1
  44. package/src/records/TLPresence.ts +5 -4
  45. package/src/shapes/TLDrawShape.ts +30 -1
  46. package/src/shapes/TLHighlightShape.ts +19 -1
  47. package/src/shapes/TLNoteShape.ts +15 -3
@@ -13,6 +13,7 @@ import { cursorTypeValidator, TLCursor } from '../misc/TLCursor'
13
13
  import { scribbleValidator, TLScribble } from '../misc/TLScribble'
14
14
  import { TLPageId } from './TLPage'
15
15
  import { TLShapeId } from './TLShape'
16
+ import { TLUserId, userIdValidator } from './TLUser'
16
17
 
17
18
  /**
18
19
  * Represents the presence state of a user in a collaborative tldraw session.
@@ -39,7 +40,7 @@ import { TLShapeId } from './TLShape'
39
40
  * @public
40
41
  */
41
42
  export interface TLInstancePresence extends BaseRecord<'instance_presence', TLInstancePresenceID> {
42
- userId: string
43
+ userId: TLUserId
43
44
  userName: string
44
45
  lastActivityTimestamp: number | null
45
46
  color: string // can be any hex color
@@ -49,7 +50,7 @@ export interface TLInstancePresence extends BaseRecord<'instance_presence', TLIn
49
50
  brush: BoxModel | null
50
51
  scribbles: TLScribble[]
51
52
  screenBounds: BoxModel | null
52
- followingUserId: string | null
53
+ followingUserId: TLUserId | null
53
54
  cursor: {
54
55
  x: number
55
56
  y: number
@@ -101,10 +102,10 @@ export const instancePresenceValidator: T.Validator<TLInstancePresence> = T.mode
101
102
  T.object({
102
103
  typeName: T.literal('instance_presence'),
103
104
  id: idValidator<TLInstancePresenceID>('instance_presence'),
104
- userId: T.string,
105
+ userId: userIdValidator,
105
106
  userName: T.string,
106
107
  lastActivityTimestamp: T.number.nullable(),
107
- followingUserId: T.string.nullable(),
108
+ followingUserId: userIdValidator.nullable(),
108
109
  cursor: T.object({
109
110
  x: T.number,
110
111
  y: T.number,
@@ -1,5 +1,5 @@
1
1
  import { T } from '@tldraw/validate'
2
- import { b64Vecs } from '../misc/b64Vecs'
2
+ import { DIM_2D, DIM_3D, b64Vecs } from '../misc/b64Vecs'
3
3
  import { VecModel } from '../misc/geometry-types'
4
4
  import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
5
5
  import { RecordProps } from '../recordsWithProps'
@@ -22,6 +22,12 @@ export interface TLDrawShapeSegment {
22
22
  * First point stored as Float32 (12 bytes) for precision, subsequent points as Float16 deltas (6 bytes each).
23
23
  */
24
24
  path: string
25
+ /**
26
+ * Encoding dimension of `path`. `2` means (x, y) only — the constant 0.5 pressure
27
+ * was omitted, for input from devices that don't report pressure. `3` or absent
28
+ * (the legacy default) means (x, y, z). Added in the `OmitNonPressureZ` migration.
29
+ */
30
+ dim?: 2 | 3
25
31
  }
26
32
 
27
33
  /**
@@ -32,6 +38,7 @@ export interface TLDrawShapeSegment {
32
38
  export const DrawShapeSegment: T.ObjectValidator<TLDrawShapeSegment> = T.object({
33
39
  type: T.literalEnum('free', 'straight'),
34
40
  path: T.string,
41
+ dim: T.literalEnum(DIM_2D, DIM_3D).optional(),
35
42
  })
36
43
 
37
44
  /**
@@ -138,6 +145,7 @@ const Versions = createShapePropsMigrationIds('draw', {
138
145
  AddScale: 2,
139
146
  Base64: 3,
140
147
  LegacyPointsConversion: 4,
148
+ OmitNonPressureZ: 5,
141
149
  })
142
150
 
143
151
  /**
@@ -239,6 +247,27 @@ export const drawShapeMigrations = createShapePropsMigrationSequence({
239
247
  // handled by the previous down migration
240
248
  },
241
249
  },
250
+ {
251
+ id: Versions.OmitNonPressureZ,
252
+ up: (_props) => {
253
+ // No-op. Pre-existing segments have no `dim` field, which is exactly how
254
+ // the new schema reads them (3D). The validator now accepts the optional
255
+ // `dim`, so newer 2D segments validate as well — nothing to rewrite here.
256
+ },
257
+ down: (props) => {
258
+ // Older clients only understand 3D paths and reject the unknown `dim` field.
259
+ // Strip `dim` from every segment that carries it; a 2D segment is also
260
+ // re-encoded back to 3D (decode supplies z = 0.5), while a `dim: 3` segment
261
+ // already has a 3D path so we just drop the field.
262
+ props.segments = props.segments.map((segment: any) => {
263
+ if (segment.dim === undefined) return segment
264
+ const { dim, ...rest } = segment
265
+ return dim === DIM_2D
266
+ ? { ...rest, path: b64Vecs.encodePoints(b64Vecs.decodePoints(segment.path, DIM_2D)) }
267
+ : rest
268
+ })
269
+ },
270
+ },
242
271
  ],
243
272
  })
244
273
 
@@ -1,5 +1,5 @@
1
1
  import { T } from '@tldraw/validate'
2
- import { b64Vecs } from '../misc/b64Vecs'
2
+ import { DIM_2D, b64Vecs } from '../misc/b64Vecs'
3
3
  import { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'
4
4
  import { RecordProps } from '../recordsWithProps'
5
5
  import { DefaultColorStyle, TLDefaultColorStyle } from '../styles/TLColorStyle'
@@ -105,6 +105,7 @@ const Versions = createShapePropsMigrationIds('highlight', {
105
105
  AddScale: 1,
106
106
  Base64: 2,
107
107
  LegacyPointsConversion: 3,
108
+ OmitNonPressureZ: 4,
108
109
  })
109
110
 
110
111
  /**
@@ -182,5 +183,22 @@ export const highlightShapeMigrations = createShapePropsMigrationSequence({
182
183
  // handled by the previous down migration
183
184
  },
184
185
  },
186
+ {
187
+ id: Versions.OmitNonPressureZ,
188
+ up: (_props) => {
189
+ // No-op — see the matching draw-shape migration. Absent `dim` reads as 3D.
190
+ },
191
+ down: (props) => {
192
+ // Strip `dim` from every segment that carries it (older clients reject the
193
+ // unknown field); 2D segments are re-encoded to 3D, dim: 3 just loses the field.
194
+ props.segments = props.segments.map((segment: any) => {
195
+ if (segment.dim === undefined) return segment
196
+ const { dim, ...rest } = segment
197
+ return dim === DIM_2D
198
+ ? { ...rest, path: b64Vecs.encodePoints(b64Vecs.decodePoints(segment.path, DIM_2D)) }
199
+ : rest
200
+ })
201
+ },
202
+ },
185
203
  ],
186
204
  })
@@ -64,8 +64,8 @@ export interface TLNoteShapeProps {
64
64
  richText: TLRichText
65
65
  /** Scale factor applied to the note shape for display */
66
66
  scale: number
67
- /** User ID of the person who first edited the note text */
68
- textFirstEditedBy: string | null
67
+ /** User ID of the person who last edited the note text */
68
+ textLastEditedBy: string | null
69
69
  }
70
70
 
71
71
  /**
@@ -132,7 +132,7 @@ export const noteShapeProps: RecordProps<TLNoteShape> = {
132
132
  url: T.linkUrl,
133
133
  richText: richTextValidator,
134
134
  scale: T.nonZeroNumber,
135
- textFirstEditedBy: T.string.nullable(),
135
+ textLastEditedBy: T.string.nullable(),
136
136
  }
137
137
 
138
138
  const Versions = createShapePropsMigrationIds('note', {
@@ -148,6 +148,7 @@ const Versions = createShapePropsMigrationIds('note', {
148
148
  AddRichTextAttrs: 10,
149
149
  AddFirstEditedBy: 11,
150
150
  MakeFontSizeAdjustmentRatio: 12,
151
+ RenameFirstEditedByToLast: 13,
151
152
  })
152
153
 
153
154
  /**
@@ -292,5 +293,16 @@ export const noteShapeMigrations = createShapePropsMigrationSequence({
292
293
  props.fontSizeAdjustment = 0
293
294
  },
294
295
  },
296
+ {
297
+ id: Versions.RenameFirstEditedByToLast,
298
+ up: (props) => {
299
+ props.textLastEditedBy = props.textFirstEditedBy ?? null
300
+ delete props.textFirstEditedBy
301
+ },
302
+ down: (props) => {
303
+ props.textFirstEditedBy = props.textLastEditedBy ?? null
304
+ delete props.textLastEditedBy
305
+ },
306
+ },
295
307
  ],
296
308
  })