From 6bd7f4fcc97bbecda6785968c64c2814ea25452f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mitja=20Bezen=C5=A1ek?= Date: Tue, 19 Dec 2023 11:40:50 +0100 Subject: [PATCH] Allow dragging on top of locked shapes. (#2337) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR allows dragging a selection on top of a locked shape. This should work when clicking inside of the selection, but not directly on a shape. Before: https://github.com/tldraw/tldraw/assets/2523721/53583ae9-9ed7-455e-bdc4-ba13804dd8a3 After: https://github.com/tldraw/tldraw/assets/2523721/81d8f8bf-5474-4a09-abac-75059a089851 Fixes https://github.com/tldraw/tldraw/issues/2316 Fixes https://github.com/tldraw/tldraw/issues/2315 ### Change Type - [x] `patch` — Bug fix - [ ] `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 big shape and lock it. 2. Create two shapes on top of the locked shape and select them. 3. Start dragging the selected shapes by clicking inside the selection (but not directly on any of the shapes). This should allow you to translate the selection. 4. Should also work if the shapes are behind the locked shape. - [x] Unit Tests - [ ] End to end tests ### Release Notes - Allow translating of shapes on top of a locked shape by clicking inside of selection and moving the mouse. --- .../lib/tools/SelectTool/childStates/Idle.ts | 8 ++- .../tldraw/src/test/selection-omnibus.test.ts | 51 +++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/packages/tldraw/src/lib/tools/SelectTool/childStates/Idle.ts b/packages/tldraw/src/lib/tools/SelectTool/childStates/Idle.ts index d0ad97321..dab92daa9 100644 --- a/packages/tldraw/src/lib/tools/SelectTool/childStates/Idle.ts +++ b/packages/tldraw/src/lib/tools/SelectTool/childStates/Idle.ts @@ -57,7 +57,7 @@ export class Idle extends StateNode { // Check to see if we hit any shape under the pointer; if so, // handle this as a pointer down on the shape instead of the canvas const hitShape = getHitShapeOnCanvasPointerDown(this.editor) - if (hitShape) { + if (hitShape && !hitShape.isLocked) { this.onPointerDown({ ...info, shape: hitShape, @@ -140,7 +140,11 @@ export class Idle extends StateNode { } default: { const hoveredShape = this.editor.getHoveredShape() - if (hoveredShape && !this.editor.getSelectedShapeIds().includes(hoveredShape.id)) { + if ( + hoveredShape && + !this.editor.getSelectedShapeIds().includes(hoveredShape.id) && + !hoveredShape.isLocked + ) { this.onPointerDown({ ...info, shape: hoveredShape, diff --git a/packages/tldraw/src/test/selection-omnibus.test.ts b/packages/tldraw/src/test/selection-omnibus.test.ts index 7cf0c9feb..32cce8bea 100644 --- a/packages/tldraw/src/test/selection-omnibus.test.ts +++ b/packages/tldraw/src/test/selection-omnibus.test.ts @@ -1750,3 +1750,54 @@ describe('When brushing close to the edges of the screen', () => { editor.pointerUp() }) }) + +describe('When a shape is locked', () => { + beforeEach(() => { + editor.createShape({ + id: ids.box1, + type: 'geo', + x: 0, + y: 0, + isLocked: true, + props: { w: 300, h: 300 }, + }) + }) + + it('does not select the shape', () => { + editor.pointerDown(50, 50) + editor.expectToBeIn('select.pointing_canvas') + editor.pointerUp() + editor.expectToBeIn('select.idle') + expect(editor.getSelectedShapeIds()).toEqual([]) + }) + + it('allows translating shapes on top of the locked shape', () => { + editor.createShape({ id: ids.box2, x: 50, y: 50, type: 'geo', props: { w: 50, h: 50 } }) + editor.createShape({ id: ids.box3, x: 200, y: 200, type: 'geo', props: { w: 50, h: 50 } }) + + // Select the first shape + editor.pointerMove(60, 60) + editor.pointerDown() + editor.pointerUp() + expect(editor.getSelectedShapeIds()).toEqual([ids.box2]) + + // Shift select the second shape + editor.pointerMove(210, 210) + editor.keyDown('Shift') + editor.pointerDown() + editor.pointerUp() + editor.keyUp('Shift') + editor.expectToBeIn('select.idle') + expect(editor.getSelectedShapeIds()).toEqual([ids.box2, ids.box3]) + + // Click between them and start dragging + editor.pointerMove(150, 150) + editor.pointerDown() + editor.expectToBeIn('select.pointing_selection') + editor.pointerMove(100, 150) + editor.expectToBeIn('select.translating') + editor.pointerUp() + editor.expectToBeIn('select.idle') + expect(editor.getSelectedShapeIds()).toEqual([ids.box2, ids.box3]) + }) +})