UNPKG

@tldraw/tlschema

Version:

tldraw infinite canvas SDK (schema).

498 lines (497 loc) • 13.6 kB
import { createMigrationIds, createRecordMigrationSequence, createRecordType } from "@tldraw/store"; import { filterEntries } from "@tldraw/utils"; import { T } from "@tldraw/validate"; import { boxModelValidator } from "../misc/geometry-types.mjs"; import { idValidator } from "../misc/id-validator.mjs"; import { cursorValidator } from "../misc/TLCursor.mjs"; import { opacityValidator } from "../misc/TLOpacity.mjs"; import { scribbleValidator } from "../misc/TLScribble.mjs"; import { pageIdValidator } from "./TLPage.mjs"; const shouldKeyBePreservedBetweenSessions = { // This object defines keys that should be preserved across calls to loadSnapshot() id: false, // meta typeName: false, // meta currentPageId: false, // does not preserve because who knows if the page still exists opacityForNextShape: false, // does not preserve because it's a temporary state stylesForNextShape: false, // does not preserve because it's a temporary state followingUserId: false, // does not preserve because it's a temporary state highlightedUserIds: false, // does not preserve because it's a temporary state brush: false, // does not preserve because it's a temporary state cursor: false, // does not preserve because it's a temporary state scribbles: false, // does not preserve because it's a temporary state isFocusMode: true, // preserves because it's a user preference isDebugMode: true, // preserves because it's a user preference isToolLocked: true, // preserves because it's a user preference exportBackground: true, // preserves because it's a user preference screenBounds: true, // preserves because it's capturing the user's screen state insets: true, // preserves because it's capturing the user's screen state zoomBrush: false, // does not preserve because it's a temporary state chatMessage: false, // does not preserve because it's a temporary state isChatting: false, // does not preserve because it's a temporary state isPenMode: false, // does not preserve because it's a temporary state isGridMode: true, // preserves because it's a user preference isFocused: true, // preserves because obviously devicePixelRatio: true, // preserves because it captures the user's screen state isCoarsePointer: true, // preserves because it captures the user's screen state isHoveringCanvas: false, // does not preserve because it's a temporary state openMenus: false, // does not preserve because it's a temporary state isChangingStyle: false, // does not preserve because it's a temporary state isReadonly: true, // preserves because it's a config option meta: false, // does not preserve because who knows what's in there, leave it up to sdk users to save and reinstate duplicateProps: false, // cameraState: false // does not preserve because it's a temporary state }; function pluckPreservingValues(val) { return val ? filterEntries(val, (key) => { return shouldKeyBePreservedBetweenSessions[key]; }) : null; } const instanceIdValidator = idValidator("instance"); function createInstanceRecordType(stylesById) { const stylesForNextShapeValidators = {}; for (const [id, style] of stylesById) { stylesForNextShapeValidators[id] = T.optional(style); } const instanceTypeValidator = T.model( "instance", T.object({ typeName: T.literal("instance"), id: idValidator("instance"), currentPageId: pageIdValidator, followingUserId: T.string.nullable(), brush: boxModelValidator.nullable(), opacityForNextShape: opacityValidator, stylesForNextShape: T.object(stylesForNextShapeValidators), cursor: cursorValidator, scribbles: T.arrayOf(scribbleValidator), isFocusMode: T.boolean, isDebugMode: T.boolean, isToolLocked: T.boolean, exportBackground: T.boolean, screenBounds: boxModelValidator, insets: T.arrayOf(T.boolean), zoomBrush: boxModelValidator.nullable(), isPenMode: T.boolean, isGridMode: T.boolean, chatMessage: T.string, isChatting: T.boolean, highlightedUserIds: T.arrayOf(T.string), isFocused: T.boolean, devicePixelRatio: T.number, isCoarsePointer: T.boolean, isHoveringCanvas: T.boolean.nullable(), openMenus: T.arrayOf(T.string), isChangingStyle: T.boolean, isReadonly: T.boolean, meta: T.jsonValue, duplicateProps: T.object({ shapeIds: T.arrayOf(idValidator("shape")), offset: T.object({ x: T.number, y: T.number }) }).nullable(), cameraState: T.literalEnum("idle", "moving") }) ); return createRecordType("instance", { validator: instanceTypeValidator, scope: "session", ephemeralKeys: { currentPageId: false, meta: false, followingUserId: true, opacityForNextShape: true, stylesForNextShape: true, brush: true, cursor: true, scribbles: true, isFocusMode: true, isDebugMode: true, isToolLocked: true, exportBackground: true, screenBounds: true, insets: true, zoomBrush: true, isPenMode: true, isGridMode: true, chatMessage: true, isChatting: true, highlightedUserIds: true, isFocused: true, devicePixelRatio: true, isCoarsePointer: true, isHoveringCanvas: true, openMenus: true, isChangingStyle: true, isReadonly: true, duplicateProps: true, cameraState: true } }).withDefaultProperties( () => ({ followingUserId: null, opacityForNextShape: 1, stylesForNextShape: {}, brush: null, scribbles: [], cursor: { type: "default", rotation: 0 }, isFocusMode: false, exportBackground: false, isDebugMode: false, isToolLocked: false, screenBounds: { x: 0, y: 0, w: 1080, h: 720 }, insets: [false, false, false, false], zoomBrush: null, isGridMode: false, isPenMode: false, chatMessage: "", isChatting: false, highlightedUserIds: [], isFocused: false, devicePixelRatio: typeof window === "undefined" ? 1 : window.devicePixelRatio, isCoarsePointer: false, isHoveringCanvas: null, openMenus: [], isChangingStyle: false, isReadonly: false, meta: {}, duplicateProps: null, cameraState: "idle" }) ); } const instanceVersions = createMigrationIds("com.tldraw.instance", { AddTransparentExportBgs: 1, RemoveDialog: 2, AddToolLockMode: 3, RemoveExtraPropsForNextShape: 4, AddLabelColor: 5, AddFollowingUserId: 6, RemoveAlignJustify: 7, AddZoom: 8, AddVerticalAlign: 9, AddScribbleDelay: 10, RemoveUserId: 11, AddIsPenModeAndIsGridMode: 12, HoistOpacity: 13, AddChat: 14, AddHighlightedUserIds: 15, ReplacePropsForNextShapeWithStylesForNextShape: 16, AddMeta: 17, RemoveCursorColor: 18, AddLonelyProperties: 19, ReadOnlyReadonly: 20, AddHoveringCanvas: 21, AddScribbles: 22, AddInset: 23, AddDuplicateProps: 24, RemoveCanMoveCamera: 25, AddCameraState: 26 }); const instanceMigrations = createRecordMigrationSequence({ sequenceId: "com.tldraw.instance", recordType: "instance", sequence: [ { id: instanceVersions.AddTransparentExportBgs, up: (instance) => { return { ...instance, exportBackground: true }; } }, { id: instanceVersions.RemoveDialog, up: ({ dialog: _, ...instance }) => { return instance; } }, { id: instanceVersions.AddToolLockMode, up: (instance) => { return { ...instance, isToolLocked: false }; } }, { id: instanceVersions.RemoveExtraPropsForNextShape, up: ({ propsForNextShape, ...instance }) => { return { ...instance, propsForNextShape: Object.fromEntries( Object.entries(propsForNextShape).filter( ([key]) => [ "color", "labelColor", "dash", "fill", "size", "font", "align", "verticalAlign", "icon", "geo", "arrowheadStart", "arrowheadEnd", "spline" ].includes(key) ) ) }; } }, { id: instanceVersions.AddLabelColor, up: ({ propsForNextShape, ...instance }) => { return { ...instance, propsForNextShape: { ...propsForNextShape, labelColor: "black" } }; } }, { id: instanceVersions.AddFollowingUserId, up: (instance) => { return { ...instance, followingUserId: null }; } }, { id: instanceVersions.RemoveAlignJustify, up: (instance) => { let newAlign = instance.propsForNextShape.align; if (newAlign === "justify") { newAlign = "start"; } return { ...instance, propsForNextShape: { ...instance.propsForNextShape, align: newAlign } }; } }, { id: instanceVersions.AddZoom, up: (instance) => { return { ...instance, zoomBrush: null }; } }, { id: instanceVersions.AddVerticalAlign, up: (instance) => { return { ...instance, propsForNextShape: { ...instance.propsForNextShape, verticalAlign: "middle" } }; } }, { id: instanceVersions.AddScribbleDelay, up: (instance) => { if (instance.scribble !== null) { return { ...instance, scribble: { ...instance.scribble, delay: 0 } }; } return { ...instance }; } }, { id: instanceVersions.RemoveUserId, up: ({ userId: _, ...instance }) => { return instance; } }, { id: instanceVersions.AddIsPenModeAndIsGridMode, up: (instance) => { return { ...instance, isPenMode: false, isGridMode: false }; } }, { id: instanceVersions.HoistOpacity, up: ({ propsForNextShape: { opacity, ...propsForNextShape }, ...instance }) => { return { ...instance, opacityForNextShape: Number(opacity ?? "1"), propsForNextShape }; } }, { id: instanceVersions.AddChat, up: (instance) => { return { ...instance, chatMessage: "", isChatting: false }; } }, { id: instanceVersions.AddHighlightedUserIds, up: (instance) => { return { ...instance, highlightedUserIds: [] }; } }, { id: instanceVersions.ReplacePropsForNextShapeWithStylesForNextShape, up: ({ propsForNextShape: _, ...instance }) => { return { ...instance, stylesForNextShape: {} }; } }, { id: instanceVersions.AddMeta, up: (record) => { return { ...record, meta: {} }; } }, { id: instanceVersions.RemoveCursorColor, up: (record) => { const { color: _, ...cursor } = record.cursor; return { ...record, cursor }; } }, { id: instanceVersions.AddLonelyProperties, up: (record) => { return { ...record, canMoveCamera: true, isFocused: false, devicePixelRatio: 1, isCoarsePointer: false, openMenus: [], isChangingStyle: false, isReadOnly: false }; } }, { id: instanceVersions.ReadOnlyReadonly, up: ({ isReadOnly: _isReadOnly, ...record }) => { return { ...record, isReadonly: _isReadOnly }; } }, { id: instanceVersions.AddHoveringCanvas, up: (record) => { return { ...record, isHoveringCanvas: null }; } }, { id: instanceVersions.AddScribbles, up: ({ scribble: _, ...record }) => { return { ...record, scribbles: [] }; } }, { id: instanceVersions.AddInset, up: (record) => { return { ...record, insets: [false, false, false, false] }; }, down: ({ insets: _, ...record }) => { return { ...record }; } }, { id: instanceVersions.AddDuplicateProps, up: (record) => { return { ...record, duplicateProps: null }; }, down: ({ duplicateProps: _, ...record }) => { return { ...record }; } }, { id: instanceVersions.RemoveCanMoveCamera, up: ({ canMoveCamera: _, ...record }) => { return { ...record }; }, down: (instance) => { return { ...instance, canMoveCamera: true }; } }, { id: instanceVersions.AddCameraState, up: (record) => { return { ...record, cameraState: "idle" }; }, down: ({ cameraState: _, ...record }) => { return record; } } ] }); const TLINSTANCE_ID = "instance:instance"; export { TLINSTANCE_ID, createInstanceRecordType, instanceIdValidator, instanceMigrations, instanceVersions, pluckPreservingValues, shouldKeyBePreservedBetweenSessions }; //# sourceMappingURL=TLInstance.mjs.map