| 
					
				 | 
			
			
				@@ -46,11 +46,14 @@ import { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   SocketUpdateDataSource, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   exportCanvas, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } from "../data"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import { restore } from "../data/restore"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { renderScene } from "../renderer"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { AppState, GestureEvent, Gesture } from "../types"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-import { ExcalidrawElement, ExcalidrawLinearElement } from "../element/types"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ExcalidrawElement, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ExcalidrawLinearElement, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ExcalidrawTextElement, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} from "../element/types"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { rotate, adjustXYWithRotation } from "../math"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -474,7 +477,15 @@ export class App extends React.Component<any, AppState> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     const { atLeastOneVisibleElement, scrollBars } = renderScene( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      globalSceneState.getAllElements(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      globalSceneState.getAllElements().filter((element) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // don't render text element that's being currently edited (it's 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //  rendered on remote only) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          !this.state.editingElement || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.state.editingElement.type !== "text" || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          element.id !== this.state.editingElement.id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       this.state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       this.state.selectionElement, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       window.devicePixelRatio, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -717,9 +728,7 @@ export class App extends React.Component<any, AppState> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         decryptedData: SocketUpdateDataSource["SCENE_INIT" | "SCENE_UPDATE"], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       ) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         const { elements: remoteElements } = decryptedData.payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        const restoredState = restore(remoteElements || [], null, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          scrollToContent: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // Perform reconciliation - in collaboration, if we encounter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // elements with more staler versions than ours, ignore them 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         // and keep ours. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -727,7 +736,7 @@ export class App extends React.Component<any, AppState> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           globalSceneState.getAllElements() == null || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           globalSceneState.getAllElements().length === 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          globalSceneState.replaceAllElements(restoredState.elements); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          globalSceneState.replaceAllElements(remoteElements); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           // create a map of ids so we don't have to iterate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           // over the array more than once. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -736,7 +745,7 @@ export class App extends React.Component<any, AppState> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           // Reconcile 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          const newElements = restoredState.elements 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          const newElements = remoteElements 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             .reduce((elements, element) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               // if the remote element references one that's currently 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               //  edited on local, skip it (it'll be added in the next 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -779,7 +788,7 @@ export class App extends React.Component<any, AppState> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               return elements; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }, [] as Mutable<typeof restoredState.elements>) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }, [] as Mutable<typeof remoteElements>) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // add local elements that weren't deleted or on remote 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             .concat(...Object.values(localElementMap)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1082,6 +1091,96 @@ export class App extends React.Component<any, AppState> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     globalSceneState.replaceAllElements(elements); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private handleTextWysiwyg( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    element: ExcalidrawTextElement, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      x, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      y, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      isExistingElement = false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }: { x: number; y: number; isExistingElement?: boolean }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const resetSelection = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.setState({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        draggingElement: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        editingElement: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // deselect all other elements when inserting text 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.setState({ selectedElementIds: {} }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const deleteElement = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      globalSceneState.replaceAllElements([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...globalSceneState.getAllElements().map((_element) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (_element.id === element.id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return newElementWith(_element, { isDeleted: true }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          return _element; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const updateElement = (text: string) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      globalSceneState.replaceAllElements([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...globalSceneState.getAllElements().map((_element) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (_element.id === element.id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return newTextElement({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              ..._element, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              x: element.x, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              y: element.y, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              text, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              font: this.state.currentItemFont, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          return _element; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    textWysiwyg({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      x, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      y, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      initText: element.text, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      strokeColor: element.strokeColor, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      opacity: element.opacity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      font: element.font, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      angle: element.angle, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      zoom: this.state.zoom, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      onChange: withBatchedUpdates((text) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (text) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          updateElement(text); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          deleteElement(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      onSubmit: withBatchedUpdates((text) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        updateElement(text); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.setState((prevState) => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          selectedElementIds: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ...prevState.selectedElementIds, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            [element.id]: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (this.state.elementLocked) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          setCursorForShape(this.state.elementType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        history.resumeRecording(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        resetSelection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      onCancel: withBatchedUpdates(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        deleteElement(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (isExistingElement) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          history.resumeRecording(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        resetSelection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // do an initial update to re-initialize element position since we were 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    //  modifying element's x/y for sake of editor (case: syncing to remote) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    updateElement(element.text); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   private startTextEditing = ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     x, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     y, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1124,13 +1223,10 @@ export class App extends React.Component<any, AppState> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     let textX = clientX || x; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     let textY = clientY || y; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (elementAtPosition && isTextElement(elementAtPosition)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      globalSceneState.replaceAllElements( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        globalSceneState 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          .getAllElements() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          .filter((element) => element.id !== elementAtPosition.id), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    let isExistingTextElement = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (elementAtPosition && isTextElement(elementAtPosition)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      isExistingTextElement = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       const centerElementX = elementAtPosition.x + elementAtPosition.width / 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       const centerElementY = elementAtPosition.y + elementAtPosition.height / 2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1152,64 +1248,40 @@ export class App extends React.Component<any, AppState> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         x: centerElementX, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         y: centerElementY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } else if (centerIfPossible) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      const snappedToCenterPosition = this.getTextWysiwygSnappedToCenterPosition( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        x, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        y, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        this.state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        this.canvas, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        window.devicePixelRatio, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      globalSceneState.replaceAllElements([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...globalSceneState.getAllElements(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        element, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (snappedToCenterPosition) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        mutateElement(element, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          x: snappedToCenterPosition.elementCenterX, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          y: snappedToCenterPosition.elementCenterY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        textX = snappedToCenterPosition.wysiwygX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        textY = snappedToCenterPosition.wysiwygY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (centerIfPossible) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        const snappedToCenterPosition = this.getTextWysiwygSnappedToCenterPosition( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          x, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          y, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          this.canvas, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          window.devicePixelRatio, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (snappedToCenterPosition) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          mutateElement(element, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            x: snappedToCenterPosition.elementCenterX, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            y: snappedToCenterPosition.elementCenterY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          textX = snappedToCenterPosition.wysiwygX; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          textY = snappedToCenterPosition.wysiwygY; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    const resetSelection = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      this.setState({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        draggingElement: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        editingElement: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // deselect all other elements when inserting text 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    this.setState({ selectedElementIds: {} }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.setState({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      editingElement: element, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    textWysiwyg({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      initText: element.text, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.handleTextWysiwyg(element, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       x: textX, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       y: textY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      strokeColor: element.strokeColor, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      font: element.font, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      opacity: this.state.currentItemOpacity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      zoom: this.state.zoom, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      angle: element.angle, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      onSubmit: (text) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if (text) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          globalSceneState.replaceAllElements([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ...globalSceneState.getAllElements(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // we need to recreate the element to update dimensions & position 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            newTextElement({ ...element, text, font: element.font }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          ]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        this.setState((prevState) => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          selectedElementIds: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ...prevState.selectedElementIds, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            [element.id]: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        history.resumeRecording(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        resetSelection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      onCancel: () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        resetSelection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      isExistingElement: isExistingTextElement, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1670,48 +1742,14 @@ export class App extends React.Component<any, AppState> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         font: this.state.currentItemFont, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      const resetSelection = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        this.setState({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          draggingElement: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          editingElement: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      globalSceneState.replaceAllElements([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ...globalSceneState.getAllElements(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        element, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      textWysiwyg({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        initText: "", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.handleTextWysiwyg(element, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         x: snappedToCenterPosition?.wysiwygX ?? event.clientX, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         y: snappedToCenterPosition?.wysiwygY ?? event.clientY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        strokeColor: this.state.currentItemStrokeColor, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        opacity: this.state.currentItemOpacity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        font: this.state.currentItemFont, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        zoom: this.state.zoom, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        angle: 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        onSubmit: (text) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          if (text) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            globalSceneState.replaceAllElements([ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              ...globalSceneState.getAllElements(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              newTextElement({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ...element, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                text, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                font: this.state.currentItemFont, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              }), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          this.setState((prevState) => ({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            selectedElementIds: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              ...prevState.selectedElementIds, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              [element.id]: true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          })); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          if (this.state.elementLocked) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            setCursorForShape(this.state.elementType); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          history.resumeRecording(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          resetSelection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        onCancel: () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          resetSelection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       resetCursor(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (!this.state.elementLocked) { 
			 |