From 1c08c1bbb3467268e9ff8770372fbba5ec6e3863 Mon Sep 17 00:00:00 2001 From: Gray Crawford Date: Mon, 2 Mar 2026 09:31:34 -0800 Subject: [PATCH 1/4] Dragging on frame body always moves the frame Made-with: Cursor --- .../src/lib/tools/SelectTool/childStates/PointingShape.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts index 75c90a96572f..701e54552fd8 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts @@ -231,9 +231,6 @@ export class PointingShape extends StateNode { if (this.didCtrlOnEnter) { this.parent.transition('brushing', info) - } else if (this.didSelectOnEnter && (this.hitShape as any).type === 'grid' && !this.didHitGridLabel) { - this.editor.setSelectedShapes([]) - this.parent.transition('brushing', { ...info, target: 'canvas' as const }) } else { this.startTranslating(info) } From 5fa99b94580248df57016111aac778b108835c91 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 2 Mar 2026 17:37:59 +0000 Subject: [PATCH 2/4] Remove unused didHitGridLabel property and grid label detection logic --- .../SelectTool/childStates/PointingShape.ts | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts index 701e54552fd8..79446240077d 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/PointingShape.ts @@ -1,4 +1,4 @@ -import { Group2d, StateNode, TLPointerEventInfo, TLShape } from '@tldraw/editor' +import { StateNode, TLPointerEventInfo, TLShape } from '@tldraw/editor' import { isOverArrowLabel } from '../../../shapes/arrow/arrowLabel' import { getTextLabels } from '../../../utils/shapes/shapes' @@ -11,7 +11,6 @@ export class PointingShape extends StateNode { didCtrlOnEnter = false didSelectOnEnter = false - didHitGridLabel = false override onEnter(info: TLPointerEventInfo & { target: 'shape' }) { const selectedShapeIds = this.editor.getSelectedShapeIds() @@ -23,19 +22,6 @@ export class PointingShape extends StateNode { this.hitShape = info.shape this.isDoubleClick = false this.didCtrlOnEnter = accelKey - this.didHitGridLabel = false - if ((info.shape as any).type === 'grid') { - const geometry = this.editor.getShapeGeometry(info.shape) - if (geometry instanceof Group2d) { - const pointInShapeSpace = this.editor.getPointInShapeSpace(info.shape, currentPagePoint) - for (const child of geometry.children) { - if (child.isLabel && child.isPointInBounds(pointInShapeSpace)) { - this.didHitGridLabel = true - break - } - } - } - } const outermostSelectingShape = this.editor.getOutermostSelectableShape(info.shape) const selectedAncestor = this.editor.findShapeAncestor(outermostSelectingShape, (parent) => selectedShapeIds.includes(parent.id) From 411e4c69c3a7673f5ff27621279eeba2ab0bd082 Mon Sep 17 00:00:00 2001 From: Gray Crawford Date: Mon, 2 Mar 2026 10:31:05 -0800 Subject: [PATCH 3/4] Cmd+drag uses intersection selection, same as normal drag (#12) Removes the isWrapping check so Cmd/Ctrl+drag selects assets by intersection instead of requiring full enclosure. Only frames still require full enclosure regardless of modifier keys. Made-with: Cursor --- .../tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts index a3bc67bd6788..f078748177fd 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Brushing.ts @@ -194,7 +194,7 @@ export class Brushing extends StateNode { // If we're in wrap mode and the brush did not fully encloses the shape, it's a miss // We also skip frames unless we've completely selected the frame. - if (isWrapping || editor.isShapeFrame(shape)) { + if (editor.isShapeFrame(shape)) { continue testAllShapes } From 817770e1896ff3dc77e187a1d14fca6dd09fb5d6 Mon Sep 17 00:00:00 2001 From: Kazuho Okui Date: Mon, 2 Mar 2026 09:45:57 -0800 Subject: [PATCH 4/4] Remove unnecessary workaround --- packages/editor/src/lib/editor/Editor.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/editor/src/lib/editor/Editor.ts b/packages/editor/src/lib/editor/Editor.ts index 43e1a5031ab5..2f4855c3d3f4 100644 --- a/packages/editor/src/lib/editor/Editor.ts +++ b/packages/editor/src/lib/editor/Editor.ts @@ -5330,19 +5330,17 @@ export class Editor extends EventEmitter { } } - if (this.isShapeFrame(shape)) { + if (this.isShapeOfType(shape, 'frame')) { // On the rare case that we've hit a frame (not its label), test again hitInside to be forced true; // this prevents clicks from passing through the body of a frame to shapes behind it. // If the hit is within the frame's outer margin, then select the frame const distance = geometry.distanceToPoint(pointInShapeSpace, hitFrameInside) - const isGrid = (shape as any).type === 'grid' if ( - !isGrid && - (hitFrameInside + hitFrameInside ? (distance > 0 && distance <= outerMargin) || (distance <= 0 && distance > -innerMargin) - : distance > 0 && distance <= outerMargin) + : distance > 0 && distance <= outerMargin ) { return inMarginClosestToEdgeHit || shape } @@ -5357,7 +5355,7 @@ export class Editor extends EventEmitter { return ( inMarginClosestToEdgeHit || inHollowSmallestAreaHit || - (hitFrameInside || isGrid ? shape : undefined) + (hitFrameInside ? shape : undefined) ) } continue