@tldraw/tlschema 4.5.3 → 4.6.0-canary.00a8c03b5687
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/createTLSchema.js +27 -1
- package/dist-cjs/createTLSchema.js.map +2 -2
- package/dist-cjs/index.d.ts +265 -11
- package/dist-cjs/index.js +7 -1
- package/dist-cjs/index.js.map +2 -2
- package/dist-cjs/records/TLCustomRecord.js +102 -0
- package/dist-cjs/records/TLCustomRecord.js.map +7 -0
- package/dist-cjs/records/TLPageState.js.map +2 -2
- package/dist-cjs/records/TLRecord.js.map +1 -1
- package/dist-cjs/recordsWithProps.js.map +1 -1
- package/dist-esm/createTLSchema.mjs +30 -1
- package/dist-esm/createTLSchema.mjs.map +2 -2
- package/dist-esm/index.d.mts +265 -11
- package/dist-esm/index.mjs +13 -1
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/records/TLCustomRecord.mjs +85 -0
- package/dist-esm/records/TLCustomRecord.mjs.map +7 -0
- package/dist-esm/records/TLPageState.mjs.map +2 -2
- package/dist-esm/recordsWithProps.mjs.map +1 -1
- package/package.json +7 -7
- package/src/createTLSchema.ts +49 -8
- package/src/index.ts +15 -1
- package/src/records/TLCustomRecord.ts +297 -0
- package/src/records/TLPageState.ts +4 -2
- package/src/records/TLRecord.ts +81 -12
- package/src/recordsWithProps.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/recordsWithProps.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n\tMigration,\n\tMigrationId,\n\tMigrationSequence,\n\tRecordType,\n\tStandaloneDependsOn,\n\tUnknownRecord,\n\tcreateMigrationSequence,\n} from '@tldraw/store'\nimport { MakeUndefinedOptional, assert } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { SchemaPropsInfo } from './createTLSchema'\n\n/**\n * Maps a record's property types to their corresponding validators.\n *\n * This utility type takes a record type with a `props` object and creates\n * a mapping where each property key maps to a validator for that property's type.\n * This is used to define validation schemas for record properties.\n *\n * @example\n * ```ts\n * interface MyShape extends TLBaseShape<'custom', { width: number; color: string }> {}\n *\n * // Define validators for the shape properties\n * const myShapeProps: RecordProps<MyShape> = {\n * width: T.number,\n * color: T.string\n * }\n * ```\n *\n * @public\n */\nexport type RecordProps<R extends UnknownRecord & { props: object }> = {\n\t[K in keyof R['props']]: T.Validatable<R['props'][K]>\n}\n\n/**\n * Extracts the TypeScript types from a record properties configuration.\n *\n * Takes a configuration object where values are validators and returns the\n * corresponding TypeScript types, with undefined values made optional.\n *\n * @example\n * ```ts\n * const shapePropsConfig = {\n * width: T.number,\n * height: T.number,\n * color: T.optional(T.string)\n * }\n *\n * type ShapeProps = RecordPropsType<typeof shapePropsConfig>\n * // Result: { width: number; height: number; color?: string }\n * ```\n *\n * @public\n */\nexport type RecordPropsType<Config extends Record<string, T.Validatable<any>>> =\n\tMakeUndefinedOptional<{\n\t\t[K in keyof Config]: T.TypeOf<Config[K]>\n\t}>\n\n/**\n * A migration definition for shape or record properties.\n *\n * Defines how to transform record properties when migrating between schema versions.\n * Each migration has an `up` function to upgrade data and an optional `down` function\n * to downgrade data if needed.\n *\n * @example\n * ```ts\n * const addColorMigration: TLPropsMigration = {\n * id: 'com.myapp.shape.custom/1.0.0',\n * up: (props) => {\n * // Add a default color property\n * return { ...props, color: 'black' }\n * },\n * down: (props) => {\n * // Remove the color property\n * const { color, ...rest } = props\n * return rest\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface TLPropsMigration {\n\treadonly id: MigrationId\n\treadonly dependsOn?: MigrationId[]\n\t// eslint-disable-next-line
|
|
4
|
+
"sourcesContent": ["import {\n\tMigration,\n\tMigrationId,\n\tMigrationSequence,\n\tRecordType,\n\tStandaloneDependsOn,\n\tUnknownRecord,\n\tcreateMigrationSequence,\n} from '@tldraw/store'\nimport { MakeUndefinedOptional, assert } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { SchemaPropsInfo } from './createTLSchema'\n\n/**\n * Maps a record's property types to their corresponding validators.\n *\n * This utility type takes a record type with a `props` object and creates\n * a mapping where each property key maps to a validator for that property's type.\n * This is used to define validation schemas for record properties.\n *\n * @example\n * ```ts\n * interface MyShape extends TLBaseShape<'custom', { width: number; color: string }> {}\n *\n * // Define validators for the shape properties\n * const myShapeProps: RecordProps<MyShape> = {\n * width: T.number,\n * color: T.string\n * }\n * ```\n *\n * @public\n */\nexport type RecordProps<R extends UnknownRecord & { props: object }> = {\n\t[K in keyof R['props']]: T.Validatable<R['props'][K]>\n}\n\n/**\n * Extracts the TypeScript types from a record properties configuration.\n *\n * Takes a configuration object where values are validators and returns the\n * corresponding TypeScript types, with undefined values made optional.\n *\n * @example\n * ```ts\n * const shapePropsConfig = {\n * width: T.number,\n * height: T.number,\n * color: T.optional(T.string)\n * }\n *\n * type ShapeProps = RecordPropsType<typeof shapePropsConfig>\n * // Result: { width: number; height: number; color?: string }\n * ```\n *\n * @public\n */\nexport type RecordPropsType<Config extends Record<string, T.Validatable<any>>> =\n\tMakeUndefinedOptional<{\n\t\t[K in keyof Config]: T.TypeOf<Config[K]>\n\t}>\n\n/**\n * A migration definition for shape or record properties.\n *\n * Defines how to transform record properties when migrating between schema versions.\n * Each migration has an `up` function to upgrade data and an optional `down` function\n * to downgrade data if needed.\n *\n * @example\n * ```ts\n * const addColorMigration: TLPropsMigration = {\n * id: 'com.myapp.shape.custom/1.0.0',\n * up: (props) => {\n * // Add a default color property\n * return { ...props, color: 'black' }\n * },\n * down: (props) => {\n * // Remove the color property\n * const { color, ...rest } = props\n * return rest\n * }\n * }\n * ```\n *\n * @public\n */\nexport interface TLPropsMigration {\n\treadonly id: MigrationId\n\treadonly dependsOn?: MigrationId[]\n\t// eslint-disable-next-line tldraw/method-signature-style\n\treadonly up: (props: any) => any\n\t/**\n\t * If a down migration was deployed more than a couple of months ago it should be safe to retire it.\n\t * We only really need them to smooth over the transition between versions, and some folks do keep\n\t * browser tabs open for months without refreshing, but at a certain point that kind of behavior is\n\t * on them. Plus anyway recently chrome has started to actually kill tabs that are open for too long\n\t * rather than just suspending them, so if other browsers follow suit maybe it's less of a concern.\n\t *\n\t * @public\n\t */\n\treadonly down?: 'none' | 'retired' | ((props: any) => any)\n}\n\n/**\n * A sequence of property migrations for a record type.\n *\n * Contains an ordered array of migrations that should be applied to transform\n * record properties from one version to another. Migrations can include both\n * property-specific migrations and standalone dependency declarations.\n *\n * @example\n * ```ts\n * const myShapeMigrations: TLPropsMigrations = {\n * sequence: [\n * {\n * id: 'com.myapp.shape.custom/1.0.0',\n * up: (props) => ({ ...props, version: 1 })\n * },\n * {\n * id: 'com.myapp.shape.custom/2.0.0',\n * up: (props) => ({ ...props, newFeature: true })\n * }\n * ]\n * }\n * ```\n *\n * @public\n */\nexport interface TLPropsMigrations {\n\treadonly sequence: Array<StandaloneDependsOn | TLPropsMigration>\n}\n\n/**\n * Processes property migrations for all record types in a schema.\n *\n * Takes a collection of record configurations and converts their migrations\n * into proper migration sequences that can be used by the store system.\n * Handles different migration formats including legacy migrations.\n *\n * @param typeName - The base type name for the records (e.g., 'shape', 'binding')\n * @param records - Record of type names to their schema configuration\n * @returns Array of processed migration sequences\n *\n * @example\n * ```ts\n * const shapeRecords = {\n * geo: { props: geoProps, migrations: geoMigrations },\n * arrow: { props: arrowProps, migrations: arrowMigrations }\n * }\n *\n * const sequences = processPropsMigrations('shape', shapeRecords)\n * ```\n *\n * @internal\n */\nexport function processPropsMigrations<R extends UnknownRecord & { type: string; props: object }>(\n\ttypeName: R['typeName'],\n\trecords: Record<string, SchemaPropsInfo>\n) {\n\tconst result: MigrationSequence[] = []\n\n\tfor (const [subType, { migrations }] of Object.entries(records)) {\n\t\tconst sequenceId = `com.tldraw.${typeName}.${subType}`\n\t\tif (!migrations) {\n\t\t\t// provide empty migrations sequence to allow for future migrations\n\t\t\tresult.push(\n\t\t\t\tcreateMigrationSequence({\n\t\t\t\t\tsequenceId,\n\t\t\t\t\tretroactive: true,\n\t\t\t\t\tsequence: [],\n\t\t\t\t})\n\t\t\t)\n\t\t} else if ('sequenceId' in migrations) {\n\t\t\tassert(\n\t\t\t\tsequenceId === migrations.sequenceId,\n\t\t\t\t`sequenceId mismatch for ${subType} ${RecordType} migrations. Expected '${sequenceId}', got '${migrations.sequenceId}'`\n\t\t\t)\n\t\t\tresult.push(migrations)\n\t\t} else if ('sequence' in migrations) {\n\t\t\tresult.push(\n\t\t\t\tcreateMigrationSequence({\n\t\t\t\t\tsequenceId,\n\t\t\t\t\tretroactive: true,\n\t\t\t\t\tsequence: migrations.sequence.map((m) =>\n\t\t\t\t\t\t'id' in m ? createPropsMigration(typeName, subType, m) : m\n\t\t\t\t\t),\n\t\t\t\t})\n\t\t\t)\n\t\t} else {\n\t\t\t// legacy migrations, will be removed in the future\n\t\t\tresult.push(\n\t\t\t\tcreateMigrationSequence({\n\t\t\t\t\tsequenceId,\n\t\t\t\t\tretroactive: true,\n\t\t\t\t\tsequence: Object.keys(migrations.migrators)\n\t\t\t\t\t\t.map((k) => Number(k))\n\t\t\t\t\t\t.sort((a: number, b: number) => a - b)\n\t\t\t\t\t\t.map(\n\t\t\t\t\t\t\t(version): Migration => ({\n\t\t\t\t\t\t\t\tid: `${sequenceId}/${version}`,\n\t\t\t\t\t\t\t\tscope: 'record',\n\t\t\t\t\t\t\t\tfilter: (r) => r.typeName === typeName && (r as R).type === subType,\n\t\t\t\t\t\t\t\tup: (record: any) => {\n\t\t\t\t\t\t\t\t\tconst result = migrations.migrators[version].up(record)\n\t\t\t\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\t\t\t\treturn result\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tdown: (record: any) => {\n\t\t\t\t\t\t\t\t\tconst result = migrations.migrators[version].down(record)\n\t\t\t\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\t\t\t\treturn result\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t),\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\t}\n\n\treturn result\n}\n\n/**\n * Creates a store migration from a props migration definition.\n *\n * Converts a high-level property migration into a low-level store migration\n * that can be applied to records. The resulting migration will only affect\n * records of the specified type and subtype.\n *\n * @param typeName - The base type name (e.g., 'shape', 'binding')\n * @param subType - The specific subtype (e.g., 'geo', 'arrow')\n * @param m - The property migration definition\n * @returns A store migration that applies the property transformation\n *\n * @example\n * ```ts\n * const propsMigration: TLPropsMigration = {\n * id: 'com.myapp.shape.custom/1.0.0',\n * up: (props) => ({ ...props, color: 'blue' })\n * }\n *\n * const storeMigration = createPropsMigration('shape', 'custom', propsMigration)\n * ```\n *\n * @internal\n */\nexport function createPropsMigration<R extends UnknownRecord & { type: string; props: object }>(\n\ttypeName: R['typeName'],\n\tsubType: R['type'],\n\tm: TLPropsMigration\n): Migration {\n\treturn {\n\t\tid: m.id,\n\t\tdependsOn: m.dependsOn,\n\t\tscope: 'record',\n\t\tfilter: (r) => r.typeName === typeName && (r as R).type === subType,\n\t\tup: (record: any) => {\n\t\t\tconst result = m.up(record.props)\n\t\t\tif (result) {\n\t\t\t\trecord.props = result\n\t\t\t}\n\t\t},\n\t\tdown:\n\t\t\ttypeof m.down === 'function'\n\t\t\t\t? (record: any) => {\n\t\t\t\t\t\tconst result = (m.down as (props: any) => any)(record.props)\n\t\t\t\t\t\tif (result) {\n\t\t\t\t\t\t\trecord.props = result\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t: undefined,\n\t}\n}\n"],
|
|
5
5
|
"mappings": "AAAA;AAAA,EAIC;AAAA,EAGA;AAAA,OACM;AACP,SAAgC,cAAc;AAmJvC,SAAS,uBACf,UACA,SACC;AACD,QAAM,SAA8B,CAAC;AAErC,aAAW,CAAC,SAAS,EAAE,WAAW,CAAC,KAAK,OAAO,QAAQ,OAAO,GAAG;AAChE,UAAM,aAAa,cAAc,QAAQ,IAAI,OAAO;AACpD,QAAI,CAAC,YAAY;AAEhB,aAAO;AAAA,QACN,wBAAwB;AAAA,UACvB;AAAA,UACA,aAAa;AAAA,UACb,UAAU,CAAC;AAAA,QACZ,CAAC;AAAA,MACF;AAAA,IACD,WAAW,gBAAgB,YAAY;AACtC;AAAA,QACC,eAAe,WAAW;AAAA,QAC1B,2BAA2B,OAAO,IAAI,UAAU,0BAA0B,UAAU,WAAW,WAAW,UAAU;AAAA,MACrH;AACA,aAAO,KAAK,UAAU;AAAA,IACvB,WAAW,cAAc,YAAY;AACpC,aAAO;AAAA,QACN,wBAAwB;AAAA,UACvB;AAAA,UACA,aAAa;AAAA,UACb,UAAU,WAAW,SAAS;AAAA,YAAI,CAAC,MAClC,QAAQ,IAAI,qBAAqB,UAAU,SAAS,CAAC,IAAI;AAAA,UAC1D;AAAA,QACD,CAAC;AAAA,MACF;AAAA,IACD,OAAO;AAEN,aAAO;AAAA,QACN,wBAAwB;AAAA,UACvB;AAAA,UACA,aAAa;AAAA,UACb,UAAU,OAAO,KAAK,WAAW,SAAS,EACxC,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,EACpB,KAAK,CAAC,GAAW,MAAc,IAAI,CAAC,EACpC;AAAA,YACA,CAAC,aAAwB;AAAA,cACxB,IAAI,GAAG,UAAU,IAAI,OAAO;AAAA,cAC5B,OAAO;AAAA,cACP,QAAQ,CAAC,MAAM,EAAE,aAAa,YAAa,EAAQ,SAAS;AAAA,cAC5D,IAAI,CAAC,WAAgB;AACpB,sBAAMA,UAAS,WAAW,UAAU,OAAO,EAAE,GAAG,MAAM;AACtD,oBAAIA,SAAQ;AACX,yBAAOA;AAAA,gBACR;AAAA,cACD;AAAA,cACA,MAAM,CAAC,WAAgB;AACtB,sBAAMA,UAAS,WAAW,UAAU,OAAO,EAAE,KAAK,MAAM;AACxD,oBAAIA,SAAQ;AACX,yBAAOA;AAAA,gBACR;AAAA,cACD;AAAA,YACD;AAAA,UACD;AAAA,QACF,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAEA,SAAO;AACR;AA0BO,SAAS,qBACf,UACA,SACA,GACY;AACZ,SAAO;AAAA,IACN,IAAI,EAAE;AAAA,IACN,WAAW,EAAE;AAAA,IACb,OAAO;AAAA,IACP,QAAQ,CAAC,MAAM,EAAE,aAAa,YAAa,EAAQ,SAAS;AAAA,IAC5D,IAAI,CAAC,WAAgB;AACpB,YAAM,SAAS,EAAE,GAAG,OAAO,KAAK;AAChC,UAAI,QAAQ;AACX,eAAO,QAAQ;AAAA,MAChB;AAAA,IACD;AAAA,IACA,MACC,OAAO,EAAE,SAAS,aACf,CAAC,WAAgB;AACjB,YAAM,SAAU,EAAE,KAA6B,OAAO,KAAK;AAC3D,UAAI,QAAQ;AACX,eAAO,QAAQ;AAAA,MAChB;AAAA,IACD,IACC;AAAA,EACL;AACD;",
|
|
6
6
|
"names": ["result"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/tlschema",
|
|
3
3
|
"description": "tldraw infinite canvas SDK (schema).",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.6.0-canary.00a8c03b5687",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -35,13 +35,13 @@
|
|
|
35
35
|
"test-ci": "yarn run -T vitest run --passWithNoTests",
|
|
36
36
|
"test": "yarn run -T vitest --passWithNoTests",
|
|
37
37
|
"test-coverage": "yarn run -T vitest run --coverage --passWithNoTests",
|
|
38
|
-
"format": "yarn run -T
|
|
38
|
+
"format": "yarn run -T oxfmt \"src/**/*.{ts,tsx,js,jsx,json,md}\"",
|
|
39
39
|
"build": "yarn run -T tsx ../../internal/scripts/build-package.ts",
|
|
40
40
|
"build-api": "yarn run -T tsx ../../internal/scripts/build-api.ts",
|
|
41
41
|
"prepack": "yarn run -T tsx ../../internal/scripts/prepack.ts",
|
|
42
42
|
"postpack": "../../internal/scripts/postpack.sh",
|
|
43
43
|
"pack-tarball": "yarn pack",
|
|
44
|
-
"lint": "yarn run -T
|
|
44
|
+
"lint": "cd ../.. && yarn run -T oxlint packages/tlschema"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"kleur": "^4.1.5",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"vitest": "^3.2.4"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@tldraw/state": "4.
|
|
54
|
-
"@tldraw/store": "4.
|
|
55
|
-
"@tldraw/utils": "4.
|
|
56
|
-
"@tldraw/validate": "4.
|
|
53
|
+
"@tldraw/state": "4.6.0-canary.00a8c03b5687",
|
|
54
|
+
"@tldraw/store": "4.6.0-canary.00a8c03b5687",
|
|
55
|
+
"@tldraw/utils": "4.6.0-canary.00a8c03b5687",
|
|
56
|
+
"@tldraw/validate": "4.6.0-canary.00a8c03b5687"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"react": "^18.2.0 || ^19.2.1",
|
package/src/createTLSchema.ts
CHANGED
|
@@ -8,6 +8,11 @@ import { arrowBindingMigrations, arrowBindingProps } from './bindings/TLArrowBin
|
|
|
8
8
|
import { AssetRecordType, assetMigrations } from './records/TLAsset'
|
|
9
9
|
import { TLBinding, TLDefaultBinding, createBindingRecordType } from './records/TLBinding'
|
|
10
10
|
import { CameraRecordType, cameraMigrations } from './records/TLCamera'
|
|
11
|
+
import {
|
|
12
|
+
CustomRecordInfo,
|
|
13
|
+
createCustomRecordType,
|
|
14
|
+
processCustomRecordMigrations,
|
|
15
|
+
} from './records/TLCustomRecord'
|
|
11
16
|
import { DocumentRecordType, documentMigrations } from './records/TLDocument'
|
|
12
17
|
import { createInstanceRecordType, instanceMigrations } from './records/TLInstance'
|
|
13
18
|
import { PageRecordType, pageMigrations } from './records/TLPage'
|
|
@@ -193,12 +198,14 @@ export const defaultBindingSchemas = {
|
|
|
193
198
|
* validation, and migration sequences for all record types in a tldraw application.
|
|
194
199
|
*
|
|
195
200
|
* The schema includes all core record types (pages, cameras, instances, etc.) plus the
|
|
196
|
-
* shape and
|
|
197
|
-
* all shapes to ensure consistency across the application.
|
|
201
|
+
* shape, binding, and custom record types you specify. Style properties are automatically
|
|
202
|
+
* collected from all shapes to ensure consistency across the application.
|
|
198
203
|
*
|
|
199
204
|
* @param options - Configuration options for the schema
|
|
200
205
|
* - shapes - Shape schema configurations. Defaults to defaultShapeSchemas if not provided
|
|
201
206
|
* - bindings - Binding schema configurations. Defaults to defaultBindingSchemas if not provided
|
|
207
|
+
* - records - Custom record type configurations. These are additional record types beyond
|
|
208
|
+
* the built-in shapes, bindings, assets, etc.
|
|
202
209
|
* - migrations - Additional migration sequences to include in the schema
|
|
203
210
|
* @returns A complete TLSchema ready for use with Store creation
|
|
204
211
|
*
|
|
@@ -222,13 +229,19 @@ export const defaultBindingSchemas = {
|
|
|
222
229
|
* },
|
|
223
230
|
* })
|
|
224
231
|
*
|
|
225
|
-
* // Create schema with
|
|
226
|
-
* const
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
232
|
+
* // Create schema with custom record types
|
|
233
|
+
* const schemaWithCustomRecords = createTLSchema({
|
|
234
|
+
* records: {
|
|
235
|
+
* comment: {
|
|
236
|
+
* scope: 'document',
|
|
237
|
+
* validator: T.object({
|
|
238
|
+
* id: T.string,
|
|
239
|
+
* typeName: T.literal('comment'),
|
|
240
|
+
* text: T.string,
|
|
241
|
+
* shapeId: T.string,
|
|
242
|
+
* }),
|
|
243
|
+
* },
|
|
230
244
|
* },
|
|
231
|
-
* bindings: defaultBindingSchemas,
|
|
232
245
|
* })
|
|
233
246
|
*
|
|
234
247
|
* // Use the schema with a store
|
|
@@ -243,10 +256,12 @@ export const defaultBindingSchemas = {
|
|
|
243
256
|
export function createTLSchema({
|
|
244
257
|
shapes = defaultShapeSchemas,
|
|
245
258
|
bindings = defaultBindingSchemas,
|
|
259
|
+
records = {},
|
|
246
260
|
migrations,
|
|
247
261
|
}: {
|
|
248
262
|
shapes?: Record<string, SchemaPropsInfo>
|
|
249
263
|
bindings?: Record<string, SchemaPropsInfo>
|
|
264
|
+
records?: Record<string, CustomRecordInfo>
|
|
250
265
|
migrations?: readonly MigrationSequence[]
|
|
251
266
|
} = {}): TLSchema {
|
|
252
267
|
const stylesById = new Map<string, StyleProp<unknown>>()
|
|
@@ -263,6 +278,30 @@ export function createTLSchema({
|
|
|
263
278
|
const BindingRecordType = createBindingRecordType(bindings)
|
|
264
279
|
const InstanceRecordType = createInstanceRecordType(stylesById)
|
|
265
280
|
|
|
281
|
+
// Create RecordTypes for custom records
|
|
282
|
+
const builtInTypeNames = new Set([
|
|
283
|
+
'asset',
|
|
284
|
+
'binding',
|
|
285
|
+
'camera',
|
|
286
|
+
'document',
|
|
287
|
+
'instance',
|
|
288
|
+
'instance_page_state',
|
|
289
|
+
'page',
|
|
290
|
+
'instance_presence',
|
|
291
|
+
'pointer',
|
|
292
|
+
'shape',
|
|
293
|
+
'store',
|
|
294
|
+
])
|
|
295
|
+
const customRecordTypes: Record<string, { createId: any }> = {}
|
|
296
|
+
for (const [typeName, config] of Object.entries(records)) {
|
|
297
|
+
if (builtInTypeNames.has(typeName)) {
|
|
298
|
+
throw new Error(
|
|
299
|
+
`Custom record type name '${typeName}' conflicts with tldraw's built-in record type of that name. Choose a different name instead.`
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
customRecordTypes[typeName] = createCustomRecordType(typeName, config)
|
|
303
|
+
}
|
|
304
|
+
|
|
266
305
|
return StoreSchema.create(
|
|
267
306
|
{
|
|
268
307
|
asset: AssetRecordType,
|
|
@@ -275,6 +314,7 @@ export function createTLSchema({
|
|
|
275
314
|
instance_presence: InstancePresenceRecordType,
|
|
276
315
|
pointer: PointerRecordType,
|
|
277
316
|
shape: ShapeRecordType,
|
|
317
|
+
...customRecordTypes,
|
|
278
318
|
},
|
|
279
319
|
{
|
|
280
320
|
migrations: [
|
|
@@ -295,6 +335,7 @@ export function createTLSchema({
|
|
|
295
335
|
|
|
296
336
|
...processPropsMigrations<TLShape>('shape', shapes),
|
|
297
337
|
...processPropsMigrations<TLBinding>('binding', bindings),
|
|
338
|
+
...processCustomRecordMigrations(records),
|
|
298
339
|
|
|
299
340
|
...(migrations ?? []),
|
|
300
341
|
],
|
package/src/index.ts
CHANGED
|
@@ -104,6 +104,14 @@ export {
|
|
|
104
104
|
type TLUnknownBinding,
|
|
105
105
|
} from './records/TLBinding'
|
|
106
106
|
export { CameraRecordType, type TLCamera, type TLCameraId } from './records/TLCamera'
|
|
107
|
+
export {
|
|
108
|
+
createCustomRecordId,
|
|
109
|
+
createCustomRecordMigrationIds,
|
|
110
|
+
createCustomRecordMigrationSequence,
|
|
111
|
+
isCustomRecord,
|
|
112
|
+
isCustomRecordId,
|
|
113
|
+
type CustomRecordInfo,
|
|
114
|
+
} from './records/TLCustomRecord'
|
|
107
115
|
export {
|
|
108
116
|
DocumentRecordType,
|
|
109
117
|
isDocument,
|
|
@@ -139,7 +147,13 @@ export {
|
|
|
139
147
|
type TLInstancePresence,
|
|
140
148
|
type TLInstancePresenceID,
|
|
141
149
|
} from './records/TLPresence'
|
|
142
|
-
export {
|
|
150
|
+
export {
|
|
151
|
+
type TLCustomRecord,
|
|
152
|
+
type TLDefaultRecord,
|
|
153
|
+
type TLGlobalRecordPropsMap,
|
|
154
|
+
type TLIndexedRecords,
|
|
155
|
+
type TLRecord,
|
|
156
|
+
} from './records/TLRecord'
|
|
143
157
|
export {
|
|
144
158
|
createShapeId,
|
|
145
159
|
createShapePropsMigrationIds,
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MigrationSequence,
|
|
3
|
+
RecordId,
|
|
4
|
+
RecordScope,
|
|
5
|
+
UnknownRecord,
|
|
6
|
+
createMigrationSequence,
|
|
7
|
+
createRecordType,
|
|
8
|
+
} from '@tldraw/store'
|
|
9
|
+
import { assert, mapObjectMapValues, uniqueId } from '@tldraw/utils'
|
|
10
|
+
import { T } from '@tldraw/validate'
|
|
11
|
+
import { TLPropsMigrations } from '../recordsWithProps'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Configuration for a custom record type in the schema.
|
|
15
|
+
*
|
|
16
|
+
* Custom record types allow you to add entirely new data types to the tldraw store
|
|
17
|
+
* that don't fit into the existing shape, binding, or asset categories. This is useful
|
|
18
|
+
* for storing domain-specific data like comments, annotations, or application state
|
|
19
|
+
* that needs to participate in persistence and synchronization.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const commentRecordConfig: CustomRecordInfo = {
|
|
24
|
+
* scope: 'document',
|
|
25
|
+
* validator: T.object({
|
|
26
|
+
* id: T.string,
|
|
27
|
+
* typeName: T.literal('comment'),
|
|
28
|
+
* text: T.string,
|
|
29
|
+
* shapeId: T.string,
|
|
30
|
+
* authorId: T.string,
|
|
31
|
+
* createdAt: T.number,
|
|
32
|
+
* }),
|
|
33
|
+
* migrations: createRecordMigrationSequence({
|
|
34
|
+
* sequenceId: 'com.myapp.comment',
|
|
35
|
+
* recordType: 'comment',
|
|
36
|
+
* sequence: [],
|
|
37
|
+
* }),
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export interface CustomRecordInfo {
|
|
44
|
+
/**
|
|
45
|
+
* The scope determines how records of this type are persisted and synchronized:
|
|
46
|
+
* - **document**: Persisted and synced across all clients
|
|
47
|
+
* - **session**: Local to current session, not synced
|
|
48
|
+
* - **presence**: Ephemeral presence data, may be synced but not persisted
|
|
49
|
+
*/
|
|
50
|
+
scope: RecordScope
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Validator for the complete record structure.
|
|
54
|
+
*
|
|
55
|
+
* Should validate the entire record including `id` and `typeName` fields.
|
|
56
|
+
* Use validators like T.object, T.string, etc.
|
|
57
|
+
*/
|
|
58
|
+
validator: T.Validatable<any>
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Optional migration sequence for handling schema evolution over time.
|
|
62
|
+
*
|
|
63
|
+
* Can be a full MigrationSequence or a simplified TLPropsMigrations format.
|
|
64
|
+
* If not provided, an empty migration sequence will be created automatically.
|
|
65
|
+
*/
|
|
66
|
+
migrations?: MigrationSequence | TLPropsMigrations
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Optional factory function that returns default property values for new records.
|
|
70
|
+
*
|
|
71
|
+
* Called when creating new records to provide initial values for any properties
|
|
72
|
+
* not explicitly provided during creation.
|
|
73
|
+
*/
|
|
74
|
+
// eslint-disable-next-line tldraw/method-signature-style
|
|
75
|
+
createDefaultProperties?: () => Record<string, unknown>
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates a RecordType for a custom record based on its configuration.
|
|
80
|
+
*
|
|
81
|
+
* @param typeName - The unique type name for this record type
|
|
82
|
+
* @param config - Configuration for the custom record type
|
|
83
|
+
* @returns A RecordType instance that can be used to create and manage records
|
|
84
|
+
*
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
export function createCustomRecordType(typeName: string, config: CustomRecordInfo) {
|
|
88
|
+
return createRecordType<UnknownRecord>(typeName, {
|
|
89
|
+
scope: config.scope,
|
|
90
|
+
validator: config.validator,
|
|
91
|
+
}).withDefaultProperties(config.createDefaultProperties ?? (() => ({})))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Processes migrations for custom record types.
|
|
96
|
+
*
|
|
97
|
+
* Converts the migration configuration from CustomRecordInfo into proper
|
|
98
|
+
* MigrationSequence objects that can be used by the store system.
|
|
99
|
+
*
|
|
100
|
+
* @param records - Record of type names to their configuration
|
|
101
|
+
* @returns Array of migration sequences for the custom record types
|
|
102
|
+
*
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
export function processCustomRecordMigrations(
|
|
106
|
+
records: Record<string, CustomRecordInfo>
|
|
107
|
+
): MigrationSequence[] {
|
|
108
|
+
const result: MigrationSequence[] = []
|
|
109
|
+
|
|
110
|
+
for (const [typeName, config] of Object.entries(records)) {
|
|
111
|
+
const sequenceId = `com.tldraw.${typeName}`
|
|
112
|
+
const { migrations } = config
|
|
113
|
+
|
|
114
|
+
if (!migrations) {
|
|
115
|
+
// Provide empty migration sequence to allow for future migrations
|
|
116
|
+
result.push(
|
|
117
|
+
createMigrationSequence({
|
|
118
|
+
sequenceId,
|
|
119
|
+
retroactive: true,
|
|
120
|
+
sequence: [],
|
|
121
|
+
})
|
|
122
|
+
)
|
|
123
|
+
} else if ('sequenceId' in migrations) {
|
|
124
|
+
// Full MigrationSequence provided
|
|
125
|
+
assert(
|
|
126
|
+
sequenceId === migrations.sequenceId,
|
|
127
|
+
`sequenceId mismatch for ${typeName} custom record migrations. Expected '${sequenceId}', got '${migrations.sequenceId}'`
|
|
128
|
+
)
|
|
129
|
+
result.push(migrations)
|
|
130
|
+
} else if ('sequence' in migrations) {
|
|
131
|
+
// TLPropsMigrations format - convert to full MigrationSequence
|
|
132
|
+
result.push(
|
|
133
|
+
createMigrationSequence({
|
|
134
|
+
sequenceId,
|
|
135
|
+
retroactive: true,
|
|
136
|
+
sequence: migrations.sequence.map((m) => {
|
|
137
|
+
if (!('id' in m)) return m
|
|
138
|
+
return {
|
|
139
|
+
id: m.id,
|
|
140
|
+
dependsOn: m.dependsOn,
|
|
141
|
+
scope: 'record' as const,
|
|
142
|
+
filter: (r: UnknownRecord) => r.typeName === typeName,
|
|
143
|
+
up: (record: any) => {
|
|
144
|
+
const result = m.up(record)
|
|
145
|
+
if (result) return result
|
|
146
|
+
},
|
|
147
|
+
down:
|
|
148
|
+
typeof m.down === 'function'
|
|
149
|
+
? (record: any) => {
|
|
150
|
+
const result = (m.down as (r: any) => any)(record)
|
|
151
|
+
if (result) return result
|
|
152
|
+
}
|
|
153
|
+
: undefined,
|
|
154
|
+
}
|
|
155
|
+
}),
|
|
156
|
+
})
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return result
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Creates properly formatted migration IDs for custom record migrations.
|
|
166
|
+
*
|
|
167
|
+
* Generates standardized migration IDs following the convention:
|
|
168
|
+
* `com.tldraw.{recordType}/{version}`
|
|
169
|
+
*
|
|
170
|
+
* @param recordType - The type name of the custom record
|
|
171
|
+
* @param ids - Record mapping migration names to version numbers
|
|
172
|
+
* @returns Record with the same keys but formatted migration ID values
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```ts
|
|
176
|
+
* const commentVersions = createCustomRecordMigrationIds('comment', {
|
|
177
|
+
* AddAuthorId: 1,
|
|
178
|
+
* AddCreatedAt: 2,
|
|
179
|
+
* RefactorReactions: 3
|
|
180
|
+
* })
|
|
181
|
+
* // Result: {
|
|
182
|
+
* // AddAuthorId: 'com.tldraw.comment/1',
|
|
183
|
+
* // AddCreatedAt: 'com.tldraw.comment/2',
|
|
184
|
+
* // RefactorReactions: 'com.tldraw.comment/3'
|
|
185
|
+
* // }
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* @public
|
|
189
|
+
*/
|
|
190
|
+
export function createCustomRecordMigrationIds<
|
|
191
|
+
const S extends string,
|
|
192
|
+
const T extends Record<string, number>,
|
|
193
|
+
>(recordType: S, ids: T): { [k in keyof T]: `com.tldraw.${S}/${T[k]}` } {
|
|
194
|
+
return mapObjectMapValues(ids, (_k, v) => `com.tldraw.${recordType}/${v}`) as any
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Creates a migration sequence for custom record types.
|
|
199
|
+
*
|
|
200
|
+
* This is a pass-through function that maintains the same structure as the input.
|
|
201
|
+
* It's used for consistency and to provide a clear API for defining custom record migrations.
|
|
202
|
+
*
|
|
203
|
+
* @param migrations - The migration sequence to create
|
|
204
|
+
* @returns The same migration sequence (pass-through)
|
|
205
|
+
*
|
|
206
|
+
* @example
|
|
207
|
+
* ```ts
|
|
208
|
+
* const commentMigrations = createCustomRecordMigrationSequence({
|
|
209
|
+
* sequence: [
|
|
210
|
+
* {
|
|
211
|
+
* id: 'com.myapp.comment/1',
|
|
212
|
+
* up: (record) => ({ ...record, authorId: record.authorId ?? 'unknown' }),
|
|
213
|
+
* down: ({ authorId, ...record }) => record
|
|
214
|
+
* }
|
|
215
|
+
* ]
|
|
216
|
+
* })
|
|
217
|
+
* ```
|
|
218
|
+
*
|
|
219
|
+
* @public
|
|
220
|
+
*/
|
|
221
|
+
export function createCustomRecordMigrationSequence(
|
|
222
|
+
migrations: TLPropsMigrations
|
|
223
|
+
): TLPropsMigrations {
|
|
224
|
+
return migrations
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Creates a unique ID for a custom record type.
|
|
229
|
+
*
|
|
230
|
+
* @param typeName - The type name of the custom record
|
|
231
|
+
* @param id - Optional custom ID suffix. If not provided, a unique ID will be generated
|
|
232
|
+
* @returns A properly formatted record ID
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* // Create with auto-generated ID
|
|
237
|
+
* const commentId = createCustomRecordId('comment') // 'comment:abc123'
|
|
238
|
+
*
|
|
239
|
+
* // Create with custom ID
|
|
240
|
+
* const customId = createCustomRecordId('comment', 'my-comment') // 'comment:my-comment'
|
|
241
|
+
* ```
|
|
242
|
+
*
|
|
243
|
+
* @public
|
|
244
|
+
*/
|
|
245
|
+
export function createCustomRecordId<T extends string>(
|
|
246
|
+
typeName: T,
|
|
247
|
+
id?: string
|
|
248
|
+
): RecordId<UnknownRecord> & `${T}:${string}` {
|
|
249
|
+
return `${typeName}:${id ?? uniqueId()}` as RecordId<UnknownRecord> & `${T}:${string}`
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Type guard to check if a string is a valid ID for a specific custom record type.
|
|
254
|
+
*
|
|
255
|
+
* @param typeName - The type name to check against
|
|
256
|
+
* @param id - The string to check
|
|
257
|
+
* @returns True if the string is a valid ID for the specified record type
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* const id = 'comment:abc123'
|
|
262
|
+
* if (isCustomRecordId('comment', id)) {
|
|
263
|
+
* // id is now typed as a comment record ID
|
|
264
|
+
* const comment = store.get(id)
|
|
265
|
+
* }
|
|
266
|
+
* ```
|
|
267
|
+
*
|
|
268
|
+
* @public
|
|
269
|
+
*/
|
|
270
|
+
export function isCustomRecordId(typeName: string, id?: string): boolean {
|
|
271
|
+
if (!id) return false
|
|
272
|
+
return id.startsWith(`${typeName}:`)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Type guard to check if a record is of a specific custom type.
|
|
277
|
+
*
|
|
278
|
+
* @param typeName - The type name to check against
|
|
279
|
+
* @param record - The record to check
|
|
280
|
+
* @returns True if the record is of the specified type
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* function handleRecord(record: TLRecord) {
|
|
285
|
+
* if (isCustomRecord('comment', record)) {
|
|
286
|
+
* // Handle comment record
|
|
287
|
+
* console.log(`Comment: ${record.text}`)
|
|
288
|
+
* }
|
|
289
|
+
* }
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
292
|
+
* @public
|
|
293
|
+
*/
|
|
294
|
+
export function isCustomRecord(typeName: string, record?: UnknownRecord): boolean {
|
|
295
|
+
if (!record) return false
|
|
296
|
+
return record.typeName === typeName
|
|
297
|
+
}
|
|
@@ -35,8 +35,10 @@ import { TLShapeId } from './TLShape'
|
|
|
35
35
|
*
|
|
36
36
|
* @public
|
|
37
37
|
*/
|
|
38
|
-
export interface TLInstancePageState
|
|
39
|
-
|
|
38
|
+
export interface TLInstancePageState extends BaseRecord<
|
|
39
|
+
'instance_page_state',
|
|
40
|
+
TLInstancePageStateId
|
|
41
|
+
> {
|
|
40
42
|
pageId: RecordId<TLPage>
|
|
41
43
|
selectedShapeIds: TLShapeId[]
|
|
42
44
|
hintingShapeIds: TLShapeId[]
|
package/src/records/TLRecord.ts
CHANGED
|
@@ -9,10 +9,89 @@ import { TLPointer } from './TLPointer'
|
|
|
9
9
|
import { TLInstancePresence } from './TLPresence'
|
|
10
10
|
import { TLShape } from './TLShape'
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Interface for extending tldraw with custom record types via TypeScript module augmentation.
|
|
14
|
+
*
|
|
15
|
+
* Custom record types allow you to add entirely new data types to the tldraw store that
|
|
16
|
+
* don't fit into the existing shape, binding, or asset categories. Each key in this
|
|
17
|
+
* interface becomes a new record type name, and the value should be your full record type.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* import { BaseRecord, RecordId } from '@tldraw/store'
|
|
22
|
+
*
|
|
23
|
+
* // Define your custom record type
|
|
24
|
+
* interface TLComment extends BaseRecord<'comment', RecordId<TLComment>> {
|
|
25
|
+
* text: string
|
|
26
|
+
* shapeId: TLShapeId
|
|
27
|
+
* authorId: string
|
|
28
|
+
* createdAt: number
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* // Augment the global record props map
|
|
32
|
+
* declare module '@tldraw/tlschema' {
|
|
33
|
+
* interface TLGlobalRecordPropsMap {
|
|
34
|
+
* comment: TLComment
|
|
35
|
+
* }
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* // Now TLRecord includes your custom comment type
|
|
39
|
+
* // and you can use it with createTLSchema()
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
45
|
+
export interface TLGlobalRecordPropsMap {}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Union type of all built-in tldraw record types.
|
|
49
|
+
*
|
|
50
|
+
* This includes persistent records (documents, pages, shapes, assets, bindings)
|
|
51
|
+
* and session/presence records (cameras, instances, pointers, page states).
|
|
52
|
+
*
|
|
53
|
+
* @public
|
|
54
|
+
*/
|
|
55
|
+
export type TLDefaultRecord =
|
|
56
|
+
| TLAsset
|
|
57
|
+
| TLBinding
|
|
58
|
+
| TLCamera
|
|
59
|
+
| TLDocument
|
|
60
|
+
| TLInstance
|
|
61
|
+
| TLInstancePageState
|
|
62
|
+
| TLPage
|
|
63
|
+
| TLShape
|
|
64
|
+
| TLInstancePresence
|
|
65
|
+
| TLPointer
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Index type that maps custom record type names to their record types.
|
|
69
|
+
*
|
|
70
|
+
* Similar to TLIndexedShapes and TLIndexedBindings, this type creates a mapping
|
|
71
|
+
* from type name keys to their corresponding record types, filtering out any
|
|
72
|
+
* disabled types (those set to null or undefined in TLGlobalRecordPropsMap).
|
|
73
|
+
*
|
|
74
|
+
* @public
|
|
75
|
+
*/
|
|
76
|
+
// prettier-ignore
|
|
77
|
+
export type TLIndexedRecords = {
|
|
78
|
+
[K in keyof TLGlobalRecordPropsMap as TLGlobalRecordPropsMap[K] extends null | undefined
|
|
79
|
+
? never
|
|
80
|
+
: K]: TLGlobalRecordPropsMap[K]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Union type representing a custom record from the TLGlobalRecordPropsMap.
|
|
85
|
+
*
|
|
86
|
+
* @public
|
|
87
|
+
*/
|
|
88
|
+
export type TLCustomRecord = TLIndexedRecords[keyof TLIndexedRecords]
|
|
89
|
+
|
|
12
90
|
/**
|
|
13
91
|
* Union type representing all possible record types in a tldraw store.
|
|
14
92
|
* This includes both persistent records (documents, pages, shapes, assets, bindings)
|
|
15
|
-
* and session/presence records (cameras, instances, pointers, page states)
|
|
93
|
+
* and session/presence records (cameras, instances, pointers, page states),
|
|
94
|
+
* as well as any custom record types added via TLGlobalRecordPropsMap augmentation.
|
|
16
95
|
*
|
|
17
96
|
* Records are organized by scope:
|
|
18
97
|
* - **document**: Persisted across sessions (shapes, pages, assets, bindings, documents)
|
|
@@ -52,14 +131,4 @@ import { TLShape } from './TLShape'
|
|
|
52
131
|
*
|
|
53
132
|
* @public
|
|
54
133
|
*/
|
|
55
|
-
export type TLRecord =
|
|
56
|
-
| TLAsset
|
|
57
|
-
| TLBinding
|
|
58
|
-
| TLCamera
|
|
59
|
-
| TLDocument
|
|
60
|
-
| TLInstance
|
|
61
|
-
| TLInstancePageState
|
|
62
|
-
| TLPage
|
|
63
|
-
| TLShape
|
|
64
|
-
| TLInstancePresence
|
|
65
|
-
| TLPointer
|
|
134
|
+
export type TLRecord = TLDefaultRecord | TLCustomRecord
|
package/src/recordsWithProps.ts
CHANGED
|
@@ -88,7 +88,7 @@ export type RecordPropsType<Config extends Record<string, T.Validatable<any>>> =
|
|
|
88
88
|
export interface TLPropsMigration {
|
|
89
89
|
readonly id: MigrationId
|
|
90
90
|
readonly dependsOn?: MigrationId[]
|
|
91
|
-
// eslint-disable-next-line
|
|
91
|
+
// eslint-disable-next-line tldraw/method-signature-style
|
|
92
92
|
readonly up: (props: any) => any
|
|
93
93
|
/**
|
|
94
94
|
* If a down migration was deployed more than a couple of months ago it should be safe to retire it.
|