diff --git a/src/components/App.tsx b/src/components/App.tsx index 618c2e88..b27c2e29 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -291,7 +291,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, @@ -302,15 +302,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) { @@ -358,7 +385,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, }, }); @@ -1382,6 +1411,7 @@ export class App extends React.Component { elements = [...elements, element]; this.setState({ draggingElement: element, + editingElement: element, }); } } else if (element.type === "selection") { @@ -1391,7 +1421,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: @@ -1860,6 +1894,7 @@ export class App extends React.Component { isResizing: false, resizingElement: null, selectionElement: null, + editingElement: multiElement ? this.state.editingElement : null, }); resizeArrowFn = null; @@ -1883,7 +1918,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(); @@ -2151,7 +2189,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, }, }); diff --git a/src/data/index.ts b/src/data/index.ts index aea93bd0..9ec26e0f 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -341,12 +341,10 @@ export async function exportCanvas( export async function loadScene(id: string | null, privateKey?: string) { let data; - let selectedId; if (id != null) { // the private key is used to decrypt the content from the server, take // extra care not to leak it data = await importFromBackend(id, privateKey); - selectedId = id; window.history.replaceState({}, "Excalidraw", window.location.origin); } else { data = restoreFromLocalStorage(); @@ -354,6 +352,6 @@ export async function loadScene(id: string | null, privateKey?: string) { return { elements: data.elements, - appState: data.appState && { ...data.appState, selectedId }, + appState: data.appState && { ...data.appState }, }; } diff --git a/src/data/types.ts b/src/data/types.ts index daa85c6f..7d0166cc 100644 --- a/src/data/types.ts +++ b/src/data/types.ts @@ -7,5 +7,4 @@ export interface DataState { source?: string; elements: readonly ExcalidrawElement[]; appState: AppState | null; - selectedId?: number; } diff --git a/src/types.ts b/src/types.ts index e1bf965a..6e96b833 100644 --- a/src/types.ts +++ b/src/types.ts @@ -28,7 +28,6 @@ export type AppState = { cursorY: number; scrolledOutside: boolean; name: string; - selectedId?: string; isCollaborating: boolean; isResizing: boolean; zoom: number;