[fix] restore bg option, fix calculations (#1765)

This PR fixes a bug introduced with #1751 where pointing the bounds of
rotated selections would not correctly hit the bounds background.

### Change Type

- [x] `patch` — Bug fix

### Test Plan

1. Create a rotated selection.
2. Point into the bounds background

- [x] Unit Tests
This commit is contained in:
Steve Ruiz 2023-07-26 16:32:33 +01:00 committed by GitHub
parent 56cf77a8cd
commit 28b92c5e76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 114 additions and 22 deletions

View file

@ -1736,6 +1736,7 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
getOutlineSegments(shape: Shape): Vec2d[][];
hideResizeHandles: TLShapeUtilFlag<Shape>;
hideRotateHandle: TLShapeUtilFlag<Shape>;
hideSelectionBoundsBg: TLShapeUtilFlag<Shape>;
hideSelectionBoundsFg: TLShapeUtilFlag<Shape>;
abstract indicator(shape: Shape): any;
isAspectRatioLocked: TLShapeUtilFlag<Shape>;

View file

@ -149,6 +149,13 @@ export abstract class ShapeUtil<Shape extends TLUnknownShape = TLUnknownShape> {
*/
hideRotateHandle: TLShapeUtilFlag<Shape> = () => false
/**
* Whether the shape should hide its selection bounds background when selected.
*
* @public
*/
hideSelectionBoundsBg: TLShapeUtilFlag<Shape> = () => false
/**
* Whether the shape should hide its selection bounds foreground when selected.
*

View file

@ -99,14 +99,11 @@ export const TldrawSelectionForeground: TLSelectionForegroundComponent = track(
onlyShape &&
editor.isShapeOfType<TLTextShape>(onlyShape, 'text'))
if (
onlyShape &&
editor.isShapeOfType<TLEmbedShape>(onlyShape, 'embed') &&
shouldDisplayBox &&
IS_FIREFOX
) {
if (onlyShape && shouldDisplayBox) {
if (IS_FIREFOX && editor.isShapeOfType<TLEmbedShape>(onlyShape, 'embed')) {
shouldDisplayBox = false
}
}
const showCropHandles =
editor.isInAny(

View file

@ -64,6 +64,7 @@ export class ArrowShapeUtil extends ShapeUtil<TLArrowShape> {
override canSnap = () => true
override hideResizeHandles: TLShapeUtilFlag<TLArrowShape> = () => true
override hideRotateHandle: TLShapeUtilFlag<TLArrowShape> = () => true
override hideSelectionBoundsBg: TLShapeUtilFlag<TLArrowShape> = () => true
override hideSelectionBoundsFg: TLShapeUtilFlag<TLArrowShape> = () => true
override getDefaultProps(): TLArrowShape['props'] {

View file

@ -1,4 +1,5 @@
import {
Editor,
HIT_TEST_MARGIN,
StateNode,
TLClickEventInfo,
@ -8,7 +9,9 @@ import {
TLShape,
TLTextShape,
Vec2d,
VecLike,
createShapeId,
pointInPolygon,
} from '@tldraw/editor'
import { getHitShapeOnCanvasPointerDown } from '../../selection-logic/getHitShapeOnCanvasPointerDown'
import { getShouldEnterCropMode } from '../../selection-logic/getShouldEnterCropModeOnPointerDown'
@ -60,18 +63,17 @@ export class Idle extends StateNode {
}
const {
onlySelectedShape,
selectedShapeIds,
inputs: { currentPagePoint },
} = this.editor
if (selectedShapeIds.length > 0) {
// If there's only one shape selected, and if that shape's
// geometry is open, then don't test the selection background
if (
selectedShapeIds.length > 1 ||
this.editor.getGeometry(selectedShapeIds[0]).isClosed
(onlySelectedShape &&
!this.editor.getShapeUtil(onlySelectedShape).hideSelectionBoundsBg(onlySelectedShape))
) {
if (this.editor.selectionBounds?.containsPoint(currentPagePoint)) {
if (isPointInRotatedSelectionBounds(this.editor, currentPagePoint)) {
this.onPointerDown({
...info,
target: 'selection',
@ -79,7 +81,6 @@ export class Idle extends StateNode {
return
}
}
}
this.parent.transition('pointing_canvas', info)
break
@ -511,3 +512,16 @@ export class Idle extends StateNode {
export const MAJOR_NUDGE_FACTOR = 10
export const MINOR_NUDGE_FACTOR = 1
export const GRID_INCREMENT = 5
function isPointInRotatedSelectionBounds(editor: Editor, point: VecLike) {
const { selectionBounds } = editor
if (!selectionBounds) return false
const { selectionRotation } = editor
if (!selectionRotation) return selectionBounds.containsPoint(point)
return pointInPolygon(
point,
selectionBounds.corners.map((c) => Vec2d.RotWith(c, selectionBounds.point, selectionRotation))
)
}

View file

@ -69,7 +69,11 @@ export function selectOnCanvasPointerUp(editor: Editor) {
} else {
// Otherwise, we clear the selction because the user selected
// nothing instead of their current selection.
if (selectedShapeIds.length > 0) {
editor.mark('selecting none')
editor.selectNone()
}
// If the click was inside of the current focused group, then
// we keep that focused group; otherwise we clear the focused

View file

@ -195,6 +195,74 @@ describe('when shape is hollow', () => {
editor.pointerUp()
expect(editor.selectedShapeIds).toEqual([])
})
it('drags draw shape child', () => {
editor
.selectAll()
.deleteShapes(editor.selectedShapeIds)
.setCurrentTool('draw')
.pointerMove(500, 500)
.pointerDown()
.pointerMove(501, 501)
.pointerMove(550, 550)
.pointerMove(599, 599)
.pointerMove(600, 600)
.pointerUp()
.selectAll()
.setCurrentTool('select')
expect(editor.selectedShapeIds.length).toBe(1)
// Not inside of the shape but inside of the selection bounds
editor.pointerMove(510, 590)
expect(editor.hoveredShapeId).toBe(null)
// Draw shapes have `hideSelectionBoundsBg` set to false
editor.pointerDown()
editor.expectToBeIn('select.pointing_selection')
editor.pointerUp()
editor.selectAll()
editor.rotateSelection(Math.PI)
editor.setCurrentTool('select')
editor.pointerMove(590, 510)
editor.pointerDown()
editor.expectToBeIn('select.pointing_selection')
editor.pointerUp()
})
it('does not drag arrow shape', () => {
editor
.selectAll()
.deleteShapes(editor.selectedShapeIds)
.setCurrentTool('arrow')
.pointerMove(500, 500)
.pointerDown()
.pointerMove(600, 600)
.pointerUp()
.selectAll()
.setCurrentTool('select')
expect(editor.selectedShapeIds.length).toBe(1)
// Not inside of the shape but inside of the selection bounds
editor.pointerMove(510, 590)
expect(editor.hoveredShapeId).toBe(null)
// Arrow shapes have `hideSelectionBoundsBg` set to true
editor.pointerDown()
editor.expectToBeIn('select.pointing_canvas')
editor.selectAll()
editor.rotateSelection(Math.PI)
editor.setCurrentTool('select')
editor.pointerMove(590, 510)
editor.pointerDown()
editor.expectToBeIn('select.pointing_canvas')
editor.pointerUp()
})
})
describe('when shape is a frame', () => {