@tldraw/editor 5.3.0-canary.50fed61679d4 → 5.3.0-canary.58df715967e7

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.
@@ -219,7 +219,7 @@ export declare abstract class BaseBoxShapeUtil<Shape extends TLBaseBoxShape> ext
219
219
  }
220
220
 
221
221
  /**
222
- * A base class for frame-like shapes — containers that clip their children,
222
+ * A base class for frame-like shapes — containers that clip their children except arrows,
223
223
  * require full-brush selection, block erasure from inside, and support
224
224
  * drag-and-drop reparenting.
225
225
  *
@@ -231,6 +231,7 @@ export declare abstract class BaseBoxShapeUtil<Shape extends TLBaseBoxShape> ext
231
231
  * - `canReceiveNewChildrenOfType()` returns `true` unless the container is locked
232
232
  * - `canRemoveChildrenOfType()` returns `true` unless the container is locked
233
233
  * - `getClipPath()` returns the shape geometry's vertices
234
+ * - `shouldClipChild()` clips all children except arrows
234
235
  * - `onDragShapesIn()` reparents shapes into the frame (with index restoration)
235
236
  * - `onDragShapesOut()` reparents shapes back to the page
236
237
  *
@@ -266,6 +267,7 @@ export declare abstract class BaseFrameLikeShapeUtil<Shape extends TLBaseBoxShap
266
267
  canReceiveNewChildrenOfType(shape: Shape, _type: TLShape['type']): boolean;
267
268
  canRemoveChildrenOfType(shape: Shape, _type: TLShape['type']): boolean;
268
269
  getClipPath(shape: Shape): undefined | Vec[];
270
+ shouldClipChild(child: TLShape): boolean;
269
271
  onDragShapesIn(shape: Shape, draggingShapes: TLShape[], { initialParentIds, initialIndices }: TLDragShapesInInfo): void;
270
272
  onDragShapesOut(shape: Shape, draggingShapes: TLShape[], info: TLDragShapesOutInfo): void;
271
273
  }
package/dist-cjs/index.js CHANGED
@@ -379,7 +379,7 @@ var import_uniq = require("./lib/utils/uniq");
379
379
  var import_defaultThemes2 = require("./lib/editor/managers/ThemeManager/defaultThemes");
380
380
  (0, import_utils.registerTldrawLibraryVersion)(
381
381
  "@tldraw/editor",
382
- "5.3.0-canary.50fed61679d4",
382
+ "5.3.0-canary.58df715967e7",
383
383
  "cjs"
384
384
  );
385
385
  //# sourceMappingURL=index.js.map
@@ -39,6 +39,9 @@ class BaseFrameLikeShapeUtil extends import_BaseBoxShapeUtil.BaseBoxShapeUtil {
39
39
  getClipPath(shape) {
40
40
  return this.editor.getShapeGeometry(shape.id).vertices;
41
41
  }
42
+ shouldClipChild(child) {
43
+ return child.type !== "arrow";
44
+ }
42
45
  onDragShapesIn(shape, draggingShapes, { initialParentIds, initialIndices }) {
43
46
  const { editor } = this;
44
47
  if (draggingShapes.every((s) => s.parentId === shape.id)) return;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx"],
4
- "sourcesContent": ["import { TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { IndexKey, compact } from '@tldraw/utils'\nimport { Vec } from '../../primitives/Vec'\nimport { BaseBoxShapeUtil, TLBaseBoxShape } from './BaseBoxShapeUtil'\nimport { TLDragShapesInInfo, TLDragShapesOutInfo } from './ShapeUtil'\n\n/**\n * A base class for frame-like shapes \u2014 containers that clip their children,\n * require full-brush selection, block erasure from inside, and support\n * drag-and-drop reparenting.\n *\n * Extending this class is the easiest way to create a custom frame-like shape.\n * It provides sensible defaults for all frame-like behaviors:\n *\n * - `isFrameLike()` returns `true`\n * - `providesBackgroundForChildren()` returns `true`\n * - `canReceiveNewChildrenOfType()` returns `true` unless the container is locked\n * - `canRemoveChildrenOfType()` returns `true` unless the container is locked\n * - `getClipPath()` returns the shape geometry's vertices\n * - `onDragShapesIn()` reparents shapes into the frame (with index restoration)\n * - `onDragShapesOut()` reparents shapes back to the page\n *\n * All methods can be overridden for custom behavior.\n *\n * @example\n * ```ts\n * class MyContainerUtil extends BaseFrameLikeShapeUtil<MyContainerShape> {\n * static override type = 'my-container' as const\n * static override props = myContainerShapeProps\n *\n * override getDefaultProps() {\n * return { w: 300, h: 200 }\n * }\n *\n * override component(shape: MyContainerShape) {\n * return <SVGContainer>...</SVGContainer>\n * }\n *\n * override getIndicatorPath(shape: MyContainerShape) {\n * const path = new Path2D()\n * path.rect(0, 0, shape.props.w, shape.props.h)\n * return path\n * }\n * }\n * ```\n *\n * @public\n */\nexport abstract class BaseFrameLikeShapeUtil<\n\tShape extends TLBaseBoxShape,\n> extends BaseBoxShapeUtil<Shape> {\n\toverride isFrameLike(_shape: Shape): boolean {\n\t\treturn true\n\t}\n\n\toverride providesBackgroundForChildren(): boolean {\n\t\treturn true\n\t}\n\n\toverride canReceiveNewChildrenOfType(shape: Shape, _type: TLShape['type']): boolean {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride canRemoveChildrenOfType(shape: Shape, _type: TLShape['type']): boolean {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride getClipPath(shape: Shape): Vec[] | undefined {\n\t\treturn this.editor.getShapeGeometry(shape.id).vertices\n\t}\n\n\toverride onDragShapesIn(\n\t\tshape: Shape,\n\t\tdraggingShapes: TLShape[],\n\t\t{ initialParentIds, initialIndices }: TLDragShapesInInfo\n\t): void {\n\t\tconst { editor } = this\n\n\t\tif (draggingShapes.every((s) => s.parentId === shape.id)) return\n\n\t\t// Check to see whether any of the shapes can have their old index restored\n\t\tlet canRestoreOriginalIndices = false\n\t\tconst previousChildren = draggingShapes.filter(\n\t\t\t(s) => shape.id === (initialParentIds.get(s.id) as TLShapeId)\n\t\t)\n\n\t\tif (previousChildren.length > 0) {\n\t\t\tconst currentChildren = compact(\n\t\t\t\teditor.getSortedChildIdsForParent(shape).map((id) => editor.getShape(id))\n\t\t\t)\n\t\t\tif (previousChildren.every((s) => !currentChildren.find((c) => c.index === s.index))) {\n\t\t\t\tcanRestoreOriginalIndices = true\n\t\t\t}\n\t\t}\n\n\t\t// If any of the children are the ancestor of the frame, quit here\n\t\tif (draggingShapes.some((s) => editor.hasAncestor(shape, s.id))) return\n\n\t\teditor.reparentShapes(draggingShapes, shape.id)\n\n\t\tif (canRestoreOriginalIndices) {\n\t\t\tfor (const s of previousChildren) {\n\t\t\t\teditor.updateShape({\n\t\t\t\t\tid: s.id,\n\t\t\t\t\ttype: s.type,\n\t\t\t\t\tindex: initialIndices.get(s.id) as IndexKey,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\toverride onDragShapesOut(\n\t\tshape: Shape,\n\t\tdraggingShapes: TLShape[],\n\t\tinfo: TLDragShapesOutInfo\n\t): void {\n\t\tconst { editor } = this\n\t\t// When a user drags shapes out and we're not dragging into a new shape,\n\t\t// reparent the dragging shapes onto the current page instead\n\t\tif (!info.nextDraggingOverShapeId) {\n\t\t\t// Locked shapes are already filtered out upstream by DragAndDropManager.\n\t\t\teditor.reparentShapes(\n\t\t\t\tdraggingShapes.filter((s) => s.parentId === shape.id),\n\t\t\t\teditor.getCurrentPageId()\n\t\t\t)\n\t\t}\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAAkC;AAElC,8BAAiD;AA6C1C,MAAe,+BAEZ,yCAAwB;AAAA,EACxB,YAAY,QAAwB;AAC5C,WAAO;AAAA,EACR;AAAA,EAES,gCAAyC;AACjD,WAAO;AAAA,EACR;AAAA,EAES,4BAA4B,OAAc,OAAiC;AACnF,WAAO,CAAC,MAAM;AAAA,EACf;AAAA,EAES,wBAAwB,OAAc,OAAiC;AAC/E,WAAO,CAAC,MAAM;AAAA,EACf;AAAA,EAES,YAAY,OAAiC;AACrD,WAAO,KAAK,OAAO,iBAAiB,MAAM,EAAE,EAAE;AAAA,EAC/C;AAAA,EAES,eACR,OACA,gBACA,EAAE,kBAAkB,eAAe,GAC5B;AACP,UAAM,EAAE,OAAO,IAAI;AAEnB,QAAI,eAAe,MAAM,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE,EAAG;AAG1D,QAAI,4BAA4B;AAChC,UAAM,mBAAmB,eAAe;AAAA,MACvC,CAAC,MAAM,MAAM,OAAQ,iBAAiB,IAAI,EAAE,EAAE;AAAA,IAC/C;AAEA,QAAI,iBAAiB,SAAS,GAAG;AAChC,YAAM,sBAAkB;AAAA,QACvB,OAAO,2BAA2B,KAAK,EAAE,IAAI,CAAC,OAAO,OAAO,SAAS,EAAE,CAAC;AAAA,MACzE;AACA,UAAI,iBAAiB,MAAM,CAAC,MAAM,CAAC,gBAAgB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,GAAG;AACrF,oCAA4B;AAAA,MAC7B;AAAA,IACD;AAGA,QAAI,eAAe,KAAK,CAAC,MAAM,OAAO,YAAY,OAAO,EAAE,EAAE,CAAC,EAAG;AAEjE,WAAO,eAAe,gBAAgB,MAAM,EAAE;AAE9C,QAAI,2BAA2B;AAC9B,iBAAW,KAAK,kBAAkB;AACjC,eAAO,YAAY;AAAA,UAClB,IAAI,EAAE;AAAA,UACN,MAAM,EAAE;AAAA,UACR,OAAO,eAAe,IAAI,EAAE,EAAE;AAAA,QAC/B,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAES,gBACR,OACA,gBACA,MACO;AACP,UAAM,EAAE,OAAO,IAAI;AAGnB,QAAI,CAAC,KAAK,yBAAyB;AAElC,aAAO;AAAA,QACN,eAAe,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE;AAAA,QACpD,OAAO,iBAAiB;AAAA,MACzB;AAAA,IACD;AAAA,EACD;AACD;",
4
+ "sourcesContent": ["import { TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { IndexKey, compact } from '@tldraw/utils'\nimport { Vec } from '../../primitives/Vec'\nimport { BaseBoxShapeUtil, TLBaseBoxShape } from './BaseBoxShapeUtil'\nimport { TLDragShapesInInfo, TLDragShapesOutInfo } from './ShapeUtil'\n\n/**\n * A base class for frame-like shapes \u2014 containers that clip their children except arrows,\n * require full-brush selection, block erasure from inside, and support\n * drag-and-drop reparenting.\n *\n * Extending this class is the easiest way to create a custom frame-like shape.\n * It provides sensible defaults for all frame-like behaviors:\n *\n * - `isFrameLike()` returns `true`\n * - `providesBackgroundForChildren()` returns `true`\n * - `canReceiveNewChildrenOfType()` returns `true` unless the container is locked\n * - `canRemoveChildrenOfType()` returns `true` unless the container is locked\n * - `getClipPath()` returns the shape geometry's vertices\n * - `shouldClipChild()` clips all children except arrows\n * - `onDragShapesIn()` reparents shapes into the frame (with index restoration)\n * - `onDragShapesOut()` reparents shapes back to the page\n *\n * All methods can be overridden for custom behavior.\n *\n * @example\n * ```ts\n * class MyContainerUtil extends BaseFrameLikeShapeUtil<MyContainerShape> {\n * static override type = 'my-container' as const\n * static override props = myContainerShapeProps\n *\n * override getDefaultProps() {\n * return { w: 300, h: 200 }\n * }\n *\n * override component(shape: MyContainerShape) {\n * return <SVGContainer>...</SVGContainer>\n * }\n *\n * override getIndicatorPath(shape: MyContainerShape) {\n * const path = new Path2D()\n * path.rect(0, 0, shape.props.w, shape.props.h)\n * return path\n * }\n * }\n * ```\n *\n * @public\n */\nexport abstract class BaseFrameLikeShapeUtil<\n\tShape extends TLBaseBoxShape,\n> extends BaseBoxShapeUtil<Shape> {\n\toverride isFrameLike(_shape: Shape): boolean {\n\t\treturn true\n\t}\n\n\toverride providesBackgroundForChildren(): boolean {\n\t\treturn true\n\t}\n\n\toverride canReceiveNewChildrenOfType(shape: Shape, _type: TLShape['type']): boolean {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride canRemoveChildrenOfType(shape: Shape, _type: TLShape['type']): boolean {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride getClipPath(shape: Shape): Vec[] | undefined {\n\t\treturn this.editor.getShapeGeometry(shape.id).vertices\n\t}\n\n\toverride shouldClipChild(child: TLShape): boolean {\n\t\treturn child.type !== 'arrow'\n\t}\n\n\toverride onDragShapesIn(\n\t\tshape: Shape,\n\t\tdraggingShapes: TLShape[],\n\t\t{ initialParentIds, initialIndices }: TLDragShapesInInfo\n\t): void {\n\t\tconst { editor } = this\n\n\t\tif (draggingShapes.every((s) => s.parentId === shape.id)) return\n\n\t\t// Check to see whether any of the shapes can have their old index restored\n\t\tlet canRestoreOriginalIndices = false\n\t\tconst previousChildren = draggingShapes.filter(\n\t\t\t(s) => shape.id === (initialParentIds.get(s.id) as TLShapeId)\n\t\t)\n\n\t\tif (previousChildren.length > 0) {\n\t\t\tconst currentChildren = compact(\n\t\t\t\teditor.getSortedChildIdsForParent(shape).map((id) => editor.getShape(id))\n\t\t\t)\n\t\t\tif (previousChildren.every((s) => !currentChildren.find((c) => c.index === s.index))) {\n\t\t\t\tcanRestoreOriginalIndices = true\n\t\t\t}\n\t\t}\n\n\t\t// If any of the children are the ancestor of the frame, quit here\n\t\tif (draggingShapes.some((s) => editor.hasAncestor(shape, s.id))) return\n\n\t\teditor.reparentShapes(draggingShapes, shape.id)\n\n\t\tif (canRestoreOriginalIndices) {\n\t\t\tfor (const s of previousChildren) {\n\t\t\t\teditor.updateShape({\n\t\t\t\t\tid: s.id,\n\t\t\t\t\ttype: s.type,\n\t\t\t\t\tindex: initialIndices.get(s.id) as IndexKey,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\toverride onDragShapesOut(\n\t\tshape: Shape,\n\t\tdraggingShapes: TLShape[],\n\t\tinfo: TLDragShapesOutInfo\n\t): void {\n\t\tconst { editor } = this\n\t\t// When a user drags shapes out and we're not dragging into a new shape,\n\t\t// reparent the dragging shapes onto the current page instead\n\t\tif (!info.nextDraggingOverShapeId) {\n\t\t\t// Locked shapes are already filtered out upstream by DragAndDropManager.\n\t\t\teditor.reparentShapes(\n\t\t\t\tdraggingShapes.filter((s) => s.parentId === shape.id),\n\t\t\t\teditor.getCurrentPageId()\n\t\t\t)\n\t\t}\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,mBAAkC;AAElC,8BAAiD;AA8C1C,MAAe,+BAEZ,yCAAwB;AAAA,EACxB,YAAY,QAAwB;AAC5C,WAAO;AAAA,EACR;AAAA,EAES,gCAAyC;AACjD,WAAO;AAAA,EACR;AAAA,EAES,4BAA4B,OAAc,OAAiC;AACnF,WAAO,CAAC,MAAM;AAAA,EACf;AAAA,EAES,wBAAwB,OAAc,OAAiC;AAC/E,WAAO,CAAC,MAAM;AAAA,EACf;AAAA,EAES,YAAY,OAAiC;AACrD,WAAO,KAAK,OAAO,iBAAiB,MAAM,EAAE,EAAE;AAAA,EAC/C;AAAA,EAES,gBAAgB,OAAyB;AACjD,WAAO,MAAM,SAAS;AAAA,EACvB;AAAA,EAES,eACR,OACA,gBACA,EAAE,kBAAkB,eAAe,GAC5B;AACP,UAAM,EAAE,OAAO,IAAI;AAEnB,QAAI,eAAe,MAAM,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE,EAAG;AAG1D,QAAI,4BAA4B;AAChC,UAAM,mBAAmB,eAAe;AAAA,MACvC,CAAC,MAAM,MAAM,OAAQ,iBAAiB,IAAI,EAAE,EAAE;AAAA,IAC/C;AAEA,QAAI,iBAAiB,SAAS,GAAG;AAChC,YAAM,sBAAkB;AAAA,QACvB,OAAO,2BAA2B,KAAK,EAAE,IAAI,CAAC,OAAO,OAAO,SAAS,EAAE,CAAC;AAAA,MACzE;AACA,UAAI,iBAAiB,MAAM,CAAC,MAAM,CAAC,gBAAgB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,GAAG;AACrF,oCAA4B;AAAA,MAC7B;AAAA,IACD;AAGA,QAAI,eAAe,KAAK,CAAC,MAAM,OAAO,YAAY,OAAO,EAAE,EAAE,CAAC,EAAG;AAEjE,WAAO,eAAe,gBAAgB,MAAM,EAAE;AAE9C,QAAI,2BAA2B;AAC9B,iBAAW,KAAK,kBAAkB;AACjC,eAAO,YAAY;AAAA,UAClB,IAAI,EAAE;AAAA,UACN,MAAM,EAAE;AAAA,UACR,OAAO,eAAe,IAAI,EAAE,EAAE;AAAA,QAC/B,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAES,gBACR,OACA,gBACA,MACO;AACP,UAAM,EAAE,OAAO,IAAI;AAGnB,QAAI,CAAC,KAAK,yBAAyB;AAElC,aAAO;AAAA,QACN,eAAe,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE;AAAA,QACpD,OAAO,iBAAiB;AAAA,MACzB;AAAA,IACD;AAAA,EACD;AACD;",
6
6
  "names": []
7
7
  }
@@ -22,10 +22,10 @@ __export(version_exports, {
22
22
  version: () => version
23
23
  });
24
24
  module.exports = __toCommonJS(version_exports);
25
- const version = "5.3.0-canary.50fed61679d4";
25
+ const version = "5.3.0-canary.58df715967e7";
26
26
  const publishDates = {
27
27
  major: "2026-05-06T16:28:18.473Z",
28
- minor: "2026-07-02T09:23:18.538Z",
29
- patch: "2026-07-02T09:23:18.538Z"
28
+ minor: "2026-07-02T13:11:09.282Z",
29
+ patch: "2026-07-02T13:11:09.282Z"
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 = '5.3.0-canary.50fed61679d4'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-02T09:23:18.538Z',\n\tpatch: '2026-07-02T09:23:18.538Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.3.0-canary.58df715967e7'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-02T13:11:09.282Z',\n\tpatch: '2026-07-02T13:11:09.282Z',\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
  }
@@ -219,7 +219,7 @@ export declare abstract class BaseBoxShapeUtil<Shape extends TLBaseBoxShape> ext
219
219
  }
220
220
 
221
221
  /**
222
- * A base class for frame-like shapes — containers that clip their children,
222
+ * A base class for frame-like shapes — containers that clip their children except arrows,
223
223
  * require full-brush selection, block erasure from inside, and support
224
224
  * drag-and-drop reparenting.
225
225
  *
@@ -231,6 +231,7 @@ export declare abstract class BaseBoxShapeUtil<Shape extends TLBaseBoxShape> ext
231
231
  * - `canReceiveNewChildrenOfType()` returns `true` unless the container is locked
232
232
  * - `canRemoveChildrenOfType()` returns `true` unless the container is locked
233
233
  * - `getClipPath()` returns the shape geometry's vertices
234
+ * - `shouldClipChild()` clips all children except arrows
234
235
  * - `onDragShapesIn()` reparents shapes into the frame (with index restoration)
235
236
  * - `onDragShapesOut()` reparents shapes back to the page
236
237
  *
@@ -266,6 +267,7 @@ export declare abstract class BaseFrameLikeShapeUtil<Shape extends TLBaseBoxShap
266
267
  canReceiveNewChildrenOfType(shape: Shape, _type: TLShape['type']): boolean;
267
268
  canRemoveChildrenOfType(shape: Shape, _type: TLShape['type']): boolean;
268
269
  getClipPath(shape: Shape): undefined | Vec[];
270
+ shouldClipChild(child: TLShape): boolean;
269
271
  onDragShapesIn(shape: Shape, draggingShapes: TLShape[], { initialParentIds, initialIndices }: TLDragShapesInInfo): void;
270
272
  onDragShapesOut(shape: Shape, draggingShapes: TLShape[], info: TLDragShapesOutInfo): void;
271
273
  }
@@ -296,7 +296,7 @@ import { LocalIndexedDb, Table } from "./lib/utils/sync/LocalIndexedDb.mjs";
296
296
  import { uniq } from "./lib/utils/uniq.mjs";
297
297
  registerTldrawLibraryVersion(
298
298
  "@tldraw/editor",
299
- "5.3.0-canary.50fed61679d4",
299
+ "5.3.0-canary.58df715967e7",
300
300
  "esm"
301
301
  );
302
302
  import { getColorValue } from "./lib/editor/managers/ThemeManager/defaultThemes.mjs";
@@ -16,6 +16,9 @@ class BaseFrameLikeShapeUtil extends BaseBoxShapeUtil {
16
16
  getClipPath(shape) {
17
17
  return this.editor.getShapeGeometry(shape.id).vertices;
18
18
  }
19
+ shouldClipChild(child) {
20
+ return child.type !== "arrow";
21
+ }
19
22
  onDragShapesIn(shape, draggingShapes, { initialParentIds, initialIndices }) {
20
23
  const { editor } = this;
21
24
  if (draggingShapes.every((s) => s.parentId === shape.id)) return;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/editor/shapes/BaseFrameLikeShapeUtil.tsx"],
4
- "sourcesContent": ["import { TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { IndexKey, compact } from '@tldraw/utils'\nimport { Vec } from '../../primitives/Vec'\nimport { BaseBoxShapeUtil, TLBaseBoxShape } from './BaseBoxShapeUtil'\nimport { TLDragShapesInInfo, TLDragShapesOutInfo } from './ShapeUtil'\n\n/**\n * A base class for frame-like shapes \u2014 containers that clip their children,\n * require full-brush selection, block erasure from inside, and support\n * drag-and-drop reparenting.\n *\n * Extending this class is the easiest way to create a custom frame-like shape.\n * It provides sensible defaults for all frame-like behaviors:\n *\n * - `isFrameLike()` returns `true`\n * - `providesBackgroundForChildren()` returns `true`\n * - `canReceiveNewChildrenOfType()` returns `true` unless the container is locked\n * - `canRemoveChildrenOfType()` returns `true` unless the container is locked\n * - `getClipPath()` returns the shape geometry's vertices\n * - `onDragShapesIn()` reparents shapes into the frame (with index restoration)\n * - `onDragShapesOut()` reparents shapes back to the page\n *\n * All methods can be overridden for custom behavior.\n *\n * @example\n * ```ts\n * class MyContainerUtil extends BaseFrameLikeShapeUtil<MyContainerShape> {\n * static override type = 'my-container' as const\n * static override props = myContainerShapeProps\n *\n * override getDefaultProps() {\n * return { w: 300, h: 200 }\n * }\n *\n * override component(shape: MyContainerShape) {\n * return <SVGContainer>...</SVGContainer>\n * }\n *\n * override getIndicatorPath(shape: MyContainerShape) {\n * const path = new Path2D()\n * path.rect(0, 0, shape.props.w, shape.props.h)\n * return path\n * }\n * }\n * ```\n *\n * @public\n */\nexport abstract class BaseFrameLikeShapeUtil<\n\tShape extends TLBaseBoxShape,\n> extends BaseBoxShapeUtil<Shape> {\n\toverride isFrameLike(_shape: Shape): boolean {\n\t\treturn true\n\t}\n\n\toverride providesBackgroundForChildren(): boolean {\n\t\treturn true\n\t}\n\n\toverride canReceiveNewChildrenOfType(shape: Shape, _type: TLShape['type']): boolean {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride canRemoveChildrenOfType(shape: Shape, _type: TLShape['type']): boolean {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride getClipPath(shape: Shape): Vec[] | undefined {\n\t\treturn this.editor.getShapeGeometry(shape.id).vertices\n\t}\n\n\toverride onDragShapesIn(\n\t\tshape: Shape,\n\t\tdraggingShapes: TLShape[],\n\t\t{ initialParentIds, initialIndices }: TLDragShapesInInfo\n\t): void {\n\t\tconst { editor } = this\n\n\t\tif (draggingShapes.every((s) => s.parentId === shape.id)) return\n\n\t\t// Check to see whether any of the shapes can have their old index restored\n\t\tlet canRestoreOriginalIndices = false\n\t\tconst previousChildren = draggingShapes.filter(\n\t\t\t(s) => shape.id === (initialParentIds.get(s.id) as TLShapeId)\n\t\t)\n\n\t\tif (previousChildren.length > 0) {\n\t\t\tconst currentChildren = compact(\n\t\t\t\teditor.getSortedChildIdsForParent(shape).map((id) => editor.getShape(id))\n\t\t\t)\n\t\t\tif (previousChildren.every((s) => !currentChildren.find((c) => c.index === s.index))) {\n\t\t\t\tcanRestoreOriginalIndices = true\n\t\t\t}\n\t\t}\n\n\t\t// If any of the children are the ancestor of the frame, quit here\n\t\tif (draggingShapes.some((s) => editor.hasAncestor(shape, s.id))) return\n\n\t\teditor.reparentShapes(draggingShapes, shape.id)\n\n\t\tif (canRestoreOriginalIndices) {\n\t\t\tfor (const s of previousChildren) {\n\t\t\t\teditor.updateShape({\n\t\t\t\t\tid: s.id,\n\t\t\t\t\ttype: s.type,\n\t\t\t\t\tindex: initialIndices.get(s.id) as IndexKey,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\toverride onDragShapesOut(\n\t\tshape: Shape,\n\t\tdraggingShapes: TLShape[],\n\t\tinfo: TLDragShapesOutInfo\n\t): void {\n\t\tconst { editor } = this\n\t\t// When a user drags shapes out and we're not dragging into a new shape,\n\t\t// reparent the dragging shapes onto the current page instead\n\t\tif (!info.nextDraggingOverShapeId) {\n\t\t\t// Locked shapes are already filtered out upstream by DragAndDropManager.\n\t\t\teditor.reparentShapes(\n\t\t\t\tdraggingShapes.filter((s) => s.parentId === shape.id),\n\t\t\t\teditor.getCurrentPageId()\n\t\t\t)\n\t\t}\n\t}\n}\n"],
5
- "mappings": "AACA,SAAmB,eAAe;AAElC,SAAS,wBAAwC;AA6C1C,MAAe,+BAEZ,iBAAwB;AAAA,EACxB,YAAY,QAAwB;AAC5C,WAAO;AAAA,EACR;AAAA,EAES,gCAAyC;AACjD,WAAO;AAAA,EACR;AAAA,EAES,4BAA4B,OAAc,OAAiC;AACnF,WAAO,CAAC,MAAM;AAAA,EACf;AAAA,EAES,wBAAwB,OAAc,OAAiC;AAC/E,WAAO,CAAC,MAAM;AAAA,EACf;AAAA,EAES,YAAY,OAAiC;AACrD,WAAO,KAAK,OAAO,iBAAiB,MAAM,EAAE,EAAE;AAAA,EAC/C;AAAA,EAES,eACR,OACA,gBACA,EAAE,kBAAkB,eAAe,GAC5B;AACP,UAAM,EAAE,OAAO,IAAI;AAEnB,QAAI,eAAe,MAAM,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE,EAAG;AAG1D,QAAI,4BAA4B;AAChC,UAAM,mBAAmB,eAAe;AAAA,MACvC,CAAC,MAAM,MAAM,OAAQ,iBAAiB,IAAI,EAAE,EAAE;AAAA,IAC/C;AAEA,QAAI,iBAAiB,SAAS,GAAG;AAChC,YAAM,kBAAkB;AAAA,QACvB,OAAO,2BAA2B,KAAK,EAAE,IAAI,CAAC,OAAO,OAAO,SAAS,EAAE,CAAC;AAAA,MACzE;AACA,UAAI,iBAAiB,MAAM,CAAC,MAAM,CAAC,gBAAgB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,GAAG;AACrF,oCAA4B;AAAA,MAC7B;AAAA,IACD;AAGA,QAAI,eAAe,KAAK,CAAC,MAAM,OAAO,YAAY,OAAO,EAAE,EAAE,CAAC,EAAG;AAEjE,WAAO,eAAe,gBAAgB,MAAM,EAAE;AAE9C,QAAI,2BAA2B;AAC9B,iBAAW,KAAK,kBAAkB;AACjC,eAAO,YAAY;AAAA,UAClB,IAAI,EAAE;AAAA,UACN,MAAM,EAAE;AAAA,UACR,OAAO,eAAe,IAAI,EAAE,EAAE;AAAA,QAC/B,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAES,gBACR,OACA,gBACA,MACO;AACP,UAAM,EAAE,OAAO,IAAI;AAGnB,QAAI,CAAC,KAAK,yBAAyB;AAElC,aAAO;AAAA,QACN,eAAe,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE;AAAA,QACpD,OAAO,iBAAiB;AAAA,MACzB;AAAA,IACD;AAAA,EACD;AACD;",
4
+ "sourcesContent": ["import { TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { IndexKey, compact } from '@tldraw/utils'\nimport { Vec } from '../../primitives/Vec'\nimport { BaseBoxShapeUtil, TLBaseBoxShape } from './BaseBoxShapeUtil'\nimport { TLDragShapesInInfo, TLDragShapesOutInfo } from './ShapeUtil'\n\n/**\n * A base class for frame-like shapes \u2014 containers that clip their children except arrows,\n * require full-brush selection, block erasure from inside, and support\n * drag-and-drop reparenting.\n *\n * Extending this class is the easiest way to create a custom frame-like shape.\n * It provides sensible defaults for all frame-like behaviors:\n *\n * - `isFrameLike()` returns `true`\n * - `providesBackgroundForChildren()` returns `true`\n * - `canReceiveNewChildrenOfType()` returns `true` unless the container is locked\n * - `canRemoveChildrenOfType()` returns `true` unless the container is locked\n * - `getClipPath()` returns the shape geometry's vertices\n * - `shouldClipChild()` clips all children except arrows\n * - `onDragShapesIn()` reparents shapes into the frame (with index restoration)\n * - `onDragShapesOut()` reparents shapes back to the page\n *\n * All methods can be overridden for custom behavior.\n *\n * @example\n * ```ts\n * class MyContainerUtil extends BaseFrameLikeShapeUtil<MyContainerShape> {\n * static override type = 'my-container' as const\n * static override props = myContainerShapeProps\n *\n * override getDefaultProps() {\n * return { w: 300, h: 200 }\n * }\n *\n * override component(shape: MyContainerShape) {\n * return <SVGContainer>...</SVGContainer>\n * }\n *\n * override getIndicatorPath(shape: MyContainerShape) {\n * const path = new Path2D()\n * path.rect(0, 0, shape.props.w, shape.props.h)\n * return path\n * }\n * }\n * ```\n *\n * @public\n */\nexport abstract class BaseFrameLikeShapeUtil<\n\tShape extends TLBaseBoxShape,\n> extends BaseBoxShapeUtil<Shape> {\n\toverride isFrameLike(_shape: Shape): boolean {\n\t\treturn true\n\t}\n\n\toverride providesBackgroundForChildren(): boolean {\n\t\treturn true\n\t}\n\n\toverride canReceiveNewChildrenOfType(shape: Shape, _type: TLShape['type']): boolean {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride canRemoveChildrenOfType(shape: Shape, _type: TLShape['type']): boolean {\n\t\treturn !shape.isLocked\n\t}\n\n\toverride getClipPath(shape: Shape): Vec[] | undefined {\n\t\treturn this.editor.getShapeGeometry(shape.id).vertices\n\t}\n\n\toverride shouldClipChild(child: TLShape): boolean {\n\t\treturn child.type !== 'arrow'\n\t}\n\n\toverride onDragShapesIn(\n\t\tshape: Shape,\n\t\tdraggingShapes: TLShape[],\n\t\t{ initialParentIds, initialIndices }: TLDragShapesInInfo\n\t): void {\n\t\tconst { editor } = this\n\n\t\tif (draggingShapes.every((s) => s.parentId === shape.id)) return\n\n\t\t// Check to see whether any of the shapes can have their old index restored\n\t\tlet canRestoreOriginalIndices = false\n\t\tconst previousChildren = draggingShapes.filter(\n\t\t\t(s) => shape.id === (initialParentIds.get(s.id) as TLShapeId)\n\t\t)\n\n\t\tif (previousChildren.length > 0) {\n\t\t\tconst currentChildren = compact(\n\t\t\t\teditor.getSortedChildIdsForParent(shape).map((id) => editor.getShape(id))\n\t\t\t)\n\t\t\tif (previousChildren.every((s) => !currentChildren.find((c) => c.index === s.index))) {\n\t\t\t\tcanRestoreOriginalIndices = true\n\t\t\t}\n\t\t}\n\n\t\t// If any of the children are the ancestor of the frame, quit here\n\t\tif (draggingShapes.some((s) => editor.hasAncestor(shape, s.id))) return\n\n\t\teditor.reparentShapes(draggingShapes, shape.id)\n\n\t\tif (canRestoreOriginalIndices) {\n\t\t\tfor (const s of previousChildren) {\n\t\t\t\teditor.updateShape({\n\t\t\t\t\tid: s.id,\n\t\t\t\t\ttype: s.type,\n\t\t\t\t\tindex: initialIndices.get(s.id) as IndexKey,\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\t}\n\n\toverride onDragShapesOut(\n\t\tshape: Shape,\n\t\tdraggingShapes: TLShape[],\n\t\tinfo: TLDragShapesOutInfo\n\t): void {\n\t\tconst { editor } = this\n\t\t// When a user drags shapes out and we're not dragging into a new shape,\n\t\t// reparent the dragging shapes onto the current page instead\n\t\tif (!info.nextDraggingOverShapeId) {\n\t\t\t// Locked shapes are already filtered out upstream by DragAndDropManager.\n\t\t\teditor.reparentShapes(\n\t\t\t\tdraggingShapes.filter((s) => s.parentId === shape.id),\n\t\t\t\teditor.getCurrentPageId()\n\t\t\t)\n\t\t}\n\t}\n}\n"],
5
+ "mappings": "AACA,SAAmB,eAAe;AAElC,SAAS,wBAAwC;AA8C1C,MAAe,+BAEZ,iBAAwB;AAAA,EACxB,YAAY,QAAwB;AAC5C,WAAO;AAAA,EACR;AAAA,EAES,gCAAyC;AACjD,WAAO;AAAA,EACR;AAAA,EAES,4BAA4B,OAAc,OAAiC;AACnF,WAAO,CAAC,MAAM;AAAA,EACf;AAAA,EAES,wBAAwB,OAAc,OAAiC;AAC/E,WAAO,CAAC,MAAM;AAAA,EACf;AAAA,EAES,YAAY,OAAiC;AACrD,WAAO,KAAK,OAAO,iBAAiB,MAAM,EAAE,EAAE;AAAA,EAC/C;AAAA,EAES,gBAAgB,OAAyB;AACjD,WAAO,MAAM,SAAS;AAAA,EACvB;AAAA,EAES,eACR,OACA,gBACA,EAAE,kBAAkB,eAAe,GAC5B;AACP,UAAM,EAAE,OAAO,IAAI;AAEnB,QAAI,eAAe,MAAM,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE,EAAG;AAG1D,QAAI,4BAA4B;AAChC,UAAM,mBAAmB,eAAe;AAAA,MACvC,CAAC,MAAM,MAAM,OAAQ,iBAAiB,IAAI,EAAE,EAAE;AAAA,IAC/C;AAEA,QAAI,iBAAiB,SAAS,GAAG;AAChC,YAAM,kBAAkB;AAAA,QACvB,OAAO,2BAA2B,KAAK,EAAE,IAAI,CAAC,OAAO,OAAO,SAAS,EAAE,CAAC;AAAA,MACzE;AACA,UAAI,iBAAiB,MAAM,CAAC,MAAM,CAAC,gBAAgB,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,CAAC,GAAG;AACrF,oCAA4B;AAAA,MAC7B;AAAA,IACD;AAGA,QAAI,eAAe,KAAK,CAAC,MAAM,OAAO,YAAY,OAAO,EAAE,EAAE,CAAC,EAAG;AAEjE,WAAO,eAAe,gBAAgB,MAAM,EAAE;AAE9C,QAAI,2BAA2B;AAC9B,iBAAW,KAAK,kBAAkB;AACjC,eAAO,YAAY;AAAA,UAClB,IAAI,EAAE;AAAA,UACN,MAAM,EAAE;AAAA,UACR,OAAO,eAAe,IAAI,EAAE,EAAE;AAAA,QAC/B,CAAC;AAAA,MACF;AAAA,IACD;AAAA,EACD;AAAA,EAES,gBACR,OACA,gBACA,MACO;AACP,UAAM,EAAE,OAAO,IAAI;AAGnB,QAAI,CAAC,KAAK,yBAAyB;AAElC,aAAO;AAAA,QACN,eAAe,OAAO,CAAC,MAAM,EAAE,aAAa,MAAM,EAAE;AAAA,QACpD,OAAO,iBAAiB;AAAA,MACzB;AAAA,IACD;AAAA,EACD;AACD;",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,8 @@
1
- const version = "5.3.0-canary.50fed61679d4";
1
+ const version = "5.3.0-canary.58df715967e7";
2
2
  const publishDates = {
3
3
  major: "2026-05-06T16:28:18.473Z",
4
- minor: "2026-07-02T09:23:18.538Z",
5
- patch: "2026-07-02T09:23:18.538Z"
4
+ minor: "2026-07-02T13:11:09.282Z",
5
+ patch: "2026-07-02T13:11:09.282Z"
6
6
  };
7
7
  export {
8
8
  publishDates,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.3.0-canary.50fed61679d4'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-02T09:23:18.538Z',\n\tpatch: '2026-07-02T09:23:18.538Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '5.3.0-canary.58df715967e7'\nexport const publishDates = {\n\tmajor: '2026-05-06T16:28:18.473Z',\n\tminor: '2026-07-02T13:11:09.282Z',\n\tpatch: '2026-07-02T13:11:09.282Z',\n}\n"],
5
5
  "mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tldraw/editor",
3
3
  "description": "tldraw infinite canvas SDK (editor).",
4
- "version": "5.3.0-canary.50fed61679d4",
4
+ "version": "5.3.0-canary.58df715967e7",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -49,12 +49,12 @@
49
49
  "@tiptap/core": "^3.12.1",
50
50
  "@tiptap/pm": "^3.12.1",
51
51
  "@tiptap/react": "^3.12.1",
52
- "@tldraw/state": "5.3.0-canary.50fed61679d4",
53
- "@tldraw/state-react": "5.3.0-canary.50fed61679d4",
54
- "@tldraw/store": "5.3.0-canary.50fed61679d4",
55
- "@tldraw/tlschema": "5.3.0-canary.50fed61679d4",
56
- "@tldraw/utils": "5.3.0-canary.50fed61679d4",
57
- "@tldraw/validate": "5.3.0-canary.50fed61679d4",
52
+ "@tldraw/state": "5.3.0-canary.58df715967e7",
53
+ "@tldraw/state-react": "5.3.0-canary.58df715967e7",
54
+ "@tldraw/store": "5.3.0-canary.58df715967e7",
55
+ "@tldraw/tlschema": "5.3.0-canary.58df715967e7",
56
+ "@tldraw/utils": "5.3.0-canary.58df715967e7",
57
+ "@tldraw/validate": "5.3.0-canary.58df715967e7",
58
58
  "classnames": "^2.5.1",
59
59
  "eventemitter3": "^4.0.7",
60
60
  "idb": "^7.1.1",
@@ -5,7 +5,7 @@ import { BaseBoxShapeUtil, TLBaseBoxShape } from './BaseBoxShapeUtil'
5
5
  import { TLDragShapesInInfo, TLDragShapesOutInfo } from './ShapeUtil'
6
6
 
7
7
  /**
8
- * A base class for frame-like shapes — containers that clip their children,
8
+ * A base class for frame-like shapes — containers that clip their children except arrows,
9
9
  * require full-brush selection, block erasure from inside, and support
10
10
  * drag-and-drop reparenting.
11
11
  *
@@ -17,6 +17,7 @@ import { TLDragShapesInInfo, TLDragShapesOutInfo } from './ShapeUtil'
17
17
  * - `canReceiveNewChildrenOfType()` returns `true` unless the container is locked
18
18
  * - `canRemoveChildrenOfType()` returns `true` unless the container is locked
19
19
  * - `getClipPath()` returns the shape geometry's vertices
20
+ * - `shouldClipChild()` clips all children except arrows
20
21
  * - `onDragShapesIn()` reparents shapes into the frame (with index restoration)
21
22
  * - `onDragShapesOut()` reparents shapes back to the page
22
23
  *
@@ -69,6 +70,10 @@ export abstract class BaseFrameLikeShapeUtil<
69
70
  return this.editor.getShapeGeometry(shape.id).vertices
70
71
  }
71
72
 
73
+ override shouldClipChild(child: TLShape): boolean {
74
+ return child.type !== 'arrow'
75
+ }
76
+
72
77
  override onDragShapesIn(
73
78
  shape: Shape,
74
79
  draggingShapes: TLShape[],
package/src/version.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  // This file is automatically generated by internal/scripts/refresh-assets.ts.
2
2
  // Do not edit manually. Or do, I'm a comment, not a cop.
3
3
 
4
- export const version = '5.3.0-canary.50fed61679d4'
4
+ export const version = '5.3.0-canary.58df715967e7'
5
5
  export const publishDates = {
6
6
  major: '2026-05-06T16:28:18.473Z',
7
- minor: '2026-07-02T09:23:18.538Z',
8
- patch: '2026-07-02T09:23:18.538Z',
7
+ minor: '2026-07-02T13:11:09.282Z',
8
+ patch: '2026-07-02T13:11:09.282Z',
9
9
  }