diff --git a/packages/element/src/sizeHelpers.ts b/packages/element/src/sizeHelpers.ts index bd3d3fb0c4..02f6ea9231 100644 --- a/packages/element/src/sizeHelpers.ts +++ b/packages/element/src/sizeHelpers.ts @@ -3,10 +3,12 @@ import { viewportCoordsToSceneCoords, } from "@excalidraw/common"; +import { pointsEqual } from "@excalidraw/math"; + import type { AppState, Offsets, Zoom } from "@excalidraw/excalidraw/types"; import { getCommonBounds, getElementBounds } from "./bounds"; -import { isFreeDrawElement, isLinearElement } from "./typeChecks"; +import { isElbowArrow, isFreeDrawElement, isLinearElement } from "./typeChecks"; import type { ElementsMap, ExcalidrawElement } from "./types"; @@ -16,6 +18,12 @@ import type { ElementsMap, ExcalidrawElement } from "./types"; export const isInvisiblySmallElement = ( element: ExcalidrawElement, ): boolean => { + if (isElbowArrow(element)) { + return ( + element.points.length < 2 || + pointsEqual(element.points[0], element.points[element.points.length - 1]) + ); + } if (isLinearElement(element) || isFreeDrawElement(element)) { return element.points.length < 2; } diff --git a/packages/excalidraw/actions/actionFinalize.tsx b/packages/excalidraw/actions/actionFinalize.tsx index 22638ee917..7ab677f02f 100644 --- a/packages/excalidraw/actions/actionFinalize.tsx +++ b/packages/excalidraw/actions/actionFinalize.tsx @@ -7,6 +7,7 @@ import { import { LinearElementEditor } from "@excalidraw/element/linearElementEditor"; import { + isArrowElement, isBindingElement, isLinearElement, } from "@excalidraw/element/typeChecks"; @@ -62,6 +63,7 @@ export const actionFinalize = register({ captureUpdate: CaptureUpdateAction.IMMEDIATELY, }; } + } else if (isArrowElement(appState.newElement)) { } let newElements = elements; @@ -82,48 +84,46 @@ export const actionFinalize = register({ focusContainer(); } - const multiPointElement = appState.multiElement + const element = appState.multiElement ? appState.multiElement : appState.newElement?.type === "freedraw" ? appState.newElement + : isBindingElement(appState.newElement) + ? appState.newElement : null; - if (multiPointElement) { + if (element) { // pen and mouse have hover if ( - multiPointElement.type !== "freedraw" && + appState.multiElement && + element.type !== "freedraw" && appState.lastPointerDownWith !== "touch" ) { - const { points, lastCommittedPoint } = multiPointElement; + const { points, lastCommittedPoint } = element; if ( !lastCommittedPoint || points[points.length - 1] !== lastCommittedPoint ) { - scene.mutateElement(multiPointElement, { - points: multiPointElement.points.slice(0, -1), + scene.mutateElement(element, { + points: element.points.slice(0, -1), }); } } - if (isInvisiblySmallElement(multiPointElement)) { + if (isInvisiblySmallElement(element)) { // TODO: #7348 in theory this gets recorded by the store, so the invisible elements could be restored by the undo/redo, which might be not what we would want - newElements = newElements.filter( - (el) => el.id !== multiPointElement.id, - ); + newElements = newElements.filter((el) => el.id !== element.id); } // If the multi point line closes the loop, // set the last point to first point. // This ensures that loop remains closed at different scales. - const isLoop = isPathALoop(multiPointElement.points, appState.zoom.value); - if ( - multiPointElement.type === "line" || - multiPointElement.type === "freedraw" - ) { + const isLoop = isPathALoop(element.points, appState.zoom.value); + if (element.type === "line" || element.type === "freedraw") { if (isLoop) { - const linePoints = multiPointElement.points; + const linePoints = element.points; const firstPoint = linePoints[0]; - scene.mutateElement(multiPointElement, { + scene.mutateElement(element, { points: linePoints.map((p, index) => index === linePoints.length - 1 ? pointFrom(firstPoint[0], firstPoint[1]) @@ -133,24 +133,20 @@ export const actionFinalize = register({ } } - if ( - isBindingElement(multiPointElement) && - !isLoop && - multiPointElement.points.length > 1 - ) { + if (isBindingElement(element) && !isLoop && element.points.length > 1) { const [x, y] = LinearElementEditor.getPointAtIndexGlobalCoordinates( - multiPointElement, + element, -1, arrayToMap(elements), ); - maybeBindLinearElement(multiPointElement, appState, { x, y }, scene); + maybeBindLinearElement(element, appState, { x, y }, scene); } } if ( (!appState.activeTool.locked && appState.activeTool.type !== "freedraw") || - !multiPointElement + !element ) { resetCursor(interactiveCanvas); } @@ -177,7 +173,7 @@ export const actionFinalize = register({ activeTool: (appState.activeTool.locked || appState.activeTool.type === "freedraw") && - multiPointElement + element ? appState.activeTool : activeTool, activeEmbeddable: null, @@ -188,21 +184,18 @@ export const actionFinalize = register({ startBoundElement: null, suggestedBindings: [], selectedElementIds: - multiPointElement && + element && !appState.activeTool.locked && appState.activeTool.type !== "freedraw" ? { ...appState.selectedElementIds, - [multiPointElement.id]: true, + [element.id]: true, } : appState.selectedElementIds, // To select the linear element when user has finished mutipoint editing selectedLinearElement: - multiPointElement && isLinearElement(multiPointElement) - ? new LinearElementEditor( - multiPointElement, - arrayToMap(newElements), - ) + element && isLinearElement(element) + ? new LinearElementEditor(element, arrayToMap(newElements)) : appState.selectedLinearElement, pendingImageElementId: null, }, diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index ddb071981f..7c7d2ba495 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -9022,6 +9022,7 @@ class App extends React.Component { linearElementEditor; const element = this.scene.getElement(linearElementEditor.elementId); if (isBindingElement(element)) { + this.actionManager.executeAction(actionFinalize); bindOrUnbindLinearElement( element, startBindingElement,