@tldraw/editor 3.14.0-canary.6f68b0394e8a → 3.14.0-canary.6fbbca54ff57

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 (40) hide show
  1. package/dist-cjs/index.d.ts +82 -13
  2. package/dist-cjs/index.js +4 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/editor/Editor.js +35 -21
  5. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  6. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +2 -2
  7. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  8. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +0 -10
  9. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  10. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  11. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +6 -2
  12. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  13. package/dist-cjs/lib/utils/reparenting.js +232 -0
  14. package/dist-cjs/lib/utils/reparenting.js.map +7 -0
  15. package/dist-cjs/version.js +3 -3
  16. package/dist-cjs/version.js.map +1 -1
  17. package/dist-esm/index.d.mts +82 -13
  18. package/dist-esm/index.mjs +4 -1
  19. package/dist-esm/index.mjs.map +2 -2
  20. package/dist-esm/lib/editor/Editor.mjs +35 -21
  21. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  22. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +2 -2
  23. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  24. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +0 -10
  25. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  26. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +6 -2
  27. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  28. package/dist-esm/lib/utils/reparenting.mjs +216 -0
  29. package/dist-esm/lib/utils/reparenting.mjs.map +7 -0
  30. package/dist-esm/version.mjs +3 -3
  31. package/dist-esm/version.mjs.map +1 -1
  32. package/package.json +7 -7
  33. package/src/index.ts +5 -0
  34. package/src/lib/editor/Editor.ts +45 -29
  35. package/src/lib/editor/managers/TextManager/TextManager.ts +3 -2
  36. package/src/lib/editor/shapes/ShapeUtil.ts +47 -15
  37. package/src/lib/editor/types/emit-types.ts +4 -0
  38. package/src/lib/primitives/geometry/Geometry2d.ts +7 -2
  39. package/src/lib/utils/reparenting.ts +383 -0
  40. package/src/version.ts +3 -3
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var reparenting_exports = {};
20
+ __export(reparenting_exports, {
21
+ doesGeometryOverlapPolygon: () => doesGeometryOverlapPolygon,
22
+ getDroppedShapesToNewParents: () => getDroppedShapesToNewParents,
23
+ kickoutOccludedShapes: () => kickoutOccludedShapes
24
+ });
25
+ module.exports = __toCommonJS(reparenting_exports);
26
+ var import_state = require("@tldraw/state");
27
+ var import_utils = require("@tldraw/utils");
28
+ var import_Group2d = require("../primitives/geometry/Group2d");
29
+ var import_intersect = require("../primitives/intersect");
30
+ var import_utils2 = require("../primitives/utils");
31
+ function kickoutOccludedShapes(editor, shapeIds, opts) {
32
+ const parentsToCheck = /* @__PURE__ */ new Set();
33
+ for (const id of shapeIds) {
34
+ const shape = editor.getShape(id);
35
+ if (!shape) continue;
36
+ parentsToCheck.add(shape);
37
+ const parent = editor.getShape(shape.parentId);
38
+ if (!parent) continue;
39
+ parentsToCheck.add(parent);
40
+ }
41
+ const parentsToLostChildren = /* @__PURE__ */ new Map();
42
+ for (const parent of parentsToCheck) {
43
+ const childIds = editor.getSortedChildIdsForParent(parent);
44
+ if (opts?.filter && !opts.filter(parent)) {
45
+ parentsToLostChildren.set(parent, childIds);
46
+ } else {
47
+ const overlappingChildren = getOverlappingShapes(editor, parent.id, childIds);
48
+ if (overlappingChildren.length < childIds.length) {
49
+ parentsToLostChildren.set(
50
+ parent,
51
+ childIds.filter((id) => !overlappingChildren.includes(id))
52
+ );
53
+ }
54
+ }
55
+ }
56
+ const sortedShapeIds = editor.getCurrentPageShapesSorted().map((s) => s.id);
57
+ const parentsToNewChildren = {};
58
+ for (const [prevParent, lostChildrenIds] of parentsToLostChildren) {
59
+ const lostChildren = (0, import_utils.compact)(lostChildrenIds.map((id) => editor.getShape(id)));
60
+ const { reparenting, remainingShapesToReparent } = getDroppedShapesToNewParents(
61
+ editor,
62
+ lostChildren,
63
+ (shape, maybeNewParent) => {
64
+ if (opts?.filter && !opts.filter(maybeNewParent)) return false;
65
+ return maybeNewParent.id !== prevParent.id && sortedShapeIds.indexOf(maybeNewParent.id) < sortedShapeIds.indexOf(shape.id);
66
+ }
67
+ );
68
+ reparenting.forEach((childrenToReparent, newParentId) => {
69
+ if (childrenToReparent.length === 0) return;
70
+ if (!parentsToNewChildren[newParentId]) {
71
+ parentsToNewChildren[newParentId] = {
72
+ parentId: newParentId,
73
+ shapeIds: []
74
+ };
75
+ }
76
+ parentsToNewChildren[newParentId].shapeIds.push(...childrenToReparent.map((s) => s.id));
77
+ });
78
+ if (remainingShapesToReparent.size > 0) {
79
+ const newParentId = editor.findShapeAncestor(prevParent, (s) => editor.isShapeOfType(s, "group"))?.id ?? editor.getCurrentPageId();
80
+ remainingShapesToReparent.forEach((shape) => {
81
+ if (!parentsToNewChildren[newParentId]) {
82
+ let insertIndexKey;
83
+ const oldParentSiblingIds = editor.getSortedChildIdsForParent(newParentId);
84
+ const oldParentIndex = oldParentSiblingIds.indexOf(prevParent.id);
85
+ if (oldParentIndex > -1) {
86
+ const siblingsIndexAbove = oldParentSiblingIds[oldParentIndex + 1];
87
+ const indexKeyAbove = siblingsIndexAbove ? editor.getShape(siblingsIndexAbove).index : (0, import_utils.getIndexAbove)(prevParent.index);
88
+ insertIndexKey = (0, import_utils.getIndexBetween)(prevParent.index, indexKeyAbove);
89
+ } else {
90
+ }
91
+ parentsToNewChildren[newParentId] = {
92
+ parentId: newParentId,
93
+ shapeIds: [],
94
+ index: insertIndexKey
95
+ };
96
+ }
97
+ parentsToNewChildren[newParentId].shapeIds.push(shape.id);
98
+ });
99
+ }
100
+ }
101
+ editor.run(() => {
102
+ Object.values(parentsToNewChildren).forEach(({ parentId, shapeIds: shapeIds2, index }) => {
103
+ if (shapeIds2.length === 0) return;
104
+ shapeIds2.sort((a, b) => sortedShapeIds.indexOf(a) < sortedShapeIds.indexOf(b) ? -1 : 1);
105
+ editor.reparentShapes(shapeIds2, parentId, index);
106
+ });
107
+ });
108
+ }
109
+ function getOverlappingShapes(editor, shape, otherShapes) {
110
+ if (otherShapes.length === 0) {
111
+ return import_state.EMPTY_ARRAY;
112
+ }
113
+ const parentPageBounds = editor.getShapePageBounds(shape);
114
+ if (!parentPageBounds) return import_state.EMPTY_ARRAY;
115
+ const parentGeometry = editor.getShapeGeometry(shape);
116
+ const parentPageTransform = editor.getShapePageTransform(shape);
117
+ const parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices);
118
+ const parentPageMaskVertices = editor.getShapeMask(shape);
119
+ const parentPagePolygon = parentPageMaskVertices ? (0, import_intersect.intersectPolygonPolygon)(parentPageMaskVertices, parentPageCorners) : parentPageCorners;
120
+ if (!parentPagePolygon) return import_state.EMPTY_ARRAY;
121
+ return otherShapes.filter((childId) => {
122
+ const shapePageBounds = editor.getShapePageBounds(childId);
123
+ if (!shapePageBounds || !parentPageBounds.includes(shapePageBounds)) return false;
124
+ const parentPolygonInShapeShape = editor.getShapePageTransform(childId).clone().invert().applyToPoints(parentPagePolygon);
125
+ const geometry = editor.getShapeGeometry(childId);
126
+ return doesGeometryOverlapPolygon(geometry, parentPolygonInShapeShape);
127
+ });
128
+ }
129
+ function doesGeometryOverlapPolygon(geometry, parentCornersInShapeSpace) {
130
+ if (geometry instanceof import_Group2d.Group2d) {
131
+ return geometry.children.some(
132
+ (childGeometry) => doesGeometryOverlapPolygon(childGeometry, parentCornersInShapeSpace)
133
+ );
134
+ }
135
+ const { vertices, center, isFilled, isEmptyLabel, isClosed } = geometry;
136
+ if (isEmptyLabel) return false;
137
+ if (vertices.some((v) => (0, import_utils2.pointInPolygon)(v, parentCornersInShapeSpace))) {
138
+ return true;
139
+ }
140
+ if (isClosed) {
141
+ if (isFilled) {
142
+ if ((0, import_utils2.pointInPolygon)(center, parentCornersInShapeSpace)) {
143
+ return true;
144
+ }
145
+ if (parentCornersInShapeSpace.every((v) => (0, import_utils2.pointInPolygon)(v, vertices))) {
146
+ return true;
147
+ }
148
+ }
149
+ if ((0, import_intersect.polygonsIntersect)(parentCornersInShapeSpace, vertices)) {
150
+ return true;
151
+ }
152
+ } else {
153
+ if ((0, import_intersect.polygonIntersectsPolyline)(parentCornersInShapeSpace, vertices)) {
154
+ return true;
155
+ }
156
+ }
157
+ return false;
158
+ }
159
+ function getDroppedShapesToNewParents(editor, shapes, cb) {
160
+ const shapesToActuallyCheck = new Set(shapes);
161
+ const movingGroups = /* @__PURE__ */ new Set();
162
+ for (const shape of shapes) {
163
+ const parent = editor.getShapeParent(shape);
164
+ if (parent && editor.isShapeOfType(parent, "group")) {
165
+ if (!movingGroups.has(parent)) {
166
+ movingGroups.add(parent);
167
+ }
168
+ }
169
+ }
170
+ for (const movingGroup of movingGroups) {
171
+ const children = (0, import_utils.compact)(
172
+ editor.getSortedChildIdsForParent(movingGroup).map((id) => editor.getShape(id))
173
+ );
174
+ for (const child of children) {
175
+ shapesToActuallyCheck.delete(child);
176
+ }
177
+ shapesToActuallyCheck.add(movingGroup);
178
+ }
179
+ const shapeGroupIds = /* @__PURE__ */ new Map();
180
+ const reparenting = /* @__PURE__ */ new Map();
181
+ const remainingShapesToReparent = new Set(shapesToActuallyCheck);
182
+ const potentialParentShapes = editor.getCurrentPageShapesSorted().filter(
183
+ (s) => editor.getShapeUtil(s).canReceiveNewChildrenOfType?.(s, s.type) && !remainingShapesToReparent.has(s)
184
+ );
185
+ parentCheck: for (let i = potentialParentShapes.length - 1; i >= 0; i--) {
186
+ const parentShape = potentialParentShapes[i];
187
+ const parentShapeContainingGroupId = editor.findShapeAncestor(
188
+ parentShape,
189
+ (s) => editor.isShapeOfType(s, "group")
190
+ )?.id;
191
+ const parentGeometry = editor.getShapeGeometry(parentShape);
192
+ const parentPageTransform = editor.getShapePageTransform(parentShape);
193
+ const parentPageMaskVertices = editor.getShapeMask(parentShape);
194
+ const parentPageCorners = parentPageTransform.applyToPoints(parentGeometry.vertices);
195
+ const parentPagePolygon = parentPageMaskVertices ? (0, import_intersect.intersectPolygonPolygon)(parentPageMaskVertices, parentPageCorners) : parentPageCorners;
196
+ if (!parentPagePolygon) continue parentCheck;
197
+ const childrenToReparent = [];
198
+ shapeCheck: for (const shape of remainingShapesToReparent) {
199
+ if (parentShape.id === shape.id) continue shapeCheck;
200
+ if (cb && !cb(shape, parentShape)) continue shapeCheck;
201
+ if (!shapeGroupIds.has(shape.id)) {
202
+ shapeGroupIds.set(
203
+ shape.id,
204
+ editor.findShapeAncestor(shape, (s) => editor.isShapeOfType(s, "group"))?.id
205
+ );
206
+ }
207
+ const shapeGroupId = shapeGroupIds.get(shape.id);
208
+ if (shapeGroupId !== parentShapeContainingGroupId) continue shapeCheck;
209
+ if (editor.findShapeAncestor(parentShape, (s) => shape.id === s.id)) continue shapeCheck;
210
+ const parentPolygonInShapeSpace = editor.getShapePageTransform(shape).clone().invert().applyToPoints(parentPagePolygon);
211
+ if (doesGeometryOverlapPolygon(editor.getShapeGeometry(shape), parentPolygonInShapeSpace)) {
212
+ if (!editor.getShapeUtil(parentShape).canReceiveNewChildrenOfType?.(parentShape, shape.type))
213
+ continue shapeCheck;
214
+ if (shape.parentId !== parentShape.id) {
215
+ childrenToReparent.push(shape);
216
+ }
217
+ remainingShapesToReparent.delete(shape);
218
+ continue shapeCheck;
219
+ }
220
+ }
221
+ if (childrenToReparent.length) {
222
+ reparenting.set(parentShape.id, childrenToReparent);
223
+ }
224
+ }
225
+ return {
226
+ // these are the shapes that will be reparented to new parents
227
+ reparenting,
228
+ // these are the shapes that will be reparented to the page or their ancestral group
229
+ remainingShapesToReparent
230
+ };
231
+ }
232
+ //# sourceMappingURL=reparenting.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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 { Vec } from '../primitives/Vec'\nimport { Geometry2d } from '../primitives/geometry/Geometry2d'\nimport { Group2d } from '../primitives/geometry/Group2d'\nimport {\n\tintersectPolygonPolygon,\n\tpolygonIntersectsPolyline,\n\tpolygonsIntersect,\n} from '../primitives/intersect'\nimport { pointInPolygon } from '../primitives/utils'\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 parentPageMaskVertices = editor.getShapeMask(shape)\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 doesGeometryOverlapPolygon(geometry, parentPolygonInShapeShape)\n\t})\n}\n\n/**\n * @public\n */\nexport function doesGeometryOverlapPolygon(\n\tgeometry: Geometry2d,\n\tparentCornersInShapeSpace: Vec[]\n): boolean {\n\t// If the child is a group, check if any of its children overlap the box\n\tif (geometry instanceof Group2d) {\n\t\treturn geometry.children.some((childGeometry) =>\n\t\t\tdoesGeometryOverlapPolygon(childGeometry, parentCornersInShapeSpace)\n\t\t)\n\t}\n\n\t// Otherwise, check if the geometry overlaps the box\n\tconst { vertices, center, isFilled, isEmptyLabel, isClosed } = geometry\n\n\t// We'll do things in order of cheapest to most expensive checks\n\n\t// Skip empty labels\n\tif (isEmptyLabel) return false\n\n\t// If any of the shape's vertices are inside the occluder, it's inside\n\tif (vertices.some((v) => pointInPolygon(v, parentCornersInShapeSpace))) {\n\t\treturn true\n\t}\n\n\t// If the shape is filled and closed and its center is inside the parent, it's inside\n\tif (isClosed) {\n\t\tif (isFilled) {\n\t\t\t// If closed and filled, check if the center is inside the parent\n\t\t\tif (pointInPolygon(center, parentCornersInShapeSpace)) {\n\t\t\t\treturn true\n\t\t\t}\n\n\t\t\t// ..then, slightly more expensive check, see the shape covers the entire parent but not its center\n\t\t\tif (parentCornersInShapeSpace.every((v) => pointInPolygon(v, vertices))) {\n\t\t\t\treturn true\n\t\t\t}\n\t\t}\n\n\t\t// If any the shape's vertices intersect the edge of the occluder, it's inside.\n\t\t// for example when a rotated rectangle is moved over the corner of a parent rectangle\n\t\t// If the child shape is closed, intersect as a polygon\n\t\tif (polygonsIntersect(parentCornersInShapeSpace, vertices)) {\n\t\t\treturn true\n\t\t}\n\t} else {\n\t\t// if the child shape is not closed, intersect as a polyline\n\t\tif (polygonIntersectsPolyline(parentCornersInShapeSpace, vertices)) {\n\t\t\treturn true\n\t\t}\n\t}\n\n\t// If none of the above checks passed, the shape is outside the parent\n\treturn false\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 (doesGeometryOverlapPolygon(editor.getShapeGeometry(shape), 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
+ "names": ["import_utils", "shapeIds"]
7
+ }
@@ -22,10 +22,10 @@ __export(version_exports, {
22
22
  version: () => version
23
23
  });
24
24
  module.exports = __toCommonJS(version_exports);
25
- const version = "3.14.0-canary.6f68b0394e8a";
25
+ const version = "3.14.0-canary.6fbbca54ff57";
26
26
  const publishDates = {
27
27
  major: "2024-09-13T14:36:29.063Z",
28
- minor: "2025-06-23T08:33:08.428Z",
29
- patch: "2025-06-23T08:33:08.428Z"
28
+ minor: "2025-06-24T16:09:26.541Z",
29
+ patch: "2025-06-24T16:09:26.541Z"
30
30
  };
31
31
  //# sourceMappingURL=version.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.0-canary.6f68b0394e8a'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-06-23T08:33:08.428Z',\n\tpatch: '2025-06-23T08:33:08.428Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.14.0-canary.6fbbca54ff57'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-06-24T16:09:26.541Z',\n\tpatch: '2025-06-24T16:09:26.541Z',\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
@@ -2911,6 +2911,8 @@ export declare class Editor extends EventEmitter<TLEventMap> {
2911
2911
  * @public
2912
2912
  */
2913
2913
  getShapeAndDescendantIds(ids: TLShapeId[]): Set<TLShapeId>;
2914
+ /** @deprecated Use {@link Editor.getDraggingOverShape} instead */
2915
+ getDroppingOverShape(point: Vec, droppingShapes: TLShape[]): TLShape | undefined;
2914
2916
  /**
2915
2917
  * Get the shape that some shapes should be dropped on at a given point.
2916
2918
  *
@@ -2921,7 +2923,7 @@ export declare class Editor extends EventEmitter<TLEventMap> {
2921
2923
  *
2922
2924
  * @public
2923
2925
  */
2924
- getDroppingOverShape(point: VecLike, droppingShapes?: TLShape[]): TLUnknownShape | undefined;
2926
+ getDraggingOverShape(point: Vec, droppingShapes: TLShape[]): TLShape | undefined;
2925
2927
  /**
2926
2928
  * Get the shape that should be selected when you click on a given shape, assuming there is
2927
2929
  * nothing already selected. It will not return anything higher than or including the current
@@ -4080,6 +4082,7 @@ export declare abstract class Geometry2d {
4080
4082
  isFilled: boolean;
4081
4083
  isClosed: boolean;
4082
4084
  isLabel: boolean;
4085
+ isEmptyLabel: boolean;
4083
4086
  isInternal: boolean;
4084
4087
  debugColor?: string;
4085
4088
  ignore?: boolean;
@@ -4171,6 +4174,21 @@ export declare function getCursor(cursor: TLCursorType, rotation?: number, color
4171
4174
  /** @public */
4172
4175
  export declare function getDefaultCdnBaseUrl(): string;
4173
4176
 
4177
+ /**
4178
+ * Get the shapes that will be reparented to new parents when the shapes are dropped.
4179
+ *
4180
+ * @param editor - The editor instance.
4181
+ * @param shapes - The shapes to check.
4182
+ * @param cb - A callback to filter out certain shapes.
4183
+ * @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.
4184
+ *
4185
+ * @public
4186
+ */
4187
+ export declare function getDroppedShapesToNewParents(editor: Editor, shapes: Set<TLShape> | TLShape[], cb?: (shape: TLShape, parent: TLShape) => boolean): {
4188
+ remainingShapesToReparent: Set<TLShape>;
4189
+ reparenting: Map<TLShapeId, TLShape[]>;
4190
+ };
4191
+
4174
4192
  /** @public */
4175
4193
  export declare function getFontsFromRichText(editor: Editor, richText: TLRichText, initialState: RichTextFontVisitorState): TLFontFace[];
4176
4194
 
@@ -4524,6 +4542,20 @@ export declare function intersectPolygonPolygon(polygonA: VecLike[], polygonB: V
4524
4542
  */
4525
4543
  export declare const isSafeFloat: (n: number) => boolean;
4526
4544
 
4545
+ /**
4546
+ * Reparents shapes that are no longer contained within their parent shapes.
4547
+ * todo: rename me to something more descriptive, like `reparentOccludedShapes` or `reparentAutoDroppedShapes`
4548
+ *
4549
+ * @param editor - The editor instance.
4550
+ * @param shapeIds - The IDs of the shapes to reparent.
4551
+ * @param opts - Optional options, including a callback to filter out certain parents, such as when removing a frame.
4552
+ *
4553
+ * @public
4554
+ */
4555
+ export declare function kickoutOccludedShapes(editor: Editor, shapeIds: TLShapeId[], opts?: {
4556
+ filter?(parent: TLShape): boolean;
4557
+ }): void;
4558
+
4527
4559
  /* Excluded from this release type: LicenseFromKeyResult */
4528
4560
 
4529
4561
  /* Excluded from this release type: LicenseInfo */
@@ -5203,14 +5235,6 @@ export declare abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknown
5203
5235
  * @public
5204
5236
  */
5205
5237
  canReceiveNewChildrenOfType(_shape: Shape, _type: TLShape['type']): boolean;
5206
- /**
5207
- * Get whether the shape can receive children of a given type.
5208
- *
5209
- * @param shape - The shape type.
5210
- * @param shapes - The shapes that are being dropped.
5211
- * @public
5212
- */
5213
- canDropShapes(_shape: Shape, _shapes: TLShape[]): boolean;
5214
5238
  /**
5215
5239
  * Get the shape as an SVG object.
5216
5240
  *
@@ -5298,7 +5322,15 @@ export declare abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknown
5298
5322
  */
5299
5323
  onCrop?(shape: Shape, info: TLCropInfo<Shape>): Omit<TLShapePartial<Shape>, 'id' | 'type'> | undefined | void;
5300
5324
  /**
5301
- * A callback called when some other shapes are dragged over this one.
5325
+ * A callback called when some other shapes are dragged into this one. This fires when the shapes are dragged over the shape for the first time.
5326
+ *
5327
+ * @param shape - The shape.
5328
+ * @param shapes - The shapes that are being dragged in.
5329
+ * @public
5330
+ */
5331
+ onDragShapesIn?(shape: Shape, shapes: TLShape[], info: TLDragShapesInInfo): void;
5332
+ /**
5333
+ * A callback called when some other shapes are dragged over this one. This fires when the shapes are dragged over the shape for the first time (after the onDragShapesIn callback), and again on every update while the shapes are being dragged.
5302
5334
  *
5303
5335
  * @example
5304
5336
  *
@@ -5312,7 +5344,7 @@ export declare abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknown
5312
5344
  * @param shapes - The shapes that are being dragged over this one.
5313
5345
  * @public
5314
5346
  */
5315
- onDragShapesOver?(shape: Shape, shapes: TLShape[]): void;
5347
+ onDragShapesOver?(shape: Shape, shapes: TLShape[], info: TLDragShapesOverInfo): void;
5316
5348
  /**
5317
5349
  * A callback called when some other shapes are dragged out of this one.
5318
5350
  *
@@ -5320,7 +5352,7 @@ export declare abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknown
5320
5352
  * @param shapes - The shapes that are being dragged out.
5321
5353
  * @public
5322
5354
  */
5323
- onDragShapesOut?(shape: Shape, shapes: TLShape[]): void;
5355
+ onDragShapesOut?(shape: Shape, shapes: TLShape[], info: TLDragShapesOutInfo): void;
5324
5356
  /**
5325
5357
  * A callback called when some other shapes are dropped over this one.
5326
5358
  *
@@ -5328,7 +5360,7 @@ export declare abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknown
5328
5360
  * @param shapes - The shapes that are being dropped over this one.
5329
5361
  * @public
5330
5362
  */
5331
- onDropShapesOver?(shape: Shape, shapes: TLShape[]): void;
5363
+ onDropShapesOver?(shape: Shape, shapes: TLShape[], info: TLDropShapesOverInfo): void;
5332
5364
  /**
5333
5365
  * A callback called when a shape starts being resized.
5334
5366
  *
@@ -6002,6 +6034,7 @@ export declare interface TLCropInfo<T extends TLShape> {
6002
6034
  w: number;
6003
6035
  };
6004
6036
  initialShape: T;
6037
+ aspectRatioLocked?: boolean;
6005
6038
  }
6006
6039
 
6007
6040
  /** @public */
@@ -6060,6 +6093,29 @@ export declare interface TLDeepLinkOptions {
6060
6093
  onChange?(url: URL, editor: Editor): void;
6061
6094
  }
6062
6095
 
6096
+ /** @public */
6097
+ export declare interface TLDragShapesInInfo {
6098
+ initialDraggingOverShapeId: null | TLShapeId;
6099
+ prevDraggingOverShapeId: null | TLShapeId;
6100
+ initialParentIds: Map<TLShapeId, TLParentId>;
6101
+ initialIndices: Map<TLShapeId, IndexKey>;
6102
+ }
6103
+
6104
+ /** @public */
6105
+ export declare interface TLDragShapesOutInfo {
6106
+ nextDraggingOverShapeId: null | TLShapeId;
6107
+ initialDraggingOverShapeId: null | TLShapeId;
6108
+ initialParentIds: Map<TLShapeId, TLParentId>;
6109
+ initialIndices: Map<TLShapeId, IndexKey>;
6110
+ }
6111
+
6112
+ /** @public */
6113
+ export declare interface TLDragShapesOverInfo {
6114
+ initialDraggingOverShapeId: null | TLShapeId;
6115
+ initialParentIds: Map<TLShapeId, TLParentId>;
6116
+ initialIndices: Map<TLShapeId, IndexKey>;
6117
+ }
6118
+
6063
6119
  /** @public @react */
6064
6120
  export declare const TldrawEditor: React_2.NamedExoticComponent<TldrawEditorProps>;
6065
6121
 
@@ -6307,6 +6363,13 @@ export declare interface TldrawOptions {
6307
6363
  readonly branding?: string;
6308
6364
  }
6309
6365
 
6366
+ /** @public */
6367
+ export declare interface TLDropShapesOverInfo {
6368
+ initialDraggingOverShapeId: null | TLShapeId;
6369
+ initialParentIds: Map<TLShapeId, TLParentId>;
6370
+ initialIndices: Map<TLShapeId, IndexKey>;
6371
+ }
6372
+
6310
6373
  /** @public */
6311
6374
  export declare interface TLEditorComponents {
6312
6375
  Background?: ComponentType | null;
@@ -6529,6 +6592,10 @@ export declare interface TLEventMap {
6529
6592
  };
6530
6593
  shapeId: TLShapeId;
6531
6594
  }];
6595
+ 'created-shapes': [TLRecord[]];
6596
+ 'edited-shapes': [TLRecord[]];
6597
+ 'deleted-shapes': [TLShapeId[]];
6598
+ edit: [];
6532
6599
  }
6533
6600
 
6534
6601
  /** @public */
@@ -6784,6 +6851,7 @@ export declare interface TLMeasureTextOpts {
6784
6851
  fontWeight: string;
6785
6852
  fontFamily: string;
6786
6853
  fontSize: number;
6854
+ /** This must be a number, e.g. 1.35, not a pixel value. */
6787
6855
  lineHeight: number;
6788
6856
  /**
6789
6857
  * When maxWidth is a number, the text will be wrapped to that maxWidth. When maxWidth
@@ -7473,6 +7541,7 @@ export declare class TransformedGeometry2d extends Geometry2d {
7473
7541
  /** @public */
7474
7542
  export declare interface TransformedGeometry2dOptions {
7475
7543
  isLabel?: boolean;
7544
+ isEmptyLabel?: boolean;
7476
7545
  isInternal?: boolean;
7477
7546
  debugColor?: string;
7478
7547
  ignore?: boolean;
@@ -275,6 +275,7 @@ import { hardResetEditor } from "./lib/utils/hardResetEditor.mjs";
275
275
  import { isAccelKey } from "./lib/utils/keyboard.mjs";
276
276
  import { normalizeWheel } from "./lib/utils/normalizeWheel.mjs";
277
277
  import { refreshPage } from "./lib/utils/refreshPage.mjs";
278
+ import { getDroppedShapesToNewParents, kickoutOccludedShapes } from "./lib/utils/reparenting.mjs";
278
279
  import {
279
280
  getFontsFromRichText
280
281
  } from "./lib/utils/richText.mjs";
@@ -292,7 +293,7 @@ function debugEnableLicensing() {
292
293
  }
293
294
  registerTldrawLibraryVersion(
294
295
  "@tldraw/editor",
295
- "3.14.0-canary.6f68b0394e8a",
296
+ "3.14.0-canary.6fbbca54ff57",
296
297
  "esm"
297
298
  );
298
299
  export {
@@ -405,6 +406,7 @@ export {
405
406
  getArcMeasure,
406
407
  getCursor,
407
408
  getDefaultCdnBaseUrl,
409
+ getDroppedShapesToNewParents,
408
410
  getFontsFromRichText,
409
411
  getFreshUserPreferences,
410
412
  getIncrementedName,
@@ -433,6 +435,7 @@ export {
433
435
  intersectPolygonPolygon,
434
436
  isAccelKey,
435
437
  isSafeFloat,
438
+ kickoutOccludedShapes,
436
439
  linesIntersect,
437
440
  loadSessionStateSnapshotIntoStore,
438
441
  loadSnapshot,