diff --git a/packages/excalidraw/change.ts b/packages/excalidraw/change.ts index e4c6821f9..74f6239e2 100644 --- a/packages/excalidraw/change.ts +++ b/packages/excalidraw/change.ts @@ -1215,8 +1215,12 @@ export class ElementsChange implements Change { flags: { containsVisibleDifference: boolean; containsZindexDifference: boolean; + } = { + // by default we don't care about about the flags + containsVisibleDifference: true, + containsZindexDifference: true, }, - ): OrderedExcalidrawElement { + ) { const { boundElements, ...directlyApplicablePartial } = delta.inserted; if ( diff --git a/packages/excalidraw/element/binding.ts b/packages/excalidraw/element/binding.ts index 9ff7ded04..3320da2f7 100644 --- a/packages/excalidraw/element/binding.ts +++ b/packages/excalidraw/element/binding.ts @@ -739,13 +739,13 @@ export const updateBoundElements = ( simultaneouslyUpdated?: readonly ExcalidrawElement[]; newSize?: { width: number; height: number }; changedElements?: Map; - preservePoints?: boolean; // [FIX] added + preservePoints?: boolean; }, ) => { const { newSize, simultaneouslyUpdated, - preservePoints = false, // [FIX] default false + preservePoints = false, } = options ?? {}; const simultaneouslyUpdatedElementIds = getSimultaneouslyUpdatedElementIds( simultaneouslyUpdated, @@ -760,10 +760,12 @@ export const updateBoundElements = ( return; } + // In case the boundElements are stale if (!doesNeedUpdate(element, changedElement)) { return; } + // Check for intersections before updating bound elements incase connected elements overlap const startBindingElement = element.startBinding ? elementsMap.get(element.startBinding.elementId) : null; @@ -791,12 +793,13 @@ export const updateBoundElements = ( ), }; + // `linearElement` is being moved/scaled already, just update the binding if (simultaneouslyUpdatedElementIds.has(element.id)) { mutateElement(element, bindings, true); return; } - // [FIX] If preservePoints is true, skip adjusting arrow geometry. + // If preservePoints is true, skip adjusting arrow geometry. if (preservePoints && isArrowElement(element)) { // Only update the binding fields mutateElement(element, { diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap index 75c17531a..f4527716a 100644 --- a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap +++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap @@ -683,7 +683,9 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "scrollX": 0, "scrollY": 0, "searchMatches": [], - "selectedElementIds": {}, + "selectedElementIds": { + "id167": true, + }, "selectedElementsAreBeingDragged": false, "selectedGroupIds": {}, "selectionElement": null, @@ -735,7 +737,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "strokeWidth": 2, "type": "rectangle", "updated": 1, - "version": 7, + "version": 9, "width": 100, "x": 150, "y": -50, @@ -767,7 +769,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "strokeWidth": 2, "type": "rectangle", "updated": 1, - "version": 7, + "version": 9, "width": 100, "x": 150, "y": -50, @@ -789,7 +791,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "height": 0, "id": "id167", "index": "a2", - "isDeleted": true, + "isDeleted": false, "lastCommittedPoint": null, "link": null, "locked": false, @@ -815,7 +817,7 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl "strokeWidth": 2, "type": "arrow", "updated": 1, - "version": 22, + "version": 30, "width": 100, "x": 150, "y": 0, @@ -949,75 +951,6 @@ History { }, }, }, - HistoryEntry { - "appStateChange": AppStateChange { - "delta": Delta { - "deleted": { - "selectedElementIds": {}, - "selectedLinearElementId": null, - }, - "inserted": { - "selectedElementIds": { - "id167": true, - }, - "selectedLinearElementId": "id167", - }, - }, - }, - "elementsChange": ElementsChange { - "added": Map { - "id167" => Delta { - "deleted": { - "isDeleted": true, - }, - "inserted": { - "angle": 0, - "backgroundColor": "transparent", - "boundElements": null, - "customData": undefined, - "elbowed": false, - "endArrowhead": "arrow", - "endBinding": null, - "fillStyle": "solid", - "frameId": null, - "groupIds": [], - "height": 0, - "index": "a2", - "isDeleted": false, - "lastCommittedPoint": null, - "link": null, - "locked": false, - "opacity": 100, - "points": [ - [ - 0, - 0, - ], - [ - 100, - 0, - ], - ], - "roughness": 1, - "roundness": { - "type": 2, - }, - "startArrowhead": null, - "startBinding": null, - "strokeColor": "#1e1e1e", - "strokeStyle": "solid", - "strokeWidth": 2, - "type": "arrow", - "width": 100, - "x": 150, - "y": 0, - }, - }, - }, - "removed": Map {}, - "updated": Map {}, - }, - }, ], "undoStack": [ HistoryEntry { @@ -1096,13 +1029,82 @@ History { "updated": Map {}, }, }, + HistoryEntry { + "appStateChange": AppStateChange { + "delta": Delta { + "deleted": { + "selectedElementIds": { + "id167": true, + }, + "selectedLinearElementId": "id167", + }, + "inserted": { + "selectedElementIds": {}, + "selectedLinearElementId": null, + }, + }, + }, + "elementsChange": ElementsChange { + "added": Map {}, + "removed": Map { + "id167" => Delta { + "deleted": { + "angle": 0, + "backgroundColor": "transparent", + "boundElements": null, + "customData": undefined, + "elbowed": false, + "endArrowhead": "arrow", + "endBinding": null, + "fillStyle": "solid", + "frameId": null, + "groupIds": [], + "height": 0, + "index": "a2", + "isDeleted": false, + "lastCommittedPoint": null, + "link": null, + "locked": false, + "opacity": 100, + "points": [ + [ + 0, + 0, + ], + [ + 100, + 0, + ], + ], + "roughness": 1, + "roundness": { + "type": 2, + }, + "startArrowhead": null, + "startBinding": null, + "strokeColor": "#1e1e1e", + "strokeStyle": "solid", + "strokeWidth": 2, + "type": "arrow", + "width": 100, + "x": 0, + "y": 0, + }, + "inserted": { + "isDeleted": true, + }, + }, + }, + "updated": Map {}, + }, + }, ], } `; exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of elements 1`] = `3`; -exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of renders 1`] = `19`; +exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of renders 1`] = `23`; exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] appState 1`] = ` {