@tldraw/editor 3.15.0-canary.bc8278557679 → 3.15.0-canary.c1b331d4edc1

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.
Files changed (135) hide show
  1. package/dist-cjs/index.d.ts +105 -44
  2. package/dist-cjs/index.js +18 -16
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/components/SVGContainer.js +1 -1
  5. package/dist-cjs/lib/components/SVGContainer.js.map +2 -2
  6. package/dist-cjs/lib/components/default-components/DefaultBrush.js +1 -1
  7. package/dist-cjs/lib/components/default-components/DefaultBrush.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -1
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +1 -1
  11. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +2 -2
  12. package/dist-cjs/lib/components/default-components/DefaultCursor.js +1 -1
  13. package/dist-cjs/lib/components/default-components/DefaultCursor.js.map +2 -2
  14. package/dist-cjs/lib/components/default-components/DefaultGrid.js +1 -1
  15. package/dist-cjs/lib/components/default-components/DefaultGrid.js.map +2 -2
  16. package/dist-cjs/lib/components/default-components/DefaultHandles.js +1 -1
  17. package/dist-cjs/lib/components/default-components/DefaultHandles.js.map +2 -2
  18. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +1 -1
  19. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  20. package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js +1 -1
  21. package/dist-cjs/lib/components/default-components/DefaultSnapIndictor.js.map +2 -2
  22. package/dist-cjs/lib/components/default-components/DefaultSpinner.js +27 -15
  23. package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +3 -3
  24. package/dist-cjs/lib/editor/Editor.js +24 -8
  25. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  26. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +96 -101
  27. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  28. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  29. package/dist-cjs/lib/editor/tools/StateNode.js +20 -1
  30. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  31. package/dist-cjs/lib/hooks/useEditorComponents.js.map +1 -1
  32. package/dist-cjs/lib/license/Watermark.js +2 -2
  33. package/dist-cjs/lib/license/Watermark.js.map +2 -2
  34. package/dist-cjs/lib/primitives/geometry/Arc2d.js +1 -1
  35. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  36. package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
  37. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
  38. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +3 -1
  39. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  40. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js +1 -1
  41. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
  42. package/dist-cjs/lib/primitives/geometry/geometry-constants.js +2 -2
  43. package/dist-cjs/lib/primitives/geometry/geometry-constants.js.map +2 -2
  44. package/dist-cjs/lib/primitives/intersect.js +4 -4
  45. package/dist-cjs/lib/primitives/intersect.js.map +2 -2
  46. package/dist-cjs/lib/primitives/utils.js +4 -0
  47. package/dist-cjs/lib/primitives/utils.js.map +2 -2
  48. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +0 -1
  49. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
  50. package/dist-cjs/version.js +3 -3
  51. package/dist-cjs/version.js.map +1 -1
  52. package/dist-esm/index.d.mts +105 -44
  53. package/dist-esm/index.mjs +43 -41
  54. package/dist-esm/index.mjs.map +2 -2
  55. package/dist-esm/lib/components/SVGContainer.mjs +1 -1
  56. package/dist-esm/lib/components/SVGContainer.mjs.map +2 -2
  57. package/dist-esm/lib/components/default-components/DefaultBrush.mjs +1 -1
  58. package/dist-esm/lib/components/default-components/DefaultBrush.mjs.map +2 -2
  59. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -1
  60. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  61. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +1 -1
  62. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +2 -2
  63. package/dist-esm/lib/components/default-components/DefaultCursor.mjs +1 -1
  64. package/dist-esm/lib/components/default-components/DefaultCursor.mjs.map +2 -2
  65. package/dist-esm/lib/components/default-components/DefaultGrid.mjs +1 -1
  66. package/dist-esm/lib/components/default-components/DefaultGrid.mjs.map +2 -2
  67. package/dist-esm/lib/components/default-components/DefaultHandles.mjs +1 -1
  68. package/dist-esm/lib/components/default-components/DefaultHandles.mjs.map +2 -2
  69. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +1 -1
  70. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  71. package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs +1 -1
  72. package/dist-esm/lib/components/default-components/DefaultSnapIndictor.mjs.map +2 -2
  73. package/dist-esm/lib/components/default-components/DefaultSpinner.mjs +17 -15
  74. package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
  75. package/dist-esm/lib/editor/Editor.mjs +24 -8
  76. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  77. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +96 -101
  78. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  79. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  80. package/dist-esm/lib/editor/tools/StateNode.mjs +20 -1
  81. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  82. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +1 -1
  83. package/dist-esm/lib/license/Watermark.mjs +2 -2
  84. package/dist-esm/lib/license/Watermark.mjs.map +2 -2
  85. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +2 -2
  86. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  87. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +2 -2
  88. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
  89. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +3 -1
  90. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  91. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs +2 -2
  92. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
  93. package/dist-esm/lib/primitives/geometry/geometry-constants.mjs +2 -2
  94. package/dist-esm/lib/primitives/geometry/geometry-constants.mjs.map +2 -2
  95. package/dist-esm/lib/primitives/intersect.mjs +5 -5
  96. package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
  97. package/dist-esm/lib/primitives/utils.mjs +4 -0
  98. package/dist-esm/lib/primitives/utils.mjs.map +2 -2
  99. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +0 -1
  100. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
  101. package/dist-esm/version.mjs +3 -3
  102. package/dist-esm/version.mjs.map +1 -1
  103. package/editor.css +17 -4
  104. package/package.json +9 -8
  105. package/src/index.ts +63 -62
  106. package/src/lib/components/SVGContainer.tsx +1 -1
  107. package/src/lib/components/default-components/DefaultBrush.tsx +1 -1
  108. package/src/lib/components/default-components/DefaultCanvas.tsx +1 -1
  109. package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +1 -1
  110. package/src/lib/components/default-components/DefaultCursor.tsx +1 -1
  111. package/src/lib/components/default-components/DefaultGrid.tsx +1 -1
  112. package/src/lib/components/default-components/DefaultHandles.tsx +5 -1
  113. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +1 -1
  114. package/src/lib/components/default-components/DefaultSnapIndictor.tsx +1 -1
  115. package/src/lib/components/default-components/DefaultSpinner.tsx +12 -12
  116. package/src/lib/editor/Editor.test.ts +407 -0
  117. package/src/lib/editor/Editor.ts +35 -9
  118. package/src/lib/editor/managers/TextManager/TextManager.ts +108 -128
  119. package/src/lib/editor/shapes/ShapeUtil.ts +57 -0
  120. package/src/lib/editor/tools/StateNode.test.ts +285 -0
  121. package/src/lib/editor/tools/StateNode.ts +27 -1
  122. package/src/lib/hooks/useEditorComponents.tsx +1 -1
  123. package/src/lib/license/LicenseManager.test.ts +1 -1
  124. package/src/lib/license/Watermark.tsx +2 -2
  125. package/src/lib/primitives/geometry/Arc2d.ts +2 -2
  126. package/src/lib/primitives/geometry/Circle2d.ts +2 -2
  127. package/src/lib/primitives/geometry/CubicBezier2d.ts +4 -1
  128. package/src/lib/primitives/geometry/Ellipse2d.ts +2 -2
  129. package/src/lib/primitives/geometry/geometry-constants.ts +2 -1
  130. package/src/lib/primitives/intersect.test.ts +946 -0
  131. package/src/lib/primitives/intersect.ts +12 -5
  132. package/src/lib/primitives/utils.ts +11 -0
  133. package/src/lib/utils/sync/TLLocalSyncClient.ts +0 -1
  134. package/src/version.ts +3 -3
  135. package/src/lib/test/currentToolIdMask.test.ts +0 -49
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/utils/sync/TLLocalSyncClient.ts"],
4
- "sourcesContent": ["import { Signal, transact } from '@tldraw/state'\nimport { RecordsDiff, SerializedSchema, UnknownRecord, squashRecordDiffs } from '@tldraw/store'\nimport { TLStore } from '@tldraw/tlschema'\nimport { assert } from '@tldraw/utils'\nimport {\n\tTAB_ID,\n\tTLSessionStateSnapshot,\n\tcreateSessionStateSnapshotSignal,\n\textractSessionStateFromLegacySnapshot,\n\tloadSessionStateSnapshotIntoStore,\n} from '../../config/TLSessionStateSnapshot'\nimport { LocalIndexedDb } from './LocalIndexedDb'\nimport { showCantReadFromIndexDbAlert, showCantWriteToIndexDbAlert } from './alerts'\n\n/** How should we debounce persists? */\nconst PERSIST_THROTTLE_MS = 350\n/** If we're in an error state, how long should we wait before retrying a write? */\nconst PERSIST_RETRY_THROTTLE_MS = 10_000\n\nconst UPDATE_INSTANCE_STATE = Symbol('UPDATE_INSTANCE_STATE')\n\n/**\n * IMPORTANT!!!\n *\n * This is just a quick-n-dirty temporary solution that will be replaced with the remote sync client\n * once it has the db integrated\n */\n\ninterface SyncMessage {\n\ttype: 'diff'\n\tstoreId: string\n\tchanges: RecordsDiff<UnknownRecord>\n\tschema: SerializedSchema\n}\n\n// Sent by new clients when they connect\n// If another client is on the channel with a newer schema version\n// It will\ninterface AnnounceMessage {\n\ttype: 'announce'\n\tschema: SerializedSchema\n}\n\ntype Message = SyncMessage | AnnounceMessage\n\ntype UnpackPromise<T> = T extends Promise<infer U> ? U : T\n\nconst msg = (msg: Message) => msg\n\n/** @internal */\nexport class BroadcastChannelMock {\n\tonmessage?: (e: MessageEvent) => void\n\tconstructor(_name: string) {\n\t\t// noop\n\t}\n\tpostMessage(_msg: Message) {\n\t\t// noop\n\t}\n\tclose() {\n\t\t// noop\n\t}\n}\n\nconst BC = typeof BroadcastChannel === 'undefined' ? BroadcastChannelMock : BroadcastChannel\n\n/** @internal */\nexport class TLLocalSyncClient {\n\tprivate disposables = new Set<() => void>()\n\tprivate diffQueue: Array<RecordsDiff<UnknownRecord> | typeof UPDATE_INSTANCE_STATE> = []\n\tprivate didDispose = false\n\tprivate shouldDoFullDBWrite = true\n\tprivate isReloading = false\n\treadonly persistenceKey: string\n\treadonly sessionId: string\n\treadonly serializedSchema: SerializedSchema\n\tprivate isDebugging = false\n\tprivate readonly documentTypes: ReadonlySet<string>\n\tprivate readonly $sessionStateSnapshot: Signal<TLSessionStateSnapshot | null>\n\t/** @internal */\n\treadonly db: LocalIndexedDb\n\n\tinitTime = Date.now()\n\tprivate debug(...args: any[]) {\n\t\tif (this.isDebugging) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug(...args)\n\t\t}\n\t}\n\tconstructor(\n\t\tpublic readonly store: TLStore,\n\t\t{\n\t\t\tpersistenceKey,\n\t\t\tsessionId = TAB_ID,\n\t\t\tonLoad,\n\t\t\tonLoadError,\n\t\t}: {\n\t\t\tpersistenceKey: string\n\t\t\tsessionId?: string\n\t\t\tonLoad(self: TLLocalSyncClient): void\n\t\t\tonLoadError(error: Error): void\n\t\t},\n\t\tpublic readonly channel = new BC(`tldraw-tab-sync-${persistenceKey}`)\n\t) {\n\t\tif (typeof window !== 'undefined') {\n\t\t\t;(window as any).tlsync = this\n\t\t}\n\t\tthis.persistenceKey = persistenceKey\n\t\tthis.sessionId = sessionId\n\t\tthis.db = new LocalIndexedDb(persistenceKey)\n\t\tthis.disposables.add(() => this.db.close())\n\n\t\tthis.serializedSchema = this.store.schema.serialize()\n\t\tthis.$sessionStateSnapshot = createSessionStateSnapshotSignal(this.store)\n\n\t\tthis.disposables.add(\n\t\t\t// Set up a subscription to changes from the store: When\n\t\t\t// the store changes (and if the change was made by the user)\n\t\t\t// then immediately send the diff to other tabs via postMessage\n\t\t\t// and schedule a persist.\n\t\t\tstore.listen(\n\t\t\t\t({ changes }) => {\n\t\t\t\t\tthis.diffQueue.push(changes)\n\t\t\t\t\tthis.channel.postMessage(\n\t\t\t\t\t\tmsg({\n\t\t\t\t\t\t\ttype: 'diff',\n\t\t\t\t\t\t\tstoreId: this.store.id,\n\t\t\t\t\t\t\tchanges,\n\t\t\t\t\t\t\tschema: this.serializedSchema,\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t\tthis.schedulePersist()\n\t\t\t\t},\n\t\t\t\t{ source: 'user', scope: 'document' }\n\t\t\t)\n\t\t)\n\t\tthis.disposables.add(\n\t\t\tstore.listen(\n\t\t\t\t() => {\n\t\t\t\t\tthis.diffQueue.push(UPDATE_INSTANCE_STATE)\n\t\t\t\t\tthis.schedulePersist()\n\t\t\t\t},\n\t\t\t\t{ scope: 'session' }\n\t\t\t)\n\t\t)\n\n\t\tthis.connect(onLoad, onLoadError)\n\n\t\tthis.documentTypes = new Set(\n\t\t\tObject.values(this.store.schema.types)\n\t\t\t\t.filter((t) => t.scope === 'document')\n\t\t\t\t.map((t) => t.typeName)\n\t\t)\n\t}\n\n\tprivate async connect(onLoad: (client: this) => void, onLoadError: (error: Error) => void) {\n\t\tthis.debug('connecting')\n\t\tlet data: UnpackPromise<ReturnType<LocalIndexedDb['load']>> | undefined\n\n\t\ttry {\n\t\t\tdata = await this.db.load({ sessionId: this.sessionId })\n\t\t} catch (error: any) {\n\t\t\tonLoadError(error)\n\t\t\tshowCantReadFromIndexDbAlert()\n\t\t\treturn\n\t\t}\n\n\t\tthis.debug('loaded data from store', data, 'didDispose', this.didDispose)\n\t\tif (this.didDispose) return\n\n\t\ttry {\n\t\t\tif (data) {\n\t\t\t\tconst documentSnapshot = Object.fromEntries(data.records.map((r) => [r.id, r]))\n\t\t\t\tconst sessionStateSnapshot =\n\t\t\t\t\tdata.sessionStateSnapshot ?? extractSessionStateFromLegacySnapshot(documentSnapshot)\n\t\t\t\tconst migrationResult = this.store.schema.migrateStoreSnapshot({\n\t\t\t\t\tstore: documentSnapshot,\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t\tschema: data.schema ?? this.store.schema.serializeEarliestVersion(),\n\t\t\t\t})\n\n\t\t\t\tif (migrationResult.type === 'error') {\n\t\t\t\t\tconsole.error('failed to migrate store', migrationResult)\n\t\t\t\t\tonLoadError(new Error(`Failed to migrate store: ${migrationResult.reason}`))\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst records = Object.values(migrationResult.value).filter((r) =>\n\t\t\t\t\tthis.documentTypes.has(r.typeName)\n\t\t\t\t)\n\t\t\t\tif (records.length > 0) {\n\t\t\t\t\t// 3. Merge the changes into the REAL STORE\n\t\t\t\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\t\t\t\t// Calling put will validate the records!\n\t\t\t\t\t\tthis.store.put(records, 'initialize')\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif (sessionStateSnapshot) {\n\t\t\t\t\tloadSessionStateSnapshotIntoStore(this.store, sessionStateSnapshot, {\n\t\t\t\t\t\tforceOverwrite: true,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.channel.onmessage = ({ data }) => {\n\t\t\t\tthis.debug('got message', data)\n\t\t\t\tconst msg = data as Message\n\t\t\t\t// if their schema is earlier than ours, we need to tell them so they can refresh\n\t\t\t\t// if their schema is later than ours, we need to refresh\n\t\t\t\tconst res = this.store.schema.getMigrationsSince(msg.schema)\n\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\t// we are older, refresh\n\t\t\t\t\t// but add a safety check to make sure we don't get in an infinite loop\n\t\t\t\t\tconst timeSinceInit = Date.now() - this.initTime\n\t\t\t\t\tif (timeSinceInit < 5000) {\n\t\t\t\t\t\t// This tab was just reloaded, but is out of date compared to other tabs.\n\t\t\t\t\t\t// Not expecting this to ever happen. It should only happen if we roll back a release that incremented\n\t\t\t\t\t\t// the schema version (which we should never do)\n\t\t\t\t\t\t// Or maybe during development if you have multiple local tabs open running the app on prod mode and you\n\t\t\t\t\t\t// check out an older commit. Dev server should be fine.\n\t\t\t\t\t\tonLoadError(new Error('Schema mismatch, please close other tabs and reload the page'))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tthis.debug('reloading')\n\t\t\t\t\tthis.isReloading = true\n\t\t\t\t\twindow?.location?.reload?.()\n\t\t\t\t\treturn\n\t\t\t\t} else if (res.value.length > 0) {\n\t\t\t\t\t// they are older, tell them to refresh and not write any more data\n\t\t\t\t\tthis.debug('telling them to reload')\n\t\t\t\t\tthis.channel.postMessage({ type: 'announce', schema: this.serializedSchema })\n\t\t\t\t\t// schedule a full db write in case they wrote data anyway\n\t\t\t\t\tthis.shouldDoFullDBWrite = true\n\t\t\t\t\tthis.persistIfNeeded()\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// otherwise, all good, same version :)\n\t\t\t\tif (msg.type === 'diff') {\n\t\t\t\t\tthis.debug('applying diff')\n\t\t\t\t\ttransact(() => {\n\t\t\t\t\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\t\t\t\t\tthis.store.applyDiff(msg.changes as any)\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.channel.postMessage({ type: 'announce', schema: this.serializedSchema })\n\t\t\tthis.disposables.add(() => {\n\t\t\t\tthis.channel.close()\n\t\t\t})\n\t\t\tonLoad(this)\n\t\t} catch (e: any) {\n\t\t\tthis.debug('error loading data from store', e)\n\t\t\tif (this.didDispose) return\n\t\t\tonLoadError(e)\n\t\t\treturn\n\t\t}\n\t}\n\n\tclose() {\n\t\tthis.debug('closing')\n\t\tthis.didDispose = true\n\t\tthis.disposables.forEach((d) => d())\n\t}\n\n\tprivate isPersisting = false\n\tprivate didLastWriteError = false\n\t// eslint-disable-next-line no-restricted-globals\n\tprivate scheduledPersistTimeout: ReturnType<typeof setTimeout> | null = null\n\n\t/**\n\t * Schedule a persist. Persists don't happen immediately: they are throttled to avoid writing too\n\t * often, and will retry if failed.\n\t *\n\t * @internal\n\t */\n\tprivate schedulePersist() {\n\t\tthis.debug('schedulePersist', this.scheduledPersistTimeout)\n\t\tif (this.scheduledPersistTimeout) return\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tthis.scheduledPersistTimeout = setTimeout(\n\t\t\t() => {\n\t\t\t\tthis.scheduledPersistTimeout = null\n\t\t\t\tthis.persistIfNeeded()\n\t\t\t},\n\t\t\tthis.didLastWriteError ? PERSIST_RETRY_THROTTLE_MS : PERSIST_THROTTLE_MS\n\t\t)\n\t}\n\n\t/**\n\t * Persist to IndexedDB only under certain circumstances:\n\t *\n\t * - If we're not already persisting\n\t * - If we're not reloading the page\n\t * - And we have something to persist (a full db write scheduled or changes in the diff queue)\n\t *\n\t * @internal\n\t */\n\tprivate persistIfNeeded() {\n\t\tthis.debug('persistIfNeeded', {\n\t\t\tisPersisting: this.isPersisting,\n\t\t\tisReloading: this.isReloading,\n\t\t\tshouldDoFullDBWrite: this.shouldDoFullDBWrite,\n\t\t\tdiffQueueLength: this.diffQueue.length,\n\t\t\tstoreIsPossiblyCorrupt: this.store.isPossiblyCorrupted(),\n\t\t})\n\n\t\t// if we've scheduled a persist for the future, that's no longer needed\n\t\tif (this.scheduledPersistTimeout) {\n\t\t\tclearTimeout(this.scheduledPersistTimeout)\n\t\t\tthis.scheduledPersistTimeout = null\n\t\t}\n\n\t\t// if a persist is already in progress, we don't need to do anything -\n\t\t// if there are still outstanding changes once it's finished, it'll\n\t\t// schedule another persist\n\t\tif (this.isPersisting) return\n\n\t\t// if we're reloading the page, it's because there's a newer client\n\t\t// present so lets not overwrite their changes\n\t\tif (this.isReloading) return\n\n\t\t// if the store is possibly corrupted, we don't want to persist\n\t\tif (this.store.isPossiblyCorrupted()) return\n\n\t\t// if we're scheduled for a full write or if we have changes outstanding, let's persist them!\n\t\tif (this.shouldDoFullDBWrite || this.diffQueue.length > 0) {\n\t\t\tthis.doPersist()\n\t\t}\n\t}\n\n\t/**\n\t * Actually persist to IndexedDB. If the write fails, then we'll retry with a full db write after\n\t * a short delay.\n\t */\n\tprivate async doPersist() {\n\t\tassert(!this.isPersisting, 'persist already in progress')\n\t\tif (this.didDispose) return\n\t\tthis.isPersisting = true\n\n\t\tthis.debug('doPersist start')\n\n\t\t// instantly empty the diff queue, but keep our own copy of it. this way\n\t\t// diffs that come in during the persist will still get tracked\n\t\tconst diffQueue = this.diffQueue\n\t\tthis.diffQueue = []\n\n\t\ttry {\n\t\t\tif (this.shouldDoFullDBWrite) {\n\t\t\t\tthis.shouldDoFullDBWrite = false\n\t\t\t\tawait this.db.storeSnapshot({\n\t\t\t\t\tschema: this.store.schema,\n\t\t\t\t\tsnapshot: this.store.serialize(),\n\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\tsessionStateSnapshot: this.$sessionStateSnapshot.get(),\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tconst diffs = squashRecordDiffs(\n\t\t\t\t\tdiffQueue.filter((d): d is RecordsDiff<UnknownRecord> => d !== UPDATE_INSTANCE_STATE)\n\t\t\t\t)\n\t\t\t\tawait this.db.storeChanges({\n\t\t\t\t\tchanges: diffs,\n\t\t\t\t\tschema: this.store.schema,\n\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\tsessionStateSnapshot: this.$sessionStateSnapshot.get(),\n\t\t\t\t})\n\t\t\t}\n\t\t\tthis.didLastWriteError = false\n\t\t} catch (e) {\n\t\t\t// set this.shouldDoFullDBWrite because we clear the diffQueue no matter what,\n\t\t\t// so if this is just a temporary error, we will still persist all changes\n\t\t\tthis.shouldDoFullDBWrite = true\n\t\t\tthis.didLastWriteError = true\n\t\t\tconsole.error('failed to store changes in indexed db', e)\n\n\t\t\tshowCantWriteToIndexDbAlert()\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\t// adios\n\t\t\t\twindow.location.reload()\n\t\t\t}\n\t\t}\n\n\t\tthis.isPersisting = false\n\t\tthis.debug('doPersist end')\n\n\t\t// changes might have come in between when we started the persist and\n\t\t// now. we request another persist so any new changes can get written\n\t\tthis.schedulePersist()\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Signal, transact } from '@tldraw/state'\nimport { RecordsDiff, SerializedSchema, UnknownRecord, squashRecordDiffs } from '@tldraw/store'\nimport { TLStore } from '@tldraw/tlschema'\nimport { assert } from '@tldraw/utils'\nimport {\n\tTAB_ID,\n\tTLSessionStateSnapshot,\n\tcreateSessionStateSnapshotSignal,\n\textractSessionStateFromLegacySnapshot,\n\tloadSessionStateSnapshotIntoStore,\n} from '../../config/TLSessionStateSnapshot'\nimport { LocalIndexedDb } from './LocalIndexedDb'\nimport { showCantReadFromIndexDbAlert, showCantWriteToIndexDbAlert } from './alerts'\n\n/** How should we debounce persists? */\nconst PERSIST_THROTTLE_MS = 350\n/** If we're in an error state, how long should we wait before retrying a write? */\nconst PERSIST_RETRY_THROTTLE_MS = 10_000\n\nconst UPDATE_INSTANCE_STATE = Symbol('UPDATE_INSTANCE_STATE')\n\n/**\n * IMPORTANT!!!\n *\n * This is just a quick-n-dirty temporary solution that will be replaced with the remote sync client\n * once it has the db integrated\n */\n\ninterface SyncMessage {\n\ttype: 'diff'\n\tstoreId: string\n\tchanges: RecordsDiff<UnknownRecord>\n\tschema: SerializedSchema\n}\n\n// Sent by new clients when they connect\n// If another client is on the channel with a newer schema version\n// It will\ninterface AnnounceMessage {\n\ttype: 'announce'\n\tschema: SerializedSchema\n}\n\ntype Message = SyncMessage | AnnounceMessage\n\ntype UnpackPromise<T> = T extends Promise<infer U> ? U : T\n\nconst msg = (msg: Message) => msg\n\n/** @internal */\nexport class BroadcastChannelMock {\n\tonmessage?: (e: MessageEvent) => void\n\tconstructor(_name: string) {\n\t\t// noop\n\t}\n\tpostMessage(_msg: Message) {\n\t\t// noop\n\t}\n\tclose() {\n\t\t// noop\n\t}\n}\n\nconst BC = typeof BroadcastChannel === 'undefined' ? BroadcastChannelMock : BroadcastChannel\n\n/** @internal */\nexport class TLLocalSyncClient {\n\tprivate disposables = new Set<() => void>()\n\tprivate diffQueue: Array<RecordsDiff<UnknownRecord> | typeof UPDATE_INSTANCE_STATE> = []\n\tprivate didDispose = false\n\tprivate shouldDoFullDBWrite = true\n\tprivate isReloading = false\n\treadonly persistenceKey: string\n\treadonly sessionId: string\n\treadonly serializedSchema: SerializedSchema\n\tprivate isDebugging = false\n\tprivate readonly documentTypes: ReadonlySet<string>\n\tprivate readonly $sessionStateSnapshot: Signal<TLSessionStateSnapshot | null>\n\t/** @internal */\n\treadonly db: LocalIndexedDb\n\n\tinitTime = Date.now()\n\tprivate debug(...args: any[]) {\n\t\tif (this.isDebugging) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug(...args)\n\t\t}\n\t}\n\tconstructor(\n\t\tpublic readonly store: TLStore,\n\t\t{\n\t\t\tpersistenceKey,\n\t\t\tsessionId = TAB_ID,\n\t\t\tonLoad,\n\t\t\tonLoadError,\n\t\t}: {\n\t\t\tpersistenceKey: string\n\t\t\tsessionId?: string\n\t\t\tonLoad(self: TLLocalSyncClient): void\n\t\t\tonLoadError(error: Error): void\n\t\t},\n\t\tpublic readonly channel = new BC(`tldraw-tab-sync-${persistenceKey}`)\n\t) {\n\t\tif (typeof window !== 'undefined') {\n\t\t\t;(window as any).tlsync = this\n\t\t}\n\t\tthis.persistenceKey = persistenceKey\n\t\tthis.sessionId = sessionId\n\t\tthis.db = new LocalIndexedDb(persistenceKey)\n\t\tthis.disposables.add(() => this.db.close())\n\n\t\tthis.serializedSchema = this.store.schema.serialize()\n\t\tthis.$sessionStateSnapshot = createSessionStateSnapshotSignal(this.store)\n\n\t\tthis.disposables.add(\n\t\t\t// Set up a subscription to changes from the store: When\n\t\t\t// the store changes (and if the change was made by the user)\n\t\t\t// then immediately send the diff to other tabs via postMessage\n\t\t\t// and schedule a persist.\n\t\t\tstore.listen(\n\t\t\t\t({ changes }) => {\n\t\t\t\t\tthis.diffQueue.push(changes)\n\t\t\t\t\tthis.channel.postMessage(\n\t\t\t\t\t\tmsg({\n\t\t\t\t\t\t\ttype: 'diff',\n\t\t\t\t\t\t\tstoreId: this.store.id,\n\t\t\t\t\t\t\tchanges,\n\t\t\t\t\t\t\tschema: this.serializedSchema,\n\t\t\t\t\t\t})\n\t\t\t\t\t)\n\t\t\t\t\tthis.schedulePersist()\n\t\t\t\t},\n\t\t\t\t{ source: 'user', scope: 'document' }\n\t\t\t)\n\t\t)\n\t\tthis.disposables.add(\n\t\t\tstore.listen(\n\t\t\t\t() => {\n\t\t\t\t\tthis.diffQueue.push(UPDATE_INSTANCE_STATE)\n\t\t\t\t\tthis.schedulePersist()\n\t\t\t\t},\n\t\t\t\t{ scope: 'session' }\n\t\t\t)\n\t\t)\n\n\t\tthis.connect(onLoad, onLoadError)\n\n\t\tthis.documentTypes = new Set(\n\t\t\tObject.values(this.store.schema.types)\n\t\t\t\t.filter((t) => t.scope === 'document')\n\t\t\t\t.map((t) => t.typeName)\n\t\t)\n\t}\n\n\tprivate async connect(onLoad: (client: this) => void, onLoadError: (error: Error) => void) {\n\t\tthis.debug('connecting')\n\t\tlet data: UnpackPromise<ReturnType<LocalIndexedDb['load']>> | undefined\n\n\t\ttry {\n\t\t\tdata = await this.db.load({ sessionId: this.sessionId })\n\t\t} catch (error: any) {\n\t\t\tonLoadError(error)\n\t\t\tshowCantReadFromIndexDbAlert()\n\t\t\treturn\n\t\t}\n\n\t\tthis.debug('loaded data from store', data, 'didDispose', this.didDispose)\n\t\tif (this.didDispose) return\n\n\t\ttry {\n\t\t\tif (data) {\n\t\t\t\tconst documentSnapshot = Object.fromEntries(data.records.map((r) => [r.id, r]))\n\t\t\t\tconst sessionStateSnapshot =\n\t\t\t\t\tdata.sessionStateSnapshot ?? extractSessionStateFromLegacySnapshot(documentSnapshot)\n\t\t\t\tconst migrationResult = this.store.schema.migrateStoreSnapshot({\n\t\t\t\t\tstore: documentSnapshot,\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\t\t\tschema: data.schema ?? this.store.schema.serializeEarliestVersion(),\n\t\t\t\t})\n\n\t\t\t\tif (migrationResult.type === 'error') {\n\t\t\t\t\tconsole.error('failed to migrate store', migrationResult)\n\t\t\t\t\tonLoadError(new Error(`Failed to migrate store: ${migrationResult.reason}`))\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tconst records = Object.values(migrationResult.value).filter((r) =>\n\t\t\t\t\tthis.documentTypes.has(r.typeName)\n\t\t\t\t)\n\t\t\t\tif (records.length > 0) {\n\t\t\t\t\t// 3. Merge the changes into the REAL STORE\n\t\t\t\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\t\t\t\t// Calling put will validate the records!\n\t\t\t\t\t\tthis.store.put(records, 'initialize')\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tif (sessionStateSnapshot) {\n\t\t\t\t\tloadSessionStateSnapshotIntoStore(this.store, sessionStateSnapshot, {\n\t\t\t\t\t\tforceOverwrite: true,\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.channel.onmessage = ({ data }) => {\n\t\t\t\tthis.debug('got message', data)\n\t\t\t\tconst msg = data as Message\n\t\t\t\t// if their schema is earlier than ours, we need to tell them so they can refresh\n\t\t\t\t// if their schema is later than ours, we need to refresh\n\t\t\t\tconst res = this.store.schema.getMigrationsSince(msg.schema)\n\n\t\t\t\tif (!res.ok) {\n\t\t\t\t\t// we are older, refresh\n\t\t\t\t\t// but add a safety check to make sure we don't get in an infinite loop\n\t\t\t\t\tconst timeSinceInit = Date.now() - this.initTime\n\t\t\t\t\tif (timeSinceInit < 5000) {\n\t\t\t\t\t\t// This tab was just reloaded, but is out of date compared to other tabs.\n\t\t\t\t\t\t// Not expecting this to ever happen. It should only happen if we roll back a release that incremented\n\t\t\t\t\t\t// the schema version (which we should never do)\n\t\t\t\t\t\t// Or maybe during development if you have multiple local tabs open running the app on prod mode and you\n\t\t\t\t\t\t// check out an older commit. Dev server should be fine.\n\t\t\t\t\t\tonLoadError(new Error('Schema mismatch, please close other tabs and reload the page'))\n\t\t\t\t\t\treturn\n\t\t\t\t\t}\n\t\t\t\t\tthis.debug('reloading')\n\t\t\t\t\tthis.isReloading = true\n\t\t\t\t\twindow?.location?.reload?.()\n\t\t\t\t\treturn\n\t\t\t\t} else if (res.value.length > 0) {\n\t\t\t\t\t// they are older, tell them to refresh and not write any more data\n\t\t\t\t\tthis.debug('telling them to reload')\n\t\t\t\t\tthis.channel.postMessage({ type: 'announce', schema: this.serializedSchema })\n\t\t\t\t\t// schedule a full db write in case they wrote data anyway\n\t\t\t\t\tthis.shouldDoFullDBWrite = true\n\t\t\t\t\tthis.persistIfNeeded()\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// otherwise, all good, same version :)\n\t\t\t\tif (msg.type === 'diff') {\n\t\t\t\t\tthis.debug('applying diff')\n\t\t\t\t\ttransact(() => {\n\t\t\t\t\t\tthis.store.mergeRemoteChanges(() => {\n\t\t\t\t\t\t\tthis.store.applyDiff(msg.changes as any)\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.channel.postMessage({ type: 'announce', schema: this.serializedSchema })\n\t\t\tthis.disposables.add(() => {\n\t\t\t\tthis.channel.close()\n\t\t\t})\n\t\t\tonLoad(this)\n\t\t} catch (e: any) {\n\t\t\tthis.debug('error loading data from store', e)\n\t\t\tif (this.didDispose) return\n\t\t\tonLoadError(e)\n\t\t\treturn\n\t\t}\n\t}\n\n\tclose() {\n\t\tthis.debug('closing')\n\t\tthis.didDispose = true\n\t\tthis.disposables.forEach((d) => d())\n\t}\n\n\tprivate isPersisting = false\n\tprivate didLastWriteError = false\n\tprivate scheduledPersistTimeout: ReturnType<typeof setTimeout> | null = null\n\n\t/**\n\t * Schedule a persist. Persists don't happen immediately: they are throttled to avoid writing too\n\t * often, and will retry if failed.\n\t *\n\t * @internal\n\t */\n\tprivate schedulePersist() {\n\t\tthis.debug('schedulePersist', this.scheduledPersistTimeout)\n\t\tif (this.scheduledPersistTimeout) return\n\t\t// eslint-disable-next-line no-restricted-globals\n\t\tthis.scheduledPersistTimeout = setTimeout(\n\t\t\t() => {\n\t\t\t\tthis.scheduledPersistTimeout = null\n\t\t\t\tthis.persistIfNeeded()\n\t\t\t},\n\t\t\tthis.didLastWriteError ? PERSIST_RETRY_THROTTLE_MS : PERSIST_THROTTLE_MS\n\t\t)\n\t}\n\n\t/**\n\t * Persist to IndexedDB only under certain circumstances:\n\t *\n\t * - If we're not already persisting\n\t * - If we're not reloading the page\n\t * - And we have something to persist (a full db write scheduled or changes in the diff queue)\n\t *\n\t * @internal\n\t */\n\tprivate persistIfNeeded() {\n\t\tthis.debug('persistIfNeeded', {\n\t\t\tisPersisting: this.isPersisting,\n\t\t\tisReloading: this.isReloading,\n\t\t\tshouldDoFullDBWrite: this.shouldDoFullDBWrite,\n\t\t\tdiffQueueLength: this.diffQueue.length,\n\t\t\tstoreIsPossiblyCorrupt: this.store.isPossiblyCorrupted(),\n\t\t})\n\n\t\t// if we've scheduled a persist for the future, that's no longer needed\n\t\tif (this.scheduledPersistTimeout) {\n\t\t\tclearTimeout(this.scheduledPersistTimeout)\n\t\t\tthis.scheduledPersistTimeout = null\n\t\t}\n\n\t\t// if a persist is already in progress, we don't need to do anything -\n\t\t// if there are still outstanding changes once it's finished, it'll\n\t\t// schedule another persist\n\t\tif (this.isPersisting) return\n\n\t\t// if we're reloading the page, it's because there's a newer client\n\t\t// present so lets not overwrite their changes\n\t\tif (this.isReloading) return\n\n\t\t// if the store is possibly corrupted, we don't want to persist\n\t\tif (this.store.isPossiblyCorrupted()) return\n\n\t\t// if we're scheduled for a full write or if we have changes outstanding, let's persist them!\n\t\tif (this.shouldDoFullDBWrite || this.diffQueue.length > 0) {\n\t\t\tthis.doPersist()\n\t\t}\n\t}\n\n\t/**\n\t * Actually persist to IndexedDB. If the write fails, then we'll retry with a full db write after\n\t * a short delay.\n\t */\n\tprivate async doPersist() {\n\t\tassert(!this.isPersisting, 'persist already in progress')\n\t\tif (this.didDispose) return\n\t\tthis.isPersisting = true\n\n\t\tthis.debug('doPersist start')\n\n\t\t// instantly empty the diff queue, but keep our own copy of it. this way\n\t\t// diffs that come in during the persist will still get tracked\n\t\tconst diffQueue = this.diffQueue\n\t\tthis.diffQueue = []\n\n\t\ttry {\n\t\t\tif (this.shouldDoFullDBWrite) {\n\t\t\t\tthis.shouldDoFullDBWrite = false\n\t\t\t\tawait this.db.storeSnapshot({\n\t\t\t\t\tschema: this.store.schema,\n\t\t\t\t\tsnapshot: this.store.serialize(),\n\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\tsessionStateSnapshot: this.$sessionStateSnapshot.get(),\n\t\t\t\t})\n\t\t\t} else {\n\t\t\t\tconst diffs = squashRecordDiffs(\n\t\t\t\t\tdiffQueue.filter((d): d is RecordsDiff<UnknownRecord> => d !== UPDATE_INSTANCE_STATE)\n\t\t\t\t)\n\t\t\t\tawait this.db.storeChanges({\n\t\t\t\t\tchanges: diffs,\n\t\t\t\t\tschema: this.store.schema,\n\t\t\t\t\tsessionId: this.sessionId,\n\t\t\t\t\tsessionStateSnapshot: this.$sessionStateSnapshot.get(),\n\t\t\t\t})\n\t\t\t}\n\t\t\tthis.didLastWriteError = false\n\t\t} catch (e) {\n\t\t\t// set this.shouldDoFullDBWrite because we clear the diffQueue no matter what,\n\t\t\t// so if this is just a temporary error, we will still persist all changes\n\t\t\tthis.shouldDoFullDBWrite = true\n\t\t\tthis.didLastWriteError = true\n\t\t\tconsole.error('failed to store changes in indexed db', e)\n\n\t\t\tshowCantWriteToIndexDbAlert()\n\t\t\tif (typeof window !== 'undefined') {\n\t\t\t\t// adios\n\t\t\t\twindow.location.reload()\n\t\t\t}\n\t\t}\n\n\t\tthis.isPersisting = false\n\t\tthis.debug('doPersist end')\n\n\t\t// changes might have come in between when we started the persist and\n\t\t// now. we request another persist so any new changes can get written\n\t\tthis.schedulePersist()\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["msg", "data"]
7
7
  }
@@ -22,10 +22,10 @@ __export(version_exports, {
22
22
  version: () => version
23
23
  });
24
24
  module.exports = __toCommonJS(version_exports);
25
- const version = "3.15.0-canary.bc8278557679";
25
+ const version = "3.15.0-canary.c1b331d4edc1";
26
26
  const publishDates = {
27
27
  major: "2024-09-13T14:36:29.063Z",
28
- minor: "2025-07-04T10:03:34.185Z",
29
- patch: "2025-07-04T10:03:34.185Z"
28
+ minor: "2025-07-25T11:08:42.848Z",
29
+ patch: "2025-07-25T11:08:42.848Z"
30
30
  };
31
31
  //# sourceMappingURL=version.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.15.0-canary.bc8278557679'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-07-04T10:03:34.185Z',\n\tpatch: '2025-07-04T10:03:34.185Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.15.0-canary.c1b331d4edc1'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-07-25T11:08:42.848Z',\n\tpatch: '2025-07-25T11:08:42.848Z',\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,3 @@
1
- /// <reference types="react" />
2
-
3
1
  import { Atom } from '@tldraw/state';
4
2
  import { BoxModel } from '@tldraw/tlschema';
5
3
  import { ComponentType } from 'react';
@@ -19,8 +17,8 @@ import { NamedExoticComponent } from 'react';
19
17
  import { Node as Node_2 } from '@tiptap/pm/model';
20
18
  import { PerformanceTracker } from '@tldraw/utils';
21
19
  import { PointerEventHandler } from 'react';
22
- import { default as React_2 } from 'react';
23
- import * as React_3 from 'react';
20
+ import * as React_2 from 'react';
21
+ import { default as React_3 } from 'react';
24
22
  import { ReactElement } from 'react';
25
23
  import { ReactNode } from 'react';
26
24
  import { RecordProps } from '@tldraw/tlschema';
@@ -59,6 +57,7 @@ import { TLImageAsset } from '@tldraw/tlschema';
59
57
  import { TLInstance } from '@tldraw/tlschema';
60
58
  import { TLInstancePageState } from '@tldraw/tlschema';
61
59
  import { TLInstancePresence } from '@tldraw/tlschema';
60
+ import { TLOpacityType } from '@tldraw/tlschema';
62
61
  import { TLPage } from '@tldraw/tlschema';
63
62
  import { TLPageId } from '@tldraw/tlschema';
64
63
  import { TLParentId } from '@tldraw/tlschema';
@@ -716,8 +715,8 @@ export declare function createTLStore({ initialData, defaultName, id, assets, on
716
715
 
717
716
  /** @public */
718
717
  export declare function createTLUser(opts?: {
719
- setUserPreferences?: ((userPreferences: TLUserPreferences) => void) | undefined;
720
- userPreferences?: Signal<TLUserPreferences, unknown> | undefined;
718
+ setUserPreferences?: (userPreferences: TLUserPreferences) => void;
719
+ userPreferences?: Signal<TLUserPreferences>;
721
720
  }): TLUser;
722
721
 
723
722
  /** @public */
@@ -726,10 +725,12 @@ export declare class CubicBezier2d extends Polyline2d {
726
725
  private _b;
727
726
  private _c;
728
727
  private _d;
728
+ private _resolution;
729
729
  constructor(config: Omit<Geometry2dOptions, 'isClosed' | 'isFilled'> & {
730
730
  cp1: Vec;
731
731
  cp2: Vec;
732
732
  end: Vec;
733
+ resolution?: number;
733
734
  start: Vec;
734
735
  });
735
736
  getVertices(): Vec[];
@@ -820,7 +821,7 @@ export declare const DefaultShapeIndicators: NamedExoticComponent<TLShapeIndicat
820
821
  export declare function DefaultSnapIndicator({ className, line, zoom }: TLSnapIndicatorProps): JSX_2.Element;
821
822
 
822
823
  /** @public @react */
823
- export declare function DefaultSpinner(): JSX_2.Element;
824
+ export declare function DefaultSpinner(props: React.SVGProps<SVGSVGElement>): JSX_2.Element;
824
825
 
825
826
  /** @public @react */
826
827
  export declare const DefaultSvgDefs: () => null;
@@ -848,7 +849,7 @@ export declare const defaultTldrawOptions: {
848
849
  readonly edgeScrollSpeed: 25;
849
850
  readonly enableToolbarKeyboardShortcuts: true;
850
851
  readonly exportProvider: ExoticComponent< {
851
- children?: ReactNode;
852
+ children?: ReactNode | undefined;
852
853
  }>;
853
854
  readonly flattenImageBoundsExpand: 64;
854
855
  readonly flattenImageBoundsPadding: 16;
@@ -1019,8 +1020,8 @@ export declare class Editor extends EventEmitter<TLEventMap> {
1019
1020
  readonly timers: {
1020
1021
  dispose: () => void;
1021
1022
  requestAnimationFrame: (callback: FrameRequestCallback) => number;
1022
- setInterval: (handler: TimerHandler, timeout?: number | undefined, ...args: any[]) => number;
1023
- setTimeout: (handler: TimerHandler, timeout?: number | undefined, ...args: any[]) => number;
1023
+ setInterval: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
1024
+ setTimeout: (handler: TimerHandler, timeout?: number, ...args: any[]) => number;
1024
1025
  };
1025
1026
  /**
1026
1027
  * A manager for the user and their preferences.
@@ -1554,7 +1555,9 @@ export declare class Editor extends EventEmitter<TLEventMap> {
1554
1555
  */
1555
1556
  deselect(...shapes: TLShape[] | TLShapeId[]): this;
1556
1557
  /**
1557
- * Select all direct children of the current page.
1558
+ * Select all shapes. If the user has selected shapes that share a parent,
1559
+ * select all shapes within that parent. If the user has not selected any shapes,
1560
+ * or if the shapes shapes are only on select all shapes on the current page.
1558
1561
  *
1559
1562
  * @example
1560
1563
  * ```ts
@@ -1588,7 +1591,7 @@ export declare class Editor extends EventEmitter<TLEventMap> {
1588
1591
  *
1589
1592
  * @public
1590
1593
  */
1591
- getNearestAdjacentShape(currentShapeId: TLShapeId, direction: 'down' | 'left' | 'right' | 'up'): TLShapeId;
1594
+ getNearestAdjacentShape(shapes: TLShape[], currentShapeId: TLShapeId, direction: 'down' | 'left' | 'right' | 'up'): TLShapeId;
1592
1595
  selectParentShape(): void;
1593
1596
  selectFirstChildShape(): void;
1594
1597
  private _selectShapesAndZoom;
@@ -2069,10 +2072,10 @@ export declare class Editor extends EventEmitter<TLEventMap> {
2069
2072
  */
2070
2073
  slideCamera(opts?: {
2071
2074
  direction: VecLike;
2072
- force?: boolean | undefined;
2073
- friction?: number | undefined;
2075
+ force?: boolean;
2076
+ friction?: number;
2074
2077
  speed: number;
2075
- speedThreshold?: number | undefined;
2078
+ speedThreshold?: number;
2076
2079
  }): this;
2077
2080
  /**
2078
2081
  * Animate the camera to a user's cursor position. This also briefly show the user's cursor if it's not currently visible.
@@ -2684,12 +2687,12 @@ export declare class Editor extends EventEmitter<TLEventMap> {
2684
2687
  */
2685
2688
  getShapeAtPoint(point: VecLike, opts?: {
2686
2689
  filter?(shape: TLShape): boolean;
2687
- hitFrameInside?: boolean | undefined;
2688
- hitInside?: boolean | undefined;
2689
- hitLabels?: boolean | undefined;
2690
- hitLocked?: boolean | undefined;
2691
- margin?: number | undefined;
2692
- renderingOnly?: boolean | undefined;
2690
+ hitFrameInside?: boolean;
2691
+ hitInside?: boolean;
2692
+ hitLabels?: boolean;
2693
+ hitLocked?: boolean;
2694
+ margin?: number;
2695
+ renderingOnly?: boolean;
2693
2696
  }): TLShape | undefined;
2694
2697
  /**
2695
2698
  * Get the shapes, if any, at a given page point.
@@ -2708,8 +2711,8 @@ export declare class Editor extends EventEmitter<TLEventMap> {
2708
2711
  * @public
2709
2712
  */
2710
2713
  getShapesAtPoint(point: VecLike, opts?: {
2711
- hitInside?: boolean | undefined;
2712
- margin?: number | undefined;
2714
+ hitInside?: boolean;
2715
+ margin?: number;
2713
2716
  }): TLShape[];
2714
2717
  /**
2715
2718
  * Test whether a point (in the current page space) will will a shape. This method takes into account masks,
@@ -2727,8 +2730,8 @@ export declare class Editor extends EventEmitter<TLEventMap> {
2727
2730
  * @public
2728
2731
  */
2729
2732
  isPointInShape(shape: TLShape | TLShapeId, point: VecLike, opts?: {
2730
- hitInside?: boolean | undefined;
2731
- margin?: number | undefined;
2733
+ hitInside?: boolean;
2734
+ margin?: number;
2732
2735
  }): boolean;
2733
2736
  /**
2734
2737
  * Convert a point in the current page space to a point in the local space of a shape. For example, if a
@@ -4014,7 +4017,7 @@ export declare class Editor extends EventEmitter<TLEventMap> {
4014
4017
  }
4015
4018
 
4016
4019
  /** @public */
4017
- export declare const EditorContext: React_2.Context<Editor | null>;
4020
+ export declare const EditorContext: React_3.Context<Editor | null>;
4018
4021
 
4019
4022
  /** @public @react */
4020
4023
  export declare function EditorProvider({ editor, children }: EditorProviderProps): JSX_2.Element;
@@ -4022,7 +4025,7 @@ export declare function EditorProvider({ editor, children }: EditorProviderProps
4022
4025
  /** @public */
4023
4026
  export declare interface EditorProviderProps {
4024
4027
  editor: Editor;
4025
- children: React_2.ReactNode;
4028
+ children: React_3.ReactNode;
4026
4029
  }
4027
4030
 
4028
4031
  /** @public */
@@ -4048,7 +4051,7 @@ export declare class Ellipse2d extends Geometry2d {
4048
4051
  }
4049
4052
 
4050
4053
  /** @public */
4051
- export declare class ErrorBoundary extends React_3.Component<React_3.PropsWithRef<React_3.PropsWithChildren<TLErrorBoundaryProps>>, {
4054
+ export declare class ErrorBoundary extends React_2.Component<React_2.PropsWithRef<React_2.PropsWithChildren<TLErrorBoundaryProps>>, {
4052
4055
  error: Error | null;
4053
4056
  }> {
4054
4057
  static getDerivedStateFromError(error: Error): {
@@ -4058,7 +4061,7 @@ export declare class ErrorBoundary extends React_3.Component<React_3.PropsWithRe
4058
4061
  error: null;
4059
4062
  };
4060
4063
  componentDidCatch(error: unknown): void;
4061
- render(): boolean | JSX_2.Element | Iterable<React_3.ReactNode> | null | number | string | undefined;
4064
+ render(): boolean | JSX_2.Element | Iterable<React_2.ReactNode> | null | number | string | undefined;
4062
4065
  }
4063
4066
 
4064
4067
  /** @public @react */
@@ -4319,6 +4322,8 @@ export declare function getSvgPathFromPoints(points: VecLike[], closed?: boolean
4319
4322
  /** @public */
4320
4323
  export declare function getUserPreferences(): TLUserPreferences;
4321
4324
 
4325
+ /* Excluded from this release type: getVerticesCountForArcLength */
4326
+
4322
4327
  /** @public */
4323
4328
  export declare class Group2d extends Geometry2d {
4324
4329
  children: Geometry2d[];
@@ -4462,7 +4467,7 @@ export declare class HistoryManager<R extends UnknownRecord> {
4462
4467
  export declare function HTMLContainer({ children, className, ...rest }: HTMLContainerProps): JSX_2.Element;
4463
4468
 
4464
4469
  /** @public */
4465
- export declare type HTMLContainerProps = React_3.HTMLAttributes<HTMLDivElement>;
4470
+ export declare type HTMLContainerProps = React_2.HTMLAttributes<HTMLDivElement>;
4466
4471
 
4467
4472
  /** @public */
4468
4473
  export declare const inlineBase64AssetStore: TLAssetStore;
@@ -4518,7 +4523,7 @@ export declare function intersectLineSegmentCircle(a1: VecLike, a2: VecLike, c:
4518
4523
  * @param b2 - The second segment's second point.
4519
4524
  * @public
4520
4525
  */
4521
- export declare function intersectLineSegmentLineSegment(a1: VecLike, a2: VecLike, b1: VecLike, b2: VecLike): null | Vec;
4526
+ export declare function intersectLineSegmentLineSegment(a1: VecLike, a2: VecLike, b1: VecLike, b2: VecLike, precision?: number): null | Vec;
4522
4527
 
4523
4528
  /**
4524
4529
  * Find the intersections between a line segment and a closed polygon.
@@ -4824,7 +4829,7 @@ export declare function precise(A: VecLike): string;
4824
4829
  * @param event - To prevent default on
4825
4830
  * @public
4826
4831
  */
4827
- export declare function preventDefault(event: Event | React_2.BaseSyntheticEvent): void;
4832
+ export declare function preventDefault(event: Event | React_3.BaseSyntheticEvent): void;
4828
4833
 
4829
4834
  /**
4830
4835
  * Convert radians to degrees.
@@ -4859,10 +4864,10 @@ export declare class ReadonlySharedStyleMap {
4859
4864
  getAsKnownValue<T>(prop: StyleProp<T>): T | undefined;
4860
4865
  get size(): number;
4861
4866
  equals(other: ReadonlySharedStyleMap): boolean;
4862
- keys(): IterableIterator<StyleProp<any>>;
4863
- values(): IterableIterator<SharedStyle<unknown>>;
4864
- entries(): IterableIterator<[StyleProp<any>, SharedStyle<unknown>]>;
4865
- [Symbol.iterator](): IterableIterator<[StyleProp<any>, SharedStyle<unknown>]>;
4867
+ keys(): MapIterator<StyleProp<any>>;
4868
+ values(): MapIterator<SharedStyle<unknown>>;
4869
+ entries(): MapIterator<[StyleProp<any>, SharedStyle<unknown>]>;
4870
+ [Symbol.iterator](): MapIterator<[StyleProp<any>, SharedStyle<unknown>]>;
4866
4871
  }
4867
4872
 
4868
4873
  /** @public */
@@ -4886,7 +4891,7 @@ export declare class Rectangle2d extends Polygon2d {
4886
4891
  export declare function refreshPage(): void;
4887
4892
 
4888
4893
  /** @public */
4889
- export declare function releasePointerCapture(element: Element, event: PointerEvent | React_2.PointerEvent<Element>): void;
4894
+ export declare function releasePointerCapture(element: Element, event: PointerEvent | React_3.PointerEvent<Element>): void;
4890
4895
 
4891
4896
  /** @public */
4892
4897
  export declare type RequiredKeys<T, K extends keyof T> = Required<Pick<T, K>> & Omit<T, K>;
@@ -5029,7 +5034,7 @@ export declare type SelectionEdge = 'bottom' | 'left' | 'right' | 'top';
5029
5034
  export declare type SelectionHandle = SelectionCorner | SelectionEdge;
5030
5035
 
5031
5036
  /** @public */
5032
- export declare function setPointerCapture(element: Element, event: PointerEvent | React_2.PointerEvent<Element>): void;
5037
+ export declare function setPointerCapture(element: Element, event: PointerEvent | React_3.PointerEvent<Element>): void;
5033
5038
 
5034
5039
  /** @public */
5035
5040
  export declare function setRuntimeOverrides(input: Partial<typeof runtime>): void;
@@ -5413,6 +5418,14 @@ export declare abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknown
5413
5418
  * @public
5414
5419
  */
5415
5420
  onResizeEnd?(initial: Shape, current: Shape): TLShapePartial<Shape> | void;
5421
+ /**
5422
+ * A callback called when a shape resize is cancelled.
5423
+ *
5424
+ * @param initial - The shape at the start of the resize.
5425
+ * @param current - The current shape.
5426
+ * @public
5427
+ */
5428
+ onResizeCancel?(initial: Shape, current: Shape): void;
5416
5429
  /**
5417
5430
  * A callback called when a shape starts being translated.
5418
5431
  *
@@ -5439,6 +5452,23 @@ export declare abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknown
5439
5452
  * @public
5440
5453
  */
5441
5454
  onTranslateEnd?(initial: Shape, current: Shape): TLShapePartial<Shape> | void;
5455
+ /**
5456
+ * A callback called when a shape translation is cancelled.
5457
+ *
5458
+ * @param initial - The shape at the start of the translation.
5459
+ * @param current - The current shape.
5460
+ * @public
5461
+ */
5462
+ onTranslateCancel?(initial: Shape, current: Shape): void;
5463
+ /**
5464
+ * A callback called when a shape's handle starts being dragged.
5465
+ *
5466
+ * @param shape - The shape.
5467
+ * @param info - An object containing the handle and whether the handle is 'precise' or not.
5468
+ * @returns A change to apply to the shape, or void.
5469
+ * @public
5470
+ */
5471
+ onHandleDragStart?(shape: Shape, info: TLHandleDragInfo<Shape>): TLShapePartial<Shape> | void;
5442
5472
  /**
5443
5473
  * A callback called when a shape's handle changes.
5444
5474
  *
@@ -5448,6 +5478,23 @@ export declare abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknown
5448
5478
  * @public
5449
5479
  */
5450
5480
  onHandleDrag?(shape: Shape, info: TLHandleDragInfo<Shape>): TLShapePartial<Shape> | void;
5481
+ /**
5482
+ * A callback called when a shape's handle finishes being dragged.
5483
+ *
5484
+ * @param current - The current shape.
5485
+ * @param info - An object containing the handle and whether the handle is 'precise' or not.
5486
+ * @returns A change to apply to the shape, or void.
5487
+ * @public
5488
+ */
5489
+ onHandleDragEnd?(current: Shape, info: TLHandleDragInfo<Shape>): TLShapePartial<Shape> | void;
5490
+ /**
5491
+ * A callback called when a shape's handle drag is cancelled.
5492
+ *
5493
+ * @param current - The current shape.
5494
+ * @param info - An object containing the handle and whether the handle is 'precise' or not.
5495
+ * @public
5496
+ */
5497
+ onHandleDragCancel?(current: Shape, info: TLHandleDragInfo<Shape>): void;
5451
5498
  /**
5452
5499
  * A callback called when a shape starts being rotated.
5453
5500
  *
@@ -5474,6 +5521,14 @@ export declare abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknown
5474
5521
  * @public
5475
5522
  */
5476
5523
  onRotateEnd?(initial: Shape, current: Shape): TLShapePartial<Shape> | void;
5524
+ /**
5525
+ * A callback called when a shape rotation is cancelled.
5526
+ *
5527
+ * @param initial - The shape at the start of the rotation.
5528
+ * @param current - The current shape.
5529
+ * @public
5530
+ */
5531
+ onRotateCancel?(initial: Shape, current: Shape): void;
5477
5532
  /* Excluded from this release type: onBindingChange */
5478
5533
  /**
5479
5534
  * A callback called when a shape's children change.
@@ -5702,6 +5757,12 @@ export declare abstract class StateNode implements Partial<TLEventHandlers> {
5702
5757
  _currentToolIdMask: Atom<string | undefined, unknown>;
5703
5758
  getCurrentToolIdMask(): string | undefined;
5704
5759
  setCurrentToolIdMask(id: string | undefined): void;
5760
+ /**
5761
+ * Add a child node to this state node.
5762
+ *
5763
+ * @public
5764
+ */
5765
+ addChild(childConstructor: TLStateNodeConstructor): this;
5705
5766
  onWheel?(info: TLWheelEventInfo): void;
5706
5767
  onPointerDown?(info: TLPointerEventInfo): void;
5707
5768
  onPointerMove?(info: TLPointerEventInfo): void;
@@ -5735,7 +5796,7 @@ export declare function suffixSafeId(id: SafeId, suffix: string): SafeId;
5735
5796
  export declare function SVGContainer({ children, className, ...rest }: SVGContainerProps): JSX_2.Element;
5736
5797
 
5737
5798
  /** @public */
5738
- export declare type SVGContainerProps = React_3.ComponentProps<'svg'>;
5799
+ export declare type SVGContainerProps = React_2.ComponentProps<'svg'>;
5739
5800
 
5740
5801
  /** @public */
5741
5802
  export declare interface SvgExportContext {
@@ -5796,10 +5857,9 @@ export declare const TAB_ID: string;
5796
5857
  export declare class TextManager {
5797
5858
  editor: Editor;
5798
5859
  private elm;
5799
- private defaultStyles;
5800
5860
  constructor(editor: Editor);
5861
+ private setElementStyles;
5801
5862
  dispose(): void;
5802
- private resetElmStyles;
5803
5863
  measureText(textToMeasure: string, opts: TLMeasureTextOpts): BoxModel & {
5804
5864
  scrollWidth: number;
5805
5865
  };
@@ -6143,7 +6203,7 @@ export declare interface TLDragShapesOverInfo {
6143
6203
  }
6144
6204
 
6145
6205
  /** @public @react */
6146
- export declare const TldrawEditor: React_2.NamedExoticComponent<TldrawEditorProps>;
6206
+ export declare const TldrawEditor: React_3.NamedExoticComponent<TldrawEditorProps>;
6147
6207
 
6148
6208
  /**
6149
6209
  * Base props for the {@link tldraw#Tldraw} and {@link TldrawEditor} components.
@@ -6420,7 +6480,7 @@ export declare interface TLEditorComponents {
6420
6480
  ShapeIndicator?: ComponentType<TLShapeIndicatorProps> | null;
6421
6481
  ShapeIndicators?: ComponentType | null;
6422
6482
  SnapIndicator?: ComponentType<TLSnapIndicatorProps> | null;
6423
- Spinner?: ComponentType | null;
6483
+ Spinner?: ComponentType<React.SVGProps<SVGSVGElement>> | null;
6424
6484
  SvgDefs?: ComponentType | null;
6425
6485
  ZoomBrush?: ComponentType<TLBrushProps> | null;
6426
6486
  ErrorFallback?: TLErrorFallbackComponent;
@@ -6547,7 +6607,7 @@ export declare const tlenv: {
6547
6607
 
6548
6608
  /** @public */
6549
6609
  export declare interface TLErrorBoundaryProps {
6550
- children: React_3.ReactNode;
6610
+ children: React_2.ReactNode;
6551
6611
  onError?: ((error: unknown) => void) | null;
6552
6612
  fallback: TLErrorFallbackComponent;
6553
6613
  }
@@ -6766,6 +6826,7 @@ export declare interface TLGridProps {
6766
6826
  export declare interface TLHandleDragInfo<T extends TLShape> {
6767
6827
  handle: TLHandle;
6768
6828
  isPrecise: boolean;
6829
+ isCreatingShape: boolean;
6769
6830
  initial?: T | undefined;
6770
6831
  }
6771
6832