@tldraw/editor 4.3.0-canary.da35795ba8e2 → 4.3.0-canary.eb3bbfa1daab

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 (58) hide show
  1. package/dist-cjs/index.d.ts +56 -35
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  4. package/dist-cjs/lib/editor/Editor.js +4 -12
  5. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  6. package/dist-cjs/lib/editor/bindings/BindingUtil.js.map +2 -2
  7. package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
  8. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
  9. package/dist-cjs/lib/editor/shapes/BaseBoxShapeUtil.js.map +1 -1
  10. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  11. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.js.map +2 -2
  13. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
  14. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  15. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  16. package/dist-cjs/lib/globals/menus.js +1 -1
  17. package/dist-cjs/lib/globals/menus.js.map +2 -2
  18. package/dist-cjs/lib/utils/reparenting.js.map +2 -2
  19. package/dist-cjs/version.js +3 -3
  20. package/dist-cjs/version.js.map +1 -1
  21. package/dist-esm/index.d.mts +56 -35
  22. package/dist-esm/index.mjs +1 -1
  23. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  24. package/dist-esm/lib/editor/Editor.mjs +4 -12
  25. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  26. package/dist-esm/lib/editor/bindings/BindingUtil.mjs.map +2 -2
  27. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
  28. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
  29. package/dist-esm/lib/editor/shapes/BaseBoxShapeUtil.mjs.map +1 -1
  30. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  31. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  32. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.mjs.map +2 -2
  33. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
  34. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  35. package/dist-esm/lib/globals/menus.mjs +1 -1
  36. package/dist-esm/lib/globals/menus.mjs.map +2 -2
  37. package/dist-esm/lib/utils/reparenting.mjs.map +2 -2
  38. package/dist-esm/version.mjs +3 -3
  39. package/dist-esm/version.mjs.map +1 -1
  40. package/package.json +10 -10
  41. package/src/lib/components/default-components/DefaultCanvas.tsx +1 -0
  42. package/src/lib/editor/Editor.test.ts +10 -10
  43. package/src/lib/editor/Editor.ts +85 -59
  44. package/src/lib/editor/bindings/BindingUtil.ts +15 -9
  45. package/src/lib/editor/derivations/bindingsIndex.ts +2 -2
  46. package/src/lib/editor/managers/FontManager/FontManager.test.ts +14 -4
  47. package/src/lib/editor/managers/SnapManager/SnapManager.ts +3 -3
  48. package/src/lib/editor/shapes/BaseBoxShapeUtil.tsx +2 -2
  49. package/src/lib/editor/shapes/ShapeUtil.ts +5 -8
  50. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +1 -3
  51. package/src/lib/editor/tools/BaseBoxShapeTool/BaseBoxShapeTool.ts +2 -1
  52. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +3 -3
  53. package/src/lib/editor/types/emit-types.ts +2 -1
  54. package/src/lib/exports/getSvgJsx.test.ts +10 -19
  55. package/src/lib/exports/getSvgJsx.tsx +2 -5
  56. package/src/lib/globals/menus.ts +1 -1
  57. package/src/lib/utils/reparenting.ts +5 -5
  58. package/src/version.ts +3 -3
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/utils/reparenting.ts"],
4
- "sourcesContent": ["import { EMPTY_ARRAY } from '@tldraw/state'\nimport { TLGroupShape, TLParentId, TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { IndexKey, compact, getIndexAbove, getIndexBetween } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\nimport { intersectPolygonPolygon } from '../primitives/intersect'\n\n/**\n * Reparents shapes that are no longer contained within their parent shapes.\n * todo: rename me to something more descriptive, like `reparentOccludedShapes` or `reparentAutoDroppedShapes`\n *\n * @param editor - The editor instance.\n * @param shapeIds - The IDs of the shapes to reparent.\n * @param opts - Optional options, including a callback to filter out certain parents, such as when removing a frame.\n *\n * @public\n */\nexport function kickoutOccludedShapes(\n\teditor: Editor,\n\tshapeIds: TLShapeId[],\n\topts?: { filter?(parent: TLShape): boolean }\n) {\n\tconst parentsToCheck = new Set<TLShape>()\n\n\tfor (const id of shapeIds) {\n\t\tconst shape = editor.getShape(id)\n\n\t\tif (!shape) continue\n\t\tparentsToCheck.add(shape)\n\n\t\tconst parent = editor.getShape(shape.parentId)\n\t\tif (!parent) continue\n\t\tparentsToCheck.add(parent)\n\t}\n\n\t// Check all of the parents and gather up parents who have lost children\n\tconst parentsToLostChildren = new Map<TLShape, TLShapeId[]>()\n\n\tfor (const parent of parentsToCheck) {\n\t\tconst childIds = editor.getSortedChildIdsForParent(parent)\n\t\tif (opts?.filter && !opts.filter(parent)) {\n\t\t\t// If the shape is filtered out, we kick out all of its children\n\t\t\tparentsToLostChildren.set(parent, childIds)\n\t\t} else {\n\t\t\tconst overlappingChildren = getOverlappingShapes(editor, parent.id, childIds)\n\t\t\tif (overlappingChildren.length < childIds.length) {\n\t\t\t\tparentsToLostChildren.set(\n\t\t\t\t\tparent,\n\t\t\t\t\tchildIds.filter((id) => !overlappingChildren.includes(id))\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Get all of the shapes on the current page, sorted by their index\n\tconst sortedShapeIds = editor.getCurrentPageShapesSorted().map((s) => s.id)\n\n\tconst parentsToNewChildren: Record<\n\t\tTLParentId,\n\t\t{ parentId: TLParentId; shapeIds: TLShapeId[]; index?: IndexKey }\n\t> = {}\n\n\tfor (const [prevParent, lostChildrenIds] of parentsToLostChildren) {\n\t\tconst lostChildren = compact(lostChildrenIds.map((id) => editor.getShape(id)))\n\n\t\t// Don't fall \"up\" into frames in front of the shape\n\t\t// if (pageShapes.indexOf(shape) < frameSortPosition) continue shapeCheck\n\n\t\t// Otherwise, we have no next dropping shape under the cursor, so go find\n\t\t// all the frames on the page where the moving shapes will fall into\n\t\tconst { reparenting, remainingShapesToReparent } = getDroppedShapesToNewParents(\n\t\t\teditor,\n\t\t\tlostChildren,\n\t\t\t(shape, maybeNewParent) => {\n\t\t\t\t// If we're filtering out a potential parent, don't reparent shapes to the filtered out shape\n\t\t\t\tif (opts?.filter && !opts.filter(maybeNewParent)) return false\n\t\t\t\treturn (\n\t\t\t\t\tmaybeNewParent.id !== prevParent.id &&\n\t\t\t\t\tsortedShapeIds.indexOf(maybeNewParent.id) < sortedShapeIds.indexOf(shape.id)\n\t\t\t\t)\n\t\t\t}\n\t\t)\n\n\t\treparenting.forEach((childrenToReparent, newParentId) => {\n\t\t\tif (childrenToReparent.length === 0) return\n\t\t\tif (!parentsToNewChildren[newParentId]) {\n\t\t\t\tparentsToNewChildren[newParentId] = {\n\t\t\t\t\tparentId: newParentId,\n\t\t\t\t\tshapeIds: [],\n\t\t\t\t}\n\t\t\t}\n\t\t\tparentsToNewChildren[newParentId].shapeIds.push(...childrenToReparent.map((s) => s.id))\n\t\t})\n\n\t\t// Reparent the rest to the page (or containing group)\n\t\tif (remainingShapesToReparent.size > 0) {\n\t\t\t// The remaining shapes are going to be reparented to the old parent's containing group, if there was one, or else to the page\n\t\t\tconst newParentId =\n\t\t\t\teditor.findShapeAncestor(prevParent, (s) => editor.isShapeOfType<TLGroupShape>(s, 'group'))\n\t\t\t\t\t?.id ?? editor.getCurrentPageId()\n\n\t\t\tremainingShapesToReparent.forEach((shape) => {\n\t\t\t\tif (!parentsToNewChildren[newParentId]) {\n\t\t\t\t\tlet insertIndexKey: IndexKey | undefined\n\n\t\t\t\t\tconst oldParentSiblingIds = editor.getSortedChildIdsForParent(newParentId)\n\t\t\t\t\tconst oldParentIndex = oldParentSiblingIds.indexOf(prevParent.id)\n\t\t\t\t\tif (oldParentIndex > -1) {\n\t\t\t\t\t\t// If the old parent is a direct child of the new parent, then we'll add them above the old parent but below the next sibling.\n\t\t\t\t\t\tconst siblingsIndexAbove = oldParentSiblingIds[oldParentIndex + 1]\n\t\t\t\t\t\tconst indexKeyAbove = siblingsIndexAbove\n\t\t\t\t\t\t\t? editor.getShape(siblingsIndexAbove)!.index\n\t\t\t\t\t\t\t: getIndexAbove(prevParent.index)\n\t\t\t\t\t\tinsertIndexKey = getIndexBetween(prevParent.index, indexKeyAbove)\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If the old parent is not a direct child of the new parent, then we'll add them to the \"top\" of the new parent's children.\n\t\t\t\t\t\t// This is done automatically if we leave the index undefined, so let's do that.\n\t\t\t\t\t}\n\n\t\t\t\t\tparentsToNewChildren[newParentId] = {\n\t\t\t\t\t\tparentId: newParentId,\n\t\t\t\t\t\tshapeIds: [],\n\t\t\t\t\t\tindex: insertIndexKey,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tparentsToNewChildren[newParentId].shapeIds.push(shape.id)\n\t\t\t})\n\t\t}\n\t}\n\n\teditor.run(() => {\n\t\tObject.values(parentsToNewChildren).forEach(({ parentId, shapeIds, index }) => {\n\t\t\tif (shapeIds.length === 0) return\n\t\t\t// Before we reparent, sort the new shape ids by their place in the original absolute order on the page\n\t\t\tshapeIds.sort((a, b) => (sortedShapeIds.indexOf(a) < sortedShapeIds.indexOf(b) ? -1 : 1))\n\t\t\teditor.reparentShapes(shapeIds, parentId, index)\n\t\t})\n\t})\n}\n\n/**\n * Get the shapes that overlap with a given shape.\n *\n * @param editor - The editor instance.\n * @param shape - The shapes or shape IDs to check against.\n * @param otherShapes - The shapes or shape IDs to check for overlap.\n * @returns An array of shapes or shape IDs that overlap with the given shape.\n */\nfunction getOverlappingShapes<T extends TLShape[] | TLShapeId[]>(\n\teditor: Editor,\n\tshape: T[number],\n\totherShapes: T\n) {\n\tif (otherShapes.length === 0) {\n\t\treturn EMPTY_ARRAY\n\t}\n\n\tconst parentPageBounds = editor.getShapePageBounds(shape)\n\tif (!parentPageBounds) return EMPTY_ARRAY\n\n\tconst parentGeometry = editor.getShapeGeometry(shape)\n\tconst parentPageTransform = editor.getShapePageTransform(shape)\n\tconst parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)\n\n\tconst _shape = editor.getShape(shape)\n\tif (!_shape) return EMPTY_ARRAY\n\n\tconst pageTransform = editor.getShapePageTransform(shape)\n\tconst clipPath = editor.getShapeUtil(_shape.type).getClipPath?.(_shape)\n\n\tconst parentPageMaskVertices = clipPath ? pageTransform.applyToPoints(clipPath) : undefined\n\tconst parentPagePolygon = parentPageMaskVertices\n\t\t? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)\n\t\t: parentPageCorners\n\n\tif (!parentPagePolygon) return EMPTY_ARRAY\n\n\treturn otherShapes.filter((childId) => {\n\t\tconst shapePageBounds = editor.getShapePageBounds(childId)\n\t\tif (!shapePageBounds || !parentPageBounds.includes(shapePageBounds)) return false\n\n\t\tconst parentPolygonInShapeShape = editor\n\t\t\t.getShapePageTransform(childId)\n\t\t\t.clone()\n\t\t\t.invert()\n\t\t\t.applyToPoints(parentPagePolygon)\n\n\t\tconst geometry = editor.getShapeGeometry(childId)\n\n\t\treturn geometry.overlapsPolygon(parentPolygonInShapeShape)\n\t})\n}\n\n/**\n * Get the shapes that will be reparented to new parents when the shapes are dropped.\n *\n * @param editor - The editor instance.\n * @param shapes - The shapes to check.\n * @param cb - A callback to filter out certain shapes.\n * @returns An object with the shapes that will be reparented to new parents and the shapes that will be reparented to the page or their ancestral group.\n *\n * @public\n */\nexport function getDroppedShapesToNewParents(\n\teditor: Editor,\n\tshapes: Set<TLShape> | TLShape[],\n\tcb?: (shape: TLShape, parent: TLShape) => boolean\n) {\n\tconst shapesToActuallyCheck = new Set<TLShape>(shapes)\n\tconst movingGroups = new Set<TLGroupShape>()\n\n\tfor (const shape of shapes) {\n\t\tconst parent = editor.getShapeParent(shape)\n\t\tif (parent && editor.isShapeOfType<TLGroupShape>(parent, 'group')) {\n\t\t\tif (!movingGroups.has(parent)) {\n\t\t\t\tmovingGroups.add(parent)\n\t\t\t}\n\t\t}\n\t}\n\n\t// If all of a group's children are moving, then move the group instead\n\tfor (const movingGroup of movingGroups) {\n\t\tconst children = compact(\n\t\t\teditor.getSortedChildIdsForParent(movingGroup).map((id) => editor.getShape(id))\n\t\t)\n\t\tfor (const child of children) {\n\t\t\tshapesToActuallyCheck.delete(child)\n\t\t}\n\t\tshapesToActuallyCheck.add(movingGroup)\n\t}\n\n\t// this could be cached and passed in\n\tconst shapeGroupIds = new Map<TLShapeId, TLShapeId | undefined>()\n\n\tconst reparenting = new Map<TLShapeId, TLShape[]>()\n\n\tconst remainingShapesToReparent = new Set(shapesToActuallyCheck)\n\n\tconst potentialParentShapes = editor\n\t\t.getCurrentPageShapesSorted()\n\t\t// filter out any shapes that aren't frames or that are included among the provided shapes\n\t\t.filter(\n\t\t\t(s) =>\n\t\t\t\teditor.getShapeUtil(s).canReceiveNewChildrenOfType?.(s, s.type) &&\n\t\t\t\t!remainingShapesToReparent.has(s)\n\t\t)\n\n\tparentCheck: for (let i = potentialParentShapes.length - 1; i >= 0; i--) {\n\t\tconst parentShape = potentialParentShapes[i]\n\t\tconst parentShapeContainingGroupId = editor.findShapeAncestor(parentShape, (s) =>\n\t\t\teditor.isShapeOfType<TLGroupShape>(s, 'group')\n\t\t)?.id\n\n\t\tconst parentGeometry = editor.getShapeGeometry(parentShape)\n\t\tconst parentPageTransform = editor.getShapePageTransform(parentShape)\n\t\tconst parentPageMaskVertices = editor.getShapeMask(parentShape)\n\t\tconst parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)\n\t\tconst parentPagePolygon = parentPageMaskVertices\n\t\t\t? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)\n\t\t\t: parentPageCorners\n\n\t\tif (!parentPagePolygon) continue parentCheck\n\n\t\tconst childrenToReparent = []\n\n\t\t// For each of the dropping shapes...\n\t\tshapeCheck: for (const shape of remainingShapesToReparent) {\n\t\t\t// Don't reparent a frame to itself\n\t\t\tif (parentShape.id === shape.id) continue shapeCheck\n\n\t\t\t// Use the callback to filter out certain shapes\n\t\t\tif (cb && !cb(shape, parentShape)) continue shapeCheck\n\n\t\t\tif (!shapeGroupIds.has(shape.id)) {\n\t\t\t\tshapeGroupIds.set(\n\t\t\t\t\tshape.id,\n\t\t\t\t\teditor.findShapeAncestor(shape, (s) => editor.isShapeOfType<TLGroupShape>(s, 'group'))?.id\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst shapeGroupId = shapeGroupIds.get(shape.id)\n\n\t\t\t// Are the shape and the parent part of different groups?\n\t\t\tif (shapeGroupId !== parentShapeContainingGroupId) continue shapeCheck\n\n\t\t\t// Is the shape is actually the ancestor of the parent?\n\t\t\tif (editor.findShapeAncestor(parentShape, (s) => shape.id === s.id)) continue shapeCheck\n\n\t\t\t// Convert the parent polygon to the shape's space\n\t\t\tconst parentPolygonInShapeSpace = editor\n\t\t\t\t.getShapePageTransform(shape)\n\t\t\t\t.clone()\n\t\t\t\t.invert()\n\t\t\t\t.applyToPoints(parentPagePolygon)\n\n\t\t\t// If the shape overlaps the parent polygon, reparent it to that parent\n\t\t\tif (editor.getShapeGeometry(shape).overlapsPolygon(parentPolygonInShapeSpace)) {\n\t\t\t\t// Use the util to check if the shape can be reparented to the parent\n\t\t\t\tif (\n\t\t\t\t\t!editor.getShapeUtil(parentShape).canReceiveNewChildrenOfType?.(parentShape, shape.type)\n\t\t\t\t)\n\t\t\t\t\tcontinue shapeCheck\n\n\t\t\t\tif (shape.parentId !== parentShape.id) {\n\t\t\t\t\tchildrenToReparent.push(shape)\n\t\t\t\t}\n\t\t\t\tremainingShapesToReparent.delete(shape)\n\t\t\t\tcontinue shapeCheck\n\t\t\t}\n\t\t}\n\n\t\tif (childrenToReparent.length) {\n\t\t\treparenting.set(parentShape.id, childrenToReparent)\n\t\t}\n\t}\n\n\treturn {\n\t\t// these are the shapes that will be reparented to new parents\n\t\treparenting,\n\t\t// these are the shapes that will be reparented to the page or their ancestral group\n\t\tremainingShapesToReparent,\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { EMPTY_ARRAY } from '@tldraw/state'\nimport { TLGroupShape, TLParentId, TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { IndexKey, compact, getIndexAbove, getIndexBetween } from '@tldraw/utils'\nimport { Editor } from '../editor/Editor'\nimport { intersectPolygonPolygon } from '../primitives/intersect'\n\n/**\n * Reparents shapes that are no longer contained within their parent shapes.\n * todo: rename me to something more descriptive, like `reparentOccludedShapes` or `reparentAutoDroppedShapes`\n *\n * @param editor - The editor instance.\n * @param shapeIds - The IDs of the shapes to reparent.\n * @param opts - Optional options, including a callback to filter out certain parents, such as when removing a frame.\n *\n * @public\n */\nexport function kickoutOccludedShapes(\n\teditor: Editor,\n\tshapeIds: TLShapeId[],\n\topts?: { filter?(parent: TLShape): boolean }\n) {\n\tconst parentsToCheck = new Set<TLShape>()\n\n\tfor (const id of shapeIds) {\n\t\tconst shape = editor.getShape(id)\n\n\t\tif (!shape) continue\n\t\tparentsToCheck.add(shape)\n\n\t\tconst parent = editor.getShape(shape.parentId)\n\t\tif (!parent) continue\n\t\tparentsToCheck.add(parent)\n\t}\n\n\t// Check all of the parents and gather up parents who have lost children\n\tconst parentsToLostChildren = new Map<TLShape, TLShapeId[]>()\n\n\tfor (const parent of parentsToCheck) {\n\t\tconst childIds = editor.getSortedChildIdsForParent(parent)\n\t\tif (opts?.filter && !opts.filter(parent)) {\n\t\t\t// If the shape is filtered out, we kick out all of its children\n\t\t\tparentsToLostChildren.set(parent, childIds)\n\t\t} else {\n\t\t\tconst overlappingChildren = getOverlappingShapes(editor, parent.id, childIds)\n\t\t\tif (overlappingChildren.length < childIds.length) {\n\t\t\t\tparentsToLostChildren.set(\n\t\t\t\t\tparent,\n\t\t\t\t\tchildIds.filter((id) => !overlappingChildren.includes(id))\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t}\n\n\t// Get all of the shapes on the current page, sorted by their index\n\tconst sortedShapeIds = editor.getCurrentPageShapesSorted().map((s) => s.id)\n\n\tconst parentsToNewChildren: Record<\n\t\tTLParentId,\n\t\t{ parentId: TLParentId; shapeIds: TLShapeId[]; index?: IndexKey }\n\t> = {}\n\n\tfor (const [prevParent, lostChildrenIds] of parentsToLostChildren) {\n\t\tconst lostChildren = compact(lostChildrenIds.map((id) => editor.getShape(id)))\n\n\t\t// Don't fall \"up\" into frames in front of the shape\n\t\t// if (pageShapes.indexOf(shape) < frameSortPosition) continue shapeCheck\n\n\t\t// Otherwise, we have no next dropping shape under the cursor, so go find\n\t\t// all the frames on the page where the moving shapes will fall into\n\t\tconst { reparenting, remainingShapesToReparent } = getDroppedShapesToNewParents(\n\t\t\teditor,\n\t\t\tlostChildren,\n\t\t\t(shape, maybeNewParent) => {\n\t\t\t\t// If we're filtering out a potential parent, don't reparent shapes to the filtered out shape\n\t\t\t\tif (opts?.filter && !opts.filter(maybeNewParent)) return false\n\t\t\t\treturn (\n\t\t\t\t\tmaybeNewParent.id !== prevParent.id &&\n\t\t\t\t\tsortedShapeIds.indexOf(maybeNewParent.id) < sortedShapeIds.indexOf(shape.id)\n\t\t\t\t)\n\t\t\t}\n\t\t)\n\n\t\treparenting.forEach((childrenToReparent, newParentId) => {\n\t\t\tif (childrenToReparent.length === 0) return\n\t\t\tif (!parentsToNewChildren[newParentId]) {\n\t\t\t\tparentsToNewChildren[newParentId] = {\n\t\t\t\t\tparentId: newParentId,\n\t\t\t\t\tshapeIds: [],\n\t\t\t\t}\n\t\t\t}\n\t\t\tparentsToNewChildren[newParentId].shapeIds.push(...childrenToReparent.map((s) => s.id))\n\t\t})\n\n\t\t// Reparent the rest to the page (or containing group)\n\t\tif (remainingShapesToReparent.size > 0) {\n\t\t\t// The remaining shapes are going to be reparented to the old parent's containing group, if there was one, or else to the page\n\t\t\tconst newParentId =\n\t\t\t\teditor.findShapeAncestor(prevParent, (s) => editor.isShapeOfType(s, 'group'))?.id ??\n\t\t\t\teditor.getCurrentPageId()\n\n\t\t\tremainingShapesToReparent.forEach((shape) => {\n\t\t\t\tif (!parentsToNewChildren[newParentId]) {\n\t\t\t\t\tlet insertIndexKey: IndexKey | undefined\n\n\t\t\t\t\tconst oldParentSiblingIds = editor.getSortedChildIdsForParent(newParentId)\n\t\t\t\t\tconst oldParentIndex = oldParentSiblingIds.indexOf(prevParent.id)\n\t\t\t\t\tif (oldParentIndex > -1) {\n\t\t\t\t\t\t// If the old parent is a direct child of the new parent, then we'll add them above the old parent but below the next sibling.\n\t\t\t\t\t\tconst siblingsIndexAbove = oldParentSiblingIds[oldParentIndex + 1]\n\t\t\t\t\t\tconst indexKeyAbove = siblingsIndexAbove\n\t\t\t\t\t\t\t? editor.getShape(siblingsIndexAbove)!.index\n\t\t\t\t\t\t\t: getIndexAbove(prevParent.index)\n\t\t\t\t\t\tinsertIndexKey = getIndexBetween(prevParent.index, indexKeyAbove)\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If the old parent is not a direct child of the new parent, then we'll add them to the \"top\" of the new parent's children.\n\t\t\t\t\t\t// This is done automatically if we leave the index undefined, so let's do that.\n\t\t\t\t\t}\n\n\t\t\t\t\tparentsToNewChildren[newParentId] = {\n\t\t\t\t\t\tparentId: newParentId,\n\t\t\t\t\t\tshapeIds: [],\n\t\t\t\t\t\tindex: insertIndexKey,\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tparentsToNewChildren[newParentId].shapeIds.push(shape.id)\n\t\t\t})\n\t\t}\n\t}\n\n\teditor.run(() => {\n\t\tObject.values(parentsToNewChildren).forEach(({ parentId, shapeIds, index }) => {\n\t\t\tif (shapeIds.length === 0) return\n\t\t\t// Before we reparent, sort the new shape ids by their place in the original absolute order on the page\n\t\t\tshapeIds.sort((a, b) => (sortedShapeIds.indexOf(a) < sortedShapeIds.indexOf(b) ? -1 : 1))\n\t\t\teditor.reparentShapes(shapeIds, parentId, index)\n\t\t})\n\t})\n}\n\n/**\n * Get the shapes that overlap with a given shape.\n *\n * @param editor - The editor instance.\n * @param shape - The shapes or shape IDs to check against.\n * @param otherShapes - The shapes or shape IDs to check for overlap.\n * @returns An array of shapes or shape IDs that overlap with the given shape.\n */\nfunction getOverlappingShapes<T extends TLShape[] | TLShapeId[]>(\n\teditor: Editor,\n\tshape: T[number],\n\totherShapes: T\n) {\n\tif (otherShapes.length === 0) {\n\t\treturn EMPTY_ARRAY\n\t}\n\n\tconst parentPageBounds = editor.getShapePageBounds(shape)\n\tif (!parentPageBounds) return EMPTY_ARRAY\n\n\tconst parentGeometry = editor.getShapeGeometry(shape)\n\tconst parentPageTransform = editor.getShapePageTransform(shape)\n\tconst parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)\n\n\tconst _shape = editor.getShape(shape)\n\tif (!_shape) return EMPTY_ARRAY\n\n\tconst pageTransform = editor.getShapePageTransform(shape)\n\tconst clipPath = editor.getShapeUtil(_shape.type).getClipPath?.(_shape)\n\n\tconst parentPageMaskVertices = clipPath ? pageTransform.applyToPoints(clipPath) : undefined\n\tconst parentPagePolygon = parentPageMaskVertices\n\t\t? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)\n\t\t: parentPageCorners\n\n\tif (!parentPagePolygon) return EMPTY_ARRAY\n\n\treturn otherShapes.filter((childId) => {\n\t\tconst shapePageBounds = editor.getShapePageBounds(childId)\n\t\tif (!shapePageBounds || !parentPageBounds.includes(shapePageBounds)) return false\n\n\t\tconst parentPolygonInShapeShape = editor\n\t\t\t.getShapePageTransform(childId)\n\t\t\t.clone()\n\t\t\t.invert()\n\t\t\t.applyToPoints(parentPagePolygon)\n\n\t\tconst geometry = editor.getShapeGeometry(childId)\n\n\t\treturn geometry.overlapsPolygon(parentPolygonInShapeShape)\n\t})\n}\n\n/**\n * Get the shapes that will be reparented to new parents when the shapes are dropped.\n *\n * @param editor - The editor instance.\n * @param shapes - The shapes to check.\n * @param cb - A callback to filter out certain shapes.\n * @returns An object with the shapes that will be reparented to new parents and the shapes that will be reparented to the page or their ancestral group.\n *\n * @public\n */\nexport function getDroppedShapesToNewParents(\n\teditor: Editor,\n\tshapes: Set<TLShape> | TLShape[],\n\tcb?: (shape: TLShape, parent: TLShape) => boolean\n) {\n\tconst shapesToActuallyCheck = new Set<TLShape>(shapes)\n\tconst movingGroups = new Set<TLGroupShape>()\n\n\tfor (const shape of shapes) {\n\t\tconst parent = editor.getShapeParent(shape)\n\t\tif (parent && editor.isShapeOfType(parent, 'group')) {\n\t\t\tif (!movingGroups.has(parent)) {\n\t\t\t\tmovingGroups.add(parent)\n\t\t\t}\n\t\t}\n\t}\n\n\t// If all of a group's children are moving, then move the group instead\n\tfor (const movingGroup of movingGroups) {\n\t\tconst children = compact(\n\t\t\teditor.getSortedChildIdsForParent(movingGroup).map((id) => editor.getShape(id))\n\t\t)\n\t\tfor (const child of children) {\n\t\t\tshapesToActuallyCheck.delete(child)\n\t\t}\n\t\tshapesToActuallyCheck.add(movingGroup)\n\t}\n\n\t// this could be cached and passed in\n\tconst shapeGroupIds = new Map<TLShapeId, TLShapeId | undefined>()\n\n\tconst reparenting = new Map<TLShapeId, TLShape[]>()\n\n\tconst remainingShapesToReparent = new Set(shapesToActuallyCheck)\n\n\tconst potentialParentShapes = editor\n\t\t.getCurrentPageShapesSorted()\n\t\t// filter out any shapes that aren't frames or that are included among the provided shapes\n\t\t.filter(\n\t\t\t(s) =>\n\t\t\t\teditor.getShapeUtil(s).canReceiveNewChildrenOfType?.(s, s.type) &&\n\t\t\t\t!remainingShapesToReparent.has(s)\n\t\t)\n\n\tparentCheck: for (let i = potentialParentShapes.length - 1; i >= 0; i--) {\n\t\tconst parentShape = potentialParentShapes[i]\n\t\tconst parentShapeContainingGroupId = editor.findShapeAncestor(parentShape, (s) =>\n\t\t\teditor.isShapeOfType(s, 'group')\n\t\t)?.id\n\n\t\tconst parentGeometry = editor.getShapeGeometry(parentShape)\n\t\tconst parentPageTransform = editor.getShapePageTransform(parentShape)\n\t\tconst parentPageMaskVertices = editor.getShapeMask(parentShape)\n\t\tconst parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices)\n\t\tconst parentPagePolygon = parentPageMaskVertices\n\t\t\t? intersectPolygonPolygon(parentPageMaskVertices, parentPageCorners)\n\t\t\t: parentPageCorners\n\n\t\tif (!parentPagePolygon) continue parentCheck\n\n\t\tconst childrenToReparent = []\n\n\t\t// For each of the dropping shapes...\n\t\tshapeCheck: for (const shape of remainingShapesToReparent) {\n\t\t\t// Don't reparent a frame to itself\n\t\t\tif (parentShape.id === shape.id) continue shapeCheck\n\n\t\t\t// Use the callback to filter out certain shapes\n\t\t\tif (cb && !cb(shape, parentShape)) continue shapeCheck\n\n\t\t\tif (!shapeGroupIds.has(shape.id)) {\n\t\t\t\tshapeGroupIds.set(\n\t\t\t\t\tshape.id,\n\t\t\t\t\teditor.findShapeAncestor(shape, (s) => editor.isShapeOfType(s, 'group'))?.id\n\t\t\t\t)\n\t\t\t}\n\n\t\t\tconst shapeGroupId = shapeGroupIds.get(shape.id)\n\n\t\t\t// Are the shape and the parent part of different groups?\n\t\t\tif (shapeGroupId !== parentShapeContainingGroupId) continue shapeCheck\n\n\t\t\t// Is the shape is actually the ancestor of the parent?\n\t\t\tif (editor.findShapeAncestor(parentShape, (s) => shape.id === s.id)) continue shapeCheck\n\n\t\t\t// Convert the parent polygon to the shape's space\n\t\t\tconst parentPolygonInShapeSpace = editor\n\t\t\t\t.getShapePageTransform(shape)\n\t\t\t\t.clone()\n\t\t\t\t.invert()\n\t\t\t\t.applyToPoints(parentPagePolygon)\n\n\t\t\t// If the shape overlaps the parent polygon, reparent it to that parent\n\t\t\tif (editor.getShapeGeometry(shape).overlapsPolygon(parentPolygonInShapeSpace)) {\n\t\t\t\t// Use the util to check if the shape can be reparented to the parent\n\t\t\t\tif (\n\t\t\t\t\t!editor.getShapeUtil(parentShape).canReceiveNewChildrenOfType?.(parentShape, shape.type)\n\t\t\t\t)\n\t\t\t\t\tcontinue shapeCheck\n\n\t\t\t\tif (shape.parentId !== parentShape.id) {\n\t\t\t\t\tchildrenToReparent.push(shape)\n\t\t\t\t}\n\t\t\t\tremainingShapesToReparent.delete(shape)\n\t\t\t\tcontinue shapeCheck\n\t\t\t}\n\t\t}\n\n\t\tif (childrenToReparent.length) {\n\t\t\treparenting.set(parentShape.id, childrenToReparent)\n\t\t}\n\t}\n\n\treturn {\n\t\t// these are the shapes that will be reparented to new parents\n\t\treparenting,\n\t\t// these are the shapes that will be reparented to the page or their ancestral group\n\t\tremainingShapesToReparent,\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["shapeIds"]
7
7
  }
@@ -1,8 +1,8 @@
1
- const version = "4.3.0-canary.da35795ba8e2";
1
+ const version = "4.3.0-canary.eb3bbfa1daab";
2
2
  const publishDates = {
3
3
  major: "2025-09-18T14:39:22.803Z",
4
- minor: "2025-11-19T15:43:54.030Z",
5
- patch: "2025-11-19T15:43:54.030Z"
4
+ minor: "2025-11-30T22:51:06.079Z",
5
+ patch: "2025-11-30T22:51:06.079Z"
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 = '4.3.0-canary.da35795ba8e2'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-11-19T15:43:54.030Z',\n\tpatch: '2025-11-19T15:43:54.030Z',\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 = '4.3.0-canary.eb3bbfa1daab'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2025-11-30T22:51:06.079Z',\n\tpatch: '2025-11-30T22:51:06.079Z',\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": "4.3.0-canary.da35795ba8e2",
4
+ "version": "4.3.0-canary.eb3bbfa1daab",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -47,15 +47,15 @@
47
47
  "context": "yarn run -T tsx ../../internal/scripts/context.ts"
48
48
  },
49
49
  "dependencies": {
50
- "@tiptap/core": "3.6.2",
51
- "@tiptap/pm": "3.6.2",
52
- "@tiptap/react": "3.6.2",
53
- "@tldraw/state": "4.3.0-canary.da35795ba8e2",
54
- "@tldraw/state-react": "4.3.0-canary.da35795ba8e2",
55
- "@tldraw/store": "4.3.0-canary.da35795ba8e2",
56
- "@tldraw/tlschema": "4.3.0-canary.da35795ba8e2",
57
- "@tldraw/utils": "4.3.0-canary.da35795ba8e2",
58
- "@tldraw/validate": "4.3.0-canary.da35795ba8e2",
50
+ "@tiptap/core": "^3.6.2",
51
+ "@tiptap/pm": "^3.6.2",
52
+ "@tiptap/react": "^3.6.2",
53
+ "@tldraw/state": "4.3.0-canary.eb3bbfa1daab",
54
+ "@tldraw/state-react": "4.3.0-canary.eb3bbfa1daab",
55
+ "@tldraw/store": "4.3.0-canary.eb3bbfa1daab",
56
+ "@tldraw/tlschema": "4.3.0-canary.eb3bbfa1daab",
57
+ "@tldraw/utils": "4.3.0-canary.eb3bbfa1daab",
58
+ "@tldraw/validate": "4.3.0-canary.eb3bbfa1daab",
59
59
  "@types/core-js": "^2.5.8",
60
60
  "@use-gesture/react": "^10.3.1",
61
61
  "classnames": "^2.5.1",
@@ -86,6 +86,7 @@ export function DefaultCanvas({ className }: TLCanvasComponentProps) {
86
86
  const transform = `scale(${toDomPrecision(z)}) translate(${toDomPrecision(
87
87
  x + offset
88
88
  )}px,${toDomPrecision(y + offset)}px)`
89
+
89
90
  setStyleProperty(rHtmlLayer.current, 'transform', transform)
90
91
  setStyleProperty(rHtmlLayer2.current, 'transform', transform)
91
92
  },
@@ -6,25 +6,25 @@ import {
6
6
  Rectangle2d,
7
7
  ShapeUtil,
8
8
  T,
9
- TLBaseShape,
9
+ TLShape,
10
10
  createShapeId,
11
11
  createTLStore,
12
12
  } from '../..'
13
13
  import { Editor } from './Editor'
14
14
  import { StateNode } from './tools/StateNode'
15
15
 
16
- type ICustomShape = TLBaseShape<
17
- 'my-custom-shape',
18
- {
19
- w: number
20
- h: number
21
- text: string | undefined
22
- isFilled: boolean
16
+ const MY_CUSTOM_SHAPE_TYPE = 'my-custom-shape'
17
+
18
+ declare module '@tldraw/tlschema' {
19
+ export interface TLGlobalShapePropsMap {
20
+ [MY_CUSTOM_SHAPE_TYPE]: { w: number; h: number; text: string | undefined; isFilled: boolean }
23
21
  }
24
- >
22
+ }
23
+
24
+ type ICustomShape = TLShape<typeof MY_CUSTOM_SHAPE_TYPE>
25
25
 
26
26
  class CustomShape extends ShapeUtil<ICustomShape> {
27
- static override type = 'my-custom-shape' as const
27
+ static override type = MY_CUSTOM_SHAPE_TYPE
28
28
  static override props: RecordProps<ICustomShape> = {
29
29
  w: T.number,
30
30
  h: T.number,
@@ -21,7 +21,6 @@ import {
21
21
  PageRecordType,
22
22
  StyleProp,
23
23
  StylePropValue,
24
- TLArrowShape,
25
24
  TLAsset,
26
25
  TLAssetId,
27
26
  TLAssetPartial,
@@ -30,12 +29,12 @@ import {
30
29
  TLBindingId,
31
30
  TLBindingUpdate,
32
31
  TLCamera,
32
+ TLCreateShapePartial,
33
33
  TLCursor,
34
34
  TLCursorType,
35
35
  TLDOCUMENT_ID,
36
36
  TLDocument,
37
37
  TLFrameShape,
38
- TLGeoShape,
39
38
  TLGroupShape,
40
39
  TLHandle,
41
40
  TLINSTANCE_ID,
@@ -43,7 +42,6 @@ import {
43
42
  TLInstance,
44
43
  TLInstancePageState,
45
44
  TLInstancePresence,
46
- TLNoteShape,
47
45
  TLPOINTER_ID,
48
46
  TLPage,
49
47
  TLPageId,
@@ -54,8 +52,6 @@ import {
54
52
  TLShapePartial,
55
53
  TLStore,
56
54
  TLStoreSnapshot,
57
- TLUnknownBinding,
58
- TLUnknownShape,
59
55
  TLVideoAsset,
60
56
  createBindingId,
61
57
  createShapeId,
@@ -447,7 +443,7 @@ export class Editor extends EventEmitter<TLEventMap> {
447
443
  let deletedBindings = new Map<TLBindingId, BindingOnDeleteOptions<any>>()
448
444
  const deletedShapeIds = new Set<TLShapeId>()
449
445
  const invalidParents = new Set<TLShapeId>()
450
- let invalidBindingTypes = new Set<string>()
446
+ let invalidBindingTypes = new Set<TLBinding['type']>()
451
447
  this.disposables.add(
452
448
  this.sideEffects.registerOperationCompleteHandler(() => {
453
449
  // this needs to be cleared here because further effects may delete more shapes
@@ -710,7 +706,7 @@ export class Editor extends EventEmitter<TLEventMap> {
710
706
  if (filtered.length > 0) {
711
707
  const commonGroupAncestor = this.findCommonAncestor(
712
708
  compact(filtered.map((id) => this.getShape(id))),
713
- (shape) => this.isShapeOfType<TLGroupShape>(shape, 'group')
709
+ (shape) => this.isShapeOfType(shape, 'group')
714
710
  )
715
711
 
716
712
  if (commonGroupAncestor) {
@@ -982,7 +978,7 @@ export class Editor extends EventEmitter<TLEventMap> {
982
978
  *
983
979
  * @public
984
980
  */
985
- shapeUtils: { readonly [K in string]?: ShapeUtil<TLUnknownShape> }
981
+ shapeUtils: { readonly [K in string]?: ShapeUtil<TLShape> }
986
982
 
987
983
  styleProps: { [key: string]: Map<StyleProp<any>, string> }
988
984
 
@@ -1001,8 +997,8 @@ export class Editor extends EventEmitter<TLEventMap> {
1001
997
  *
1002
998
  * @public
1003
999
  */
1004
- getShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): ShapeUtil<S>
1005
- getShapeUtil<S extends TLUnknownShape>(type: S['type']): ShapeUtil<S>
1000
+ getShapeUtil<K extends TLShape['type']>(type: K): ShapeUtil<Extract<TLShape, { type: K }>>
1001
+ getShapeUtil<S extends TLShape>(shape: S | TLShapePartial<S> | S['type']): ShapeUtil<S>
1006
1002
  getShapeUtil<T extends ShapeUtil>(type: T extends ShapeUtil<infer R> ? R['type'] : string): T
1007
1003
  getShapeUtil(arg: string | { type: string }) {
1008
1004
  const type = typeof arg === 'string' ? arg : arg.type
@@ -1016,8 +1012,8 @@ export class Editor extends EventEmitter<TLEventMap> {
1016
1012
  *
1017
1013
  * @param shape - A shape, shape partial, or shape type.
1018
1014
  */
1019
- hasShapeUtil<S extends TLUnknownShape>(shape: S | TLShapePartial<S>): boolean
1020
- hasShapeUtil<S extends TLUnknownShape>(type: S['type']): boolean
1015
+ hasShapeUtil(shape: TLShape | TLShapePartial<TLShape>): boolean
1016
+ hasShapeUtil(type: TLShape['type']): boolean
1021
1017
  hasShapeUtil<T extends ShapeUtil>(
1022
1018
  type: T extends ShapeUtil<infer R> ? R['type'] : string
1023
1019
  ): boolean
@@ -1032,7 +1028,7 @@ export class Editor extends EventEmitter<TLEventMap> {
1032
1028
  *
1033
1029
  * @public
1034
1030
  */
1035
- bindingUtils: { readonly [K in string]?: BindingUtil<TLUnknownBinding> }
1031
+ bindingUtils: { readonly [K in string]?: BindingUtil<TLBinding> }
1036
1032
 
1037
1033
  /**
1038
1034
  * Get a binding util from a binding itself.
@@ -1049,8 +1045,8 @@ export class Editor extends EventEmitter<TLEventMap> {
1049
1045
  *
1050
1046
  * @public
1051
1047
  */
1052
- getBindingUtil<S extends TLUnknownBinding>(binding: S | { type: S['type'] }): BindingUtil<S>
1053
- getBindingUtil<S extends TLUnknownBinding>(type: S['type']): BindingUtil<S>
1048
+ getBindingUtil<K extends TLBinding['type']>(type: K): BindingUtil<Extract<TLBinding, { type: K }>>
1049
+ getBindingUtil<S extends TLBinding>(binding: S | { type: S['type'] }): BindingUtil<S>
1054
1050
  getBindingUtil<T extends BindingUtil>(
1055
1051
  type: T extends BindingUtil<infer R> ? R['type'] : string
1056
1052
  ): T
@@ -2220,7 +2216,7 @@ export class Editor extends EventEmitter<TLEventMap> {
2220
2216
  throw Error(`Editor.setFocusedGroup: Shape with id ${id} does not exist`)
2221
2217
  }
2222
2218
 
2223
- if (!this.isShapeOfType<TLGroupShape>(shape, 'group')) {
2219
+ if (!this.isShapeOfType(shape, 'group')) {
2224
2220
  throw Error(
2225
2221
  `Editor.setFocusedGroup: Cannot set focused group to shape of type ${shape.type}`
2226
2222
  )
@@ -2248,7 +2244,7 @@ export class Editor extends EventEmitter<TLEventMap> {
2248
2244
  if (focusedGroup) {
2249
2245
  // If we have a focused layer, look for an ancestor of the focused shape that is a group
2250
2246
  const match = this.findShapeAncestor(focusedGroup, (shape) =>
2251
- this.isShapeOfType<TLGroupShape>(shape, 'group')
2247
+ this.isShapeOfType(shape, 'group')
2252
2248
  )
2253
2249
  // If we have an ancestor that can become a focused layer, set it as the focused layer
2254
2250
  this.setFocusedGroup(match?.id ?? null)
@@ -3635,16 +3631,19 @@ export class Editor extends EventEmitter<TLEventMap> {
3635
3631
  if (_willSetInitialBounds) {
3636
3632
  // If we have just received the initial bounds, don't center the camera.
3637
3633
  this.updateInstanceState({ screenBounds: screenBounds.toJson(), insets })
3634
+ this.emit('resize', screenBounds.toJson())
3638
3635
  this.setCamera(this.getCamera())
3639
3636
  } else {
3640
3637
  if (center && !this.getInstanceState().followingUserId) {
3641
3638
  // Get the page center before the change, make the change, and restore it
3642
3639
  const before = this.getViewportPageBounds().center
3643
3640
  this.updateInstanceState({ screenBounds: screenBounds.toJson(), insets })
3641
+ this.emit('resize', screenBounds.toJson())
3644
3642
  this.centerOnPoint(before)
3645
3643
  } else {
3646
3644
  // Otherwise,
3647
3645
  this.updateInstanceState({ screenBounds: screenBounds.toJson(), insets })
3646
+ this.emit('resize', screenBounds.toJson())
3648
3647
  this._setCamera(Vec.From({ ...this.getCamera() }))
3649
3648
  }
3650
3649
  }
@@ -5127,10 +5126,10 @@ export class Editor extends EventEmitter<TLEventMap> {
5127
5126
 
5128
5127
  // Check labels first
5129
5128
  if (
5130
- this.isShapeOfType<TLFrameShape>(shape, 'frame') ||
5131
- ((this.isShapeOfType<TLNoteShape>(shape, 'note') ||
5132
- this.isShapeOfType<TLArrowShape>(shape, 'arrow') ||
5133
- (this.isShapeOfType<TLGeoShape>(shape, 'geo') && shape.props.fill === 'none')) &&
5129
+ this.isShapeOfType(shape, 'frame') ||
5130
+ ((this.isShapeOfType(shape, 'note') ||
5131
+ this.isShapeOfType(shape, 'arrow') ||
5132
+ (this.isShapeOfType(shape, 'geo') && shape.props.fill === 'none')) &&
5134
5133
  this.getShapeUtil(shape).getText(shape)?.trim())
5135
5134
  ) {
5136
5135
  for (const childGeometry of (geometry as Group2d).children) {
@@ -5140,7 +5139,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5140
5139
  }
5141
5140
  }
5142
5141
 
5143
- if (this.isShapeOfType<TLFrameShape>(shape, 'frame')) {
5142
+ if (this.isShapeOfType(shape, 'frame')) {
5144
5143
  // On the rare case that we've hit a frame (not its label), test again hitInside to be forced true;
5145
5144
  // this prevents clicks from passing through the body of a frame to shapes behind it.
5146
5145
 
@@ -5421,7 +5420,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5421
5420
  *
5422
5421
  * @example
5423
5422
  * ```ts
5424
- * const isArrowShape = isShapeOfType<TLArrowShape>(someShape, 'arrow')
5423
+ * const isArrowShape = isShapeOfType(someShape, 'arrow')
5425
5424
  * ```
5426
5425
  *
5427
5426
  * @param util - the TLShapeUtil constructor to test against
@@ -5429,15 +5428,16 @@ export class Editor extends EventEmitter<TLEventMap> {
5429
5428
  *
5430
5429
  * @public
5431
5430
  */
5432
- isShapeOfType<T extends TLUnknownShape>(shape: TLUnknownShape, type: T['type']): shape is T
5433
- isShapeOfType<T extends TLUnknownShape>(
5434
- shapeId: TLUnknownShape['id'],
5435
- type: T['type']
5436
- ): shapeId is T['id']
5437
- isShapeOfType<T extends TLUnknownShape>(
5438
- arg: TLUnknownShape | TLUnknownShape['id'],
5431
+ isShapeOfType<K extends TLShape['type']>(
5432
+ shape: TLShape,
5433
+ type: K
5434
+ ): shape is Extract<TLShape, { type: K }>
5435
+ isShapeOfType<T extends TLShape>(
5436
+ shape: TLShape,
5439
5437
  type: T['type']
5440
- ) {
5438
+ ): shape is Extract<TLShape, { type: T['type'] }>
5439
+ isShapeOfType<T extends TLShape = TLShape>(shapeId: TLShapeId, type: T['type']): boolean
5440
+ isShapeOfType(arg: TLShape | TLShapeId, type: TLShape['type']) {
5441
5441
  const shape = typeof arg === 'string' ? this.getShape(arg) : arg
5442
5442
  if (!shape) return false
5443
5443
  return shape.type === type
@@ -5833,7 +5833,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5833
5833
 
5834
5834
  while (node) {
5835
5835
  if (
5836
- this.isShapeOfType<TLGroupShape>(node, 'group') &&
5836
+ this.isShapeOfType(node, 'group') &&
5837
5837
  focusedGroup?.id !== node.id &&
5838
5838
  !this.hasAncestor(focusedGroup, node.id) &&
5839
5839
  (filter?.(node) ?? true)
@@ -5875,7 +5875,15 @@ export class Editor extends EventEmitter<TLEventMap> {
5875
5875
  * Get all bindings of a certain type _from_ a particular shape. These are the bindings whose
5876
5876
  * `fromId` matched the shape's ID.
5877
5877
  */
5878
- getBindingsFromShape<Binding extends TLUnknownBinding = TLBinding>(
5878
+ getBindingsFromShape<K extends TLBinding['type']>(
5879
+ shape: TLShape | TLShapeId,
5880
+ type: K
5881
+ ): Extract<TLBinding, { type: K }>[]
5882
+ getBindingsFromShape<Binding extends TLBinding = TLBinding>(
5883
+ shape: TLShape | TLShapeId,
5884
+ type: Binding['type']
5885
+ ): Binding[]
5886
+ getBindingsFromShape<Binding extends TLBinding = TLBinding>(
5879
5887
  shape: TLShape | TLShapeId,
5880
5888
  type: Binding['type']
5881
5889
  ): Binding[] {
@@ -5889,7 +5897,15 @@ export class Editor extends EventEmitter<TLEventMap> {
5889
5897
  * Get all bindings of a certain type _to_ a particular shape. These are the bindings whose
5890
5898
  * `toId` matches the shape's ID.
5891
5899
  */
5892
- getBindingsToShape<Binding extends TLUnknownBinding = TLBinding>(
5900
+ getBindingsToShape<K extends TLBinding['type']>(
5901
+ shape: TLShape | TLShapeId,
5902
+ type: K
5903
+ ): Extract<TLBinding, { type: K }>[]
5904
+ getBindingsToShape<Binding extends TLBinding = TLBinding>(
5905
+ shape: TLShape | TLShapeId,
5906
+ type: Binding['type']
5907
+ ): Binding[]
5908
+ getBindingsToShape<Binding extends TLBinding = TLBinding>(
5893
5909
  shape: TLShape | TLShapeId,
5894
5910
  type: Binding['type']
5895
5911
  ): Binding[] {
@@ -5903,7 +5919,15 @@ export class Editor extends EventEmitter<TLEventMap> {
5903
5919
  * Get all bindings involving a particular shape. This includes bindings where the shape is the
5904
5920
  * `fromId` or `toId`. If a type is provided, only bindings of that type are returned.
5905
5921
  */
5906
- getBindingsInvolvingShape<Binding extends TLUnknownBinding = TLBinding>(
5922
+ getBindingsInvolvingShape<K extends TLBinding['type']>(
5923
+ shape: TLShape | TLShapeId,
5924
+ type: K
5925
+ ): Extract<TLBinding, { type: K }>[]
5926
+ getBindingsInvolvingShape<Binding extends TLBinding = TLBinding>(
5927
+ shape: TLShape | TLShapeId,
5928
+ type?: Binding['type']
5929
+ ): Binding[]
5930
+ getBindingsInvolvingShape<Binding extends TLBinding = TLBinding>(
5907
5931
  shape: TLShape | TLShapeId,
5908
5932
  type?: Binding['type']
5909
5933
  ): Binding[] {
@@ -5925,7 +5949,7 @@ export class Editor extends EventEmitter<TLEventMap> {
5925
5949
  if (!fromShape || !toShape) continue
5926
5950
  if (!this.canBindShapes({ fromShape, toShape, binding: partial })) continue
5927
5951
 
5928
- const util = this.getBindingUtil<TLUnknownBinding>(partial.type)
5952
+ const util = this.getBindingUtil(partial.type)
5929
5953
  const defaultProps = util.getDefaultProps()
5930
5954
  const binding = this.store.schema.types.binding.create({
5931
5955
  ...partial,
@@ -6030,7 +6054,7 @@ export class Editor extends EventEmitter<TLEventMap> {
6030
6054
  const toShapeType = typeof toShape === 'string' ? toShape : toShape.type
6031
6055
  const bindingType = typeof binding === 'string' ? binding : binding.type
6032
6056
 
6033
- const canBindOpts = { fromShapeType, toShapeType, bindingType }
6057
+ const canBindOpts = { fromShapeType, toShapeType, bindingType } as const
6034
6058
 
6035
6059
  if (fromShapeType === toShapeType) {
6036
6060
  return this.getShapeUtil(fromShapeType).canBind(canBindOpts)
@@ -6571,7 +6595,7 @@ export class Editor extends EventEmitter<TLEventMap> {
6571
6595
  const shapesToFlipFirstPass = compact(ids.map((id) => this.getShape(id)))
6572
6596
 
6573
6597
  for (const shape of shapesToFlipFirstPass) {
6574
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
6598
+ if (this.isShapeOfType(shape, 'group')) {
6575
6599
  const childrenOfGroups = compact(
6576
6600
  this.getSortedChildIdsForParent(shape.id).map((id) => this.getShape(id))
6577
6601
  )
@@ -7692,9 +7716,7 @@ export class Editor extends EventEmitter<TLEventMap> {
7692
7716
  *
7693
7717
  * @public
7694
7718
  */
7695
- canCreateShape<T extends TLUnknownShape>(
7696
- shape: OptionalKeys<TLShapePartial<T>, 'id'> | T['id']
7697
- ): boolean {
7719
+ canCreateShape(shape: OptionalKeys<TLShapePartial<TLShape>, 'id'> | TLShape['id']): boolean {
7698
7720
  return this.canCreateShapes([shape])
7699
7721
  }
7700
7722
 
@@ -7705,8 +7727,8 @@ export class Editor extends EventEmitter<TLEventMap> {
7705
7727
  *
7706
7728
  * @public
7707
7729
  */
7708
- canCreateShapes<T extends TLUnknownShape>(
7709
- shapes: (T['id'] | OptionalKeys<TLShapePartial<T>, 'id'>)[]
7730
+ canCreateShapes(
7731
+ shapes: (TLShape['id'] | OptionalKeys<TLShapePartial<TLShape>, 'id'>)[]
7710
7732
  ): boolean {
7711
7733
  return shapes.length + this.getCurrentPageShapeIds().size <= this.options.maxShapesPerPage
7712
7734
  }
@@ -7724,7 +7746,7 @@ export class Editor extends EventEmitter<TLEventMap> {
7724
7746
  *
7725
7747
  * @public
7726
7748
  */
7727
- createShape<T extends TLUnknownShape>(shape: OptionalKeys<TLShapePartial<T>, 'id'>): this {
7749
+ createShape<TShape extends TLShape>(shape: TLCreateShapePartial<TShape>): this {
7728
7750
  this.createShapes([shape])
7729
7751
  return this
7730
7752
  }
@@ -7742,7 +7764,7 @@ export class Editor extends EventEmitter<TLEventMap> {
7742
7764
  *
7743
7765
  * @public
7744
7766
  */
7745
- createShapes<T extends TLUnknownShape>(shapes: OptionalKeys<TLShapePartial<T>, 'id'>[]): this {
7767
+ createShapes<TShape extends TLShape = TLShape>(shapes: TLCreateShapePartial<TShape>[]): this {
7746
7768
  if (!Array.isArray(shapes)) {
7747
7769
  throw Error('Editor.createShapes: must provide an array of shapes or shape partials')
7748
7770
  }
@@ -8123,7 +8145,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8123
8145
  const highestIndex = shapesWithRootParent[shapesWithRootParent.length - 1]?.index
8124
8146
 
8125
8147
  this.run(() => {
8126
- this.createShapes<TLGroupShape>([
8148
+ this.createShapes([
8127
8149
  {
8128
8150
  id: groupId,
8129
8151
  type: 'group',
@@ -8193,7 +8215,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8193
8215
  const groups: TLGroupShape[] = []
8194
8216
 
8195
8217
  shapesToUngroup.forEach((shape) => {
8196
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8218
+ if (this.isShapeOfType(shape, 'group')) {
8197
8219
  groups.push(shape)
8198
8220
  } else {
8199
8221
  idsToSelect.add(shape.id)
@@ -8239,7 +8261,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8239
8261
  *
8240
8262
  * @public
8241
8263
  */
8242
- updateShape<T extends TLUnknownShape>(partial: TLShapePartial<T> | null | undefined) {
8264
+ updateShape<T extends TLShape = TLShape>(partial: TLShapePartial<T> | null | undefined) {
8243
8265
  this.updateShapes([partial])
8244
8266
  return this
8245
8267
  }
@@ -8256,7 +8278,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8256
8278
  *
8257
8279
  * @public
8258
8280
  */
8259
- updateShapes<T extends TLUnknownShape>(partials: (TLShapePartial<T> | null | undefined)[]) {
8281
+ updateShapes<T extends TLShape>(partials: (TLShapePartial<T> | null | undefined)[]) {
8260
8282
  const compactedPartials: TLShapePartial<T>[] = Array(partials.length)
8261
8283
 
8262
8284
  for (let i = 0, n = partials.length; i < n; i++) {
@@ -8408,7 +8430,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8408
8430
  * @internal
8409
8431
  */
8410
8432
  private _extractSharedStyles(shape: TLShape, sharedStyleMap: SharedStyleMap) {
8411
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8433
+ if (this.isShapeOfType(shape, 'group')) {
8412
8434
  // For groups, ignore the styles of the group shape and instead include the styles of the
8413
8435
  // group's children. These are the shapes that would have their styles changed if the
8414
8436
  // user called `setStyle` on the current selection.
@@ -8528,7 +8550,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8528
8550
  // For groups, ignore the opacity of the group shape and instead include
8529
8551
  // the opacity of the group's children. These are the shapes that would have
8530
8552
  // their opacity changed if the user called `setOpacity` on the current selection.
8531
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8553
+ if (this.isShapeOfType(shape, 'group')) {
8532
8554
  for (const childId of this.getSortedChildIdsForParent(shape.id)) {
8533
8555
  addShape(childId)
8534
8556
  }
@@ -8589,7 +8611,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8589
8611
  // We can have many deep levels of grouped shape
8590
8612
  // Making a recursive function to look through all the levels
8591
8613
  const addShapeById = (shape: TLShape) => {
8592
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8614
+ if (this.isShapeOfType(shape, 'group')) {
8593
8615
  const childIds = this.getSortedChildIdsForParent(shape)
8594
8616
  for (const childId of childIds) {
8595
8617
  addShapeById(this.getShape(childId)!)
@@ -8673,7 +8695,7 @@ export class Editor extends EventEmitter<TLEventMap> {
8673
8695
  // We can have many deep levels of grouped shape
8674
8696
  // Making a recursive function to look through all the levels
8675
8697
  const addShapeById = (shape: TLShape) => {
8676
- if (this.isShapeOfType<TLGroupShape>(shape, 'group')) {
8698
+ if (this.isShapeOfType(shape, 'group')) {
8677
8699
  const childIds = this.getSortedChildIdsForParent(shape.id)
8678
8700
  for (const childId of childIds) {
8679
8701
  addShapeById(this.getShape(childId)!)
@@ -9098,7 +9120,7 @@ export class Editor extends EventEmitter<TLEventMap> {
9098
9120
  for (const shape of this.getSelectedShapes()) {
9099
9121
  if (lowestDepth === 0) break
9100
9122
 
9101
- const isFrame = this.isShapeOfType<TLFrameShape>(shape, 'frame')
9123
+ const isFrame = this.isShapeOfType(shape, 'frame')
9102
9124
  const ancestors = this.getShapeAncestors(shape)
9103
9125
  if (isFrame) ancestors.push(shape)
9104
9126
 
@@ -9137,8 +9159,8 @@ export class Editor extends EventEmitter<TLEventMap> {
9137
9159
  if (rootShapeIds.length === 1) {
9138
9160
  const rootShape = shapes.find((s) => s.id === rootShapeIds[0])!
9139
9161
  if (
9140
- this.isShapeOfType<TLFrameShape>(parent, 'frame') &&
9141
- this.isShapeOfType<TLFrameShape>(rootShape, 'frame') &&
9162
+ this.isShapeOfType(parent, 'frame') &&
9163
+ this.isShapeOfType(rootShape, 'frame') &&
9142
9164
  rootShape.props.w === parent?.props.w &&
9143
9165
  rootShape.props.h === parent?.props.h
9144
9166
  ) {
@@ -9313,11 +9335,11 @@ export class Editor extends EventEmitter<TLEventMap> {
9313
9335
  const onlyRoot = rootShapes[0] as TLFrameShape
9314
9336
  // If the old bounds are in the viewport...
9315
9337
  // todo: replace frame references with shapes that can accept children
9316
- if (this.isShapeOfType<TLFrameShape>(onlyRoot, 'frame')) {
9338
+ if (this.isShapeOfType(onlyRoot, 'frame')) {
9317
9339
  while (
9318
9340
  this.getShapesAtPoint(point).some(
9319
9341
  (shape) =>
9320
- this.isShapeOfType<TLFrameShape>(shape, 'frame') &&
9342
+ this.isShapeOfType(shape, 'frame') &&
9321
9343
  shape.props.w === onlyRoot.props.w &&
9322
9344
  shape.props.h === onlyRoot.props.h
9323
9345
  )
@@ -10232,6 +10254,7 @@ export class Editor extends EventEmitter<TLEventMap> {
10232
10254
  }
10233
10255
  }
10234
10256
 
10257
+ this.emit('event', info)
10235
10258
  this.root.handleEvent(info)
10236
10259
  return
10237
10260
  }
@@ -10730,7 +10753,10 @@ function alertMaxShapes(editor: Editor, pageId = editor.getCurrentPageId()) {
10730
10753
 
10731
10754
  function applyPartialToRecordWithProps<
10732
10755
  T extends UnknownRecord & { type: string; props: object; meta: object },
10733
- >(prev: T, partial?: Partial<T> & { props?: Partial<T['props']> }): T {
10756
+ >(
10757
+ prev: T,
10758
+ partial?: T extends T ? Omit<Partial<T>, 'props'> & { props?: Partial<T['props']> } : never
10759
+ ): T {
10734
10760
  if (!partial) return prev
10735
10761
  let next = null as null | T
10736
10762
  const entries = Object.entries(partial)