Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix selection issues #6128

Merged
merged 16 commits into from
Jul 29, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ async function dragElement(
modifiers: Modifiers,
includeMouseUp: boolean,
midDragCallback?: () => Promise<void>,
mouseDownModifiers?: Modifiers,
): Promise<void> {
const targetElement = renderResult.renderedDOM.getByTestId(targetTestId)
const targetElementBounds = targetElement.getBoundingClientRect()
Expand All @@ -51,10 +52,11 @@ async function dragElement(
if (includeMouseUp) {
await mouseDragFromPointToPoint(canvasControlsLayer, startPoint, endPoint, {
modifiers: modifiers,
mouseDownModifiers: mouseDownModifiers,
midDragCallback: midDragCallback,
})
} else {
await mouseDownAtPoint(canvasControlsLayer, startPoint, { modifiers: modifiers })
await mouseDownAtPoint(canvasControlsLayer, startPoint)
await mouseMoveToPoint(canvasControlsLayer, endPoint, {
modifiers: modifiers,
eventOptions: { buttons: 1 },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ async function dragByPixels(
delta: WindowPoint,
testid: string,
modifiers: Modifiers = emptyModifiers,
mouseDownModifiers?: Modifiers,
) {
const targetElement = editor.renderedDOM.getByTestId(testid)
const targetElementBounds = targetElement.getBoundingClientRect()
Expand All @@ -60,6 +61,7 @@ async function dragByPixels(

await mouseDragFromPointWithDelta(canvasControlsLayer, targetElementCenter, delta, {
modifiers,
mouseDownModifiers,
midDragCallback: async () => {
NO_OP()
},
Expand All @@ -72,8 +74,9 @@ async function dragElement(
dragDelta: WindowPoint,
modifiers: Modifiers,
midDragCallback?: () => Promise<void>,
mouseDownModifiers?: Modifiers,
): Promise<void> {
await mouseDownAtPoint(canvasControlsLayer, startPoint, { modifiers: cmdModifier })
await mouseDownAtPoint(canvasControlsLayer, startPoint, { modifiers: mouseDownModifiers })
await mouseDragFromPointWithDelta(canvasControlsLayer, startPoint, dragDelta, {
modifiers,
midDragCallback,
Expand Down Expand Up @@ -316,7 +319,7 @@ describe('Absolute Move Strategy', () => {

await selectComponentsForTest(editor, [targetElement])

await dragByPixels(editor, windowPoint({ x: 15, y: 15 }), 'bbb', cmdModifier)
await dragByPixels(editor, windowPoint({ x: 15, y: 15 }), 'bbb')

expect(getPrintedUiJsCode(editor.getEditorState())).toEqual(
makeTestProjectCodeWithSnippet(
Expand Down Expand Up @@ -947,8 +950,6 @@ describe('Absolute Move Strategy', () => {
EP.fromString(`${BakedInStoryboardUID}/${TestSceneUID}/${TestAppUID}:aaa/bbb/ccc`),
])

// await wait(10000)

await dragByPixels(editor, windowPoint({ x: 15, y: 15 }), 'bbb')

expect(getPrintedUiJsCode(editor.getEditorState())).toEqual(
Expand Down Expand Up @@ -1215,7 +1216,14 @@ describe('Absolute Move Strategy', () => {
const startPoint = windowPoint({ x: targetElementBounds.x + 5, y: targetElementBounds.y + 5 })
const dragDelta = windowPoint({ x: 40, y: 25 })

await dragElement(canvasControlsLayer, startPoint, dragDelta, emptyModifiers)
await dragElement(
canvasControlsLayer,
startPoint,
dragDelta,
cmdModifier,
undefined,
cmdModifier,
)

await renderResult.getDispatchFollowUpActionsFinished()
expect(getPrintedUiJsCode(renderResult.getEditorState())).toEqual(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ async function dragElement(
modifiers: Modifiers,
checkCursor: CheckCursor | null,
midDragCallback: (() => Promise<void>) | null,
mouseDownModifiers?: Modifiers,
) {
const targetElement = renderResult.renderedDOM.getByTestId(targetTestId)
const targetElementBounds = targetElement.getBoundingClientRect()
Expand All @@ -90,6 +91,7 @@ async function dragElement(
await mouseClickAtPoint(canvasControlsLayer, startPoint, { modifiers: cmdModifier })
await mouseDragFromPointWithDelta(canvasControlsLayer, startPoint, dragDelta, {
modifiers: modifiers,
mouseDownModifiers: mouseDownModifiers,
midDragCallback: combinedMidDragCallback,
})
}
Expand Down Expand Up @@ -1325,7 +1327,15 @@ export var ${BakedInStoryboardVariableName} = (props) => {
)

const dragDelta = windowPoint({ x: 50, y: 0 })
await dragElement(renderResult, 'child-1', dragDelta, cmdModifier, null, null)
await dragElement(
renderResult,
'child-1',
dragDelta,
cmdModifier,
null,
null,
cmdModifier,
)

await renderResult.getDispatchFollowUpActionsFinished()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
import { selectComponentsForTest } from '../../../../utils/utils.test-utils'
import { ConvertToAbsoluteAndMoveStrategyID } from './convert-to-absolute-and-move-strategy'
import CanvasActions from '../../canvas-actions'
import { ctrlModifier } from '../../../../utils/modifiers'

const complexProject = () => {
const code = `
Expand Down Expand Up @@ -1140,12 +1141,7 @@ describe('Convert to absolute/escape hatch', () => {
y: elementBounds.y + 10,
},
{
modifiers: {
alt: false,
cmd: true,
ctrl: true,
shift: false,
},
modifiers: ctrlModifier,
},
)

Expand Down Expand Up @@ -1805,12 +1801,7 @@ describe('Escape hatch strategy on awkward project', () => {
y: 15,
},
{
modifiers: {
alt: false,
cmd: true,
ctrl: true,
shift: false,
},
modifiers: ctrlModifier,
},
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ function getCandidateSelectableViews(
export function useFindValidTarget(): (
selectableViews: Array<ElementPath>,
mousePoint: WindowPoint | null,
preferAlreadySelected: 'prefer-selected' | 'dont-prefer-selected',
preferAlreadySelected: 'prefer-selected' | 'prefer-more-specific-selection',
) => {
elementPath: ElementPath
isSelected: boolean
Expand All @@ -325,7 +325,7 @@ export function useFindValidTarget(): (
(
selectableViews: Array<ElementPath>,
mousePoint: WindowPoint | null,
preferAlreadySelected: 'prefer-selected' | 'dont-prefer-selected',
preferAlreadySelected: 'prefer-selected' | 'prefer-more-specific-selection',
) => {
const {
selectedViews,
Expand All @@ -336,26 +336,43 @@ export function useFindValidTarget(): (
elementPathTree,
allElementProps,
} = storeRef.current
const validElementMouseOver: ElementPath | null =
preferAlreadySelected === 'prefer-selected'
? getSelectionOrValidTargetAtPoint(
componentMetadata,
selectedViews,
hiddenInstances,
selectableViews,
mousePoint,
canvasScale,
canvasOffset,
elementPathTree,
allElementProps,
)
: getValidTargetAtPoint(
selectableViews,
mousePoint,
canvasScale,
canvasOffset,
componentMetadata,
)
const validElementMouseOver: ElementPath | null = (() => {
if (preferAlreadySelected === 'prefer-selected') {
return getSelectionOrValidTargetAtPoint(
componentMetadata,
selectedViews,
hiddenInstances,
selectableViews,
mousePoint,
canvasScale,
canvasOffset,
elementPathTree,
allElementProps,
)
}
const newSelection = getValidTargetAtPoint(
selectableViews,
mousePoint,
canvasScale,
canvasOffset,
componentMetadata,
)
if (newSelection != null) {
return newSelection
}
return getSelectionOrValidTargetAtPoint(
componentMetadata,
selectedViews,
hiddenInstances,
selectableViews,
mousePoint,
canvasScale,
canvasOffset,
elementPathTree,
allElementProps,
)
})()

const validElementPath: ElementPath | null =
validElementMouseOver != null ? validElementMouseOver : null
if (validElementPath != null) {
Expand Down Expand Up @@ -452,7 +469,11 @@ export function useCalculateHighlightedViews(
return React.useCallback(
(targetPoint: WindowPoint, eventCmdPressed: boolean) => {
const selectableViews: Array<ElementPath> = getHighlightableViews(eventCmdPressed, false)
const validElementPath = findValidTarget(selectableViews, targetPoint, 'dont-prefer-selected')
const validElementPath = findValidTarget(
selectableViews,
targetPoint,
'prefer-more-specific-selection',
)
const validElementPathForHover = findValidTarget(
selectableViews,
targetPoint,
Expand Down Expand Up @@ -528,14 +549,15 @@ export function useHighlightCallbacks(
function getPreferredSelectionForEvent(
eventType: 'mousedown' | 'mouseup' | string,
isDoubleClick: boolean,
): 'prefer-selected' | 'dont-prefer-selected' {
cmdModifier: boolean,
): 'prefer-selected' | 'prefer-more-specific-selection' {
// mousedown keeps selection on a single click to allow dragging overlapping elements and selection happens on mouseup
// with continuous clicking mousedown should select
switch (eventType) {
case 'mousedown':
return isDoubleClick ? 'dont-prefer-selected' : 'prefer-selected'
return isDoubleClick || cmdModifier ? 'prefer-more-specific-selection' : 'prefer-selected'
case 'mouseup':
return isDoubleClick ? 'prefer-selected' : 'dont-prefer-selected'
return isDoubleClick ? 'prefer-selected' : 'prefer-more-specific-selection'
default:
return 'prefer-selected'
}
Expand All @@ -561,6 +583,7 @@ function useSelectOrLiveModeSelectAndHover(
)
const windowToCanvasCoordinates = useWindowToCanvasCoordinates()
const interactionSessionHappened = React.useRef(false)
const draggedOverThreshold = React.useRef(false)
const didWeHandleMouseDown = React.useRef(false) // this is here to avoid selecting when closing text editing

const { onMouseMove: innerOnMouseMove } = useHighlightCallbacks(
Expand All @@ -582,6 +605,14 @@ function useSelectOrLiveModeSelectAndHover(
editorStoreRef.current.editor.canvas.interactionSession,
editorStoreRef.current.editor.keysPressed['space'],
) || event.buttons === 4

const draggingOverThreshold =
editorStoreRef.current.editor.canvas.interactionSession?.interactionData?.type === 'DRAG'
? editorStoreRef.current.editor.canvas.interactionSession?.interactionData?.drag != null
: false

draggedOverThreshold.current = draggedOverThreshold.current || draggingOverThreshold

if (isDragIntention) {
return
}
Expand All @@ -601,20 +632,23 @@ function useSelectOrLiveModeSelectAndHover(
(event: React.MouseEvent<HTMLDivElement>) => {
const isLeftClick = event.button === 0
const isRightClick = event.type === 'contextmenu' && event.detail === 0
const isDragIntention =
const isCanvasPanIntention =
editorStoreRef.current.editor.keysPressed['space'] || event.button === 1
const hasInteractionSessionWithMouseMoved =

const draggingOverThreshold =
editorStoreRef.current.editor.canvas.interactionSession?.interactionData?.type === 'DRAG'
? editorStoreRef.current.editor.canvas.interactionSession?.interactionData?.drag != null
: false

const hasInteractionSession = editorStoreRef.current.editor.canvas.interactionSession != null
const hadInteractionSessionThatWasCancelled =
interactionSessionHappened.current && !hasInteractionSession

const activeControl = editorStoreRef.current.editor.canvas.interactionSession?.activeControl

const mouseUpSelectionAllowed =
didWeHandleMouseDown.current &&
!hadInteractionSessionThatWasCancelled &&
(!hadInteractionSessionThatWasCancelled || !draggedOverThreshold.current) &&
(activeControl == null || activeControl.type === 'BOUNDING_AREA')

if (event.type === 'mousedown') {
Expand All @@ -625,6 +659,7 @@ function useSelectOrLiveModeSelectAndHover(
interactionSessionHappened.current = false
// didWeHandleMouseDown is used to avoid selecting when closing text editing
didWeHandleMouseDown.current = false
draggedOverThreshold.current = false

if (!mouseUpSelectionAllowed) {
// We should skip this mouseup
Expand All @@ -633,8 +668,8 @@ function useSelectOrLiveModeSelectAndHover(
}

if (
isDragIntention ||
hasInteractionSessionWithMouseMoved ||
isCanvasPanIntention ||
draggingOverThreshold ||
!active ||
!(isLeftClick || isRightClick)
) {
Expand All @@ -643,8 +678,13 @@ function useSelectOrLiveModeSelectAndHover(
}

const doubleClick = event.type === 'mousedown' && event.detail > 0 && event.detail % 2 === 0
const cmdMouseDown = event.type === 'mousedown' && event.metaKey
const selectableViews = getSelectableViewsForSelectMode(event.metaKey, doubleClick)
const preferAlreadySelected = getPreferredSelectionForEvent(event.type, doubleClick)
const preferAlreadySelected = getPreferredSelectionForEvent(
event.type,
doubleClick,
event.metaKey,
)
const foundTarget = findValidTarget(
selectableViews,
windowPoint(point(event.clientX, event.clientY)),
Expand All @@ -658,7 +698,7 @@ function useSelectOrLiveModeSelectAndHover(
if (foundTarget != null || isDeselect) {
if (
event.button !== 2 &&
event.type !== 'mouseup' &&
(event.type !== 'mouseup' || cmdMouseDown) &&
foundTarget != null &&
draggingAllowed &&
// grid has its own drag handling
Expand Down
Loading
Loading