Allow dragging on top of locked shapes. (#2337)

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.
This commit is contained in:
Mitja Bezenšek 2023-12-19 11:40:50 +01:00 committed by GitHub
parent ded56e953a
commit 6bd7f4fcc9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 2 deletions

View file

@ -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,

View file

@ -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])
})
})