alternative: drag after selection on PCs

This commit is contained in:
Ryan Di
2025-07-18 10:11:25 +10:00
parent 85dc55c718
commit 9b644169ae
2 changed files with 23 additions and 27 deletions

View File

@ -6028,7 +6028,7 @@ class App extends React.Component<AppProps, AppState> {
if ( if (
hasDeselectedButton || hasDeselectedButton ||
(this.state.activeTool.type !== "selection" && (this.state.activeTool.type !== "selection" &&
(this.state.activeTool.type !== "lasso" || !this.isMobileOrTablet()) && this.state.activeTool.type !== "lasso" &&
this.state.activeTool.type !== "text" && this.state.activeTool.type !== "text" &&
this.state.activeTool.type !== "eraser") this.state.activeTool.type !== "eraser")
) { ) {
@ -6202,7 +6202,7 @@ class App extends React.Component<AppProps, AppState> {
) { ) {
if ( if (
this.state.activeTool.type !== "lasso" || this.state.activeTool.type !== "lasso" ||
(selectedElements.length > 0 && this.isMobileOrTablet()) selectedElements.length > 0
) { ) {
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE); setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
} }
@ -6316,8 +6316,7 @@ class App extends React.Component<AppProps, AppState> {
) { ) {
if ( if (
this.state.activeTool.type !== "lasso" || this.state.activeTool.type !== "lasso" ||
(Object.keys(this.state.selectedElementIds).length > 0 && Object.keys(this.state.selectedElementIds).length > 0
this.isMobileOrTablet())
) { ) {
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE); setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
} }
@ -6331,8 +6330,7 @@ class App extends React.Component<AppProps, AppState> {
) { ) {
if ( if (
this.state.activeTool.type !== "lasso" || this.state.activeTool.type !== "lasso" ||
(Object.keys(this.state.selectedElementIds).length > 0 && Object.keys(this.state.selectedElementIds).length > 0
this.isMobileOrTablet())
) { ) {
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE); setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
} }
@ -6600,26 +6598,26 @@ class App extends React.Component<AppProps, AppState> {
const hitSelectedElement = const hitSelectedElement =
pointerDownState.hit.element && pointerDownState.hit.element &&
this.isASelectedElement(pointerDownState.hit.element); this.isASelectedElement(pointerDownState.hit.element);
const isMobileOrTablet = this.isMobileOrTablet(); const isMobileOrTablet = this.isMobileOrTablet();
// On PCs, we always want to start a new lasso path even when we're hitting some elements
// Otherwise, start a new lasso ONLY if we're not interacting with an existing
// selection (move/resize/rotate).
if ( if (
!isMobileOrTablet || !pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements &&
(!pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements && !pointerDownState.resize.handleType &&
!pointerDownState.resize.handleType && !hitSelectedElement
!hitSelectedElement)
) { ) {
this.lassoTrail.startPath( this.lassoTrail.startPath(
pointerDownState.origin.x, pointerDownState.origin.x,
pointerDownState.origin.y, pointerDownState.origin.y,
event.shiftKey, event.shiftKey,
); );
// block dragging after lasso selection on PCs until the next pointer down
// (on mobile or tablet, we want to allow user to drag immediately)
pointerDownState.drag.blockDragging = !isMobileOrTablet;
} }
// When mobile & tablet, for lasso tool // only for mobile or tablet, if we hit an element, select it immediately like normal selection
// if we hit an element, select it immediately like normal selection
if ( if (
isMobileOrTablet && isMobileOrTablet &&
pointerDownState.hit.element && pointerDownState.hit.element &&
@ -7089,6 +7087,7 @@ class App extends React.Component<AppProps, AppState> {
hasOccurred: false, hasOccurred: false,
offset: null, offset: null,
origin: { ...origin }, origin: { ...origin },
blockDragging: false,
}, },
eventListeners: { eventListeners: {
onMove: null, onMove: null,
@ -7166,7 +7165,7 @@ class App extends React.Component<AppProps, AppState> {
): boolean => { ): boolean => {
if ( if (
this.state.activeTool.type === "selection" || this.state.activeTool.type === "selection" ||
(this.state.activeTool.type === "lasso" && this.isMobileOrTablet()) this.state.activeTool.type === "lasso"
) { ) {
const elements = this.scene.getNonDeletedElements(); const elements = this.scene.getNonDeletedElements();
const elementsMap = this.scene.getNonDeletedElementsMap(); const elementsMap = this.scene.getNonDeletedElementsMap();
@ -8410,15 +8409,9 @@ class App extends React.Component<AppProps, AppState> {
pointerDownState.hit.element?.id; pointerDownState.hit.element?.id;
if ( if (
(hasHitASelectedElement || (hasHitASelectedElement ||
pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements || pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) &&
(this.state.activeTool.type === "lasso" &&
pointerDownState.hit.element &&
this.isMobileOrTablet())) &&
!isSelectingPointsInLineEditor && !isSelectingPointsInLineEditor &&
(this.state.activeTool.type !== "lasso" || !pointerDownState.drag.blockDragging
pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements ||
hasHitASelectedElement ||
pointerDownState.hit.element)
) { ) {
const selectedElements = this.scene.getSelectedElements(this.state); const selectedElements = this.scene.getSelectedElements(this.state);
if ( if (
@ -8463,9 +8456,7 @@ class App extends React.Component<AppProps, AppState> {
selectedElements.length > 0 && selectedElements.length > 0 &&
!pointerDownState.withCmdOrCtrl && !pointerDownState.withCmdOrCtrl &&
!this.state.editingTextElement && !this.state.editingTextElement &&
this.state.activeEmbeddable?.state !== "active" && this.state.activeEmbeddable?.state !== "active"
// for lasso tool, only allow dragging on mobile or tablet devices
(this.state.activeTool.type !== "lasso" || this.isMobileOrTablet())
) { ) {
const dragOffset = { const dragOffset = {
x: pointerCoords.x - pointerDownState.drag.origin.x, x: pointerCoords.x - pointerDownState.drag.origin.x,
@ -9054,6 +9045,7 @@ class App extends React.Component<AppProps, AppState> {
): (event: PointerEvent) => void { ): (event: PointerEvent) => void {
return withBatchedUpdates((childEvent: PointerEvent) => { return withBatchedUpdates((childEvent: PointerEvent) => {
this.removePointer(childEvent); this.removePointer(childEvent);
pointerDownState.drag.blockDragging = false;
if (pointerDownState.eventListeners.onMove) { if (pointerDownState.eventListeners.onMove) {
pointerDownState.eventListeners.onMove.flush(); pointerDownState.eventListeners.onMove.flush();
} }

View File

@ -782,6 +782,10 @@ export type PointerDownState = Readonly<{
// by default same as PointerDownState.origin. On alt-duplication, reset // by default same as PointerDownState.origin. On alt-duplication, reset
// to current pointer position at time of duplication. // to current pointer position at time of duplication.
origin: { x: number; y: number }; origin: { x: number; y: number };
// Whether to block drag after lasso selection
// this is meant to be used to block dragging after lasso selection on PCs
// until the next pointer down
blockDragging: boolean;
}; };
// We need to have these in the state so that we can unsubscribe them // We need to have these in the state so that we can unsubscribe them
eventListeners: { eventListeners: {