From 7da176ff7d13aa16b23195a343689df7cd3372be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rk=20Tolm=C3=A1cs?= Date: Wed, 15 Oct 2025 21:16:20 +0200 Subject: [PATCH] fix: Increase transform handle offset (#10180) * fix: Increase transform handle offset Signed-off-by: Mark Tolmacs * fix: Temporarily disable transform handles for linear elements on mobile and tablets Signed-off-by: Mark Tolmacs * fix: Linear hidden resize Signed-off-by: Mark Tolmacs * disable mobielOrTablet linear element bbox completely * fix: Test Signed-off-by: Mark Tolmacs * fix: Lint Signed-off-by: Mark Tolmacs --------- Signed-off-by: Mark Tolmacs Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com> --- packages/element/src/transformHandles.ts | 7 ++++-- packages/element/tests/binding.test.tsx | 14 +++++------- packages/excalidraw/components/App.tsx | 22 +++++++++---------- .../excalidraw/renderer/interactiveScene.ts | 4 ++-- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/packages/element/src/transformHandles.ts b/packages/element/src/transformHandles.ts index 679937d4ae..b311e3af83 100644 --- a/packages/element/src/transformHandles.ts +++ b/packages/element/src/transformHandles.ts @@ -2,6 +2,7 @@ import { DEFAULT_TRANSFORM_HANDLE_SPACING, isAndroid, isIOS, + isMobileOrTablet, } from "@excalidraw/common"; import { pointFrom, pointRotateRads } from "@excalidraw/math"; @@ -326,7 +327,7 @@ export const getTransformHandles = ( ); }; -export const shouldShowBoundingBox = ( +export const hasBoundingBox = ( elements: readonly NonDeletedExcalidrawElement[], appState: InteractiveCanvasAppState, ) => { @@ -345,5 +346,7 @@ export const shouldShowBoundingBox = ( return true; } - return element.points.length > 2; + // on mobile/tablet we currently don't show bbox because of resize issues + // (also prob best for simplicity's sake) + return element.points.length > 2 && !isMobileOrTablet(); }; diff --git a/packages/element/tests/binding.test.tsx b/packages/element/tests/binding.test.tsx index a3da1c66d9..8690439782 100644 --- a/packages/element/tests/binding.test.tsx +++ b/packages/element/tests/binding.test.tsx @@ -10,6 +10,8 @@ import { API } from "@excalidraw/excalidraw/tests/helpers/api"; import { UI, Pointer, Keyboard } from "@excalidraw/excalidraw/tests/helpers/ui"; import { fireEvent, render } from "@excalidraw/excalidraw/tests/test-utils"; +import { LinearElementEditor } from "@excalidraw/element"; + import { getTransformHandles } from "../src/transformHandles"; import { getTextEditor, @@ -413,16 +415,12 @@ describe("element binding", () => { expect(arrow.endBinding?.elementId).toBe(rectRight.id); // Drag arrow off of bound rectangle range - const handles = getTransformHandles( + const [elX, elY] = LinearElementEditor.getPointAtIndexGlobalCoordinates( arrow, - h.state.zoom, - arrayToMap(h.elements), - "mouse", - ).se!; - + -1, + h.scene.getNonDeletedElementsMap(), + ); Keyboard.keyDown(KEYS.CTRL_OR_CMD); - const elX = handles[0] + handles[2] / 2; - const elY = handles[1] + handles[3] / 2; mouse.downAt(elX, elY); mouse.moveTo(300, 400); mouse.up(); diff --git a/packages/excalidraw/components/App.tsx b/packages/excalidraw/components/App.tsx index 574ec4eb91..19a5e00188 100644 --- a/packages/excalidraw/components/App.tsx +++ b/packages/excalidraw/components/App.tsx @@ -173,7 +173,7 @@ import { getContainerElement, isValidTextContainer, redrawTextBoundingBox, - shouldShowBoundingBox, + hasBoundingBox, getFrameChildren, isCursorInFrame, addElementsToFrame, @@ -5262,7 +5262,7 @@ class App extends React.Component { if ( considerBoundingBox && this.state.selectedElementIds[element.id] && - shouldShowBoundingBox([element], this.state) + hasBoundingBox([element], this.state) ) { // if hitting the bounding box, return early // but if not, we should check for other cases as well (e.g. frame name) @@ -6165,7 +6165,13 @@ class App extends React.Component { (!this.state.selectedLinearElement || this.state.selectedLinearElement.hoverPointIndex === -1) && this.state.openDialog?.name !== "elementLinkSelector" && - !(selectedElements.length === 1 && isElbowArrow(selectedElements[0])) + !(selectedElements.length === 1 && isElbowArrow(selectedElements[0])) && + // HACK: Disable transform handles for linear elements on mobile until a + // better way of showing them is found + !( + isLinearElement(selectedElements[0]) && + (isMobileOrTablet() || selectedElements[0].points.length === 2) + ) ) { const elementWithTransformHandleType = getElementWithTransformHandleType( @@ -7285,14 +7291,8 @@ class App extends React.Component { !this.state.selectedLinearElement?.isEditing && !isElbowArrow(selectedElements[0]) && !( - isLineElement(selectedElements[0]) && - LinearElementEditor.getPointIndexUnderCursor( - selectedElements[0], - elementsMap, - this.state.zoom, - pointerDownState.origin.x, - pointerDownState.origin.y, - ) !== -1 + isLinearElement(selectedElements[0]) && + (isMobileOrTablet() || selectedElements[0].points.length === 2) ) && !( this.state.selectedLinearElement && diff --git a/packages/excalidraw/renderer/interactiveScene.ts b/packages/excalidraw/renderer/interactiveScene.ts index e071d47aaf..9b836aecf8 100644 --- a/packages/excalidraw/renderer/interactiveScene.ts +++ b/packages/excalidraw/renderer/interactiveScene.ts @@ -22,7 +22,7 @@ import { getOmitSidesForDevice, getTransformHandles, getTransformHandlesFromCoords, - shouldShowBoundingBox, + hasBoundingBox, } from "@excalidraw/element"; import { isElbowArrow, @@ -892,7 +892,7 @@ const _renderInteractiveScene = ({ // Paint selected elements if (!appState.multiElement && !appState.selectedLinearElement?.isEditing) { - const showBoundingBox = shouldShowBoundingBox(selectedElements, appState); + const showBoundingBox = hasBoundingBox(selectedElements, appState); const isSingleLinearElementSelected = selectedElements.length === 1 && isLinearElement(selectedElements[0]);