From be927df93555f757d33342d6a788a3e22da86a1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mitja=20Bezen=C5=A1ek?= Date: Fri, 19 Jan 2024 16:17:33 +0100 Subject: [PATCH] Allow snapping of shapes to the frame when dragging inside the frame. (#2520) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows you to snap to frames when dragging inside them. https://github.com/tldraw/tldraw/assets/2523721/41816b9b-5969-416d-af15-77b8f102ad21 Resolves #2471 ### Change Type - [ ] `patch` — Bug fix - [x] `minor` — New feature - [ ] `major` — Breaking change - [ ] `dependencies` — Changes to package dependencies[^1] - [ ] `documentation` — Changes to the documentation only[^2] - [ ] `tests` — Changes to any test code only[^2] - [ ] `internal` — Any other changes that don't affect the published package[^2] - [ ] I don't know [^1]: publishes a `patch` release, for devDependencies use `internal` [^2]: will not publish a new version ### Test Plan 1. Create a frame. 2. Add some shape inside. 3. Drag the shapes while holding `cmd` or turning on always snap. You should be able to snap to the edges and the centre of the frame. - [ ] Unit Tests - [ ] End to end tests ### Release Notes - Adds snapping to frames when dragging shapes inside a frame. --- .../src/lib/editor/managers/SnapManager.ts | 20 ++++++++++++++++++- packages/tldraw/src/test/frames.test.ts | 11 ++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/editor/src/lib/editor/managers/SnapManager.ts b/packages/editor/src/lib/editor/managers/SnapManager.ts index 01954176e..179c6a85a 100644 --- a/packages/editor/src/lib/editor/managers/SnapManager.ts +++ b/packages/editor/src/lib/editor/managers/SnapManager.ts @@ -1,5 +1,13 @@ import { atom, computed, EMPTY_ARRAY } from '@tldraw/state' -import { TLGroupShape, TLParentId, TLShape, TLShapeId, VecModel } from '@tldraw/tlschema' +import { + isShapeId, + TLFrameShape, + TLGroupShape, + TLParentId, + TLShape, + TLShapeId, + VecModel, +} from '@tldraw/tlschema' import { dedupe, deepCopy } from '@tldraw/utils' import { Box, @@ -244,6 +252,16 @@ export class SnapManager { const snappableShapes: GapNode[] = [] const collectSnappableShapesFromParent = (parentId: TLParentId) => { + if (isShapeId(parentId)) { + const parent = editor.getShape(parentId) + if (parent && editor.isShapeOfType(parent, 'frame')) { + snappableShapes.push({ + id: parentId, + pageBounds: editor.getShapePageBounds(parentId)!, + isClosed: editor.getShapeGeometry(parent).isClosed, + }) + } + } const sortedChildIds = editor.getSortedChildIdsForParent(parentId) for (const childId of sortedChildIds) { // Skip any selected ids diff --git a/packages/tldraw/src/test/frames.test.ts b/packages/tldraw/src/test/frames.test.ts index b4d4a71b3..7b58fdfb1 100644 --- a/packages/tldraw/src/test/frames.test.ts +++ b/packages/tldraw/src/test/frames.test.ts @@ -492,12 +492,19 @@ describe('frame shapes', () => { editor.setCurrentTool('select') editor.pointerDown(150, 150, innerBoxId).pointerMove(150, 50).pointerMove(150, 148) editor.keyDown('Control') - expect(editor.snaps.getLines()).toHaveLength(0) + let shapes = editor.snaps.getSnappableShapes() + // We can snap to the parent frame + expect(shapes).toHaveLength(1) + expect(shapes[0].id).toBe(frameId) // move shape inside the frame to make sure it snaps in there editor.reparentShapes([outerBoxId], frameId).pointerMove(150, 149, { ctrlKey: true }) - expect(editor.snaps.getLines()).toHaveLength(1) + shapes = editor.snaps.getSnappableShapes() + expect(shapes).toHaveLength(2) + const ids = new Set(shapes.map((s) => s.id)) + expect(ids).toContain(frameId) + expect(ids).toContain(outerBoxId) }) it('masks its children', () => {