@tldraw/tlschema 4.6.0-next.1f489710ee41 → 4.6.0-next.4dde09fa17ab
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.
- package/dist-cjs/TLStore.js +13 -0
- package/dist-cjs/TLStore.js.map +2 -2
- package/dist-cjs/createPresenceStateDerivation.js +6 -4
- package/dist-cjs/createPresenceStateDerivation.js.map +2 -2
- package/dist-cjs/createTLSchema.js +8 -1
- package/dist-cjs/createTLSchema.js.map +2 -2
- package/dist-cjs/index.d.ts +211 -28
- package/dist-cjs/index.js +9 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/records/TLRecord.js.map +1 -1
- package/dist-cjs/records/TLUser.js +101 -0
- package/dist-cjs/records/TLUser.js.map +7 -0
- package/dist-cjs/shapes/TLNoteShape.js +13 -2
- package/dist-cjs/shapes/TLNoteShape.js.map +2 -2
- package/dist-esm/TLStore.mjs +13 -0
- package/dist-esm/TLStore.mjs.map +2 -2
- package/dist-esm/createPresenceStateDerivation.mjs +6 -4
- package/dist-esm/createPresenceStateDerivation.mjs.map +2 -2
- package/dist-esm/createTLSchema.mjs +8 -1
- package/dist-esm/createTLSchema.mjs.map +2 -2
- package/dist-esm/index.d.mts +211 -28
- package/dist-esm/index.mjs +17 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/records/TLUser.mjs +85 -0
- package/dist-esm/records/TLUser.mjs.map +7 -0
- package/dist-esm/shapes/TLNoteShape.mjs +13 -2
- package/dist-esm/shapes/TLNoteShape.mjs.map +2 -2
- package/package.json +6 -6
- package/src/TLStore.test.ts +5 -0
- package/src/TLStore.ts +95 -1
- package/src/createPresenceStateDerivation.test.ts +33 -20
- package/src/createPresenceStateDerivation.ts +20 -25
- package/src/createTLSchema.ts +52 -0
- package/src/index.ts +13 -1
- package/src/migrations.test.ts +22 -0
- package/src/records/TLRecord.ts +2 -0
- package/src/records/TLUser.ts +148 -0
- package/src/shapes/TLNoteShape.ts +13 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/shapes/TLNoteShape.ts"],
|
|
4
|
-
"sourcesContent": ["import { T } from '@tldraw/validate'\nimport { TLRichText, richTextValidator, toRichText } from '../misc/TLRichText'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport {\n\tDefaultColorStyle,\n\tDefaultLabelColorStyle,\n\tTLDefaultColorStyle,\n} from '../styles/TLColorStyle'\nimport { DefaultFontStyle, TLDefaultFontStyle } from '../styles/TLFontStyle'\nimport {\n\tDefaultHorizontalAlignStyle,\n\tTLDefaultHorizontalAlignStyle,\n} from '../styles/TLHorizontalAlignStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport {\n\tDefaultVerticalAlignStyle,\n\tTLDefaultVerticalAlignStyle,\n} from '../styles/TLVerticalAlignStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\n/**\n * Properties for a note shape. Note shapes represent sticky notes or text annotations\n * with rich formatting capabilities and various styling options.\n *\n * @public\n * @example\n * ```ts\n * const noteProps: TLNoteShapeProps = {\n * color: 'yellow',\n * labelColor: 'black',\n * size: 'm',\n * font: 'draw',\n * fontSizeAdjustment: 0,\n * align: 'middle',\n * verticalAlign: 'middle',\n * growY: 0,\n * url: '',\n * richText: toRichText('Hello **world**!'),\n * scale: 1\n * }\n * ```\n */\nexport interface TLNoteShapeProps {\n\t/** Background color style of the note */\n\tcolor: TLDefaultColorStyle\n\t/** Text color style for the note content */\n\tlabelColor: TLDefaultColorStyle\n\t/** Size style determining the font size and note dimensions */\n\tsize: TLDefaultSizeStyle\n\t/** Font family style for the note text */\n\tfont: TLDefaultFontStyle\n\t/** Adjustment to the base font size (positive increases, negative decreases) */\n\tfontSizeAdjustment: number\n\t/** Horizontal alignment of text within the note */\n\talign: TLDefaultHorizontalAlignStyle\n\t/** Vertical alignment of text within the note */\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\t/** Additional height growth for the note beyond its base size */\n\tgrowY: number\n\t/** Optional URL associated with the note for linking */\n\turl: string\n\t/** Rich text content with formatting like bold, italic, etc. */\n\trichText: TLRichText\n\t/** Scale factor applied to the note shape for display */\n\tscale: number\n}\n\n/**\n * A note shape representing a sticky note or text annotation on the canvas.\n * Note shapes support rich text formatting, various styling options, and can\n * be used for annotations, reminders, or general text content.\n *\n * @public\n * @example\n * ```ts\n * const noteShape: TLNoteShape = {\n * id: 'shape:note1',\n * type: 'note',\n * x: 100,\n * y: 100,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:main',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * color: 'light-blue',\n * labelColor: 'black',\n * size: 's',\n * font: 'sans',\n * fontSizeAdjustment: 2,\n * align: 'start',\n * verticalAlign: 'start',\n * growY: 50,\n * url: 'https://example.com',\n * richText: toRichText('Important **note**!'),\n * scale: 1\n * },\n * meta: {},\n * typeName: 'shape'\n * }\n * ```\n */\nexport type TLNoteShape = TLBaseShape<'note', TLNoteShapeProps>\n\n/**\n * Validation schema for note shape properties. Defines the runtime validation rules\n * for all properties of note shapes, ensuring data integrity and type safety.\n *\n * @public\n * @example\n * ```ts\n * import { noteShapeProps } from '@tldraw/tlschema'\n *\n * // Used internally by the validation system\n * const validator = T.object(noteShapeProps)\n * const validatedProps = validator.validate(someNoteProps)\n * ```\n */\nexport const noteShapeProps: RecordProps<TLNoteShape> = {\n\tcolor: DefaultColorStyle,\n\tlabelColor: DefaultLabelColorStyle,\n\tsize: DefaultSizeStyle,\n\tfont: DefaultFontStyle,\n\tfontSizeAdjustment: T.positiveNumber,\n\talign: DefaultHorizontalAlignStyle,\n\tverticalAlign: DefaultVerticalAlignStyle,\n\tgrowY: T.positiveNumber,\n\turl: T.linkUrl,\n\trichText: richTextValidator,\n\tscale: T.nonZeroNumber,\n}\n\nconst Versions = createShapePropsMigrationIds('note', {\n\tAddUrlProp: 1,\n\tRemoveJustify: 2,\n\tMigrateLegacyAlign: 3,\n\tAddVerticalAlign: 4,\n\tMakeUrlsValid: 5,\n\tAddFontSizeAdjustment: 6,\n\tAddScale: 7,\n\tAddLabelColor: 8,\n\tAddRichText: 9,\n\tAddRichTextAttrs: 10,\n})\n\n/**\n * Version identifiers for note shape migrations. These version numbers track\n * significant schema changes over time, enabling proper data migration between versions.\n *\n * @public\n */\nexport { Versions as noteShapeVersions }\n\n/**\n * Migration sequence for note shapes. Handles schema evolution over time by defining\n * how to upgrade and downgrade note shape data between different versions. Includes\n * migrations for URL properties, text alignment changes, vertical alignment addition,\n * font size adjustments, scaling support, label color, the transition from plain text to rich text,\n * and support for attrs property on richText.\n *\n * @public\n */\nexport const noteShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.AddUrlProp,\n\t\t\tup: (props) => {\n\t\t\t\tprops.url = ''\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveJustify,\n\t\t\tup: (props) => {\n\t\t\t\tif (props.align === 'justify') {\n\t\t\t\t\tprops.align = 'start'\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.MigrateLegacyAlign,\n\t\t\tup: (props) => {\n\t\t\t\tswitch (props.align) {\n\t\t\t\t\tcase 'start':\n\t\t\t\t\t\tprops.align = 'start-legacy'\n\t\t\t\t\t\treturn\n\t\t\t\t\tcase 'end':\n\t\t\t\t\t\tprops.align = 'end-legacy'\n\t\t\t\t\t\treturn\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tprops.align = 'middle-legacy'\n\t\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddVerticalAlign,\n\t\t\tup: (props) => {\n\t\t\t\tprops.verticalAlign = 'middle'\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.MakeUrlsValid,\n\t\t\tup: (props) => {\n\t\t\t\tif (!T.linkUrl.isValid(props.url)) {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (_props) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddFontSizeAdjustment,\n\t\t\tup: (props) => {\n\t\t\t\tprops.fontSizeAdjustment = 0\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.fontSizeAdjustment\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddLabelColor,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelColor = 'black'\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.labelColor\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddRichText,\n\t\t\tup: (props) => {\n\t\t\t\tprops.richText = toRichText(props.text)\n\t\t\t\tdelete props.text\n\t\t\t},\n\t\t\t// N.B. Explicitly no down state so that we force clients to update.\n\t\t\t// down: (props) => {\n\t\t\t// \tdelete props.richText\n\t\t\t// },\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddRichTextAttrs,\n\t\t\tup: (_props) => {\n\t\t\t\t// noop - attrs is optional so old records are valid\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\t// Remove attrs from richText when migrating down\n\t\t\t\tif (props.richText && 'attrs' in props.richText) {\n\t\t\t\t\tdelete props.richText.attrs\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t],\n})\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAkB;AAClB,wBAA0D;AAC1D,qBAAgF;AAEhF,0BAIO;AACP,yBAAqD;AACrD,oCAGO;AACP,yBAAqD;AACrD,kCAGO;
|
|
4
|
+
"sourcesContent": ["import { T } from '@tldraw/validate'\nimport { TLRichText, richTextValidator, toRichText } from '../misc/TLRichText'\nimport { createShapePropsMigrationIds, createShapePropsMigrationSequence } from '../records/TLShape'\nimport { RecordProps } from '../recordsWithProps'\nimport {\n\tDefaultColorStyle,\n\tDefaultLabelColorStyle,\n\tTLDefaultColorStyle,\n} from '../styles/TLColorStyle'\nimport { DefaultFontStyle, TLDefaultFontStyle } from '../styles/TLFontStyle'\nimport {\n\tDefaultHorizontalAlignStyle,\n\tTLDefaultHorizontalAlignStyle,\n} from '../styles/TLHorizontalAlignStyle'\nimport { DefaultSizeStyle, TLDefaultSizeStyle } from '../styles/TLSizeStyle'\nimport {\n\tDefaultVerticalAlignStyle,\n\tTLDefaultVerticalAlignStyle,\n} from '../styles/TLVerticalAlignStyle'\nimport { TLBaseShape } from './TLBaseShape'\n\n/**\n * Properties for a note shape. Note shapes represent sticky notes or text annotations\n * with rich formatting capabilities and various styling options.\n *\n * @public\n * @example\n * ```ts\n * const noteProps: TLNoteShapeProps = {\n * color: 'yellow',\n * labelColor: 'black',\n * size: 'm',\n * font: 'draw',\n * fontSizeAdjustment: 0,\n * align: 'middle',\n * verticalAlign: 'middle',\n * growY: 0,\n * url: '',\n * richText: toRichText('Hello **world**!'),\n * scale: 1\n * }\n * ```\n */\nexport interface TLNoteShapeProps {\n\t/** Background color style of the note */\n\tcolor: TLDefaultColorStyle\n\t/** Text color style for the note content */\n\tlabelColor: TLDefaultColorStyle\n\t/** Size style determining the font size and note dimensions */\n\tsize: TLDefaultSizeStyle\n\t/** Font family style for the note text */\n\tfont: TLDefaultFontStyle\n\t/** Adjustment to the base font size (positive increases, negative decreases) */\n\tfontSizeAdjustment: number\n\t/** Horizontal alignment of text within the note */\n\talign: TLDefaultHorizontalAlignStyle\n\t/** Vertical alignment of text within the note */\n\tverticalAlign: TLDefaultVerticalAlignStyle\n\t/** Additional height growth for the note beyond its base size */\n\tgrowY: number\n\t/** Optional URL associated with the note for linking */\n\turl: string\n\t/** Rich text content with formatting like bold, italic, etc. */\n\trichText: TLRichText\n\t/** Scale factor applied to the note shape for display */\n\tscale: number\n\t/** User ID of the person who first edited the note text */\n\ttextFirstEditedBy: string | null\n}\n\n/**\n * A note shape representing a sticky note or text annotation on the canvas.\n * Note shapes support rich text formatting, various styling options, and can\n * be used for annotations, reminders, or general text content.\n *\n * @public\n * @example\n * ```ts\n * const noteShape: TLNoteShape = {\n * id: 'shape:note1',\n * type: 'note',\n * x: 100,\n * y: 100,\n * rotation: 0,\n * index: 'a1',\n * parentId: 'page:main',\n * isLocked: false,\n * opacity: 1,\n * props: {\n * color: 'light-blue',\n * labelColor: 'black',\n * size: 's',\n * font: 'sans',\n * fontSizeAdjustment: 2,\n * align: 'start',\n * verticalAlign: 'start',\n * growY: 50,\n * url: 'https://example.com',\n * richText: toRichText('Important **note**!'),\n * scale: 1\n * },\n * meta: {},\n * typeName: 'shape'\n * }\n * ```\n */\nexport type TLNoteShape = TLBaseShape<'note', TLNoteShapeProps>\n\n/**\n * Validation schema for note shape properties. Defines the runtime validation rules\n * for all properties of note shapes, ensuring data integrity and type safety.\n *\n * @public\n * @example\n * ```ts\n * import { noteShapeProps } from '@tldraw/tlschema'\n *\n * // Used internally by the validation system\n * const validator = T.object(noteShapeProps)\n * const validatedProps = validator.validate(someNoteProps)\n * ```\n */\nexport const noteShapeProps: RecordProps<TLNoteShape> = {\n\tcolor: DefaultColorStyle,\n\tlabelColor: DefaultLabelColorStyle,\n\tsize: DefaultSizeStyle,\n\tfont: DefaultFontStyle,\n\tfontSizeAdjustment: T.positiveNumber,\n\talign: DefaultHorizontalAlignStyle,\n\tverticalAlign: DefaultVerticalAlignStyle,\n\tgrowY: T.positiveNumber,\n\turl: T.linkUrl,\n\trichText: richTextValidator,\n\tscale: T.nonZeroNumber,\n\ttextFirstEditedBy: T.string.nullable(),\n}\n\nconst Versions = createShapePropsMigrationIds('note', {\n\tAddUrlProp: 1,\n\tRemoveJustify: 2,\n\tMigrateLegacyAlign: 3,\n\tAddVerticalAlign: 4,\n\tMakeUrlsValid: 5,\n\tAddFontSizeAdjustment: 6,\n\tAddScale: 7,\n\tAddLabelColor: 8,\n\tAddRichText: 9,\n\tAddRichTextAttrs: 10,\n\tAddFirstEditedBy: 11,\n})\n\n/**\n * Version identifiers for note shape migrations. These version numbers track\n * significant schema changes over time, enabling proper data migration between versions.\n *\n * @public\n */\nexport { Versions as noteShapeVersions }\n\n/**\n * Migration sequence for note shapes. Handles schema evolution over time by defining\n * how to upgrade and downgrade note shape data between different versions. Includes\n * migrations for URL properties, text alignment changes, vertical alignment addition,\n * font size adjustments, scaling support, label color, the transition from plain text to rich text,\n * and support for attrs property on richText.\n *\n * @public\n */\nexport const noteShapeMigrations = createShapePropsMigrationSequence({\n\tsequence: [\n\t\t{\n\t\t\tid: Versions.AddUrlProp,\n\t\t\tup: (props) => {\n\t\t\t\tprops.url = ''\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.RemoveJustify,\n\t\t\tup: (props) => {\n\t\t\t\tif (props.align === 'justify') {\n\t\t\t\t\tprops.align = 'start'\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.MigrateLegacyAlign,\n\t\t\tup: (props) => {\n\t\t\t\tswitch (props.align) {\n\t\t\t\t\tcase 'start':\n\t\t\t\t\t\tprops.align = 'start-legacy'\n\t\t\t\t\t\treturn\n\t\t\t\t\tcase 'end':\n\t\t\t\t\t\tprops.align = 'end-legacy'\n\t\t\t\t\t\treturn\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tprops.align = 'middle-legacy'\n\t\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddVerticalAlign,\n\t\t\tup: (props) => {\n\t\t\t\tprops.verticalAlign = 'middle'\n\t\t\t},\n\t\t\tdown: 'retired',\n\t\t},\n\t\t{\n\t\t\tid: Versions.MakeUrlsValid,\n\t\t\tup: (props) => {\n\t\t\t\tif (!T.linkUrl.isValid(props.url)) {\n\t\t\t\t\tprops.url = ''\n\t\t\t\t}\n\t\t\t},\n\t\t\tdown: (_props) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddFontSizeAdjustment,\n\t\t\tup: (props) => {\n\t\t\t\tprops.fontSizeAdjustment = 0\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.fontSizeAdjustment\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddScale,\n\t\t\tup: (props) => {\n\t\t\t\tprops.scale = 1\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.scale\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddLabelColor,\n\t\t\tup: (props) => {\n\t\t\t\tprops.labelColor = 'black'\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.labelColor\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddRichText,\n\t\t\tup: (props) => {\n\t\t\t\tprops.richText = toRichText(props.text)\n\t\t\t\tdelete props.text\n\t\t\t},\n\t\t\t// N.B. Explicitly no down state so that we force clients to update.\n\t\t\t// down: (props) => {\n\t\t\t// \tdelete props.richText\n\t\t\t// },\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddRichTextAttrs,\n\t\t\tup: (_props) => {\n\t\t\t\t// noop - attrs is optional so old records are valid\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\t// Remove attrs from richText when migrating down\n\t\t\t\tif (props.richText && 'attrs' in props.richText) {\n\t\t\t\t\tdelete props.richText.attrs\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: Versions.AddFirstEditedBy,\n\t\t\tup: (props) => {\n\t\t\t\tprops.textFirstEditedBy = null\n\t\t\t},\n\t\t\tdown: (props) => {\n\t\t\t\tdelete props.textFirstEditedBy\n\t\t\t},\n\t\t},\n\t],\n})\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/TLStore.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { computed } from "@tldraw/state";
|
|
1
2
|
import { annotateError, sortByIndex, structuredClone } from "@tldraw/utils";
|
|
2
3
|
import { CameraRecordType } from "./records/TLCamera.mjs";
|
|
3
4
|
import { DocumentRecordType, TLDOCUMENT_ID } from "./records/TLDocument.mjs";
|
|
@@ -15,6 +16,17 @@ function redactRecordForErrorReporting(record) {
|
|
|
15
16
|
}
|
|
16
17
|
}
|
|
17
18
|
}
|
|
19
|
+
function createCachedUserResolve(resolveFn) {
|
|
20
|
+
const cache = /* @__PURE__ */ new Map();
|
|
21
|
+
return (userId) => {
|
|
22
|
+
let signal = cache.get(userId);
|
|
23
|
+
if (!signal) {
|
|
24
|
+
signal = computed("resolve-user-" + userId, () => resolveFn(userId));
|
|
25
|
+
cache.set(userId, signal);
|
|
26
|
+
}
|
|
27
|
+
return signal;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
18
30
|
function onValidationFailure({
|
|
19
31
|
error,
|
|
20
32
|
phase,
|
|
@@ -145,6 +157,7 @@ function createIntegrityChecker(store) {
|
|
|
145
157
|
return ensureStoreIsUsable;
|
|
146
158
|
}
|
|
147
159
|
export {
|
|
160
|
+
createCachedUserResolve,
|
|
148
161
|
createIntegrityChecker,
|
|
149
162
|
onValidationFailure,
|
|
150
163
|
redactRecordForErrorReporting
|
package/dist-esm/TLStore.mjs.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/TLStore.ts"],
|
|
4
|
-
"sourcesContent": ["import { Signal } from '@tldraw/state'\nimport {\n\tSerializedStore,\n\tStore,\n\tStoreSchema,\n\tStoreSnapshot,\n\tStoreValidationFailure,\n} from '@tldraw/store'\nimport { IndexKey, JsonObject, annotateError, sortByIndex, structuredClone } from '@tldraw/utils'\nimport { TLAsset, TLAssetId } from './records/TLAsset'\nimport { CameraRecordType, TLCameraId } from './records/TLCamera'\nimport { DocumentRecordType, TLDOCUMENT_ID } from './records/TLDocument'\nimport { TLINSTANCE_ID } from './records/TLInstance'\nimport { PageRecordType, TLPageId } from './records/TLPage'\nimport { InstancePageStateRecordType, TLInstancePageStateId } from './records/TLPageState'\nimport { PointerRecordType, TLPOINTER_ID } from './records/TLPointer'\nimport { TLRecord } from './records/TLRecord'\n\n/**\n * Redacts the source of an asset record for error reporting.\n *\n * @param record - The asset record to redact\n * @returns The redacted record\n * @internal\n */\nexport function redactRecordForErrorReporting(record: any) {\n\tif (record.typeName === 'asset') {\n\t\tif ('src' in record) {\n\t\t\trecord.src = '<redacted>'\n\t\t}\n\n\t\tif ('src' in record.props) {\n\t\t\trecord.props.src = '<redacted>'\n\t\t}\n\t}\n}\n\n/**\n * The complete schema type for a tldraw store, defining the structure and validation rules\n * for all tldraw records and store properties.\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema } from '@tldraw/tlschema'\n *\n * const schema = createTLSchema()\n * const storeSchema: TLStoreSchema = schema\n * ```\n */\nexport type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps>\n\n/**\n * A serialized representation of a tldraw store that can be persisted or transmitted.\n * Contains all store records in a JSON-serializable format.\n *\n * @public\n * @example\n * ```ts\n * // Serialize a store\n * const serializedStore: TLSerializedStore = store.serialize()\n *\n * // Save to localStorage\n * localStorage.setItem('drawing', JSON.stringify(serializedStore))\n * ```\n */\nexport type TLSerializedStore = SerializedStore<TLRecord>\n\n/**\n * A snapshot of a tldraw store at a specific point in time, containing all records\n * and metadata. Used for persistence, synchronization, and creating store backups.\n *\n * @public\n * @example\n * ```ts\n * // Create a snapshot\n * const snapshot: TLStoreSnapshot = store.getSnapshot()\n *\n * // Restore from snapshot\n * store.loadSnapshot(snapshot)\n * ```\n */\nexport type TLStoreSnapshot = StoreSnapshot<TLRecord>\n\n/**\n * Context information provided when resolving asset URLs, containing details about\n * the current rendering environment and user's connection to optimize asset delivery.\n *\n * @public\n * @example\n * ```ts\n * const assetStore: TLAssetStore = {\n * async resolve(asset, context: TLAssetContext) {\n * // Use low resolution for slow connections\n * if (context.networkEffectiveType === 'slow-2g') {\n * return `${asset.props.src}?quality=low`\n * }\n * // Use high DPI version for retina displays\n * if (context.dpr > 1) {\n * return `${asset.props.src}@2x`\n * }\n * return asset.props.src\n * }\n * }\n * ```\n */\nexport interface TLAssetContext {\n\t/**\n\t * The scale at which the asset is being rendered on-screen relative to its native dimensions.\n\t * If the asset is 1000px wide, but it's been resized/zoom so it takes 500px on-screen, this\n\t * will be 0.5.\n\t *\n\t * The scale measures CSS pixels, not device pixels.\n\t */\n\tscreenScale: number\n\t/** The {@link TLAssetContext.screenScale}, stepped to the nearest power-of-2 multiple. */\n\tsteppedScreenScale: number\n\t/** The device pixel ratio - how many CSS pixels are in one device pixel? */\n\tdpr: number\n\t/**\n\t * An alias for\n\t * {@link https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/effectiveType | `navigator.connection.effectiveType` }\n\t * if it's available in the current browser. Use this to e.g. serve lower-resolution images to\n\t * users on slow connections.\n\t */\n\tnetworkEffectiveType: string | null\n\t/**\n\t * In some circumstances, we need to resolve a URL that points to the original version of a\n\t * particular asset. This is used when the asset will leave the current tldraw instance - e.g.\n\t * for copy/paste, or exports.\n\t */\n\tshouldResolveToOriginal: boolean\n}\n\n/**\n * Interface for storing and managing assets (images, videos, etc.) in tldraw.\n * Provides methods for uploading, resolving, and removing assets from storage.\n *\n * A `TLAssetStore` sits alongside the main {@link TLStore} and is responsible for storing and\n * retrieving large assets such as images. Generally, this should be part of a wider sync system:\n *\n * - By default, the store is in-memory only, so `TLAssetStore` converts images to data URLs\n * - When using\n * {@link @tldraw/editor#TldrawEditorWithoutStoreProps.persistenceKey | `persistenceKey`}, the\n * store is synced to the browser's local IndexedDB, so `TLAssetStore` stores images there too\n * - When using a multiplayer sync server, you would implement `TLAssetStore` to upload images to\n * e.g. an S3 bucket.\n *\n * @public\n * @example\n * ```ts\n * // Simple in-memory asset store\n * const assetStore: TLAssetStore = {\n * async upload(asset, file) {\n * const dataUrl = await fileToDataUrl(file)\n * return { src: dataUrl }\n * },\n *\n * async resolve(asset, context) {\n * return asset.props.src\n * },\n *\n * async remove(assetIds) {\n * // Clean up if needed\n * }\n * }\n * ```\n */\nexport interface TLAssetStore {\n\t/**\n\t * Upload an asset to your storage, returning a URL that can be used to refer to the asset\n\t * long-term.\n\t *\n\t * @param asset - Information & metadata about the asset being uploaded\n\t * @param file - The `File` to be uploaded\n\t * @returns A promise that resolves to the URL of the uploaded asset\n\t */\n\tupload(\n\t\tasset: TLAsset,\n\t\tfile: File,\n\t\tabortSignal?: AbortSignal\n\t): Promise<{ src: string; meta?: JsonObject }>\n\t/**\n\t * Resolve an asset to a URL. This is used when rendering the asset in the editor. By default,\n\t * this will just use `asset.props.src`, the URL returned by `upload()`. This can be used to\n\t * rewrite that URL to add access credentials, or optimized the asset for how it's currently\n\t * being displayed using the {@link TLAssetContext | information provided}.\n\t *\n\t * @param asset - the asset being resolved\n\t * @param ctx - information about the current environment and where the asset is being used\n\t * @returns The URL of the resolved asset, or `null` if the asset is not available\n\t */\n\tresolve?(asset: TLAsset, ctx: TLAssetContext): Promise<string | null> | string | null\n\t/**\n\t * Remove an asset from storage. This is called when the asset is no longer needed, e.g. when\n\t * the user deletes it from the editor.\n\t * @param asset - the asset being removed\n\t * @returns A promise that resolves when the asset has been removed\n\t */\n\tremove?(assetIds: TLAssetId[]): Promise<void>\n}\n\n/**\n * Configuration properties for a tldraw store, defining its behavior and integrations.\n * These props are passed when creating a new store instance.\n *\n * @public\n * @example\n * ```ts\n * const storeProps: TLStoreProps = {\n * defaultName: 'My Drawing',\n * assets: myAssetStore,\n * onMount: (editor) => {\n * console.log('Editor mounted')\n * return () => console.log('Editor unmounted')\n * },\n * collaboration: {\n * status: statusSignal,\n * mode: modeSignal\n * }\n * }\n *\n * const store = new Store({ schema, props: storeProps })\n * ```\n */\nexport interface TLStoreProps {\n\t/** Default name for new documents created in this store */\n\tdefaultName: string\n\t/** Asset store implementation for handling file uploads and storage */\n\tassets: Required<TLAssetStore>\n\t/**\n\t * Called when an {@link @tldraw/editor#Editor} connected to this store is mounted.\n\t * Can optionally return a cleanup function that will be called when unmounted.\n\t *\n\t * @param editor - The editor instance that was mounted\n\t * @returns Optional cleanup function\n\t */\n\tonMount(editor: unknown): void | (() => void)\n\t/** Optional collaboration configuration for multiplayer features */\n\tcollaboration?: {\n\t\t/** Signal indicating online/offline collaboration status */\n\t\tstatus: Signal<'online' | 'offline'> | null\n\t\t/** Signal indicating collaboration mode permissions */\n\t\tmode?: Signal<'readonly' | 'readwrite'> | null\n\t}\n}\n\n/**\n * The main tldraw store type, representing a reactive database of tldraw records\n * with associated store properties. This is the central data structure that holds\n * all shapes, assets, pages, and user state.\n *\n * @public\n * @example\n * ```ts\n * import { Store } from '@tldraw/store'\n * import { createTLSchema } from '@tldraw/tlschema'\n *\n * const schema = createTLSchema()\n * const store: TLStore = new Store({\n * schema,\n * props: {\n * defaultName: 'Untitled',\n * assets: myAssetStore,\n * onMount: () => console.log('Store mounted')\n * }\n * })\n * ```\n */\nexport type TLStore = Store<TLRecord, TLStoreProps>\n\n/**\n * Default validation failure handler for tldraw stores. This function is called\n * when a record fails validation during store operations. It annotates errors\n * with debugging information and determines whether to allow invalid records\n * during store initialization.\n *\n * @param options - The validation failure details\n * - error - The validation error that occurred\n * - phase - The store operation phase when validation failed\n * - record - The invalid record that caused the failure\n * - recordBefore - The previous state of the record (if applicable)\n * @returns The record to use (typically throws the annotated error)\n * @throws The original validation error with additional debugging context\n *\n * @public\n * @example\n * ```ts\n * const store = new Store({\n * schema,\n * props: storeProps,\n * onValidationFailure // Use this as the validation failure handler\n * })\n *\n * // The handler will be called automatically when validation fails\n * try {\n * store.put([invalidRecord])\n * } catch (error) {\n * // Error will contain debugging information added by onValidationFailure\n * }\n * ```\n */\nexport function onValidationFailure({\n\terror,\n\tphase,\n\trecord,\n\trecordBefore,\n}: StoreValidationFailure<TLRecord>): TLRecord {\n\tconst isExistingValidationIssue =\n\t\t// if we're initializing the store for the first time, we should\n\t\t// allow invalid records so people can load old buggy data:\n\t\tphase === 'initialize'\n\n\tannotateError(error, {\n\t\ttags: {\n\t\t\torigin: 'store.validateRecord',\n\t\t\tstorePhase: phase,\n\t\t\tisExistingValidationIssue,\n\t\t},\n\t\textras: {\n\t\t\trecordBefore: recordBefore\n\t\t\t\t? redactRecordForErrorReporting(structuredClone(recordBefore))\n\t\t\t\t: undefined,\n\t\t\trecordAfter: redactRecordForErrorReporting(structuredClone(record)),\n\t\t},\n\t})\n\n\tthrow error\n}\n\nfunction getDefaultPages() {\n\treturn [\n\t\tPageRecordType.create({\n\t\t\tid: 'page:page' as TLPageId,\n\t\t\tname: 'Page 1',\n\t\t\tindex: 'a1' as IndexKey,\n\t\t\tmeta: {},\n\t\t}),\n\t]\n}\n\n/**\n * Creates an integrity checker function that ensures the tldraw store maintains\n * a consistent and usable state. The checker validates that required records exist\n * and relationships between records are maintained.\n *\n * The integrity checker ensures:\n * - Document and pointer records exist\n * - At least one page exists\n * - Instance state references valid pages\n * - Page states and cameras exist for all pages\n * - Shape references in page states are valid\n *\n * @param store - The tldraw store to check for integrity\n * @returns A function that when called, validates and fixes store integrity\n *\n * @internal\n * @example\n * ```ts\n * const checker = createIntegrityChecker(store)\n *\n * // Run integrity check (typically called automatically)\n * checker()\n *\n * // The checker will create missing records and fix invalid references\n * ```\n */\nexport function createIntegrityChecker(store: Store<TLRecord, TLStoreProps>): () => void {\n\tconst $pageIds = store.query.ids('page')\n\tconst $pageStates = store.query.records('instance_page_state')\n\n\tconst ensureStoreIsUsable = (): void => {\n\t\t// make sure we have exactly one document\n\t\tif (!store.has(TLDOCUMENT_ID)) {\n\t\t\tstore.put([DocumentRecordType.create({ id: TLDOCUMENT_ID, name: store.props.defaultName })])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\tif (!store.has(TLPOINTER_ID)) {\n\t\t\tstore.put([PointerRecordType.create({ id: TLPOINTER_ID })])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\t// make sure there is at least one page\n\t\tconst pageIds = $pageIds.get()\n\t\tif (pageIds.size === 0) {\n\t\t\tstore.put(getDefaultPages())\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\tconst getFirstPageId = () => [...pageIds].map((id) => store.get(id)!).sort(sortByIndex)[0].id!\n\n\t\t// make sure we have state for the current user's current tab\n\t\tconst instanceState = store.get(TLINSTANCE_ID)\n\t\tif (!instanceState) {\n\t\t\tstore.put([\n\t\t\t\tstore.schema.types.instance.create({\n\t\t\t\t\tid: TLINSTANCE_ID,\n\t\t\t\t\tcurrentPageId: getFirstPageId(),\n\t\t\t\t\texportBackground: true,\n\t\t\t\t}),\n\t\t\t])\n\n\t\t\treturn ensureStoreIsUsable()\n\t\t} else if (!pageIds.has(instanceState.currentPageId)) {\n\t\t\tstore.put([{ ...instanceState, currentPageId: getFirstPageId() }])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\t// make sure we have page states and cameras for all the pages\n\t\tconst missingPageStateIds = new Set<TLInstancePageStateId>()\n\t\tconst missingCameraIds = new Set<TLCameraId>()\n\t\tfor (const id of pageIds) {\n\t\t\tconst pageStateId = InstancePageStateRecordType.createId(id)\n\t\t\tconst pageState = store.get(pageStateId)\n\t\t\tif (!pageState) {\n\t\t\t\tmissingPageStateIds.add(pageStateId)\n\t\t\t}\n\t\t\tconst cameraId = CameraRecordType.createId(id)\n\t\t\tif (!store.has(cameraId)) {\n\t\t\t\tmissingCameraIds.add(cameraId)\n\t\t\t}\n\t\t}\n\n\t\tif (missingPageStateIds.size > 0) {\n\t\t\tstore.put(\n\t\t\t\t[...missingPageStateIds].map((id) =>\n\t\t\t\t\tInstancePageStateRecordType.create({\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tpageId: InstancePageStateRecordType.parseId(id) as TLPageId,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t)\n\t\t}\n\n\t\tif (missingCameraIds.size > 0) {\n\t\t\tstore.put([...missingCameraIds].map((id) => CameraRecordType.create({ id })))\n\t\t}\n\n\t\tconst pageStates = $pageStates.get()\n\t\tfor (const pageState of pageStates) {\n\t\t\tif (!pageIds.has(pageState.pageId)) {\n\t\t\t\tstore.remove([pageState.id])\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (pageState.croppingShapeId && !store.has(pageState.croppingShapeId)) {\n\t\t\t\tstore.put([{ ...pageState, croppingShapeId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tif (pageState.focusedGroupId && !store.has(pageState.focusedGroupId)) {\n\t\t\t\tstore.put([{ ...pageState, focusedGroupId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tif (pageState.hoveredShapeId && !store.has(pageState.hoveredShapeId)) {\n\t\t\t\tstore.put([{ ...pageState, hoveredShapeId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredSelectedIds = pageState.selectedShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredSelectedIds.length !== pageState.selectedShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, selectedShapeIds: filteredSelectedIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredHintingIds = pageState.hintingShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredHintingIds.length !== pageState.hintingShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, hintingShapeIds: filteredHintingIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredErasingIds = pageState.erasingShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredErasingIds.length !== pageState.erasingShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, erasingShapeIds: filteredErasingIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ensureStoreIsUsable\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import { Signal, computed } from '@tldraw/state'\nimport {\n\tSerializedStore,\n\tStore,\n\tStoreSchema,\n\tStoreSnapshot,\n\tStoreValidationFailure,\n} from '@tldraw/store'\nimport { IndexKey, JsonObject, annotateError, sortByIndex, structuredClone } from '@tldraw/utils'\nimport { TLAsset, TLAssetId } from './records/TLAsset'\nimport { CameraRecordType, TLCameraId } from './records/TLCamera'\nimport { DocumentRecordType, TLDOCUMENT_ID } from './records/TLDocument'\nimport { TLINSTANCE_ID } from './records/TLInstance'\nimport { PageRecordType, TLPageId } from './records/TLPage'\nimport { InstancePageStateRecordType, TLInstancePageStateId } from './records/TLPageState'\nimport { PointerRecordType, TLPOINTER_ID } from './records/TLPointer'\nimport { TLRecord } from './records/TLRecord'\nimport { TLUser } from './records/TLUser'\n\n/**\n * Redacts the source of an asset record for error reporting.\n *\n * @param record - The asset record to redact\n * @returns The redacted record\n * @internal\n */\nexport function redactRecordForErrorReporting(record: any) {\n\tif (record.typeName === 'asset') {\n\t\tif ('src' in record) {\n\t\t\trecord.src = '<redacted>'\n\t\t}\n\n\t\tif ('src' in record.props) {\n\t\t\trecord.props.src = '<redacted>'\n\t\t}\n\t}\n}\n\n/**\n * The complete schema type for a tldraw store, defining the structure and validation rules\n * for all tldraw records and store properties.\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema } from '@tldraw/tlschema'\n *\n * const schema = createTLSchema()\n * const storeSchema: TLStoreSchema = schema\n * ```\n */\nexport type TLStoreSchema = StoreSchema<TLRecord, TLStoreProps>\n\n/**\n * A serialized representation of a tldraw store that can be persisted or transmitted.\n * Contains all store records in a JSON-serializable format.\n *\n * @public\n * @example\n * ```ts\n * // Serialize a store\n * const serializedStore: TLSerializedStore = store.serialize()\n *\n * // Save to localStorage\n * localStorage.setItem('drawing', JSON.stringify(serializedStore))\n * ```\n */\nexport type TLSerializedStore = SerializedStore<TLRecord>\n\n/**\n * A snapshot of a tldraw store at a specific point in time, containing all records\n * and metadata. Used for persistence, synchronization, and creating store backups.\n *\n * @public\n * @example\n * ```ts\n * // Create a snapshot\n * const snapshot: TLStoreSnapshot = store.getSnapshot()\n *\n * // Restore from snapshot\n * store.loadSnapshot(snapshot)\n * ```\n */\nexport type TLStoreSnapshot = StoreSnapshot<TLRecord>\n\n/**\n * Context information provided when resolving asset URLs, containing details about\n * the current rendering environment and user's connection to optimize asset delivery.\n *\n * @public\n * @example\n * ```ts\n * const assetStore: TLAssetStore = {\n * async resolve(asset, context: TLAssetContext) {\n * // Use low resolution for slow connections\n * if (context.networkEffectiveType === 'slow-2g') {\n * return `${asset.props.src}?quality=low`\n * }\n * // Use high DPI version for retina displays\n * if (context.dpr > 1) {\n * return `${asset.props.src}@2x`\n * }\n * return asset.props.src\n * }\n * }\n * ```\n */\nexport interface TLAssetContext {\n\t/**\n\t * The scale at which the asset is being rendered on-screen relative to its native dimensions.\n\t * If the asset is 1000px wide, but it's been resized/zoom so it takes 500px on-screen, this\n\t * will be 0.5.\n\t *\n\t * The scale measures CSS pixels, not device pixels.\n\t */\n\tscreenScale: number\n\t/** The {@link TLAssetContext.screenScale}, stepped to the nearest power-of-2 multiple. */\n\tsteppedScreenScale: number\n\t/** The device pixel ratio - how many CSS pixels are in one device pixel? */\n\tdpr: number\n\t/**\n\t * An alias for\n\t * {@link https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/effectiveType | `navigator.connection.effectiveType` }\n\t * if it's available in the current browser. Use this to e.g. serve lower-resolution images to\n\t * users on slow connections.\n\t */\n\tnetworkEffectiveType: string | null\n\t/**\n\t * In some circumstances, we need to resolve a URL that points to the original version of a\n\t * particular asset. This is used when the asset will leave the current tldraw instance - e.g.\n\t * for copy/paste, or exports.\n\t */\n\tshouldResolveToOriginal: boolean\n}\n\n/**\n * Interface for storing and managing assets (images, videos, etc.) in tldraw.\n * Provides methods for uploading, resolving, and removing assets from storage.\n *\n * A `TLAssetStore` sits alongside the main {@link TLStore} and is responsible for storing and\n * retrieving large assets such as images. Generally, this should be part of a wider sync system:\n *\n * - By default, the store is in-memory only, so `TLAssetStore` converts images to data URLs\n * - When using\n * {@link @tldraw/editor#TldrawEditorWithoutStoreProps.persistenceKey | `persistenceKey`}, the\n * store is synced to the browser's local IndexedDB, so `TLAssetStore` stores images there too\n * - When using a multiplayer sync server, you would implement `TLAssetStore` to upload images to\n * e.g. an S3 bucket.\n *\n * @public\n * @example\n * ```ts\n * // Simple in-memory asset store\n * const assetStore: TLAssetStore = {\n * async upload(asset, file) {\n * const dataUrl = await fileToDataUrl(file)\n * return { src: dataUrl }\n * },\n *\n * async resolve(asset, context) {\n * return asset.props.src\n * },\n *\n * async remove(assetIds) {\n * // Clean up if needed\n * }\n * }\n * ```\n */\nexport interface TLAssetStore {\n\t/**\n\t * Upload an asset to your storage, returning a URL that can be used to refer to the asset\n\t * long-term.\n\t *\n\t * @param asset - Information & metadata about the asset being uploaded\n\t * @param file - The `File` to be uploaded\n\t * @returns A promise that resolves to the URL of the uploaded asset\n\t */\n\tupload(\n\t\tasset: TLAsset,\n\t\tfile: File,\n\t\tabortSignal?: AbortSignal\n\t): Promise<{ src: string; meta?: JsonObject }>\n\t/**\n\t * Resolve an asset to a URL. This is used when rendering the asset in the editor. By default,\n\t * this will just use `asset.props.src`, the URL returned by `upload()`. This can be used to\n\t * rewrite that URL to add access credentials, or optimized the asset for how it's currently\n\t * being displayed using the {@link TLAssetContext | information provided}.\n\t *\n\t * @param asset - the asset being resolved\n\t * @param ctx - information about the current environment and where the asset is being used\n\t * @returns The URL of the resolved asset, or `null` if the asset is not available\n\t */\n\tresolve?(asset: TLAsset, ctx: TLAssetContext): Promise<string | null> | string | null\n\t/**\n\t * Remove an asset from storage. This is called when the asset is no longer needed, e.g. when\n\t * the user deletes it from the editor.\n\t * @param asset - the asset being removed\n\t * @returns A promise that resolves when the asset has been removed\n\t */\n\tremove?(assetIds: TLAssetId[]): Promise<void>\n}\n\n/**\n * Interface for resolving user information in tldraw.\n *\n * A `TLUserStore` sits alongside the main {@link TLStore} and provides user\n * resolution for attribution labels and display names. Implement this interface\n * to connect tldraw to your auth/user system.\n *\n * `currentUser` and `resolve` are reactive {@link @tldraw/state#Signal | Signals}\n * so that the editor can automatically track changes to user data and\n * re-render when a user's name, color, or avatar updates.\n *\n * Implementations should cache signals returned by `resolve` \u2014 e.g. return the\n * same `Signal` for repeated calls with the same `userId` \u2014 to avoid\n * unnecessary re-computation.\n *\n * @public\n * @example\n * ```ts\n * const currentUser = computed('currentUser', () =>\n * UserRecordType.create({\n * id: createUserId(myAuth.userId),\n * name: myAuth.displayName,\n * color: myAuth.color,\n * })\n * )\n *\n * const userStore: TLUserStore = {\n * currentUser,\n * resolve(userId) {\n * return computed('resolve-' + userId, () =>\n * myUserCache.get(userId) ?? null\n * )\n * },\n * }\n * ```\n */\nexport interface TLUserStore {\n\t/**\n\t * A signal resolving to the currently authenticated user,\n\t * or `null` for anonymous / unknown.\n\t * Read when stamping attribution on shape create/update.\n\t */\n\tcurrentUser: Signal<TLUser | null>\n\n\t/**\n\t * Return a signal resolving an arbitrary user ID to display info.\n\t * Called when rendering attribution labels for shapes that may have been\n\t * created or edited by someone else.\n\t * The signal's value should be `null` if the user cannot be resolved.\n\t */\n\tresolve?(userId: string): Signal<TLUser | null>\n}\n\n/**\n * Create a cached {@link TLUserStore.resolve} implementation.\n *\n * Wraps a reactive lookup function so that each `userId` gets a single\n * stable {@link @tldraw/state#Signal | Signal} that is reused across calls.\n * The `resolveFn` is evaluated inside a `computed`, so any `.get()` calls\n * it makes are automatically tracked.\n *\n * @param resolveFn - A function that resolves a raw user-ID string to a\n * {@link TLUser} or `null`. Called reactively inside a `computed`.\n * @returns A function suitable for use as `TLUserStore.resolve`.\n *\n * @example\n * ```ts\n * const users: TLUserStore = {\n * currentUser: currentUserSignal,\n * resolve: createCachedUserResolve(\n * (userId) => usersAtom.get()[createUserId(userId)] ?? null\n * ),\n * }\n * ```\n *\n * @public\n */\nexport function createCachedUserResolve(\n\tresolveFn: (userId: string) => TLUser | null\n): (userId: string) => Signal<TLUser | null> {\n\tconst cache = new Map<string, Signal<TLUser | null>>()\n\treturn (userId: string) => {\n\t\tlet signal = cache.get(userId)\n\t\tif (!signal) {\n\t\t\tsignal = computed('resolve-user-' + userId, () => resolveFn(userId))\n\t\t\tcache.set(userId, signal)\n\t\t}\n\t\treturn signal\n\t}\n}\n\n/**\n * Configuration properties for a tldraw store, defining its behavior and integrations.\n * These props are passed when creating a new store instance.\n *\n * @public\n * @example\n * ```ts\n * const storeProps: TLStoreProps = {\n * defaultName: 'My Drawing',\n * assets: myAssetStore,\n * onMount: (editor) => {\n * console.log('Editor mounted')\n * return () => console.log('Editor unmounted')\n * },\n * collaboration: {\n * status: statusSignal,\n * mode: modeSignal\n * }\n * }\n *\n * const store = new Store({ schema, props: storeProps })\n * ```\n */\nexport interface TLStoreProps {\n\t/** Default name for new documents created in this store */\n\tdefaultName: string\n\t/** Asset store implementation for handling file uploads and storage */\n\tassets: Required<TLAssetStore>\n\t/** User store implementation for user resolution and attribution */\n\tusers: Required<TLUserStore>\n\t/**\n\t * Called when an {@link @tldraw/editor#Editor} connected to this store is mounted.\n\t * Can optionally return a cleanup function that will be called when unmounted.\n\t *\n\t * @param editor - The editor instance that was mounted\n\t * @returns Optional cleanup function\n\t */\n\tonMount(editor: unknown): void | (() => void)\n\t/** Optional collaboration configuration for multiplayer features */\n\tcollaboration?: {\n\t\t/** Signal indicating online/offline collaboration status */\n\t\tstatus: Signal<'online' | 'offline'> | null\n\t\t/** Signal indicating collaboration mode permissions */\n\t\tmode?: Signal<'readonly' | 'readwrite'> | null\n\t}\n}\n\n/**\n * The main tldraw store type, representing a reactive database of tldraw records\n * with associated store properties. This is the central data structure that holds\n * all shapes, assets, pages, and user state.\n *\n * @public\n * @example\n * ```ts\n * import { Store } from '@tldraw/store'\n * import { createTLSchema } from '@tldraw/tlschema'\n *\n * const schema = createTLSchema()\n * const store: TLStore = new Store({\n * schema,\n * props: {\n * defaultName: 'Untitled',\n * assets: myAssetStore,\n * onMount: () => console.log('Store mounted')\n * }\n * })\n * ```\n */\nexport type TLStore = Store<TLRecord, TLStoreProps>\n\n/**\n * Default validation failure handler for tldraw stores. This function is called\n * when a record fails validation during store operations. It annotates errors\n * with debugging information and determines whether to allow invalid records\n * during store initialization.\n *\n * @param options - The validation failure details\n * - error - The validation error that occurred\n * - phase - The store operation phase when validation failed\n * - record - The invalid record that caused the failure\n * - recordBefore - The previous state of the record (if applicable)\n * @returns The record to use (typically throws the annotated error)\n * @throws The original validation error with additional debugging context\n *\n * @public\n * @example\n * ```ts\n * const store = new Store({\n * schema,\n * props: storeProps,\n * onValidationFailure // Use this as the validation failure handler\n * })\n *\n * // The handler will be called automatically when validation fails\n * try {\n * store.put([invalidRecord])\n * } catch (error) {\n * // Error will contain debugging information added by onValidationFailure\n * }\n * ```\n */\nexport function onValidationFailure({\n\terror,\n\tphase,\n\trecord,\n\trecordBefore,\n}: StoreValidationFailure<TLRecord>): TLRecord {\n\tconst isExistingValidationIssue =\n\t\t// if we're initializing the store for the first time, we should\n\t\t// allow invalid records so people can load old buggy data:\n\t\tphase === 'initialize'\n\n\tannotateError(error, {\n\t\ttags: {\n\t\t\torigin: 'store.validateRecord',\n\t\t\tstorePhase: phase,\n\t\t\tisExistingValidationIssue,\n\t\t},\n\t\textras: {\n\t\t\trecordBefore: recordBefore\n\t\t\t\t? redactRecordForErrorReporting(structuredClone(recordBefore))\n\t\t\t\t: undefined,\n\t\t\trecordAfter: redactRecordForErrorReporting(structuredClone(record)),\n\t\t},\n\t})\n\n\tthrow error\n}\n\nfunction getDefaultPages() {\n\treturn [\n\t\tPageRecordType.create({\n\t\t\tid: 'page:page' as TLPageId,\n\t\t\tname: 'Page 1',\n\t\t\tindex: 'a1' as IndexKey,\n\t\t\tmeta: {},\n\t\t}),\n\t]\n}\n\n/**\n * Creates an integrity checker function that ensures the tldraw store maintains\n * a consistent and usable state. The checker validates that required records exist\n * and relationships between records are maintained.\n *\n * The integrity checker ensures:\n * - Document and pointer records exist\n * - At least one page exists\n * - Instance state references valid pages\n * - Page states and cameras exist for all pages\n * - Shape references in page states are valid\n *\n * @param store - The tldraw store to check for integrity\n * @returns A function that when called, validates and fixes store integrity\n *\n * @internal\n * @example\n * ```ts\n * const checker = createIntegrityChecker(store)\n *\n * // Run integrity check (typically called automatically)\n * checker()\n *\n * // The checker will create missing records and fix invalid references\n * ```\n */\nexport function createIntegrityChecker(store: Store<TLRecord, TLStoreProps>): () => void {\n\tconst $pageIds = store.query.ids('page')\n\tconst $pageStates = store.query.records('instance_page_state')\n\n\tconst ensureStoreIsUsable = (): void => {\n\t\t// make sure we have exactly one document\n\t\tif (!store.has(TLDOCUMENT_ID)) {\n\t\t\tstore.put([DocumentRecordType.create({ id: TLDOCUMENT_ID, name: store.props.defaultName })])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\tif (!store.has(TLPOINTER_ID)) {\n\t\t\tstore.put([PointerRecordType.create({ id: TLPOINTER_ID })])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\t// make sure there is at least one page\n\t\tconst pageIds = $pageIds.get()\n\t\tif (pageIds.size === 0) {\n\t\t\tstore.put(getDefaultPages())\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\tconst getFirstPageId = () => [...pageIds].map((id) => store.get(id)!).sort(sortByIndex)[0].id!\n\n\t\t// make sure we have state for the current user's current tab\n\t\tconst instanceState = store.get(TLINSTANCE_ID)\n\t\tif (!instanceState) {\n\t\t\tstore.put([\n\t\t\t\tstore.schema.types.instance.create({\n\t\t\t\t\tid: TLINSTANCE_ID,\n\t\t\t\t\tcurrentPageId: getFirstPageId(),\n\t\t\t\t\texportBackground: true,\n\t\t\t\t}),\n\t\t\t])\n\n\t\t\treturn ensureStoreIsUsable()\n\t\t} else if (!pageIds.has(instanceState.currentPageId)) {\n\t\t\tstore.put([{ ...instanceState, currentPageId: getFirstPageId() }])\n\t\t\treturn ensureStoreIsUsable()\n\t\t}\n\n\t\t// make sure we have page states and cameras for all the pages\n\t\tconst missingPageStateIds = new Set<TLInstancePageStateId>()\n\t\tconst missingCameraIds = new Set<TLCameraId>()\n\t\tfor (const id of pageIds) {\n\t\t\tconst pageStateId = InstancePageStateRecordType.createId(id)\n\t\t\tconst pageState = store.get(pageStateId)\n\t\t\tif (!pageState) {\n\t\t\t\tmissingPageStateIds.add(pageStateId)\n\t\t\t}\n\t\t\tconst cameraId = CameraRecordType.createId(id)\n\t\t\tif (!store.has(cameraId)) {\n\t\t\t\tmissingCameraIds.add(cameraId)\n\t\t\t}\n\t\t}\n\n\t\tif (missingPageStateIds.size > 0) {\n\t\t\tstore.put(\n\t\t\t\t[...missingPageStateIds].map((id) =>\n\t\t\t\t\tInstancePageStateRecordType.create({\n\t\t\t\t\t\tid,\n\t\t\t\t\t\tpageId: InstancePageStateRecordType.parseId(id) as TLPageId,\n\t\t\t\t\t})\n\t\t\t\t)\n\t\t\t)\n\t\t}\n\n\t\tif (missingCameraIds.size > 0) {\n\t\t\tstore.put([...missingCameraIds].map((id) => CameraRecordType.create({ id })))\n\t\t}\n\n\t\tconst pageStates = $pageStates.get()\n\t\tfor (const pageState of pageStates) {\n\t\t\tif (!pageIds.has(pageState.pageId)) {\n\t\t\t\tstore.remove([pageState.id])\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif (pageState.croppingShapeId && !store.has(pageState.croppingShapeId)) {\n\t\t\t\tstore.put([{ ...pageState, croppingShapeId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tif (pageState.focusedGroupId && !store.has(pageState.focusedGroupId)) {\n\t\t\t\tstore.put([{ ...pageState, focusedGroupId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tif (pageState.hoveredShapeId && !store.has(pageState.hoveredShapeId)) {\n\t\t\t\tstore.put([{ ...pageState, hoveredShapeId: null }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredSelectedIds = pageState.selectedShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredSelectedIds.length !== pageState.selectedShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, selectedShapeIds: filteredSelectedIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredHintingIds = pageState.hintingShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredHintingIds.length !== pageState.hintingShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, hintingShapeIds: filteredHintingIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t\tconst filteredErasingIds = pageState.erasingShapeIds.filter((id) => store.has(id))\n\t\t\tif (filteredErasingIds.length !== pageState.erasingShapeIds.length) {\n\t\t\t\tstore.put([{ ...pageState, erasingShapeIds: filteredErasingIds }])\n\t\t\t\treturn ensureStoreIsUsable()\n\t\t\t}\n\t\t}\n\t}\n\n\treturn ensureStoreIsUsable\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,12 +4,14 @@ import { TLINSTANCE_ID } from "./records/TLInstance.mjs";
|
|
|
4
4
|
import { InstancePageStateRecordType } from "./records/TLPageState.mjs";
|
|
5
5
|
import { TLPOINTER_ID } from "./records/TLPointer.mjs";
|
|
6
6
|
import { InstancePresenceRecordType } from "./records/TLPresence.mjs";
|
|
7
|
-
function createPresenceStateDerivation($user,
|
|
7
|
+
function createPresenceStateDerivation($user, opts) {
|
|
8
|
+
const { instanceId, getUserPresence: _getUserPresence } = opts ?? {};
|
|
9
|
+
const getUserPresence = _getUserPresence ?? getDefaultUserPresence;
|
|
8
10
|
return (store) => {
|
|
9
11
|
return computed("instancePresence", () => {
|
|
10
12
|
const user = $user.get();
|
|
11
13
|
if (!user) return null;
|
|
12
|
-
const state =
|
|
14
|
+
const state = getUserPresence(store, user);
|
|
13
15
|
if (!state) return null;
|
|
14
16
|
return InstancePresenceRecordType.create({
|
|
15
17
|
...state,
|
|
@@ -31,14 +33,14 @@ function getDefaultUserPresence(store, user) {
|
|
|
31
33
|
brush: instance.brush,
|
|
32
34
|
scribbles: instance.scribbles,
|
|
33
35
|
userId: user.id,
|
|
34
|
-
userName: user.name
|
|
36
|
+
userName: user.name,
|
|
35
37
|
followingUserId: instance.followingUserId,
|
|
36
38
|
camera: {
|
|
37
39
|
x: camera.x,
|
|
38
40
|
y: camera.y,
|
|
39
41
|
z: camera.z
|
|
40
42
|
},
|
|
41
|
-
color: user.color
|
|
43
|
+
color: user.color || "#FF0000",
|
|
42
44
|
currentPageId: instance.currentPageId,
|
|
43
45
|
cursor: {
|
|
44
46
|
x: pointer.x,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/createPresenceStateDerivation.ts"],
|
|
4
|
-
"sourcesContent": ["import { Signal, computed } from '@tldraw/state'\nimport { CameraRecordType } from './records/TLCamera'\nimport { TLINSTANCE_ID } from './records/TLInstance'\nimport { InstancePageStateRecordType } from './records/TLPageState'\nimport { TLPOINTER_ID } from './records/TLPointer'\nimport { InstancePresenceRecordType, TLInstancePresence } from './records/TLPresence'\nimport {
|
|
5
|
-
"mappings": "AAAA,SAAiB,gBAAgB;AACjC,SAAS,wBAAwB;AACjC,SAAS,qBAAqB;AAC9B,SAAS,mCAAmC;AAC5C,SAAS,oBAAoB;AAC7B,SAAS,kCAAsD;
|
|
4
|
+
"sourcesContent": ["import { Signal, computed } from '@tldraw/state'\nimport { CameraRecordType } from './records/TLCamera'\nimport { TLINSTANCE_ID } from './records/TLInstance'\nimport { InstancePageStateRecordType } from './records/TLPageState'\nimport { TLPOINTER_ID } from './records/TLPointer'\nimport { InstancePresenceRecordType, TLInstancePresence } from './records/TLPresence'\nimport { TLUser } from './records/TLUser'\nimport { TLStore } from './TLStore'\n\n/** @public */\nexport interface CreatePresenceStateDerivationOpts {\n\t/** Custom instance ID. If not provided, one is generated from the store ID. */\n\tinstanceId?: TLInstancePresence['id']\n\t/**\n\t * Override how presence state is built from the store and current user.\n\t * Defaults to {@link getDefaultUserPresence}.\n\t */\n\tgetUserPresence?(store: TLStore, user: TLUser): TLPresenceStateInfo | null\n}\n\n/**\n * Creates a derivation that represents the current presence state of the current user.\n *\n * This function returns a derivation factory that, when given a store, creates a computed signal\n * containing the user's current presence state. The presence state includes information like cursor\n * position, selected shapes, camera position, and user metadata that gets synchronized in\n * multiplayer scenarios.\n *\n * @param $user - A reactive signal containing the user information, or `null` when anonymous\n * @param opts - Optional configuration for instance ID and presence derivation\n * @returns A function that takes a store and returns a computed signal of the user's presence state\n *\n * @example\n * ```ts\n * import { createPresenceStateDerivation } from '@tldraw/tlschema'\n * import { atom } from '@tldraw/state'\n *\n * const userSignal = atom('user', { id: 'user-123', name: 'Alice', color: '#ff0000', meta: {} })\n * const presenceDerivation = createPresenceStateDerivation(userSignal)\n *\n * // Use with a store to get reactive presence state\n * const presenceState = presenceDerivation(store)\n * console.log(presenceState.get()) // Current user presence or null\n * ```\n *\n * @public\n */\nexport function createPresenceStateDerivation(\n\t$user: Signal<TLUser | null>,\n\topts?: CreatePresenceStateDerivationOpts\n) {\n\tconst { instanceId, getUserPresence: _getUserPresence } = opts ?? {}\n\tconst getUserPresence = _getUserPresence ?? getDefaultUserPresence\n\treturn (store: TLStore): Signal<TLInstancePresence | null> => {\n\t\treturn computed('instancePresence', () => {\n\t\t\tconst user = $user.get()\n\t\t\tif (!user) return null\n\n\t\t\tconst state = getUserPresence(store, user)\n\t\t\tif (!state) return null\n\n\t\t\treturn InstancePresenceRecordType.create({\n\t\t\t\t...state,\n\t\t\t\tid: instanceId ?? InstancePresenceRecordType.createId(store.id),\n\t\t\t})\n\t\t})\n\t}\n}\n\n/**\n * The shape of data used to create a presence record.\n *\n * This type represents all the properties needed to construct a TLInstancePresence record.\n * It includes user information, cursor state, camera position, selected shapes, and other\n * presence-related data that gets synchronized across multiplayer clients.\n *\n * @public\n */\nexport type TLPresenceStateInfo = Parameters<(typeof InstancePresenceRecordType)['create']>[0]\n\n/**\n * Creates default presence state information for a user based on the current store state.\n *\n * This function extracts the current state from various store records (instance, page state,\n * camera, pointer) and combines them with user information to create a complete presence\n * state object. This is commonly used as a starting point for custom presence implementations.\n *\n * @param store - The tldraw store containing the current editor state\n * @param user - The user information to include in the presence state\n * @returns The default presence state info, or null if required store records are missing\n *\n * @example\n * ```ts\n * import { getDefaultUserPresence } from '@tldraw/tlschema'\n *\n * const user = { id: 'user-123', name: 'Alice', color: '#ff0000', meta: {} }\n * const presenceInfo = getDefaultUserPresence(store, user)\n *\n * if (presenceInfo) {\n * console.log('Current cursor:', presenceInfo.cursor)\n * console.log('Selected shapes:', presenceInfo.selectedShapeIds)\n * console.log('Camera position:', presenceInfo.camera)\n * }\n * ```\n *\n * @example\n * ```ts\n * // Common pattern: customize default presence\n * const customPresence = {\n * ...getDefaultUserPresence(store, user),\n * // Remove camera for privacy\n * camera: undefined,\n * // Add custom metadata\n * customField: 'my-data'\n * }\n * ```\n *\n * @public\n */\nexport function getDefaultUserPresence(store: TLStore, user: TLUser) {\n\tconst instance = store.get(TLINSTANCE_ID)\n\tconst pageState = store.get(InstancePageStateRecordType.createId(instance?.currentPageId))\n\tconst camera = store.get(CameraRecordType.createId(instance?.currentPageId))\n\tconst pointer = store.get(TLPOINTER_ID)\n\tif (!pageState || !instance || !camera || !pointer) {\n\t\treturn null\n\t}\n\n\treturn {\n\t\tselectedShapeIds: pageState.selectedShapeIds,\n\t\tbrush: instance.brush,\n\t\tscribbles: instance.scribbles,\n\t\tuserId: user.id,\n\t\tuserName: user.name,\n\t\tfollowingUserId: instance.followingUserId,\n\t\tcamera: {\n\t\t\tx: camera.x,\n\t\t\ty: camera.y,\n\t\t\tz: camera.z,\n\t\t},\n\t\tcolor: user.color || '#FF0000',\n\t\tcurrentPageId: instance.currentPageId,\n\t\tcursor: {\n\t\t\tx: pointer.x,\n\t\t\ty: pointer.y,\n\t\t\trotation: instance.cursor.rotation,\n\t\t\ttype: instance.cursor.type,\n\t\t},\n\t\tlastActivityTimestamp: pointer.lastActivityTimestamp,\n\t\tscreenBounds: instance.screenBounds,\n\t\tchatMessage: instance.chatMessage,\n\t\tmeta: {},\n\t} satisfies TLPresenceStateInfo\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAiB,gBAAgB;AACjC,SAAS,wBAAwB;AACjC,SAAS,qBAAqB;AAC9B,SAAS,mCAAmC;AAC5C,SAAS,oBAAoB;AAC7B,SAAS,kCAAsD;AA0CxD,SAAS,8BACf,OACA,MACC;AACD,QAAM,EAAE,YAAY,iBAAiB,iBAAiB,IAAI,QAAQ,CAAC;AACnE,QAAM,kBAAkB,oBAAoB;AAC5C,SAAO,CAAC,UAAsD;AAC7D,WAAO,SAAS,oBAAoB,MAAM;AACzC,YAAM,OAAO,MAAM,IAAI;AACvB,UAAI,CAAC,KAAM,QAAO;AAElB,YAAM,QAAQ,gBAAgB,OAAO,IAAI;AACzC,UAAI,CAAC,MAAO,QAAO;AAEnB,aAAO,2BAA2B,OAAO;AAAA,QACxC,GAAG;AAAA,QACH,IAAI,cAAc,2BAA2B,SAAS,MAAM,EAAE;AAAA,MAC/D,CAAC;AAAA,IACF,CAAC;AAAA,EACF;AACD;AAoDO,SAAS,uBAAuB,OAAgB,MAAc;AACpE,QAAM,WAAW,MAAM,IAAI,aAAa;AACxC,QAAM,YAAY,MAAM,IAAI,4BAA4B,SAAS,UAAU,aAAa,CAAC;AACzF,QAAM,SAAS,MAAM,IAAI,iBAAiB,SAAS,UAAU,aAAa,CAAC;AAC3E,QAAM,UAAU,MAAM,IAAI,YAAY;AACtC,MAAI,CAAC,aAAa,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS;AACnD,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN,kBAAkB,UAAU;AAAA,IAC5B,OAAO,SAAS;AAAA,IAChB,WAAW,SAAS;AAAA,IACpB,QAAQ,KAAK;AAAA,IACb,UAAU,KAAK;AAAA,IACf,iBAAiB,SAAS;AAAA,IAC1B,QAAQ;AAAA,MACP,GAAG,OAAO;AAAA,MACV,GAAG,OAAO;AAAA,MACV,GAAG,OAAO;AAAA,IACX;AAAA,IACA,OAAO,KAAK,SAAS;AAAA,IACrB,eAAe,SAAS;AAAA,IACxB,QAAQ;AAAA,MACP,GAAG,QAAQ;AAAA,MACX,GAAG,QAAQ;AAAA,MACX,UAAU,SAAS,OAAO;AAAA,MAC1B,MAAM,SAAS,OAAO;AAAA,IACvB;AAAA,IACA,uBAAuB,QAAQ;AAAA,IAC/B,cAAc,SAAS;AAAA,IACvB,aAAa,SAAS;AAAA,IACtB,MAAM,CAAC;AAAA,EACR;AACD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
getShapePropKeysByStyle,
|
|
23
23
|
rootShapeMigrations
|
|
24
24
|
} from "./records/TLShape.mjs";
|
|
25
|
+
import { UserRecordType, createUserRecordType, userMigrations } from "./records/TLUser.mjs";
|
|
25
26
|
import { processPropsMigrations } from "./recordsWithProps.mjs";
|
|
26
27
|
import { arrowShapeMigrations, arrowShapeProps } from "./shapes/TLArrowShape.mjs";
|
|
27
28
|
import { bookmarkShapeMigrations, bookmarkShapeProps } from "./shapes/TLBookmarkShape.mjs";
|
|
@@ -59,6 +60,7 @@ const defaultBindingSchemas = {
|
|
|
59
60
|
function createTLSchema({
|
|
60
61
|
shapes = defaultShapeSchemas,
|
|
61
62
|
bindings = defaultBindingSchemas,
|
|
63
|
+
user,
|
|
62
64
|
records = {},
|
|
63
65
|
migrations
|
|
64
66
|
} = {}) {
|
|
@@ -74,6 +76,7 @@ function createTLSchema({
|
|
|
74
76
|
const ShapeRecordType = createShapeRecordType(shapes);
|
|
75
77
|
const BindingRecordType = createBindingRecordType(bindings);
|
|
76
78
|
const InstanceRecordType = createInstanceRecordType(stylesById);
|
|
79
|
+
const CustomUserRecordType = user ? createUserRecordType(user) : UserRecordType;
|
|
77
80
|
const builtInTypeNames = /* @__PURE__ */ new Set([
|
|
78
81
|
"asset",
|
|
79
82
|
"binding",
|
|
@@ -85,7 +88,8 @@ function createTLSchema({
|
|
|
85
88
|
"instance_presence",
|
|
86
89
|
"pointer",
|
|
87
90
|
"shape",
|
|
88
|
-
"store"
|
|
91
|
+
"store",
|
|
92
|
+
"user"
|
|
89
93
|
]);
|
|
90
94
|
const customRecordTypes = {};
|
|
91
95
|
for (const [typeName, config] of Object.entries(records)) {
|
|
@@ -108,6 +112,7 @@ function createTLSchema({
|
|
|
108
112
|
instance_presence: InstancePresenceRecordType,
|
|
109
113
|
pointer: PointerRecordType,
|
|
110
114
|
shape: ShapeRecordType,
|
|
115
|
+
user: CustomUserRecordType,
|
|
111
116
|
...customRecordTypes
|
|
112
117
|
},
|
|
113
118
|
{
|
|
@@ -122,12 +127,14 @@ function createTLSchema({
|
|
|
122
127
|
instancePresenceMigrations,
|
|
123
128
|
pointerMigrations,
|
|
124
129
|
rootShapeMigrations,
|
|
130
|
+
userMigrations,
|
|
125
131
|
bookmarkAssetMigrations,
|
|
126
132
|
imageAssetMigrations,
|
|
127
133
|
videoAssetMigrations,
|
|
128
134
|
...processPropsMigrations("shape", shapes),
|
|
129
135
|
...processPropsMigrations("binding", bindings),
|
|
130
136
|
...processCustomRecordMigrations(records),
|
|
137
|
+
...(user?.migrations ?? []),
|
|
131
138
|
...(migrations ?? [])
|
|
132
139
|
],
|
|
133
140
|
onValidationFailure,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/createTLSchema.ts"],
|
|
4
|
-
"sourcesContent": ["import { LegacyMigrations, MigrationSequence, StoreSchema, StoreValidator } from '@tldraw/store'\nimport { objectMapValues } from '@tldraw/utils'\nimport { bookmarkAssetMigrations } from './assets/TLBookmarkAsset'\nimport { imageAssetMigrations } from './assets/TLImageAsset'\nimport { videoAssetMigrations } from './assets/TLVideoAsset'\nimport { arrowBindingMigrations, arrowBindingProps } from './bindings/TLArrowBinding'\nimport { AssetRecordType, assetMigrations } from './records/TLAsset'\nimport { TLBinding, TLDefaultBinding, createBindingRecordType } from './records/TLBinding'\nimport { CameraRecordType, cameraMigrations } from './records/TLCamera'\nimport {\n\tCustomRecordInfo,\n\tcreateCustomRecordType,\n\tprocessCustomRecordMigrations,\n} from './records/TLCustomRecord'\nimport { DocumentRecordType, documentMigrations } from './records/TLDocument'\nimport { createInstanceRecordType, instanceMigrations } from './records/TLInstance'\nimport { PageRecordType, pageMigrations } from './records/TLPage'\nimport { InstancePageStateRecordType, instancePageStateMigrations } from './records/TLPageState'\nimport { PointerRecordType, pointerMigrations } from './records/TLPointer'\nimport { InstancePresenceRecordType, instancePresenceMigrations } from './records/TLPresence'\nimport { TLRecord } from './records/TLRecord'\nimport {\n\tTLDefaultShape,\n\tTLShape,\n\tcreateShapeRecordType,\n\tgetShapePropKeysByStyle,\n\trootShapeMigrations,\n} from './records/TLShape'\nimport { RecordProps, TLPropsMigrations, processPropsMigrations } from './recordsWithProps'\nimport { arrowShapeMigrations, arrowShapeProps } from './shapes/TLArrowShape'\nimport { TLBaseShape } from './shapes/TLBaseShape'\nimport { bookmarkShapeMigrations, bookmarkShapeProps } from './shapes/TLBookmarkShape'\nimport { drawShapeMigrations, drawShapeProps } from './shapes/TLDrawShape'\nimport { embedShapeMigrations, embedShapeProps } from './shapes/TLEmbedShape'\nimport { frameShapeMigrations, frameShapeProps } from './shapes/TLFrameShape'\nimport { geoShapeMigrations, geoShapeProps } from './shapes/TLGeoShape'\nimport { groupShapeMigrations, groupShapeProps } from './shapes/TLGroupShape'\nimport { highlightShapeMigrations, highlightShapeProps } from './shapes/TLHighlightShape'\nimport { imageShapeMigrations, imageShapeProps } from './shapes/TLImageShape'\nimport { lineShapeMigrations, lineShapeProps } from './shapes/TLLineShape'\nimport { noteShapeMigrations, noteShapeProps } from './shapes/TLNoteShape'\nimport { textShapeMigrations, textShapeProps } from './shapes/TLTextShape'\nimport { videoShapeMigrations, videoShapeProps } from './shapes/TLVideoShape'\nimport { storeMigrations } from './store-migrations'\nimport { StyleProp } from './styles/StyleProp'\nimport { TLStoreProps, createIntegrityChecker, onValidationFailure } from './TLStore'\n\n/**\n * Configuration information for a schema type (shape or binding), including its properties,\n * metadata, and migration sequences for data evolution over time.\n *\n * @public\n * @example\n * ```ts\n * import { arrowShapeMigrations, arrowShapeProps } from './shapes/TLArrowShape'\n *\n * const myShapeSchema: SchemaPropsInfo = {\n * migrations: arrowShapeMigrations,\n * props: arrowShapeProps,\n * meta: {\n * customField: T.string,\n * },\n * }\n * ```\n */\nexport interface SchemaPropsInfo {\n\t/**\n\t * Migration sequences for handling data evolution over time. Can be legacy migrations,\n\t * props-specific migrations, or general migration sequences.\n\t */\n\tmigrations?: LegacyMigrations | TLPropsMigrations | MigrationSequence\n\n\t/**\n\t * Validation schema for the shape or binding properties. Maps property names to their validators.\n\t */\n\tprops?: Record<string, StoreValidator<any>>\n\n\t/**\n\t * Validation schema for metadata fields. Maps metadata field names to their validators.\n\t */\n\tmeta?: Record<string, StoreValidator<any>>\n}\n\n/**\n * The complete schema definition for a tldraw store, encompassing all record types,\n * validation rules, and migration sequences. This schema defines the structure of\n * the persistent data model used by tldraw.\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema, defaultShapeSchemas } from '@tldraw/tlschema'\n * import { Store } from '@tldraw/store'\n *\n * const schema: TLSchema = createTLSchema({\n * shapes: defaultShapeSchemas,\n * })\n *\n * const store = new Store({ schema })\n * ```\n */\nexport type TLSchema = StoreSchema<TLRecord, TLStoreProps>\n\n/**\n * Default shape schema configurations for all built-in tldraw shape types.\n * Each shape type includes its validation props and migration sequences.\n *\n * This object contains schema information for:\n * - arrow: Directional lines that can bind to other shapes\n * - bookmark: Website bookmark cards with preview information\n * - draw: Freehand drawing paths created with drawing tools\n * - embed: Embedded content from external services (YouTube, Figma, etc.)\n * - frame: Container shapes for organizing content\n * - geo: Geometric shapes (rectangles, ellipses, triangles, etc.)\n * - group: Logical groupings of multiple shapes\n * - highlight: Highlighting strokes from the highlighter tool\n * - image: Raster image shapes referencing image assets\n * - line: Multi-point lines and splines\n * - note: Sticky note shapes with text content\n * - text: Rich text shapes with formatting support\n * - video: Video shapes referencing video assets\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema, defaultShapeSchemas } from '@tldraw/tlschema'\n *\n * // Use all default shapes\n * const schema = createTLSchema({\n * shapes: defaultShapeSchemas,\n * })\n *\n * // Use only specific default shapes\n * const minimalSchema = createTLSchema({\n * shapes: {\n * geo: defaultShapeSchemas.geo,\n * text: defaultShapeSchemas.text,\n * },\n * })\n * ```\n */\nexport const defaultShapeSchemas = {\n\tarrow: { migrations: arrowShapeMigrations, props: arrowShapeProps },\n\tbookmark: { migrations: bookmarkShapeMigrations, props: bookmarkShapeProps },\n\tdraw: { migrations: drawShapeMigrations, props: drawShapeProps },\n\tembed: { migrations: embedShapeMigrations, props: embedShapeProps },\n\tframe: { migrations: frameShapeMigrations, props: frameShapeProps },\n\tgeo: { migrations: geoShapeMigrations, props: geoShapeProps },\n\tgroup: { migrations: groupShapeMigrations, props: groupShapeProps },\n\thighlight: { migrations: highlightShapeMigrations, props: highlightShapeProps },\n\timage: { migrations: imageShapeMigrations, props: imageShapeProps },\n\tline: { migrations: lineShapeMigrations, props: lineShapeProps },\n\tnote: { migrations: noteShapeMigrations, props: noteShapeProps },\n\ttext: { migrations: textShapeMigrations, props: textShapeProps },\n\tvideo: { migrations: videoShapeMigrations, props: videoShapeProps },\n} satisfies {\n\t[T in TLDefaultShape['type']]: {\n\t\tmigrations: SchemaPropsInfo['migrations']\n\t\tprops: RecordProps<TLBaseShape<T, Extract<TLDefaultShape, { type: T }>['props']>>\n\t}\n}\n\n/**\n * Default binding schema configurations for all built-in tldraw binding types.\n * Bindings represent relationships between shapes, such as arrows connected to shapes.\n *\n * Currently includes:\n * - arrow: Bindings that connect arrow shapes to other shapes at specific anchor points\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema, defaultBindingSchemas } from '@tldraw/tlschema'\n *\n * // Use default bindings\n * const schema = createTLSchema({\n * bindings: defaultBindingSchemas,\n * })\n *\n * // Add custom binding alongside defaults\n * const customSchema = createTLSchema({\n * bindings: {\n * ...defaultBindingSchemas,\n * myCustomBinding: {\n * props: myCustomBindingProps,\n * migrations: myCustomBindingMigrations,\n * },\n * },\n * })\n * ```\n */\nexport const defaultBindingSchemas = {\n\tarrow: { migrations: arrowBindingMigrations, props: arrowBindingProps },\n} satisfies { [T in TLDefaultBinding['type']]: SchemaPropsInfo }\n\n/**\n * Creates a complete TLSchema for use with tldraw stores. This schema defines the structure,\n * validation, and migration sequences for all record types in a tldraw application.\n *\n * The schema includes all core record types (pages, cameras, instances, etc.) plus the\n * shape, binding, and custom record types you specify. Style properties are automatically\n * collected from all shapes to ensure consistency across the application.\n *\n * @param options - Configuration options for the schema\n * - shapes - Shape schema configurations. Defaults to defaultShapeSchemas if not provided\n * - bindings - Binding schema configurations. Defaults to defaultBindingSchemas if not provided\n * - records - Custom record type configurations. These are additional record types beyond\n * the built-in shapes, bindings, assets, etc.\n * - migrations - Additional migration sequences to include in the schema\n * @returns A complete TLSchema ready for use with Store creation\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema, defaultShapeSchemas, defaultBindingSchemas } from '@tldraw/tlschema'\n * import { Store } from '@tldraw/store'\n *\n * // Create schema with all default shapes and bindings\n * const schema = createTLSchema()\n *\n * // Create schema with custom shapes added\n * const customSchema = createTLSchema({\n * shapes: {\n * ...defaultShapeSchemas,\n * myCustomShape: {\n * props: myCustomShapeProps,\n * migrations: myCustomShapeMigrations,\n * },\n * },\n * })\n *\n * // Create schema with custom record types\n * const schemaWithCustomRecords = createTLSchema({\n * records: {\n * comment: {\n * scope: 'document',\n * validator: T.object({\n * id: T.string,\n * typeName: T.literal('comment'),\n * text: T.string,\n * shapeId: T.string,\n * }),\n * },\n * },\n * })\n *\n * // Use the schema with a store\n * const store = new Store({\n * schema: customSchema,\n * props: {\n * defaultName: 'My Drawing',\n * },\n * })\n * ```\n */\nexport function createTLSchema({\n\tshapes = defaultShapeSchemas,\n\tbindings = defaultBindingSchemas,\n\trecords = {},\n\tmigrations,\n}: {\n\tshapes?: Record<string, SchemaPropsInfo>\n\tbindings?: Record<string, SchemaPropsInfo>\n\trecords?: Record<string, CustomRecordInfo>\n\tmigrations?: readonly MigrationSequence[]\n} = {}): TLSchema {\n\tconst stylesById = new Map<string, StyleProp<unknown>>()\n\tfor (const shape of objectMapValues(shapes)) {\n\t\tfor (const style of getShapePropKeysByStyle(shape.props ?? {}).keys()) {\n\t\t\tif (stylesById.has(style.id) && stylesById.get(style.id) !== style) {\n\t\t\t\tthrow new Error(`Multiple StyleProp instances with the same id: ${style.id}`)\n\t\t\t}\n\t\t\tstylesById.set(style.id, style)\n\t\t}\n\t}\n\n\tconst ShapeRecordType = createShapeRecordType(shapes)\n\tconst BindingRecordType = createBindingRecordType(bindings)\n\tconst InstanceRecordType = createInstanceRecordType(stylesById)\n\n\t// Create RecordTypes for custom records\n\tconst builtInTypeNames = new Set([\n\t\t'asset',\n\t\t'binding',\n\t\t'camera',\n\t\t'document',\n\t\t'instance',\n\t\t'instance_page_state',\n\t\t'page',\n\t\t'instance_presence',\n\t\t'pointer',\n\t\t'shape',\n\t\t'store',\n\t])\n\tconst customRecordTypes: Record<string, { createId: any }> = {}\n\tfor (const [typeName, config] of Object.entries(records)) {\n\t\tif (builtInTypeNames.has(typeName)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Custom record type name '${typeName}' conflicts with tldraw's built-in record type of that name. Choose a different name instead.`\n\t\t\t)\n\t\t}\n\t\tcustomRecordTypes[typeName] = createCustomRecordType(typeName, config)\n\t}\n\n\treturn StoreSchema.create(\n\t\t{\n\t\t\tasset: AssetRecordType,\n\t\t\tbinding: BindingRecordType,\n\t\t\tcamera: CameraRecordType,\n\t\t\tdocument: DocumentRecordType,\n\t\t\tinstance: InstanceRecordType,\n\t\t\tinstance_page_state: InstancePageStateRecordType,\n\t\t\tpage: PageRecordType,\n\t\t\tinstance_presence: InstancePresenceRecordType,\n\t\t\tpointer: PointerRecordType,\n\t\t\tshape: ShapeRecordType,\n\t\t\t...customRecordTypes,\n\t\t},\n\t\t{\n\t\t\tmigrations: [\n\t\t\t\tstoreMigrations,\n\t\t\t\tassetMigrations,\n\t\t\t\tcameraMigrations,\n\t\t\t\tdocumentMigrations,\n\t\t\t\tinstanceMigrations,\n\t\t\t\tinstancePageStateMigrations,\n\t\t\t\tpageMigrations,\n\t\t\t\tinstancePresenceMigrations,\n\t\t\t\tpointerMigrations,\n\t\t\t\trootShapeMigrations,\n\n\t\t\t\tbookmarkAssetMigrations,\n\t\t\t\timageAssetMigrations,\n\t\t\t\tvideoAssetMigrations,\n\n\t\t\t\t...processPropsMigrations<TLShape>('shape', shapes),\n\t\t\t\t...processPropsMigrations<TLBinding>('binding', bindings),\n\t\t\t\t...processCustomRecordMigrations(records),\n\n\t\t\t\t...(migrations ?? []),\n\t\t\t],\n\t\t\tonValidationFailure,\n\t\t\tcreateIntegrityChecker,\n\t\t}\n\t)\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAA8C,mBAAmC;AACjF,SAAS,uBAAuB;
|
|
4
|
+
"sourcesContent": ["import { LegacyMigrations, MigrationSequence, StoreSchema, StoreValidator } from '@tldraw/store'\nimport { objectMapValues } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { bookmarkAssetMigrations } from './assets/TLBookmarkAsset'\nimport { imageAssetMigrations } from './assets/TLImageAsset'\nimport { videoAssetMigrations } from './assets/TLVideoAsset'\nimport { arrowBindingMigrations, arrowBindingProps } from './bindings/TLArrowBinding'\nimport { AssetRecordType, assetMigrations } from './records/TLAsset'\nimport { TLBinding, TLDefaultBinding, createBindingRecordType } from './records/TLBinding'\nimport { CameraRecordType, cameraMigrations } from './records/TLCamera'\nimport {\n\tCustomRecordInfo,\n\tcreateCustomRecordType,\n\tprocessCustomRecordMigrations,\n} from './records/TLCustomRecord'\nimport { DocumentRecordType, documentMigrations } from './records/TLDocument'\nimport { createInstanceRecordType, instanceMigrations } from './records/TLInstance'\nimport { PageRecordType, pageMigrations } from './records/TLPage'\nimport { InstancePageStateRecordType, instancePageStateMigrations } from './records/TLPageState'\nimport { PointerRecordType, pointerMigrations } from './records/TLPointer'\nimport { InstancePresenceRecordType, instancePresenceMigrations } from './records/TLPresence'\nimport { TLRecord } from './records/TLRecord'\nimport {\n\tTLDefaultShape,\n\tTLShape,\n\tcreateShapeRecordType,\n\tgetShapePropKeysByStyle,\n\trootShapeMigrations,\n} from './records/TLShape'\nimport { UserRecordType, createUserRecordType, userMigrations } from './records/TLUser'\nimport { RecordProps, TLPropsMigrations, processPropsMigrations } from './recordsWithProps'\nimport { arrowShapeMigrations, arrowShapeProps } from './shapes/TLArrowShape'\nimport { TLBaseShape } from './shapes/TLBaseShape'\nimport { bookmarkShapeMigrations, bookmarkShapeProps } from './shapes/TLBookmarkShape'\nimport { drawShapeMigrations, drawShapeProps } from './shapes/TLDrawShape'\nimport { embedShapeMigrations, embedShapeProps } from './shapes/TLEmbedShape'\nimport { frameShapeMigrations, frameShapeProps } from './shapes/TLFrameShape'\nimport { geoShapeMigrations, geoShapeProps } from './shapes/TLGeoShape'\nimport { groupShapeMigrations, groupShapeProps } from './shapes/TLGroupShape'\nimport { highlightShapeMigrations, highlightShapeProps } from './shapes/TLHighlightShape'\nimport { imageShapeMigrations, imageShapeProps } from './shapes/TLImageShape'\nimport { lineShapeMigrations, lineShapeProps } from './shapes/TLLineShape'\nimport { noteShapeMigrations, noteShapeProps } from './shapes/TLNoteShape'\nimport { textShapeMigrations, textShapeProps } from './shapes/TLTextShape'\nimport { videoShapeMigrations, videoShapeProps } from './shapes/TLVideoShape'\nimport { storeMigrations } from './store-migrations'\nimport { StyleProp } from './styles/StyleProp'\nimport { TLStoreProps, createIntegrityChecker, onValidationFailure } from './TLStore'\n\n/**\n * Configuration information for a schema type (shape or binding), including its properties,\n * metadata, and migration sequences for data evolution over time.\n *\n * @public\n * @example\n * ```ts\n * import { arrowShapeMigrations, arrowShapeProps } from './shapes/TLArrowShape'\n *\n * const myShapeSchema: SchemaPropsInfo = {\n * migrations: arrowShapeMigrations,\n * props: arrowShapeProps,\n * meta: {\n * customField: T.string,\n * },\n * }\n * ```\n */\nexport interface SchemaPropsInfo {\n\t/**\n\t * Migration sequences for handling data evolution over time. Can be legacy migrations,\n\t * props-specific migrations, or general migration sequences.\n\t */\n\tmigrations?: LegacyMigrations | TLPropsMigrations | MigrationSequence\n\n\t/**\n\t * Validation schema for the shape or binding properties. Maps property names to their validators.\n\t */\n\tprops?: Record<string, StoreValidator<any>>\n\n\t/**\n\t * Validation schema for metadata fields. Maps metadata field names to their validators.\n\t */\n\tmeta?: Record<string, StoreValidator<any>>\n}\n\n/**\n * The complete schema definition for a tldraw store, encompassing all record types,\n * validation rules, and migration sequences. This schema defines the structure of\n * the persistent data model used by tldraw.\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema, defaultShapeSchemas } from '@tldraw/tlschema'\n * import { Store } from '@tldraw/store'\n *\n * const schema: TLSchema = createTLSchema({\n * shapes: defaultShapeSchemas,\n * })\n *\n * const store = new Store({ schema })\n * ```\n */\nexport type TLSchema = StoreSchema<TLRecord, TLStoreProps>\n\n/**\n * Default shape schema configurations for all built-in tldraw shape types.\n * Each shape type includes its validation props and migration sequences.\n *\n * This object contains schema information for:\n * - arrow: Directional lines that can bind to other shapes\n * - bookmark: Website bookmark cards with preview information\n * - draw: Freehand drawing paths created with drawing tools\n * - embed: Embedded content from external services (YouTube, Figma, etc.)\n * - frame: Container shapes for organizing content\n * - geo: Geometric shapes (rectangles, ellipses, triangles, etc.)\n * - group: Logical groupings of multiple shapes\n * - highlight: Highlighting strokes from the highlighter tool\n * - image: Raster image shapes referencing image assets\n * - line: Multi-point lines and splines\n * - note: Sticky note shapes with text content\n * - text: Rich text shapes with formatting support\n * - video: Video shapes referencing video assets\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema, defaultShapeSchemas } from '@tldraw/tlschema'\n *\n * // Use all default shapes\n * const schema = createTLSchema({\n * shapes: defaultShapeSchemas,\n * })\n *\n * // Use only specific default shapes\n * const minimalSchema = createTLSchema({\n * shapes: {\n * geo: defaultShapeSchemas.geo,\n * text: defaultShapeSchemas.text,\n * },\n * })\n * ```\n */\nexport const defaultShapeSchemas = {\n\tarrow: { migrations: arrowShapeMigrations, props: arrowShapeProps },\n\tbookmark: { migrations: bookmarkShapeMigrations, props: bookmarkShapeProps },\n\tdraw: { migrations: drawShapeMigrations, props: drawShapeProps },\n\tembed: { migrations: embedShapeMigrations, props: embedShapeProps },\n\tframe: { migrations: frameShapeMigrations, props: frameShapeProps },\n\tgeo: { migrations: geoShapeMigrations, props: geoShapeProps },\n\tgroup: { migrations: groupShapeMigrations, props: groupShapeProps },\n\thighlight: { migrations: highlightShapeMigrations, props: highlightShapeProps },\n\timage: { migrations: imageShapeMigrations, props: imageShapeProps },\n\tline: { migrations: lineShapeMigrations, props: lineShapeProps },\n\tnote: { migrations: noteShapeMigrations, props: noteShapeProps },\n\ttext: { migrations: textShapeMigrations, props: textShapeProps },\n\tvideo: { migrations: videoShapeMigrations, props: videoShapeProps },\n} satisfies {\n\t[T in TLDefaultShape['type']]: {\n\t\tmigrations: SchemaPropsInfo['migrations']\n\t\tprops: RecordProps<TLBaseShape<T, Extract<TLDefaultShape, { type: T }>['props']>>\n\t}\n}\n\n/**\n * Default binding schema configurations for all built-in tldraw binding types.\n * Bindings represent relationships between shapes, such as arrows connected to shapes.\n *\n * Currently includes:\n * - arrow: Bindings that connect arrow shapes to other shapes at specific anchor points\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema, defaultBindingSchemas } from '@tldraw/tlschema'\n *\n * // Use default bindings\n * const schema = createTLSchema({\n * bindings: defaultBindingSchemas,\n * })\n *\n * // Add custom binding alongside defaults\n * const customSchema = createTLSchema({\n * bindings: {\n * ...defaultBindingSchemas,\n * myCustomBinding: {\n * props: myCustomBindingProps,\n * migrations: myCustomBindingMigrations,\n * },\n * },\n * })\n * ```\n */\nexport const defaultBindingSchemas = {\n\tarrow: { migrations: arrowBindingMigrations, props: arrowBindingProps },\n} satisfies { [T in TLDefaultBinding['type']]: SchemaPropsInfo }\n\n/**\n * Configuration for extending the user record type with custom metadata\n * validators and migration sequences.\n *\n * @example\n * ```ts\n * import { T } from '@tldraw/validate'\n *\n * const userSchema: UserSchemaInfo = {\n * meta: {\n * isAdmin: T.boolean,\n * department: T.string,\n * },\n * }\n * ```\n *\n * @public\n */\nexport interface UserSchemaInfo {\n\t/**\n\t * Validators for custom metadata fields on user records. Each field is\n\t * treated as optional \u2014 user records without these fields remain valid,\n\t * but when present, values are validated against the provided validators.\n\t */\n\tmeta?: Record<string, T.Validatable<any>>\n\n\t/**\n\t * Additional migration sequences for evolving custom user data over time.\n\t */\n\tmigrations?: readonly MigrationSequence[]\n}\n\n/**\n * Creates a complete TLSchema for use with tldraw stores. This schema defines the structure,\n * validation, and migration sequences for all record types in a tldraw application.\n *\n * The schema includes all core record types (pages, cameras, instances, etc.) plus the\n * shape, binding, and custom record types you specify. Style properties are automatically\n * collected from all shapes to ensure consistency across the application.\n *\n * @param options - Configuration options for the schema\n * - shapes - Shape schema configurations. Defaults to defaultShapeSchemas if not provided\n * - bindings - Binding schema configurations. Defaults to defaultBindingSchemas if not provided\n * - user - Custom user record configuration with meta validators and migrations\n * - records - Custom record type configurations. These are additional record types beyond\n * the built-in shapes, bindings, assets, etc.\n * - migrations - Additional migration sequences to include in the schema\n * @returns A complete TLSchema ready for use with Store creation\n *\n * @public\n * @example\n * ```ts\n * import { createTLSchema, defaultShapeSchemas, defaultBindingSchemas } from '@tldraw/tlschema'\n * import { Store } from '@tldraw/store'\n *\n * // Create schema with all default shapes and bindings\n * const schema = createTLSchema()\n *\n * // Create schema with custom shapes added\n * const customSchema = createTLSchema({\n * shapes: {\n * ...defaultShapeSchemas,\n * myCustomShape: {\n * props: myCustomShapeProps,\n * migrations: myCustomShapeMigrations,\n * },\n * },\n * })\n *\n * // Create schema with custom user metadata\n * const schemaWithCustomUser = createTLSchema({\n * user: {\n * meta: {\n * isAdmin: T.boolean,\n * department: T.string,\n * },\n * },\n * })\n *\n * // Create schema with custom record types\n * const schemaWithCustomRecords = createTLSchema({\n * records: {\n * comment: {\n * scope: 'document',\n * validator: T.object({\n * id: T.string,\n * typeName: T.literal('comment'),\n * text: T.string,\n * shapeId: T.string,\n * }),\n * },\n * },\n * })\n *\n * // Use the schema with a store\n * const store = new Store({\n * schema: customSchema,\n * props: {\n * defaultName: 'My Drawing',\n * },\n * })\n * ```\n */\nexport function createTLSchema({\n\tshapes = defaultShapeSchemas,\n\tbindings = defaultBindingSchemas,\n\tuser,\n\trecords = {},\n\tmigrations,\n}: {\n\tshapes?: Record<string, SchemaPropsInfo>\n\tbindings?: Record<string, SchemaPropsInfo>\n\tuser?: UserSchemaInfo\n\trecords?: Record<string, CustomRecordInfo>\n\tmigrations?: readonly MigrationSequence[]\n} = {}): TLSchema {\n\tconst stylesById = new Map<string, StyleProp<unknown>>()\n\tfor (const shape of objectMapValues(shapes)) {\n\t\tfor (const style of getShapePropKeysByStyle(shape.props ?? {}).keys()) {\n\t\t\tif (stylesById.has(style.id) && stylesById.get(style.id) !== style) {\n\t\t\t\tthrow new Error(`Multiple StyleProp instances with the same id: ${style.id}`)\n\t\t\t}\n\t\t\tstylesById.set(style.id, style)\n\t\t}\n\t}\n\n\tconst ShapeRecordType = createShapeRecordType(shapes)\n\tconst BindingRecordType = createBindingRecordType(bindings)\n\tconst InstanceRecordType = createInstanceRecordType(stylesById)\n\tconst CustomUserRecordType = user ? createUserRecordType(user) : UserRecordType\n\n\t// Create RecordTypes for custom records\n\tconst builtInTypeNames = new Set([\n\t\t'asset',\n\t\t'binding',\n\t\t'camera',\n\t\t'document',\n\t\t'instance',\n\t\t'instance_page_state',\n\t\t'page',\n\t\t'instance_presence',\n\t\t'pointer',\n\t\t'shape',\n\t\t'store',\n\t\t'user',\n\t])\n\tconst customRecordTypes: Record<string, { createId: any }> = {}\n\tfor (const [typeName, config] of Object.entries(records)) {\n\t\tif (builtInTypeNames.has(typeName)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Custom record type name '${typeName}' conflicts with tldraw's built-in record type of that name. Choose a different name instead.`\n\t\t\t)\n\t\t}\n\t\tcustomRecordTypes[typeName] = createCustomRecordType(typeName, config)\n\t}\n\n\treturn StoreSchema.create(\n\t\t{\n\t\t\tasset: AssetRecordType,\n\t\t\tbinding: BindingRecordType,\n\t\t\tcamera: CameraRecordType,\n\t\t\tdocument: DocumentRecordType,\n\t\t\tinstance: InstanceRecordType,\n\t\t\tinstance_page_state: InstancePageStateRecordType,\n\t\t\tpage: PageRecordType,\n\t\t\tinstance_presence: InstancePresenceRecordType,\n\t\t\tpointer: PointerRecordType,\n\t\t\tshape: ShapeRecordType,\n\t\t\tuser: CustomUserRecordType,\n\t\t\t...customRecordTypes,\n\t\t},\n\t\t{\n\t\t\tmigrations: [\n\t\t\t\tstoreMigrations,\n\t\t\t\tassetMigrations,\n\t\t\t\tcameraMigrations,\n\t\t\t\tdocumentMigrations,\n\t\t\t\tinstanceMigrations,\n\t\t\t\tinstancePageStateMigrations,\n\t\t\t\tpageMigrations,\n\t\t\t\tinstancePresenceMigrations,\n\t\t\t\tpointerMigrations,\n\t\t\t\trootShapeMigrations,\n\n\t\t\t\tuserMigrations,\n\t\t\t\tbookmarkAssetMigrations,\n\t\t\t\timageAssetMigrations,\n\t\t\t\tvideoAssetMigrations,\n\n\t\t\t\t...processPropsMigrations<TLShape>('shape', shapes),\n\t\t\t\t...processPropsMigrations<TLBinding>('binding', bindings),\n\t\t\t\t...processCustomRecordMigrations(records),\n\n\t\t\t\t...(user?.migrations ?? []),\n\t\t\t\t...(migrations ?? []),\n\t\t\t],\n\t\t\tonValidationFailure,\n\t\t\tcreateIntegrityChecker,\n\t\t}\n\t)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|