@tldraw/tlschema 5.2.0-canary.6421dbe4e25a → 5.2.0-canary.667cbd6bb6ff

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/index.js CHANGED
@@ -205,7 +205,7 @@ var import_translations = require("./translations/translations");
205
205
  var import_b64Vecs = require("./misc/b64Vecs");
206
206
  (0, import_utils.registerTldrawLibraryVersion)(
207
207
  "@tldraw/tlschema",
208
- "5.2.0-canary.6421dbe4e25a",
208
+ "5.2.0-canary.667cbd6bb6ff",
209
209
  "cjs"
210
210
  );
211
211
  //# sourceMappingURL=index.js.map
@@ -129,7 +129,11 @@ const InstancePageStateRecordType = (0, import_store.createRecordType)(
129
129
  ephemeralKeys: {
130
130
  pageId: false,
131
131
  selectedShapeIds: false,
132
- editingShapeId: false,
132
+ // editingShapeId is set with `history: 'ignore'`, so entering the editing
133
+ // state is never undoable. Marking it ephemeral keeps undo/redo from
134
+ // reapplying a stale editingShapeId (e.g. after a shape it pointed at was
135
+ // deleted), which could leave the editor pointing at a missing shape.
136
+ editingShapeId: true,
133
137
  croppingShapeId: false,
134
138
  meta: false,
135
139
  hintingShapeIds: true,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/records/TLPageState.ts"],
4
- "sourcesContent": ["import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\nimport { shapeIdValidator } from '../shapes/TLBaseShape'\nimport { pageIdValidator, TLPage } from './TLPage'\nimport { TLShapeId } from './TLShape'\n\n/**\n * State that is unique to a particular page within a particular browser tab.\n * This record tracks all page-specific interaction state including selected shapes,\n * editing state, hover state, and other transient UI state that is tied to\n * both a specific page and a specific browser session.\n *\n * Each combination of page and browser tab has its own TLInstancePageState record.\n *\n * @example\n * ```ts\n * const pageState: TLInstancePageState = {\n * id: 'instance_page_state:page1',\n * typeName: 'instance_page_state',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1', 'shape:circle2'],\n * hoveredShapeId: 'shape:text3',\n * editingShapeId: null,\n * focusedGroupId: null\n * }\n * ```\n *\n * @public\n */\nexport interface TLInstancePageState extends BaseRecord<\n\t'instance_page_state',\n\tTLInstancePageStateId\n> {\n\tpageId: RecordId<TLPage>\n\tselectedShapeIds: TLShapeId[]\n\thintingShapeIds: TLShapeId[]\n\terasingShapeIds: TLShapeId[]\n\thoveredShapeId: TLShapeId | null\n\teditingShapeId: TLShapeId | null\n\tcroppingShapeId: TLShapeId | null\n\tfocusedGroupId: TLShapeId | null\n\tmeta: JsonObject\n}\n\n/**\n * Runtime validator for TLInstancePageState records. Validates the structure\n * and types of all instance page state properties to ensure data integrity.\n *\n * @example\n * ```ts\n * const pageState = {\n * id: 'instance_page_state:page1',\n * typeName: 'instance_page_state',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1'],\n * // ... other properties\n * }\n * const isValid = instancePageStateValidator.isValid(pageState) // true\n * ```\n *\n * @public\n */\nexport const instancePageStateValidator: T.Validator<TLInstancePageState> = T.model(\n\t'instance_page_state',\n\tT.object({\n\t\ttypeName: T.literal('instance_page_state'),\n\t\tid: idValidator<TLInstancePageStateId>('instance_page_state'),\n\t\tpageId: pageIdValidator,\n\t\tselectedShapeIds: T.arrayOf(shapeIdValidator),\n\t\thintingShapeIds: T.arrayOf(shapeIdValidator),\n\t\terasingShapeIds: T.arrayOf(shapeIdValidator),\n\t\thoveredShapeId: shapeIdValidator.nullable(),\n\t\teditingShapeId: shapeIdValidator.nullable(),\n\t\tcroppingShapeId: shapeIdValidator.nullable(),\n\t\tfocusedGroupId: shapeIdValidator.nullable(),\n\t\tmeta: T.jsonValue as T.ObjectValidator<JsonObject>,\n\t})\n)\n\n/**\n * Migration version identifiers for TLInstancePageState records. Each version\n * represents a schema change that requires data transformation when loading\n * older documents.\n *\n * @public\n */\nexport const instancePageStateVersions = createMigrationIds('com.tldraw.instance_page_state', {\n\tAddCroppingId: 1,\n\tRemoveInstanceIdAndCameraId: 2,\n\tAddMeta: 3,\n\tRenameProperties: 4,\n\tRenamePropertiesAgain: 5,\n} as const)\n\n/**\n * Migration sequence for TLInstancePageState records. Defines how to transform\n * instance page state records between different schema versions, ensuring data\n * compatibility when loading documents created with different versions.\n *\n * @example\n * ```ts\n * // Migrations are applied automatically when loading documents\n * const migrated = instancePageStateMigrations.migrate(oldState, targetVersion)\n * ```\n *\n * @public\n */\nexport const instancePageStateMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.instance_page_state',\n\trecordType: 'instance_page_state',\n\tsequence: [\n\t\t{\n\t\t\tid: instancePageStateVersions.AddCroppingId,\n\t\t\tup(instance: any) {\n\t\t\t\tinstance.croppingShapeId = null\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RemoveInstanceIdAndCameraId,\n\t\t\tup(instance: any) {\n\t\t\t\tdelete instance.instanceId\n\t\t\t\tdelete instance.cameraId\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.AddMeta,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.meta = {}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenameProperties,\n\t\t\t// this migration is cursed: it was written wrong and doesn't do anything.\n\t\t\t// rather than replace it, I've added another migration below that fixes it.\n\t\t\tup: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenamePropertiesAgain,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.selectedShapeIds = record.selectedIds\n\t\t\t\tdelete record.selectedIds\n\t\t\t\trecord.hintingShapeIds = record.hintingIds\n\t\t\t\tdelete record.hintingIds\n\t\t\t\trecord.erasingShapeIds = record.erasingIds\n\t\t\t\tdelete record.erasingIds\n\t\t\t\trecord.hoveredShapeId = record.hoveredId\n\t\t\t\tdelete record.hoveredId\n\t\t\t\trecord.editingShapeId = record.editingId\n\t\t\t\tdelete record.editingId\n\t\t\t\trecord.croppingShapeId = record.croppingShapeId ?? record.croppingId ?? null\n\t\t\t\tdelete record.croppingId\n\t\t\t\trecord.focusedGroupId = record.focusLayerId\n\t\t\t\tdelete record.focusLayerId\n\t\t\t},\n\t\t\tdown: (record: any) => {\n\t\t\t\trecord.selectedIds = record.selectedShapeIds\n\t\t\t\tdelete record.selectedShapeIds\n\t\t\t\trecord.hintingIds = record.hintingShapeIds\n\t\t\t\tdelete record.hintingShapeIds\n\t\t\t\trecord.erasingIds = record.erasingShapeIds\n\t\t\t\tdelete record.erasingShapeIds\n\t\t\t\trecord.hoveredId = record.hoveredShapeId\n\t\t\t\tdelete record.hoveredShapeId\n\t\t\t\trecord.editingId = record.editingShapeId\n\t\t\t\tdelete record.editingShapeId\n\t\t\t\trecord.croppingId = record.croppingShapeId\n\t\t\t\tdelete record.croppingShapeId\n\t\t\t\trecord.focusLayerId = record.focusedGroupId\n\t\t\t\tdelete record.focusedGroupId\n\t\t\t},\n\t\t},\n\t],\n})\n\n/**\n * The RecordType definition for TLInstancePageState records. Defines validation,\n * scope, and default properties for instance page state records.\n *\n * Instance page states are scoped to the session level, meaning they are\n * specific to a browser tab and don't persist across sessions or sync\n * in collaborative environments.\n *\n * @example\n * ```ts\n * const pageState = InstancePageStateRecordType.create({\n * id: 'instance_page_state:page1',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1']\n * })\n * ```\n *\n * @public\n */\nexport const InstancePageStateRecordType = createRecordType<TLInstancePageState>(\n\t'instance_page_state',\n\t{\n\t\tvalidator: instancePageStateValidator,\n\t\tscope: 'session',\n\t\tephemeralKeys: {\n\t\t\tpageId: false,\n\t\t\tselectedShapeIds: false,\n\t\t\teditingShapeId: false,\n\t\t\tcroppingShapeId: false,\n\t\t\tmeta: false,\n\n\t\t\thintingShapeIds: true,\n\t\t\terasingShapeIds: true,\n\t\t\thoveredShapeId: true,\n\t\t\tfocusedGroupId: true,\n\t\t},\n\t}\n).withDefaultProperties(\n\t(): Omit<TLInstancePageState, 'id' | 'typeName' | 'pageId'> => ({\n\t\teditingShapeId: null,\n\t\tcroppingShapeId: null,\n\t\tselectedShapeIds: [],\n\t\thoveredShapeId: null,\n\t\terasingShapeIds: [],\n\t\thintingShapeIds: [],\n\t\tfocusedGroupId: null,\n\t\tmeta: {},\n\t})\n)\n\n/**\n * A unique identifier for TLInstancePageState records.\n *\n * Instance page state IDs follow the format 'instance_page_state:' followed\n * by a unique identifier, typically related to the page ID.\n *\n * @example\n * ```ts\n * const stateId: TLInstancePageStateId = 'instance_page_state:page1'\n * ```\n *\n * @public\n */\nexport type TLInstancePageStateId = RecordId<TLInstancePageState>\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\nimport { shapeIdValidator } from '../shapes/TLBaseShape'\nimport { pageIdValidator, TLPage } from './TLPage'\nimport { TLShapeId } from './TLShape'\n\n/**\n * State that is unique to a particular page within a particular browser tab.\n * This record tracks all page-specific interaction state including selected shapes,\n * editing state, hover state, and other transient UI state that is tied to\n * both a specific page and a specific browser session.\n *\n * Each combination of page and browser tab has its own TLInstancePageState record.\n *\n * @example\n * ```ts\n * const pageState: TLInstancePageState = {\n * id: 'instance_page_state:page1',\n * typeName: 'instance_page_state',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1', 'shape:circle2'],\n * hoveredShapeId: 'shape:text3',\n * editingShapeId: null,\n * focusedGroupId: null\n * }\n * ```\n *\n * @public\n */\nexport interface TLInstancePageState extends BaseRecord<\n\t'instance_page_state',\n\tTLInstancePageStateId\n> {\n\tpageId: RecordId<TLPage>\n\tselectedShapeIds: TLShapeId[]\n\thintingShapeIds: TLShapeId[]\n\terasingShapeIds: TLShapeId[]\n\thoveredShapeId: TLShapeId | null\n\teditingShapeId: TLShapeId | null\n\tcroppingShapeId: TLShapeId | null\n\tfocusedGroupId: TLShapeId | null\n\tmeta: JsonObject\n}\n\n/**\n * Runtime validator for TLInstancePageState records. Validates the structure\n * and types of all instance page state properties to ensure data integrity.\n *\n * @example\n * ```ts\n * const pageState = {\n * id: 'instance_page_state:page1',\n * typeName: 'instance_page_state',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1'],\n * // ... other properties\n * }\n * const isValid = instancePageStateValidator.isValid(pageState) // true\n * ```\n *\n * @public\n */\nexport const instancePageStateValidator: T.Validator<TLInstancePageState> = T.model(\n\t'instance_page_state',\n\tT.object({\n\t\ttypeName: T.literal('instance_page_state'),\n\t\tid: idValidator<TLInstancePageStateId>('instance_page_state'),\n\t\tpageId: pageIdValidator,\n\t\tselectedShapeIds: T.arrayOf(shapeIdValidator),\n\t\thintingShapeIds: T.arrayOf(shapeIdValidator),\n\t\terasingShapeIds: T.arrayOf(shapeIdValidator),\n\t\thoveredShapeId: shapeIdValidator.nullable(),\n\t\teditingShapeId: shapeIdValidator.nullable(),\n\t\tcroppingShapeId: shapeIdValidator.nullable(),\n\t\tfocusedGroupId: shapeIdValidator.nullable(),\n\t\tmeta: T.jsonValue as T.ObjectValidator<JsonObject>,\n\t})\n)\n\n/**\n * Migration version identifiers for TLInstancePageState records. Each version\n * represents a schema change that requires data transformation when loading\n * older documents.\n *\n * @public\n */\nexport const instancePageStateVersions = createMigrationIds('com.tldraw.instance_page_state', {\n\tAddCroppingId: 1,\n\tRemoveInstanceIdAndCameraId: 2,\n\tAddMeta: 3,\n\tRenameProperties: 4,\n\tRenamePropertiesAgain: 5,\n} as const)\n\n/**\n * Migration sequence for TLInstancePageState records. Defines how to transform\n * instance page state records between different schema versions, ensuring data\n * compatibility when loading documents created with different versions.\n *\n * @example\n * ```ts\n * // Migrations are applied automatically when loading documents\n * const migrated = instancePageStateMigrations.migrate(oldState, targetVersion)\n * ```\n *\n * @public\n */\nexport const instancePageStateMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.instance_page_state',\n\trecordType: 'instance_page_state',\n\tsequence: [\n\t\t{\n\t\t\tid: instancePageStateVersions.AddCroppingId,\n\t\t\tup(instance: any) {\n\t\t\t\tinstance.croppingShapeId = null\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RemoveInstanceIdAndCameraId,\n\t\t\tup(instance: any) {\n\t\t\t\tdelete instance.instanceId\n\t\t\t\tdelete instance.cameraId\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.AddMeta,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.meta = {}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenameProperties,\n\t\t\t// this migration is cursed: it was written wrong and doesn't do anything.\n\t\t\t// rather than replace it, I've added another migration below that fixes it.\n\t\t\tup: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenamePropertiesAgain,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.selectedShapeIds = record.selectedIds\n\t\t\t\tdelete record.selectedIds\n\t\t\t\trecord.hintingShapeIds = record.hintingIds\n\t\t\t\tdelete record.hintingIds\n\t\t\t\trecord.erasingShapeIds = record.erasingIds\n\t\t\t\tdelete record.erasingIds\n\t\t\t\trecord.hoveredShapeId = record.hoveredId\n\t\t\t\tdelete record.hoveredId\n\t\t\t\trecord.editingShapeId = record.editingId\n\t\t\t\tdelete record.editingId\n\t\t\t\trecord.croppingShapeId = record.croppingShapeId ?? record.croppingId ?? null\n\t\t\t\tdelete record.croppingId\n\t\t\t\trecord.focusedGroupId = record.focusLayerId\n\t\t\t\tdelete record.focusLayerId\n\t\t\t},\n\t\t\tdown: (record: any) => {\n\t\t\t\trecord.selectedIds = record.selectedShapeIds\n\t\t\t\tdelete record.selectedShapeIds\n\t\t\t\trecord.hintingIds = record.hintingShapeIds\n\t\t\t\tdelete record.hintingShapeIds\n\t\t\t\trecord.erasingIds = record.erasingShapeIds\n\t\t\t\tdelete record.erasingShapeIds\n\t\t\t\trecord.hoveredId = record.hoveredShapeId\n\t\t\t\tdelete record.hoveredShapeId\n\t\t\t\trecord.editingId = record.editingShapeId\n\t\t\t\tdelete record.editingShapeId\n\t\t\t\trecord.croppingId = record.croppingShapeId\n\t\t\t\tdelete record.croppingShapeId\n\t\t\t\trecord.focusLayerId = record.focusedGroupId\n\t\t\t\tdelete record.focusedGroupId\n\t\t\t},\n\t\t},\n\t],\n})\n\n/**\n * The RecordType definition for TLInstancePageState records. Defines validation,\n * scope, and default properties for instance page state records.\n *\n * Instance page states are scoped to the session level, meaning they are\n * specific to a browser tab and don't persist across sessions or sync\n * in collaborative environments.\n *\n * @example\n * ```ts\n * const pageState = InstancePageStateRecordType.create({\n * id: 'instance_page_state:page1',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1']\n * })\n * ```\n *\n * @public\n */\nexport const InstancePageStateRecordType = createRecordType<TLInstancePageState>(\n\t'instance_page_state',\n\t{\n\t\tvalidator: instancePageStateValidator,\n\t\tscope: 'session',\n\t\tephemeralKeys: {\n\t\t\tpageId: false,\n\t\t\tselectedShapeIds: false,\n\t\t\t// editingShapeId is set with `history: 'ignore'`, so entering the editing\n\t\t\t// state is never undoable. Marking it ephemeral keeps undo/redo from\n\t\t\t// reapplying a stale editingShapeId (e.g. after a shape it pointed at was\n\t\t\t// deleted), which could leave the editor pointing at a missing shape.\n\t\t\teditingShapeId: true,\n\t\t\tcroppingShapeId: false,\n\t\t\tmeta: false,\n\n\t\t\thintingShapeIds: true,\n\t\t\terasingShapeIds: true,\n\t\t\thoveredShapeId: true,\n\t\t\tfocusedGroupId: true,\n\t\t},\n\t}\n).withDefaultProperties(\n\t(): Omit<TLInstancePageState, 'id' | 'typeName' | 'pageId'> => ({\n\t\teditingShapeId: null,\n\t\tcroppingShapeId: null,\n\t\tselectedShapeIds: [],\n\t\thoveredShapeId: null,\n\t\terasingShapeIds: [],\n\t\thintingShapeIds: [],\n\t\tfocusedGroupId: null,\n\t\tmeta: {},\n\t})\n)\n\n/**\n * A unique identifier for TLInstancePageState records.\n *\n * Instance page state IDs follow the format 'instance_page_state:' followed\n * by a unique identifier, typically related to the page ID.\n *\n * @example\n * ```ts\n * const stateId: TLInstancePageStateId = 'instance_page_state:page1'\n * ```\n *\n * @public\n */\nexport type TLInstancePageStateId = RecordId<TLInstancePageState>\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -198,7 +198,7 @@ import {
198
198
  } from "./translations/translations.mjs";
199
199
  registerTldrawLibraryVersion(
200
200
  "@tldraw/tlschema",
201
- "5.2.0-canary.6421dbe4e25a",
201
+ "5.2.0-canary.667cbd6bb6ff",
202
202
  "esm"
203
203
  );
204
204
  import { b64Vecs } from "./misc/b64Vecs.mjs";
@@ -107,7 +107,11 @@ const InstancePageStateRecordType = createRecordType(
107
107
  ephemeralKeys: {
108
108
  pageId: false,
109
109
  selectedShapeIds: false,
110
- editingShapeId: false,
110
+ // editingShapeId is set with `history: 'ignore'`, so entering the editing
111
+ // state is never undoable. Marking it ephemeral keeps undo/redo from
112
+ // reapplying a stale editingShapeId (e.g. after a shape it pointed at was
113
+ // deleted), which could leave the editor pointing at a missing shape.
114
+ editingShapeId: true,
111
115
  croppingShapeId: false,
112
116
  meta: false,
113
117
  hintingShapeIds: true,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/records/TLPageState.ts"],
4
- "sourcesContent": ["import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\nimport { shapeIdValidator } from '../shapes/TLBaseShape'\nimport { pageIdValidator, TLPage } from './TLPage'\nimport { TLShapeId } from './TLShape'\n\n/**\n * State that is unique to a particular page within a particular browser tab.\n * This record tracks all page-specific interaction state including selected shapes,\n * editing state, hover state, and other transient UI state that is tied to\n * both a specific page and a specific browser session.\n *\n * Each combination of page and browser tab has its own TLInstancePageState record.\n *\n * @example\n * ```ts\n * const pageState: TLInstancePageState = {\n * id: 'instance_page_state:page1',\n * typeName: 'instance_page_state',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1', 'shape:circle2'],\n * hoveredShapeId: 'shape:text3',\n * editingShapeId: null,\n * focusedGroupId: null\n * }\n * ```\n *\n * @public\n */\nexport interface TLInstancePageState extends BaseRecord<\n\t'instance_page_state',\n\tTLInstancePageStateId\n> {\n\tpageId: RecordId<TLPage>\n\tselectedShapeIds: TLShapeId[]\n\thintingShapeIds: TLShapeId[]\n\terasingShapeIds: TLShapeId[]\n\thoveredShapeId: TLShapeId | null\n\teditingShapeId: TLShapeId | null\n\tcroppingShapeId: TLShapeId | null\n\tfocusedGroupId: TLShapeId | null\n\tmeta: JsonObject\n}\n\n/**\n * Runtime validator for TLInstancePageState records. Validates the structure\n * and types of all instance page state properties to ensure data integrity.\n *\n * @example\n * ```ts\n * const pageState = {\n * id: 'instance_page_state:page1',\n * typeName: 'instance_page_state',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1'],\n * // ... other properties\n * }\n * const isValid = instancePageStateValidator.isValid(pageState) // true\n * ```\n *\n * @public\n */\nexport const instancePageStateValidator: T.Validator<TLInstancePageState> = T.model(\n\t'instance_page_state',\n\tT.object({\n\t\ttypeName: T.literal('instance_page_state'),\n\t\tid: idValidator<TLInstancePageStateId>('instance_page_state'),\n\t\tpageId: pageIdValidator,\n\t\tselectedShapeIds: T.arrayOf(shapeIdValidator),\n\t\thintingShapeIds: T.arrayOf(shapeIdValidator),\n\t\terasingShapeIds: T.arrayOf(shapeIdValidator),\n\t\thoveredShapeId: shapeIdValidator.nullable(),\n\t\teditingShapeId: shapeIdValidator.nullable(),\n\t\tcroppingShapeId: shapeIdValidator.nullable(),\n\t\tfocusedGroupId: shapeIdValidator.nullable(),\n\t\tmeta: T.jsonValue as T.ObjectValidator<JsonObject>,\n\t})\n)\n\n/**\n * Migration version identifiers for TLInstancePageState records. Each version\n * represents a schema change that requires data transformation when loading\n * older documents.\n *\n * @public\n */\nexport const instancePageStateVersions = createMigrationIds('com.tldraw.instance_page_state', {\n\tAddCroppingId: 1,\n\tRemoveInstanceIdAndCameraId: 2,\n\tAddMeta: 3,\n\tRenameProperties: 4,\n\tRenamePropertiesAgain: 5,\n} as const)\n\n/**\n * Migration sequence for TLInstancePageState records. Defines how to transform\n * instance page state records between different schema versions, ensuring data\n * compatibility when loading documents created with different versions.\n *\n * @example\n * ```ts\n * // Migrations are applied automatically when loading documents\n * const migrated = instancePageStateMigrations.migrate(oldState, targetVersion)\n * ```\n *\n * @public\n */\nexport const instancePageStateMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.instance_page_state',\n\trecordType: 'instance_page_state',\n\tsequence: [\n\t\t{\n\t\t\tid: instancePageStateVersions.AddCroppingId,\n\t\t\tup(instance: any) {\n\t\t\t\tinstance.croppingShapeId = null\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RemoveInstanceIdAndCameraId,\n\t\t\tup(instance: any) {\n\t\t\t\tdelete instance.instanceId\n\t\t\t\tdelete instance.cameraId\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.AddMeta,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.meta = {}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenameProperties,\n\t\t\t// this migration is cursed: it was written wrong and doesn't do anything.\n\t\t\t// rather than replace it, I've added another migration below that fixes it.\n\t\t\tup: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenamePropertiesAgain,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.selectedShapeIds = record.selectedIds\n\t\t\t\tdelete record.selectedIds\n\t\t\t\trecord.hintingShapeIds = record.hintingIds\n\t\t\t\tdelete record.hintingIds\n\t\t\t\trecord.erasingShapeIds = record.erasingIds\n\t\t\t\tdelete record.erasingIds\n\t\t\t\trecord.hoveredShapeId = record.hoveredId\n\t\t\t\tdelete record.hoveredId\n\t\t\t\trecord.editingShapeId = record.editingId\n\t\t\t\tdelete record.editingId\n\t\t\t\trecord.croppingShapeId = record.croppingShapeId ?? record.croppingId ?? null\n\t\t\t\tdelete record.croppingId\n\t\t\t\trecord.focusedGroupId = record.focusLayerId\n\t\t\t\tdelete record.focusLayerId\n\t\t\t},\n\t\t\tdown: (record: any) => {\n\t\t\t\trecord.selectedIds = record.selectedShapeIds\n\t\t\t\tdelete record.selectedShapeIds\n\t\t\t\trecord.hintingIds = record.hintingShapeIds\n\t\t\t\tdelete record.hintingShapeIds\n\t\t\t\trecord.erasingIds = record.erasingShapeIds\n\t\t\t\tdelete record.erasingShapeIds\n\t\t\t\trecord.hoveredId = record.hoveredShapeId\n\t\t\t\tdelete record.hoveredShapeId\n\t\t\t\trecord.editingId = record.editingShapeId\n\t\t\t\tdelete record.editingShapeId\n\t\t\t\trecord.croppingId = record.croppingShapeId\n\t\t\t\tdelete record.croppingShapeId\n\t\t\t\trecord.focusLayerId = record.focusedGroupId\n\t\t\t\tdelete record.focusedGroupId\n\t\t\t},\n\t\t},\n\t],\n})\n\n/**\n * The RecordType definition for TLInstancePageState records. Defines validation,\n * scope, and default properties for instance page state records.\n *\n * Instance page states are scoped to the session level, meaning they are\n * specific to a browser tab and don't persist across sessions or sync\n * in collaborative environments.\n *\n * @example\n * ```ts\n * const pageState = InstancePageStateRecordType.create({\n * id: 'instance_page_state:page1',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1']\n * })\n * ```\n *\n * @public\n */\nexport const InstancePageStateRecordType = createRecordType<TLInstancePageState>(\n\t'instance_page_state',\n\t{\n\t\tvalidator: instancePageStateValidator,\n\t\tscope: 'session',\n\t\tephemeralKeys: {\n\t\t\tpageId: false,\n\t\t\tselectedShapeIds: false,\n\t\t\teditingShapeId: false,\n\t\t\tcroppingShapeId: false,\n\t\t\tmeta: false,\n\n\t\t\thintingShapeIds: true,\n\t\t\terasingShapeIds: true,\n\t\t\thoveredShapeId: true,\n\t\t\tfocusedGroupId: true,\n\t\t},\n\t}\n).withDefaultProperties(\n\t(): Omit<TLInstancePageState, 'id' | 'typeName' | 'pageId'> => ({\n\t\teditingShapeId: null,\n\t\tcroppingShapeId: null,\n\t\tselectedShapeIds: [],\n\t\thoveredShapeId: null,\n\t\terasingShapeIds: [],\n\t\thintingShapeIds: [],\n\t\tfocusedGroupId: null,\n\t\tmeta: {},\n\t})\n)\n\n/**\n * A unique identifier for TLInstancePageState records.\n *\n * Instance page state IDs follow the format 'instance_page_state:' followed\n * by a unique identifier, typically related to the page ID.\n *\n * @example\n * ```ts\n * const stateId: TLInstancePageStateId = 'instance_page_state:page1'\n * ```\n *\n * @public\n */\nexport type TLInstancePageStateId = RecordId<TLInstancePageState>\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tBaseRecord,\n\tcreateMigrationIds,\n\tcreateRecordMigrationSequence,\n\tcreateRecordType,\n\tRecordId,\n} from '@tldraw/store'\nimport { JsonObject } from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { idValidator } from '../misc/id-validator'\nimport { shapeIdValidator } from '../shapes/TLBaseShape'\nimport { pageIdValidator, TLPage } from './TLPage'\nimport { TLShapeId } from './TLShape'\n\n/**\n * State that is unique to a particular page within a particular browser tab.\n * This record tracks all page-specific interaction state including selected shapes,\n * editing state, hover state, and other transient UI state that is tied to\n * both a specific page and a specific browser session.\n *\n * Each combination of page and browser tab has its own TLInstancePageState record.\n *\n * @example\n * ```ts\n * const pageState: TLInstancePageState = {\n * id: 'instance_page_state:page1',\n * typeName: 'instance_page_state',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1', 'shape:circle2'],\n * hoveredShapeId: 'shape:text3',\n * editingShapeId: null,\n * focusedGroupId: null\n * }\n * ```\n *\n * @public\n */\nexport interface TLInstancePageState extends BaseRecord<\n\t'instance_page_state',\n\tTLInstancePageStateId\n> {\n\tpageId: RecordId<TLPage>\n\tselectedShapeIds: TLShapeId[]\n\thintingShapeIds: TLShapeId[]\n\terasingShapeIds: TLShapeId[]\n\thoveredShapeId: TLShapeId | null\n\teditingShapeId: TLShapeId | null\n\tcroppingShapeId: TLShapeId | null\n\tfocusedGroupId: TLShapeId | null\n\tmeta: JsonObject\n}\n\n/**\n * Runtime validator for TLInstancePageState records. Validates the structure\n * and types of all instance page state properties to ensure data integrity.\n *\n * @example\n * ```ts\n * const pageState = {\n * id: 'instance_page_state:page1',\n * typeName: 'instance_page_state',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1'],\n * // ... other properties\n * }\n * const isValid = instancePageStateValidator.isValid(pageState) // true\n * ```\n *\n * @public\n */\nexport const instancePageStateValidator: T.Validator<TLInstancePageState> = T.model(\n\t'instance_page_state',\n\tT.object({\n\t\ttypeName: T.literal('instance_page_state'),\n\t\tid: idValidator<TLInstancePageStateId>('instance_page_state'),\n\t\tpageId: pageIdValidator,\n\t\tselectedShapeIds: T.arrayOf(shapeIdValidator),\n\t\thintingShapeIds: T.arrayOf(shapeIdValidator),\n\t\terasingShapeIds: T.arrayOf(shapeIdValidator),\n\t\thoveredShapeId: shapeIdValidator.nullable(),\n\t\teditingShapeId: shapeIdValidator.nullable(),\n\t\tcroppingShapeId: shapeIdValidator.nullable(),\n\t\tfocusedGroupId: shapeIdValidator.nullable(),\n\t\tmeta: T.jsonValue as T.ObjectValidator<JsonObject>,\n\t})\n)\n\n/**\n * Migration version identifiers for TLInstancePageState records. Each version\n * represents a schema change that requires data transformation when loading\n * older documents.\n *\n * @public\n */\nexport const instancePageStateVersions = createMigrationIds('com.tldraw.instance_page_state', {\n\tAddCroppingId: 1,\n\tRemoveInstanceIdAndCameraId: 2,\n\tAddMeta: 3,\n\tRenameProperties: 4,\n\tRenamePropertiesAgain: 5,\n} as const)\n\n/**\n * Migration sequence for TLInstancePageState records. Defines how to transform\n * instance page state records between different schema versions, ensuring data\n * compatibility when loading documents created with different versions.\n *\n * @example\n * ```ts\n * // Migrations are applied automatically when loading documents\n * const migrated = instancePageStateMigrations.migrate(oldState, targetVersion)\n * ```\n *\n * @public\n */\nexport const instancePageStateMigrations = createRecordMigrationSequence({\n\tsequenceId: 'com.tldraw.instance_page_state',\n\trecordType: 'instance_page_state',\n\tsequence: [\n\t\t{\n\t\t\tid: instancePageStateVersions.AddCroppingId,\n\t\t\tup(instance: any) {\n\t\t\t\tinstance.croppingShapeId = null\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RemoveInstanceIdAndCameraId,\n\t\t\tup(instance: any) {\n\t\t\t\tdelete instance.instanceId\n\t\t\t\tdelete instance.cameraId\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.AddMeta,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.meta = {}\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenameProperties,\n\t\t\t// this migration is cursed: it was written wrong and doesn't do anything.\n\t\t\t// rather than replace it, I've added another migration below that fixes it.\n\t\t\tup: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t\tdown: (_record) => {\n\t\t\t\t// noop\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: instancePageStateVersions.RenamePropertiesAgain,\n\t\t\tup: (record: any) => {\n\t\t\t\trecord.selectedShapeIds = record.selectedIds\n\t\t\t\tdelete record.selectedIds\n\t\t\t\trecord.hintingShapeIds = record.hintingIds\n\t\t\t\tdelete record.hintingIds\n\t\t\t\trecord.erasingShapeIds = record.erasingIds\n\t\t\t\tdelete record.erasingIds\n\t\t\t\trecord.hoveredShapeId = record.hoveredId\n\t\t\t\tdelete record.hoveredId\n\t\t\t\trecord.editingShapeId = record.editingId\n\t\t\t\tdelete record.editingId\n\t\t\t\trecord.croppingShapeId = record.croppingShapeId ?? record.croppingId ?? null\n\t\t\t\tdelete record.croppingId\n\t\t\t\trecord.focusedGroupId = record.focusLayerId\n\t\t\t\tdelete record.focusLayerId\n\t\t\t},\n\t\t\tdown: (record: any) => {\n\t\t\t\trecord.selectedIds = record.selectedShapeIds\n\t\t\t\tdelete record.selectedShapeIds\n\t\t\t\trecord.hintingIds = record.hintingShapeIds\n\t\t\t\tdelete record.hintingShapeIds\n\t\t\t\trecord.erasingIds = record.erasingShapeIds\n\t\t\t\tdelete record.erasingShapeIds\n\t\t\t\trecord.hoveredId = record.hoveredShapeId\n\t\t\t\tdelete record.hoveredShapeId\n\t\t\t\trecord.editingId = record.editingShapeId\n\t\t\t\tdelete record.editingShapeId\n\t\t\t\trecord.croppingId = record.croppingShapeId\n\t\t\t\tdelete record.croppingShapeId\n\t\t\t\trecord.focusLayerId = record.focusedGroupId\n\t\t\t\tdelete record.focusedGroupId\n\t\t\t},\n\t\t},\n\t],\n})\n\n/**\n * The RecordType definition for TLInstancePageState records. Defines validation,\n * scope, and default properties for instance page state records.\n *\n * Instance page states are scoped to the session level, meaning they are\n * specific to a browser tab and don't persist across sessions or sync\n * in collaborative environments.\n *\n * @example\n * ```ts\n * const pageState = InstancePageStateRecordType.create({\n * id: 'instance_page_state:page1',\n * pageId: 'page:page1',\n * selectedShapeIds: ['shape:rect1']\n * })\n * ```\n *\n * @public\n */\nexport const InstancePageStateRecordType = createRecordType<TLInstancePageState>(\n\t'instance_page_state',\n\t{\n\t\tvalidator: instancePageStateValidator,\n\t\tscope: 'session',\n\t\tephemeralKeys: {\n\t\t\tpageId: false,\n\t\t\tselectedShapeIds: false,\n\t\t\t// editingShapeId is set with `history: 'ignore'`, so entering the editing\n\t\t\t// state is never undoable. Marking it ephemeral keeps undo/redo from\n\t\t\t// reapplying a stale editingShapeId (e.g. after a shape it pointed at was\n\t\t\t// deleted), which could leave the editor pointing at a missing shape.\n\t\t\teditingShapeId: true,\n\t\t\tcroppingShapeId: false,\n\t\t\tmeta: false,\n\n\t\t\thintingShapeIds: true,\n\t\t\terasingShapeIds: true,\n\t\t\thoveredShapeId: true,\n\t\t\tfocusedGroupId: true,\n\t\t},\n\t}\n).withDefaultProperties(\n\t(): Omit<TLInstancePageState, 'id' | 'typeName' | 'pageId'> => ({\n\t\teditingShapeId: null,\n\t\tcroppingShapeId: null,\n\t\tselectedShapeIds: [],\n\t\thoveredShapeId: null,\n\t\terasingShapeIds: [],\n\t\thintingShapeIds: [],\n\t\tfocusedGroupId: null,\n\t\tmeta: {},\n\t})\n)\n\n/**\n * A unique identifier for TLInstancePageState records.\n *\n * Instance page state IDs follow the format 'instance_page_state:' followed\n * by a unique identifier, typically related to the page ID.\n *\n * @example\n * ```ts\n * const stateId: TLInstancePageStateId = 'instance_page_state:page1'\n * ```\n *\n * @public\n */\nexport type TLInstancePageStateId = RecordId<TLInstancePageState>\n"],
5
+ "mappings": "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",
6
6
  "names": []
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": "5.2.0-canary.6421dbe4e25a",
4
+ "version": "5.2.0-canary.667cbd6bb6ff",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -51,15 +51,18 @@
51
51
  "vitest": "^4.1.7"
52
52
  },
53
53
  "dependencies": {
54
- "@tldraw/state": "5.2.0-canary.6421dbe4e25a",
55
- "@tldraw/store": "5.2.0-canary.6421dbe4e25a",
56
- "@tldraw/utils": "5.2.0-canary.6421dbe4e25a",
57
- "@tldraw/validate": "5.2.0-canary.6421dbe4e25a"
54
+ "@tldraw/state": "5.2.0-canary.667cbd6bb6ff",
55
+ "@tldraw/store": "5.2.0-canary.667cbd6bb6ff",
56
+ "@tldraw/utils": "5.2.0-canary.667cbd6bb6ff",
57
+ "@tldraw/validate": "5.2.0-canary.667cbd6bb6ff"
58
58
  },
59
59
  "peerDependencies": {
60
60
  "react": "^18.2.0 || ^19.2.1",
61
61
  "react-dom": "^18.2.0 || ^19.2.1"
62
62
  },
63
+ "engines": {
64
+ "node": ">=22.12.0"
65
+ },
63
66
  "module": "dist-esm/index.mjs",
64
67
  "source": "src/index.ts",
65
68
  "exports": {
@@ -212,7 +212,11 @@ export const InstancePageStateRecordType = createRecordType<TLInstancePageState>
212
212
  ephemeralKeys: {
213
213
  pageId: false,
214
214
  selectedShapeIds: false,
215
- editingShapeId: false,
215
+ // editingShapeId is set with `history: 'ignore'`, so entering the editing
216
+ // state is never undoable. Marking it ephemeral keeps undo/redo from
217
+ // reapplying a stale editingShapeId (e.g. after a shape it pointed at was
218
+ // deleted), which could leave the editor pointing at a missing shape.
219
+ editingShapeId: true,
216
220
  croppingShapeId: false,
217
221
  meta: false,
218
222