Browse Source

refactor: rename `draggingElement` -> `newElement` (#8294)

* add newElement to appState

* freedraw should not be an editing element

* do not set editing element for freedraw and generic

* remove ununsed `appState.draggingElement`

* remove setting dragged for new linear element

* decouple selection element from new element

* fix hint for text bindables

* update snapshot

* fixes

* fix frame regressions

* add comments to types

* document `editingElement`

---------

Co-authored-by: dwelle <[email protected]>
Ryan Di 1 year ago
parent
commit
3cf14c73a3

+ 5 - 4
packages/excalidraw/actions/actionFinalize.tsx

@@ -73,8 +73,8 @@ export const actionFinalize = register({
 
     const multiPointElement = appState.multiElement
       ? appState.multiElement
-      : appState.editingElement?.type === "freedraw"
-      ? appState.editingElement
+      : appState.newElement?.type === "freedraw"
+      ? appState.newElement
       : null;
 
     if (multiPointElement) {
@@ -176,7 +176,8 @@ export const actionFinalize = register({
             ? appState.activeTool
             : activeTool,
         activeEmbeddable: null,
-        draggingElement: null,
+        newElement: null,
+        selectionElement: null,
         multiElement: null,
         editingElement: null,
         startBoundElement: null,
@@ -204,7 +205,7 @@ export const actionFinalize = register({
   keyTest: (event, appState) =>
     (event.key === KEYS.ESCAPE &&
       (appState.editingLinearElement !== null ||
-        (!appState.draggingElement && appState.multiElement === null))) ||
+        (!appState.newElement && appState.multiElement === null))) ||
     ((event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) &&
       appState.multiElement !== null),
   PanelComponent: ({ appState, updateData, data }) => (

+ 3 - 1
packages/excalidraw/actions/actionHistory.tsx

@@ -21,7 +21,9 @@ const writeData = (
     !appState.multiElement &&
     !appState.resizingElement &&
     !appState.editingElement &&
-    !appState.draggingElement
+    !appState.newElement &&
+    !appState.selectedElementsAreBeingDragged &&
+    !appState.selectionElement
   ) {
     const result = updater();
 

+ 2 - 2
packages/excalidraw/appState.ts

@@ -41,7 +41,7 @@ export const getDefaultAppState = (): Omit<
     currentHoveredFontFamily: null,
     cursorButton: "up",
     activeEmbeddable: null,
-    draggingElement: null,
+    newElement: null,
     editingElement: null,
     editingGroupId: null,
     editingLinearElement: null,
@@ -160,7 +160,7 @@ const APP_STATE_STORAGE_CONF = (<
   currentHoveredFontFamily: { browser: false, export: false, server: false },
   cursorButton: { browser: true, export: false, server: false },
   activeEmbeddable: { browser: false, export: false, server: false },
-  draggingElement: { browser: false, export: false, server: false },
+  newElement: { browser: false, export: false, server: false },
   editingElement: { browser: false, export: false, server: false },
   editingGroupId: { browser: true, export: false, server: false },
   editingLinearElement: { browser: false, export: false, server: false },

+ 359 - 362
packages/excalidraw/components/App.tsx

@@ -183,6 +183,7 @@ import type {
   ExcalidrawIframeElement,
   ExcalidrawEmbeddableElement,
   Ordered,
+  ExcalidrawNonSelectionElement,
   ExcalidrawArrowElement,
 } from "../element/types";
 import { getCenter, getDistance } from "../gesture";
@@ -822,7 +823,7 @@ class App extends React.Component<AppProps, AppState> {
       this.setState({
         activeEmbeddable: { element, state: "active" },
         selectedElementIds: { [element.id]: true },
-        draggingElement: null,
+        newElement: null,
         selectionElement: null,
       });
     }, 100);
@@ -1460,7 +1461,8 @@ class App extends React.Component<AppProps, AppState> {
         this.state.editingElement && isLinearElement(this.state.editingElement)
       ) &&
       (this.state.selectionElement ||
-        this.state.draggingElement ||
+        this.state.newElement ||
+        this.state.selectedElementsAreBeingDragged ||
         this.state.resizingElement ||
         (this.state.activeTool.type === "laser" &&
           // technically we can just test on this once we make it more safe
@@ -1616,7 +1618,7 @@ class App extends React.Component<AppProps, AppState> {
                                         selectedElementIds: {
                                           [firstSelectedElement.id]: true,
                                         },
-                                        draggingElement: null,
+                                        newElement: null,
                                         selectionElement: null,
                                       });
                                     } catch (err: any) {
@@ -4074,7 +4076,9 @@ class App extends React.Component<AppProps, AppState> {
         !event.ctrlKey &&
         !event.altKey &&
         !event.metaKey &&
-        this.state.draggingElement === null
+        !this.state.newElement &&
+        !this.state.selectionElement &&
+        !this.state.selectedElementsAreBeingDragged
       ) {
         const shape = findShapeByKey(event.key);
         if (shape) {
@@ -4495,7 +4499,7 @@ class App extends React.Component<AppProps, AppState> {
         }
 
         this.setState({
-          draggingElement: null,
+          newElement: null,
           editingElement: null,
         });
         if (this.state.activeTool.locked) {
@@ -4887,7 +4891,7 @@ class App extends React.Component<AppProps, AppState> {
       });
     } else {
       this.setState({
-        draggingElement: element,
+        newElement: element,
         multiElement: null,
       });
     }
@@ -5194,7 +5198,12 @@ class App extends React.Component<AppProps, AppState> {
       event.clientY - this.state.offsetTop,
     );
     const isOverScrollBar = isPointerOverScrollBars.isOverEither;
-    if (!this.state.draggingElement && !this.state.multiElement) {
+    if (
+      !this.state.newElement &&
+      !this.state.selectionElement &&
+      !this.state.selectedElementsAreBeingDragged &&
+      !this.state.multiElement
+    ) {
       if (isOverScrollBar) {
         resetCursor(this.interactiveCanvas);
       } else {
@@ -5206,7 +5215,7 @@ class App extends React.Component<AppProps, AppState> {
     const { x: scenePointerX, y: scenePointerY } = scenePointer;
 
     if (
-      !this.state.draggingElement &&
+      !this.state.newElement &&
       isActiveToolNonLinearSnappable(this.state.activeTool.type)
     ) {
       const { originOffset, snapLines } = getSnapLinesAtPointer(
@@ -5237,7 +5246,11 @@ class App extends React.Component<AppProps, AppState> {
           originSnapOffset: nextOriginOffset,
         };
       });
-    } else if (!this.state.draggingElement) {
+    } else if (
+      !this.state.newElement &&
+      !this.state.selectedElementsAreBeingDragged &&
+      !this.state.selectionElement
+    ) {
       this.setState((prevState) => {
         if (prevState.snapLines.length) {
           return {
@@ -5286,10 +5299,10 @@ class App extends React.Component<AppProps, AppState> {
     if (isBindingElementType(this.state.activeTool.type)) {
       // Hovering with a selected tool or creating new linear element via click
       // and point
-      const { draggingElement } = this.state;
-      if (isBindingElement(draggingElement, false)) {
+      const { newElement } = this.state;
+      if (isBindingElement(newElement, false)) {
         this.maybeSuggestBindingsForLinearElementAtCoords(
-          draggingElement,
+          newElement,
           [scenePointer],
           this.state.startBoundElement,
         );
@@ -5787,10 +5800,10 @@ class App extends React.Component<AppProps, AppState> {
     // finger is lifted
     if (
       event.pointerType === "touch" &&
-      this.state.draggingElement &&
-      this.state.draggingElement.type === "freedraw"
+      this.state.newElement &&
+      this.state.newElement.type === "freedraw"
     ) {
-      const element = this.state.draggingElement as ExcalidrawFreeDrawElement;
+      const element = this.state.newElement as ExcalidrawFreeDrawElement;
       this.updateScene({
         ...(element.points.length < 10
           ? {
@@ -5800,7 +5813,7 @@ class App extends React.Component<AppProps, AppState> {
             }
           : {}),
         appState: {
-          draggingElement: null,
+          newElement: null,
           editingElement: null,
           startBoundElement: null,
           suggestedBindings: [],
@@ -5983,7 +5996,7 @@ class App extends React.Component<AppProps, AppState> {
       }
 
       this.setState({
-        draggingElement: pendingImageElement,
+        newElement: pendingImageElement as ExcalidrawNonSelectionElement,
         editingElement: pendingImageElement,
         pendingImageElementId: null,
         multiElement: null,
@@ -6831,8 +6844,7 @@ class App extends React.Component<AppProps, AppState> {
     );
     this.scene.insertElement(element);
     this.setState({
-      draggingElement: element,
-      editingElement: element,
+      newElement: element,
       startBoundElement: boundElement,
       suggestedBindings: [],
     });
@@ -7131,7 +7143,7 @@ class App extends React.Component<AppProps, AppState> {
 
       this.scene.insertElement(element);
       this.setState({
-        draggingElement: element,
+        newElement: element,
         editingElement: element,
         startBoundElement: boundElement,
         suggestedBindings: [],
@@ -7205,14 +7217,12 @@ class App extends React.Component<AppProps, AppState> {
     if (element.type === "selection") {
       this.setState({
         selectionElement: element,
-        draggingElement: element,
       });
     } else {
       this.scene.insertElement(element);
       this.setState({
         multiElement: null,
-        draggingElement: element,
-        editingElement: element,
+        newElement: element,
       });
     }
   };
@@ -7246,8 +7256,7 @@ class App extends React.Component<AppProps, AppState> {
 
     this.setState({
       multiElement: null,
-      draggingElement: frame,
-      editingElement: frame,
+      newElement: frame,
     });
   };
 
@@ -7524,9 +7533,7 @@ class App extends React.Component<AppProps, AppState> {
         // Marking that click was used for dragging to check
         // if elements should be deselected on pointerup
         pointerDownState.drag.hasOccurred = true;
-        this.setState({
-          selectedElementsAreBeingDragged: true,
-        });
+
         // prevent dragging even if we're no longer holding cmd/ctrl otherwise
         // it would have weird results (stuff jumping all over the screen)
         // Checking for editingElement to avoid jump while editing on mobile #6503
@@ -7592,6 +7599,13 @@ class App extends React.Component<AppProps, AppState> {
               event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
             );
 
+          this.setState({
+            selectedElementsAreBeingDragged: true,
+            // element is being dragged and selectionElement that was created on pointer down
+            // should be removed
+            selectionElement: null,
+          });
+
           if (
             selectedElements.length !== 1 ||
             !isElbowArrow(selectedElements[0])
@@ -7604,8 +7618,6 @@ class App extends React.Component<AppProps, AppState> {
             });
           }
 
-          //}
-
           // We duplicate the selected element if alt is pressed on pointer move
           if (event.altKey && !pointerDownState.hit.hasBeenDuplicated) {
             // Move the currently selected elements to the top of the z index stack, and
@@ -7696,83 +7708,87 @@ class App extends React.Component<AppProps, AppState> {
         }
       }
 
-      // It is very important to read this.state within each move event,
-      // otherwise we would read a stale one!
-      const draggingElement = this.state.draggingElement;
-      if (!draggingElement) {
-        return;
-      }
+      if (this.state.selectionElement) {
+        pointerDownState.lastCoords.x = pointerCoords.x;
+        pointerDownState.lastCoords.y = pointerCoords.y;
+        this.maybeDragNewGenericElement(pointerDownState, event);
+      } else {
+        // It is very important to read this.state within each move event,
+        // otherwise we would read a stale one!
+        const newElement = this.state.newElement;
 
-      if (draggingElement.type === "freedraw") {
-        const points = draggingElement.points;
-        const dx = pointerCoords.x - draggingElement.x;
-        const dy = pointerCoords.y - draggingElement.y;
+        if (!newElement) {
+          return;
+        }
 
-        const lastPoint = points.length > 0 && points[points.length - 1];
-        const discardPoint =
-          lastPoint && lastPoint[0] === dx && lastPoint[1] === dy;
+        if (newElement.type === "freedraw") {
+          const points = newElement.points;
+          const dx = pointerCoords.x - newElement.x;
+          const dy = pointerCoords.y - newElement.y;
 
-        if (!discardPoint) {
-          const pressures = draggingElement.simulatePressure
-            ? draggingElement.pressures
-            : [...draggingElement.pressures, event.pressure];
+          const lastPoint = points.length > 0 && points[points.length - 1];
+          const discardPoint =
+            lastPoint && lastPoint[0] === dx && lastPoint[1] === dy;
 
-          mutateElement(draggingElement, {
-            points: [...points, [dx, dy]],
-            pressures,
-          });
-        }
-      } else if (isLinearElement(draggingElement)) {
-        pointerDownState.drag.hasOccurred = true;
-        this.setState({
-          selectedElementsAreBeingDragged: true,
-        });
-        const points = draggingElement.points;
-        let dx = gridX - draggingElement.x;
-        let dy = gridY - draggingElement.y;
-
-        if (shouldRotateWithDiscreteAngle(event) && points.length === 2) {
-          ({ width: dx, height: dy } = getLockedLinearCursorAlignSize(
-            draggingElement.x,
-            draggingElement.y,
-            pointerCoords.x,
-            pointerCoords.y,
-          ));
-        }
+          if (!discardPoint) {
+            const pressures = newElement.simulatePressure
+              ? newElement.pressures
+              : [...newElement.pressures, event.pressure];
 
-        if (points.length === 1) {
-          mutateElement(draggingElement, {
-            points: [...points, [dx, dy]],
-          });
-        } else if (points.length > 1 && isElbowArrow(draggingElement)) {
-          mutateElbowArrow(
-            draggingElement,
-            this.scene,
-            [...points.slice(0, -1), [dx, dy]],
-            [0, 0],
-            undefined,
-            {
-              isDragging: true,
-            },
-          );
-        } else if (points.length === 2) {
-          mutateElement(draggingElement, {
-            points: [...points.slice(0, -1), [dx, dy]],
-          });
-        }
+            mutateElement(newElement, {
+              points: [...points, [dx, dy]],
+              pressures,
+            });
+          }
+        } else if (isLinearElement(newElement)) {
+          pointerDownState.drag.hasOccurred = true;
+          const points = newElement.points;
+          let dx = gridX - newElement.x;
+          let dy = gridY - newElement.y;
+
+          if (shouldRotateWithDiscreteAngle(event) && points.length === 2) {
+            ({ width: dx, height: dy } = getLockedLinearCursorAlignSize(
+              newElement.x,
+              newElement.y,
+              pointerCoords.x,
+              pointerCoords.y,
+            ));
+          }
 
-        if (isBindingElement(draggingElement, false)) {
-          // When creating a linear element by dragging
-          this.maybeSuggestBindingsForLinearElementAtCoords(
-            draggingElement,
-            [pointerCoords],
-            this.state.startBoundElement,
-          );
+          if (points.length === 1) {
+            mutateElement(newElement, {
+              points: [...points, [dx, dy]],
+            });
+          } else if (points.length > 1 && isElbowArrow(newElement)) {
+            mutateElbowArrow(
+              newElement,
+              this.scene,
+              [...points.slice(0, -1), [dx, dy]],
+              [0, 0],
+              undefined,
+              {
+                isDragging: true,
+              },
+            );
+          } else if (points.length === 2) {
+            mutateElement(newElement, {
+              points: [...points.slice(0, -1), [dx, dy]],
+            });
+          }
+
+          if (isBindingElement(newElement, false)) {
+            // When creating a linear element by dragging
+            this.maybeSuggestBindingsForLinearElementAtCoords(
+              newElement,
+              [pointerCoords],
+              this.state.startBoundElement,
+            );
+          }
+        } else {
+          pointerDownState.lastCoords.x = pointerCoords.x;
+          pointerDownState.lastCoords.y = pointerCoords.y;
+          this.maybeDragNewGenericElement(pointerDownState, event);
         }
-      } else {
-        pointerDownState.lastCoords.x = pointerCoords.x;
-        pointerDownState.lastCoords.y = pointerCoords.y;
-        this.maybeDragNewGenericElement(pointerDownState, event);
       }
 
       if (this.state.activeTool.type === "selection") {
@@ -7814,11 +7830,13 @@ class App extends React.Component<AppProps, AppState> {
               shouldReuseSelection = false;
             }
           }
-          const elementsWithinSelection = getElementsWithinSelection(
-            elements,
-            draggingElement,
-            this.scene.getNonDeletedElementsMap(),
-          );
+          const elementsWithinSelection = this.state.selectionElement
+            ? getElementsWithinSelection(
+                elements,
+                this.state.selectionElement,
+                this.scene.getNonDeletedElementsMap(),
+              )
+            : [];
 
           this.setState((prevState) => {
             const nextSelectedElementIds = {
@@ -7911,7 +7929,7 @@ class App extends React.Component<AppProps, AppState> {
         pointerDownState.eventListeners.onMove.flush();
       }
       const {
-        draggingElement,
+        newElement,
         resizingElement,
         multiElement,
         activeTool,
@@ -8042,15 +8060,15 @@ class App extends React.Component<AppProps, AppState> {
         childEvent,
       );
 
-      if (draggingElement?.type === "freedraw") {
+      if (newElement?.type === "freedraw") {
         const pointerCoords = viewportCoordsToSceneCoords(
           childEvent,
           this.state,
         );
 
-        const points = draggingElement.points;
-        let dx = pointerCoords.x - draggingElement.x;
-        let dy = pointerCoords.y - draggingElement.y;
+        const points = newElement.points;
+        let dx = pointerCoords.x - newElement.x;
+        let dy = pointerCoords.y - newElement.y;
 
         // Allows dots to avoid being flagged as infinitely small
         if (dx === points[0][0] && dy === points[0][1]) {
@@ -8058,11 +8076,11 @@ class App extends React.Component<AppProps, AppState> {
           dx += 0.0001;
         }
 
-        const pressures = draggingElement.simulatePressure
+        const pressures = newElement.simulatePressure
           ? []
-          : [...draggingElement.pressures, childEvent.pressure];
+          : [...newElement.pressures, childEvent.pressure];
 
-        mutateElement(draggingElement, {
+        mutateElement(newElement, {
           points: [...points, [dx, dy]],
           pressures,
           lastCommittedPoint: [dx, dy],
@@ -8072,8 +8090,8 @@ class App extends React.Component<AppProps, AppState> {
 
         return;
       }
-      if (isImageElement(draggingElement)) {
-        const imageElement = draggingElement;
+      if (isImageElement(newElement)) {
+        const imageElement = newElement;
         try {
           this.initializeImageDimensions(imageElement);
           this.setState(
@@ -8099,8 +8117,8 @@ class App extends React.Component<AppProps, AppState> {
         return;
       }
 
-      if (isLinearElement(draggingElement)) {
-        if (draggingElement!.points.length > 1) {
+      if (isLinearElement(newElement)) {
+        if (newElement!.points.length > 1) {
           this.store.shouldCaptureIncrement();
         }
         const pointerCoords = viewportCoordsToSceneCoords(
@@ -8108,31 +8126,24 @@ class App extends React.Component<AppProps, AppState> {
           this.state,
         );
 
-        if (
-          !pointerDownState.drag.hasOccurred &&
-          draggingElement &&
-          !multiElement
-        ) {
-          mutateElement(draggingElement, {
+        if (!pointerDownState.drag.hasOccurred && newElement && !multiElement) {
+          mutateElement(newElement, {
             points: [
-              ...draggingElement.points,
-              [
-                pointerCoords.x - draggingElement.x,
-                pointerCoords.y - draggingElement.y,
-              ],
+              ...newElement.points,
+              [pointerCoords.x - newElement.x, pointerCoords.y - newElement.y],
             ],
           });
           this.setState({
-            multiElement: draggingElement,
-            editingElement: this.state.draggingElement,
+            multiElement: newElement,
+            editingElement: this.state.newElement,
           });
         } else if (pointerDownState.drag.hasOccurred && !multiElement) {
           if (
             isBindingEnabled(this.state) &&
-            isBindingElement(draggingElement, false)
+            isBindingElement(newElement, false)
           ) {
             maybeBindLinearElement(
-              draggingElement,
+              newElement,
               this.state,
               pointerCoords,
               this.scene.getNonDeletedElementsMap(),
@@ -8143,63 +8154,63 @@ class App extends React.Component<AppProps, AppState> {
           if (!activeTool.locked) {
             resetCursor(this.interactiveCanvas);
             this.setState((prevState) => ({
-              draggingElement: null,
+              newElement: null,
               activeTool: updateActiveTool(this.state, {
                 type: "selection",
               }),
               selectedElementIds: makeNextSelectedElementIds(
                 {
                   ...prevState.selectedElementIds,
-                  [draggingElement.id]: true,
+                  [newElement.id]: true,
                 },
                 prevState,
               ),
-              selectedLinearElement: new LinearElementEditor(draggingElement),
+              selectedLinearElement: new LinearElementEditor(newElement),
             }));
           } else {
             this.setState((prevState) => ({
-              draggingElement: null,
+              newElement: null,
             }));
           }
         }
         return;
       }
 
-      if (isTextElement(draggingElement)) {
+      if (isTextElement(newElement)) {
         const minWidth = getMinTextElementWidth(
           getFontString({
-            fontSize: draggingElement.fontSize,
-            fontFamily: draggingElement.fontFamily,
+            fontSize: newElement.fontSize,
+            fontFamily: newElement.fontFamily,
           }),
-          draggingElement.lineHeight,
+          newElement.lineHeight,
         );
 
-        if (draggingElement.width < minWidth) {
-          mutateElement(draggingElement, {
+        if (newElement.width < minWidth) {
+          mutateElement(newElement, {
             autoResize: true,
           });
         }
 
         this.resetCursor();
 
-        this.handleTextWysiwyg(draggingElement, {
+        this.handleTextWysiwyg(newElement, {
           isExistingElement: true,
         });
       }
 
       if (
         activeTool.type !== "selection" &&
-        draggingElement &&
-        isInvisiblySmallElement(draggingElement)
+        newElement &&
+        isInvisiblySmallElement(newElement)
       ) {
         // remove invisible element which was added in onPointerDown
         // update the store snapshot, so that invisible elements are not captured by the store
         this.updateScene({
           elements: this.scene
             .getElementsIncludingDeleted()
-            .filter((el) => el.id !== draggingElement.id),
+            .filter((el) => el.id !== newElement.id),
           appState: {
-            draggingElement: null,
+            newElement: null,
           },
           storeAction: StoreAction.UPDATE,
         });
@@ -8207,161 +8218,154 @@ class App extends React.Component<AppProps, AppState> {
         return;
       }
 
-      if (draggingElement) {
-        if (pointerDownState.drag.hasOccurred) {
-          const sceneCoords = viewportCoordsToSceneCoords(
-            childEvent,
-            this.state,
-          );
+      if (isFrameLikeElement(newElement)) {
+        const elementsInsideFrame = getElementsInNewFrame(
+          this.scene.getElementsIncludingDeleted(),
+          newElement,
+          this.scene.getNonDeletedElementsMap(),
+        );
 
-          // when editing the points of a linear element, we check if the
-          // linear element still is in the frame afterwards
-          // if not, the linear element will be removed from its frame (if any)
-          if (
-            this.state.selectedLinearElement &&
-            this.state.selectedLinearElement.isDragging
-          ) {
-            const linearElement = this.scene.getElement(
-              this.state.selectedLinearElement.elementId,
-            );
+        this.scene.replaceAllElements(
+          addElementsToFrame(
+            this.scene.getElementsMapIncludingDeleted(),
+            elementsInsideFrame,
+            newElement,
+          ),
+        );
+      }
 
-            if (linearElement?.frameId) {
-              const frame = getContainingFrame(linearElement, elementsMap);
+      if (newElement) {
+        mutateElement(newElement, getNormalizedDimensions(newElement));
+      }
 
-              if (frame && linearElement) {
-                if (
-                  !elementOverlapsWithFrame(
-                    linearElement,
-                    frame,
-                    this.scene.getNonDeletedElementsMap(),
-                  )
-                ) {
-                  // remove the linear element from all groups
-                  // before removing it from the frame as well
-                  mutateElement(linearElement, {
-                    groupIds: [],
-                  });
+      if (pointerDownState.drag.hasOccurred) {
+        const sceneCoords = viewportCoordsToSceneCoords(childEvent, this.state);
 
-                  removeElementsFromFrame(
-                    [linearElement],
-                    this.scene.getNonDeletedElementsMap(),
-                  );
+        // when editing the points of a linear element, we check if the
+        // linear element still is in the frame afterwards
+        // if not, the linear element will be removed from its frame (if any)
+        if (
+          this.state.selectedLinearElement &&
+          this.state.selectedLinearElement.isDragging
+        ) {
+          const linearElement = this.scene.getElement(
+            this.state.selectedLinearElement.elementId,
+          );
 
-                  this.scene.triggerUpdate();
-                }
+          if (linearElement?.frameId) {
+            const frame = getContainingFrame(linearElement, elementsMap);
+
+            if (frame && linearElement) {
+              if (
+                !elementOverlapsWithFrame(
+                  linearElement,
+                  frame,
+                  this.scene.getNonDeletedElementsMap(),
+                )
+              ) {
+                // remove the linear element from all groups
+                // before removing it from the frame as well
+                mutateElement(linearElement, {
+                  groupIds: [],
+                });
+
+                removeElementsFromFrame(
+                  [linearElement],
+                  this.scene.getNonDeletedElementsMap(),
+                );
+
+                this.scene.triggerUpdate();
               }
             }
-          } else {
-            // update the relationships between selected elements and frames
-            const topLayerFrame =
-              this.getTopLayerFrameAtSceneCoords(sceneCoords);
-
-            const selectedElements = this.scene.getSelectedElements(this.state);
-            let nextElements = this.scene.getElementsMapIncludingDeleted();
-
-            const updateGroupIdsAfterEditingGroup = (
-              elements: ExcalidrawElement[],
-            ) => {
-              if (elements.length > 0) {
-                for (const element of elements) {
-                  const index = element.groupIds.indexOf(
-                    this.state.editingGroupId!,
-                  );
+          }
+        } else {
+          // update the relationships between selected elements and frames
+          const topLayerFrame = this.getTopLayerFrameAtSceneCoords(sceneCoords);
+
+          const selectedElements = this.scene.getSelectedElements(this.state);
+          let nextElements = this.scene.getElementsMapIncludingDeleted();
+
+          const updateGroupIdsAfterEditingGroup = (
+            elements: ExcalidrawElement[],
+          ) => {
+            if (elements.length > 0) {
+              for (const element of elements) {
+                const index = element.groupIds.indexOf(
+                  this.state.editingGroupId!,
+                );
+
+                mutateElement(
+                  element,
+                  {
+                    groupIds: element.groupIds.slice(0, index),
+                  },
+                  false,
+                );
+              }
 
+              nextElements.forEach((element) => {
+                if (
+                  element.groupIds.length &&
+                  getElementsInGroup(
+                    nextElements,
+                    element.groupIds[element.groupIds.length - 1],
+                  ).length < 2
+                ) {
                   mutateElement(
                     element,
                     {
-                      groupIds: element.groupIds.slice(0, index),
+                      groupIds: [],
                     },
                     false,
                   );
                 }
+              });
 
-                nextElements.forEach((element) => {
-                  if (
-                    element.groupIds.length &&
-                    getElementsInGroup(
-                      nextElements,
-                      element.groupIds[element.groupIds.length - 1],
-                    ).length < 2
-                  ) {
-                    mutateElement(
-                      element,
-                      {
-                        groupIds: [],
-                      },
-                      false,
-                    );
-                  }
-                });
-
-                this.setState({
-                  editingGroupId: null,
-                });
-              }
-            };
-
-            if (
-              topLayerFrame &&
-              !this.state.selectedElementIds[topLayerFrame.id]
-            ) {
-              const elementsToAdd = selectedElements.filter(
-                (element) =>
-                  element.frameId !== topLayerFrame.id &&
-                  isElementInFrame(element, nextElements, this.state),
-              );
-
-              if (this.state.editingGroupId) {
-                updateGroupIdsAfterEditingGroup(elementsToAdd);
-              }
+              this.setState({
+                editingGroupId: null,
+              });
+            }
+          };
 
-              nextElements = addElementsToFrame(
-                nextElements,
-                elementsToAdd,
-                topLayerFrame,
-              );
-            } else if (!topLayerFrame) {
-              if (this.state.editingGroupId) {
-                const elementsToRemove = selectedElements.filter(
-                  (element) =>
-                    element.frameId &&
-                    !isElementInFrame(element, nextElements, this.state),
-                );
+          if (
+            topLayerFrame &&
+            !this.state.selectedElementIds[topLayerFrame.id]
+          ) {
+            const elementsToAdd = selectedElements.filter(
+              (element) =>
+                element.frameId !== topLayerFrame.id &&
+                isElementInFrame(element, nextElements, this.state),
+            );
 
-                updateGroupIdsAfterEditingGroup(elementsToRemove);
-              }
+            if (this.state.editingGroupId) {
+              updateGroupIdsAfterEditingGroup(elementsToAdd);
             }
 
-            nextElements = updateFrameMembershipOfSelectedElements(
+            nextElements = addElementsToFrame(
               nextElements,
-              this.state,
-              this,
+              elementsToAdd,
+              topLayerFrame,
             );
+          } else if (!topLayerFrame) {
+            if (this.state.editingGroupId) {
+              const elementsToRemove = selectedElements.filter(
+                (element) =>
+                  element.frameId &&
+                  !isElementInFrame(element, nextElements, this.state),
+              );
 
-            this.scene.replaceAllElements(nextElements);
+              updateGroupIdsAfterEditingGroup(elementsToRemove);
+            }
           }
-        }
 
-        if (isFrameLikeElement(draggingElement)) {
-          const elementsInsideFrame = getElementsInNewFrame(
-            this.scene.getElementsIncludingDeleted(),
-            draggingElement,
-            this.scene.getNonDeletedElementsMap(),
+          nextElements = updateFrameMembershipOfSelectedElements(
+            nextElements,
+            this.state,
+            this,
           );
 
-          this.scene.replaceAllElements(
-            addElementsToFrame(
-              this.scene.getElementsMapIncludingDeleted(),
-              elementsInsideFrame,
-              draggingElement,
-            ),
-          );
+          this.scene.replaceAllElements(nextElements);
         }
-
-        mutateElement(
-          draggingElement,
-          getNormalizedDimensions(draggingElement),
-        );
       }
 
       if (resizingElement) {
@@ -8656,22 +8660,17 @@ class App extends React.Component<AppProps, AppState> {
         return;
       }
 
-      if (
-        !activeTool.locked &&
-        activeTool.type !== "freedraw" &&
-        draggingElement &&
-        draggingElement.type !== "selection"
-      ) {
+      if (!activeTool.locked && activeTool.type !== "freedraw" && newElement) {
         this.setState((prevState) => ({
           selectedElementIds: makeNextSelectedElementIds(
             {
               ...prevState.selectedElementIds,
-              [draggingElement.id]: true,
+              [newElement.id]: true,
             },
             prevState,
           ),
           showHyperlinkPopup:
-            isEmbeddableElement(draggingElement) && !draggingElement.link
+            isEmbeddableElement(newElement) && !newElement.link
               ? "editor"
               : prevState.showHyperlinkPopup,
         }));
@@ -8713,13 +8712,13 @@ class App extends React.Component<AppProps, AppState> {
       if (!activeTool.locked && activeTool.type !== "freedraw") {
         resetCursor(this.interactiveCanvas);
         this.setState({
-          draggingElement: null,
+          newElement: null,
           suggestedBindings: [],
           activeTool: updateActiveTool(this.state, { type: "selection" }),
         });
       } else {
         this.setState({
-          draggingElement: null,
+          newElement: null,
           suggestedBindings: [],
         });
       }
@@ -8882,7 +8881,7 @@ class App extends React.Component<AppProps, AppState> {
           }
           if (
             this.state.pendingImageElementId !== imageElement.id &&
-            this.state.draggingElement?.id !== imageElement.id
+            this.state.newElement?.id !== imageElement.id
           ) {
             this.initializeImageDimensions(imageElement, true);
           }
@@ -9542,17 +9541,11 @@ class App extends React.Component<AppProps, AppState> {
     pointerDownState: PointerDownState,
     event: MouseEvent | KeyboardEvent,
   ): void => {
-    const draggingElement = this.state.draggingElement;
+    const selectionElement = this.state.selectionElement;
     const pointerCoords = pointerDownState.lastCoords;
-    if (!draggingElement) {
-      return;
-    }
-    if (
-      draggingElement.type === "selection" &&
-      this.state.activeTool.type !== "eraser"
-    ) {
+    if (selectionElement && this.state.activeTool.type !== "eraser") {
       dragNewElement(
-        draggingElement,
+        selectionElement,
         this.state.activeTool.type,
         pointerDownState.origin.x,
         pointerDownState.origin.y,
@@ -9564,81 +9557,85 @@ class App extends React.Component<AppProps, AppState> {
         shouldResizeFromCenter(event),
         this.state.zoom.value,
       );
-    } else {
-      let [gridX, gridY] = getGridPoint(
-        pointerCoords.x,
-        pointerCoords.y,
-        event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
-      );
+      return;
+    }
 
-      const image =
-        isInitializedImageElement(draggingElement) &&
-        this.imageCache.get(draggingElement.fileId)?.image;
-      const aspectRatio =
-        image && !(image instanceof Promise)
-          ? image.width / image.height
-          : null;
+    const newElement = this.state.newElement;
+    if (!newElement) {
+      return;
+    }
 
-      this.maybeCacheReferenceSnapPoints(event, [draggingElement]);
+    let [gridX, gridY] = getGridPoint(
+      pointerCoords.x,
+      pointerCoords.y,
+      event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize,
+    );
 
-      const { snapOffset, snapLines } = snapNewElement(
-        draggingElement,
-        this.state,
-        event,
-        {
-          x:
-            pointerDownState.originInGrid.x +
-            (this.state.originSnapOffset?.x ?? 0),
-          y:
-            pointerDownState.originInGrid.y +
-            (this.state.originSnapOffset?.y ?? 0),
-        },
-        {
-          x: gridX - pointerDownState.originInGrid.x,
-          y: gridY - pointerDownState.originInGrid.y,
-        },
-        this.scene.getNonDeletedElementsMap(),
-      );
+    const image =
+      isInitializedImageElement(newElement) &&
+      this.imageCache.get(newElement.fileId)?.image;
+    const aspectRatio =
+      image && !(image instanceof Promise) ? image.width / image.height : null;
 
-      gridX += snapOffset.x;
-      gridY += snapOffset.y;
+    this.maybeCacheReferenceSnapPoints(event, [newElement]);
 
-      this.setState({
-        snapLines,
-      });
+    const { snapOffset, snapLines } = snapNewElement(
+      newElement,
+      this.state,
+      event,
+      {
+        x:
+          pointerDownState.originInGrid.x +
+          (this.state.originSnapOffset?.x ?? 0),
+        y:
+          pointerDownState.originInGrid.y +
+          (this.state.originSnapOffset?.y ?? 0),
+      },
+      {
+        x: gridX - pointerDownState.originInGrid.x,
+        y: gridY - pointerDownState.originInGrid.y,
+      },
+      this.scene.getNonDeletedElementsMap(),
+    );
 
-      dragNewElement(
-        draggingElement,
-        this.state.activeTool.type,
-        pointerDownState.originInGrid.x,
-        pointerDownState.originInGrid.y,
-        gridX,
-        gridY,
-        distance(pointerDownState.originInGrid.x, gridX),
-        distance(pointerDownState.originInGrid.y, gridY),
-        isImageElement(draggingElement)
-          ? !shouldMaintainAspectRatio(event)
-          : shouldMaintainAspectRatio(event),
-        shouldResizeFromCenter(event),
-        this.state.zoom.value,
-        aspectRatio,
-        this.state.originSnapOffset,
-      );
+    gridX += snapOffset.x;
+    gridY += snapOffset.y;
 
-      // highlight elements that are to be added to frames on frames creation
-      if (
-        this.state.activeTool.type === TOOL_TYPE.frame ||
-        this.state.activeTool.type === TOOL_TYPE.magicframe
-      ) {
-        this.setState({
-          elementsToHighlight: getElementsInResizingFrame(
-            this.scene.getNonDeletedElements(),
-            draggingElement as ExcalidrawFrameLikeElement,
-            this.state,
-            this.scene.getNonDeletedElementsMap(),
-          ),
-        });
-      }
+    this.setState({
+      snapLines,
+    });
+
+    dragNewElement(
+      newElement,
+      this.state.activeTool.type,
+      pointerDownState.originInGrid.x,
+      pointerDownState.originInGrid.y,
+      gridX,
+      gridY,
+      distance(pointerDownState.originInGrid.x, gridX),
+      distance(pointerDownState.originInGrid.y, gridY),
+      isImageElement(newElement)
+        ? !shouldMaintainAspectRatio(event)
+        : shouldMaintainAspectRatio(event),
+      shouldResizeFromCenter(event),
+      this.state.zoom.value,
+      aspectRatio,
+      this.state.originSnapOffset,
+    );
+
+    // highlight elements that are to be added to frames on frames creation
+    if (
+      this.state.activeTool.type === TOOL_TYPE.frame ||
+      this.state.activeTool.type === TOOL_TYPE.magicframe
+    ) {
+      this.setState({
+        elementsToHighlight: getElementsInResizingFrame(
+          this.scene.getNonDeletedElements(),
+          newElement as ExcalidrawFrameLikeElement,
+          this.state,
+          this.scene.getNonDeletedElementsMap(),
+        ),
+      });
     }
   };
 

+ 4 - 3
packages/excalidraw/components/HintViewer.tsx

@@ -85,7 +85,7 @@ const getHints = ({ appState, isMobile, device, app }: HintViewerProps) => {
 
   if (activeTool.type === "selection") {
     if (
-      appState.draggingElement?.type === "selection" &&
+      appState.selectionElement &&
       !selectedElements.length &&
       !appState.editingElement &&
       !appState.editingLinearElement
@@ -93,7 +93,7 @@ const getHints = ({ appState, isMobile, device, app }: HintViewerProps) => {
       return t("hints.deepBoxSelect");
     }
 
-    if (appState.gridSize && appState.draggingElement) {
+    if (appState.gridSize && appState.selectedElementsAreBeingDragged) {
       return t("hints.disableSnapping");
     }
 
@@ -111,7 +111,8 @@ const getHints = ({ appState, isMobile, device, app }: HintViewerProps) => {
         return t("hints.lineEditor_info");
       }
       if (
-        !appState.draggingElement &&
+        !appState.newElement &&
+        !appState.selectedElementsAreBeingDragged &&
         isTextBindableContainer(selectedElements[0])
       ) {
         return t("hints.bindTextToElement");

+ 1 - 1
packages/excalidraw/components/hyperlink/Hyperlink.tsx

@@ -211,7 +211,7 @@ export const Hyperlink = ({
   const { x, y } = getCoordsForPopover(element, appState, elementsMap);
   if (
     appState.contextMenu ||
-    appState.draggingElement ||
+    appState.selectedElementsAreBeingDragged ||
     appState.resizingElement ||
     appState.isRotating ||
     appState.openMenu ||

+ 1 - 1
packages/excalidraw/data/reconcile.ts

@@ -26,7 +26,7 @@ const shouldDiscardRemoteElement = (
     // local element is being edited
     (local.id === localAppState.editingElement?.id ||
       local.id === localAppState.resizingElement?.id ||
-      local.id === localAppState.draggingElement?.id || // TODO: Is this still valid? As draggingElement is selection element, which is never part of the elements array
+      local.id === localAppState.newElement?.id || // TODO: Is this still valid? As newElement is selection element, which is never part of the elements array
       // local element is newer
       local.version > remote.version ||
       // resolve conflicting edits deterministically by taking the one with

+ 1 - 1
packages/excalidraw/element/ElementCanvasButtons.tsx

@@ -36,7 +36,7 @@ export const ElementCanvasButtons = ({
 
   if (
     appState.contextMenu ||
-    appState.draggingElement ||
+    appState.newElement ||
     appState.resizingElement ||
     appState.isRotating ||
     appState.openMenu ||

+ 8 - 11
packages/excalidraw/element/dragElements.ts

@@ -160,7 +160,7 @@ export const getDragOffsetXY = (
 };
 
 export const dragNewElement = (
-  draggingElement: NonDeletedExcalidrawElement,
+  newElement: NonDeletedExcalidrawElement,
   elementType: AppState["activeTool"]["type"],
   originX: number,
   originY: number,
@@ -179,7 +179,7 @@ export const dragNewElement = (
     y: number;
   } | null = null,
 ) => {
-  if (shouldMaintainAspectRatio && draggingElement.type !== "selection") {
+  if (shouldMaintainAspectRatio && newElement.type !== "selection") {
     if (widthAspectRatio) {
       height = width / widthAspectRatio;
     } else {
@@ -218,17 +218,14 @@ export const dragNewElement = (
 
   let textAutoResize = null;
 
-  // NOTE this should apply only to creating text elements, not existing
-  // (once we rewrite appState.draggingElement to actually mean dragging
-  // elements)
-  if (isTextElement(draggingElement)) {
-    height = draggingElement.height;
+  if (isTextElement(newElement)) {
+    height = newElement.height;
     const minWidth = getMinTextElementWidth(
       getFontString({
-        fontSize: draggingElement.fontSize,
-        fontFamily: draggingElement.fontFamily,
+        fontSize: newElement.fontSize,
+        fontFamily: newElement.fontFamily,
       }),
-      draggingElement.lineHeight,
+      newElement.lineHeight,
     );
     width = Math.max(width, minWidth);
 
@@ -245,7 +242,7 @@ export const dragNewElement = (
   }
 
   if (width !== 0 && height !== 0) {
-    mutateElement(draggingElement, {
+    mutateElement(newElement, {
       x: newX + (originOffset?.x ?? 0),
       y: newY + (originOffset?.y ?? 0),
       width,

+ 2 - 5
packages/excalidraw/element/linearElementEditor.ts

@@ -151,10 +151,7 @@ export class LinearElementEditor {
     setState: React.Component<any, AppState>["setState"],
     elementsMap: NonDeletedSceneElementsMap,
   ) {
-    if (
-      !appState.editingLinearElement ||
-      appState.draggingElement?.type !== "selection"
-    ) {
+    if (!appState.editingLinearElement || !appState.selectionElement) {
       return false;
     }
     const { editingLinearElement } = appState;
@@ -166,7 +163,7 @@ export class LinearElementEditor {
     }
 
     const [selectionX1, selectionY1, selectionX2, selectionY2] =
-      getElementAbsoluteCoords(appState.draggingElement, elementsMap);
+      getElementAbsoluteCoords(appState.selectionElement, elementsMap);
 
     const pointsSceneCoords = LinearElementEditor.getPointsGlobalCoordinates(
       element,

+ 5 - 0
packages/excalidraw/element/types.ts

@@ -176,6 +176,11 @@ export type ExcalidrawElement =
   | ExcalidrawIframeElement
   | ExcalidrawEmbeddableElement;
 
+export type ExcalidrawNonSelectionElement = Exclude<
+  ExcalidrawElement,
+  ExcalidrawSelectionElement
+>;
+
 export type Ordered<TElement extends ExcalidrawElement> = TElement & {
   index: FractionalIndex;
 };

+ 5 - 7
packages/excalidraw/snapping.ts

@@ -1209,16 +1209,14 @@ export const snapResizingElements = (
 };
 
 export const snapNewElement = (
-  draggingElement: ExcalidrawElement,
+  newElement: ExcalidrawElement,
   appState: AppState,
   event: KeyboardModifiersObject,
   origin: Vector2D,
   dragOffset: Vector2D,
   elementsMap: ElementsMap,
 ) => {
-  if (
-    !isSnappingEnabled({ event, selectedElements: [draggingElement], appState })
-  ) {
+  if (!isSnappingEnabled({ event, selectedElements: [newElement], appState })) {
     return {
       snapOffset: { x: 0, y: 0 },
       snapLines: [],
@@ -1240,7 +1238,7 @@ export const snapNewElement = (
   const nearestSnapsY: Snaps = [];
 
   getPointSnaps(
-    [draggingElement],
+    [newElement],
     selectionSnapPoints,
     appState,
     event,
@@ -1259,13 +1257,13 @@ export const snapNewElement = (
   nearestSnapsX.length = 0;
   nearestSnapsY.length = 0;
 
-  const corners = getElementsCorners([draggingElement], elementsMap, {
+  const corners = getElementsCorners([newElement], elementsMap, {
     boundingBoxCorners: true,
     omitCenter: true,
   });
 
   getPointSnaps(
-    [draggingElement],
+    [newElement],
     corners,
     appState,
     event,

+ 17 - 17
packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap

@@ -812,7 +812,6 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -841,6 +840,7 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -1015,7 +1015,6 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1044,6 +1043,7 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -1228,7 +1228,6 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1257,6 +1256,7 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -1556,7 +1556,6 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1585,6 +1584,7 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -1884,7 +1884,6 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1913,6 +1912,7 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -2097,7 +2097,6 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2126,6 +2125,7 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -2334,7 +2334,6 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2363,6 +2362,7 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -2632,7 +2632,6 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2661,6 +2660,7 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -2998,7 +2998,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3027,6 +3026,7 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -3470,7 +3470,6 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3499,6 +3498,7 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -3790,7 +3790,6 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3819,6 +3818,7 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -4110,7 +4110,6 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -4139,6 +4138,7 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -5293,7 +5293,6 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -5322,6 +5321,7 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -6417,7 +6417,6 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -6446,6 +6445,7 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -7349,7 +7349,6 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -7378,6 +7377,7 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -8258,7 +8258,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -8287,6 +8286,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,
@@ -9149,7 +9149,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9178,6 +9177,7 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 20,
   "offsetTop": 10,

+ 58 - 58
packages/excalidraw/tests/__snapshots__/history.test.tsx.snap

@@ -29,7 +29,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -57,6 +56,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -628,7 +628,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -656,6 +655,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -1131,7 +1131,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1159,6 +1158,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -1496,7 +1496,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1524,6 +1523,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -1862,7 +1862,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1890,6 +1889,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -2126,7 +2126,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2154,6 +2153,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -2563,7 +2563,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2591,6 +2590,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -2859,7 +2859,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2887,6 +2886,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -3140,7 +3140,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3168,6 +3167,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -3431,7 +3431,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3459,6 +3458,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -3714,7 +3714,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3742,6 +3741,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -3946,7 +3946,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3974,6 +3973,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -4202,7 +4202,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -4230,6 +4229,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -4472,7 +4472,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -4500,6 +4499,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -4700,7 +4700,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -4728,6 +4727,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -4928,7 +4928,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -4956,6 +4955,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -5154,7 +5154,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -5182,6 +5181,7 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -5380,7 +5380,6 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -5408,6 +5407,7 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -5636,7 +5636,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -5664,6 +5663,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -5964,7 +5964,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -5992,6 +5991,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -6386,7 +6386,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -6414,6 +6413,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -6761,7 +6761,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -6789,6 +6788,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -7077,7 +7077,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -7105,6 +7104,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -7372,7 +7372,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -7400,6 +7399,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -7598,7 +7598,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -7626,6 +7625,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -7950,7 +7950,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -7978,6 +7977,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -8302,7 +8302,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -8330,6 +8329,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -8703,7 +8703,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -8731,6 +8730,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -8987,7 +8987,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9015,6 +9014,7 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -9249,7 +9249,6 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9277,6 +9276,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -9510,7 +9510,6 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9538,6 +9537,7 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -9738,7 +9738,6 @@ exports[`history > multiplayer undo/redo > should override remotely added groups
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9766,6 +9765,7 @@ exports[`history > multiplayer undo/redo > should override remotely added groups
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -10036,7 +10036,6 @@ exports[`history > multiplayer undo/redo > should override remotely added points
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -10064,6 +10063,7 @@ exports[`history > multiplayer undo/redo > should override remotely added points
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -10373,7 +10373,6 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -10401,6 +10400,7 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -10605,7 +10605,6 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -10633,6 +10632,7 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -11055,7 +11055,6 @@ exports[`history > multiplayer undo/redo > should update history entries after r
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -11083,6 +11082,7 @@ exports[`history > multiplayer undo/redo > should update history entries after r
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -11306,7 +11306,6 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -11334,6 +11333,7 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -11542,7 +11542,6 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -11570,6 +11569,7 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -11780,7 +11780,6 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -11808,6 +11807,7 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -12178,7 +12178,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on s
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -12206,6 +12205,7 @@ exports[`history > singleplayer undo/redo > should create new history entry on s
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -12422,7 +12422,6 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -12450,6 +12449,7 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -12660,7 +12660,6 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -12688,6 +12687,7 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -12898,7 +12898,6 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -12926,6 +12925,7 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -13142,7 +13142,6 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -13170,6 +13169,7 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -13471,7 +13471,6 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -13499,6 +13498,7 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -13640,7 +13640,6 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -13668,6 +13667,7 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -13925,7 +13925,6 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -13953,6 +13952,7 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -14189,7 +14189,6 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -14217,6 +14216,7 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -14461,7 +14461,6 @@ exports[`history > singleplayer undo/redo > should support appstate name or view
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -14489,6 +14488,7 @@ exports[`history > singleplayer undo/redo > should support appstate name or view
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -14619,7 +14619,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -14647,6 +14646,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -15312,7 +15312,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -15340,6 +15339,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -15929,7 +15929,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -15957,6 +15956,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -16546,7 +16546,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -16574,6 +16573,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -17255,7 +17255,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -17283,6 +17282,7 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -18002,7 +18002,6 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -18030,6 +18029,7 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -18473,7 +18473,6 @@ exports[`history > singleplayer undo/redo > should support duplication of groups
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -18501,6 +18500,7 @@ exports[`history > singleplayer undo/redo > should support duplication of groups
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -18992,7 +18992,6 @@ exports[`history > singleplayer undo/redo > should support element creation, del
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -19020,6 +19019,7 @@ exports[`history > singleplayer undo/redo > should support element creation, del
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -19445,7 +19445,6 @@ exports[`history > singleplayer undo/redo > should support linear element creati
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -19473,6 +19472,7 @@ exports[`history > singleplayer undo/redo > should support linear element creati
   "isRotating": false,
   "lastPointerDownWith": "mouse",
   "multiElement": null,
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,

+ 52 - 202
packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap

@@ -29,7 +29,6 @@ exports[`given element A and group of elements B and given both are selected whe
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -58,6 +57,7 @@ exports[`given element A and group of elements B and given both are selected whe
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -438,7 +438,6 @@ exports[`given element A and group of elements B and given both are selected whe
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -467,6 +466,7 @@ exports[`given element A and group of elements B and given both are selected whe
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -838,7 +838,6 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": "id10",
@@ -867,6 +866,7 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -1377,7 +1377,6 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1406,6 +1405,7 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -1575,7 +1575,6 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1604,6 +1603,7 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -1944,7 +1944,6 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -1973,6 +1972,7 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -2178,7 +2178,6 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = `
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2207,6 +2206,7 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = `
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -2352,7 +2352,6 @@ exports[`regression tests > can drag element that covers another element, while
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2381,6 +2380,7 @@ exports[`regression tests > can drag element that covers another element, while
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -2666,7 +2666,6 @@ exports[`regression tests > change the properties of a shape > [end of test] app
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2695,6 +2694,7 @@ exports[`regression tests > change the properties of a shape > [end of test] app
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -2906,7 +2906,6 @@ exports[`regression tests > click on an element and drag it > [dragged] appState
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -2935,6 +2934,7 @@ exports[`regression tests > click on an element and drag it > [dragged] appState
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -3143,7 +3143,6 @@ exports[`regression tests > click on an element and drag it > [end of test] appS
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3172,6 +3171,7 @@ exports[`regression tests > click on an element and drag it > [end of test] appS
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -3367,7 +3367,6 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`]
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3396,6 +3395,7 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`]
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -3617,7 +3617,6 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3646,6 +3645,7 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -3922,7 +3922,6 @@ exports[`regression tests > deleting last but one element in editing group shoul
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -3951,6 +3950,7 @@ exports[`regression tests > deleting last but one element in editing group shoul
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -4330,37 +4330,6 @@ exports[`regression tests > deselects group of selected elements on pointer down
   "currentItemTextAlign": "left",
   "cursorButton": "down",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": {
-    "angle": 0,
-    "backgroundColor": "transparent",
-    "boundElements": null,
-    "customData": undefined,
-    "fillStyle": "solid",
-    "frameId": null,
-    "groupIds": [],
-    "height": 0,
-    "id": "id3",
-    "index": null,
-    "isDeleted": false,
-    "link": null,
-    "locked": false,
-    "opacity": 100,
-    "roughness": 1,
-    "roundness": {
-      "type": 2,
-    },
-    "seed": 1505387817,
-    "strokeColor": "#1e1e1e",
-    "strokeStyle": "solid",
-    "strokeWidth": 2,
-    "type": "selection",
-    "updated": 1,
-    "version": 1,
-    "versionNonce": 0,
-    "width": 0,
-    "x": 500,
-    "y": 500,
-  },
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -4389,6 +4358,7 @@ exports[`regression tests > deselects group of selected elements on pointer down
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -4637,37 +4607,6 @@ exports[`regression tests > deselects group of selected elements on pointer up w
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": {
-    "angle": 0,
-    "backgroundColor": "transparent",
-    "boundElements": null,
-    "customData": undefined,
-    "fillStyle": "solid",
-    "frameId": null,
-    "groupIds": [],
-    "height": 0,
-    "id": "id3",
-    "index": null,
-    "isDeleted": false,
-    "link": null,
-    "locked": false,
-    "opacity": 100,
-    "roughness": 1,
-    "roundness": {
-      "type": 2,
-    },
-    "seed": 1505387817,
-    "strokeColor": "#1e1e1e",
-    "strokeStyle": "solid",
-    "strokeWidth": 2,
-    "type": "selection",
-    "updated": 1,
-    "version": 1,
-    "versionNonce": 0,
-    "width": 0,
-    "x": 50,
-    "y": 50,
-  },
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -4696,6 +4635,7 @@ exports[`regression tests > deselects group of selected elements on pointer up w
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -4914,37 +4854,6 @@ exports[`regression tests > deselects selected element on pointer down when poin
   "currentItemTextAlign": "left",
   "cursorButton": "down",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": {
-    "angle": 0,
-    "backgroundColor": "transparent",
-    "boundElements": null,
-    "customData": undefined,
-    "fillStyle": "solid",
-    "frameId": null,
-    "groupIds": [],
-    "height": 0,
-    "id": "id1",
-    "index": null,
-    "isDeleted": false,
-    "link": null,
-    "locked": false,
-    "opacity": 100,
-    "roughness": 1,
-    "roundness": {
-      "type": 2,
-    },
-    "seed": 1150084233,
-    "strokeColor": "#1e1e1e",
-    "strokeStyle": "solid",
-    "strokeWidth": 2,
-    "type": "selection",
-    "updated": 1,
-    "version": 1,
-    "versionNonce": 0,
-    "width": 0,
-    "x": 110,
-    "y": 110,
-  },
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -4973,6 +4882,7 @@ exports[`regression tests > deselects selected element on pointer down when poin
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -5148,7 +5058,6 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -5177,6 +5086,7 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -5341,7 +5251,6 @@ exports[`regression tests > double click to edit a group > [end of test] appStat
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": "id3",
@@ -5370,6 +5279,7 @@ exports[`regression tests > double click to edit a group > [end of test] appStat
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -5717,7 +5627,6 @@ exports[`regression tests > drags selected elements from point inside common bou
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -5746,6 +5655,7 @@ exports[`regression tests > drags selected elements from point inside common bou
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -6001,7 +5911,6 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -6030,6 +5939,7 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -6803,7 +6713,6 @@ exports[`regression tests > given a group of selected elements with an element t
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -6832,6 +6741,7 @@ exports[`regression tests > given a group of selected elements with an element t
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -7127,7 +7037,6 @@ exports[`regression tests > given a selected element A and a not selected elemen
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -7156,6 +7065,7 @@ exports[`regression tests > given a selected element A and a not selected elemen
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -7397,7 +7307,6 @@ exports[`regression tests > given selected element A with lower z-index than uns
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -7426,6 +7335,7 @@ exports[`regression tests > given selected element A with lower z-index than uns
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -7625,7 +7535,6 @@ exports[`regression tests > given selected element A with lower z-index than uns
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -7654,6 +7563,7 @@ exports[`regression tests > given selected element A with lower z-index than uns
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -7856,7 +7766,6 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -7885,6 +7794,7 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -8030,7 +7940,6 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -8059,6 +7968,7 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -8204,7 +8114,6 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -8233,6 +8142,7 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -8378,7 +8288,6 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -8407,6 +8316,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -8594,7 +8504,6 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -8623,6 +8532,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -8809,7 +8719,6 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -8838,6 +8747,7 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -8997,7 +8907,6 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9026,6 +8935,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -9213,7 +9123,6 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9242,6 +9151,7 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -9387,7 +9297,6 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9416,6 +9325,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -9602,7 +9512,6 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9631,6 +9540,7 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -9776,7 +9686,6 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9805,6 +9714,7 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -9964,7 +9874,6 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -9993,6 +9902,7 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -10138,7 +10048,6 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -10167,6 +10076,7 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -10646,7 +10556,6 @@ exports[`regression tests > noop interaction after undo shouldn't create history
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -10675,6 +10584,7 @@ exports[`regression tests > noop interaction after undo shouldn't create history
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -10917,7 +10827,6 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
   "currentItemTextAlign": "left",
   "cursorButton": "down",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -10946,6 +10855,7 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
   "lastPointerDownWith": "touch",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -11037,7 +10947,6 @@ exports[`regression tests > shift click on selected element should deselect it o
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -11066,6 +10975,7 @@ exports[`regression tests > shift click on selected element should deselect it o
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -11230,7 +11140,6 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -11259,6 +11168,7 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -11535,7 +11445,6 @@ exports[`regression tests > should group elements and ungroup them > [end of tes
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -11564,6 +11473,7 @@ exports[`regression tests > should group elements and ungroup them > [end of tes
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -11941,7 +11851,6 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -11970,6 +11879,7 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -12548,7 +12458,6 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -12577,6 +12486,7 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -12671,7 +12581,6 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`]
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": "id3",
@@ -12700,6 +12609,7 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`]
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -13249,37 +13159,6 @@ exports[`regression tests > switches from group of selected elements to another
   "currentItemTextAlign": "left",
   "cursorButton": "down",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": {
-    "angle": 0,
-    "backgroundColor": "transparent",
-    "boundElements": null,
-    "customData": undefined,
-    "fillStyle": "solid",
-    "frameId": null,
-    "groupIds": [],
-    "height": 0,
-    "id": "id4",
-    "index": null,
-    "isDeleted": false,
-    "link": null,
-    "locked": false,
-    "opacity": 100,
-    "roughness": 1,
-    "roundness": {
-      "type": 2,
-    },
-    "seed": 1723083209,
-    "strokeColor": "#1e1e1e",
-    "strokeStyle": "solid",
-    "strokeWidth": 2,
-    "type": "selection",
-    "updated": 1,
-    "version": 1,
-    "versionNonce": 0,
-    "width": 0,
-    "x": 0,
-    "y": 0,
-  },
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -13308,6 +13187,7 @@ exports[`regression tests > switches from group of selected elements to another
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -13611,37 +13491,6 @@ exports[`regression tests > switches selected element on pointer down > [end of
   "currentItemTextAlign": "left",
   "cursorButton": "down",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": {
-    "angle": 0,
-    "backgroundColor": "transparent",
-    "boundElements": null,
-    "customData": undefined,
-    "fillStyle": "solid",
-    "frameId": null,
-    "groupIds": [],
-    "height": 0,
-    "id": "id2",
-    "index": null,
-    "isDeleted": false,
-    "link": null,
-    "locked": false,
-    "opacity": 100,
-    "roughness": 1,
-    "roundness": {
-      "type": 2,
-    },
-    "seed": 1604849351,
-    "strokeColor": "#1e1e1e",
-    "strokeStyle": "solid",
-    "strokeWidth": 2,
-    "type": "selection",
-    "updated": 1,
-    "version": 1,
-    "versionNonce": 0,
-    "width": 0,
-    "x": 0,
-    "y": 0,
-  },
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -13670,6 +13519,7 @@ exports[`regression tests > switches selected element on pointer down > [end of
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -13900,7 +13750,6 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
   "currentItemTextAlign": "left",
   "cursorButton": "down",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -13929,6 +13778,7 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
   "lastPointerDownWith": "touch",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -14020,7 +13870,6 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -14049,6 +13898,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -14393,7 +14243,6 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -14422,6 +14271,7 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,
@@ -14513,7 +14363,6 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = `
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -14542,6 +14391,7 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = `
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "Untitled-201933152653",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "offsetLeft": 0,
   "offsetTop": 0,

+ 25 - 3
packages/excalidraw/types.ts

@@ -21,6 +21,7 @@ import type {
   ExcalidrawElementType,
   ExcalidrawIframeLikeElement,
   OrderedExcalidrawElement,
+  ExcalidrawNonSelectionElement,
 } from "./element/types";
 import type { Action } from "./actions/types";
 import type { Point as RoughPoint } from "roughjs/bin/geometry";
@@ -233,9 +234,25 @@ export interface AppState {
     element: NonDeletedExcalidrawElement;
     state: "hover" | "active";
   } | null;
-  draggingElement: NonDeletedExcalidrawElement | null;
+  /**
+   * for a newly created element
+   * - set on pointer down, updated during pointer move, used on pointer up
+   */
+  newElement: NonDeleted<ExcalidrawNonSelectionElement> | null;
+  /**
+   * for a single element that's being resized
+   * - set on pointer down when it's selected and the active tool is selection
+   */
   resizingElement: NonDeletedExcalidrawElement | null;
+  /**
+   * multiElement is for multi-point linear element that's created by clicking as opposed to dragging
+   * - when set and present, the editor will handle linear element creation logic accordingly
+   */
   multiElement: NonDeleted<ExcalidrawLinearElement> | null;
+  /**
+   * decoupled from newElement, dragging selection only creates selectionElement
+   * - set on pointer down, updated during pointer move
+   */
   selectionElement: NonDeletedExcalidrawElement | null;
   isBindingEnabled: boolean;
   startBoundElement: NonDeleted<ExcalidrawBindableElement> | null;
@@ -249,8 +266,13 @@ export interface AppState {
   };
   editingFrame: string | null;
   elementsToHighlight: NonDeleted<ExcalidrawElement>[] | null;
-  // element being edited, but not necessarily added to elements array yet
-  // (e.g. text element when typing into the input)
+  /**
+   * currently set for:
+   * - text elements while in wysiwyg
+   * - newly created linear elements while in line editor (not set for existing
+   *   elements in line editor)
+   * - and new images while being placed on canvas
+   */
   editingElement: NonDeletedExcalidrawElement | null;
   editingLinearElement: LinearElementEditor | null;
   activeTool: {

+ 1 - 1
packages/utils/__snapshots__/export.test.ts.snap

@@ -29,7 +29,6 @@ exports[`exportToSvg > with default arguments 1`] = `
   "currentItemTextAlign": "left",
   "cursorButton": "up",
   "defaultSidebarDockedPreference": false,
-  "draggingElement": null,
   "editingElement": null,
   "editingFrame": null,
   "editingGroupId": null,
@@ -58,6 +57,7 @@ exports[`exportToSvg > with default arguments 1`] = `
   "lastPointerDownWith": "mouse",
   "multiElement": null,
   "name": "name",
+  "newElement": null,
   "objectsSnapModeEnabled": false,
   "openDialog": null,
   "openMenu": null,