| 
					
				 | 
			
			
				@@ -0,0 +1,203 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { ToolName } from "../queries/toolQueries"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { fireEvent, GlobalTestState } from "../test-utils"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { KEYS, Key } from "../../keys"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { ExcalidrawElement } from "../../element/types"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import { API } from "./api"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const { h } = window; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let altKey = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let shiftKey = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+let ctrlKey = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+export class Keyboard { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static withModifierKeys = ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    modifiers: { alt?: boolean; shift?: boolean; ctrl?: boolean }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    cb: () => void, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const prevAltKey = altKey; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const prevShiftKey = shiftKey; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const prevCtrlKey = ctrlKey; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    altKey = !!modifiers.alt; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    shiftKey = !!modifiers.shift; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ctrlKey = !!modifiers.ctrl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      cb(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } finally { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      altKey = prevAltKey; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      shiftKey = prevShiftKey; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ctrlKey = prevCtrlKey; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static hotkeyDown = (hotkey: Key) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const key = KEYS[hotkey]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (typeof key !== "string") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      throw new Error("must provide a hotkey, not a key code"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Keyboard.keyDown(key); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static hotkeyUp = (hotkey: Key) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const key = KEYS[hotkey]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (typeof key !== "string") { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      throw new Error("must provide a hotkey, not a key code"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Keyboard.keyUp(key); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static keyDown = (key: string) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fireEvent.keyDown(document, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      key, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ctrlKey, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      shiftKey, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      altKey, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      keyCode: key.toUpperCase().charCodeAt(0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      which: key.toUpperCase().charCodeAt(0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static keyUp = (key: string) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fireEvent.keyUp(document, { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      key, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ctrlKey, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      shiftKey, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      altKey, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      keyCode: key.toUpperCase().charCodeAt(0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      which: key.toUpperCase().charCodeAt(0), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static hotkeyPress = (key: Key) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Keyboard.hotkeyDown(key); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Keyboard.hotkeyUp(key); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static keyPress = (key: string) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Keyboard.keyDown(key); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Keyboard.keyUp(key); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+export class Pointer { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private clientX = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private clientY = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  constructor( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private readonly pointerType: "mouse" | "touch" | "pen", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private readonly pointerId = 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ) {} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  reset() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.clientX = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.clientY = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  getPosition() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return [this.clientX, this.clientY]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  restorePosition(x = 0, y = 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.clientX = x; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.clientY = y; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fireEvent.pointerMove(GlobalTestState.canvas, this.getEvent()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  private getEvent() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      clientX: this.clientX, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      clientY: this.clientY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pointerType: this.pointerType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pointerId: this.pointerId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      altKey, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      shiftKey, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ctrlKey, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  move(dx: number, dy: number) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (dx !== 0 || dy !== 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.clientX += dx; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      this.clientY += dy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      fireEvent.pointerMove(GlobalTestState.canvas, this.getEvent()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  down(dx = 0, dy = 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.move(dx, dy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fireEvent.pointerDown(GlobalTestState.canvas, this.getEvent()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  up(dx = 0, dy = 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.move(dx, dy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fireEvent.pointerUp(GlobalTestState.canvas, this.getEvent()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  click(dx = 0, dy = 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.down(dx, dy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.up(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  doubleClick(dx = 0, dy = 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.move(dx, dy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fireEvent.doubleClick(GlobalTestState.canvas, this.getEvent()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  select( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** if multiple elements supplied, they're shift-selected */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    elements: ExcalidrawElement | ExcalidrawElement[], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    API.clearSelection(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Keyboard.withModifierKeys({ shift: true }, () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      elements = Array.isArray(elements) ? elements : [elements]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      elements.forEach((element) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        this.click(element.x, element.y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  clickOn(element: ExcalidrawElement) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.click(element.x, element.y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    this.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const mouse = new Pointer("mouse"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+export class UI { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static clickTool = (toolName: ToolName) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    fireEvent.click(GlobalTestState.renderResult.getByToolName(toolName)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static createElement( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    type: ToolName, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      x = 0, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      y = x, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      size = 10, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }: { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      x?: number; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      y?: number; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      size?: number; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  ) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    UI.clickTool(type); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mouse.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mouse.down(x, y); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mouse.reset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mouse.up(x + size, y + size); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return h.elements[h.elements.length - 1]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static group(elements: ExcalidrawElement[]) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    mouse.select(elements); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    Keyboard.withModifierKeys({ ctrl: true }, () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      Keyboard.keyPress("g"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |