@tldraw/editor 3.14.0-canary.cf19563e117d → 3.14.0-canary.d15c939851b6

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 (107) hide show
  1. package/dist-cjs/index.d.ts +155 -55
  2. package/dist-cjs/index.js +4 -3
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/config/TLSessionStateSnapshot.js +1 -12
  5. package/dist-cjs/lib/config/TLSessionStateSnapshot.js.map +3 -3
  6. package/dist-cjs/lib/editor/Editor.js +90 -30
  7. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  8. package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +2 -2
  9. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +1 -2
  10. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
  11. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +3 -1
  12. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
  13. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +73 -42
  14. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  15. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +0 -10
  16. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  17. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +1 -1
  18. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +1 -1
  19. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +13 -6
  20. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +3 -3
  21. package/dist-cjs/lib/editor/tools/StateNode.js +3 -3
  22. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  23. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  24. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  25. package/dist-cjs/lib/hooks/useCanvasEvents.js +1 -2
  26. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  27. package/dist-cjs/lib/primitives/Box.js +0 -6
  28. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  29. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +6 -2
  30. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  31. package/dist-cjs/lib/primitives/geometry/Group2d.js +11 -6
  32. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  33. package/dist-cjs/lib/utils/areShapesContentEqual.js +1 -1
  34. package/dist-cjs/lib/utils/areShapesContentEqual.js.map +2 -2
  35. package/dist-cjs/lib/utils/dom.js +1 -1
  36. package/dist-cjs/lib/utils/dom.js.map +2 -2
  37. package/dist-cjs/lib/utils/reparenting.js +232 -0
  38. package/dist-cjs/lib/utils/reparenting.js.map +7 -0
  39. package/dist-cjs/lib/utils/richText.js +7 -2
  40. package/dist-cjs/lib/utils/richText.js.map +2 -2
  41. package/dist-cjs/version.js +3 -3
  42. package/dist-cjs/version.js.map +1 -1
  43. package/dist-esm/index.d.mts +155 -55
  44. package/dist-esm/index.mjs +4 -3
  45. package/dist-esm/index.mjs.map +2 -2
  46. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs +1 -1
  47. package/dist-esm/lib/config/TLSessionStateSnapshot.mjs.map +2 -2
  48. package/dist-esm/lib/editor/Editor.mjs +90 -30
  49. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  50. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +2 -2
  51. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +1 -2
  52. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
  53. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +3 -1
  54. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
  55. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +73 -42
  56. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  57. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +0 -10
  58. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  59. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +1 -1
  60. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +1 -1
  61. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +13 -6
  62. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +3 -3
  63. package/dist-esm/lib/editor/tools/StateNode.mjs +3 -3
  64. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  65. package/dist-esm/lib/hooks/useCanvasEvents.mjs +1 -2
  66. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  67. package/dist-esm/lib/primitives/Box.mjs +0 -6
  68. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  69. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +6 -2
  70. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  71. package/dist-esm/lib/primitives/geometry/Group2d.mjs +11 -6
  72. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  73. package/dist-esm/lib/utils/areShapesContentEqual.mjs +1 -1
  74. package/dist-esm/lib/utils/areShapesContentEqual.mjs.map +2 -2
  75. package/dist-esm/lib/utils/dom.mjs +1 -1
  76. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  77. package/dist-esm/lib/utils/reparenting.mjs +216 -0
  78. package/dist-esm/lib/utils/reparenting.mjs.map +7 -0
  79. package/dist-esm/lib/utils/richText.mjs +8 -3
  80. package/dist-esm/lib/utils/richText.mjs.map +2 -2
  81. package/dist-esm/version.mjs +3 -3
  82. package/dist-esm/version.mjs.map +1 -1
  83. package/editor.css +446 -489
  84. package/package.json +8 -9
  85. package/src/index.ts +7 -1
  86. package/src/lib/config/TLSessionStateSnapshot.ts +1 -1
  87. package/src/lib/editor/Editor.ts +107 -38
  88. package/src/lib/editor/bindings/BindingUtil.ts +6 -0
  89. package/src/lib/editor/managers/FontManager/FontManager.ts +1 -2
  90. package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +3 -1
  91. package/src/lib/editor/managers/TextManager/TextManager.test.ts +1 -5
  92. package/src/lib/editor/managers/TextManager/TextManager.ts +118 -86
  93. package/src/lib/editor/shapes/ShapeUtil.ts +47 -15
  94. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -1
  95. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +25 -17
  96. package/src/lib/editor/tools/StateNode.ts +3 -3
  97. package/src/lib/editor/types/emit-types.ts +4 -0
  98. package/src/lib/editor/types/external-content.ts +11 -2
  99. package/src/lib/hooks/useCanvasEvents.ts +0 -1
  100. package/src/lib/primitives/Box.ts +0 -8
  101. package/src/lib/primitives/geometry/Geometry2d.ts +7 -2
  102. package/src/lib/primitives/geometry/Group2d.ts +11 -5
  103. package/src/lib/utils/areShapesContentEqual.ts +1 -2
  104. package/src/lib/utils/dom.ts +1 -1
  105. package/src/lib/utils/reparenting.ts +383 -0
  106. package/src/lib/utils/richText.ts +9 -3
  107. package/src/version.ts +3 -3
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/config/TLSessionStateSnapshot.ts"],
4
- "sourcesContent": ["import { Signal, computed } from '@tldraw/state'\nimport { UnknownRecord } from '@tldraw/store'\nimport {\n\tCameraRecordType,\n\tInstancePageStateRecordType,\n\tTLINSTANCE_ID,\n\tTLPageId,\n\tTLShapeId,\n\tTLStore,\n\tpageIdValidator,\n\tpluckPreservingValues,\n\tshapeIdValidator,\n} from '@tldraw/tlschema'\nimport {\n\tdeleteFromSessionStorage,\n\tgetFromSessionStorage,\n\tsetInSessionStorage,\n\tstructuredClone,\n\tuniqueId,\n} from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport isEqual from 'lodash.isequal'\nimport { tlenv } from '../globals/environment'\n\nconst tabIdKey = 'TLDRAW_TAB_ID_v2' as const\n\nconst window = globalThis.window as\n\t| {\n\t\t\tnavigator: Window['navigator']\n\t\t\taddEventListener: Window['addEventListener']\n\t\t\tTLDRAW_TAB_ID_v2?: string\n\t }\n\t| undefined\n\n// https://stackoverflow.com/a/9039885\nfunction iOS() {\n\tif (!window) return false\n\treturn (\n\t\t['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\twindow.navigator.platform\n\t\t) ||\n\t\t// iPad on iOS 13 detection\n\t\t(tlenv.isDarwin && 'ontouchend' in document)\n\t)\n}\n\n/**\n * A string that is unique per browser tab\n * @public\n */\nexport const TAB_ID: string = window\n\t? (window[tabIdKey] ??\n\t\tgetFromSessionStorage(tabIdKey) ??\n\t\t`TLDRAW_INSTANCE_STATE_V1_` + uniqueId())\n\t: '<error>'\nif (window) {\n\twindow[tabIdKey] = TAB_ID\n\tif (iOS()) {\n\t\t// iOS does not trigger beforeunload\n\t\t// so we need to keep the sessionStorage value around\n\t\t// and hope the user doesn't figure out a way to duplicate their tab\n\t\t// in which case they'll have two tabs with the same UI state.\n\t\t// It's not a big deal, but it's not ideal.\n\t\t// And anyway I can't see a way to duplicate a tab in iOS Safari.\n\t\tsetInSessionStorage(tabIdKey, TAB_ID)\n\t} else {\n\t\tdeleteFromSessionStorage(tabIdKey)\n\t}\n}\n\nwindow?.addEventListener('beforeunload', () => {\n\tsetInSessionStorage(tabIdKey, TAB_ID)\n})\n\nconst Versions = {\n\tInitial: 0,\n} as const\n\nconst CURRENT_SESSION_STATE_SNAPSHOT_VERSION = Math.max(...Object.values(Versions))\n\nfunction migrate(snapshot: any) {\n\tif (snapshot.version < Versions.Initial) {\n\t\t// initial version\n\t\t// noop\n\t}\n\t// add further migrations down here. see TLUserPreferences.ts for an example.\n\n\t// finally\n\tsnapshot.version = CURRENT_SESSION_STATE_SNAPSHOT_VERSION\n}\n\n/**\n * The state of the editor instance, not including any document state.\n *\n * @public\n */\nexport interface TLSessionStateSnapshot {\n\tversion: number\n\tcurrentPageId?: TLPageId\n\tisFocusMode?: boolean\n\texportBackground?: boolean\n\tisDebugMode?: boolean\n\tisToolLocked?: boolean\n\tisGridMode?: boolean\n\tpageStates?: Array<{\n\t\tpageId: TLPageId\n\t\tcamera?: { x: number; y: number; z: number }\n\t\tselectedShapeIds?: TLShapeId[]\n\t\tfocusedGroupId?: TLShapeId | null\n\t}>\n}\n\nconst sessionStateSnapshotValidator: T.Validator<TLSessionStateSnapshot> = T.object({\n\tversion: T.number,\n\tcurrentPageId: pageIdValidator.optional(),\n\tisFocusMode: T.boolean.optional(),\n\texportBackground: T.boolean.optional(),\n\tisDebugMode: T.boolean.optional(),\n\tisToolLocked: T.boolean.optional(),\n\tisGridMode: T.boolean.optional(),\n\tpageStates: T.arrayOf(\n\t\tT.object({\n\t\t\tpageId: pageIdValidator,\n\t\t\tcamera: T.object({\n\t\t\t\tx: T.number,\n\t\t\t\ty: T.number,\n\t\t\t\tz: T.number,\n\t\t\t}).optional(),\n\t\t\tselectedShapeIds: T.arrayOf(shapeIdValidator).optional(),\n\t\t\tfocusedGroupId: shapeIdValidator.nullable().optional(),\n\t\t})\n\t).optional(),\n})\n\nfunction migrateAndValidateSessionStateSnapshot(state: unknown): TLSessionStateSnapshot | null {\n\tif (!state || typeof state !== 'object') {\n\t\tconsole.warn('Invalid instance state')\n\t\treturn null\n\t}\n\tif (!('version' in state) || typeof state.version !== 'number') {\n\t\tconsole.warn('No version in instance state')\n\t\treturn null\n\t}\n\tif (state.version !== CURRENT_SESSION_STATE_SNAPSHOT_VERSION) {\n\t\tstate = structuredClone(state)\n\t\tmigrate(state)\n\t}\n\n\ttry {\n\t\treturn sessionStateSnapshotValidator.validate(state)\n\t} catch (e) {\n\t\tconsole.warn(e)\n\t\treturn null\n\t}\n}\n\n/**\n * Creates a signal of the instance state for a given store.\n * @public\n * @param store - The store to create the instance state snapshot signal for\n * @returns\n */\nexport function createSessionStateSnapshotSignal(\n\tstore: TLStore\n): Signal<TLSessionStateSnapshot | null> {\n\tconst $allPageIds = store.query.ids('page')\n\n\treturn computed<TLSessionStateSnapshot | null>(\n\t\t'sessionStateSnapshot',\n\t\t() => {\n\t\t\tconst instanceState = store.get(TLINSTANCE_ID)\n\t\t\tif (!instanceState) return null\n\n\t\t\tconst allPageIds = [...$allPageIds.get()]\n\t\t\treturn {\n\t\t\t\tversion: CURRENT_SESSION_STATE_SNAPSHOT_VERSION,\n\t\t\t\tcurrentPageId: instanceState.currentPageId,\n\t\t\t\texportBackground: instanceState.exportBackground,\n\t\t\t\tisFocusMode: instanceState.isFocusMode,\n\t\t\t\tisDebugMode: instanceState.isDebugMode,\n\t\t\t\tisToolLocked: instanceState.isToolLocked,\n\t\t\t\tisGridMode: instanceState.isGridMode,\n\t\t\t\tpageStates: allPageIds.map((id) => {\n\t\t\t\t\tconst ps = store.get(InstancePageStateRecordType.createId(id))\n\t\t\t\t\tconst camera = store.get(CameraRecordType.createId(id))\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpageId: id,\n\t\t\t\t\t\tcamera: {\n\t\t\t\t\t\t\tx: camera?.x ?? 0,\n\t\t\t\t\t\t\ty: camera?.y ?? 0,\n\t\t\t\t\t\t\tz: camera?.z ?? 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tselectedShapeIds: ps?.selectedShapeIds ?? [],\n\t\t\t\t\t\tfocusedGroupId: ps?.focusedGroupId ?? null,\n\t\t\t\t\t} satisfies NonNullable<TLSessionStateSnapshot['pageStates']>[0]\n\t\t\t\t}),\n\t\t\t} satisfies TLSessionStateSnapshot\n\t\t},\n\t\t{ isEqual }\n\t)\n}\n\n/**\n * Options for {@link loadSessionStateSnapshotIntoStore}\n * @public\n */\nexport interface TLLoadSessionStateSnapshotOptions {\n\t/**\n\t * By default, some session state flags like `isDebugMode` are not overwritten when loading a snapshot.\n\t * These are usually considered \"sticky\" by users while the document data is not.\n\t * If you want to overwrite these flags, set this to `true`.\n\t */\n\tforceOverwrite?: boolean\n}\n\n/**\n * Loads a snapshot of the editor's instance state into the store of a new editor instance.\n *\n * @public\n * @param store - The store to load the instance state into\n * @param snapshot - The instance state snapshot to load\n * @returns\n */\nexport function loadSessionStateSnapshotIntoStore(\n\tstore: TLStore,\n\tsnapshot: TLSessionStateSnapshot,\n\topts?: TLLoadSessionStateSnapshotOptions\n) {\n\tconst res = migrateAndValidateSessionStateSnapshot(snapshot)\n\tif (!res) return\n\n\tconst preserved = pluckPreservingValues(store.get(TLINSTANCE_ID))\n\tconst primary = opts?.forceOverwrite ? res : preserved\n\tconst secondary = opts?.forceOverwrite ? preserved : res\n\n\tconst instanceState = store.schema.types.instance.create({\n\t\tid: TLINSTANCE_ID,\n\t\t...preserved,\n\t\t// the integrity checker will ensure that the currentPageId is valid\n\t\tcurrentPageId: res.currentPageId,\n\t\tisDebugMode: primary?.isDebugMode ?? secondary?.isDebugMode,\n\t\tisFocusMode: primary?.isFocusMode ?? secondary?.isFocusMode,\n\t\tisToolLocked: primary?.isToolLocked ?? secondary?.isToolLocked,\n\t\tisGridMode: primary?.isGridMode ?? secondary?.isGridMode,\n\t\texportBackground: primary?.exportBackground ?? secondary?.exportBackground,\n\t})\n\n\tstore.atomic(() => {\n\t\tfor (const ps of res.pageStates ?? []) {\n\t\t\tif (!store.has(ps.pageId)) continue\n\t\t\tconst cameraId = CameraRecordType.createId(ps.pageId)\n\t\t\tconst instancePageState = InstancePageStateRecordType.createId(ps.pageId)\n\t\t\tconst previousCamera = store.get(cameraId)\n\t\t\tconst previousInstanceState = store.get(instancePageState)\n\t\t\tstore.put([\n\t\t\t\tCameraRecordType.create({\n\t\t\t\t\tid: cameraId,\n\t\t\t\t\tx: ps.camera?.x ?? previousCamera?.x,\n\t\t\t\t\ty: ps.camera?.y ?? previousCamera?.y,\n\t\t\t\t\tz: ps.camera?.z ?? previousCamera?.z,\n\t\t\t\t}),\n\t\t\t\tInstancePageStateRecordType.create({\n\t\t\t\t\tid: instancePageState,\n\t\t\t\t\tpageId: ps.pageId,\n\t\t\t\t\tselectedShapeIds: ps.selectedShapeIds ?? previousInstanceState?.selectedShapeIds,\n\t\t\t\t\tfocusedGroupId: ps.focusedGroupId ?? previousInstanceState?.focusedGroupId,\n\t\t\t\t}),\n\t\t\t])\n\t\t}\n\n\t\tstore.put([instanceState])\n\t\tstore.ensureStoreIsUsable()\n\t})\n}\n\n/**\n * @internal\n */\nexport function extractSessionStateFromLegacySnapshot(\n\tstore: Record<string, UnknownRecord>\n): TLSessionStateSnapshot | null {\n\tconst instanceRecords = []\n\tfor (const record of Object.values(store)) {\n\t\tif (record.typeName?.match(/^(instance.*|pointer|camera)$/)) {\n\t\t\tinstanceRecords.push(record)\n\t\t}\n\t}\n\n\t// for scratch documents, we need to extract the most recently-used instance and it's associated page states\n\t// but oops we don't have the concept of \"most recently-used\" so we'll just take the first one\n\tconst oldInstance = instanceRecords.filter(\n\t\t(r) => r.typeName === 'instance' && r.id !== TLINSTANCE_ID\n\t)[0] as any\n\tif (!oldInstance) return null\n\n\tconst result: TLSessionStateSnapshot = {\n\t\tversion: CURRENT_SESSION_STATE_SNAPSHOT_VERSION,\n\t\tcurrentPageId: oldInstance.currentPageId,\n\t\texportBackground: !!oldInstance.exportBackground,\n\t\tisFocusMode: !!oldInstance.isFocusMode,\n\t\tisDebugMode: !!oldInstance.isDebugMode,\n\t\tisToolLocked: !!oldInstance.isToolLocked,\n\t\tisGridMode: false,\n\t\tpageStates: instanceRecords\n\t\t\t.filter((r: any) => r.typeName === 'instance_page_state' && r.instanceId === oldInstance.id)\n\t\t\t.map((ps: any) => {\n\t\t\t\tconst camera = (store[ps.cameraId] as any) ?? { x: 0, y: 0, z: 1 }\n\t\t\t\treturn {\n\t\t\t\t\tpageId: ps.pageId,\n\t\t\t\t\tcamera: {\n\t\t\t\t\t\tx: camera.x,\n\t\t\t\t\t\ty: camera.y,\n\t\t\t\t\t\tz: camera.z,\n\t\t\t\t\t},\n\t\t\t\t\tselectedShapeIds: ps.selectedShapeIds,\n\t\t\t\t\tfocusedGroupId: ps.focusedGroupId,\n\t\t\t\t} satisfies NonNullable<TLSessionStateSnapshot['pageStates']>[0]\n\t\t\t}),\n\t}\n\n\ttry {\n\t\tsessionStateSnapshotValidator.validate(result)\n\t\treturn result\n\t} catch {\n\t\treturn null\n\t}\n}\n"],
5
- "mappings": "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",
6
- "names": ["isEqual"]
4
+ "sourcesContent": ["import { Signal, computed } from '@tldraw/state'\nimport { UnknownRecord } from '@tldraw/store'\nimport {\n\tCameraRecordType,\n\tInstancePageStateRecordType,\n\tTLINSTANCE_ID,\n\tTLPageId,\n\tTLShapeId,\n\tTLStore,\n\tpageIdValidator,\n\tpluckPreservingValues,\n\tshapeIdValidator,\n} from '@tldraw/tlschema'\nimport {\n\tdeleteFromSessionStorage,\n\tgetFromSessionStorage,\n\tisEqual,\n\tsetInSessionStorage,\n\tstructuredClone,\n\tuniqueId,\n} from '@tldraw/utils'\nimport { T } from '@tldraw/validate'\nimport { tlenv } from '../globals/environment'\n\nconst tabIdKey = 'TLDRAW_TAB_ID_v2' as const\n\nconst window = globalThis.window as\n\t| {\n\t\t\tnavigator: Window['navigator']\n\t\t\taddEventListener: Window['addEventListener']\n\t\t\tTLDRAW_TAB_ID_v2?: string\n\t }\n\t| undefined\n\n// https://stackoverflow.com/a/9039885\nfunction iOS() {\n\tif (!window) return false\n\treturn (\n\t\t['iPad Simulator', 'iPhone Simulator', 'iPod Simulator', 'iPad', 'iPhone', 'iPod'].includes(\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\twindow.navigator.platform\n\t\t) ||\n\t\t// iPad on iOS 13 detection\n\t\t(tlenv.isDarwin && 'ontouchend' in document)\n\t)\n}\n\n/**\n * A string that is unique per browser tab\n * @public\n */\nexport const TAB_ID: string = window\n\t? (window[tabIdKey] ??\n\t\tgetFromSessionStorage(tabIdKey) ??\n\t\t`TLDRAW_INSTANCE_STATE_V1_` + uniqueId())\n\t: '<error>'\nif (window) {\n\twindow[tabIdKey] = TAB_ID\n\tif (iOS()) {\n\t\t// iOS does not trigger beforeunload\n\t\t// so we need to keep the sessionStorage value around\n\t\t// and hope the user doesn't figure out a way to duplicate their tab\n\t\t// in which case they'll have two tabs with the same UI state.\n\t\t// It's not a big deal, but it's not ideal.\n\t\t// And anyway I can't see a way to duplicate a tab in iOS Safari.\n\t\tsetInSessionStorage(tabIdKey, TAB_ID)\n\t} else {\n\t\tdeleteFromSessionStorage(tabIdKey)\n\t}\n}\n\nwindow?.addEventListener('beforeunload', () => {\n\tsetInSessionStorage(tabIdKey, TAB_ID)\n})\n\nconst Versions = {\n\tInitial: 0,\n} as const\n\nconst CURRENT_SESSION_STATE_SNAPSHOT_VERSION = Math.max(...Object.values(Versions))\n\nfunction migrate(snapshot: any) {\n\tif (snapshot.version < Versions.Initial) {\n\t\t// initial version\n\t\t// noop\n\t}\n\t// add further migrations down here. see TLUserPreferences.ts for an example.\n\n\t// finally\n\tsnapshot.version = CURRENT_SESSION_STATE_SNAPSHOT_VERSION\n}\n\n/**\n * The state of the editor instance, not including any document state.\n *\n * @public\n */\nexport interface TLSessionStateSnapshot {\n\tversion: number\n\tcurrentPageId?: TLPageId\n\tisFocusMode?: boolean\n\texportBackground?: boolean\n\tisDebugMode?: boolean\n\tisToolLocked?: boolean\n\tisGridMode?: boolean\n\tpageStates?: Array<{\n\t\tpageId: TLPageId\n\t\tcamera?: { x: number; y: number; z: number }\n\t\tselectedShapeIds?: TLShapeId[]\n\t\tfocusedGroupId?: TLShapeId | null\n\t}>\n}\n\nconst sessionStateSnapshotValidator: T.Validator<TLSessionStateSnapshot> = T.object({\n\tversion: T.number,\n\tcurrentPageId: pageIdValidator.optional(),\n\tisFocusMode: T.boolean.optional(),\n\texportBackground: T.boolean.optional(),\n\tisDebugMode: T.boolean.optional(),\n\tisToolLocked: T.boolean.optional(),\n\tisGridMode: T.boolean.optional(),\n\tpageStates: T.arrayOf(\n\t\tT.object({\n\t\t\tpageId: pageIdValidator,\n\t\t\tcamera: T.object({\n\t\t\t\tx: T.number,\n\t\t\t\ty: T.number,\n\t\t\t\tz: T.number,\n\t\t\t}).optional(),\n\t\t\tselectedShapeIds: T.arrayOf(shapeIdValidator).optional(),\n\t\t\tfocusedGroupId: shapeIdValidator.nullable().optional(),\n\t\t})\n\t).optional(),\n})\n\nfunction migrateAndValidateSessionStateSnapshot(state: unknown): TLSessionStateSnapshot | null {\n\tif (!state || typeof state !== 'object') {\n\t\tconsole.warn('Invalid instance state')\n\t\treturn null\n\t}\n\tif (!('version' in state) || typeof state.version !== 'number') {\n\t\tconsole.warn('No version in instance state')\n\t\treturn null\n\t}\n\tif (state.version !== CURRENT_SESSION_STATE_SNAPSHOT_VERSION) {\n\t\tstate = structuredClone(state)\n\t\tmigrate(state)\n\t}\n\n\ttry {\n\t\treturn sessionStateSnapshotValidator.validate(state)\n\t} catch (e) {\n\t\tconsole.warn(e)\n\t\treturn null\n\t}\n}\n\n/**\n * Creates a signal of the instance state for a given store.\n * @public\n * @param store - The store to create the instance state snapshot signal for\n * @returns\n */\nexport function createSessionStateSnapshotSignal(\n\tstore: TLStore\n): Signal<TLSessionStateSnapshot | null> {\n\tconst $allPageIds = store.query.ids('page')\n\n\treturn computed<TLSessionStateSnapshot | null>(\n\t\t'sessionStateSnapshot',\n\t\t() => {\n\t\t\tconst instanceState = store.get(TLINSTANCE_ID)\n\t\t\tif (!instanceState) return null\n\n\t\t\tconst allPageIds = [...$allPageIds.get()]\n\t\t\treturn {\n\t\t\t\tversion: CURRENT_SESSION_STATE_SNAPSHOT_VERSION,\n\t\t\t\tcurrentPageId: instanceState.currentPageId,\n\t\t\t\texportBackground: instanceState.exportBackground,\n\t\t\t\tisFocusMode: instanceState.isFocusMode,\n\t\t\t\tisDebugMode: instanceState.isDebugMode,\n\t\t\t\tisToolLocked: instanceState.isToolLocked,\n\t\t\t\tisGridMode: instanceState.isGridMode,\n\t\t\t\tpageStates: allPageIds.map((id) => {\n\t\t\t\t\tconst ps = store.get(InstancePageStateRecordType.createId(id))\n\t\t\t\t\tconst camera = store.get(CameraRecordType.createId(id))\n\t\t\t\t\treturn {\n\t\t\t\t\t\tpageId: id,\n\t\t\t\t\t\tcamera: {\n\t\t\t\t\t\t\tx: camera?.x ?? 0,\n\t\t\t\t\t\t\ty: camera?.y ?? 0,\n\t\t\t\t\t\t\tz: camera?.z ?? 1,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tselectedShapeIds: ps?.selectedShapeIds ?? [],\n\t\t\t\t\t\tfocusedGroupId: ps?.focusedGroupId ?? null,\n\t\t\t\t\t} satisfies NonNullable<TLSessionStateSnapshot['pageStates']>[0]\n\t\t\t\t}),\n\t\t\t} satisfies TLSessionStateSnapshot\n\t\t},\n\t\t{ isEqual }\n\t)\n}\n\n/**\n * Options for {@link loadSessionStateSnapshotIntoStore}\n * @public\n */\nexport interface TLLoadSessionStateSnapshotOptions {\n\t/**\n\t * By default, some session state flags like `isDebugMode` are not overwritten when loading a snapshot.\n\t * These are usually considered \"sticky\" by users while the document data is not.\n\t * If you want to overwrite these flags, set this to `true`.\n\t */\n\tforceOverwrite?: boolean\n}\n\n/**\n * Loads a snapshot of the editor's instance state into the store of a new editor instance.\n *\n * @public\n * @param store - The store to load the instance state into\n * @param snapshot - The instance state snapshot to load\n * @returns\n */\nexport function loadSessionStateSnapshotIntoStore(\n\tstore: TLStore,\n\tsnapshot: TLSessionStateSnapshot,\n\topts?: TLLoadSessionStateSnapshotOptions\n) {\n\tconst res = migrateAndValidateSessionStateSnapshot(snapshot)\n\tif (!res) return\n\n\tconst preserved = pluckPreservingValues(store.get(TLINSTANCE_ID))\n\tconst primary = opts?.forceOverwrite ? res : preserved\n\tconst secondary = opts?.forceOverwrite ? preserved : res\n\n\tconst instanceState = store.schema.types.instance.create({\n\t\tid: TLINSTANCE_ID,\n\t\t...preserved,\n\t\t// the integrity checker will ensure that the currentPageId is valid\n\t\tcurrentPageId: res.currentPageId,\n\t\tisDebugMode: primary?.isDebugMode ?? secondary?.isDebugMode,\n\t\tisFocusMode: primary?.isFocusMode ?? secondary?.isFocusMode,\n\t\tisToolLocked: primary?.isToolLocked ?? secondary?.isToolLocked,\n\t\tisGridMode: primary?.isGridMode ?? secondary?.isGridMode,\n\t\texportBackground: primary?.exportBackground ?? secondary?.exportBackground,\n\t})\n\n\tstore.atomic(() => {\n\t\tfor (const ps of res.pageStates ?? []) {\n\t\t\tif (!store.has(ps.pageId)) continue\n\t\t\tconst cameraId = CameraRecordType.createId(ps.pageId)\n\t\t\tconst instancePageState = InstancePageStateRecordType.createId(ps.pageId)\n\t\t\tconst previousCamera = store.get(cameraId)\n\t\t\tconst previousInstanceState = store.get(instancePageState)\n\t\t\tstore.put([\n\t\t\t\tCameraRecordType.create({\n\t\t\t\t\tid: cameraId,\n\t\t\t\t\tx: ps.camera?.x ?? previousCamera?.x,\n\t\t\t\t\ty: ps.camera?.y ?? previousCamera?.y,\n\t\t\t\t\tz: ps.camera?.z ?? previousCamera?.z,\n\t\t\t\t}),\n\t\t\t\tInstancePageStateRecordType.create({\n\t\t\t\t\tid: instancePageState,\n\t\t\t\t\tpageId: ps.pageId,\n\t\t\t\t\tselectedShapeIds: ps.selectedShapeIds ?? previousInstanceState?.selectedShapeIds,\n\t\t\t\t\tfocusedGroupId: ps.focusedGroupId ?? previousInstanceState?.focusedGroupId,\n\t\t\t\t}),\n\t\t\t])\n\t\t}\n\n\t\tstore.put([instanceState])\n\t\tstore.ensureStoreIsUsable()\n\t})\n}\n\n/**\n * @internal\n */\nexport function extractSessionStateFromLegacySnapshot(\n\tstore: Record<string, UnknownRecord>\n): TLSessionStateSnapshot | null {\n\tconst instanceRecords = []\n\tfor (const record of Object.values(store)) {\n\t\tif (record.typeName?.match(/^(instance.*|pointer|camera)$/)) {\n\t\t\tinstanceRecords.push(record)\n\t\t}\n\t}\n\n\t// for scratch documents, we need to extract the most recently-used instance and it's associated page states\n\t// but oops we don't have the concept of \"most recently-used\" so we'll just take the first one\n\tconst oldInstance = instanceRecords.filter(\n\t\t(r) => r.typeName === 'instance' && r.id !== TLINSTANCE_ID\n\t)[0] as any\n\tif (!oldInstance) return null\n\n\tconst result: TLSessionStateSnapshot = {\n\t\tversion: CURRENT_SESSION_STATE_SNAPSHOT_VERSION,\n\t\tcurrentPageId: oldInstance.currentPageId,\n\t\texportBackground: !!oldInstance.exportBackground,\n\t\tisFocusMode: !!oldInstance.isFocusMode,\n\t\tisDebugMode: !!oldInstance.isDebugMode,\n\t\tisToolLocked: !!oldInstance.isToolLocked,\n\t\tisGridMode: false,\n\t\tpageStates: instanceRecords\n\t\t\t.filter((r: any) => r.typeName === 'instance_page_state' && r.instanceId === oldInstance.id)\n\t\t\t.map((ps: any) => {\n\t\t\t\tconst camera = (store[ps.cameraId] as any) ?? { x: 0, y: 0, z: 1 }\n\t\t\t\treturn {\n\t\t\t\t\tpageId: ps.pageId,\n\t\t\t\t\tcamera: {\n\t\t\t\t\t\tx: camera.x,\n\t\t\t\t\t\ty: camera.y,\n\t\t\t\t\t\tz: camera.z,\n\t\t\t\t\t},\n\t\t\t\t\tselectedShapeIds: ps.selectedShapeIds,\n\t\t\t\t\tfocusedGroupId: ps.focusedGroupId,\n\t\t\t\t} satisfies NonNullable<TLSessionStateSnapshot['pageStates']>[0]\n\t\t\t}),\n\t}\n\n\ttry {\n\t\tsessionStateSnapshotValidator.validate(result)\n\t\treturn result\n\t} catch {\n\t\treturn null\n\t}\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
7
  }
@@ -323,6 +323,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
323
323
  __publicField(this, "externalContentHandlers", {
324
324
  text: null,
325
325
  files: null,
326
+ "file-replace": null,
326
327
  embed: null,
327
328
  "svg-text": null,
328
329
  url: null,
@@ -439,6 +440,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
439
440
  this.disposables.add(() => this.user.dispose());
440
441
  this.getContainer = getContainer;
441
442
  this.textMeasure = new import_TextManager.TextManager(this);
443
+ this.disposables.add(() => this.textMeasure.dispose());
442
444
  this.fonts = new import_FontManager.FontManager(this, fontAssetUrls);
443
445
  this._tickManager = new import_TickManager.TickManager(this);
444
446
  class NewRoot extends import_RootState.RootState {
@@ -559,20 +561,21 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
559
561
  shape: {
560
562
  afterChange: (shapeBefore, shapeAfter) => {
561
563
  for (const binding of this.getBindingsInvolvingShape(shapeAfter)) {
562
- if ((0, import_areShapesContentEqual.areShapesContentEqual)(shapeBefore, shapeAfter)) continue;
563
564
  invalidBindingTypes.add(binding.type);
564
565
  if (binding.fromId === shapeAfter.id) {
565
566
  this.getBindingUtil(binding).onAfterChangeFromShape?.({
566
567
  binding,
567
568
  shapeBefore,
568
- shapeAfter
569
+ shapeAfter,
570
+ reason: "self"
569
571
  });
570
572
  }
571
573
  if (binding.toId === shapeAfter.id) {
572
574
  this.getBindingUtil(binding).onAfterChangeToShape?.({
573
575
  binding,
574
576
  shapeBefore,
575
- shapeAfter
577
+ shapeAfter,
578
+ reason: "self"
576
579
  });
577
580
  }
578
581
  }
@@ -586,14 +589,16 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
586
589
  this.getBindingUtil(binding).onAfterChangeFromShape?.({
587
590
  binding,
588
591
  shapeBefore: descendantShape,
589
- shapeAfter: descendantShape
592
+ shapeAfter: descendantShape,
593
+ reason: "ancestry"
590
594
  });
591
595
  }
592
596
  if (binding.toId === descendantShape.id) {
593
597
  this.getBindingUtil(binding).onAfterChangeToShape?.({
594
598
  binding,
595
599
  shapeBefore: descendantShape,
596
- shapeAfter: descendantShape
600
+ shapeAfter: descendantShape,
601
+ reason: "ancestry"
597
602
  });
598
603
  }
599
604
  }
@@ -1637,6 +1642,19 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
1637
1642
  getSelectionPageBounds() {
1638
1643
  return this.getShapesPageBounds(this.getSelectedShapeIds());
1639
1644
  }
1645
+ /**
1646
+ * The bounds of the selection bounding box in the current page space.
1647
+ *
1648
+ * @readonly
1649
+ * @public
1650
+ */
1651
+ getSelectionScreenBounds() {
1652
+ const bounds = this.getSelectionPageBounds();
1653
+ if (!bounds) return void 0;
1654
+ const { x, y } = this.pageToScreen(bounds.point);
1655
+ const zoom = this.getZoomLevel();
1656
+ return new import_Box.Box(x, y, bounds.width * zoom, bounds.height * zoom);
1657
+ }
1640
1658
  /**
1641
1659
  * @internal
1642
1660
  */
@@ -2770,7 +2788,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
2770
2788
  * @public
2771
2789
  */
2772
2790
  updateViewportScreenBounds(screenBounds, center = false) {
2773
- if (screenBounds instanceof HTMLElement) {
2791
+ if (!(screenBounds instanceof import_Box.Box)) {
2774
2792
  const rect = screenBounds.getBoundingClientRect();
2775
2793
  screenBounds = new import_Box.Box(
2776
2794
  rect.left || rect.x,
@@ -4113,7 +4131,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4113
4131
  if (!id) return void 0;
4114
4132
  const freshShape = this.getShape(id);
4115
4133
  if (freshShape === void 0 || !(0, import_tlschema.isShapeId)(freshShape.parentId)) return void 0;
4116
- return this.store.get(freshShape.parentId);
4134
+ return this.getShape(freshShape.parentId);
4117
4135
  }
4118
4136
  /**
4119
4137
  * If siblingShape and targetShape are siblings, this returns targetShape. If targetShape has an
@@ -4245,6 +4263,9 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4245
4263
  if (!pagePoint) continue;
4246
4264
  const newPoint = invertedParentTransform.applyToPoint(pagePoint);
4247
4265
  const newRotation = pageTransform.rotation() - parentPageRotation;
4266
+ if (shape.id === parentId) {
4267
+ throw Error("Attempted to reparent a shape to itself!");
4268
+ }
4248
4269
  changes.push({
4249
4270
  id: shape.id,
4250
4271
  type: shape.type,
@@ -4337,6 +4358,10 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4337
4358
  }
4338
4359
  return shapeIds;
4339
4360
  }
4361
+ /** @deprecated Use {@link Editor.getDraggingOverShape} instead */
4362
+ getDroppingOverShape(point, droppingShapes) {
4363
+ return this.getDraggingOverShape(point, droppingShapes);
4364
+ }
4340
4365
  /**
4341
4366
  * Get the shape that some shapes should be dropped on at a given point.
4342
4367
  *
@@ -4347,22 +4372,20 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4347
4372
  *
4348
4373
  * @public
4349
4374
  */
4350
- getDroppingOverShape(point, droppingShapes = []) {
4351
- const currentPageShapesSorted = this.getCurrentPageShapesSorted();
4352
- for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
4353
- const shape = currentPageShapesSorted[i];
4354
- if (
4355
- // ignore hidden shapes
4356
- this.isShapeHidden(shape) || // don't allow dropping on selected shapes
4357
- this.getSelectedShapeIds().includes(shape.id) || // only allow shapes that can receive children
4358
- !this.getShapeUtil(shape).canDropShapes(shape, droppingShapes) || // don't allow dropping a shape on itself or one of it's children
4359
- droppingShapes.find((s) => s.id === shape.id || this.hasAncestor(shape, s.id))
4360
- ) {
4361
- continue;
4362
- }
4363
- const maskedPageBounds = this.getShapeMaskedPageBounds(shape.id);
4364
- if (maskedPageBounds && maskedPageBounds.containsPoint(point) && this.getShapeGeometry(shape).hitTestPoint(this.getPointInShapeSpace(shape, point), 0, true)) {
4365
- return shape;
4375
+ getDraggingOverShape(point, droppingShapes) {
4376
+ const draggingShapes = (0, import_utils.compact)(droppingShapes.map((s) => this.getShape(s))).filter(
4377
+ (s) => !s.isLocked && !this.isShapeHidden(s)
4378
+ );
4379
+ const maybeDraggingOverShapes = this.getShapesAtPoint(point, {
4380
+ hitInside: true,
4381
+ margin: 0
4382
+ }).filter(
4383
+ (s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !draggingShapes.includes(s)
4384
+ );
4385
+ for (const maybeDraggingOverShape of maybeDraggingOverShapes) {
4386
+ const shapeUtil = this.getShapeUtil(maybeDraggingOverShape);
4387
+ if (shapeUtil.onDragShapesOver || shapeUtil.onDragShapesIn || shapeUtil.onDragShapesOut || shapeUtil.onDropShapesOver) {
4388
+ return maybeDraggingOverShape;
4366
4389
  }
4367
4390
  }
4368
4391
  }
@@ -4639,7 +4662,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4639
4662
  */
4640
4663
  duplicateShapes(shapes, offset) {
4641
4664
  this.run(() => {
4642
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
4665
+ const _ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
4666
+ const ids = this._shouldIgnoreShapeLock ? _ids : this._getUnlockedShapeIds(_ids);
4643
4667
  if (ids.length <= 0) return this;
4644
4668
  const initialIds = new Set(ids);
4645
4669
  const shapeIdSet = this.getShapeAndDescendantIds(ids);
@@ -4703,8 +4727,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4703
4727
  shape.index = index;
4704
4728
  });
4705
4729
  const shapesToCreate = shapesToCreateWithOriginals.map(({ shape }) => shape);
4706
- const maxShapesReached = shapesToCreate.length + this.getCurrentPageShapeIds().size > this.options.maxShapesPerPage;
4707
- if (maxShapesReached) {
4730
+ if (!this.canCreateShapes(shapesToCreate)) {
4708
4731
  alertMaxShapes(this);
4709
4732
  return;
4710
4733
  }
@@ -5719,6 +5742,26 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
5719
5742
  getInitialMetaForShape(_shape) {
5720
5743
  return {};
5721
5744
  }
5745
+ /**
5746
+ * Get whether the provided shape can be created.
5747
+ *
5748
+ * @param shape - The shape or shape IDs to check.
5749
+ *
5750
+ * @public
5751
+ */
5752
+ canCreateShape(shape) {
5753
+ return this.canCreateShapes([shape]);
5754
+ }
5755
+ /**
5756
+ * Get whether the provided shapes can be created.
5757
+ *
5758
+ * @param shapes - The shapes or shape IDs to create.
5759
+ *
5760
+ * @public
5761
+ */
5762
+ canCreateShapes(shapes) {
5763
+ return shapes.length + this.getCurrentPageShapeIds().size <= this.options.maxShapesPerPage;
5764
+ }
5722
5765
  /**
5723
5766
  * Create a single shape.
5724
5767
  *
@@ -5772,7 +5815,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
5772
5815
  let parentId = this.getFocusedGroupId();
5773
5816
  for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
5774
5817
  const parent = currentPageShapesSorted[i];
5775
- if (!this.isShapeHidden(parent) && this.getShapeUtil(parent).canReceiveNewChildrenOfType(parent, partial.type) && this.isPointInShape(
5818
+ const util = this.getShapeUtil(parent);
5819
+ if (util.canReceiveNewChildrenOfType(parent, partial.type) && !this.isShapeHidden(parent) && this.isPointInShape(
5776
5820
  parent,
5777
5821
  // If no parent is provided, then we can treat the
5778
5822
  // shape's provided x/y as being in the page's space.
@@ -5847,6 +5891,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
5847
5891
  ...shape.meta
5848
5892
  };
5849
5893
  });
5894
+ this.emit("created-shapes", shapeRecordsToCreate);
5895
+ this.emit("edit");
5850
5896
  this.store.put(shapeRecordsToCreate);
5851
5897
  });
5852
5898
  return this;
@@ -6088,6 +6134,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6088
6134
  updated = this.getShapeUtil(shape).onBeforeUpdate?.(shape, updated) ?? updated;
6089
6135
  updates.push(updated);
6090
6136
  }
6137
+ this.emit("edited-shapes", updates);
6138
+ this.emit("edit");
6091
6139
  this.store.put(updates);
6092
6140
  });
6093
6141
  }
@@ -6109,6 +6157,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6109
6157
  allShapeIdsToDelete.add(childId);
6110
6158
  });
6111
6159
  }
6160
+ this.emit("deleted-shapes", [...allShapeIdsToDelete]);
6161
+ this.emit("edit");
6112
6162
  return this.run(() => this.store.remove([...allShapeIdsToDelete]));
6113
6163
  }
6114
6164
  deleteShape(_id) {
@@ -6452,6 +6502,14 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6452
6502
  async putExternalContent(info) {
6453
6503
  return this.externalContentHandlers[info.type]?.(info);
6454
6504
  }
6505
+ /**
6506
+ * Handle replacing external content.
6507
+ *
6508
+ * @param info - Info about the external content.
6509
+ */
6510
+ async replaceExternalContent(info) {
6511
+ return this.externalContentHandlers[info.type]?.(info);
6512
+ }
6455
6513
  /**
6456
6514
  * Get content that can be exported for the given shape ids.
6457
6515
  *
@@ -6869,7 +6927,9 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6869
6927
  previousScreenPoint,
6870
6928
  previousPagePoint,
6871
6929
  currentScreenPoint,
6872
- currentPagePoint
6930
+ currentPagePoint,
6931
+ originScreenPoint,
6932
+ originPagePoint
6873
6933
  } = this.inputs;
6874
6934
  const { screenBounds } = this.store.unsafeGetWithoutCapture(import_tlschema.TLINSTANCE_ID);
6875
6935
  const { x: cx, y: cy, z: cz } = (0, import_state.unsafe__withoutCapture)(() => this.getCamera());
@@ -6887,8 +6947,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6887
6947
  this.inputs.isPen = info.type === "pointer" && info.isPen;
6888
6948
  if (info.name === "pointer_down" || this.inputs.isPinching) {
6889
6949
  pointerVelocity.set(0, 0);
6890
- this.inputs.originScreenPoint.setTo(currentScreenPoint);
6891
- this.inputs.originPagePoint.setTo(currentPagePoint);
6950
+ originScreenPoint.setTo(currentScreenPoint);
6951
+ originPagePoint.setTo(currentPagePoint);
6892
6952
  }
6893
6953
  this.run(
6894
6954
  () => {