diff --git a/packages/editor/api-report.md b/packages/editor/api-report.md index 1baf1891b..3ed30089a 100644 --- a/packages/editor/api-report.md +++ b/packages/editor/api-report.md @@ -1602,6 +1602,8 @@ export abstract class ShapeUtil { canSnap: TLShapeUtilFlag; canUnmount: TLShapeUtilFlag; abstract component(shape: Shape): any; + // @internal + doesAutoSnap: TLShapeUtilFlag; // (undocumented) editor: Editor; // @internal (undocumented) diff --git a/packages/editor/src/lib/editor/shapes/ShapeUtil.ts b/packages/editor/src/lib/editor/shapes/ShapeUtil.ts index 1e4d13f4f..67b45fced 100644 --- a/packages/editor/src/lib/editor/shapes/ShapeUtil.ts +++ b/packages/editor/src/lib/editor/shapes/ShapeUtil.ts @@ -131,6 +131,13 @@ export abstract class ShapeUtil { */ canCrop: TLShapeUtilFlag = () => false + /** + * Whether the shape auto-snaps when translated or resized. + * + * @internal + */ + doesAutoSnap: TLShapeUtilFlag = () => false + /** * Does this shape provide a background for its children? If this is true, * then any children with a `renderBackground` method will have their diff --git a/packages/tldraw/api-report.md b/packages/tldraw/api-report.md index 6638e124e..5ab87f8f6 100644 --- a/packages/tldraw/api-report.md +++ b/packages/tldraw/api-report.md @@ -1028,6 +1028,8 @@ export class NoteShapeUtil extends ShapeUtil { // (undocumented) component(shape: TLNoteShape): JSX_2.Element; // (undocumented) + doesAutoSnap: () => boolean; + // (undocumented) getDefaultProps(): TLNoteShape['props']; // (undocumented) getGeometry(shape: TLNoteShape): Rectangle2d; diff --git a/packages/tldraw/api/api.json b/packages/tldraw/api/api.json index f32afb13a..6b903c869 100644 --- a/packages/tldraw/api/api.json +++ b/packages/tldraw/api/api.json @@ -12239,6 +12239,36 @@ "isAbstract": false, "name": "component" }, + { + "kind": "Property", + "canonicalReference": "tldraw!NoteShapeUtil#doesAutoSnap:member", + "docComment": "", + "excerptTokens": [ + { + "kind": "Content", + "text": "doesAutoSnap: " + }, + { + "kind": "Content", + "text": "() => boolean" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isReadonly": false, + "isOptional": false, + "releaseTag": "Public", + "name": "doesAutoSnap", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isStatic": false, + "isProtected": false, + "isAbstract": false + }, { "kind": "Method", "canonicalReference": "tldraw!NoteShapeUtil#getDefaultProps:member(1)", diff --git a/packages/tldraw/src/lib/shapes/note/NoteShapeUtil.tsx b/packages/tldraw/src/lib/shapes/note/NoteShapeUtil.tsx index d4446a94b..107c3824f 100644 --- a/packages/tldraw/src/lib/shapes/note/NoteShapeUtil.tsx +++ b/packages/tldraw/src/lib/shapes/note/NoteShapeUtil.tsx @@ -27,6 +27,7 @@ export class NoteShapeUtil extends ShapeUtil { static override migrations = noteShapeMigrations override canEdit = () => true + override doesAutoSnap = () => true override hideResizeHandles = () => true override hideSelectionBoundsFg = () => true diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Resizing.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Resizing.ts index 6c9a76280..4566a175f 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Resizing.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Resizing.ts @@ -234,7 +234,14 @@ export class Resizing extends StateNode { this.editor.snaps.clearIndicators() - const shouldSnap = this.editor.user.getIsSnapMode() ? !ctrlKey : ctrlKey + const onlySelectedShape = this.editor.getOnlySelectedShape() + const shouldSnap = + this.editor.user.getIsSnapMode() || + (onlySelectedShape && this.editor.getShapeUtil(onlySelectedShape))?.doesAutoSnap( + onlySelectedShape + ) + ? !ctrlKey + : ctrlKey if (shouldSnap && selectionRotation % HALF_PI === 0) { const { nudge } = this.editor.snaps.shapeBounds.snapResizeShapes({ diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts index 2952c3857..28c94543a 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Translating.ts @@ -398,10 +398,13 @@ export function moveShapesToPoint({ // Provisional snapping editor.snaps.clearIndicators() + const onlySelectedShape = editor.getOnlySelectedShape() const shouldSnap = - (editor.user.getIsSnapMode() ? !inputs.ctrlKey : inputs.ctrlKey) && - editor.inputs.pointerVelocity.len() < 0.5 // ...and if the user is not dragging fast + (editor.user.getIsSnapMode() || + (onlySelectedShape && editor.getShapeUtil(onlySelectedShape))?.doesAutoSnap(onlySelectedShape) + ? !inputs.ctrlKey + : inputs.ctrlKey) && editor.inputs.pointerVelocity.len() < 0.5 // ...and if the user is not dragging fast if (shouldSnap) { const { nudge } = editor.snaps.shapeBounds.snapTranslateShapes({