Restore drag

This commit is contained in:
Mark Tolmacs
2025-07-09 19:51:12 +02:00
parent 41cfbf7840
commit 3e090ebc4f
2 changed files with 49 additions and 10 deletions

View File

@ -13,7 +13,7 @@ import type {
import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
import { updateBoundElements } from "./binding";
import { bindOrUnbindLinearElement, updateBoundElements } from "./binding";
import { getCommonBounds } from "./bounds";
import { getPerfectElementSize } from "./sizeHelpers";
import { getBoundTextElement } from "./textElement";
@ -44,7 +44,7 @@ export const dragSelectedElements = (
) => {
if (
_selectedElements.length === 1 &&
isArrowElement(_selectedElements[0]) &&
isElbowArrow(_selectedElements[0]) &&
(_selectedElements[0].startBinding || _selectedElements[0].endBinding)
) {
return;
@ -102,9 +102,26 @@ export const dragSelectedElements = (
gridSize,
);
const elementsToUpdateIds = new Set(
Array.from(elementsToUpdate, (el) => el.id),
);
elementsToUpdate.forEach((element) => {
updateElementCoords(pointerDownState, element, scene, adjustedOffset);
const isArrow = !isArrowElement(element);
const isStartBoundElementSelected =
isArrow ||
(element.startBinding
? elementsToUpdateIds.has(element.startBinding.elementId)
: false);
const isEndBoundElementSelected =
isArrow ||
(element.endBinding
? elementsToUpdateIds.has(element.endBinding.elementId)
: false);
if (!isArrowElement(element)) {
updateElementCoords(pointerDownState, element, scene, adjustedOffset);
// skip arrow labels since we calculate its position during render
const textElement = getBoundTextElement(
element,
@ -121,6 +138,28 @@ export const dragSelectedElements = (
updateBoundElements(element, scene, {
simultaneouslyUpdated: Array.from(elementsToUpdate),
});
} else if (
// NOTE: Add a little initial drag to the arrow dragging to avoid
// accidentally unbinding the arrow when the user just wants to select it.
Math.max(Math.abs(adjustedOffset.x), Math.abs(adjustedOffset.y)) > 1
) {
updateElementCoords(pointerDownState, element, scene, adjustedOffset);
const shouldUnbindStart =
element.startBinding && !isStartBoundElementSelected;
const shouldUnbindEnd = element.endBinding && !isEndBoundElementSelected;
if (shouldUnbindStart || shouldUnbindEnd) {
// NOTE: Moving the bound arrow should unbind it, otherwise we would
// have weird situations, like 0 lenght arrow when the user moves
// the arrow outside a filled shape suddenly forcing the arrow start
// and end point to jump "outside" the shape.
bindOrUnbindLinearElement(
element,
shouldUnbindStart ? null : "keep",
shouldUnbindEnd ? null : "keep",
scene,
);
}
}
});
};

View File

@ -4365,7 +4365,7 @@ class App extends React.Component<AppProps, AppState> {
const arrowIdsToRemove = new Set<string>();
selectedElements
.filter(isArrowElement)
.filter(isElbowArrow)
.filter((arrow) => {
const startElementNotInSelection =
arrow.startBinding &&
@ -6398,8 +6398,8 @@ class App extends React.Component<AppProps, AppState> {
});
} else if (
!hitElement ||
// Arrows can only be moved when unconnected
!isArrowElement(hitElement) ||
// Elbow arrows can only be moved when unconnected
!isElbowArrow(hitElement) ||
!(hitElement.startBinding || hitElement.endBinding)
) {
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
@ -6515,8 +6515,8 @@ class App extends React.Component<AppProps, AppState> {
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
} else if (this.hitElement(scenePointerX, scenePointerY, element)) {
if (
// Arrows can only be moved when unconnected
!isArrowElement(element) ||
// Elbow arrows can only be moved when unconnected
!isElbowArrow(element) ||
!(element.startBinding || element.endBinding)
) {
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
@ -6524,8 +6524,8 @@ class App extends React.Component<AppProps, AppState> {
}
} else if (this.hitElement(scenePointerX, scenePointerY, element)) {
if (
// Arrows can only be moved when unconnected
!isArrowElement(element) ||
// Elbow arrow can only be moved when unconnected
!isElbowArrow(element) ||
!(element.startBinding || element.endBinding)
) {
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);