@tldraw/tlschema 5.3.0-internal.fba91ed55f6c → 5.3.0-next.030bf6014f04

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.
@@ -529,6 +529,14 @@ export declare const CameraRecordType: RecordType<TLCamera, never>;
529
529
  */
530
530
  export declare const canvasUiColorTypeValidator: T.Validator<"accent" | "black" | "laser" | "muted-1" | "selection-fill" | "selection-stroke" | "white">;
531
531
 
532
+ /**
533
+ * Config for registering the `comment-reaction` record type in a tldraw schema. Pass via
534
+ * `commentSchemaRecords`; see `TLCommentReaction`.
535
+ *
536
+ * @public
537
+ */
538
+ export declare const commentReactionRecordConfig: CustomRecordInfo;
539
+
532
540
  /**
533
541
  * Config for registering the `comment` record type in a tldraw schema. Pass via
534
542
  * `commentSchemaRecords`; see `TLComment`.
@@ -539,12 +547,13 @@ export declare const commentRecordConfig: CustomRecordInfo;
539
547
 
540
548
  /**
541
549
  * The `records` map to pass to `createTLSchema` / the client `records` option so comment
542
- * threads and comments sync. Register both types together — a comment without its thread type
543
- * (or vice versa) will fail schema validation on one side of the connection.
550
+ * threads, comments, and reactions sync. Register the types together — one without the others
551
+ * will fail schema validation on one side of the connection.
544
552
  *
545
553
  * @public
546
554
  */
547
555
  export declare const commentSchemaRecords: {
556
+ 'comment-reaction': CustomRecordInfo;
548
557
  'comment-thread': CustomRecordInfo;
549
558
  comment: CustomRecordInfo;
550
559
  };
@@ -855,6 +864,33 @@ export declare function createComment(props: {
855
864
  /** @public */
856
865
  export declare function createCommentId(id?: string): TLCommentId;
857
866
 
867
+ /**
868
+ * Create a reaction record for one user's reaction to one comment. The id is derived from the
869
+ * comment and user (see `createCommentReactionId`), so re-reacting overwrites rather than adding.
870
+ *
871
+ * @public
872
+ */
873
+ export declare function createCommentReaction(props: {
874
+ commentId: TLCommentId;
875
+ emoji: string;
876
+ meta?: JsonObject;
877
+ now?: number;
878
+ pageId: TLPageId;
879
+ threadId: TLCommentThreadId;
880
+ userId: string;
881
+ }): TLCommentReaction;
882
+
883
+ /**
884
+ * The id of one user's reaction to one comment, derived from the (comment, user, emoji) triple
885
+ * rather than random, so the same triple always addresses the same record and two tabs converge
886
+ * instead of racing to create duplicates. The sync authorizer leans on this, so it must be
887
+ * injective: all three parts are URI-encoded before joining, so a `:` in any of them can't shift
888
+ * the boundary and collapse two triples onto one id.
889
+ *
890
+ * @public
891
+ */
892
+ export declare function createCommentReactionId(commentId: TLCommentId, userId: string, emoji: string): TLCommentReactionId;
893
+
858
894
  /**
859
895
  * Create a new comment thread record. Pair with `createComment` for the thread's first message.
860
896
  *
@@ -2288,17 +2324,22 @@ export declare function isBinding(record?: UnknownRecord): record is TLBinding;
2288
2324
  export declare function isBindingId(id?: string): id is TLBindingId;
2289
2325
 
2290
2326
  /**
2291
- * Type guard for `TLCommentId`. See `isCommentThreadId` for why `comment-thread:...` ids are
2292
- * correctly rejected here.
2327
+ * Type guard for `TLCommentId`. See `isCommentThreadId`.
2293
2328
  *
2294
2329
  * @public
2295
2330
  */
2296
2331
  export declare function isCommentId(id: string): id is TLCommentId;
2297
2332
 
2298
2333
  /**
2299
- * Type guard for `TLCommentThreadId`. Note `isCommentId` does not accept these: the prefixes
2300
- * are `comment-thread:` vs `comment:`, and the character after `comment` differs (`-` vs `:`),
2301
- * so the two never overlap.
2334
+ * Type guard for `TLCommentReactionId`. See `isCommentThreadId`.
2335
+ *
2336
+ * @public
2337
+ */
2338
+ export declare function isCommentReactionId(id: string): id is TLCommentReactionId;
2339
+
2340
+ /**
2341
+ * Type guard for `TLCommentThreadId`. `isCommentId` rejects these — `comment-thread:` and
2342
+ * `comment:` differ in the character after `comment`, so the prefixes never overlap.
2302
2343
  *
2303
2344
  * @public
2304
2345
  */
@@ -4105,6 +4146,8 @@ export declare interface TLComment extends BaseRecord<'comment', TLCommentId> {
4105
4146
  editedAt: null | number;
4106
4147
  /** Rich text body. Use `toRichText(...)` for plaintext input. */
4107
4148
  body: TLRichText;
4149
+ /** Whether the comment is soft-deleted. Same model as `TLCommentThread.isDeleted`. */
4150
+ isDeleted: boolean;
4108
4151
  meta: JsonObject;
4109
4152
  }
4110
4153
 
@@ -4112,24 +4155,22 @@ export declare interface TLComment extends BaseRecord<'comment', TLCommentId> {
4112
4155
  * Where a comment thread is anchored on the canvas. Modeled as a discriminated union so new
4113
4156
  * anchor kinds can be added without breaking existing threads:
4114
4157
  *
4115
- * - `shape` — pinned to a shape. `x`/`y` are normalized (0–1) within the shape's page bounds, so
4116
- * the pin keeps its spot as the shape moves and resizes. `isPrecise` mirrors arrow bindings: when
4117
- * true the pin sits at exactly `x`/`y`; when false (the default) it sits at a consumer-defined
4118
- * spot (top-right out of the box), and `x`/`y` are the remembered precise position
4158
+ * - `shape` — pinned to a shape. `x`/`y` are normalized (0–1) within the shape's bounds, so the pin
4159
+ * keeps its spot as the shape moves, resizes, and rotates. `isPrecise` mirrors arrow bindings:
4160
+ * when false (the default) the pin sits at a consumer-defined spot instead, top-right out of the
4161
+ * box, and `x`/`y` are the remembered precise position
4119
4162
  * - `point` — pinned to a fixed point on the page, in page coordinates
4120
4163
  * - `region` — pinned to a rectangular area of the page, in page coordinates
4121
4164
  * - `page` — a page-level thread with no spatial anchor
4122
- * - `text-range` — pinned to a character range inside a shape's text
4123
4165
  *
4124
4166
  * @public
4125
4167
  */
4126
4168
  export declare type TLCommentAnchor = {
4127
- from: number;
4128
- shapeId: TLShapeId;
4129
- to: number;
4130
- type: 'text-range';
4131
- } | {
4169
+ /** The normalized (0–1) corner the pin sits on — where the creating drag was released.
4170
+ * Absent on older records; consumers fall back to a corner of their own choosing. */
4171
+ pinX?: number;
4132
4172
  h: number;
4173
+ pinY?: number;
4133
4174
  type: 'region';
4134
4175
  w: number;
4135
4176
  x: number;
@@ -4151,6 +4192,36 @@ export declare type TLCommentAnchor = {
4151
4192
  /** @public */
4152
4193
  export declare type TLCommentId = RecordId<TLComment>;
4153
4194
 
4195
+ /**
4196
+ * One person's emoji reaction to one comment.
4197
+ *
4198
+ * A reaction is its own record rather than a field on the comment: comment records are owner-only
4199
+ * for updates, and a shared field would make concurrent reactions race to overwrite each other.
4200
+ *
4201
+ * A user holds at most one record per (comment, emoji) pair, enforced by the derived id — see
4202
+ * `createCommentReactionId`. Limiting a user to one reaction overall is client-side policy (the
4203
+ * commenting package's `reactionMode`), not a property of this record.
4204
+ *
4205
+ * @public
4206
+ */
4207
+ export declare interface TLCommentReaction extends BaseRecord<'comment-reaction', TLCommentReactionId> {
4208
+ /** The comment being reacted to. */
4209
+ commentId: TLCommentId;
4210
+ /** Denormalized from the comment, so a thread's reactions can be found without a join. */
4211
+ threadId: TLCommentThreadId;
4212
+ /** Denormalized from the comment — see `TLComment.pageId`. */
4213
+ pageId: TLPageId;
4214
+ /** Who reacted. See `TLCommentThread.createdBy` — same server-stamping caveat applies. */
4215
+ userId: string;
4216
+ /** The emoji itself, as a string (e.g. `'👍'`), not a shortcode. */
4217
+ emoji: string;
4218
+ createdAt: number;
4219
+ meta: JsonObject;
4220
+ }
4221
+
4222
+ /** @public */
4223
+ export declare type TLCommentReactionId = RecordId<TLCommentReaction>;
4224
+
4154
4225
  /**
4155
4226
  * A comment thread. The thread owns the anchor (where the conversation lives on the canvas) and
4156
4227
  * the resolution state; the messages themselves are `TLComment` records pointing at the thread
@@ -4172,11 +4243,7 @@ export declare interface TLCommentThread extends BaseRecord<'comment-thread', TL
4172
4243
  pageId: TLPageId;
4173
4244
  /** Where the thread is anchored on that page. */
4174
4245
  anchor: TLCommentAnchor;
4175
- /**
4176
- * Who started the thread. Client-supplied for now; the sync server should stamp/verify this
4177
- * from the session's authenticated identity once record-level authorization lands (the same
4178
- * model presence already uses for self-ownership).
4179
- */
4246
+ /** Who started the thread. Client-supplied; sync servers are expected to stamp/verify it. */
4180
4247
  createdBy: string;
4181
4248
  createdAt: number;
4182
4249
  /** Resolution state: when and by whom the thread was resolved, or null while open. */
@@ -4184,6 +4251,12 @@ export declare interface TLCommentThread extends BaseRecord<'comment-thread', TL
4184
4251
  at: number;
4185
4252
  by: string;
4186
4253
  } | null;
4254
+ /**
4255
+ * Whether the thread is soft-deleted. Clients set the flag and leave the record in place. Sync
4256
+ * servers are expected to enforce it as write-once and creator-only, reject client hard
4257
+ * deletes, and drop flagged threads from future room loads.
4258
+ */
4259
+ isDeleted: boolean;
4187
4260
  meta: JsonObject;
4188
4261
  }
4189
4262
 
@@ -4915,7 +4988,9 @@ export declare interface TLFrameShapeProps {
4915
4988
  * labelColor: 'black',
4916
4989
  * url: '',
4917
4990
  * growY: 0,
4918
- * scale: 1
4991
+ * scale: 1,
4992
+ * flipX: false,
4993
+ * flipY: false
4919
4994
  * },
4920
4995
  * meta: {}
4921
4996
  * }
@@ -4950,6 +5025,10 @@ export declare interface TLGeoShapeProps {
4950
5025
  growY: number;
4951
5026
  /** Scale factor applied to the shape */
4952
5027
  scale: number;
5028
+ /** Whether to mirror the shape horizontally */
5029
+ flipX: boolean;
5030
+ /** Whether to mirror the shape vertically */
5031
+ flipY: boolean;
4953
5032
  /** Color style for text label */
4954
5033
  labelColor: TLDefaultColorStyle;
4955
5034
  /** Color style for the shape outline */
package/dist-cjs/index.js CHANGED
@@ -70,6 +70,7 @@ __export(index_exports, {
70
70
  bookmarkShapeProps: () => import_TLBookmarkShape.bookmarkShapeProps,
71
71
  boxModelValidator: () => import_geometry_types.boxModelValidator,
72
72
  canvasUiColorTypeValidator: () => import_TLColor.canvasUiColorTypeValidator,
73
+ commentReactionRecordConfig: () => import_TLComment.commentReactionRecordConfig,
73
74
  commentRecordConfig: () => import_TLComment.commentRecordConfig,
74
75
  commentSchemaRecords: () => import_TLComment.commentSchemaRecords,
75
76
  commentThreadRecordConfig: () => import_TLComment.commentThreadRecordConfig,
@@ -85,6 +86,8 @@ __export(index_exports, {
85
86
  createCachedUserResolve: () => import_TLStore.createCachedUserResolve,
86
87
  createComment: () => import_TLComment.createComment,
87
88
  createCommentId: () => import_TLComment.createCommentId,
89
+ createCommentReaction: () => import_TLComment.createCommentReaction,
90
+ createCommentReactionId: () => import_TLComment.createCommentReactionId,
88
91
  createCommentThread: () => import_TLComment.createCommentThread,
89
92
  createCommentThreadId: () => import_TLComment.createCommentThreadId,
90
93
  createCustomRecordId: () => import_TLCustomRecord.createCustomRecordId,
@@ -124,6 +127,7 @@ __export(index_exports, {
124
127
  isBinding: () => import_TLBinding.isBinding,
125
128
  isBindingId: () => import_TLBinding.isBindingId,
126
129
  isCommentId: () => import_TLComment.isCommentId,
130
+ isCommentReactionId: () => import_TLComment.isCommentReactionId,
127
131
  isCommentThreadId: () => import_TLComment.isCommentThreadId,
128
132
  isCustomRecord: () => import_TLCustomRecord.isCustomRecord,
129
133
  isCustomRecordId: () => import_TLCustomRecord.isCustomRecordId,
@@ -217,7 +221,7 @@ var import_translations = require("./translations/translations");
217
221
  var import_b64Vecs = require("./misc/b64Vecs");
218
222
  (0, import_utils.registerTldrawLibraryVersion)(
219
223
  "@tldraw/tlschema",
220
- "5.3.0-internal.fba91ed55f6c",
224
+ "5.3.0-next.030bf6014f04",
221
225
  "cjs"
222
226
  );
223
227
  //# sourceMappingURL=index.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["/**\n * @fileoverview\n * Main entry point for the tldraw schema package. Exports the complete type system,\n * data structures, validation, and migrations for tldraw's persisted data.\n *\n * This package provides:\n * - Schema creation utilities (createTLSchema, defaultShapeSchemas, defaultBindingSchemas)\n * - All built-in shape types (TLGeoShape, TLTextShape, TLArrowShape, etc.)\n * - Asset management types and validators (TLImageAsset, TLVideoAsset, TLBookmarkAsset)\n * - Binding system for shape relationships (TLArrowBinding)\n * - Store integration types (TLStore, TLStoreProps, TLStoreSnapshot)\n * - Style properties for consistent styling (DefaultColorStyle, DefaultSizeStyle, etc.)\n * - Validation utilities and type guards\n * - Migration systems for schema evolution\n * - Geometry and utility types\n *\n * @example\n * ```ts\n * import { createTLSchema, defaultShapeSchemas, TLStore } from '@tldraw/tlschema'\n *\n * // Create a schema with default shapes\n * const schema = createTLSchema({\n * shapes: defaultShapeSchemas\n * })\n *\n * // Use with a store\n * const store = new Store({ schema })\n * ```\n *\n * @public\n */\n\nimport { registerTldrawLibraryVersion } from '@tldraw/utils'\nexport { assetIdValidator, createAssetValidator, type TLBaseAsset } from './assets/TLBaseAsset'\nexport {\n\tbookmarkAssetMigrations,\n\tbookmarkAssetProps,\n\ttype TLBookmarkAsset,\n} from './assets/TLBookmarkAsset'\nexport { imageAssetMigrations, imageAssetProps, type TLImageAsset } from './assets/TLImageAsset'\nexport { videoAssetMigrations, videoAssetProps, type TLVideoAsset } from './assets/TLVideoAsset'\nexport {\n\tarrowBindingMigrations,\n\tarrowBindingProps,\n\tarrowBindingVersions,\n\tElbowArrowSnap,\n\ttype TLArrowBinding,\n\ttype TLArrowBindingProps,\n} from './bindings/TLArrowBinding'\nexport {\n\tbindingIdValidator,\n\tcreateBindingValidator,\n\ttype TLBaseBinding,\n} from './bindings/TLBaseBinding'\nexport {\n\tcreatePresenceStateDerivation,\n\tgetDefaultUserPresence,\n\ttype CreatePresenceStateDerivationOpts,\n\ttype TLPresenceStateInfo,\n} from './createPresenceStateDerivation'\nexport {\n\tcreateTLSchema,\n\tdefaultAssetSchemas,\n\tdefaultBindingSchemas,\n\tdefaultShapeSchemas,\n\ttype SchemaPropsInfo,\n\ttype TLSchema,\n\ttype UserSchemaInfo,\n} from './createTLSchema'\nexport {\n\tboxModelValidator,\n\tvecModelValidator,\n\ttype BoxModel,\n\ttype VecModel,\n} from './misc/geometry-types'\nexport { idValidator } from './misc/id-validator'\nexport {\n\tcanvasUiColorTypeValidator,\n\tTL_CANVAS_UI_COLOR_TYPES,\n\ttype TLCanvasUiColor,\n} from './misc/TLColor'\nexport { TL_CURSOR_TYPES, type TLCursor, type TLCursorType } from './misc/TLCursor'\nexport { TL_HANDLE_TYPES, type TLHandle, type TLHandleType } from './misc/TLHandle'\nexport { opacityValidator, type TLOpacityType } from './misc/TLOpacity'\nexport { richTextValidator, toRichText, type TLRichText } from './misc/TLRichText'\nexport { scribbleValidator, TL_SCRIBBLE_STATES, type TLScribble } from './misc/TLScribble'\nexport {\n\tassetMigrations,\n\tAssetRecordType,\n\tcreateAssetPropsMigrationIds,\n\tcreateAssetPropsMigrationSequence,\n\tcreateAssetRecordType,\n\ttype TLAsset,\n\ttype TLAssetId,\n\ttype TLAssetPartial,\n\ttype TLAssetShape,\n\ttype TLDefaultAsset,\n\ttype TLGlobalAssetPropsMap,\n\ttype TLIndexedAssets,\n\ttype TLUnknownAsset,\n} from './records/TLAsset'\nexport {\n\tcreateBindingId,\n\tcreateBindingPropsMigrationIds,\n\tcreateBindingPropsMigrationSequence,\n\tisBinding,\n\tisBindingId,\n\trootBindingMigrations,\n\ttype TLBinding,\n\ttype TLBindingCreate,\n\ttype TLBindingId,\n\ttype TLBindingUpdate,\n\ttype TLDefaultBinding,\n\ttype TLGlobalBindingPropsMap,\n\ttype TLIndexedBindings,\n\ttype TLUnknownBinding,\n} from './records/TLBinding'\nexport { CameraRecordType, type TLCamera, type TLCameraId } from './records/TLCamera'\nexport {\n\tcommentRecordConfig,\n\tcommentSchemaRecords,\n\tcommentThreadRecordConfig,\n\tcreateComment,\n\tcreateCommentId,\n\tcreateCommentThread,\n\tcreateCommentThreadId,\n\tisCommentId,\n\tisCommentThreadId,\n\ttype TLComment,\n\ttype TLCommentAnchor,\n\ttype TLCommentId,\n\ttype TLCommentThread,\n\ttype TLCommentThreadId,\n} from './records/TLComment'\nexport {\n\tcreateCustomRecordId,\n\tcreateCustomRecordMigrationIds,\n\tcreateCustomRecordMigrationSequence,\n\tisCustomRecord,\n\tisCustomRecordId,\n\ttype CustomRecordInfo,\n} from './records/TLCustomRecord'\nexport {\n\tDocumentRecordType,\n\tisDocument,\n\tTLDOCUMENT_ID,\n\ttype TLDocument,\n} from './records/TLDocument'\nexport {\n\tpluckPreservingValues,\n\tTLINSTANCE_ID,\n\ttype TLInstance,\n\ttype TLInstanceId,\n} from './records/TLInstance'\nexport {\n\tisPageId,\n\tpageIdValidator,\n\tPageRecordType,\n\ttype TLPage,\n\ttype TLPageId,\n} from './records/TLPage'\nexport {\n\tInstancePageStateRecordType,\n\ttype TLInstancePageState,\n\ttype TLInstancePageStateId,\n} from './records/TLPageState'\nexport {\n\tPointerRecordType,\n\tTLPOINTER_ID,\n\ttype TLPointer,\n\ttype TLPointerId,\n} from './records/TLPointer'\nexport {\n\tInstancePresenceRecordType,\n\ttype TLInstancePresence,\n\ttype TLInstancePresenceID,\n} from './records/TLPresence'\nexport {\n\ttype TLCustomRecord,\n\ttype TLDefaultRecord,\n\ttype TLGlobalRecordPropsMap,\n\ttype TLIndexedRecords,\n\ttype TLRecord,\n} from './records/TLRecord'\nexport {\n\tcreateShapeId,\n\tcreateShapePropsMigrationIds,\n\tcreateShapePropsMigrationSequence,\n\tgetShapePropKeysByStyle,\n\tisShape,\n\tisShapeId,\n\trootShapeMigrations,\n\ttype ExtractShapeByProps,\n\ttype TLCreateShapePartial,\n\ttype TLDefaultShape,\n\ttype TLGlobalShapePropsMap,\n\ttype TLIndexedShapes,\n\ttype TLParentId,\n\ttype TLShape,\n\ttype TLShapeId,\n\ttype TLShapePartial,\n\ttype TLUnknownShape,\n} from './records/TLShape'\nexport {\n\tcreateUserId,\n\tcreateUserRecordType,\n\tisUserId,\n\tuserIdValidator,\n\tUserRecordType,\n\ttype TLUser,\n\ttype TLUserId,\n} from './records/TLUser'\nexport {\n\ttype RecordProps,\n\ttype RecordPropsType,\n\ttype TLPropsMigration,\n\ttype TLPropsMigrations,\n} from './recordsWithProps'\nexport { type ShapeWithCrop, type TLShapeCrop } from './shapes/ShapeWithCrop'\nexport {\n\tArrowShapeArrowheadEndStyle,\n\tArrowShapeArrowheadStartStyle,\n\tArrowShapeKindStyle,\n\tarrowShapeMigrations,\n\tarrowShapeProps,\n\tarrowShapeVersions,\n\ttype TLArrowShape,\n\ttype TLArrowShapeArrowheadStyle,\n\ttype TLArrowShapeKind,\n\ttype TLArrowShapeProps,\n} from './shapes/TLArrowShape'\nexport {\n\tcreateShapeValidator,\n\tparentIdValidator,\n\tshapeIdValidator,\n\ttype TLBaseShape,\n} from './shapes/TLBaseShape'\nexport {\n\tbookmarkShapeMigrations,\n\tbookmarkShapeProps,\n\ttype TLBookmarkShape,\n\ttype TLBookmarkShapeProps,\n} from './shapes/TLBookmarkShape'\nexport {\n\tcompressLegacySegments,\n\tdrawShapeMigrations,\n\tdrawShapeProps,\n\ttype TLDrawShape,\n\ttype TLDrawShapeProps,\n\ttype TLDrawShapeSegment,\n} from './shapes/TLDrawShape'\nexport {\n\tembedShapeMigrations,\n\tembedShapeProps,\n\ttype TLEmbedShape,\n\ttype TLEmbedShapeProps,\n} from './shapes/TLEmbedShape'\nexport {\n\tframeShapeMigrations,\n\tframeShapeProps,\n\ttype TLFrameShape,\n\ttype TLFrameShapeProps,\n} from './shapes/TLFrameShape'\nexport {\n\tGeoShapeGeoStyle,\n\tgeoShapeMigrations,\n\tgeoShapeProps,\n\ttype TLGeoShape,\n\ttype TLGeoShapeGeoStyle,\n\ttype TLGeoShapeProps,\n} from './shapes/TLGeoShape'\nexport {\n\tgroupShapeMigrations,\n\tgroupShapeProps,\n\ttype TLGroupShape,\n\ttype TLGroupShapeProps,\n} from './shapes/TLGroupShape'\nexport {\n\thighlightShapeMigrations,\n\thighlightShapeProps,\n\ttype TLHighlightShape,\n\ttype TLHighlightShapeProps,\n} from './shapes/TLHighlightShape'\nexport {\n\tImageShapeCrop,\n\timageShapeMigrations,\n\timageShapeProps,\n\ttype TLImageShape,\n\ttype TLImageShapeProps,\n} from './shapes/TLImageShape'\nexport {\n\tlineShapeMigrations,\n\tlineShapeProps,\n\tLineShapeSplineStyle,\n\ttype TLLineShape,\n\ttype TLLineShapePoint,\n\ttype TLLineShapeProps,\n\ttype TLLineShapeSplineStyle,\n} from './shapes/TLLineShape'\nexport {\n\tnoteShapeMigrations,\n\tnoteShapeProps,\n\ttype TLNoteShape,\n\ttype TLNoteShapeProps,\n} from './shapes/TLNoteShape'\nexport {\n\ttextShapeMigrations,\n\ttextShapeProps,\n\ttype TLTextShape,\n\ttype TLTextShapeProps,\n} from './shapes/TLTextShape'\nexport {\n\tvideoShapeMigrations,\n\tvideoShapeProps,\n\ttype TLVideoShape,\n\ttype TLVideoShapeProps,\n} from './shapes/TLVideoShape'\nexport { EnumStyleProp, StyleProp, type StylePropValue } from './styles/StyleProp'\nexport {\n\tDefaultColorStyle,\n\tregisterColorsFromThemes,\n\ttype TLDefaultColorStyle,\n} from './styles/TLColorStyle'\nexport { DefaultDashStyle, type TLDefaultDashStyle } from './styles/TLDashStyle'\nexport { DefaultFillStyle, type TLDefaultFillStyle } from './styles/TLFillStyle'\nexport { type TLFontFace, type TLFontFaceSource } from './styles/TLFontFace'\nexport {\n\tDefaultFontFamilies,\n\tDefaultFontStyle,\n\tisFontEntry,\n\tregisterFontsFromThemes,\n\ttype TLDefaultFontStyle,\n} from './styles/TLFontStyle'\nexport {\n\tDefaultHorizontalAlignStyle,\n\ttype TLDefaultHorizontalAlignStyle,\n} from './styles/TLHorizontalAlignStyle'\nexport { DefaultSizeStyle, type TLDefaultSizeStyle } from './styles/TLSizeStyle'\nexport { DefaultTextAlignStyle, type TLDefaultTextAlignStyle } from './styles/TLTextAlignStyle'\nexport {\n\ttype TLDefaultColor,\n\ttype TLRemovedDefaultThemeColors,\n\ttype TLTheme,\n\ttype TLThemeColors,\n\ttype TLThemeDefaultColors,\n\ttype TLThemeFont,\n\ttype TLThemeFonts,\n\ttype TLThemeId,\n\ttype TLThemes,\n\ttype TLThemeUiColorKeys,\n} from './styles/TLTheme'\nexport {\n\tDefaultVerticalAlignStyle,\n\ttype TLDefaultVerticalAlignStyle,\n} from './styles/TLVerticalAlignStyle'\nexport {\n\tcreateCachedUserResolve,\n\ttype TLAssetContext,\n\ttype TLAssetStore,\n\ttype TLSerializedStore,\n\ttype TLStore,\n\ttype TLStoreProps,\n\ttype TLStoreSchema,\n\ttype TLStoreSnapshot,\n\ttype TLUserStore,\n} from './TLStore'\nexport {\n\tgetDefaultTranslationLocale,\n\tLANGUAGES,\n\ttype TLLanguage,\n} from './translations/translations'\nexport { type SetValue } from './util-types'\n\nregisterTldrawLibraryVersion(\n\t(globalThis as any).TLDRAW_LIBRARY_NAME,\n\t(globalThis as any).TLDRAW_LIBRARY_VERSION,\n\t(globalThis as any).TLDRAW_LIBRARY_MODULES\n)\n\nexport { DIM_2D, DIM_3D, b64Vecs } from './misc/b64Vecs'\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCA,mBAA6C;AAC7C,yBAAyE;AACzE,6BAIO;AACP,0BAAyE;AACzE,0BAAyE;AACzE,4BAOO;AACP,2BAIO;AACP,2CAKO;AACP,4BAQO;AACP,4BAKO;AACP,0BAA4B;AAC5B,qBAIO;AACP,sBAAkE;AAClE,sBAAkE;AAClE,uBAAqD;AACrD,wBAA+D;AAC/D,wBAAuE;AACvE,qBAcO;AACP,uBAeO;AACP,sBAAiE;AACjE,uBAeO;AACP,4BAOO;AACP,wBAKO;AACP,wBAKO;AACP,oBAMO;AACP,yBAIO;AACP,uBAKO;AACP,wBAIO;AAQP,qBAkBO;AACP,oBAQO;AAQP,0BAWO;AACP,yBAKO;AACP,6BAKO;AACP,yBAOO;AACP,0BAKO;AACP,0BAKO;AACP,wBAOO;AACP,0BAKO;AACP,8BAKO;AACP,0BAMO;AACP,yBAQO;AACP,yBAKO;AACP,yBAKO;AACP,0BAKO;AACP,uBAA8D;AAC9D,0BAIO;AACP,yBAA0D;AAC1D,yBAA0D;AAE1D,yBAMO;AACP,oCAGO;AACP,yBAA0D;AAC1D,8BAAoE;AAapE,kCAGO;AACP,qBAUO;AACP,0BAIO;AASP,qBAAwC;AAAA,IANxC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AACF;",
4
+ "sourcesContent": ["/**\n * @fileoverview\n * Main entry point for the tldraw schema package. Exports the complete type system,\n * data structures, validation, and migrations for tldraw's persisted data.\n *\n * This package provides:\n * - Schema creation utilities (createTLSchema, defaultShapeSchemas, defaultBindingSchemas)\n * - All built-in shape types (TLGeoShape, TLTextShape, TLArrowShape, etc.)\n * - Asset management types and validators (TLImageAsset, TLVideoAsset, TLBookmarkAsset)\n * - Binding system for shape relationships (TLArrowBinding)\n * - Store integration types (TLStore, TLStoreProps, TLStoreSnapshot)\n * - Style properties for consistent styling (DefaultColorStyle, DefaultSizeStyle, etc.)\n * - Validation utilities and type guards\n * - Migration systems for schema evolution\n * - Geometry and utility types\n *\n * @example\n * ```ts\n * import { createTLSchema, defaultShapeSchemas, TLStore } from '@tldraw/tlschema'\n *\n * // Create a schema with default shapes\n * const schema = createTLSchema({\n * shapes: defaultShapeSchemas\n * })\n *\n * // Use with a store\n * const store = new Store({ schema })\n * ```\n *\n * @public\n */\n\nimport { registerTldrawLibraryVersion } from '@tldraw/utils'\nexport { assetIdValidator, createAssetValidator, type TLBaseAsset } from './assets/TLBaseAsset'\nexport {\n\tbookmarkAssetMigrations,\n\tbookmarkAssetProps,\n\ttype TLBookmarkAsset,\n} from './assets/TLBookmarkAsset'\nexport { imageAssetMigrations, imageAssetProps, type TLImageAsset } from './assets/TLImageAsset'\nexport { videoAssetMigrations, videoAssetProps, type TLVideoAsset } from './assets/TLVideoAsset'\nexport {\n\tarrowBindingMigrations,\n\tarrowBindingProps,\n\tarrowBindingVersions,\n\tElbowArrowSnap,\n\ttype TLArrowBinding,\n\ttype TLArrowBindingProps,\n} from './bindings/TLArrowBinding'\nexport {\n\tbindingIdValidator,\n\tcreateBindingValidator,\n\ttype TLBaseBinding,\n} from './bindings/TLBaseBinding'\nexport {\n\tcreatePresenceStateDerivation,\n\tgetDefaultUserPresence,\n\ttype CreatePresenceStateDerivationOpts,\n\ttype TLPresenceStateInfo,\n} from './createPresenceStateDerivation'\nexport {\n\tcreateTLSchema,\n\tdefaultAssetSchemas,\n\tdefaultBindingSchemas,\n\tdefaultShapeSchemas,\n\ttype SchemaPropsInfo,\n\ttype TLSchema,\n\ttype UserSchemaInfo,\n} from './createTLSchema'\nexport {\n\tboxModelValidator,\n\tvecModelValidator,\n\ttype BoxModel,\n\ttype VecModel,\n} from './misc/geometry-types'\nexport { idValidator } from './misc/id-validator'\nexport {\n\tcanvasUiColorTypeValidator,\n\tTL_CANVAS_UI_COLOR_TYPES,\n\ttype TLCanvasUiColor,\n} from './misc/TLColor'\nexport { TL_CURSOR_TYPES, type TLCursor, type TLCursorType } from './misc/TLCursor'\nexport { TL_HANDLE_TYPES, type TLHandle, type TLHandleType } from './misc/TLHandle'\nexport { opacityValidator, type TLOpacityType } from './misc/TLOpacity'\nexport { richTextValidator, toRichText, type TLRichText } from './misc/TLRichText'\nexport { scribbleValidator, TL_SCRIBBLE_STATES, type TLScribble } from './misc/TLScribble'\nexport {\n\tassetMigrations,\n\tAssetRecordType,\n\tcreateAssetPropsMigrationIds,\n\tcreateAssetPropsMigrationSequence,\n\tcreateAssetRecordType,\n\ttype TLAsset,\n\ttype TLAssetId,\n\ttype TLAssetPartial,\n\ttype TLAssetShape,\n\ttype TLDefaultAsset,\n\ttype TLGlobalAssetPropsMap,\n\ttype TLIndexedAssets,\n\ttype TLUnknownAsset,\n} from './records/TLAsset'\nexport {\n\tcreateBindingId,\n\tcreateBindingPropsMigrationIds,\n\tcreateBindingPropsMigrationSequence,\n\tisBinding,\n\tisBindingId,\n\trootBindingMigrations,\n\ttype TLBinding,\n\ttype TLBindingCreate,\n\ttype TLBindingId,\n\ttype TLBindingUpdate,\n\ttype TLDefaultBinding,\n\ttype TLGlobalBindingPropsMap,\n\ttype TLIndexedBindings,\n\ttype TLUnknownBinding,\n} from './records/TLBinding'\nexport { CameraRecordType, type TLCamera, type TLCameraId } from './records/TLCamera'\nexport {\n\tcommentReactionRecordConfig,\n\tcommentRecordConfig,\n\tcommentSchemaRecords,\n\tcommentThreadRecordConfig,\n\tcreateComment,\n\tcreateCommentId,\n\tcreateCommentReaction,\n\tcreateCommentReactionId,\n\tcreateCommentThread,\n\tcreateCommentThreadId,\n\tisCommentId,\n\tisCommentReactionId,\n\tisCommentThreadId,\n\ttype TLComment,\n\ttype TLCommentAnchor,\n\ttype TLCommentId,\n\ttype TLCommentReaction,\n\ttype TLCommentReactionId,\n\ttype TLCommentThread,\n\ttype TLCommentThreadId,\n} from './records/TLComment'\nexport {\n\tcreateCustomRecordId,\n\tcreateCustomRecordMigrationIds,\n\tcreateCustomRecordMigrationSequence,\n\tisCustomRecord,\n\tisCustomRecordId,\n\ttype CustomRecordInfo,\n} from './records/TLCustomRecord'\nexport {\n\tDocumentRecordType,\n\tisDocument,\n\tTLDOCUMENT_ID,\n\ttype TLDocument,\n} from './records/TLDocument'\nexport {\n\tpluckPreservingValues,\n\tTLINSTANCE_ID,\n\ttype TLInstance,\n\ttype TLInstanceId,\n} from './records/TLInstance'\nexport {\n\tisPageId,\n\tpageIdValidator,\n\tPageRecordType,\n\ttype TLPage,\n\ttype TLPageId,\n} from './records/TLPage'\nexport {\n\tInstancePageStateRecordType,\n\ttype TLInstancePageState,\n\ttype TLInstancePageStateId,\n} from './records/TLPageState'\nexport {\n\tPointerRecordType,\n\tTLPOINTER_ID,\n\ttype TLPointer,\n\ttype TLPointerId,\n} from './records/TLPointer'\nexport {\n\tInstancePresenceRecordType,\n\ttype TLInstancePresence,\n\ttype TLInstancePresenceID,\n} from './records/TLPresence'\nexport {\n\ttype TLCustomRecord,\n\ttype TLDefaultRecord,\n\ttype TLGlobalRecordPropsMap,\n\ttype TLIndexedRecords,\n\ttype TLRecord,\n} from './records/TLRecord'\nexport {\n\tcreateShapeId,\n\tcreateShapePropsMigrationIds,\n\tcreateShapePropsMigrationSequence,\n\tgetShapePropKeysByStyle,\n\tisShape,\n\tisShapeId,\n\trootShapeMigrations,\n\ttype ExtractShapeByProps,\n\ttype TLCreateShapePartial,\n\ttype TLDefaultShape,\n\ttype TLGlobalShapePropsMap,\n\ttype TLIndexedShapes,\n\ttype TLParentId,\n\ttype TLShape,\n\ttype TLShapeId,\n\ttype TLShapePartial,\n\ttype TLUnknownShape,\n} from './records/TLShape'\nexport {\n\tcreateUserId,\n\tcreateUserRecordType,\n\tisUserId,\n\tuserIdValidator,\n\tUserRecordType,\n\ttype TLUser,\n\ttype TLUserId,\n} from './records/TLUser'\nexport {\n\ttype RecordProps,\n\ttype RecordPropsType,\n\ttype TLPropsMigration,\n\ttype TLPropsMigrations,\n} from './recordsWithProps'\nexport { type ShapeWithCrop, type TLShapeCrop } from './shapes/ShapeWithCrop'\nexport {\n\tArrowShapeArrowheadEndStyle,\n\tArrowShapeArrowheadStartStyle,\n\tArrowShapeKindStyle,\n\tarrowShapeMigrations,\n\tarrowShapeProps,\n\tarrowShapeVersions,\n\ttype TLArrowShape,\n\ttype TLArrowShapeArrowheadStyle,\n\ttype TLArrowShapeKind,\n\ttype TLArrowShapeProps,\n} from './shapes/TLArrowShape'\nexport {\n\tcreateShapeValidator,\n\tparentIdValidator,\n\tshapeIdValidator,\n\ttype TLBaseShape,\n} from './shapes/TLBaseShape'\nexport {\n\tbookmarkShapeMigrations,\n\tbookmarkShapeProps,\n\ttype TLBookmarkShape,\n\ttype TLBookmarkShapeProps,\n} from './shapes/TLBookmarkShape'\nexport {\n\tcompressLegacySegments,\n\tdrawShapeMigrations,\n\tdrawShapeProps,\n\ttype TLDrawShape,\n\ttype TLDrawShapeProps,\n\ttype TLDrawShapeSegment,\n} from './shapes/TLDrawShape'\nexport {\n\tembedShapeMigrations,\n\tembedShapeProps,\n\ttype TLEmbedShape,\n\ttype TLEmbedShapeProps,\n} from './shapes/TLEmbedShape'\nexport {\n\tframeShapeMigrations,\n\tframeShapeProps,\n\ttype TLFrameShape,\n\ttype TLFrameShapeProps,\n} from './shapes/TLFrameShape'\nexport {\n\tGeoShapeGeoStyle,\n\tgeoShapeMigrations,\n\tgeoShapeProps,\n\ttype TLGeoShape,\n\ttype TLGeoShapeGeoStyle,\n\ttype TLGeoShapeProps,\n} from './shapes/TLGeoShape'\nexport {\n\tgroupShapeMigrations,\n\tgroupShapeProps,\n\ttype TLGroupShape,\n\ttype TLGroupShapeProps,\n} from './shapes/TLGroupShape'\nexport {\n\thighlightShapeMigrations,\n\thighlightShapeProps,\n\ttype TLHighlightShape,\n\ttype TLHighlightShapeProps,\n} from './shapes/TLHighlightShape'\nexport {\n\tImageShapeCrop,\n\timageShapeMigrations,\n\timageShapeProps,\n\ttype TLImageShape,\n\ttype TLImageShapeProps,\n} from './shapes/TLImageShape'\nexport {\n\tlineShapeMigrations,\n\tlineShapeProps,\n\tLineShapeSplineStyle,\n\ttype TLLineShape,\n\ttype TLLineShapePoint,\n\ttype TLLineShapeProps,\n\ttype TLLineShapeSplineStyle,\n} from './shapes/TLLineShape'\nexport {\n\tnoteShapeMigrations,\n\tnoteShapeProps,\n\ttype TLNoteShape,\n\ttype TLNoteShapeProps,\n} from './shapes/TLNoteShape'\nexport {\n\ttextShapeMigrations,\n\ttextShapeProps,\n\ttype TLTextShape,\n\ttype TLTextShapeProps,\n} from './shapes/TLTextShape'\nexport {\n\tvideoShapeMigrations,\n\tvideoShapeProps,\n\ttype TLVideoShape,\n\ttype TLVideoShapeProps,\n} from './shapes/TLVideoShape'\nexport { EnumStyleProp, StyleProp, type StylePropValue } from './styles/StyleProp'\nexport {\n\tDefaultColorStyle,\n\tregisterColorsFromThemes,\n\ttype TLDefaultColorStyle,\n} from './styles/TLColorStyle'\nexport { DefaultDashStyle, type TLDefaultDashStyle } from './styles/TLDashStyle'\nexport { DefaultFillStyle, type TLDefaultFillStyle } from './styles/TLFillStyle'\nexport { type TLFontFace, type TLFontFaceSource } from './styles/TLFontFace'\nexport {\n\tDefaultFontFamilies,\n\tDefaultFontStyle,\n\tisFontEntry,\n\tregisterFontsFromThemes,\n\ttype TLDefaultFontStyle,\n} from './styles/TLFontStyle'\nexport {\n\tDefaultHorizontalAlignStyle,\n\ttype TLDefaultHorizontalAlignStyle,\n} from './styles/TLHorizontalAlignStyle'\nexport { DefaultSizeStyle, type TLDefaultSizeStyle } from './styles/TLSizeStyle'\nexport { DefaultTextAlignStyle, type TLDefaultTextAlignStyle } from './styles/TLTextAlignStyle'\nexport {\n\ttype TLDefaultColor,\n\ttype TLRemovedDefaultThemeColors,\n\ttype TLTheme,\n\ttype TLThemeColors,\n\ttype TLThemeDefaultColors,\n\ttype TLThemeFont,\n\ttype TLThemeFonts,\n\ttype TLThemeId,\n\ttype TLThemes,\n\ttype TLThemeUiColorKeys,\n} from './styles/TLTheme'\nexport {\n\tDefaultVerticalAlignStyle,\n\ttype TLDefaultVerticalAlignStyle,\n} from './styles/TLVerticalAlignStyle'\nexport {\n\tcreateCachedUserResolve,\n\ttype TLAssetContext,\n\ttype TLAssetStore,\n\ttype TLSerializedStore,\n\ttype TLStore,\n\ttype TLStoreProps,\n\ttype TLStoreSchema,\n\ttype TLStoreSnapshot,\n\ttype TLUserStore,\n} from './TLStore'\nexport {\n\tgetDefaultTranslationLocale,\n\tLANGUAGES,\n\ttype TLLanguage,\n} from './translations/translations'\nexport { type SetValue } from './util-types'\n\nregisterTldrawLibraryVersion(\n\t(globalThis as any).TLDRAW_LIBRARY_NAME,\n\t(globalThis as any).TLDRAW_LIBRARY_VERSION,\n\t(globalThis as any).TLDRAW_LIBRARY_MODULES\n)\n\nexport { DIM_2D, DIM_3D, b64Vecs } from './misc/b64Vecs'\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCA,mBAA6C;AAC7C,yBAAyE;AACzE,6BAIO;AACP,0BAAyE;AACzE,0BAAyE;AACzE,4BAOO;AACP,2BAIO;AACP,2CAKO;AACP,4BAQO;AACP,4BAKO;AACP,0BAA4B;AAC5B,qBAIO;AACP,sBAAkE;AAClE,sBAAkE;AAClE,uBAAqD;AACrD,wBAA+D;AAC/D,wBAAuE;AACvE,qBAcO;AACP,uBAeO;AACP,sBAAiE;AACjE,uBAqBO;AACP,4BAOO;AACP,wBAKO;AACP,wBAKO;AACP,oBAMO;AACP,yBAIO;AACP,uBAKO;AACP,wBAIO;AAQP,qBAkBO;AACP,oBAQO;AAQP,0BAWO;AACP,yBAKO;AACP,6BAKO;AACP,yBAOO;AACP,0BAKO;AACP,0BAKO;AACP,wBAOO;AACP,0BAKO;AACP,8BAKO;AACP,0BAMO;AACP,yBAQO;AACP,yBAKO;AACP,yBAKO;AACP,0BAKO;AACP,uBAA8D;AAC9D,0BAIO;AACP,yBAA0D;AAC1D,yBAA0D;AAE1D,yBAMO;AACP,oCAGO;AACP,yBAA0D;AAC1D,8BAAoE;AAapE,kCAGO;AACP,qBAUO;AACP,0BAIO;AASP,qBAAwC;AAAA,IANxC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AACF;",
6
6
  "names": []
7
7
  }
@@ -29,6 +29,7 @@ const TL_CURSOR_TYPES = /* @__PURE__ */ new Set([
29
29
  "default",
30
30
  "pointer",
31
31
  "cross",
32
+ "comment",
32
33
  "grab",
33
34
  "rotate",
34
35
  "grabbing",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/misc/TLCursor.ts"],
4
- "sourcesContent": ["import { T } from '@tldraw/validate'\nimport { SetValue } from '../util-types'\n\n/**\n * All available cursor types used throughout the tldraw editor.\n *\n * These cursor types correspond to CSS cursor values and are used to indicate\n * different interaction modes and states within the editor. The cursor types\n * cover selection, resizing, rotation, text editing, and various other editor\n * interactions.\n *\n * @example\n * ```ts\n * // Check if a cursor type is valid\n * if (TL_CURSOR_TYPES.has('resize-corner')) {\n * console.log('Valid cursor type')\n * }\n *\n * // Get all available cursor types\n * const allCursors = Array.from(TL_CURSOR_TYPES)\n * ```\n *\n * @public\n */\nexport const TL_CURSOR_TYPES = new Set([\n\t'none',\n\t'default',\n\t'pointer',\n\t'cross',\n\t'grab',\n\t'rotate',\n\t'grabbing',\n\t'resize-edge',\n\t'resize-corner',\n\t'text',\n\t'move',\n\t'ew-resize',\n\t'ns-resize',\n\t'nesw-resize',\n\t'nwse-resize',\n\t'nesw-rotate',\n\t'nwse-rotate',\n\t'swne-rotate',\n\t'senw-rotate',\n\t'zoom-in',\n\t'zoom-out',\n])\n\n/**\n * A union type representing all available cursor types in the tldraw editor.\n *\n * Each cursor type corresponds to a different interaction mode or state,\n * helping users understand what action they can perform at any given moment.\n *\n * @example\n * ```ts\n * const defaultCursor: TLCursorType = 'default'\n * const textCursor: TLCursorType = 'text'\n * const resizeCursor: TLCursorType = 'resize-corner'\n * const rotateCursor: TLCursorType = 'nesw-rotate'\n * ```\n *\n * @public\n */\nexport type TLCursorType = SetValue<typeof TL_CURSOR_TYPES>\n\n/**\n * A validator for cursor types.\n *\n * This validator ensures that cursor type values are one of the valid types\n * defined in {@link TL_CURSOR_TYPES}. It provides runtime type checking for\n * cursor properties throughout the editor.\n *\n * @example\n * ```ts\n * import { cursorTypeValidator } from '@tldraw/tlschema'\n *\n * // Validate a cursor type\n * try {\n * const validCursor = cursorTypeValidator.validate('pointer')\n * console.log('Valid cursor:', validCursor)\n * } catch (error) {\n * console.error('Invalid cursor:', error.message)\n * }\n * ```\n *\n * @public\n */\nexport const cursorTypeValidator = T.setEnum(TL_CURSOR_TYPES)\n\n/**\n * A cursor object used throughout the tldraw editor.\n *\n * Represents both the cursor type (which determines the visual appearance)\n * and its rotation angle. The rotation is particularly useful for resize\n * and rotation cursors that need to align with the current interaction angle.\n *\n * @example\n * ```ts\n * // Default cursor\n * const defaultCursor: TLCursor = {\n * type: 'default',\n * rotation: 0\n * }\n *\n * // Rotated resize cursor\n * const rotatedResizeCursor: TLCursor = {\n * type: 'resize-corner',\n * rotation: Math.PI / 4 // 45 degrees\n * }\n *\n * // Text editing cursor\n * const textCursor: TLCursor = {\n * type: 'text',\n * rotation: 0\n * }\n * ```\n *\n * @public\n */\nexport interface TLCursor {\n\t/** The cursor type, determining the visual appearance and interaction mode */\n\ttype: TLCursorType\n\t/** The rotation angle in radians, used for rotated cursors like resize handles */\n\trotation: number\n}\n\n/**\n * A validator for TLCursor objects.\n *\n * This validator ensures that cursor objects have valid cursor types and\n * numeric rotation values. It provides runtime validation for cursor\n * properties used throughout the editor.\n *\n * @example\n * ```ts\n * import { cursorValidator } from '@tldraw/tlschema'\n *\n * // Validate a cursor object\n * try {\n * const validCursor = cursorValidator.validate({\n * type: 'pointer',\n * rotation: 0.5\n * })\n * console.log('Valid cursor:', validCursor)\n * } catch (error) {\n * console.error('Invalid cursor:', error.message)\n * }\n * ```\n *\n * @public\n */\nexport const cursorValidator: T.ObjectValidator<TLCursor> = T.object<TLCursor>({\n\ttype: cursorTypeValidator,\n\trotation: T.number,\n})\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAkB;AAwBX,MAAM,kBAAkB,oBAAI,IAAI;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AA0CM,MAAM,sBAAsB,kBAAE,QAAQ,eAAe;AAgErD,MAAM,kBAA+C,kBAAE,OAAiB;AAAA,EAC9E,MAAM;AAAA,EACN,UAAU,kBAAE;AACb,CAAC;",
4
+ "sourcesContent": ["import { T } from '@tldraw/validate'\nimport { SetValue } from '../util-types'\n\n/**\n * All available cursor types used throughout the tldraw editor.\n *\n * These cursor types correspond to CSS cursor values and are used to indicate\n * different interaction modes and states within the editor. The cursor types\n * cover selection, resizing, rotation, text editing, and various other editor\n * interactions.\n *\n * @example\n * ```ts\n * // Check if a cursor type is valid\n * if (TL_CURSOR_TYPES.has('resize-corner')) {\n * console.log('Valid cursor type')\n * }\n *\n * // Get all available cursor types\n * const allCursors = Array.from(TL_CURSOR_TYPES)\n * ```\n *\n * @public\n */\nexport const TL_CURSOR_TYPES = new Set([\n\t'none',\n\t'default',\n\t'pointer',\n\t'cross',\n\t'comment',\n\t'grab',\n\t'rotate',\n\t'grabbing',\n\t'resize-edge',\n\t'resize-corner',\n\t'text',\n\t'move',\n\t'ew-resize',\n\t'ns-resize',\n\t'nesw-resize',\n\t'nwse-resize',\n\t'nesw-rotate',\n\t'nwse-rotate',\n\t'swne-rotate',\n\t'senw-rotate',\n\t'zoom-in',\n\t'zoom-out',\n])\n\n/**\n * A union type representing all available cursor types in the tldraw editor.\n *\n * Each cursor type corresponds to a different interaction mode or state,\n * helping users understand what action they can perform at any given moment.\n *\n * @example\n * ```ts\n * const defaultCursor: TLCursorType = 'default'\n * const textCursor: TLCursorType = 'text'\n * const resizeCursor: TLCursorType = 'resize-corner'\n * const rotateCursor: TLCursorType = 'nesw-rotate'\n * ```\n *\n * @public\n */\nexport type TLCursorType = SetValue<typeof TL_CURSOR_TYPES>\n\n/**\n * A validator for cursor types.\n *\n * This validator ensures that cursor type values are one of the valid types\n * defined in {@link TL_CURSOR_TYPES}. It provides runtime type checking for\n * cursor properties throughout the editor.\n *\n * @example\n * ```ts\n * import { cursorTypeValidator } from '@tldraw/tlschema'\n *\n * // Validate a cursor type\n * try {\n * const validCursor = cursorTypeValidator.validate('pointer')\n * console.log('Valid cursor:', validCursor)\n * } catch (error) {\n * console.error('Invalid cursor:', error.message)\n * }\n * ```\n *\n * @public\n */\nexport const cursorTypeValidator = T.setEnum(TL_CURSOR_TYPES)\n\n/**\n * A cursor object used throughout the tldraw editor.\n *\n * Represents both the cursor type (which determines the visual appearance)\n * and its rotation angle. The rotation is particularly useful for resize\n * and rotation cursors that need to align with the current interaction angle.\n *\n * @example\n * ```ts\n * // Default cursor\n * const defaultCursor: TLCursor = {\n * type: 'default',\n * rotation: 0\n * }\n *\n * // Rotated resize cursor\n * const rotatedResizeCursor: TLCursor = {\n * type: 'resize-corner',\n * rotation: Math.PI / 4 // 45 degrees\n * }\n *\n * // Text editing cursor\n * const textCursor: TLCursor = {\n * type: 'text',\n * rotation: 0\n * }\n * ```\n *\n * @public\n */\nexport interface TLCursor {\n\t/** The cursor type, determining the visual appearance and interaction mode */\n\ttype: TLCursorType\n\t/** The rotation angle in radians, used for rotated cursors like resize handles */\n\trotation: number\n}\n\n/**\n * A validator for TLCursor objects.\n *\n * This validator ensures that cursor objects have valid cursor types and\n * numeric rotation values. It provides runtime validation for cursor\n * properties used throughout the editor.\n *\n * @example\n * ```ts\n * import { cursorValidator } from '@tldraw/tlschema'\n *\n * // Validate a cursor object\n * try {\n * const validCursor = cursorValidator.validate({\n * type: 'pointer',\n * rotation: 0.5\n * })\n * console.log('Valid cursor:', validCursor)\n * } catch (error) {\n * console.error('Invalid cursor:', error.message)\n * }\n * ```\n *\n * @public\n */\nexport const cursorValidator: T.ObjectValidator<TLCursor> = T.object<TLCursor>({\n\ttype: cursorTypeValidator,\n\trotation: T.number,\n})\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAkB;AAwBX,MAAM,kBAAkB,oBAAI,IAAI;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,CAAC;AA0CM,MAAM,sBAAsB,kBAAE,QAAQ,eAAe;AAgErD,MAAM,kBAA+C,kBAAE,OAAiB;AAAA,EAC9E,MAAM;AAAA,EACN,UAAU,kBAAE;AACb,CAAC;",
6
6
  "names": []
7
7
  }
@@ -18,14 +18,18 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var TLComment_exports = {};
20
20
  __export(TLComment_exports, {
21
+ commentReactionRecordConfig: () => commentReactionRecordConfig,
21
22
  commentRecordConfig: () => commentRecordConfig,
22
23
  commentSchemaRecords: () => commentSchemaRecords,
23
24
  commentThreadRecordConfig: () => commentThreadRecordConfig,
24
25
  createComment: () => createComment,
25
26
  createCommentId: () => createCommentId,
27
+ createCommentReaction: () => createCommentReaction,
28
+ createCommentReactionId: () => createCommentReactionId,
26
29
  createCommentThread: () => createCommentThread,
27
30
  createCommentThreadId: () => createCommentThreadId,
28
31
  isCommentId: () => isCommentId,
32
+ isCommentReactionId: () => isCommentReactionId,
29
33
  isCommentThreadId: () => isCommentThreadId
30
34
  });
31
35
  module.exports = __toCommonJS(TLComment_exports);
@@ -34,6 +38,11 @@ var import_validate = require("@tldraw/validate");
34
38
  var import_id_validator = require("../misc/id-validator");
35
39
  var import_TLRichText = require("../misc/TLRichText");
36
40
  var import_TLCustomRecord = require("./TLCustomRecord");
41
+ const emojiValidator = import_validate.T.string.check((value) => {
42
+ if (value.length === 0 || value.length > 64) {
43
+ throw new import_validate.T.ValidationError(`Expected an emoji of 1-64 characters, got ${value.length}`);
44
+ }
45
+ });
37
46
  const commentAnchorValidator = import_validate.T.union("type", {
38
47
  shape: import_validate.T.object({
39
48
  type: import_validate.T.literal("shape"),
@@ -52,16 +61,12 @@ const commentAnchorValidator = import_validate.T.union("type", {
52
61
  x: import_validate.T.number,
53
62
  y: import_validate.T.number,
54
63
  w: import_validate.T.number,
55
- h: import_validate.T.number
64
+ h: import_validate.T.number,
65
+ pinX: import_validate.T.number.optional(),
66
+ pinY: import_validate.T.number.optional()
56
67
  }),
57
68
  page: import_validate.T.object({
58
69
  type: import_validate.T.literal("page")
59
- }),
60
- "text-range": import_validate.T.object({
61
- type: import_validate.T.literal("text-range"),
62
- shapeId: (0, import_id_validator.idValidator)("shape"),
63
- from: import_validate.T.number,
64
- to: import_validate.T.number
65
70
  })
66
71
  });
67
72
  function createCommentGuardMigrations(typeName, extra = []) {
@@ -100,6 +105,19 @@ const commentThreadRecordConfig = {
100
105
  }
101
106
  return record;
102
107
  }
108
+ },
109
+ {
110
+ // Region anchors gained an optional pin corner (where the creating drag released).
111
+ id: "com.tldraw.comment-thread/3",
112
+ up: (record) => record,
113
+ down: (record) => {
114
+ const anchor = record.anchor;
115
+ if (anchor?.type === "region") {
116
+ const { pinX: _pinX, pinY: _pinY, ...rest } = anchor;
117
+ record.anchor = rest;
118
+ }
119
+ return record;
120
+ }
103
121
  }
104
122
  ]),
105
123
  validator: import_validate.T.object({
@@ -110,6 +128,7 @@ const commentThreadRecordConfig = {
110
128
  createdBy: import_validate.T.string,
111
129
  createdAt: import_validate.T.number,
112
130
  resolved: import_validate.T.object({ at: import_validate.T.number, by: import_validate.T.string }).nullable(),
131
+ isDeleted: import_validate.T.boolean,
113
132
  meta: import_validate.T.jsonValue
114
133
  })
115
134
  };
@@ -125,12 +144,29 @@ const commentRecordConfig = {
125
144
  createdAt: import_validate.T.number,
126
145
  editedAt: import_validate.T.number.nullable(),
127
146
  body: import_TLRichText.richTextValidator,
147
+ isDeleted: import_validate.T.boolean,
148
+ meta: import_validate.T.jsonValue
149
+ })
150
+ };
151
+ const commentReactionRecordConfig = {
152
+ scope: "document",
153
+ migrations: createCommentGuardMigrations("comment-reaction"),
154
+ validator: import_validate.T.object({
155
+ id: (0, import_id_validator.idValidator)("comment-reaction"),
156
+ typeName: import_validate.T.literal("comment-reaction"),
157
+ commentId: (0, import_id_validator.idValidator)("comment"),
158
+ threadId: (0, import_id_validator.idValidator)("comment-thread"),
159
+ pageId: (0, import_id_validator.idValidator)("page"),
160
+ userId: import_validate.T.string,
161
+ emoji: emojiValidator,
162
+ createdAt: import_validate.T.number,
128
163
  meta: import_validate.T.jsonValue
129
164
  })
130
165
  };
131
166
  const commentSchemaRecords = {
132
167
  "comment-thread": commentThreadRecordConfig,
133
- comment: commentRecordConfig
168
+ comment: commentRecordConfig,
169
+ "comment-reaction": commentReactionRecordConfig
134
170
  };
135
171
  function createCommentThreadId(id) {
136
172
  return (0, import_TLCustomRecord.createCustomRecordId)("comment-thread", id);
@@ -138,12 +174,21 @@ function createCommentThreadId(id) {
138
174
  function createCommentId(id) {
139
175
  return (0, import_TLCustomRecord.createCustomRecordId)("comment", id);
140
176
  }
177
+ function createCommentReactionId(commentId, userId, emoji) {
178
+ return (0, import_TLCustomRecord.createCustomRecordId)(
179
+ "comment-reaction",
180
+ `${encodeURIComponent(commentId)}:${encodeURIComponent(userId)}:${encodeURIComponent(emoji)}`
181
+ );
182
+ }
141
183
  function isCommentThreadId(id) {
142
184
  return (0, import_TLCustomRecord.isCustomRecordId)("comment-thread", id);
143
185
  }
144
186
  function isCommentId(id) {
145
187
  return (0, import_TLCustomRecord.isCustomRecordId)("comment", id);
146
188
  }
189
+ function isCommentReactionId(id) {
190
+ return (0, import_TLCustomRecord.isCustomRecordId)("comment-reaction", id);
191
+ }
147
192
  function createCommentThread(props) {
148
193
  return {
149
194
  id: createCommentThreadId(),
@@ -153,6 +198,7 @@ function createCommentThread(props) {
153
198
  createdBy: props.createdBy,
154
199
  createdAt: props.now ?? Date.now(),
155
200
  resolved: null,
201
+ isDeleted: false,
156
202
  meta: props.meta ?? {}
157
203
  };
158
204
  }
@@ -166,6 +212,20 @@ function createComment(props) {
166
212
  createdAt: props.now ?? Date.now(),
167
213
  editedAt: null,
168
214
  body: props.body,
215
+ isDeleted: false,
216
+ meta: props.meta ?? {}
217
+ };
218
+ }
219
+ function createCommentReaction(props) {
220
+ return {
221
+ id: createCommentReactionId(props.commentId, props.userId, props.emoji),
222
+ typeName: "comment-reaction",
223
+ commentId: props.commentId,
224
+ threadId: props.threadId,
225
+ pageId: props.pageId,
226
+ userId: props.userId,
227
+ emoji: props.emoji,
228
+ createdAt: props.now ?? Date.now(),
169
229
  meta: props.meta ?? {}
170
230
  };
171
231
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/records/TLComment.ts"],
4
- "sourcesContent": ["import { BaseRecord, RecordId, createRecordMigrationSequence } from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\nimport { richTextValidator, TLRichText } from '../misc/TLRichText'\nimport { CustomRecordInfo, createCustomRecordId, isCustomRecordId } from './TLCustomRecord'\nimport { TLPageId } from './TLPage'\nimport { TLShapeId } from './TLShape'\n\n/**\n * Where a comment thread is anchored on the canvas. Modeled as a discriminated union so new\n * anchor kinds can be added without breaking existing threads:\n *\n * - `shape` \u2014 pinned to a shape. `x`/`y` are normalized (0\u20131) within the shape's page bounds, so\n * the pin keeps its spot as the shape moves and resizes. `isPrecise` mirrors arrow bindings: when\n * true the pin sits at exactly `x`/`y`; when false (the default) it sits at a consumer-defined\n * spot (top-right out of the box), and `x`/`y` are the remembered precise position\n * - `point` \u2014 pinned to a fixed point on the page, in page coordinates\n * - `region` \u2014 pinned to a rectangular area of the page, in page coordinates\n * - `page` \u2014 a page-level thread with no spatial anchor\n * - `text-range` \u2014 pinned to a character range inside a shape's text\n *\n * @public\n */\nexport type TLCommentAnchor =\n\t| { type: 'shape'; shapeId: TLShapeId; x: number; y: number; isPrecise: boolean }\n\t| { type: 'point'; x: number; y: number }\n\t| { type: 'region'; x: number; y: number; w: number; h: number }\n\t| { type: 'page' }\n\t| { type: 'text-range'; shapeId: TLShapeId; from: number; to: number }\n\n/**\n * A comment thread. The thread owns the anchor (where the conversation lives on the canvas) and\n * the resolution state; the messages themselves are `TLComment` records pointing at the thread\n * via `threadId`, ordered by `createdAt`. v1 threads are flat \u2014 no nested replies.\n *\n * Threads and comments are document records, but they're intended to be served through the sync\n * server's object-store lane: gated by the session's `objectAccess` rather than `isReadonly`\n * (so \"can comment but not edit\" is expressible), excluded from document snapshots and `.tldr`\n * exports server-side, and persisted in a separate lane from the main document.\n *\n * Opt-in: register with `createTLSchema({ records: commentSchemaRecords })` on the server and\n * the matching `records` option on the client \u2014 neither type is part of the default schema, and\n * both sides must register them identically.\n *\n * @public\n */\nexport interface TLCommentThread extends BaseRecord<'comment-thread', TLCommentThreadId> {\n\t/** The page the thread lives on. */\n\tpageId: TLPageId\n\t/** Where the thread is anchored on that page. */\n\tanchor: TLCommentAnchor\n\t/**\n\t * Who started the thread. Client-supplied for now; the sync server should stamp/verify this\n\t * from the session's authenticated identity once record-level authorization lands (the same\n\t * model presence already uses for self-ownership).\n\t */\n\tcreatedBy: string\n\tcreatedAt: number\n\t/** Resolution state: when and by whom the thread was resolved, or null while open. */\n\tresolved: { at: number; by: string } | null\n\tmeta: JsonObject\n}\n\n/** @public */\nexport type TLCommentThreadId = RecordId<TLCommentThread>\n\n/**\n * A single comment message within a thread. See `TLCommentThread` for the overall model and\n * sync/registration notes.\n *\n * Comment mutations are deliberately not undoable \u2014 create/edit them with\n * `{ history: 'ignore' }` to avoid multiplayer surprises like a comment reappearing after\n * someone else deleted it.\n *\n * @public\n */\nexport interface TLComment extends BaseRecord<'comment', TLCommentId> {\n\t/** The thread this comment belongs to. */\n\tthreadId: TLCommentThreadId\n\t/** Denormalized from the thread so per-page queries don't need a join. */\n\tpageId: TLPageId\n\t/** See `TLCommentThread.createdBy` \u2014 same server-stamping caveat applies. */\n\tauthorId: string\n\tcreatedAt: number\n\t/** Null until the comment is first edited. */\n\teditedAt: number | null\n\t/** Rich text body. Use `toRichText(...)` for plaintext input. */\n\tbody: TLRichText\n\tmeta: JsonObject\n}\n\n/** @public */\nexport type TLCommentId = RecordId<TLComment>\n\nconst commentAnchorValidator: T.Validator<TLCommentAnchor> = T.union('type', {\n\tshape: T.object({\n\t\ttype: T.literal('shape'),\n\t\tshapeId: idValidator<TLShapeId>('shape'),\n\t\tx: T.number,\n\t\ty: T.number,\n\t\tisPrecise: T.boolean,\n\t}),\n\tpoint: T.object({\n\t\ttype: T.literal('point'),\n\t\tx: T.number,\n\t\ty: T.number,\n\t}),\n\tregion: T.object({\n\t\ttype: T.literal('region'),\n\t\tx: T.number,\n\t\ty: T.number,\n\t\tw: T.number,\n\t\th: T.number,\n\t}),\n\tpage: T.object({\n\t\ttype: T.literal('page'),\n\t}),\n\t'text-range': T.object({\n\t\ttype: T.literal('text-range'),\n\t\tshapeId: idValidator<TLShapeId>('shape'),\n\t\tfrom: T.number,\n\t\tto: T.number,\n\t}),\n})\n\n/**\n * Guard migrations for the comment record types. Each sequence is retroactive and starts with an\n * identity migration that has no `down`: a sync server whose schema registers the comment types\n * cannot down-migrate records for a session whose schema predates them, so such sessions are\n * rejected with CLIENT_TOO_OLD (prompting a refresh) instead of being sent record types their\n * store cannot represent.\n */\nfunction createCommentGuardMigrations(\n\ttypeName: 'comment' | 'comment-thread',\n\textra: Parameters<typeof createRecordMigrationSequence>[0]['sequence'] = []\n) {\n\treturn createRecordMigrationSequence({\n\t\tsequenceId: `com.tldraw.${typeName}`,\n\t\trecordType: typeName,\n\t\tretroactive: true,\n\t\tsequence: [\n\t\t\t{\n\t\t\t\tid: `com.tldraw.${typeName}/1`,\n\t\t\t\tup: (record) => record,\n\t\t\t},\n\t\t\t...extra,\n\t\t],\n\t})\n}\n\n/**\n * Config for registering the `comment-thread` record type in a tldraw schema. Pass via\n * `commentSchemaRecords`; see `TLCommentThread`.\n *\n * @public\n */\nexport const commentThreadRecordConfig: CustomRecordInfo = {\n\tscope: 'document',\n\tmigrations: createCommentGuardMigrations('comment-thread', [\n\t\t{\n\t\t\t// Shape anchors gained normalized x/y + isPrecise; existing ones were imprecise (top-right).\n\t\t\tid: 'com.tldraw.comment-thread/2',\n\t\t\tup: (record) => {\n\t\t\t\tconst anchor = (record as any).anchor\n\t\t\t\tif (anchor?.type === 'shape' && anchor.x === undefined) {\n\t\t\t\t\t;(record as any).anchor = { ...anchor, x: 1, y: 0, isPrecise: false }\n\t\t\t\t}\n\t\t\t\treturn record\n\t\t\t},\n\t\t\tdown: (record) => {\n\t\t\t\tconst anchor = (record as any).anchor\n\t\t\t\tif (anchor?.type === 'shape') {\n\t\t\t\t\t;(record as any).anchor = { type: 'shape', shapeId: anchor.shapeId }\n\t\t\t\t}\n\t\t\t\treturn record\n\t\t\t},\n\t\t},\n\t]),\n\tvalidator: T.object({\n\t\tid: idValidator<TLCommentThreadId>('comment-thread'),\n\t\ttypeName: T.literal('comment-thread'),\n\t\tpageId: idValidator<TLPageId>('page'),\n\t\tanchor: commentAnchorValidator,\n\t\tcreatedBy: T.string,\n\t\tcreatedAt: T.number,\n\t\tresolved: T.object({ at: T.number, by: T.string }).nullable(),\n\t\tmeta: T.jsonValue,\n\t}),\n}\n\n/**\n * Config for registering the `comment` record type in a tldraw schema. Pass via\n * `commentSchemaRecords`; see `TLComment`.\n *\n * @public\n */\nexport const commentRecordConfig: CustomRecordInfo = {\n\tscope: 'document',\n\tmigrations: createCommentGuardMigrations('comment'),\n\tvalidator: T.object({\n\t\tid: idValidator<TLCommentId>('comment'),\n\t\ttypeName: T.literal('comment'),\n\t\tthreadId: idValidator<TLCommentThreadId>('comment-thread'),\n\t\tpageId: idValidator<TLPageId>('page'),\n\t\tauthorId: T.string,\n\t\tcreatedAt: T.number,\n\t\teditedAt: T.number.nullable(),\n\t\tbody: richTextValidator,\n\t\tmeta: T.jsonValue,\n\t}),\n}\n\n/**\n * The `records` map to pass to `createTLSchema` / the client `records` option so comment\n * threads and comments sync. Register both types together \u2014 a comment without its thread type\n * (or vice versa) will fail schema validation on one side of the connection.\n *\n * @public\n */\nexport const commentSchemaRecords = {\n\t'comment-thread': commentThreadRecordConfig,\n\tcomment: commentRecordConfig,\n}\n\n/** @public */\nexport function createCommentThreadId(id?: string): TLCommentThreadId {\n\treturn createCustomRecordId('comment-thread', id) as TLCommentThreadId\n}\n\n/** @public */\nexport function createCommentId(id?: string): TLCommentId {\n\treturn createCustomRecordId('comment', id) as TLCommentId\n}\n\n/**\n * Type guard for `TLCommentThreadId`. Note `isCommentId` does not accept these: the prefixes\n * are `comment-thread:` vs `comment:`, and the character after `comment` differs (`-` vs `:`),\n * so the two never overlap.\n *\n * @public\n */\nexport function isCommentThreadId(id: string): id is TLCommentThreadId {\n\treturn isCustomRecordId('comment-thread', id)\n}\n\n/**\n * Type guard for `TLCommentId`. See `isCommentThreadId` for why `comment-thread:...` ids are\n * correctly rejected here.\n *\n * @public\n */\nexport function isCommentId(id: string): id is TLCommentId {\n\treturn isCustomRecordId('comment', id)\n}\n\n/**\n * Create a new comment thread record. Pair with `createComment` for the thread's first message.\n *\n * @public\n */\nexport function createCommentThread(props: {\n\tpageId: TLPageId\n\tanchor: TLCommentAnchor\n\tcreatedBy: string\n\tnow?: number\n\tmeta?: JsonObject\n}): TLCommentThread {\n\treturn {\n\t\tid: createCommentThreadId(),\n\t\ttypeName: 'comment-thread',\n\t\tpageId: props.pageId,\n\t\tanchor: props.anchor,\n\t\tcreatedBy: props.createdBy,\n\t\tcreatedAt: props.now ?? Date.now(),\n\t\tresolved: null,\n\t\tmeta: props.meta ?? {},\n\t}\n}\n\n/**\n * Create a new comment record within a thread.\n *\n * @public\n */\nexport function createComment(props: {\n\tthreadId: TLCommentThreadId\n\tpageId: TLPageId\n\tauthorId: string\n\tbody: TLRichText\n\tnow?: number\n\tmeta?: JsonObject\n}): TLComment {\n\treturn {\n\t\tid: createCommentId(),\n\t\ttypeName: 'comment',\n\t\tthreadId: props.threadId,\n\t\tpageId: props.pageId,\n\t\tauthorId: props.authorId,\n\t\tcreatedAt: props.now ?? Date.now(),\n\t\teditedAt: null,\n\t\tbody: props.body,\n\t\tmeta: props.meta ?? {},\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAoE;AAEpE,sBAAkB;AAClB,0BAA4B;AAC5B,wBAA8C;AAC9C,4BAAyE;AA0FzE,MAAM,yBAAuD,kBAAE,MAAM,QAAQ;AAAA,EAC5E,OAAO,kBAAE,OAAO;AAAA,IACf,MAAM,kBAAE,QAAQ,OAAO;AAAA,IACvB,aAAS,iCAAuB,OAAO;AAAA,IACvC,GAAG,kBAAE;AAAA,IACL,GAAG,kBAAE;AAAA,IACL,WAAW,kBAAE;AAAA,EACd,CAAC;AAAA,EACD,OAAO,kBAAE,OAAO;AAAA,IACf,MAAM,kBAAE,QAAQ,OAAO;AAAA,IACvB,GAAG,kBAAE;AAAA,IACL,GAAG,kBAAE;AAAA,EACN,CAAC;AAAA,EACD,QAAQ,kBAAE,OAAO;AAAA,IAChB,MAAM,kBAAE,QAAQ,QAAQ;AAAA,IACxB,GAAG,kBAAE;AAAA,IACL,GAAG,kBAAE;AAAA,IACL,GAAG,kBAAE;AAAA,IACL,GAAG,kBAAE;AAAA,EACN,CAAC;AAAA,EACD,MAAM,kBAAE,OAAO;AAAA,IACd,MAAM,kBAAE,QAAQ,MAAM;AAAA,EACvB,CAAC;AAAA,EACD,cAAc,kBAAE,OAAO;AAAA,IACtB,MAAM,kBAAE,QAAQ,YAAY;AAAA,IAC5B,aAAS,iCAAuB,OAAO;AAAA,IACvC,MAAM,kBAAE;AAAA,IACR,IAAI,kBAAE;AAAA,EACP,CAAC;AACF,CAAC;AASD,SAAS,6BACR,UACA,QAAyE,CAAC,GACzE;AACD,aAAO,4CAA8B;AAAA,IACpC,YAAY,cAAc,QAAQ;AAAA,IAClC,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,UAAU;AAAA,MACT;AAAA,QACC,IAAI,cAAc,QAAQ;AAAA,QAC1B,IAAI,CAAC,WAAW;AAAA,MACjB;AAAA,MACA,GAAG;AAAA,IACJ;AAAA,EACD,CAAC;AACF;AAQO,MAAM,4BAA8C;AAAA,EAC1D,OAAO;AAAA,EACP,YAAY,6BAA6B,kBAAkB;AAAA,IAC1D;AAAA;AAAA,MAEC,IAAI;AAAA,MACJ,IAAI,CAAC,WAAW;AACf,cAAM,SAAU,OAAe;AAC/B,YAAI,QAAQ,SAAS,WAAW,OAAO,MAAM,QAAW;AACvD;AAAC,UAAC,OAAe,SAAS,EAAE,GAAG,QAAQ,GAAG,GAAG,GAAG,GAAG,WAAW,MAAM;AAAA,QACrE;AACA,eAAO;AAAA,MACR;AAAA,MACA,MAAM,CAAC,WAAW;AACjB,cAAM,SAAU,OAAe;AAC/B,YAAI,QAAQ,SAAS,SAAS;AAC7B;AAAC,UAAC,OAAe,SAAS,EAAE,MAAM,SAAS,SAAS,OAAO,QAAQ;AAAA,QACpE;AACA,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD,CAAC;AAAA,EACD,WAAW,kBAAE,OAAO;AAAA,IACnB,QAAI,iCAA+B,gBAAgB;AAAA,IACnD,UAAU,kBAAE,QAAQ,gBAAgB;AAAA,IACpC,YAAQ,iCAAsB,MAAM;AAAA,IACpC,QAAQ;AAAA,IACR,WAAW,kBAAE;AAAA,IACb,WAAW,kBAAE;AAAA,IACb,UAAU,kBAAE,OAAO,EAAE,IAAI,kBAAE,QAAQ,IAAI,kBAAE,OAAO,CAAC,EAAE,SAAS;AAAA,IAC5D,MAAM,kBAAE;AAAA,EACT,CAAC;AACF;AAQO,MAAM,sBAAwC;AAAA,EACpD,OAAO;AAAA,EACP,YAAY,6BAA6B,SAAS;AAAA,EAClD,WAAW,kBAAE,OAAO;AAAA,IACnB,QAAI,iCAAyB,SAAS;AAAA,IACtC,UAAU,kBAAE,QAAQ,SAAS;AAAA,IAC7B,cAAU,iCAA+B,gBAAgB;AAAA,IACzD,YAAQ,iCAAsB,MAAM;AAAA,IACpC,UAAU,kBAAE;AAAA,IACZ,WAAW,kBAAE;AAAA,IACb,UAAU,kBAAE,OAAO,SAAS;AAAA,IAC5B,MAAM;AAAA,IACN,MAAM,kBAAE;AAAA,EACT,CAAC;AACF;AASO,MAAM,uBAAuB;AAAA,EACnC,kBAAkB;AAAA,EAClB,SAAS;AACV;AAGO,SAAS,sBAAsB,IAAgC;AACrE,aAAO,4CAAqB,kBAAkB,EAAE;AACjD;AAGO,SAAS,gBAAgB,IAA0B;AACzD,aAAO,4CAAqB,WAAW,EAAE;AAC1C;AASO,SAAS,kBAAkB,IAAqC;AACtE,aAAO,wCAAiB,kBAAkB,EAAE;AAC7C;AAQO,SAAS,YAAY,IAA+B;AAC1D,aAAO,wCAAiB,WAAW,EAAE;AACtC;AAOO,SAAS,oBAAoB,OAMhB;AACnB,SAAO;AAAA,IACN,IAAI,sBAAsB;AAAA,IAC1B,UAAU;AAAA,IACV,QAAQ,MAAM;AAAA,IACd,QAAQ,MAAM;AAAA,IACd,WAAW,MAAM;AAAA,IACjB,WAAW,MAAM,OAAO,KAAK,IAAI;AAAA,IACjC,UAAU;AAAA,IACV,MAAM,MAAM,QAAQ,CAAC;AAAA,EACtB;AACD;AAOO,SAAS,cAAc,OAOhB;AACb,SAAO;AAAA,IACN,IAAI,gBAAgB;AAAA,IACpB,UAAU;AAAA,IACV,UAAU,MAAM;AAAA,IAChB,QAAQ,MAAM;AAAA,IACd,UAAU,MAAM;AAAA,IAChB,WAAW,MAAM,OAAO,KAAK,IAAI;AAAA,IACjC,UAAU;AAAA,IACV,MAAM,MAAM;AAAA,IACZ,MAAM,MAAM,QAAQ,CAAC;AAAA,EACtB;AACD;",
4
+ "sourcesContent": ["import { BaseRecord, RecordId, createRecordMigrationSequence } from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\nimport { richTextValidator, TLRichText } from '../misc/TLRichText'\nimport { CustomRecordInfo, createCustomRecordId, isCustomRecordId } from './TLCustomRecord'\nimport { TLPageId } from './TLPage'\nimport { TLShapeId } from './TLShape'\n\n/**\n * Where a comment thread is anchored on the canvas. Modeled as a discriminated union so new\n * anchor kinds can be added without breaking existing threads:\n *\n * - `shape` \u2014 pinned to a shape. `x`/`y` are normalized (0\u20131) within the shape's bounds, so the pin\n * keeps its spot as the shape moves, resizes, and rotates. `isPrecise` mirrors arrow bindings:\n * when false (the default) the pin sits at a consumer-defined spot instead, top-right out of the\n * box, and `x`/`y` are the remembered precise position\n * - `point` \u2014 pinned to a fixed point on the page, in page coordinates\n * - `region` \u2014 pinned to a rectangular area of the page, in page coordinates\n * - `page` \u2014 a page-level thread with no spatial anchor\n *\n * @public\n */\nexport type TLCommentAnchor =\n\t| { type: 'shape'; shapeId: TLShapeId; x: number; y: number; isPrecise: boolean }\n\t| { type: 'point'; x: number; y: number }\n\t| {\n\t\t\ttype: 'region'\n\t\t\tx: number\n\t\t\ty: number\n\t\t\tw: number\n\t\t\th: number\n\t\t\t/** The normalized (0\u20131) corner the pin sits on \u2014 where the creating drag was released.\n\t\t\t * Absent on older records; consumers fall back to a corner of their own choosing. */\n\t\t\tpinX?: number\n\t\t\tpinY?: number\n\t }\n\t| { type: 'page' }\n\n/**\n * A comment thread. The thread owns the anchor (where the conversation lives on the canvas) and\n * the resolution state; the messages themselves are `TLComment` records pointing at the thread\n * via `threadId`, ordered by `createdAt`. v1 threads are flat \u2014 no nested replies.\n *\n * Threads and comments are document records, but they're intended to be served through the sync\n * server's object-store lane: gated by the session's `objectAccess` rather than `isReadonly`\n * (so \"can comment but not edit\" is expressible), excluded from document snapshots and `.tldr`\n * exports server-side, and persisted in a separate lane from the main document.\n *\n * Opt-in: register with `createTLSchema({ records: commentSchemaRecords })` on the server and\n * the matching `records` option on the client \u2014 neither type is part of the default schema, and\n * both sides must register them identically.\n *\n * @public\n */\nexport interface TLCommentThread extends BaseRecord<'comment-thread', TLCommentThreadId> {\n\t/** The page the thread lives on. */\n\tpageId: TLPageId\n\t/** Where the thread is anchored on that page. */\n\tanchor: TLCommentAnchor\n\t/** Who started the thread. Client-supplied; sync servers are expected to stamp/verify it. */\n\tcreatedBy: string\n\tcreatedAt: number\n\t/** Resolution state: when and by whom the thread was resolved, or null while open. */\n\tresolved: { at: number; by: string } | null\n\t/**\n\t * Whether the thread is soft-deleted. Clients set the flag and leave the record in place. Sync\n\t * servers are expected to enforce it as write-once and creator-only, reject client hard\n\t * deletes, and drop flagged threads from future room loads.\n\t */\n\tisDeleted: boolean\n\tmeta: JsonObject\n}\n\n/** @public */\nexport type TLCommentThreadId = RecordId<TLCommentThread>\n\n/**\n * A single comment message within a thread. See `TLCommentThread` for the overall model and\n * sync/registration notes.\n *\n * Comment mutations are deliberately not undoable \u2014 create/edit them with\n * `{ history: 'ignore' }` to avoid multiplayer surprises like a comment reappearing after\n * someone else deleted it.\n *\n * @public\n */\nexport interface TLComment extends BaseRecord<'comment', TLCommentId> {\n\t/** The thread this comment belongs to. */\n\tthreadId: TLCommentThreadId\n\t/** Denormalized from the thread so per-page queries don't need a join. */\n\tpageId: TLPageId\n\t/** See `TLCommentThread.createdBy` \u2014 same server-stamping caveat applies. */\n\tauthorId: string\n\tcreatedAt: number\n\t/** Null until the comment is first edited. */\n\teditedAt: number | null\n\t/** Rich text body. Use `toRichText(...)` for plaintext input. */\n\tbody: TLRichText\n\t/** Whether the comment is soft-deleted. Same model as `TLCommentThread.isDeleted`. */\n\tisDeleted: boolean\n\tmeta: JsonObject\n}\n\n/** @public */\nexport type TLCommentId = RecordId<TLComment>\n\n/**\n * One person's emoji reaction to one comment.\n *\n * A reaction is its own record rather than a field on the comment: comment records are owner-only\n * for updates, and a shared field would make concurrent reactions race to overwrite each other.\n *\n * A user holds at most one record per (comment, emoji) pair, enforced by the derived id \u2014 see\n * `createCommentReactionId`. Limiting a user to one reaction overall is client-side policy (the\n * commenting package's `reactionMode`), not a property of this record.\n *\n * @public\n */\nexport interface TLCommentReaction extends BaseRecord<'comment-reaction', TLCommentReactionId> {\n\t/** The comment being reacted to. */\n\tcommentId: TLCommentId\n\t/** Denormalized from the comment, so a thread's reactions can be found without a join. */\n\tthreadId: TLCommentThreadId\n\t/** Denormalized from the comment \u2014 see `TLComment.pageId`. */\n\tpageId: TLPageId\n\t/** Who reacted. See `TLCommentThread.createdBy` \u2014 same server-stamping caveat applies. */\n\tuserId: string\n\t/** The emoji itself, as a string (e.g. `'\uD83D\uDC4D'`), not a shortcode. */\n\temoji: string\n\tcreatedAt: number\n\tmeta: JsonObject\n}\n\n/** @public */\nexport type TLCommentReactionId = RecordId<TLCommentReaction>\n\n/**\n * An emoji shortcode or literal. Bounded because reaction ids embed the emoji verbatim\n * (see {@link createCommentReactionId}), so an unbounded value means an unbounded record id.\n */\nconst emojiValidator = T.string.check((value) => {\n\tif (value.length === 0 || value.length > 64) {\n\t\tthrow new T.ValidationError(`Expected an emoji of 1-64 characters, got ${value.length}`)\n\t}\n})\n\nconst commentAnchorValidator: T.Validator<TLCommentAnchor> = T.union('type', {\n\tshape: T.object({\n\t\ttype: T.literal('shape'),\n\t\tshapeId: idValidator<TLShapeId>('shape'),\n\t\tx: T.number,\n\t\ty: T.number,\n\t\tisPrecise: T.boolean,\n\t}),\n\tpoint: T.object({\n\t\ttype: T.literal('point'),\n\t\tx: T.number,\n\t\ty: T.number,\n\t}),\n\tregion: T.object({\n\t\ttype: T.literal('region'),\n\t\tx: T.number,\n\t\ty: T.number,\n\t\tw: T.number,\n\t\th: T.number,\n\t\tpinX: T.number.optional(),\n\t\tpinY: T.number.optional(),\n\t}),\n\tpage: T.object({\n\t\ttype: T.literal('page'),\n\t}),\n})\n\n/**\n * Guard migrations for the comment record types. Each sequence starts with an identity migration\n * that has no `down`, so a session whose schema predates the comment types is rejected with\n * CLIENT_TOO_OLD instead of being sent records its store can't represent.\n */\nfunction createCommentGuardMigrations(\n\ttypeName: 'comment' | 'comment-thread' | 'comment-reaction',\n\textra: Parameters<typeof createRecordMigrationSequence>[0]['sequence'] = []\n) {\n\treturn createRecordMigrationSequence({\n\t\tsequenceId: `com.tldraw.${typeName}`,\n\t\trecordType: typeName,\n\t\tretroactive: true,\n\t\tsequence: [\n\t\t\t{\n\t\t\t\tid: `com.tldraw.${typeName}/1`,\n\t\t\t\tup: (record) => record,\n\t\t\t},\n\t\t\t...extra,\n\t\t],\n\t})\n}\n\n/**\n * Config for registering the `comment-thread` record type in a tldraw schema. Pass via\n * `commentSchemaRecords`; see `TLCommentThread`.\n *\n * @public\n */\nexport const commentThreadRecordConfig: CustomRecordInfo = {\n\tscope: 'document',\n\tmigrations: createCommentGuardMigrations('comment-thread', [\n\t\t{\n\t\t\t// Shape anchors gained normalized x/y + isPrecise; existing ones were imprecise (top-right).\n\t\t\tid: 'com.tldraw.comment-thread/2',\n\t\t\tup: (record) => {\n\t\t\t\tconst anchor = (record as any).anchor\n\t\t\t\tif (anchor?.type === 'shape' && anchor.x === undefined) {\n\t\t\t\t\t;(record as any).anchor = { ...anchor, x: 1, y: 0, isPrecise: false }\n\t\t\t\t}\n\t\t\t\treturn record\n\t\t\t},\n\t\t\tdown: (record) => {\n\t\t\t\tconst anchor = (record as any).anchor\n\t\t\t\tif (anchor?.type === 'shape') {\n\t\t\t\t\t;(record as any).anchor = { type: 'shape', shapeId: anchor.shapeId }\n\t\t\t\t}\n\t\t\t\treturn record\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\t// Region anchors gained an optional pin corner (where the creating drag released).\n\t\t\tid: 'com.tldraw.comment-thread/3',\n\t\t\tup: (record) => record,\n\t\t\tdown: (record) => {\n\t\t\t\tconst anchor = (record as any).anchor\n\t\t\t\tif (anchor?.type === 'region') {\n\t\t\t\t\tconst { pinX: _pinX, pinY: _pinY, ...rest } = anchor\n\t\t\t\t\t;(record as any).anchor = rest\n\t\t\t\t}\n\t\t\t\treturn record\n\t\t\t},\n\t\t},\n\t]),\n\tvalidator: T.object({\n\t\tid: idValidator<TLCommentThreadId>('comment-thread'),\n\t\ttypeName: T.literal('comment-thread'),\n\t\tpageId: idValidator<TLPageId>('page'),\n\t\tanchor: commentAnchorValidator,\n\t\tcreatedBy: T.string,\n\t\tcreatedAt: T.number,\n\t\tresolved: T.object({ at: T.number, by: T.string }).nullable(),\n\t\tisDeleted: T.boolean,\n\t\tmeta: T.jsonValue,\n\t}),\n}\n\n/**\n * Config for registering the `comment` record type in a tldraw schema. Pass via\n * `commentSchemaRecords`; see `TLComment`.\n *\n * @public\n */\nexport const commentRecordConfig: CustomRecordInfo = {\n\tscope: 'document',\n\tmigrations: createCommentGuardMigrations('comment'),\n\tvalidator: T.object({\n\t\tid: idValidator<TLCommentId>('comment'),\n\t\ttypeName: T.literal('comment'),\n\t\tthreadId: idValidator<TLCommentThreadId>('comment-thread'),\n\t\tpageId: idValidator<TLPageId>('page'),\n\t\tauthorId: T.string,\n\t\tcreatedAt: T.number,\n\t\teditedAt: T.number.nullable(),\n\t\tbody: richTextValidator,\n\t\tisDeleted: T.boolean,\n\t\tmeta: T.jsonValue,\n\t}),\n}\n\n/**\n * Config for registering the `comment-reaction` record type in a tldraw schema. Pass via\n * `commentSchemaRecords`; see `TLCommentReaction`.\n *\n * @public\n */\nexport const commentReactionRecordConfig: CustomRecordInfo = {\n\tscope: 'document',\n\tmigrations: createCommentGuardMigrations('comment-reaction'),\n\tvalidator: T.object({\n\t\tid: idValidator<TLCommentReactionId>('comment-reaction'),\n\t\ttypeName: T.literal('comment-reaction'),\n\t\tcommentId: idValidator<TLCommentId>('comment'),\n\t\tthreadId: idValidator<TLCommentThreadId>('comment-thread'),\n\t\tpageId: idValidator<TLPageId>('page'),\n\t\tuserId: T.string,\n\t\temoji: emojiValidator,\n\t\tcreatedAt: T.number,\n\t\tmeta: T.jsonValue,\n\t}),\n}\n\n/**\n * The `records` map to pass to `createTLSchema` / the client `records` option so comment\n * threads, comments, and reactions sync. Register the types together \u2014 one without the others\n * will fail schema validation on one side of the connection.\n *\n * @public\n */\nexport const commentSchemaRecords = {\n\t'comment-thread': commentThreadRecordConfig,\n\tcomment: commentRecordConfig,\n\t'comment-reaction': commentReactionRecordConfig,\n}\n\n/** @public */\nexport function createCommentThreadId(id?: string): TLCommentThreadId {\n\treturn createCustomRecordId('comment-thread', id) as TLCommentThreadId\n}\n\n/** @public */\nexport function createCommentId(id?: string): TLCommentId {\n\treturn createCustomRecordId('comment', id) as TLCommentId\n}\n\n/**\n * The id of one user's reaction to one comment, derived from the (comment, user, emoji) triple\n * rather than random, so the same triple always addresses the same record and two tabs converge\n * instead of racing to create duplicates. The sync authorizer leans on this, so it must be\n * injective: all three parts are URI-encoded before joining, so a `:` in any of them can't shift\n * the boundary and collapse two triples onto one id.\n *\n * @public\n */\nexport function createCommentReactionId(\n\tcommentId: TLCommentId,\n\tuserId: string,\n\temoji: string\n): TLCommentReactionId {\n\treturn createCustomRecordId(\n\t\t'comment-reaction',\n\t\t`${encodeURIComponent(commentId)}:${encodeURIComponent(userId)}:${encodeURIComponent(emoji)}`\n\t) as TLCommentReactionId\n}\n\n/**\n * Type guard for `TLCommentThreadId`. `isCommentId` rejects these \u2014 `comment-thread:` and\n * `comment:` differ in the character after `comment`, so the prefixes never overlap.\n *\n * @public\n */\nexport function isCommentThreadId(id: string): id is TLCommentThreadId {\n\treturn isCustomRecordId('comment-thread', id)\n}\n\n/**\n * Type guard for `TLCommentId`. See `isCommentThreadId`.\n *\n * @public\n */\nexport function isCommentId(id: string): id is TLCommentId {\n\treturn isCustomRecordId('comment', id)\n}\n\n/**\n * Type guard for `TLCommentReactionId`. See `isCommentThreadId`.\n *\n * @public\n */\nexport function isCommentReactionId(id: string): id is TLCommentReactionId {\n\treturn isCustomRecordId('comment-reaction', id)\n}\n\n/**\n * Create a new comment thread record. Pair with `createComment` for the thread's first message.\n *\n * @public\n */\nexport function createCommentThread(props: {\n\tpageId: TLPageId\n\tanchor: TLCommentAnchor\n\tcreatedBy: string\n\tnow?: number\n\tmeta?: JsonObject\n}): TLCommentThread {\n\treturn {\n\t\tid: createCommentThreadId(),\n\t\ttypeName: 'comment-thread',\n\t\tpageId: props.pageId,\n\t\tanchor: props.anchor,\n\t\tcreatedBy: props.createdBy,\n\t\tcreatedAt: props.now ?? Date.now(),\n\t\tresolved: null,\n\t\tisDeleted: false,\n\t\tmeta: props.meta ?? {},\n\t}\n}\n\n/**\n * Create a new comment record within a thread.\n *\n * @public\n */\nexport function createComment(props: {\n\tthreadId: TLCommentThreadId\n\tpageId: TLPageId\n\tauthorId: string\n\tbody: TLRichText\n\tnow?: number\n\tmeta?: JsonObject\n}): TLComment {\n\treturn {\n\t\tid: createCommentId(),\n\t\ttypeName: 'comment',\n\t\tthreadId: props.threadId,\n\t\tpageId: props.pageId,\n\t\tauthorId: props.authorId,\n\t\tcreatedAt: props.now ?? Date.now(),\n\t\teditedAt: null,\n\t\tbody: props.body,\n\t\tisDeleted: false,\n\t\tmeta: props.meta ?? {},\n\t}\n}\n\n/**\n * Create a reaction record for one user's reaction to one comment. The id is derived from the\n * comment and user (see `createCommentReactionId`), so re-reacting overwrites rather than adding.\n *\n * @public\n */\nexport function createCommentReaction(props: {\n\tcommentId: TLCommentId\n\tthreadId: TLCommentThreadId\n\tpageId: TLPageId\n\tuserId: string\n\temoji: string\n\tnow?: number\n\tmeta?: JsonObject\n}): TLCommentReaction {\n\treturn {\n\t\tid: createCommentReactionId(props.commentId, props.userId, props.emoji),\n\t\ttypeName: 'comment-reaction',\n\t\tcommentId: props.commentId,\n\t\tthreadId: props.threadId,\n\t\tpageId: props.pageId,\n\t\tuserId: props.userId,\n\t\temoji: props.emoji,\n\t\tcreatedAt: props.now ?? Date.now(),\n\t\tmeta: props.meta ?? {},\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -68,6 +68,8 @@ const geoShapeProps = {
68
68
  h: import_validate.T.nonZeroNumber,
69
69
  growY: import_validate.T.positiveNumber,
70
70
  scale: import_validate.T.nonZeroNumber,
71
+ flipX: import_validate.T.boolean,
72
+ flipY: import_validate.T.boolean,
71
73
  // Text properties
72
74
  labelColor: import_TLColorStyle.DefaultLabelColorStyle,
73
75
  color: import_TLColorStyle.DefaultColorStyle,
@@ -89,7 +91,8 @@ const geoShapeVersions = (0, import_TLShape.createShapePropsMigrationIds)("geo",
89
91
  MakeUrlsValid: 8,
90
92
  AddScale: 9,
91
93
  AddRichText: 10,
92
- AddRichTextAttrs: 11
94
+ AddRichTextAttrs: 11,
95
+ AddFlipProps: 12
93
96
  });
94
97
  const geoShapeMigrations = (0, import_TLShape.createShapePropsMigrationSequence)({
95
98
  sequence: [
@@ -193,6 +196,17 @@ const geoShapeMigrations = (0, import_TLShape.createShapePropsMigrationSequence)
193
196
  delete props.richText.attrs;
194
197
  }
195
198
  }
199
+ },
200
+ {
201
+ id: geoShapeVersions.AddFlipProps,
202
+ up: (props) => {
203
+ props.flipX = false;
204
+ props.flipY = false;
205
+ },
206
+ down: (props) => {
207
+ delete props.flipX;
208
+ delete props.flipY;
209
+ }
196
210
  }
197
211
  ]
198
212
  });