diff --git a/packages/excalidraw/components/Stats/Angle.tsx b/packages/excalidraw/components/Stats/Angle.tsx index 59368d4843..3c0d59e661 100644 --- a/packages/excalidraw/components/Stats/Angle.tsx +++ b/packages/excalidraw/components/Stats/Angle.tsx @@ -18,10 +18,7 @@ import type { AppState } from "@excalidraw/excalidraw/types"; import type { Degrees, Radians } from "@excalidraw/math"; -import type { - ExcalidrawElement, - NonDeletedExcalidrawElement, -} from "@excalidraw/element/types"; +import type { ExcalidrawElement } from "@excalidraw/element/types"; import { angleIcon } from "../icons"; @@ -75,14 +72,6 @@ const handleDegreeChange: DragInputCallbackType = ({ mutateElement(boundTextElement, { angle: nextAngle }); } - setAppState({ - suggestedBindings: getSuggestedBindingsForArrows( - [latestElement] as NonDeletedExcalidrawElement[], - elementsMap, - originalAppState.zoom, - ), - }); - return; } @@ -114,7 +103,7 @@ const handleDegreeChange: DragInputCallbackType = ({ setAppState({ suggestedBindings: getSuggestedBindingsForArrows( - [latestElement] as NonDeletedExcalidrawElement[], + [latestElement], elementsMap, originalAppState.zoom, ), @@ -122,7 +111,7 @@ const handleDegreeChange: DragInputCallbackType = ({ } }; -const handleFinished: DragFinishedCallbackType = ({ +const handleFinished: DragFinishedCallbackType = ({ originalElements, originalAppState, scene, @@ -137,25 +126,15 @@ const handleFinished: DragFinishedCallbackType = ({ if (latestElement) { updateBindings(latestElement, elementsMap, originalAppState.zoom, () => { - const revertAngle = (latestElement.angle - - degreesToRadians(accumulatedChange as Degrees)) as Radians; + const change = degreesToRadians(accumulatedChange as Degrees); mutateElement(latestElement, { - angle: revertAngle, + angle: (latestElement.angle - change) as Radians, }); + }); - const boundTextElement = getBoundTextElement( - latestElement, - elementsMap, - ); - - if (boundTextElement && !isArrowElement(latestElement)) { - mutateElement(boundTextElement, { angle: revertAngle }); - } - - setAppState({ - suggestedBindings: [], - }); + setAppState({ + suggestedBindings: [], }); } } diff --git a/packages/excalidraw/components/Stats/DragInput.tsx b/packages/excalidraw/components/Stats/DragInput.tsx index 8cb07cc6b6..7d741ecab3 100644 --- a/packages/excalidraw/components/Stats/DragInput.tsx +++ b/packages/excalidraw/components/Stats/DragInput.tsx @@ -37,10 +37,14 @@ export type DragInputCallbackType< setAppState: React.Component["setState"]; }) => void; -export type DragFinishedCallbackType = (props: { +export type DragFinishedCallbackType< + P extends StatsInputProperty, + E = ExcalidrawElement, +> = (props: { originalElements: readonly E[]; originalElementsMap: ElementsMap; scene: Scene; + property: P; originalAppState: AppState; accumulatedChange: number; setAppState: React.Component["setState"]; @@ -57,7 +61,7 @@ interface StatsDragInputProps< editable?: boolean; shouldKeepAspectRatio?: boolean; dragInputCallback: DragInputCallbackType; - dragFinishedCallback?: DragFinishedCallbackType; + dragFinishedCallback?: DragFinishedCallbackType; property: T; scene: Scene; appState: AppState; @@ -136,6 +140,7 @@ const StatsDragInput = < // reason: idempotent to avoid unnecessary if (isNaN(original) || Math.abs(rounded - original) >= SMALLEST_DELTA) { stateRef.current.lastUpdatedValue = updatedValue; + const originalElementsMap = app.scene.getNonDeletedElementsMap(); dragInputCallback({ accumulatedChange: 0, instantChange: 0, @@ -150,6 +155,15 @@ const StatsDragInput = < setInputValue: (value) => setInputValue(String(value)), setAppState, }); + dragFinishedCallback?.({ + originalElements: elements, + originalElementsMap, + scene, + originalAppState: appState, + accumulatedChange: rounded, + property, + setAppState, + }); app.syncActionResult({ captureUpdate: CaptureUpdateAction.IMMEDIATELY, }); @@ -303,6 +317,7 @@ const StatsDragInput = < originalElementsMap, scene, originalAppState, + property, accumulatedChange, setAppState, }); diff --git a/packages/excalidraw/components/Stats/Position.tsx b/packages/excalidraw/components/Stats/Position.tsx index 2c62fa1d4f..312e0eec95 100644 --- a/packages/excalidraw/components/Stats/Position.tsx +++ b/packages/excalidraw/components/Stats/Position.tsx @@ -7,12 +7,17 @@ import { import { mutateElement } from "@excalidraw/element/mutateElement"; import { isImageElement } from "@excalidraw/element/typeChecks"; +import { getSuggestedBindingsForArrows } from "@excalidraw/element/binding"; + import type { ElementsMap, ExcalidrawElement } from "@excalidraw/element/types"; import StatsDragInput from "./DragInput"; -import { getStepSizedValue, moveElement } from "./utils"; +import { getStepSizedValue, moveElement, updateBindings } from "./utils"; -import type { DragInputCallbackType } from "./DragInput"; +import type { + DragFinishedCallbackType, + DragInputCallbackType, +} from "./DragInput"; import type Scene from "../../scene/Scene"; import type { AppState } from "../../types"; @@ -36,6 +41,7 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({ property, scene, originalAppState, + setAppState, }) => { const elementsMap = scene.getNonDeletedElementsMap(); const origElement = originalElements[0]; @@ -122,6 +128,14 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({ crop: nextCrop, }); + setAppState({ + suggestedBindings: getSuggestedBindingsForArrows( + [origElement], + elementsMap, + originalAppState.zoom, + ), + }); + return; } @@ -135,6 +149,7 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({ elementsMap, originalElementsMap, ); + return; } @@ -166,15 +181,51 @@ const handlePositionChange: DragInputCallbackType<"x" | "y"> = ({ elementsMap, originalElementsMap, ); + + if (origElement) { + const latestElement = elementsMap.get(origElement.id); + + if (latestElement) { + setAppState({ + suggestedBindings: getSuggestedBindingsForArrows( + [latestElement], + elementsMap, + originalAppState.zoom, + ), + }); + } + } }; -const Position = ({ - property, - element, - elementsMap, +const handleFinished: DragFinishedCallbackType<"x" | "y"> = ({ + originalElements, + originalAppState, scene, - appState, -}: PositionProps) => { + accumulatedChange, + property, + setAppState, +}) => { + const elementsMap = scene.getNonDeletedElementsMap(); + const origElement = originalElements[0]; + + if (origElement) { + const latestElement = elementsMap.get(origElement.id); + + if (latestElement) { + updateBindings(latestElement, elementsMap, originalAppState.zoom, () => { + mutateElement(latestElement, { + [property]: latestElement[property] - accumulatedChange, + }); + }); + + setAppState({ + suggestedBindings: [], + }); + } + } +}; + +const Position = ({ property, element, scene, appState }: PositionProps) => { const [topLeftX, topLeftY] = pointRotateRads( pointFrom(element.x, element.y), pointFrom(element.x + element.width / 2, element.y + element.height / 2), @@ -202,6 +253,7 @@ const Position = ({ label={property === "x" ? "X" : "Y"} elements={[element]} dragInputCallback={handlePositionChange} + dragFinishedCallback={handleFinished} scene={scene} value={value} property={property} diff --git a/packages/excalidraw/components/Stats/utils.ts b/packages/excalidraw/components/Stats/utils.ts index 9d005b9797..3281a760f5 100644 --- a/packages/excalidraw/components/Stats/utils.ts +++ b/packages/excalidraw/components/Stats/utils.ts @@ -204,7 +204,7 @@ export const updateBindings = ( latestElement: ExcalidrawElement, elementsMap: NonDeletedSceneElementsMap, zoom?: AppState["zoom"], - remainedBound?: () => void, + bindingElementKeptOriginalBinding?: () => void, ) => { if (isBindingElement(latestElement)) { const [start, end] = getOriginalBindingsIfStillCloseToArrowEnds( @@ -217,7 +217,7 @@ export const updateBindings = ( (latestElement.startBinding && start) || (latestElement.endBinding && end) ) { - remainedBound?.(); + bindingElementKeptOriginalBinding?.(); } else { if (latestElement.startBinding && !start) { unbindLinearElement(latestElement, "start"); @@ -227,9 +227,5 @@ export const updateBindings = ( unbindLinearElement(latestElement, "end"); } } - - // else if (end) { - // updateBoundElements(end, elementsMap); - // } } };