UNPKG

@tldraw/tlschema

Version:

tldraw infinite canvas SDK (schema).

213 lines (212 loc) • 5.93 kB
import { createRecordMigrationSequence } from "@tldraw/store"; import { T } from "@tldraw/validate"; import { idValidator } from "../misc/id-validator.mjs"; import { richTextValidator } from "../misc/TLRichText.mjs"; import { createCustomRecordId, isCustomRecordId } from "./TLCustomRecord.mjs"; const emojiValidator = T.string.check((value) => { if (value.length === 0 || value.length > 64) { throw new T.ValidationError(`Expected an emoji of 1-64 characters, got ${value.length}`); } }); const commentAnchorValidator = T.union("type", { shape: T.object({ type: T.literal("shape"), shapeId: idValidator("shape"), x: T.number, y: T.number, isPrecise: T.boolean }), point: T.object({ type: T.literal("point"), x: T.number, y: T.number }), region: T.object({ type: T.literal("region"), x: T.number, y: T.number, w: T.number, h: T.number, pinX: T.number.optional(), pinY: T.number.optional() }), page: T.object({ type: T.literal("page") }) }); function createCommentGuardMigrations(typeName, extra = []) { return createRecordMigrationSequence({ sequenceId: `com.tldraw.${typeName}`, recordType: typeName, retroactive: true, sequence: [ { id: `com.tldraw.${typeName}/1`, up: (record) => record }, ...extra ] }); } const commentThreadRecordConfig = { scope: "document", migrations: createCommentGuardMigrations("comment-thread", [ { // Shape anchors gained normalized x/y + isPrecise; existing ones were imprecise (top-right). id: "com.tldraw.comment-thread/2", up: (record) => { const anchor = record.anchor; if (anchor?.type === "shape" && anchor.x === void 0) { ; record.anchor = { ...anchor, x: 1, y: 0, isPrecise: false }; } return record; }, down: (record) => { const anchor = record.anchor; if (anchor?.type === "shape") { ; record.anchor = { type: "shape", shapeId: anchor.shapeId }; } return record; } }, { // Region anchors gained an optional pin corner (where the creating drag released). id: "com.tldraw.comment-thread/3", up: (record) => record, down: (record) => { const anchor = record.anchor; if (anchor?.type === "region") { const { pinX: _pinX, pinY: _pinY, ...rest } = anchor; record.anchor = rest; } return record; } } ]), validator: T.object({ id: idValidator("comment-thread"), typeName: T.literal("comment-thread"), pageId: idValidator("page"), anchor: commentAnchorValidator, createdBy: T.string, createdAt: T.number, resolved: T.object({ at: T.number, by: T.string }).nullable(), isDeleted: T.boolean, meta: T.jsonValue }) }; const commentRecordConfig = { scope: "document", migrations: createCommentGuardMigrations("comment"), validator: T.object({ id: idValidator("comment"), typeName: T.literal("comment"), threadId: idValidator("comment-thread"), pageId: idValidator("page"), authorId: T.string, createdAt: T.number, editedAt: T.number.nullable(), body: richTextValidator, isDeleted: T.boolean, meta: T.jsonValue }) }; const commentReactionRecordConfig = { scope: "document", migrations: createCommentGuardMigrations("comment-reaction"), validator: T.object({ id: idValidator("comment-reaction"), typeName: T.literal("comment-reaction"), commentId: idValidator("comment"), threadId: idValidator("comment-thread"), pageId: idValidator("page"), userId: T.string, emoji: emojiValidator, createdAt: T.number, meta: T.jsonValue }) }; const commentSchemaRecords = { "comment-thread": commentThreadRecordConfig, comment: commentRecordConfig, "comment-reaction": commentReactionRecordConfig }; function createCommentThreadId(id) { return createCustomRecordId("comment-thread", id); } function createCommentId(id) { return createCustomRecordId("comment", id); } function createCommentReactionId(commentId, userId, emoji) { return createCustomRecordId( "comment-reaction", `${encodeURIComponent(commentId)}:${encodeURIComponent(userId)}:${encodeURIComponent(emoji)}` ); } function isCommentThreadId(id) { return isCustomRecordId("comment-thread", id); } function isCommentId(id) { return isCustomRecordId("comment", id); } function isCommentReactionId(id) { return isCustomRecordId("comment-reaction", id); } function createCommentThread(props) { return { id: createCommentThreadId(), typeName: "comment-thread", pageId: props.pageId, anchor: props.anchor, createdBy: props.createdBy, createdAt: props.now ?? Date.now(), resolved: null, isDeleted: false, meta: props.meta ?? {} }; } function createComment(props) { return { id: createCommentId(), typeName: "comment", threadId: props.threadId, pageId: props.pageId, authorId: props.authorId, createdAt: props.now ?? Date.now(), editedAt: null, body: props.body, isDeleted: false, meta: props.meta ?? {} }; } function createCommentReaction(props) { return { id: createCommentReactionId(props.commentId, props.userId, props.emoji), typeName: "comment-reaction", commentId: props.commentId, threadId: props.threadId, pageId: props.pageId, userId: props.userId, emoji: props.emoji, createdAt: props.now ?? Date.now(), meta: props.meta ?? {} }; } export { commentReactionRecordConfig, commentRecordConfig, commentSchemaRecords, commentThreadRecordConfig, createComment, createCommentId, createCommentReaction, createCommentReactionId, createCommentThread, createCommentThreadId, isCommentId, isCommentReactionId, isCommentThreadId }; //# sourceMappingURL=TLComment.mjs.map