diff --git a/src/components/App.tsx b/src/components/App.tsx index c25962dc..44fd4ea3 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -293,7 +293,7 @@ export class App extends React.Component { } else { // create a map of ids so we don't have to iterate // over the array more than once. - const elementMap = elements.reduce( + const localElementMap = elements.reduce( ( acc: { [key: string]: ExcalidrawElement }, element: ExcalidrawElement, @@ -304,15 +304,42 @@ export class App extends React.Component { {}, ); // Reconcile - elements = restoredState.elements.map(element => { - if ( - elementMap.hasOwnProperty(element.id) && - elementMap[element.id].version > element.version - ) { - return elementMap[element.id]; - } - return element; - }); + elements = restoredState.elements + .reduce((elements, element) => { + // if the remote element references one that's currently + // edited on local, skip it (it'll be added in the next + // step) + if ( + element.id === this.state.editingElement?.id || + element.id === this.state.resizingElement?.id || + element.id === this.state.draggingElement?.id + ) { + return elements; + } + + if ( + localElementMap.hasOwnProperty(element.id) && + localElementMap[element.id].version > element.version + ) { + elements.push(localElementMap[element.id]); + } else { + elements.push(element); + } + + return elements; + }, [] as any) + // add local elements that are currently being edited + // (can't be done in the step above because the elements may + // not exist on remote at all) + .concat( + elements.filter(element => { + return ( + element.id === this.state.editingElement?.id || + element.id === this.state.resizingElement?.id || + element.id === this.state.draggingElement?.id + ); + }), + ); } this.setState({}); if (this.socketInitialized === false) { @@ -344,7 +371,9 @@ export class App extends React.Component { this.broadcastSocketData({ type: "SCENE_UPDATE", payload: { - elements, + elements: elements.filter(element => { + return element.id !== this.state.editingElement?.id; + }), appState: this.state, }, }); @@ -1368,6 +1397,7 @@ export class App extends React.Component { elements = [...elements, element]; this.setState({ draggingElement: element, + editingElement: element, }); } } else if (element.type === "selection") { @@ -1377,7 +1407,11 @@ export class App extends React.Component { }); } else { elements = [...elements, element]; - this.setState({ multiElement: null, draggingElement: element }); + this.setState({ + multiElement: null, + draggingElement: element, + editingElement: element, + }); } let resizeArrowFn: @@ -1846,6 +1880,7 @@ export class App extends React.Component { isResizing: false, resizingElement: null, selectionElement: null, + editingElement: multiElement ? this.state.editingElement : null, }); resizeArrowFn = null; @@ -1869,7 +1904,10 @@ export class App extends React.Component { y - draggingElement.y, ]); invalidateShapeForElement(draggingElement); - this.setState({ multiElement: this.state.draggingElement }); + this.setState({ + multiElement: this.state.draggingElement, + editingElement: this.state.draggingElement, + }); } else if (draggingOccurred && !multiElement) { if (!elementLocked) { resetCursor(); @@ -2135,7 +2173,9 @@ export class App extends React.Component { this.broadcastSocketData({ type: "SCENE_UPDATE", payload: { - elements, + elements: elements.filter(element => { + return element.id !== this.state.editingElement?.id; + }), appState: this.state, }, });