|  | @@ -46,6 +46,7 @@ import { ExcalidrawElement } from "./element/types";
 | 
											
												
													
														|  |  import {
 |  |  import {
 | 
											
												
													
														|  |    isWritableElement,
 |  |    isWritableElement,
 | 
											
												
													
														|  |    isInputLike,
 |  |    isInputLike,
 | 
											
												
													
														|  | 
 |  | +  isToolIcon,
 | 
											
												
													
														|  |    debounce,
 |  |    debounce,
 | 
											
												
													
														|  |    capitalizeString,
 |  |    capitalizeString,
 | 
											
												
													
														|  |    distance,
 |  |    distance,
 | 
											
										
											
												
													
														|  | @@ -100,11 +101,7 @@ import { t, languages, setLanguage, getLanguage } from "./i18n";
 | 
											
												
													
														|  |  import { StoredScenesList } from "./components/StoredScenesList";
 |  |  import { StoredScenesList } from "./components/StoredScenesList";
 | 
											
												
													
														|  |  import { HintViewer } from "./components/HintViewer";
 |  |  import { HintViewer } from "./components/HintViewer";
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -import {
 |  | 
 | 
											
												
													
														|  | -  getAppClipboard,
 |  | 
 | 
											
												
													
														|  | -  copyToAppClipboard,
 |  | 
 | 
											
												
													
														|  | -  parseClipboardEvent,
 |  | 
 | 
											
												
													
														|  | -} from "./clipboard";
 |  | 
 | 
											
												
													
														|  | 
 |  | +import { copyToAppClipboard, getClipboardContent } from "./clipboard";
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  let { elements } = createScene();
 |  |  let { elements } = createScene();
 | 
											
												
													
														|  |  const { history } = createHistory();
 |  |  const { history } = createHistory();
 | 
											
										
											
												
													
														|  | @@ -474,48 +471,6 @@ export class App extends React.Component<any, AppState> {
 | 
											
												
													
														|  |      copyToAppClipboard(elements);
 |  |      copyToAppClipboard(elements);
 | 
											
												
													
														|  |      e.preventDefault();
 |  |      e.preventDefault();
 | 
											
												
													
														|  |    };
 |  |    };
 | 
											
												
													
														|  | -  private onPaste = (e: ClipboardEvent) => {
 |  | 
 | 
											
												
													
														|  | -    // #686
 |  | 
 | 
											
												
													
														|  | -    const target = document.activeElement;
 |  | 
 | 
											
												
													
														|  | -    const elementUnderCursor = document.elementFromPoint(cursorX, cursorY);
 |  | 
 | 
											
												
													
														|  | -    if (
 |  | 
 | 
											
												
													
														|  | -      elementUnderCursor instanceof HTMLCanvasElement &&
 |  | 
 | 
											
												
													
														|  | -      !isWritableElement(target)
 |  | 
 | 
											
												
													
														|  | -    ) {
 |  | 
 | 
											
												
													
														|  | -      const data = parseClipboardEvent(e);
 |  | 
 | 
											
												
													
														|  | -      if (data.elements) {
 |  | 
 | 
											
												
													
														|  | -        this.addElementsFromPaste(data.elements);
 |  | 
 | 
											
												
													
														|  | -      } else if (data.text) {
 |  | 
 | 
											
												
													
														|  | -        const { x, y } = viewportCoordsToSceneCoords(
 |  | 
 | 
											
												
													
														|  | -          { clientX: cursorX, clientY: cursorY },
 |  | 
 | 
											
												
													
														|  | -          this.state,
 |  | 
 | 
											
												
													
														|  | -        );
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -        const element = newTextElement(
 |  | 
 | 
											
												
													
														|  | -          newElement(
 |  | 
 | 
											
												
													
														|  | -            "text",
 |  | 
 | 
											
												
													
														|  | -            x,
 |  | 
 | 
											
												
													
														|  | -            y,
 |  | 
 | 
											
												
													
														|  | -            this.state.currentItemStrokeColor,
 |  | 
 | 
											
												
													
														|  | -            this.state.currentItemBackgroundColor,
 |  | 
 | 
											
												
													
														|  | -            this.state.currentItemFillStyle,
 |  | 
 | 
											
												
													
														|  | -            this.state.currentItemStrokeWidth,
 |  | 
 | 
											
												
													
														|  | -            this.state.currentItemRoughness,
 |  | 
 | 
											
												
													
														|  | -            this.state.currentItemOpacity,
 |  | 
 | 
											
												
													
														|  | -          ),
 |  | 
 | 
											
												
													
														|  | -          data.text,
 |  | 
 | 
											
												
													
														|  | -          this.state.currentItemFont,
 |  | 
 | 
											
												
													
														|  | -        );
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -        element.isSelected = true;
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -        elements = [...clearSelection(elements), element];
 |  | 
 | 
											
												
													
														|  | -        history.resumeRecording();
 |  | 
 | 
											
												
													
														|  | -        this.setState({});
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -      e.preventDefault();
 |  | 
 | 
											
												
													
														|  | -    }
 |  | 
 | 
											
												
													
														|  | -  };
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    private onUnload = () => {
 |  |    private onUnload = () => {
 | 
											
												
													
														|  |      isHoldingSpace = false;
 |  |      isHoldingSpace = false;
 | 
											
										
											
												
													
														|  | @@ -551,7 +506,7 @@ export class App extends React.Component<any, AppState> {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    public async componentDidMount() {
 |  |    public async componentDidMount() {
 | 
											
												
													
														|  |      document.addEventListener("copy", this.onCopy);
 |  |      document.addEventListener("copy", this.onCopy);
 | 
											
												
													
														|  | -    document.addEventListener("paste", this.onPaste);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    document.addEventListener("paste", this.pasteFromClipboard);
 | 
											
												
													
														|  |      document.addEventListener("cut", this.onCut);
 |  |      document.addEventListener("cut", this.onCut);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      document.addEventListener("keydown", this.onKeyDown, false);
 |  |      document.addEventListener("keydown", this.onKeyDown, false);
 | 
											
										
											
												
													
														|  | @@ -583,7 +538,7 @@ export class App extends React.Component<any, AppState> {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    public componentWillUnmount() {
 |  |    public componentWillUnmount() {
 | 
											
												
													
														|  |      document.removeEventListener("copy", this.onCopy);
 |  |      document.removeEventListener("copy", this.onCopy);
 | 
											
												
													
														|  | -    document.removeEventListener("paste", this.onPaste);
 |  | 
 | 
											
												
													
														|  | 
 |  | +    document.removeEventListener("paste", this.pasteFromClipboard);
 | 
											
												
													
														|  |      document.removeEventListener("cut", this.onCut);
 |  |      document.removeEventListener("cut", this.onCut);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |      document.removeEventListener("keydown", this.onKeyDown, false);
 |  |      document.removeEventListener("keydown", this.onKeyDown, false);
 | 
											
										
											
												
													
														|  | @@ -657,14 +612,7 @@ export class App extends React.Component<any, AppState> {
 | 
											
												
													
														|  |        !event.metaKey &&
 |  |        !event.metaKey &&
 | 
											
												
													
														|  |        this.state.draggingElement === null
 |  |        this.state.draggingElement === null
 | 
											
												
													
														|  |      ) {
 |  |      ) {
 | 
											
												
													
														|  | -      if (!isHoldingSpace) {
 |  | 
 | 
											
												
													
														|  | -        setCursorForShape(shape);
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -      if (document.activeElement instanceof HTMLElement) {
 |  | 
 | 
											
												
													
														|  | -        document.activeElement.blur();
 |  | 
 | 
											
												
													
														|  | -      }
 |  | 
 | 
											
												
													
														|  | -      elements = clearSelection(elements);
 |  | 
 | 
											
												
													
														|  | -      this.setState({ elementType: shape });
 |  | 
 | 
											
												
													
														|  | 
 |  | +      this.selectShapeTool(shape);
 | 
											
												
													
														|  |        // Undo action
 |  |        // Undo action
 | 
											
												
													
														|  |      } else if (event[KEYS.META] && /z/i.test(event.key)) {
 |  |      } else if (event[KEYS.META] && /z/i.test(event.key)) {
 | 
											
												
													
														|  |        event.preventDefault();
 |  |        event.preventDefault();
 | 
											
										
											
												
													
														|  | @@ -721,13 +669,65 @@ export class App extends React.Component<any, AppState> {
 | 
											
												
													
														|  |      copyToAppClipboard(elements);
 |  |      copyToAppClipboard(elements);
 | 
											
												
													
														|  |    };
 |  |    };
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  private pasteFromClipboard = () => {
 |  | 
 | 
											
												
													
														|  | -    const data = getAppClipboard();
 |  | 
 | 
											
												
													
														|  | -    if (data.elements) {
 |  | 
 | 
											
												
													
														|  | -      this.addElementsFromPaste(data.elements);
 |  | 
 | 
											
												
													
														|  | 
 |  | +  private pasteFromClipboard = async (e: ClipboardEvent | null) => {
 | 
											
												
													
														|  | 
 |  | +    // #686
 | 
											
												
													
														|  | 
 |  | +    const target = document.activeElement;
 | 
											
												
													
														|  | 
 |  | +    const elementUnderCursor = document.elementFromPoint(cursorX, cursorY);
 | 
											
												
													
														|  | 
 |  | +    if (
 | 
											
												
													
														|  | 
 |  | +      // if no ClipboardEvent supplied, assume we're pasting via contextMenu
 | 
											
												
													
														|  | 
 |  | +      //  thus these checks don't make sense
 | 
											
												
													
														|  | 
 |  | +      !e ||
 | 
											
												
													
														|  | 
 |  | +      (elementUnderCursor instanceof HTMLCanvasElement &&
 | 
											
												
													
														|  | 
 |  | +        !isWritableElement(target))
 | 
											
												
													
														|  | 
 |  | +    ) {
 | 
											
												
													
														|  | 
 |  | +      const data = await getClipboardContent(e);
 | 
											
												
													
														|  | 
 |  | +      if (data.elements) {
 | 
											
												
													
														|  | 
 |  | +        this.addElementsFromPaste(data.elements);
 | 
											
												
													
														|  | 
 |  | +      } else if (data.text) {
 | 
											
												
													
														|  | 
 |  | +        const { x, y } = viewportCoordsToSceneCoords(
 | 
											
												
													
														|  | 
 |  | +          { clientX: cursorX, clientY: cursorY },
 | 
											
												
													
														|  | 
 |  | +          this.state,
 | 
											
												
													
														|  | 
 |  | +        );
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        const element = newTextElement(
 | 
											
												
													
														|  | 
 |  | +          newElement(
 | 
											
												
													
														|  | 
 |  | +            "text",
 | 
											
												
													
														|  | 
 |  | +            x,
 | 
											
												
													
														|  | 
 |  | +            y,
 | 
											
												
													
														|  | 
 |  | +            this.state.currentItemStrokeColor,
 | 
											
												
													
														|  | 
 |  | +            this.state.currentItemBackgroundColor,
 | 
											
												
													
														|  | 
 |  | +            this.state.currentItemFillStyle,
 | 
											
												
													
														|  | 
 |  | +            this.state.currentItemStrokeWidth,
 | 
											
												
													
														|  | 
 |  | +            this.state.currentItemRoughness,
 | 
											
												
													
														|  | 
 |  | +            this.state.currentItemOpacity,
 | 
											
												
													
														|  | 
 |  | +          ),
 | 
											
												
													
														|  | 
 |  | +          data.text,
 | 
											
												
													
														|  | 
 |  | +          this.state.currentItemFont,
 | 
											
												
													
														|  | 
 |  | +        );
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        element.isSelected = true;
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +        elements = [...clearSelection(elements), element];
 | 
											
												
													
														|  | 
 |  | +        history.resumeRecording();
 | 
											
												
													
														|  | 
 |  | +      }
 | 
											
												
													
														|  | 
 |  | +      this.selectShapeTool("selection");
 | 
											
												
													
														|  | 
 |  | +      e?.preventDefault();
 | 
											
												
													
														|  |      }
 |  |      }
 | 
											
												
													
														|  |    };
 |  |    };
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +  private selectShapeTool(elementType: AppState["elementType"]) {
 | 
											
												
													
														|  | 
 |  | +    if (!isHoldingSpace) {
 | 
											
												
													
														|  | 
 |  | +      setCursorForShape(elementType);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    if (isToolIcon(document.activeElement)) {
 | 
											
												
													
														|  | 
 |  | +      document.activeElement.blur();
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    if (elementType !== "selection") {
 | 
											
												
													
														|  | 
 |  | +      elements = clearSelection(elements);
 | 
											
												
													
														|  | 
 |  | +    }
 | 
											
												
													
														|  | 
 |  | +    this.setState({ elementType });
 | 
											
												
													
														|  | 
 |  | +  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |    setAppState = (obj: any) => {
 |  |    setAppState = (obj: any) => {
 | 
											
												
													
														|  |      this.setState(obj);
 |  |      this.setState(obj);
 | 
											
												
													
														|  |    };
 |  |    };
 | 
											
										
											
												
													
														|  | @@ -800,7 +800,7 @@ export class App extends React.Component<any, AppState> {
 | 
											
												
													
														|  |                    options: [
 |  |                    options: [
 | 
											
												
													
														|  |                      navigator.clipboard && {
 |  |                      navigator.clipboard && {
 | 
											
												
													
														|  |                        label: t("labels.paste"),
 |  |                        label: t("labels.paste"),
 | 
											
												
													
														|  | -                      action: () => this.pasteFromClipboard(),
 |  | 
 | 
											
												
													
														|  | 
 |  | +                      action: () => this.pasteFromClipboard(null),
 | 
											
												
													
														|  |                      },
 |  |                      },
 | 
											
												
													
														|  |                      ...this.actionManager.getContextMenuItems(action =>
 |  |                      ...this.actionManager.getContextMenuItems(action =>
 | 
											
												
													
														|  |                        this.canvasOnlyActions.includes(action),
 |  |                        this.canvasOnlyActions.includes(action),
 | 
											
										
											
												
													
														|  | @@ -826,7 +826,7 @@ export class App extends React.Component<any, AppState> {
 | 
											
												
													
														|  |                    },
 |  |                    },
 | 
											
												
													
														|  |                    navigator.clipboard && {
 |  |                    navigator.clipboard && {
 | 
											
												
													
														|  |                      label: t("labels.paste"),
 |  |                      label: t("labels.paste"),
 | 
											
												
													
														|  | -                    action: () => this.pasteFromClipboard(),
 |  | 
 | 
											
												
													
														|  | 
 |  | +                    action: () => this.pasteFromClipboard(null),
 | 
											
												
													
														|  |                    },
 |  |                    },
 | 
											
												
													
														|  |                    ...this.actionManager.getContextMenuItems(
 |  |                    ...this.actionManager.getContextMenuItems(
 | 
											
												
													
														|  |                      action => !this.canvasOnlyActions.includes(action),
 |  |                      action => !this.canvasOnlyActions.includes(action),
 |