@tldraw/editor 5.2.1 → 5.3.0-canary.7d00ddf70f63

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 (70) hide show
  1. package/dist-cjs/index.d.ts +45 -8
  2. package/dist-cjs/index.js +3 -3
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/editor/Editor.js +12 -2
  5. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  6. package/dist-cjs/lib/editor/managers/EditorManager.js +52 -0
  7. package/dist-cjs/lib/editor/managers/EditorManager.js.map +7 -0
  8. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +9 -11
  9. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
  10. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +5 -9
  11. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
  12. package/dist-cjs/lib/editor/managers/SpatialIndexManager/RBushIndex.js +18 -29
  13. package/dist-cjs/lib/editor/managers/SpatialIndexManager/RBushIndex.js.map +2 -2
  14. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +96 -54
  15. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +2 -2
  16. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +24 -19
  17. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  18. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +4 -7
  19. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
  20. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +1 -1
  21. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +1 -2
  22. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
  23. package/dist-cjs/version.js +3 -3
  24. package/dist-cjs/version.js.map +1 -1
  25. package/dist-esm/index.d.mts +45 -8
  26. package/dist-esm/index.mjs +3 -3
  27. package/dist-esm/index.mjs.map +2 -2
  28. package/dist-esm/lib/editor/Editor.mjs +12 -2
  29. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  30. package/dist-esm/lib/editor/managers/EditorManager.mjs +32 -0
  31. package/dist-esm/lib/editor/managers/EditorManager.mjs.map +7 -0
  32. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +9 -11
  33. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
  34. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +5 -9
  35. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
  36. package/dist-esm/lib/editor/managers/SpatialIndexManager/RBushIndex.mjs +18 -29
  37. package/dist-esm/lib/editor/managers/SpatialIndexManager/RBushIndex.mjs.map +2 -2
  38. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +103 -56
  39. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +2 -2
  40. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +24 -19
  41. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  42. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +4 -7
  43. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
  44. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +1 -1
  45. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +1 -2
  46. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
  47. package/dist-esm/version.mjs +3 -3
  48. package/dist-esm/version.mjs.map +1 -1
  49. package/package.json +7 -7
  50. package/src/index.ts +1 -1
  51. package/src/lib/editor/Editor.ts +15 -2
  52. package/src/lib/editor/managers/EditorManager.test.ts +51 -0
  53. package/src/lib/editor/managers/EditorManager.ts +60 -0
  54. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +2 -1
  55. package/src/lib/editor/managers/FocusManager/FocusManager.ts +10 -14
  56. package/src/lib/editor/managers/InputsManager/InputsManager.ts +6 -9
  57. package/src/lib/editor/managers/SpatialIndexManager/RBushIndex.ts +19 -33
  58. package/src/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.ts +173 -86
  59. package/src/lib/editor/managers/TextManager/TextManager.test.ts +61 -1
  60. package/src/lib/editor/managers/TextManager/TextManager.ts +33 -19
  61. package/src/lib/editor/managers/TickManager/TickManager.test.ts +0 -10
  62. package/src/lib/editor/managers/TickManager/TickManager.ts +5 -6
  63. package/src/lib/editor/shapes/ShapeUtil.ts +1 -0
  64. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +2 -2
  65. package/src/version.ts +3 -3
  66. package/dist-cjs/lib/editor/tools/cancelShapeCreationOnLongPress.js +0 -28
  67. package/dist-cjs/lib/editor/tools/cancelShapeCreationOnLongPress.js.map +0 -7
  68. package/dist-esm/lib/editor/tools/cancelShapeCreationOnLongPress.mjs +0 -8
  69. package/dist-esm/lib/editor/tools/cancelShapeCreationOnLongPress.mjs.map +0 -7
  70. package/src/lib/editor/tools/cancelShapeCreationOnLongPress.ts +0 -31
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts"],
4
- "sourcesContent": ["import { TLShape, createShapeId } from '@tldraw/tlschema'\nimport { structuredClone } from '@tldraw/utils'\nimport { Vec } from '../../../../primitives/Vec'\nimport type { Editor } from '../../../Editor'\nimport { TLBaseBoxShape } from '../../../shapes/BaseBoxShapeUtil'\nimport { TLPointerEventInfo } from '../../../types/event-types'\nimport { cancelShapeCreationOnLongPress } from '../../cancelShapeCreationOnLongPress'\nimport { StateNode } from '../../StateNode'\nimport type { BaseBoxShapeTool } from '../BaseBoxShapeTool'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tconst { editor } = this\n\t\tif (editor.inputs.getIsDragging()) {\n\t\t\tconst originPagePoint = editor.inputs.getOriginPagePoint()\n\n\t\t\tconst shapeType = (this.parent as BaseBoxShapeTool)!.shapeType\n\n\t\t\tconst id = createShapeId()\n\n\t\t\tconst creatingMarkId = editor.markHistoryStoppingPoint(`creating_box:${id}`)\n\t\t\tconst newPoint = maybeSnapToGrid(originPagePoint, editor)\n\n\t\t\t// Allow this to trigger the max shapes reached alert\n\t\t\tthis.editor.createShapes([\n\t\t\t\t{\n\t\t\t\t\tid,\n\t\t\t\t\ttype: shapeType,\n\t\t\t\t\tx: newPoint.x,\n\t\t\t\t\ty: newPoint.y,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tw: 1,\n\t\t\t\t\t\th: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t])\n\t\t\tconst shape = editor.getShape(id)\n\t\t\tif (!shape) {\n\t\t\t\tthis.cancel()\n\t\t\t\treturn\n\t\t\t}\n\t\t\teditor.select(id)\n\n\t\t\tconst parent = this.parent as BaseBoxShapeTool\n\t\t\tthis.editor.setCurrentTool(\n\t\t\t\t'select.resizing',\n\t\t\t\t{\n\t\t\t\t\t...info,\n\t\t\t\t\ttarget: 'selection',\n\t\t\t\t\thandle: 'bottom_right',\n\t\t\t\t\tisCreating: true,\n\t\t\t\t\tcreatingMarkId,\n\t\t\t\t\tcreationCursorOffset: { x: 1, y: 1 },\n\t\t\t\t\tonInteractionEnd: this.parent.id,\n\t\t\t\t\tonCreate: parent.onCreate\n\t\t\t\t\t\t? (shape: TLShape | null) => parent.onCreate?.(shape)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t} /** satisfies ResizingInfo, defined in main tldraw package \uD83D\uDE27 */\n\t\t\t)\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onLongPress() {\n\t\tcancelShapeCreationOnLongPress(this.editor, () => this.cancel())\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tcomplete() {\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\n\t\tconst shapeType = (this.parent as BaseBoxShapeTool)!.shapeType as TLBaseBoxShape['type']\n\n\t\tconst id = createShapeId()\n\n\t\tthis.editor.markHistoryStoppingPoint(`creating_box:${id}`)\n\n\t\t// Allow this to trigger the max shapes reached alert\n\t\t// todo: add scale here when dynamic size is enabled (is this still needed?)\n\t\tthis.editor.createShapes([\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\ttype: shapeType,\n\t\t\t\tx: originPagePoint.x,\n\t\t\t\ty: originPagePoint.y,\n\t\t\t},\n\t\t])\n\n\t\tconst shape = this.editor.getShape<TLBaseBoxShape>(id)!\n\t\tif (!shape) {\n\t\t\tthis.cancel()\n\t\t\treturn\n\t\t}\n\n\t\tlet { w, h } = shape.props\n\t\tconst delta = new Vec(w / 2, h / 2)\n\t\tconst parentTransform = this.editor.getShapeParentTransform(shape)\n\t\tif (parentTransform) delta.rot(-parentTransform.rotation())\n\t\tconst scale = this.editor.getResizeScaleFactor()\n\n\t\t// A scale factor of 1 means dynamic sizing is not affecting this shape.\n\t\tif (scale !== 1) {\n\t\t\tw *= scale\n\t\t\th *= scale\n\t\t\tdelta.mul(scale)\n\t\t}\n\n\t\tconst next = structuredClone(shape)\n\t\tconst newPoint = maybeSnapToGrid(new Vec(shape.x - delta.x, shape.y - delta.y), this.editor)\n\t\tnext.x = newPoint.x\n\t\tnext.y = newPoint.y\n\t\tnext.props.w = w\n\t\tnext.props.h = h\n\n\t\tif ('scale' in shape.props) {\n\t\t\t;(next as TLBaseBoxShape & { props: { scale: number } }).props.scale = scale\n\t\t}\n\n\t\tthis.editor.updateShape(next)\n\n\t\tthis.editor.setSelectedShapes([id])\n\n\t\tif (this.editor.getInstanceState().isToolLocked) {\n\t\t\tthis.parent.transition('idle')\n\t\t} else {\n\t\t\tthis.editor.setCurrentTool('select.idle')\n\t\t}\n\t}\n\n\tcancel() {\n\t\tthis.parent.transition('idle')\n\t}\n}\n\n/**\n * Checks if grid mode is enabled and snaps a point to the grid if so\n *\n * @public\n */\nexport function maybeSnapToGrid(point: Vec, editor: Editor): Vec {\n\tconst isGridMode = editor.getInstanceState().isGridMode\n\tconst gridSize = editor.getDocumentSettings().gridSize\n\tif (isGridMode) return point.clone().snapToGrid(gridSize)\n\treturn point.clone()\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { TLShape, createShapeId } from '@tldraw/tlschema'\nimport { structuredClone } from '@tldraw/utils'\nimport { Vec } from '../../../../primitives/Vec'\nimport type { Editor } from '../../../Editor'\nimport { TLBaseBoxShape } from '../../../shapes/BaseBoxShapeUtil'\nimport { TLPointerEventInfo } from '../../../types/event-types'\nimport { StateNode } from '../../StateNode'\nimport type { BaseBoxShapeTool } from '../BaseBoxShapeTool'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tconst { editor } = this\n\t\tif (editor.inputs.getIsDragging()) {\n\t\t\tconst originPagePoint = editor.inputs.getOriginPagePoint()\n\n\t\t\tconst shapeType = (this.parent as BaseBoxShapeTool)!.shapeType\n\n\t\t\tconst id = createShapeId()\n\n\t\t\tconst creatingMarkId = editor.markHistoryStoppingPoint(`creating_box:${id}`)\n\t\t\tconst newPoint = maybeSnapToGrid(originPagePoint, editor)\n\n\t\t\t// Allow this to trigger the max shapes reached alert\n\t\t\tthis.editor.createShapes([\n\t\t\t\t{\n\t\t\t\t\tid,\n\t\t\t\t\ttype: shapeType,\n\t\t\t\t\tx: newPoint.x,\n\t\t\t\t\ty: newPoint.y,\n\t\t\t\t\tprops: {\n\t\t\t\t\t\tw: 1,\n\t\t\t\t\t\th: 1,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t])\n\t\t\tconst shape = editor.getShape(id)\n\t\t\tif (!shape) {\n\t\t\t\tthis.cancel()\n\t\t\t\treturn\n\t\t\t}\n\t\t\teditor.select(id)\n\n\t\t\tconst parent = this.parent as BaseBoxShapeTool\n\t\t\tthis.editor.setCurrentTool(\n\t\t\t\t'select.resizing',\n\t\t\t\t{\n\t\t\t\t\t...info,\n\t\t\t\t\ttarget: 'selection',\n\t\t\t\t\thandle: 'bottom_right',\n\t\t\t\t\tisCreating: true,\n\t\t\t\t\tcreatingMarkId,\n\t\t\t\t\tcreationCursorOffset: { x: 1, y: 1 },\n\t\t\t\t\tonInteractionEnd: this.parent.id,\n\t\t\t\t\tonCreate: parent.onCreate\n\t\t\t\t\t\t? (shape: TLShape | null) => parent.onCreate?.(shape)\n\t\t\t\t\t\t: undefined,\n\t\t\t\t} /** satisfies ResizingInfo, defined in main tldraw package \uD83D\uDE27 */\n\t\t\t)\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onLongPress() {\n\t\t// On a touch (coarse pointer) long-press, cancel the pending shape so it leaves nothing behind.\n\t\tif (this.editor.getInstanceState().isCoarsePointer) this.cancel()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tcomplete() {\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\n\t\tconst shapeType = (this.parent as BaseBoxShapeTool)!.shapeType as TLBaseBoxShape['type']\n\n\t\tconst id = createShapeId()\n\n\t\tthis.editor.markHistoryStoppingPoint(`creating_box:${id}`)\n\n\t\t// Allow this to trigger the max shapes reached alert\n\t\t// todo: add scale here when dynamic size is enabled (is this still needed?)\n\t\tthis.editor.createShapes([\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\ttype: shapeType,\n\t\t\t\tx: originPagePoint.x,\n\t\t\t\ty: originPagePoint.y,\n\t\t\t},\n\t\t])\n\n\t\tconst shape = this.editor.getShape<TLBaseBoxShape>(id)!\n\t\tif (!shape) {\n\t\t\tthis.cancel()\n\t\t\treturn\n\t\t}\n\n\t\tlet { w, h } = shape.props\n\t\tconst delta = new Vec(w / 2, h / 2)\n\t\tconst parentTransform = this.editor.getShapeParentTransform(shape)\n\t\tif (parentTransform) delta.rot(-parentTransform.rotation())\n\t\tconst scale = this.editor.getResizeScaleFactor()\n\n\t\t// A scale factor of 1 means dynamic sizing is not affecting this shape.\n\t\tif (scale !== 1) {\n\t\t\tw *= scale\n\t\t\th *= scale\n\t\t\tdelta.mul(scale)\n\t\t}\n\n\t\tconst next = structuredClone(shape)\n\t\tconst newPoint = maybeSnapToGrid(new Vec(shape.x - delta.x, shape.y - delta.y), this.editor)\n\t\tnext.x = newPoint.x\n\t\tnext.y = newPoint.y\n\t\tnext.props.w = w\n\t\tnext.props.h = h\n\n\t\tif ('scale' in shape.props) {\n\t\t\t;(next as TLBaseBoxShape & { props: { scale: number } }).props.scale = scale\n\t\t}\n\n\t\tthis.editor.updateShape(next)\n\n\t\tthis.editor.setSelectedShapes([id])\n\n\t\tif (this.editor.getInstanceState().isToolLocked) {\n\t\t\tthis.parent.transition('idle')\n\t\t} else {\n\t\t\tthis.editor.setCurrentTool('select.idle')\n\t\t}\n\t}\n\n\tcancel() {\n\t\tthis.parent.transition('idle')\n\t}\n}\n\n/**\n * Checks if grid mode is enabled and snaps a point to the grid if so\n *\n * @public\n */\nexport function maybeSnapToGrid(point: Vec, editor: Editor): Vec {\n\tconst isGridMode = editor.getInstanceState().isGridMode\n\tconst gridSize = editor.getDocumentSettings().gridSize\n\tif (isGridMode) return point.clone().snapToGrid(gridSize)\n\treturn point.clone()\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["shape"]
7
7
  }
@@ -1,8 +1,8 @@
1
- const version = "5.2.1";
1
+ const version = "5.3.0-canary.7d00ddf70f63";
2
2
  const publishDates = {
3
3
  major: "2026-05-06T16:28:18.473Z",
4
- minor: "2026-07-01T09:20:01.735Z",
5
- patch: "2026-07-01T10:28:54.350Z"
4
+ minor: "2026-07-01T14:32:31.738Z",
5
+ patch: "2026-07-01T14:32:31.738Z"
6
6
  };
7
7
  export {
8
8
  publishDates,
@@ -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 = '5.2.1'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-01T09:20:01.735Z',\n\tpatch: '2026-07-01T10:28:54.350Z',\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 = '5.3.0-canary.7d00ddf70f63'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-01T14:32:31.738Z',\n\tpatch: '2026-07-01T14:32:31.738Z',\n}\n"],
5
5
  "mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tldraw/editor",
3
3
  "description": "tldraw infinite canvas SDK (editor).",
4
- "version": "5.2.1",
4
+ "version": "5.3.0-canary.7d00ddf70f63",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -49,12 +49,12 @@
49
49
  "@tiptap/core": "^3.12.1",
50
50
  "@tiptap/pm": "^3.12.1",
51
51
  "@tiptap/react": "^3.12.1",
52
- "@tldraw/state": "5.2.1",
53
- "@tldraw/state-react": "5.2.1",
54
- "@tldraw/store": "5.2.1",
55
- "@tldraw/tlschema": "5.2.1",
56
- "@tldraw/utils": "5.2.1",
57
- "@tldraw/validate": "5.2.1",
52
+ "@tldraw/state": "5.3.0-canary.7d00ddf70f63",
53
+ "@tldraw/state-react": "5.3.0-canary.7d00ddf70f63",
54
+ "@tldraw/store": "5.3.0-canary.7d00ddf70f63",
55
+ "@tldraw/tlschema": "5.3.0-canary.7d00ddf70f63",
56
+ "@tldraw/utils": "5.3.0-canary.7d00ddf70f63",
57
+ "@tldraw/validate": "5.3.0-canary.7d00ddf70f63",
58
58
  "classnames": "^2.5.1",
59
59
  "eventemitter3": "^4.0.7",
60
60
  "idb": "^7.1.1",
package/src/index.ts CHANGED
@@ -102,6 +102,7 @@ export { ClickManager, type TLClickState } from './lib/editor/managers/ClickMana
102
102
  export { EdgeScrollManager } from './lib/editor/managers/EdgeScrollManager/EdgeScrollManager'
103
103
  export { FontManager } from './lib/editor/managers/FontManager/FontManager'
104
104
  export { HistoryManager } from './lib/editor/managers/HistoryManager/HistoryManager'
105
+ export { EditorManager } from './lib/editor/managers/EditorManager'
105
106
  export { InputsManager } from './lib/editor/managers/InputsManager/InputsManager'
106
107
  export {
107
108
  ScribbleManager,
@@ -191,7 +192,6 @@ export { resizeBox, type ResizeBoxOptions } from './lib/editor/shapes/shared/res
191
192
  export { resizeScaled } from './lib/editor/shapes/shared/resizeScaled'
192
193
  export { BaseBoxShapeTool } from './lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool'
193
194
  export { maybeSnapToGrid } from './lib/editor/tools/BaseBoxShapeTool/children/Pointing'
194
- export { cancelShapeCreationOnLongPress } from './lib/editor/tools/cancelShapeCreationOnLongPress'
195
195
  export { StateNode, type TLStateNodeConstructor } from './lib/editor/tools/StateNode'
196
196
  export { type TLContent } from './lib/editor/types/clipboard-types'
197
197
  export { type TLEventMap, type TLEventMapHandler } from './lib/editor/types/emit-types'
@@ -563,6 +563,7 @@ export class Editor extends EventEmitter<TLEventMap> {
563
563
  let deletedBindings = new Map<TLBindingId, BindingOnDeleteOptions<any>>()
564
564
  const deletedShapeIds = new Set<TLShapeId>()
565
565
  const invalidParents = new Set<TLShapeId>()
566
+ const createdShapes = new Set<TLShapeId>()
566
567
  let invalidBindingTypes = new Set<TLBinding['type']>()
567
568
 
568
569
  this.disposables.add(
@@ -571,8 +572,12 @@ export class Editor extends EventEmitter<TLEventMap> {
571
572
  // and we want the next invocation of this handler to handle those separately
572
573
  deletedShapeIds.clear()
573
574
 
575
+ const justCreatedShapeIds = new Set(createdShapes)
576
+ createdShapes.clear()
577
+
574
578
  for (const parentId of invalidParents) {
575
579
  invalidParents.delete(parentId)
580
+ if (justCreatedShapeIds.has(parentId)) continue
576
581
  const parent = this.getShape(parentId)
577
582
  if (!parent) continue
578
583
 
@@ -608,6 +613,12 @@ export class Editor extends EventEmitter<TLEventMap> {
608
613
  this.disposables.add(
609
614
  this.sideEffects.register({
610
615
  shape: {
616
+ afterCreate: (shape) => {
617
+ createdShapes.add(shape.id)
618
+ if (shape.parentId && isShapeId(shape.parentId)) {
619
+ invalidParents.add(shape.parentId)
620
+ }
621
+ },
611
622
  afterChange: (shapeBefore, shapeAfter) => {
612
623
  for (const binding of this.getBindingsInvolvingShape(shapeAfter)) {
613
624
  invalidBindingTypes.add(binding.type)
@@ -891,7 +902,7 @@ export class Editor extends EventEmitter<TLEventMap> {
891
902
 
892
903
  this.edgeScrollManager = new EdgeScrollManager(this)
893
904
  this.focusManager = new FocusManager(this, autoFocus)
894
- this.disposables.add(this.focusManager.dispose.bind(this.focusManager))
905
+ this.disposables.add(() => this.focusManager.dispose())
895
906
 
896
907
  if (this.getInstanceState().followingUserId) {
897
908
  this.stopFollowingUser()
@@ -10983,7 +10994,9 @@ export class Editor extends EventEmitter<TLEventMap> {
10983
10994
  this._ctrlKeyTimeout = this.timers.setTimeout(this._setCtrlKeyTimeout, 150)
10984
10995
  }
10985
10996
 
10986
- if (info.metaKey) {
10997
+ if (info.metaKey && info.name !== 'key_up') {
10998
+ // Unlike the other modifiers, the native metaKey property is still true on keyup.
10999
+ // If we don't have this guard, then the metakey will be left true without the timeout.
10987
11000
  clearTimeout(this._metaKeyTimeout)
10988
11001
  this._metaKeyTimeout = -1
10989
11002
  inputs.setMetaKey(true)
@@ -0,0 +1,51 @@
1
+ import { vi } from 'vitest'
2
+ import type { Editor } from '../Editor'
3
+ import { EditorManager } from './EditorManager'
4
+
5
+ class TestManager extends EditorManager {
6
+ onTestEvent = vi.fn()
7
+
8
+ constructor(editor: Editor) {
9
+ super(editor)
10
+ this.addEditorEvent('frame', this.onTestEvent)
11
+ }
12
+
13
+ cancelRaf = vi.fn()
14
+ startRaf() {
15
+ this.register(this.cancelRaf)
16
+ }
17
+ }
18
+
19
+ describe('EditorManager', () => {
20
+ let on: ReturnType<typeof vi.fn>
21
+ let off: ReturnType<typeof vi.fn>
22
+ let editor: Editor
23
+ let manager: TestManager
24
+
25
+ beforeEach(() => {
26
+ on = vi.fn()
27
+ off = vi.fn()
28
+ editor = { on, off } as unknown as Editor
29
+ manager = new TestManager(editor)
30
+ })
31
+
32
+ it('addEditorEvent registers a listener on the editor', () => {
33
+ expect(on).toHaveBeenCalledWith('frame', manager.onTestEvent)
34
+ })
35
+
36
+ it('dispose removes registered editor listeners', () => {
37
+ manager.dispose()
38
+ expect(off).toHaveBeenCalledWith('frame', manager.onTestEvent)
39
+ })
40
+
41
+ it('register runs custom disposables on dispose', () => {
42
+ manager.startRaf()
43
+ manager.dispose()
44
+ expect(manager.cancelRaf).toHaveBeenCalled()
45
+ })
46
+
47
+ it('dispose is safe to call twice', () => {
48
+ manager.dispose()
49
+ expect(() => manager.dispose()).not.toThrow()
50
+ })
51
+ })
@@ -0,0 +1,60 @@
1
+ import type { Editor } from '../Editor'
2
+ import type { TLEventMap } from '../types/emit-types'
3
+
4
+ /**
5
+ * Base class for editor-attached managers that need to clean up after themselves.
6
+ *
7
+ * Extending `EditorManager` gives a manager one consistent teardown contract: register
8
+ * anything that needs undoing, and it runs automatically on `dispose()`. This keeps
9
+ * subscription lifecycle symmetric — whatever sets a thing up is what tears it down — so
10
+ * it can't be forgotten (the failure mode behind the strict-mode camera bug, #8892).
11
+ *
12
+ * Register cleanup by what you're creating:
13
+ *
14
+ * - Editor bus event (`tick`, `frame`, `change`, …): {@link EditorManager.addEditorEvent}
15
+ * - Store side effect (`editor.sideEffects.register…`): `this.register(disposer)`
16
+ * - Reaction (`react(...)` from `@tldraw/state`): `this.register(react(...))`
17
+ * - DOM listener: `this.register(() => el.removeEventListener(...))`
18
+ * - Other resource (cache, index, child manager): `this.register(() => x.dispose())`
19
+ *
20
+ * For timeouts, intervals, and animation frames prefer `editor.timers` (context-grouped
21
+ * and auto-disposed) over raw `setTimeout`. For cleanup on the editor itself rather than a
22
+ * manager, use `editor.disposables`.
23
+ *
24
+ * If a manager needs ordered teardown (e.g. pause a loop before cancelling it), override
25
+ * `dispose()` and call `super.dispose()` last — see `TickManager`.
26
+ *
27
+ * @public
28
+ */
29
+ export abstract class EditorManager {
30
+ protected readonly disposables = new Set<() => void>()
31
+
32
+ constructor(protected readonly editor: Editor) {}
33
+
34
+ /**
35
+ * Register a teardown function to run on `dispose()`. The universal way for a manager to
36
+ * make a resource "see itself out". Returns the same function for convenience.
37
+ */
38
+ protected register(dispose: () => void): () => void {
39
+ this.disposables.add(dispose)
40
+ return dispose
41
+ }
42
+
43
+ /**
44
+ * Subscribe to an editor bus event and register the matching unsubscribe, so the listener
45
+ * is removed automatically on `dispose()`.
46
+ */
47
+ protected addEditorEvent<E extends keyof TLEventMap>(
48
+ event: E,
49
+ fn: (...args: TLEventMap[E]) => void
50
+ ): void {
51
+ this.editor.on(event, fn as any)
52
+ this.register(() => this.editor.off(event, fn as any))
53
+ }
54
+
55
+ /** @internal */
56
+ dispose(): void {
57
+ this.disposables.forEach((d) => d())
58
+ this.disposables.clear()
59
+ }
60
+ }
@@ -73,7 +73,8 @@ describe('FocusManager', () => {
73
73
  describe('constructor', () => {
74
74
  it('should initialize with editor reference', () => {
75
75
  focusManager = new FocusManager(editor)
76
- expect(focusManager.editor).toBe(editor)
76
+ expect(focusManager).toBeInstanceOf(FocusManager)
77
+ expect(editor.sideEffects.registerAfterChangeHandler).toHaveBeenCalled()
77
78
  })
78
79
 
79
80
  it('should register side effect listener for instance state changes', () => {
@@ -1,5 +1,6 @@
1
1
  import { bind } from '@tldraw/utils'
2
2
  import type { Editor } from '../../Editor'
3
+ import { EditorManager } from '../EditorManager'
3
4
 
4
5
  /**
5
6
  * A manager for ensuring correct focus across the editor.
@@ -10,14 +11,11 @@ import type { Editor } from '../../Editor'
10
11
  *
11
12
  * @internal
12
13
  */
13
- export class FocusManager {
14
- private disposeSideEffectListener?: () => void
14
+ export class FocusManager extends EditorManager {
15
+ constructor(editor: Editor, autoFocus?: boolean) {
16
+ super(editor)
15
17
 
16
- constructor(
17
- public editor: Editor,
18
- autoFocus?: boolean
19
- ) {
20
- this.disposeSideEffectListener = editor.sideEffects.registerAfterChangeHandler(
18
+ const disposeSideEffectListener = editor.sideEffects.registerAfterChangeHandler(
21
19
  'instance',
22
20
  (prev, next) => {
23
21
  if (prev.isFocused !== next.isFocused) {
@@ -25,6 +23,7 @@ export class FocusManager {
25
23
  }
26
24
  }
27
25
  )
26
+ this.register(() => disposeSideEffectListener?.())
28
27
 
29
28
  const currentFocusState = editor.getInstanceState().isFocused
30
29
  if (autoFocus !== currentFocusState) {
@@ -35,6 +34,10 @@ export class FocusManager {
35
34
  const body = editor.getContainerDocument().body
36
35
  body.addEventListener('keydown', this.handleKeyDown)
37
36
  body.addEventListener('mousedown', this.handleMouseDown)
37
+ this.register(() => {
38
+ body.removeEventListener('keydown', this.handleKeyDown)
39
+ body.removeEventListener('mousedown', this.handleMouseDown)
40
+ })
38
41
  }
39
42
 
40
43
  /**
@@ -83,11 +86,4 @@ export class FocusManager {
83
86
  this.editor.complete() // stop any interaction
84
87
  if (blurContainer) this.editor.getContainer().blur() // blur the container
85
88
  }
86
-
87
- dispose() {
88
- const body = this.editor.getContainerDocument().body
89
- body.removeEventListener('keydown', this.handleKeyDown)
90
- body.removeEventListener('mousedown', this.handleMouseDown)
91
- this.disposeSideEffectListener?.()
92
- }
93
89
  }
@@ -7,19 +7,16 @@ import { Vec } from '../../../primitives/Vec'
7
7
  import { isAccelKey } from '../../../utils/keyboard'
8
8
  import type { Editor } from '../../Editor'
9
9
  import { TLPinchEventInfo, TLPointerEventInfo, TLWheelEventInfo } from '../../types/event-types'
10
+ import { EditorManager } from '../EditorManager'
10
11
 
11
12
  const POINTER_VELOCITY_REFERENCE_INTERVAL_MS = 16
12
13
  const POINTER_VELOCITY_REFERENCE_SMOOTHING = 0.5
13
14
 
14
15
  /** @public */
15
- export class InputsManager {
16
- constructor(private readonly editor: Editor) {
17
- this.editor.on('frame', this._onFrame)
18
- }
19
-
20
- /** @internal */
21
- dispose() {
22
- this.editor.off('frame', this._onFrame)
16
+ export class InputsManager extends EditorManager {
17
+ constructor(editor: Editor) {
18
+ super(editor)
19
+ this.addEditorEvent('frame', this._onFrame)
23
20
  }
24
21
 
25
22
  @bind
@@ -472,7 +469,7 @@ export class InputsManager {
472
469
  private _velocityPrevPoint = new Vec()
473
470
 
474
471
  /**
475
- * Update the pointer velocity based on elapsed time. Called each frame.
472
+ * Update the pointer velocity based on elapsed time. Called by the tick manager.
476
473
  * @param elapsed - The time elapsed since the last tick in milliseconds.
477
474
  * @internal
478
475
  */
@@ -46,28 +46,6 @@ export class RBushIndex {
46
46
  return new Set(results.map((e: SpatialElement) => e.id))
47
47
  }
48
48
 
49
- /**
50
- * Insert or update a shape in the spatial index.
51
- * If the shape already exists, it will be removed first to prevent duplicates.
52
- */
53
- upsert(id: TLShapeId, bounds: Box): void {
54
- // Remove existing entry to prevent map-tree desync
55
- const existing = this.elementsInTree.get(id)
56
- if (existing) {
57
- this.rBush.remove(existing)
58
- }
59
-
60
- const element: SpatialElement = {
61
- minX: bounds.minX,
62
- minY: bounds.minY,
63
- maxX: bounds.maxX,
64
- maxY: bounds.maxY,
65
- id,
66
- }
67
- this.rBush.insert(element)
68
- this.elementsInTree.set(id, element)
69
- }
70
-
71
49
  /**
72
50
  * Remove a shape from the spatial index.
73
51
  */
@@ -79,6 +57,25 @@ export class RBushIndex {
79
57
  }
80
58
  }
81
59
 
60
+ /**
61
+ * Apply the removals and upserts collected during one incremental update.
62
+ * Mutations are applied per item: bulk-rebuilding the whole tree instead
63
+ * was measured slower even with ~10% of the index in the batch.
64
+ */
65
+ applyBatch(removes: Set<TLShapeId>, upserts: SpatialElement[]): void {
66
+ for (const id of removes) {
67
+ this.remove(id)
68
+ }
69
+ for (const element of upserts) {
70
+ const existing = this.elementsInTree.get(element.id)
71
+ if (existing) {
72
+ this.rBush.remove(existing)
73
+ }
74
+ this.rBush.insert(element)
75
+ this.elementsInTree.set(element.id, element)
76
+ }
77
+ }
78
+
82
79
  /**
83
80
  * Bulk load elements into the spatial index.
84
81
  * More efficient than individual inserts for initial loading.
@@ -122,17 +119,6 @@ export class RBushIndex {
122
119
  return this.elementsInTree.get(id)
123
120
  }
124
121
 
125
- /**
126
- * Iterate the entries currently in the index. Callers may upsert existing
127
- * keys or remove keys during iteration; current callers do not insert new
128
- * keys.
129
- *
130
- * @internal
131
- */
132
- entries(): IterableIterator<[TLShapeId, SpatialElement]> {
133
- return this.elementsInTree.entries()
134
- }
135
-
136
122
  /**
137
123
  * Dispose of the spatial index.
138
124
  * Clears all data structures to prevent memory leaks.