Parcourir la source

Set Trailing Cmma to (#525)

Lipis il y a 5 ans
Parent
commit
ee68af0fd3
53 fichiers modifiés avec 352 ajouts et 350 suppressions
  1. 1 1
      .lintstagedrc.js
  2. 3 1
      .prettierrc
  3. 3 3
      scripts/build-node.js
  4. 3 3
      src/actions/actionCanvas.tsx
  5. 2 2
      src/actions/actionDeleteSelected.tsx
  6. 5 5
      src/actions/actionExport.tsx
  7. 39 39
      src/actions/actionProperties.tsx
  8. 2 2
      src/actions/actionSelectAll.ts
  9. 4 4
      src/actions/actionStyles.ts
  10. 9 9
      src/actions/actionZindex.tsx
  11. 4 4
      src/actions/index.ts
  12. 8 8
      src/actions/manager.tsx
  13. 5 5
      src/actions/types.ts
  14. 1 1
      src/appState.ts
  15. 1 1
      src/components/ButtonSelect.tsx
  16. 7 7
      src/components/ColorPicker.tsx
  17. 2 2
      src/components/ContextMenu.tsx
  18. 6 6
      src/components/ExportDialog.tsx
  19. 1 1
      src/components/FixedSideContainer.tsx
  20. 1 1
      src/components/LanguageList.tsx
  21. 1 1
      src/components/LockIcon.tsx
  22. 1 1
      src/components/Modal.tsx
  23. 1 1
      src/components/Popover.tsx
  24. 3 3
      src/components/Stack.tsx
  25. 5 5
      src/element/bounds.test.ts
  26. 1 1
      src/element/bounds.ts
  27. 3 3
      src/element/collision.ts
  28. 10 10
      src/element/handlerRectangles.ts
  29. 2 2
      src/element/index.ts
  30. 4 4
      src/element/newElement.ts
  31. 3 3
      src/element/resizeTest.ts
  32. 2 2
      src/element/sizeHelpers.ts
  33. 2 2
      src/element/textWysiwyg.tsx
  34. 1 1
      src/element/typeChecks.ts
  35. 3 3
      src/history.ts
  36. 2 2
      src/i18n.ts
  37. 6 6
      src/index-node.ts
  38. 85 85
      src/index.tsx
  39. 1 1
      src/keys.ts
  40. 3 3
      src/math.ts
  41. 13 13
      src/renderer/renderElement.ts
  42. 12 12
      src/renderer/renderScene.ts
  43. 2 2
      src/renderer/roundRect.ts
  44. 4 4
      src/scene/comparisons.ts
  45. 21 21
      src/scene/data.ts
  46. 6 6
      src/scene/getExportCanvasPreview.ts
  47. 3 3
      src/scene/index.ts
  48. 13 13
      src/scene/scrollbars.ts
  49. 6 6
      src/scene/selection.ts
  50. 9 9
      src/shapes.tsx
  51. 2 2
      src/utils.ts
  52. 13 13
      src/zindex.test.ts
  53. 2 2
      src/zindex.ts

+ 1 - 1
.lintstagedrc.js

@@ -11,5 +11,5 @@ module.exports = {
       files.filter(file => !cli.isPathIgnored(file)).join(" ")
     );
   },
-  "*.{js,css,scss,json,md,ts,tsx,html,yml}": ["prettier --write"]
+  "*.{js,css,scss,json,md,ts,tsx,html,yml}": ["prettier --write"],
 };

+ 3 - 1
.prettierrc

@@ -1 +1,3 @@
-{}
+{
+  "trailingComma": "all"
+}

+ 3 - 3
scripts/build-node.js

@@ -17,8 +17,8 @@ var config = defaults.__get__("config");
 config.optimization.runtimeChunk = false;
 config.optimization.splitChunks = {
   cacheGroups: {
-    default: false
-  }
+    default: false,
+  },
 };
 // Set the filename to be deterministic
 config.output.filename = "static/js/build-node.js";
@@ -33,7 +33,7 @@ config.externals = function(context, request, callback) {
   if (/\.node$/.test(request)) {
     return callback(
       null,
-      "commonjs ../../../node_modules/canvas/build/Release/canvas.node"
+      "commonjs ../../../node_modules/canvas/build/Release/canvas.node",
     );
   }
   callback();

+ 3 - 3
src/actions/actionCanvas.tsx

@@ -20,7 +20,7 @@ export const actionChangeViewBackgroundColor: Action = {
         />
       </div>
     );
-  }
+  },
 };
 
 export const actionClearCanvas: Action = {
@@ -28,7 +28,7 @@ export const actionClearCanvas: Action = {
   perform: () => {
     return {
       elements: [],
-      appState: getDefaultAppState()
+      appState: getDefaultAppState(),
     };
   },
   PanelComponent: ({ updateData, t }) => (
@@ -47,5 +47,5 @@ export const actionClearCanvas: Action = {
         }
       }}
     />
-  )
+  ),
 };

+ 2 - 2
src/actions/actionDeleteSelected.tsx

@@ -6,10 +6,10 @@ export const actionDeleteSelected: Action = {
   name: "deleteSelectedElements",
   perform: elements => {
     return {
-      elements: deleteSelectedElements(elements)
+      elements: deleteSelectedElements(elements),
     };
   },
   contextItemLabel: "labels.delete",
   contextMenuOrder: 3,
-  keyTest: event => event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE
+  keyTest: event => event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE,
 };

+ 5 - 5
src/actions/actionExport.tsx

@@ -15,7 +15,7 @@ export const actionChangeProjectName: Action = {
       value={appState.name || "Unnamed"}
       onChange={(name: string) => updateData(name)}
     />
-  )
+  ),
 };
 
 export const actionChangeExportBackground: Action = {
@@ -34,7 +34,7 @@ export const actionChangeExportBackground: Action = {
       />{" "}
       {t("labels.withBackground")}
     </label>
-  )
+  ),
 };
 
 export const actionSaveScene: Action = {
@@ -51,7 +51,7 @@ export const actionSaveScene: Action = {
       aria-label={t("buttons.save")}
       onClick={() => updateData(null)}
     />
-  )
+  ),
 };
 
 export const actionLoadScene: Action = {
@@ -59,7 +59,7 @@ export const actionLoadScene: Action = {
   perform: (
     elements,
     appState,
-    { elements: loadedElements, appState: loadedAppState }
+    { elements: loadedElements, appState: loadedAppState },
   ) => {
     return { elements: loadedElements, appState: loadedAppState };
   },
@@ -77,5 +77,5 @@ export const actionLoadScene: Action = {
           .catch(err => console.error(err));
       }}
     />
-  )
+  ),
 };

+ 39 - 39
src/actions/actionProperties.tsx

@@ -9,7 +9,7 @@ import { AppState } from "../../src/types";
 
 const changeProperty = (
   elements: readonly ExcalidrawElement[],
-  callback: (element: ExcalidrawElement) => ExcalidrawElement
+  callback: (element: ExcalidrawElement) => ExcalidrawElement,
 ) => {
   return elements.map(element => {
     if (element.isSelected) {
@@ -23,7 +23,7 @@ const getFormValue = function<T>(
   editingElement: AppState["editingElement"],
   elements: readonly ExcalidrawElement[],
   getAttribute: (element: ExcalidrawElement) => T,
-  defaultValue?: T
+  defaultValue?: T,
 ): T | null {
   return (
     (editingElement && getAttribute(editingElement)) ??
@@ -40,9 +40,9 @@ export const actionChangeStrokeColor: Action = {
       elements: changeProperty(elements, el => ({
         ...el,
         shape: null,
-        strokeColor: value
+        strokeColor: value,
       })),
-      appState: { ...appState, currentItemStrokeColor: value }
+      appState: { ...appState, currentItemStrokeColor: value },
     };
   },
   PanelComponent: ({ elements, appState, updateData, t }) => (
@@ -54,12 +54,12 @@ export const actionChangeStrokeColor: Action = {
           appState.editingElement,
           elements,
           element => element.strokeColor,
-          appState.currentItemStrokeColor
+          appState.currentItemStrokeColor,
         )}
         onChange={updateData}
       />
     </>
-  )
+  ),
 };
 
 export const actionChangeBackgroundColor: Action = {
@@ -69,9 +69,9 @@ export const actionChangeBackgroundColor: Action = {
       elements: changeProperty(elements, el => ({
         ...el,
         shape: null,
-        backgroundColor: value
+        backgroundColor: value,
       })),
-      appState: { ...appState, currentItemBackgroundColor: value }
+      appState: { ...appState, currentItemBackgroundColor: value },
     };
   },
   PanelComponent: ({ elements, appState, updateData, t }) => (
@@ -83,12 +83,12 @@ export const actionChangeBackgroundColor: Action = {
           appState.editingElement,
           elements,
           element => element.backgroundColor,
-          appState.currentItemBackgroundColor
+          appState.currentItemBackgroundColor,
         )}
         onChange={updateData}
       />
     </>
-  )
+  ),
 };
 
 export const actionChangeFillStyle: Action = {
@@ -98,8 +98,8 @@ export const actionChangeFillStyle: Action = {
       elements: changeProperty(elements, el => ({
         ...el,
         shape: null,
-        fillStyle: value
-      }))
+        fillStyle: value,
+      })),
     };
   },
   PanelComponent: ({ elements, appState, updateData, t }) => (
@@ -109,19 +109,19 @@ export const actionChangeFillStyle: Action = {
         options={[
           { value: "solid", text: t("labels.solid") },
           { value: "hachure", text: t("labels.hachure") },
-          { value: "cross-hatch", text: t("labels.crossHatch") }
+          { value: "cross-hatch", text: t("labels.crossHatch") },
         ]}
         value={getFormValue(
           appState.editingElement,
           elements,
-          element => element.fillStyle
+          element => element.fillStyle,
         )}
         onChange={value => {
           updateData(value);
         }}
       />
     </>
-  )
+  ),
 };
 
 export const actionChangeStrokeWidth: Action = {
@@ -131,8 +131,8 @@ export const actionChangeStrokeWidth: Action = {
       elements: changeProperty(elements, el => ({
         ...el,
         shape: null,
-        strokeWidth: value
-      }))
+        strokeWidth: value,
+      })),
     };
   },
   PanelComponent: ({ elements, appState, updateData, t }) => (
@@ -142,17 +142,17 @@ export const actionChangeStrokeWidth: Action = {
         options={[
           { value: 1, text: t("labels.thin") },
           { value: 2, text: t("labels.bold") },
-          { value: 4, text: t("labels.extraBold") }
+          { value: 4, text: t("labels.extraBold") },
         ]}
         value={getFormValue(
           appState.editingElement,
           elements,
-          element => element.strokeWidth
+          element => element.strokeWidth,
         )}
         onChange={value => updateData(value)}
       />
     </>
-  )
+  ),
 };
 
 export const actionChangeSloppiness: Action = {
@@ -162,8 +162,8 @@ export const actionChangeSloppiness: Action = {
       elements: changeProperty(elements, el => ({
         ...el,
         shape: null,
-        roughness: value
-      }))
+        roughness: value,
+      })),
     };
   },
   PanelComponent: ({ elements, appState, updateData, t }) => (
@@ -173,17 +173,17 @@ export const actionChangeSloppiness: Action = {
         options={[
           { value: 0, text: t("labels.architect") },
           { value: 1, text: t("labels.artist") },
-          { value: 3, text: t("labels.cartoonist") }
+          { value: 3, text: t("labels.cartoonist") },
         ]}
         value={getFormValue(
           appState.editingElement,
           elements,
-          element => element.roughness
+          element => element.roughness,
         )}
         onChange={value => updateData(value)}
       />
     </>
-  )
+  ),
 };
 
 export const actionChangeOpacity: Action = {
@@ -193,8 +193,8 @@ export const actionChangeOpacity: Action = {
       elements: changeProperty(elements, el => ({
         ...el,
         shape: null,
-        opacity: value
-      }))
+        opacity: value,
+      })),
     };
   },
   PanelComponent: ({ elements, appState, updateData, t }) => (
@@ -210,12 +210,12 @@ export const actionChangeOpacity: Action = {
             appState.editingElement,
             elements,
             element => element.opacity,
-            100 /* default opacity */
+            100 /* default opacity */,
           ) ?? undefined
         }
       />
     </>
-  )
+  ),
 };
 
 export const actionChangeFontSize: Action = {
@@ -227,14 +227,14 @@ export const actionChangeFontSize: Action = {
           const element: ExcalidrawTextElement = {
             ...el,
             shape: null,
-            font: `${value}px ${el.font.split("px ")[1]}`
+            font: `${value}px ${el.font.split("px ")[1]}`,
           };
           redrawTextBoundingBox(element);
           return element;
         }
 
         return el;
-      })
+      }),
     };
   },
   PanelComponent: ({ elements, appState, updateData, t }) => (
@@ -245,17 +245,17 @@ export const actionChangeFontSize: Action = {
           { value: 16, text: t("labels.small") },
           { value: 20, text: t("labels.medium") },
           { value: 28, text: t("labels.large") },
-          { value: 36, text: t("labels.veryLarge") }
+          { value: 36, text: t("labels.veryLarge") },
         ]}
         value={getFormValue(
           appState.editingElement,
           elements,
-          element => isTextElement(element) && +element.font.split("px ")[0]
+          element => isTextElement(element) && +element.font.split("px ")[0],
         )}
         onChange={value => updateData(value)}
       />
     </>
-  )
+  ),
 };
 
 export const actionChangeFontFamily: Action = {
@@ -267,14 +267,14 @@ export const actionChangeFontFamily: Action = {
           const element: ExcalidrawTextElement = {
             ...el,
             shape: null,
-            font: `${el.font.split("px ")[0]}px ${value}`
+            font: `${el.font.split("px ")[0]}px ${value}`,
           };
           redrawTextBoundingBox(element);
           return element;
         }
 
         return el;
-      })
+      }),
     };
   },
   PanelComponent: ({ elements, appState, updateData, t }) => (
@@ -284,15 +284,15 @@ export const actionChangeFontFamily: Action = {
         options={[
           { value: "Virgil", text: t("labels.handDrawn") },
           { value: "Helvetica", text: t("labels.normal") },
-          { value: "Cascadia", text: t("labels.code") }
+          { value: "Cascadia", text: t("labels.code") },
         ]}
         value={getFormValue(
           appState.editingElement,
           elements,
-          element => isTextElement(element) && element.font.split("px ")[1]
+          element => isTextElement(element) && element.font.split("px ")[1],
         )}
         onChange={value => updateData(value)}
       />
     </>
-  )
+  ),
 };

+ 2 - 2
src/actions/actionSelectAll.ts

@@ -5,9 +5,9 @@ export const actionSelectAll: Action = {
   name: "selectAll",
   perform: elements => {
     return {
-      elements: elements.map(elem => ({ ...elem, isSelected: true }))
+      elements: elements.map(elem => ({ ...elem, isSelected: true })),
     };
   },
   contextItemLabel: "labels.selectAll",
-  keyTest: event => event[KEYS.META] && event.code === "KeyA"
+  keyTest: event => event[KEYS.META] && event.code === "KeyA",
 };

+ 4 - 4
src/actions/actionStyles.ts

@@ -15,7 +15,7 @@ export const actionCopyStyles: Action = {
   },
   contextItemLabel: "labels.copyStyles",
   keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyC",
-  contextMenuOrder: 0
+  contextMenuOrder: 0,
 };
 
 export const actionPasteStyles: Action = {
@@ -33,7 +33,7 @@ export const actionPasteStyles: Action = {
             strokeColor: pastedElement?.strokeColor,
             fillStyle: pastedElement?.fillStyle,
             opacity: pastedElement?.opacity,
-            roughness: pastedElement?.roughness
+            roughness: pastedElement?.roughness,
           };
           if (isTextElement(newElement)) {
             newElement.font = pastedElement?.font;
@@ -42,10 +42,10 @@ export const actionPasteStyles: Action = {
           return newElement;
         }
         return element;
-      })
+      }),
     };
   },
   contextItemLabel: "labels.pasteStyles",
   keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyV",
-  contextMenuOrder: 1
+  contextMenuOrder: 1,
 };

+ 9 - 9
src/actions/actionZindex.tsx

@@ -3,7 +3,7 @@ import {
   moveOneLeft,
   moveOneRight,
   moveAllLeft,
-  moveAllRight
+  moveAllRight,
 } from "../zindex";
 import { getSelectedIndices } from "../scene";
 import { KEYS } from "../keys";
@@ -13,13 +13,13 @@ export const actionSendBackward: Action = {
   perform: (elements, appState) => {
     return {
       elements: moveOneLeft([...elements], getSelectedIndices(elements)),
-      appState
+      appState,
     };
   },
   contextItemLabel: "labels.sendBackward",
   keyPriority: 40,
   keyTest: event =>
-    event[KEYS.META] && event.shiftKey && event.altKey && event.code === "KeyB"
+    event[KEYS.META] && event.shiftKey && event.altKey && event.code === "KeyB",
 };
 
 export const actionBringForward: Action = {
@@ -27,13 +27,13 @@ export const actionBringForward: Action = {
   perform: (elements, appState) => {
     return {
       elements: moveOneRight([...elements], getSelectedIndices(elements)),
-      appState
+      appState,
     };
   },
   contextItemLabel: "labels.bringForward",
   keyPriority: 40,
   keyTest: event =>
-    event[KEYS.META] && event.shiftKey && event.altKey && event.code === "KeyF"
+    event[KEYS.META] && event.shiftKey && event.altKey && event.code === "KeyF",
 };
 
 export const actionSendToBack: Action = {
@@ -41,11 +41,11 @@ export const actionSendToBack: Action = {
   perform: (elements, appState) => {
     return {
       elements: moveAllLeft([...elements], getSelectedIndices(elements)),
-      appState
+      appState,
     };
   },
   contextItemLabel: "labels.sendToBack",
-  keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyB"
+  keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyB",
 };
 
 export const actionBringToFront: Action = {
@@ -53,9 +53,9 @@ export const actionBringToFront: Action = {
   perform: (elements, appState) => {
     return {
       elements: moveAllRight([...elements], getSelectedIndices(elements)),
-      appState
+      appState,
     };
   },
   contextItemLabel: "labels.bringToFront",
-  keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyF"
+  keyTest: event => event[KEYS.META] && event.shiftKey && event.code === "KeyF",
 };

+ 4 - 4
src/actions/index.ts

@@ -4,7 +4,7 @@ export {
   actionBringForward,
   actionBringToFront,
   actionSendBackward,
-  actionSendToBack
+  actionSendToBack,
 } from "./actionZindex";
 export { actionSelectAll } from "./actionSelectAll";
 export {
@@ -15,19 +15,19 @@ export {
   actionChangeSloppiness,
   actionChangeOpacity,
   actionChangeFontSize,
-  actionChangeFontFamily
+  actionChangeFontFamily,
 } from "./actionProperties";
 
 export {
   actionChangeViewBackgroundColor,
-  actionClearCanvas
+  actionClearCanvas,
 } from "./actionCanvas";
 
 export {
   actionChangeProjectName,
   actionChangeExportBackground,
   actionSaveScene,
-  actionLoadScene
+  actionLoadScene,
 } from "./actionExport";
 
 export { actionCopyStyles, actionPasteStyles } from "./actionStyles";

+ 8 - 8
src/actions/manager.tsx

@@ -3,7 +3,7 @@ import {
   Action,
   ActionsManagerInterface,
   UpdaterFn,
-  ActionFilterFn
+  ActionFilterFn,
 } from "./types";
 import { ExcalidrawElement } from "../element/types";
 import { AppState } from "../types";
@@ -17,7 +17,7 @@ export class ActionManager implements ActionsManagerInterface {
     | null = null;
 
   setUpdater(
-    updater: (elements: ExcalidrawElement[], appState: AppState) => void
+    updater: (elements: ExcalidrawElement[], appState: AppState) => void,
   ) {
     this.updater = updater;
   }
@@ -29,12 +29,12 @@ export class ActionManager implements ActionsManagerInterface {
   handleKeyDown(
     event: KeyboardEvent,
     elements: readonly ExcalidrawElement[],
-    appState: AppState
+    appState: AppState,
   ) {
     const data = Object.values(this.actions)
       .sort((a, b) => (b.keyPriority || 0) - (a.keyPriority || 0))
       .filter(
-        action => action.keyTest && action.keyTest(event, elements, appState)
+        action => action.keyTest && action.keyTest(event, elements, appState),
       );
 
     if (data.length === 0) return {};
@@ -48,7 +48,7 @@ export class ActionManager implements ActionsManagerInterface {
     appState: AppState,
     updater: UpdaterFn,
     actionFilter: ActionFilterFn = action => action,
-    t?: TFunction
+    t?: TFunction,
   ) {
     return Object.values(this.actions)
       .filter(actionFilter)
@@ -56,7 +56,7 @@ export class ActionManager implements ActionsManagerInterface {
       .sort(
         (a, b) =>
           (a.contextMenuOrder !== undefined ? a.contextMenuOrder : 999) -
-          (b.contextMenuOrder !== undefined ? b.contextMenuOrder : 999)
+          (b.contextMenuOrder !== undefined ? b.contextMenuOrder : 999),
       )
       .map(action => ({
         label:
@@ -65,7 +65,7 @@ export class ActionManager implements ActionsManagerInterface {
             : action.contextItemLabel!,
         action: () => {
           updater(action.perform(elements, appState, null));
-        }
+        },
       }));
   }
 
@@ -74,7 +74,7 @@ export class ActionManager implements ActionsManagerInterface {
     elements: readonly ExcalidrawElement[],
     appState: AppState,
     updater: UpdaterFn,
-    t: TFunction
+    t: TFunction,
   ) {
     if (this.actions[name] && "PanelComponent" in this.actions[name]) {
       const action = this.actions[name];

+ 5 - 5
src/actions/types.ts

@@ -11,7 +11,7 @@ export type ActionResult = {
 type ActionFn = (
   elements: readonly ExcalidrawElement[],
   appState: AppState,
-  formData: any
+  formData: any,
 ) => ActionResult;
 
 export type UpdaterFn = (res: ActionResult) => void;
@@ -30,7 +30,7 @@ export interface Action {
   keyTest?: (
     event: KeyboardEvent,
     elements?: readonly ExcalidrawElement[],
-    appState?: AppState
+    appState?: AppState,
   ) => boolean;
   contextItemLabel?: string;
   contextMenuOrder?: number;
@@ -44,19 +44,19 @@ export interface ActionsManagerInterface {
   handleKeyDown: (
     event: KeyboardEvent,
     elements: readonly ExcalidrawElement[],
-    appState: AppState
+    appState: AppState,
   ) => ActionResult | {};
   getContextMenuItems: (
     elements: readonly ExcalidrawElement[],
     appState: AppState,
     updater: UpdaterFn,
-    actionFilter: ActionFilterFn
+    actionFilter: ActionFilterFn,
   ) => { label: string; action: () => void }[];
   renderAction: (
     name: string,
     elements: readonly ExcalidrawElement[],
     appState: AppState,
     updater: UpdaterFn,
-    t: TFunction
+    t: TFunction,
   ) => React.ReactElement | null;
 }

+ 1 - 1
src/appState.ts

@@ -19,6 +19,6 @@ export function getDefaultAppState(): AppState {
     scrollY: 0,
     cursorX: 0,
     cursorY: 0,
-    name: DEFAULT_PROJECT_NAME
+    name: DEFAULT_PROJECT_NAME,
   };
 }

+ 1 - 1
src/components/ButtonSelect.tsx

@@ -3,7 +3,7 @@ import React from "react";
 export function ButtonSelect<T>({
   options,
   value,
-  onChange
+  onChange,
 }: {
   options: { value: T; text: string }[];
   value: T | null;

+ 7 - 7
src/components/ColorPicker.tsx

@@ -9,7 +9,7 @@ import "./ColorPicker.css";
 const Picker = function({
   colors,
   color,
-  onChange
+  onChange,
 }: {
   colors: string[];
   color: string | null;
@@ -53,7 +53,7 @@ const Picker = function({
 
 function ColorInput({
   color,
-  onChange
+  onChange,
 }: {
   color: string | null;
   onChange: (color: string) => void;
@@ -90,7 +90,7 @@ function ColorInput({
 export function ColorPicker({
   type,
   color,
-  onChange
+  onChange,
 }: {
   type: "canvasBackground" | "elementBackground" | "elementStroke";
   color: string | null;
@@ -149,7 +149,7 @@ const colors = {
     "#ebfbee",
     "#f4fce3",
     "#fff9db",
-    "#fff4e6"
+    "#fff4e6",
   ],
   // Shade 6
   elementBackground: [
@@ -167,7 +167,7 @@ const colors = {
     "#40c057",
     "#82c91e",
     "#fab005",
-    "#fd7e14"
+    "#fd7e14",
   ],
   // Shade 9
   elementStroke: [
@@ -185,6 +185,6 @@ const colors = {
     "#2b8a3e",
     "#5c940d",
     "#e67700",
-    "#d9480f"
-  ]
+    "#d9480f",
+  ],
 };

+ 2 - 2
src/components/ContextMenu.tsx

@@ -83,8 +83,8 @@ export default {
           options={options}
           onCloseRequest={handleClose}
         />,
-        getContextMenuNode()
+        getContextMenuNode(),
       );
     }
-  }
+  },
 };

+ 6 - 6
src/components/ExportDialog.tsx

@@ -25,7 +25,7 @@ const defaultScale = scales.includes(devicePixelRatio) ? devicePixelRatio : 1;
 
 type ExportCB = (
   elements: readonly ExcalidrawElement[],
-  scale?: number
+  scale?: number,
 ) => void;
 
 export function ExportDialog({
@@ -36,7 +36,7 @@ export function ExportDialog({
   syncActionResult,
   onExportToPng,
   onExportToClipboard,
-  onExportToBackend
+  onExportToBackend,
 }: {
   appState: AppState;
   elements: readonly ExcalidrawElement[];
@@ -69,7 +69,7 @@ export function ExportDialog({
       exportBackground,
       viewBackgroundColor,
       exportPadding,
-      scale
+      scale,
     });
     previewNode?.appendChild(canvas);
     return () => {
@@ -81,7 +81,7 @@ export function ExportDialog({
     exportBackground,
     exportPadding,
     viewBackgroundColor,
-    scale
+    scale,
   ]);
 
   function handleClose() {
@@ -141,7 +141,7 @@ export function ExportDialog({
                   elements,
                   appState,
                   syncActionResult,
-                  t
+                  t,
                 )}
                 <Stack.Col gap={1}>
                   <div className="ExportDialog__scales">
@@ -165,7 +165,7 @@ export function ExportDialog({
                     elements,
                     appState,
                     syncActionResult,
-                    t
+                    t,
                   )}
                   {someElementIsSelected && (
                     <div>

+ 1 - 1
src/components/FixedSideContainer.tsx

@@ -9,7 +9,7 @@ type FixedSideContainerProps = {
 
 export function FixedSideContainer({
   children,
-  side
+  side,
 }: FixedSideContainerProps) {
   return (
     <div className={"FixedSideContainer FixedSideContainer_side_" + side}>

+ 1 - 1
src/components/LanguageList.tsx

@@ -3,7 +3,7 @@ import React from "react";
 export function LanguageList<T>({
   onClick,
   languages,
-  currentLanguage
+  currentLanguage,
 }: {
   languages: { lng: string; label: string }[];
   onClick: (value: string) => void;

+ 1 - 1
src/components/LockIcon.tsx

@@ -35,7 +35,7 @@ const ICONS = {
     >
       <path d="M1728 576v256q0 26-19 45t-45 19h-64q-26 0-45-19t-19-45v-256q0-106-75-181t-181-75-181 75-75 181v192h96q40 0 68 28t28 68v576q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-576q0-40 28-68t68-28h672v-192q0-185 131.5-316.5t316.5-131.5 316.5 131.5 131.5 316.5z" />
     </svg>
-  )
+  ),
 };
 
 export function LockIcon(props: LockIconProps) {

+ 1 - 1
src/components/Modal.tsx

@@ -16,7 +16,7 @@ export function Modal(props: {
         {props.children}
       </div>
     </div>,
-    modalRoot
+    modalRoot,
   );
 }
 

+ 1 - 1
src/components/Popover.tsx

@@ -14,7 +14,7 @@ export function Popover({
   left,
   top,
   onCloseRequest,
-  fitInViewport = false
+  fitInViewport = false,
 }: Props) {
   const popoverRef = useRef<HTMLDivElement>(null);
 

+ 3 - 3
src/components/Stack.tsx

@@ -17,7 +17,7 @@ function RowStack({ children, gap, align, justifyContent }: StackProps) {
         {
           "--gap": gap,
           alignItems: align,
-          justifyContent
+          justifyContent,
         } as React.CSSProperties
       }
     >
@@ -34,7 +34,7 @@ function ColStack({ children, gap, align, justifyContent }: StackProps) {
         {
           "--gap": gap,
           justifyItems: align,
-          justifyContent
+          justifyContent,
         } as React.CSSProperties
       }
     >
@@ -45,5 +45,5 @@ function ColStack({ children, gap, align, justifyContent }: StackProps) {
 
 export default {
   Row: RowStack,
-  Col: ColStack
+  Col: ColStack,
 };

+ 5 - 5
src/element/bounds.test.ts

@@ -13,7 +13,7 @@ const _ce = ({ x, y, w, h }: { x: number; y: number; w: number; h: number }) =>
     x,
     y,
     width: w,
-    height: h
+    height: h,
   } as ExcalidrawElement);
 
 describe("getElementAbsoluteCoords", () => {
@@ -29,14 +29,14 @@ describe("getElementAbsoluteCoords", () => {
 
   it("test x2 coordinate if width is positive or zero", () => {
     const [, , x2] = getElementAbsoluteCoords(
-      _ce({ x: 10, y: 0, w: 10, h: 0 })
+      _ce({ x: 10, y: 0, w: 10, h: 0 }),
     );
     expect(x2).toEqual(20);
   });
 
   it("test x2 coordinate if width is negative", () => {
     const [, , x2] = getElementAbsoluteCoords(
-      _ce({ x: 10, y: 0, w: -10, h: 0 })
+      _ce({ x: 10, y: 0, w: -10, h: 0 }),
     );
     expect(x2).toEqual(10);
   });
@@ -53,14 +53,14 @@ describe("getElementAbsoluteCoords", () => {
 
   it("test y2 coordinate if height is positive or zero", () => {
     const [, , , y2] = getElementAbsoluteCoords(
-      _ce({ x: 0, y: 10, w: 0, h: 10 })
+      _ce({ x: 0, y: 10, w: 0, h: 10 }),
     );
     expect(y2).toEqual(20);
   });
 
   it("test y2 coordinate if height is negative", () => {
     const [, , , y2] = getElementAbsoluteCoords(
-      _ce({ x: 0, y: 10, w: 0, h: -10 })
+      _ce({ x: 0, y: 10, w: 0, h: -10 }),
     );
     expect(y2).toEqual(10);
   });

+ 1 - 1
src/element/bounds.ts

@@ -10,7 +10,7 @@ export function getElementAbsoluteCoords(element: ExcalidrawElement) {
     element.width >= 0 ? element.x : element.x + element.width, // x1
     element.height >= 0 ? element.y : element.y + element.height, // y1
     element.width >= 0 ? element.x + element.width : element.x, // x2
-    element.height >= 0 ? element.y + element.height : element.y // y2
+    element.height >= 0 ? element.y + element.height : element.y, // y2
   ];
 }
 

+ 3 - 3
src/element/collision.ts

@@ -5,7 +5,7 @@ import {
   getArrowPoints,
   getDiamondPoints,
   getElementAbsoluteCoords,
-  getLinePoints
+  getLinePoints,
 } from "./bounds";
 
 function isElementDraggableFromInside(element: ExcalidrawElement): boolean {
@@ -15,7 +15,7 @@ function isElementDraggableFromInside(element: ExcalidrawElement): boolean {
 export function hitTest(
   element: ExcalidrawElement,
   x: number,
-  y: number
+  y: number,
 ): boolean {
   // For shapes that are composed of lines, we only enable point-selection when the distance
   // of the click is less than x pixels of any of the lines that the shape is composed of
@@ -95,7 +95,7 @@ export function hitTest(
       bottomX,
       bottomY,
       leftX,
-      leftY
+      leftY,
     ] = getDiamondPoints(element);
 
     if (isElementDraggableFromInside(element)) {

+ 10 - 10
src/element/handlerRectangles.ts

@@ -5,7 +5,7 @@ type Sides = "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se";
 
 export function handlerRectangles(
   element: ExcalidrawElement,
-  { scrollX, scrollY }: SceneScroll
+  { scrollX, scrollY }: SceneScroll,
 ) {
   const elementX1 = element.x;
   const elementX2 = element.x + element.width;
@@ -24,14 +24,14 @@ export function handlerRectangles(
       elementX1 + (elementX2 - elementX1) / 2 + scrollX - 4,
       elementY1 - margin + scrollY + marginY,
       8,
-      8
+      8,
     ];
 
     handlers["s"] = [
       elementX1 + (elementX2 - elementX1) / 2 + scrollX - 4,
       elementY2 - margin + scrollY - marginY,
       8,
-      8
+      8,
     ];
   }
 
@@ -40,14 +40,14 @@ export function handlerRectangles(
       elementX1 - margin + scrollX + marginX,
       elementY1 + (elementY2 - elementY1) / 2 + scrollY - 4,
       8,
-      8
+      8,
     ];
 
     handlers["e"] = [
       elementX2 - margin + scrollX - marginX,
       elementY1 + (elementY2 - elementY1) / 2 + scrollY - 4,
       8,
-      8
+      8,
     ];
   }
 
@@ -55,31 +55,31 @@ export function handlerRectangles(
     elementX1 - margin + scrollX + marginX,
     elementY1 - margin + scrollY + marginY,
     8,
-    8
+    8,
   ]; // nw
   handlers["ne"] = [
     elementX2 - margin + scrollX - marginX,
     elementY1 - margin + scrollY + marginY,
     8,
-    8
+    8,
   ]; // ne
   handlers["sw"] = [
     elementX1 - margin + scrollX + marginX,
     elementY2 - margin + scrollY - marginY,
     8,
-    8
+    8,
   ]; // sw
   handlers["se"] = [
     elementX2 - margin + scrollX - marginX,
     elementY2 - margin + scrollY - marginY,
     8,
-    8
+    8,
   ]; // se
 
   if (element.type === "arrow" || element.type === "line") {
     return {
       nw: handlers.nw,
-      se: handlers.se
+      se: handlers.se,
     } as typeof handlers;
   }
 

+ 2 - 2
src/element/index.ts

@@ -3,7 +3,7 @@ export {
   getElementAbsoluteCoords,
   getDiamondPoints,
   getArrowPoints,
-  getLinePoints
+  getLinePoints,
 } from "./bounds";
 
 export { handlerRectangles } from "./handlerRectangles";
@@ -15,5 +15,5 @@ export { redrawTextBoundingBox } from "./textElement";
 export {
   getPerfectElementSize,
   isInvisiblySmallElement,
-  resizePerfectLineForNWHandler
+  resizePerfectLineForNWHandler,
 } from "./sizeHelpers";

+ 4 - 4
src/element/newElement.ts

@@ -16,7 +16,7 @@ export function newElement(
   roughness: number,
   opacity: number,
   width = 0,
-  height = 0
+  height = 0,
 ) {
   const element = {
     id: nanoid(),
@@ -33,7 +33,7 @@ export function newElement(
     opacity,
     isSelected: false,
     seed: randomSeed(),
-    shape: null as Drawable | Drawable[] | null
+    shape: null as Drawable | Drawable[] | null,
   };
   return element;
 }
@@ -41,7 +41,7 @@ export function newElement(
 export function newTextElement(
   element: ExcalidrawElement,
   text: string,
-  font: string
+  font: string,
 ) {
   const metrics = measureText(text, font);
   const textElement: ExcalidrawTextElement = {
@@ -54,7 +54,7 @@ export function newTextElement(
     y: element.y - metrics.height / 2,
     width: metrics.width,
     height: metrics.height,
-    baseline: metrics.baseline
+    baseline: metrics.baseline,
   };
 
   return textElement;

+ 3 - 3
src/element/resizeTest.ts

@@ -9,7 +9,7 @@ export function resizeTest(
   element: ExcalidrawElement,
   x: number,
   y: number,
-  { scrollX, scrollY }: SceneScroll
+  { scrollX, scrollY }: SceneScroll,
 ): HandlerRectanglesRet | false {
   if (!element.isSelected || element.type === "text") return false;
 
@@ -36,7 +36,7 @@ export function resizeTest(
 export function getElementWithResizeHandler(
   elements: readonly ExcalidrawElement[],
   { x, y }: { x: number; y: number },
-  { scrollX, scrollY }: SceneScroll
+  { scrollX, scrollY }: SceneScroll,
 ) {
   return elements.reduce((result, element) => {
     if (result) {
@@ -44,7 +44,7 @@ export function getElementWithResizeHandler(
     }
     const resizeHandle = resizeTest(element, x, y, {
       scrollX,
-      scrollY
+      scrollY,
     });
     return resizeHandle ? { element, resizeHandle } : null;
   }, null as { element: ExcalidrawElement; resizeHandle: ReturnType<typeof resizeTest> } | null);

+ 2 - 2
src/element/sizeHelpers.ts

@@ -10,7 +10,7 @@ export function isInvisiblySmallElement(element: ExcalidrawElement): boolean {
 export function getPerfectElementSize(
   elementType: string,
   width: number,
-  height: number
+  height: number,
 ): { width: number; height: number } {
   const absWidth = Math.abs(width);
   const absHeight = Math.abs(height);
@@ -33,7 +33,7 @@ export function getPerfectElementSize(
 export function resizePerfectLineForNWHandler(
   element: ExcalidrawElement,
   x: number,
-  y: number
+  y: number,
 ) {
   const anchorX = element.x + element.width;
   const anchorY = element.y + element.height;

+ 2 - 2
src/element/textWysiwyg.tsx

@@ -22,7 +22,7 @@ export function textWysiwyg({
   y,
   strokeColor,
   font,
-  onSubmit
+  onSubmit,
 }: TextWysiwygParams) {
   // Using contenteditable here as it has dynamic width.
   // But this solution has an issue — it allows to paste
@@ -45,7 +45,7 @@ export function textWysiwyg({
     padding: "4px",
     outline: "transparent",
     whiteSpace: "nowrap",
-    minHeight: "1em"
+    minHeight: "1em",
   });
 
   editable.onkeydown = ev => {

+ 1 - 1
src/element/typeChecks.ts

@@ -1,7 +1,7 @@
 import { ExcalidrawElement, ExcalidrawTextElement } from "./types";
 
 export function isTextElement(
-  element: ExcalidrawElement
+  element: ExcalidrawElement,
 ): element is ExcalidrawTextElement {
   return element.type === "text";
 }

+ 3 - 3
src/history.ts

@@ -8,14 +8,14 @@ class SceneHistory {
 
   generateCurrentEntry(
     appState: Partial<AppState>,
-    elements: readonly ExcalidrawElement[]
+    elements: readonly ExcalidrawElement[],
   ) {
     return JSON.stringify({
       appState,
       elements: elements.map(({ shape, ...element }) => ({
         ...element,
-        isSelected: false
-      }))
+        isSelected: false,
+      })),
     });
   }
 

+ 2 - 2
src/i18n.ts

@@ -18,7 +18,7 @@ export const languages = [
   { lng: "en", label: "English" },
   { lng: "es", label: "Español" },
   { lng: "fr", label: "Français" },
-  { lng: "pt", label: "Português" }
+  { lng: "pt", label: "Português" },
 ];
 
 i18n
@@ -28,7 +28,7 @@ i18n
   .init({
     fallbackLng,
     react: { useSuspense: false },
-    load: "languageOnly"
+    load: "languageOnly",
   });
 
 export default i18n;

+ 6 - 6
src/index-node.ts

@@ -17,7 +17,7 @@ const elements = [
     roughness: 1,
     opacity: 100,
     isSelected: false,
-    seed: 749612521
+    seed: 749612521,
   },
   {
     id: "7W-iw5pEBPTU3eaCaLtFo",
@@ -33,7 +33,7 @@ const elements = [
     roughness: 1,
     opacity: 100,
     isSelected: false,
-    seed: 952056308
+    seed: 952056308,
   },
   {
     id: "kqKI231mvTrcsYo2DkUsR",
@@ -52,8 +52,8 @@ const elements = [
     seed: 1683771448,
     text: "test",
     font: "20px Virgil",
-    baseline: 22
-  }
+    baseline: 22,
+  },
 ];
 
 registerFont("./public/FG_Virgil.ttf", { family: "Virgil" });
@@ -62,9 +62,9 @@ const canvas = getExportCanvasPreview(
   {
     exportBackground: true,
     viewBackgroundColor: "#ffffff",
-    scale: 1
+    scale: 1,
   },
-  createCanvas
+  createCanvas,
 );
 
 const fs = require("fs");

+ 85 - 85
src/index.tsx

@@ -15,7 +15,7 @@ import {
   getElementAbsoluteCoords,
   getCursorForResizingElement,
   getPerfectElementSize,
-  resizePerfectLineForNWHandler
+  resizePerfectLineForNWHandler,
 } from "./element";
 import {
   clearSelection,
@@ -31,7 +31,7 @@ import {
   hasStroke,
   hasText,
   exportCanvas,
-  importFromBackend
+  importFromBackend,
 } from "./scene";
 
 import { renderScene } from "./renderer";
@@ -71,7 +71,7 @@ import {
   actionLoadScene,
   actionSaveScene,
   actionCopyStyles,
-  actionPasteStyles
+  actionPasteStyles,
 } from "./actions";
 import { Action, ActionResult } from "./actions/types";
 import { getDefaultAppState } from "./appState";
@@ -100,7 +100,7 @@ const ELEMENT_TRANSLATE_AMOUNT = 1;
 const TEXT_TO_CENTER_SNAP_THRESHOLD = 30;
 const CURSOR_TYPE = {
   TEXT: "text",
-  CROSSHAIR: "crosshair"
+  CROSSHAIR: "crosshair",
 };
 
 let lastCanvasWidth = -1;
@@ -110,7 +110,7 @@ let lastMouseUp: ((e: any) => void) | null = null;
 
 export function viewportCoordsToSceneCoords(
   { clientX, clientY }: { clientX: number; clientY: number },
-  { scrollX, scrollY }: { scrollX: number; scrollY: number }
+  { scrollX, scrollY }: { scrollX: number; scrollY: number },
 ) {
   const x = clientX - CANVAS_WINDOW_OFFSET_LEFT - scrollX;
   const y = clientY - CANVAS_WINDOW_OFFSET_TOP - scrollY;
@@ -118,7 +118,7 @@ export function viewportCoordsToSceneCoords(
 }
 
 function pickAppStatePropertiesForHistory(
-  appState: AppState
+  appState: AppState,
 ): Partial<AppState> {
   return {
     exportBackground: appState.exportBackground,
@@ -126,7 +126,7 @@ function pickAppStatePropertiesForHistory(
     currentItemBackgroundColor: appState.currentItemBackgroundColor,
     currentItemFont: appState.currentItemFont,
     viewBackgroundColor: appState.viewBackgroundColor,
-    name: appState.name
+    name: appState.name,
   };
 }
 
@@ -186,8 +186,8 @@ export class App extends React.Component<any, AppState> {
       JSON.stringify(
         elements
           .filter(element => element.isSelected)
-          .map(({ shape, ...el }) => el)
-      )
+          .map(({ shape, ...el }) => el),
+      ),
     );
     elements = deleteSelectedElements(elements);
     this.forceUpdate();
@@ -200,8 +200,8 @@ export class App extends React.Component<any, AppState> {
       JSON.stringify(
         elements
           .filter(element => element.isSelected)
-          .map(({ shape, ...el }) => el)
-      )
+          .map(({ shape, ...el }) => el),
+      ),
     );
     e.preventDefault();
   };
@@ -257,7 +257,7 @@ export class App extends React.Component<any, AppState> {
     document.removeEventListener(
       "mousemove",
       this.getCurrentCursorPosition,
-      false
+      false,
     );
     window.removeEventListener("resize", this.onResize, false);
     window.removeEventListener("unload", this.onUnload, false);
@@ -354,7 +354,7 @@ export class App extends React.Component<any, AppState> {
       const text = JSON.stringify(
         elements
           .filter(element => element.isSelected)
-          .map(({ shape, ...el }) => el)
+          .map(({ shape, ...el }) => el),
       );
       navigator.clipboard.writeText(text);
     }
@@ -393,7 +393,7 @@ export class App extends React.Component<any, AppState> {
             elements,
             this.state,
             this.syncActionResult,
-            t
+            t,
           )}
 
           {(hasBackground(elements) ||
@@ -404,7 +404,7 @@ export class App extends React.Component<any, AppState> {
                 elements,
                 this.state,
                 this.syncActionResult,
-                t
+                t,
               )}
 
               {this.actionManager.renderAction(
@@ -412,7 +412,7 @@ export class App extends React.Component<any, AppState> {
                 elements,
                 this.state,
                 this.syncActionResult,
-                t
+                t,
               )}
               <hr />
             </>
@@ -426,7 +426,7 @@ export class App extends React.Component<any, AppState> {
                 elements,
                 this.state,
                 this.syncActionResult,
-                t
+                t,
               )}
 
               {this.actionManager.renderAction(
@@ -434,7 +434,7 @@ export class App extends React.Component<any, AppState> {
                 elements,
                 this.state,
                 this.syncActionResult,
-                t
+                t,
               )}
               <hr />
             </>
@@ -447,7 +447,7 @@ export class App extends React.Component<any, AppState> {
                 elements,
                 this.state,
                 this.syncActionResult,
-                t
+                t,
               )}
 
               {this.actionManager.renderAction(
@@ -455,7 +455,7 @@ export class App extends React.Component<any, AppState> {
                 elements,
                 this.state,
                 this.syncActionResult,
-                t
+                t,
               )}
               <hr />
             </>
@@ -466,7 +466,7 @@ export class App extends React.Component<any, AppState> {
             elements,
             this.state,
             this.syncActionResult,
-            t
+            t,
           )}
 
           {this.actionManager.renderAction(
@@ -474,7 +474,7 @@ export class App extends React.Component<any, AppState> {
             elements,
             this.state,
             this.syncActionResult,
-            t
+            t,
           )}
         </div>
       </Island>
@@ -533,14 +533,14 @@ export class App extends React.Component<any, AppState> {
             elements,
             this.state,
             this.syncActionResult,
-            t
+            t,
           )}
           {this.actionManager.renderAction(
             "saveScene",
             elements,
             this.state,
             this.syncActionResult,
-            t
+            t,
           )}
           <ExportDialog
             elements={elements}
@@ -553,7 +553,7 @@ export class App extends React.Component<any, AppState> {
                   exportBackground: this.state.exportBackground,
                   name: this.state.name,
                   viewBackgroundColor: this.state.viewBackgroundColor,
-                  scale
+                  scale,
                 });
             }}
             onExportToClipboard={(exportedElements, scale) => {
@@ -562,7 +562,7 @@ export class App extends React.Component<any, AppState> {
                   exportBackground: this.state.exportBackground,
                   name: this.state.name,
                   viewBackgroundColor: this.state.viewBackgroundColor,
-                  scale
+                  scale,
                 });
             }}
             onExportToBackend={exportedElements => {
@@ -571,10 +571,10 @@ export class App extends React.Component<any, AppState> {
                   "backend",
                   exportedElements.map(element => ({
                     ...element,
-                    isSelected: false
+                    isSelected: false,
                   })),
                   this.canvas,
-                  this.state
+                  this.state,
                 );
             }}
           />
@@ -583,7 +583,7 @@ export class App extends React.Component<any, AppState> {
             elements,
             this.state,
             this.syncActionResult,
-            t
+            t,
           )}
         </Stack.Row>
         {this.actionManager.renderAction(
@@ -591,7 +591,7 @@ export class App extends React.Component<any, AppState> {
           elements,
           this.state,
           this.syncActionResult,
-          t
+          t,
         )}
       </Stack.Col>
     );
@@ -626,7 +626,7 @@ export class App extends React.Component<any, AppState> {
           id="canvas"
           style={{
             width: canvasWidth,
-            height: canvasHeight
+            height: canvasHeight,
           }}
           width={canvasWidth * window.devicePixelRatio}
           height={canvasHeight * window.devicePixelRatio}
@@ -641,7 +641,7 @@ export class App extends React.Component<any, AppState> {
             }
             if (canvas) {
               canvas.addEventListener("wheel", this.handleWheel, {
-                passive: false
+                passive: false,
               });
               this.removeWheelEventListener = () =>
                 canvas.removeEventListener("wheel", this.handleWheel);
@@ -670,18 +670,18 @@ export class App extends React.Component<any, AppState> {
                 options: [
                   navigator.clipboard && {
                     label: t("labels.paste"),
-                    action: () => this.pasteFromClipboard()
+                    action: () => this.pasteFromClipboard(),
                   },
                   ...this.actionManager.getContextMenuItems(
                     elements,
                     this.state,
                     this.syncActionResult,
                     action => this.canvasOnlyActions.includes(action),
-                    t
-                  )
+                    t,
+                  ),
                 ],
                 top: e.clientY,
-                left: e.clientX
+                left: e.clientX,
               });
               return;
             }
@@ -696,22 +696,22 @@ export class App extends React.Component<any, AppState> {
               options: [
                 navigator.clipboard && {
                   label: t("labels.copy"),
-                  action: this.copyToClipboard
+                  action: this.copyToClipboard,
                 },
                 navigator.clipboard && {
                   label: t("labels.paste"),
-                  action: () => this.pasteFromClipboard()
+                  action: () => this.pasteFromClipboard(),
                 },
                 ...this.actionManager.getContextMenuItems(
                   elements,
                   this.state,
                   this.syncActionResult,
                   action => !this.canvasOnlyActions.includes(action),
-                  t
-                )
+                  t,
+                ),
               ],
               top: e.clientY,
-              left: e.clientX
+              left: e.clientX,
             });
           }}
           onMouseDown={e => {
@@ -733,7 +733,7 @@ export class App extends React.Component<any, AppState> {
                 lastY = e.clientY;
                 this.setState(state => ({
                   scrollX: state.scrollX - deltaX,
-                  scrollY: state.scrollY - deltaY
+                  scrollY: state.scrollY - deltaY,
                 }));
               };
               const onMouseUp = (lastMouseUp = (e: MouseEvent) => {
@@ -743,7 +743,7 @@ export class App extends React.Component<any, AppState> {
                 window.removeEventListener("mouseup", onMouseUp);
               });
               window.addEventListener("mousemove", onMouseMove, {
-                passive: true
+                passive: true,
               });
               window.addEventListener("mouseup", onMouseUp);
               return;
@@ -763,7 +763,7 @@ export class App extends React.Component<any, AppState> {
             // Handle scrollbars dragging
             const {
               isOverHorizontalScrollBar,
-              isOverVerticalScrollBar
+              isOverVerticalScrollBar,
             } = isOverScrollBars(
               elements,
               e.clientX - CANVAS_WINDOW_OFFSET_LEFT,
@@ -771,7 +771,7 @@ export class App extends React.Component<any, AppState> {
               canvasWidth,
               canvasHeight,
               this.state.scrollX,
-              this.state.scrollY
+              this.state.scrollY,
             );
 
             const { x, y } = viewportCoordsToSceneCoords(e, this.state);
@@ -785,7 +785,7 @@ export class App extends React.Component<any, AppState> {
               "hachure",
               1,
               1,
-              100
+              100,
             );
 
             if (isTextElement(element)) {
@@ -802,16 +802,16 @@ export class App extends React.Component<any, AppState> {
               const resizeElement = getElementWithResizeHandler(
                 elements,
                 { x, y },
-                this.state
+                this.state,
               );
               this.setState({
-                resizingElement: resizeElement ? resizeElement.element : null
+                resizingElement: resizeElement ? resizeElement.element : null,
               });
 
               if (resizeElement) {
                 resizeHandle = resizeElement.resizeHandle;
                 document.documentElement.style.cursor = getCursorForResizingElement(
-                  resizeElement
+                  resizeElement,
                 );
                 isResizingElements = true;
               } else {
@@ -837,7 +837,7 @@ export class App extends React.Component<any, AppState> {
                     elements = [
                       ...elements.map(element => ({
                         ...element,
-                        isSelected: false
+                        isSelected: false,
                       })),
                       ...elements
                         .filter(element => element.isSelected)
@@ -845,7 +845,7 @@ export class App extends React.Component<any, AppState> {
                           const newElement = duplicateElement(element);
                           newElement.isSelected = true;
                           return newElement;
-                        })
+                        }),
                     ];
                   }
                 }
@@ -860,7 +860,7 @@ export class App extends React.Component<any, AppState> {
               if (!e.altKey) {
                 const snappedToCenterPosition = this.getTextWysiwygSnappedToCenterPosition(
                   x,
-                  y
+                  y,
                 );
                 if (snappedToCenterPosition) {
                   element.x = snappedToCenterPosition.elementCenterX;
@@ -884,22 +884,22 @@ export class App extends React.Component<any, AppState> {
                         ...newTextElement(
                           element,
                           text,
-                          this.state.currentItemFont
+                          this.state.currentItemFont,
                         ),
-                        isSelected: true
-                      }
+                        isSelected: true,
+                      },
                     ];
                   }
                   this.setState({
                     draggingElement: null,
                     editingElement: null,
-                    elementType: "selection"
+                    elementType: "selection",
                   });
-                }
+                },
               });
               this.setState({
                 elementType: "selection",
-                editingElement: element
+                editingElement: element,
               });
               return;
             }
@@ -993,7 +993,7 @@ export class App extends React.Component<any, AppState> {
                           const { width, height } = getPerfectElementSize(
                             element.type,
                             x - element.x,
-                            y - element.y
+                            y - element.y,
                           );
                           element.width = width;
                           element.height = height;
@@ -1023,7 +1023,7 @@ export class App extends React.Component<any, AppState> {
                   }
 
                   document.documentElement.style.cursor = getCursorForResizingElement(
-                    { element, resizeHandle }
+                    { element, resizeHandle },
                   );
                   el.x = element.x;
                   el.y = element.y;
@@ -1078,11 +1078,11 @@ export class App extends React.Component<any, AppState> {
               if (e.shiftKey) {
                 let {
                   width: newWidth,
-                  height: newHeight
+                  height: newHeight,
                 } = getPerfectElementSize(
                   this.state.elementType,
                   width,
-                  height
+                  height,
                 );
                 draggingElement.width = newWidth;
                 draggingElement.height = newHeight;
@@ -1099,7 +1099,7 @@ export class App extends React.Component<any, AppState> {
                 }
                 const elementsWithinSelection = getElementsWithinSelection(
                   elements,
-                  draggingElement
+                  draggingElement,
                 );
                 elementsWithinSelection.forEach(element => {
                   element.isSelected = true;
@@ -1115,7 +1115,7 @@ export class App extends React.Component<any, AppState> {
                 draggingElement,
                 resizingElement,
                 elementType,
-                elementLocked
+                elementLocked,
               } = this.state;
 
               lastMouseUp = null;
@@ -1130,7 +1130,7 @@ export class App extends React.Component<any, AppState> {
                 // remove invisible element which was added in onMouseDown
                 elements = elements.slice(0, -1);
                 this.setState({
-                  draggingElement: null
+                  draggingElement: null,
                 });
                 this.forceUpdate();
                 return;
@@ -1179,7 +1179,7 @@ export class App extends React.Component<any, AppState> {
 
                 this.setState({
                   draggingElement: null,
-                  elementType: "selection"
+                  elementType: "selection",
                 });
               }
 
@@ -1214,10 +1214,10 @@ export class App extends React.Component<any, AppState> {
                       "hachure",
                       1,
                       1,
-                      100
+                      100,
                     ),
                     "", // default text
-                    this.state.currentItemFont // default font
+                    this.state.currentItemFont, // default font
                   );
 
             this.setState({ editingElement: element });
@@ -1227,7 +1227,7 @@ export class App extends React.Component<any, AppState> {
 
             if (elementAtPosition && isTextElement(elementAtPosition)) {
               elements = elements.filter(
-                element => element.id !== elementAtPosition.id
+                element => element.id !== elementAtPosition.id,
               );
               this.forceUpdate();
 
@@ -1248,7 +1248,7 @@ export class App extends React.Component<any, AppState> {
             } else if (!e.altKey) {
               const snappedToCenterPosition = this.getTextWysiwygSnappedToCenterPosition(
                 x,
-                y
+                y,
               );
 
               if (snappedToCenterPosition) {
@@ -1273,16 +1273,16 @@ export class App extends React.Component<any, AppState> {
                       // we need to recreate the element to update dimensions &
                       //  position
                       ...newTextElement(element, text, element.font),
-                      isSelected: true
-                    }
+                      isSelected: true,
+                    },
                   ];
                 }
                 this.setState({
                   draggingElement: null,
                   editingElement: null,
-                  elementType: "selection"
+                  elementType: "selection",
                 });
-              }
+              },
             });
           }}
           onMouseMove={e => {
@@ -1296,11 +1296,11 @@ export class App extends React.Component<any, AppState> {
               const resizeElement = getElementWithResizeHandler(
                 elements,
                 { x, y },
-                this.state
+                this.state,
               );
               if (resizeElement && resizeElement.resizeHandle) {
                 document.documentElement.style.cursor = getCursorForResizingElement(
-                  resizeElement
+                  resizeElement,
                 );
                 return;
               }
@@ -1327,7 +1327,7 @@ export class App extends React.Component<any, AppState> {
     const { deltaX, deltaY } = e;
     this.setState(state => ({
       scrollX: state.scrollX - deltaX,
-      scrollY: state.scrollY - deltaY
+      scrollY: state.scrollY - deltaY,
     }));
   };
 
@@ -1384,7 +1384,7 @@ export class App extends React.Component<any, AppState> {
           duplicate.x += dx - minX;
           duplicate.y += dy - minY;
           return duplicate;
-        })
+        }),
       ];
       this.forceUpdate();
     }
@@ -1399,7 +1399,7 @@ export class App extends React.Component<any, AppState> {
         elementClickedInside.y + elementClickedInside.height / 2;
       const distanceToCenter = Math.hypot(
         x - elementCenterX,
-        y - elementCenterY
+        y - elementCenterY,
       );
       const isSnappedToCenter =
         distanceToCenter < TEXT_TO_CENTER_SNAP_THRESHOLD;
@@ -1427,15 +1427,15 @@ export class App extends React.Component<any, AppState> {
     renderScene(elements, this.rc!, this.canvas!, {
       scrollX: this.state.scrollX,
       scrollY: this.state.scrollY,
-      viewBackgroundColor: this.state.viewBackgroundColor
+      viewBackgroundColor: this.state.viewBackgroundColor,
     });
     this.saveDebounced();
     if (history.isRecording()) {
       history.pushEntry(
         history.generateCurrentEntry(
           pickAppStatePropertiesForHistory(this.state),
-          elements
-        )
+          elements,
+        ),
       );
     }
   }
@@ -1453,7 +1453,7 @@ class TopErrorBoundary extends React.Component {
     return {
       hasError: true,
       localStorage: JSON.stringify({ ...localStorage }),
-      stack: error.stack
+      stack: error.stack,
     };
   }
 
@@ -1471,7 +1471,7 @@ class TopErrorBoundary extends React.Component {
     } catch {}
 
     window.open(
-      `https://github.com/excalidraw/excalidraw/issues/new?body=${body}`
+      `https://github.com/excalidraw/excalidraw/issues/new?body=${body}`,
     );
   }
 
@@ -1539,5 +1539,5 @@ ReactDOM.render(
   <TopErrorBoundary>
     <AppWithTrans />
   </TopErrorBoundary>,
-  rootElement
+  rootElement,
 );

+ 1 - 1
src/keys.ts

@@ -11,7 +11,7 @@ export const KEYS = {
     return /Mac|iPod|iPhone|iPad/.test(window.navigator.platform)
       ? "metaKey"
       : "ctrlKey";
-  }
+  },
 };
 
 export function isArrowKey(keyCode: string) {

+ 3 - 3
src/math.ts

@@ -5,7 +5,7 @@ export function distanceBetweenPointAndSegment(
   x1: number,
   y1: number,
   x2: number,
-  y2: number
+  y2: number,
 ) {
   const A = x - x1;
   const B = y - y1;
@@ -42,13 +42,13 @@ export function rotate(
   y1: number,
   x2: number,
   y2: number,
-  angle: number
+  angle: number,
 ) {
   // 𝑎′𝑥=(𝑎𝑥−𝑐𝑥)cos𝜃−(𝑎𝑦−𝑐𝑦)sin𝜃+𝑐𝑥
   // 𝑎′𝑦=(𝑎𝑥−𝑐𝑥)sin𝜃+(𝑎𝑦−𝑐𝑦)cos𝜃+𝑐𝑦.
   // https://math.stackexchange.com/questions/2204520/how-do-i-rotate-a-line-segment-in-a-specific-point-on-the-line
   return [
     (x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle) + x2,
-    (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2
+    (x1 - x2) * Math.sin(angle) + (y1 - y2) * Math.cos(angle) + y2,
   ];
 }

+ 13 - 13
src/renderer/renderElement.ts

@@ -3,7 +3,7 @@ import { isTextElement } from "../element/typeChecks";
 import {
   getDiamondPoints,
   getArrowPoints,
-  getLinePoints
+  getLinePoints,
 } from "../element/bounds";
 import { RoughCanvas } from "roughjs/bin/canvas";
 import { Drawable } from "roughjs/bin/core";
@@ -11,7 +11,7 @@ import { Drawable } from "roughjs/bin/core";
 export function renderElement(
   element: ExcalidrawElement,
   rc: RoughCanvas,
-  context: CanvasRenderingContext2D
+  context: CanvasRenderingContext2D,
 ) {
   const generator = rc.generator;
   if (element.type === "selection") {
@@ -30,7 +30,7 @@ export function renderElement(
         fillStyle: element.fillStyle,
         strokeWidth: element.strokeWidth,
         roughness: element.roughness,
-        seed: element.seed
+        seed: element.seed,
       });
     }
 
@@ -47,14 +47,14 @@ export function renderElement(
         bottomX,
         bottomY,
         leftX,
-        leftY
+        leftY,
       ] = getDiamondPoints(element);
       element.shape = generator.polygon(
         [
           [topX, topY],
           [rightX, rightY],
           [bottomX, bottomY],
-          [leftX, leftY]
+          [leftX, leftY],
         ],
         {
           stroke: element.strokeColor,
@@ -65,8 +65,8 @@ export function renderElement(
           fillStyle: element.fillStyle,
           strokeWidth: element.strokeWidth,
           roughness: element.roughness,
-          seed: element.seed
-        }
+          seed: element.seed,
+        },
       );
     }
 
@@ -90,8 +90,8 @@ export function renderElement(
           strokeWidth: element.strokeWidth,
           roughness: element.roughness,
           seed: element.seed,
-          curveFitting: 1
-        }
+          curveFitting: 1,
+        },
       );
     }
 
@@ -104,7 +104,7 @@ export function renderElement(
       stroke: element.strokeColor,
       strokeWidth: element.strokeWidth,
       roughness: element.roughness,
-      seed: element.seed
+      seed: element.seed,
     };
 
     if (!element.shape) {
@@ -114,7 +114,7 @@ export function renderElement(
         // -----
         generator.line(x1, y1, x2, y2, options),
         //    /
-        generator.line(x4, y4, x2, y2, options)
+        generator.line(x4, y4, x2, y2, options),
       ];
     }
 
@@ -128,7 +128,7 @@ export function renderElement(
       stroke: element.strokeColor,
       strokeWidth: element.strokeWidth,
       roughness: element.roughness,
-      seed: element.seed
+      seed: element.seed,
     };
 
     if (!element.shape) {
@@ -147,7 +147,7 @@ export function renderElement(
     context.fillText(
       element.text,
       0,
-      element.baseline || element.actualBoundingBoxAscent || 0
+      element.baseline || element.actualBoundingBoxAscent || 0,
     );
     context.fillStyle = fillStyle;
     context.font = font;

+ 12 - 12
src/renderer/renderScene.ts

@@ -8,7 +8,7 @@ import { SceneState } from "../scene/types";
 import {
   getScrollBars,
   SCROLLBAR_COLOR,
-  SCROLLBAR_WIDTH
+  SCROLLBAR_WIDTH,
 } from "../scene/scrollbars";
 
 import { renderElement } from "./renderElement";
@@ -23,13 +23,13 @@ export function renderScene(
     offsetX,
     offsetY,
     renderScrollbars = true,
-    renderSelection = true
+    renderSelection = true,
   }: {
     offsetX?: number;
     offsetY?: number;
     renderScrollbars?: boolean;
     renderSelection?: boolean;
-  } = {}
+  } = {},
 ) {
   if (!canvas) return;
   const context = canvas.getContext("2d")!;
@@ -53,7 +53,7 @@ export function renderScene(
   sceneState = {
     ...sceneState,
     scrollX: typeof offsetX === "number" ? offsetX : sceneState.scrollX,
-    scrollY: typeof offsetY === "number" ? offsetY : sceneState.scrollY
+    scrollY: typeof offsetY === "number" ? offsetY : sceneState.scrollY,
   };
 
   elements.forEach(element => {
@@ -65,19 +65,19 @@ export function renderScene(
         // If canvas is scaled for high pixelDeviceRatio width and height
         // setted in the `style` attribute
         parseInt(canvas.style.width) || canvas.width,
-        parseInt(canvas.style.height) || canvas.height
+        parseInt(canvas.style.height) || canvas.height,
       )
     ) {
       return;
     }
     context.translate(
       element.x + sceneState.scrollX,
-      element.y + sceneState.scrollY
+      element.y + sceneState.scrollY,
     );
     renderElement(element, rc, context);
     context.translate(
       -element.x - sceneState.scrollX,
-      -element.y - sceneState.scrollY
+      -element.y - sceneState.scrollY,
     );
   });
 
@@ -91,7 +91,7 @@ export function renderScene(
         elementX1,
         elementY1,
         elementX2,
-        elementY2
+        elementY2,
       ] = getElementAbsoluteCoords(element);
       const lineDash = context.getLineDash();
       context.setLineDash([8, 4]);
@@ -99,7 +99,7 @@ export function renderScene(
         elementX1 - margin + sceneState.scrollX,
         elementY1 - margin + sceneState.scrollY,
         elementX2 - elementX1 + margin * 2,
-        elementY2 - elementY1 + margin * 2
+        elementY2 - elementY1 + margin * 2,
       );
       context.setLineDash(lineDash);
     });
@@ -118,7 +118,7 @@ export function renderScene(
       context.canvas.width / window.devicePixelRatio,
       context.canvas.height / window.devicePixelRatio,
       sceneState.scrollX,
-      sceneState.scrollY
+      sceneState.scrollY,
     );
 
     const strokeStyle = context.strokeStyle;
@@ -132,7 +132,7 @@ export function renderScene(
           scrollBar.y,
           scrollBar.width,
           scrollBar.height,
-          SCROLLBAR_WIDTH / 2
+          SCROLLBAR_WIDTH / 2,
         );
     });
     context.strokeStyle = strokeStyle;
@@ -145,7 +145,7 @@ function isVisibleElement(
   scrollX: number,
   scrollY: number,
   canvasWidth: number,
-  canvasHeight: number
+  canvasHeight: number,
 ) {
   let [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
   x1 += scrollX;

+ 2 - 2
src/renderer/roundRect.ts

@@ -14,7 +14,7 @@ export function roundRect(
   y: number,
   width: number,
   height: number,
-  radius: number
+  radius: number,
 ) {
   context.beginPath();
   context.moveTo(x + radius, y);
@@ -25,7 +25,7 @@ export function roundRect(
     x + width,
     y + height,
     x + width - radius,
-    y + height
+    y + height,
   );
   context.lineTo(x + radius, y + height);
   context.quadraticCurveTo(x, y + height, x, y + height - radius);

+ 4 - 4
src/scene/comparisons.ts

@@ -8,7 +8,7 @@ export const hasBackground = (elements: readonly ExcalidrawElement[]) =>
       element.isSelected &&
       (element.type === "rectangle" ||
         element.type === "ellipse" ||
-        element.type === "diamond")
+        element.type === "diamond"),
   );
 
 export const hasStroke = (elements: readonly ExcalidrawElement[]) =>
@@ -19,7 +19,7 @@ export const hasStroke = (elements: readonly ExcalidrawElement[]) =>
         element.type === "ellipse" ||
         element.type === "diamond" ||
         element.type === "arrow" ||
-        element.type === "line")
+        element.type === "line"),
   );
 
 export const hasText = (elements: readonly ExcalidrawElement[]) =>
@@ -28,7 +28,7 @@ export const hasText = (elements: readonly ExcalidrawElement[]) =>
 export function getElementAtPosition(
   elements: readonly ExcalidrawElement[],
   x: number,
-  y: number
+  y: number,
 ) {
   let hitElement = null;
   // We need to to hit testing from front (end of the array) to back (beginning of the array)
@@ -45,7 +45,7 @@ export function getElementAtPosition(
 export function getElementContainingPosition(
   elements: readonly ExcalidrawElement[],
   x: number,
-  y: number
+  y: number,
 ) {
   let hitElement = null;
   // We need to to hit testing from front (end of the array) to back (beginning of the array)

+ 21 - 21
src/scene/data.ts

@@ -27,19 +27,19 @@ interface DataState {
 
 export function serializeAsJSON(
   elements: readonly ExcalidrawElement[],
-  appState?: AppState
+  appState?: AppState,
 ): string {
   return JSON.stringify({
     version: 1,
     source: window.location.origin,
     elements: elements.map(({ shape, ...el }) => el),
-    appState: appState || getDefaultAppState()
+    appState: appState || getDefaultAppState(),
   });
 }
 
 export async function saveAsJSON(
   elements: readonly ExcalidrawElement[],
-  appState: AppState
+  appState: AppState,
 ) {
   const serialized = serializeAsJSON(elements, appState);
 
@@ -48,9 +48,9 @@ export async function saveAsJSON(
     new Blob([serialized], { type: "application/json" }),
     {
       fileName: name,
-      description: "Excalidraw file"
+      description: "Excalidraw file",
     },
-    (window as any).handle
+    (window as any).handle,
   );
 }
 
@@ -72,7 +72,7 @@ export async function loadFromJSON() {
   const blob = await fileOpen({
     description: "Excalidraw files",
     extensions: ["json"],
-    mimeTypes: ["application/json"]
+    mimeTypes: ["application/json"],
   });
   if (blob.handle) {
     (window as any).handle = blob.handle;
@@ -101,12 +101,12 @@ export async function loadFromJSON() {
 
 export async function exportToBackend(
   elements: readonly ExcalidrawElement[],
-  appState: AppState
+  appState: AppState,
 ) {
   const response = await fetch(BACKEND_POST, {
     method: "POST",
     headers: { "Content-Type": "application/json" },
-    body: serializeAsJSON(elements, appState)
+    body: serializeAsJSON(elements, appState),
   });
   const json = await response.json();
   if (json.id) {
@@ -117,8 +117,8 @@ export async function exportToBackend(
     window.alert(
       i18n.t("alerts.copiedToClipboard", {
         url: url.toString(),
-        interpolation: { escapeValue: false }
-      })
+        interpolation: { escapeValue: false },
+      }),
     );
   } else {
     window.alert(i18n.t("alerts.couldNotCreateShareableLink"));
@@ -129,7 +129,7 @@ export async function importFromBackend(id: string | null) {
   let elements: readonly ExcalidrawElement[] = [];
   let appState: AppState = getDefaultAppState();
   const response = await fetch(`${BACKEND_GET}${id}.json`).then(data =>
-    data.clone().json()
+    data.clone().json(),
   );
   if (response != null) {
     try {
@@ -152,14 +152,14 @@ export async function exportCanvas(
     exportPadding = 10,
     viewBackgroundColor,
     name,
-    scale = 1
+    scale = 1,
   }: {
     exportBackground: boolean;
     exportPadding?: number;
     viewBackgroundColor: string;
     name: string;
     scale?: number;
-  }
+  },
 ) {
   if (!elements.length)
     return window.alert(i18n.t("alerts.cannotExportEmptyCanvas"));
@@ -169,7 +169,7 @@ export async function exportCanvas(
     exportBackground,
     viewBackgroundColor,
     exportPadding,
-    scale
+    scale,
   });
   tempCanvas.style.display = "none";
   document.body.appendChild(tempCanvas);
@@ -180,7 +180,7 @@ export async function exportCanvas(
       if (blob) {
         await fileSave(blob, {
           fileName: fileName,
-          description: "Excalidraw image"
+          description: "Excalidraw image",
         });
       }
     });
@@ -190,7 +190,7 @@ export async function exportCanvas(
       tempCanvas.toBlob(async function(blob: any) {
         try {
           await navigator.clipboard.write([
-            new window.ClipboardItem({ "image/png": blob })
+            new window.ClipboardItem({ "image/png": blob }),
           ]);
         } catch (err) {
           window.alert(errorMsg);
@@ -213,7 +213,7 @@ export async function exportCanvas(
 
 function restore(
   savedElements: readonly ExcalidrawElement[],
-  savedState: AppState
+  savedState: AppState,
 ): DataState {
   return {
     elements: savedElements.map(element => ({
@@ -225,9 +225,9 @@ function restore(
       opacity:
         element.opacity === null || element.opacity === undefined
           ? 100
-          : element.opacity
+          : element.opacity,
     })),
-    appState: savedState
+    appState: savedState,
   };
 }
 
@@ -239,7 +239,7 @@ export function restoreFromLocalStorage() {
   if (savedElements) {
     try {
       elements = JSON.parse(savedElements).map(
-        ({ shape, ...element }: ExcalidrawElement) => element
+        ({ shape, ...element }: ExcalidrawElement) => element,
       );
     } catch (e) {
       // Do nothing because elements array is already empty
@@ -260,7 +260,7 @@ export function restoreFromLocalStorage() {
 
 export function saveToLocalStorage(
   elements: readonly ExcalidrawElement[],
-  state: AppState
+  state: AppState,
 ) {
   localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(elements));
   localStorage.setItem(LOCAL_STORAGE_KEY_STATE, JSON.stringify(state));

+ 6 - 6
src/scene/getExportCanvasPreview.ts

@@ -9,7 +9,7 @@ export function getExportCanvasPreview(
     exportBackground,
     exportPadding = 10,
     viewBackgroundColor,
-    scale = 1
+    scale = 1,
   }: {
     exportBackground: boolean;
     exportPadding?: number;
@@ -18,13 +18,13 @@ export function getExportCanvasPreview(
   },
   createCanvas: (width: number, height: number) => any = function(
     width,
-    height
+    height,
   ) {
     const tempCanvas = document.createElement("canvas");
     tempCanvas.width = width * scale;
     tempCanvas.height = height * scale;
     return tempCanvas;
-  }
+  },
 ) {
   // calculate smallest area to fit the contents in
   let subCanvasX1 = Infinity;
@@ -56,14 +56,14 @@ export function getExportCanvasPreview(
     {
       viewBackgroundColor: exportBackground ? viewBackgroundColor : null,
       scrollX: 0,
-      scrollY: 0
+      scrollY: 0,
     },
     {
       offsetX: -subCanvasX1 + exportPadding,
       offsetY: -subCanvasY1 + exportPadding,
       renderScrollbars: false,
-      renderSelection: false
-    }
+      renderSelection: false,
+    },
   );
   return tempCanvas;
 }

+ 3 - 3
src/scene/index.ts

@@ -5,7 +5,7 @@ export {
   deleteSelectedElements,
   someElementIsSelected,
   getElementsWithinSelection,
-  getCommonAttributeOfSelectedElements
+  getCommonAttributeOfSelectedElements,
 } from "./selection";
 export {
   exportCanvas,
@@ -14,13 +14,13 @@ export {
   restoreFromLocalStorage,
   saveToLocalStorage,
   exportToBackend,
-  importFromBackend
+  importFromBackend,
 } from "./data";
 export {
   hasBackground,
   hasStroke,
   getElementAtPosition,
   getElementContainingPosition,
-  hasText
+  hasText,
 } from "./comparisons";
 export { createScene } from "./createScene";

+ 13 - 13
src/scene/scrollbars.ts

@@ -11,7 +11,7 @@ export function getScrollBars(
   canvasWidth: number,
   canvasHeight: number,
   scrollX: number,
-  scrollY: number
+  scrollY: number,
 ) {
   let minX = Infinity;
   let maxX = 0;
@@ -41,14 +41,14 @@ export function getScrollBars(
     horizontalScrollBar = {
       x: Math.min(
         leftOverflow + SCROLLBAR_MARGIN,
-        canvasWidth - SCROLLBAR_MIN_SIZE - SCROLLBAR_MARGIN
+        canvasWidth - SCROLLBAR_MIN_SIZE - SCROLLBAR_MARGIN,
       ),
       y: canvasHeight - SCROLLBAR_WIDTH - SCROLLBAR_MARGIN,
       width: Math.max(
         canvasWidth - rightOverflow - leftOverflow - SCROLLBAR_MARGIN * 2,
-        SCROLLBAR_MIN_SIZE
+        SCROLLBAR_MIN_SIZE,
       ),
-      height: SCROLLBAR_WIDTH
+      height: SCROLLBAR_WIDTH,
     };
   }
 
@@ -59,19 +59,19 @@ export function getScrollBars(
       x: canvasWidth - SCROLLBAR_WIDTH - SCROLLBAR_MARGIN,
       y: Math.min(
         topOverflow + SCROLLBAR_MARGIN,
-        canvasHeight - SCROLLBAR_MIN_SIZE - SCROLLBAR_MARGIN
+        canvasHeight - SCROLLBAR_MIN_SIZE - SCROLLBAR_MARGIN,
       ),
       width: SCROLLBAR_WIDTH,
       height: Math.max(
         canvasHeight - bottomOverflow - topOverflow - SCROLLBAR_WIDTH * 2,
-        SCROLLBAR_MIN_SIZE
-      )
+        SCROLLBAR_MIN_SIZE,
+      ),
     };
   }
 
   return {
     horizontal: horizontalScrollBar,
-    vertical: verticalScrollBar
+    vertical: verticalScrollBar,
   };
 }
 
@@ -82,30 +82,30 @@ export function isOverScrollBars(
   canvasWidth: number,
   canvasHeight: number,
   scrollX: number,
-  scrollY: number
+  scrollY: number,
 ) {
   const scrollBars = getScrollBars(
     elements,
     canvasWidth,
     canvasHeight,
     scrollX,
-    scrollY
+    scrollY,
   );
 
   const [isOverHorizontalScrollBar, isOverVerticalScrollBar] = [
     scrollBars.horizontal,
-    scrollBars.vertical
+    scrollBars.vertical,
   ].map(
     scrollBar =>
       scrollBar &&
       scrollBar.x <= x &&
       x <= scrollBar.x + scrollBar.width &&
       scrollBar.y <= y &&
-      y <= scrollBar.y + scrollBar.height
+      y <= scrollBar.y + scrollBar.height,
   );
 
   return {
     isOverHorizontalScrollBar,
-    isOverVerticalScrollBar
+    isOverVerticalScrollBar,
   };
 }

+ 6 - 6
src/scene/selection.ts

@@ -3,20 +3,20 @@ import { getElementAbsoluteCoords } from "../element";
 
 export function getElementsWithinSelection(
   elements: readonly ExcalidrawElement[],
-  selection: ExcalidrawElement
+  selection: ExcalidrawElement,
 ) {
   const [
     selectionX1,
     selectionY1,
     selectionX2,
-    selectionY2
+    selectionY2,
   ] = getElementAbsoluteCoords(selection);
   return elements.filter(element => {
     const [
       elementX1,
       elementY1,
       elementX2,
-      elementY2
+      elementY2,
     ] = getElementAbsoluteCoords(element);
 
     return (
@@ -62,14 +62,14 @@ export const someElementIsSelected = (elements: readonly ExcalidrawElement[]) =>
  */
 export function getCommonAttributeOfSelectedElements<T>(
   elements: readonly ExcalidrawElement[],
-  getAttribute: (element: ExcalidrawElement) => T
+  getAttribute: (element: ExcalidrawElement) => T,
 ): T | null {
   const attributes = Array.from(
     new Set(
       elements
         .filter(element => element.isSelected)
-        .map(element => getAttribute(element))
-    )
+        .map(element => getAttribute(element)),
+    ),
   );
   return attributes.length === 1 ? attributes[0] : null;
 }

+ 9 - 9
src/shapes.tsx

@@ -9,7 +9,7 @@ export const SHAPES = [
         <path d="M302.189 329.126H196.105l55.831 135.993c3.889 9.428-.555 19.999-9.444 23.999l-49.165 21.427c-9.165 4-19.443-.571-23.332-9.714l-53.053-129.136-86.664 89.138C18.729 472.71 0 463.554 0 447.977V18.299C0 1.899 19.921-6.096 30.277 5.443l284.412 292.542c11.472 11.179 3.007 31.141-12.5 31.141z" />
       </svg>
     ),
-    value: "selection"
+    value: "selection",
   },
   {
     icon: (
@@ -18,7 +18,7 @@ export const SHAPES = [
         <path d="M400 32H48C21.5 32 0 53.5 0 80v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V80c0-26.5-21.5-48-48-48z" />
       </svg>
     ),
-    value: "rectangle"
+    value: "rectangle",
   },
   {
     icon: (
@@ -27,7 +27,7 @@ export const SHAPES = [
         <path d="M111.823 0L16.622 111.823 111.823 223.646 207.025 111.823z" />
       </svg>
     ),
-    value: "diamond"
+    value: "diamond",
   },
   {
     icon: (
@@ -36,7 +36,7 @@ export const SHAPES = [
         <path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z" />
       </svg>
     ),
-    value: "ellipse"
+    value: "ellipse",
   },
   {
     icon: (
@@ -45,7 +45,7 @@ export const SHAPES = [
         <path d="M313.941 216H12c-6.627 0-12 5.373-12 12v56c0 6.627 5.373 12 12 12h301.941v46.059c0 21.382 25.851 32.09 40.971 16.971l86.059-86.059c9.373-9.373 9.373-24.569 0-33.941l-86.059-86.059c-15.119-15.119-40.971-4.411-40.971 16.971V216z" />
       </svg>
     ),
-    value: "arrow"
+    value: "arrow",
   },
   {
     icon: (
@@ -54,7 +54,7 @@ export const SHAPES = [
         <line x1="0" y1="3" x2="6" y2="3" stroke="#000" strokeLinecap="round" />
       </svg>
     ),
-    value: "line"
+    value: "line",
   },
   {
     icon: (
@@ -63,13 +63,13 @@ export const SHAPES = [
         <path d="M432 416h-23.41L277.88 53.69A32 32 0 0 0 247.58 32h-47.16a32 32 0 0 0-30.3 21.69L39.41 416H16a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16h-19.58l23.3-64h152.56l23.3 64H304a16 16 0 0 0-16 16v32a16 16 0 0 0 16 16h128a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zM176.85 272L224 142.51 271.15 272z" />
       </svg>
     ),
-    value: "text"
-  }
+    value: "text",
+  },
 ];
 
 export const shapesShortcutKeys = SHAPES.map((shape, index) => [
   shape.value[0],
-  (index + 1).toString()
+  (index + 1).toString(),
 ]).flat(1);
 
 export function findShapeByKey(key: string) {

+ 2 - 2
src/utils.ts

@@ -15,7 +15,7 @@ export function capitalizeString(str: string) {
 }
 
 export function isInputLike(
-  target: Element | EventTarget | null
+  target: Element | EventTarget | null,
 ): target is HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement {
   return (
     (target instanceof HTMLElement && target.dataset.type === "wysiwyg") ||
@@ -54,7 +54,7 @@ export function measureText(text: string, font: string) {
 
 export function debounce<T extends any[]>(
   fn: (...args: T) => void,
-  timeout: number
+  timeout: number,
 ) {
   let handle = 0;
   let lastArgs: T;

+ 13 - 13
src/zindex.test.ts

@@ -4,7 +4,7 @@ function expectMove<T>(
   fn: (elements: T[], indicesToMove: number[]) => void,
   elems: T[],
   indices: number[],
-  equal: T[]
+  equal: T[],
 ) {
   fn(elems, indices);
   expect(elems).toEqual(equal);
@@ -17,7 +17,7 @@ it("should moveOneLeft", () => {
     moveOneLeft,
     ["a", "b", "c", "d"],
     [0, 1, 2, 3],
-    ["a", "b", "c", "d"]
+    ["a", "b", "c", "d"],
   );
   expectMove(moveOneLeft, ["a", "b", "c", "d"], [1, 3], ["b", "a", "d", "c"]);
 });
@@ -29,7 +29,7 @@ it("should moveOneRight", () => {
     moveOneRight,
     ["a", "b", "c", "d"],
     [0, 1, 2, 3],
-    ["a", "b", "c", "d"]
+    ["a", "b", "c", "d"],
   );
   expectMove(moveOneRight, ["a", "b", "c", "d"], [0, 2], ["b", "a", "d", "c"]);
 });
@@ -39,31 +39,31 @@ it("should moveAllLeft", () => {
     moveAllLeft,
     ["a", "b", "c", "d", "e", "f", "g"],
     [2, 5],
-    ["c", "f", "a", "b", "d", "e", "g"]
+    ["c", "f", "a", "b", "d", "e", "g"],
   );
   expectMove(
     moveAllLeft,
     ["a", "b", "c", "d", "e", "f", "g"],
     [5],
-    ["f", "a", "b", "c", "d", "e", "g"]
+    ["f", "a", "b", "c", "d", "e", "g"],
   );
   expectMove(
     moveAllLeft,
     ["a", "b", "c", "d", "e", "f", "g"],
     [0, 1, 2, 3, 4, 5, 6],
-    ["a", "b", "c", "d", "e", "f", "g"]
+    ["a", "b", "c", "d", "e", "f", "g"],
   );
   expectMove(
     moveAllLeft,
     ["a", "b", "c", "d", "e", "f", "g"],
     [0, 1, 2],
-    ["a", "b", "c", "d", "e", "f", "g"]
+    ["a", "b", "c", "d", "e", "f", "g"],
   );
   expectMove(
     moveAllLeft,
     ["a", "b", "c", "d", "e", "f", "g"],
     [4, 5, 6],
-    ["e", "f", "g", "a", "b", "c", "d"]
+    ["e", "f", "g", "a", "b", "c", "d"],
   );
 });
 
@@ -72,30 +72,30 @@ it("should moveAllRight", () => {
     moveAllRight,
     ["a", "b", "c", "d", "e", "f", "g"],
     [2, 5],
-    ["a", "b", "d", "e", "g", "c", "f"]
+    ["a", "b", "d", "e", "g", "c", "f"],
   );
   expectMove(
     moveAllRight,
     ["a", "b", "c", "d", "e", "f", "g"],
     [5],
-    ["a", "b", "c", "d", "e", "g", "f"]
+    ["a", "b", "c", "d", "e", "g", "f"],
   );
   expectMove(
     moveAllRight,
     ["a", "b", "c", "d", "e", "f", "g"],
     [0, 1, 2, 3, 4, 5, 6],
-    ["a", "b", "c", "d", "e", "f", "g"]
+    ["a", "b", "c", "d", "e", "f", "g"],
   );
   expectMove(
     moveAllRight,
     ["a", "b", "c", "d", "e", "f", "g"],
     [0, 1, 2],
-    ["d", "e", "f", "g", "a", "b", "c"]
+    ["d", "e", "f", "g", "a", "b", "c"],
   );
   expectMove(
     moveAllRight,
     ["a", "b", "c", "d", "e", "f", "g"],
     [4, 5, 6],
-    ["a", "b", "c", "d", "e", "f", "g"]
+    ["a", "b", "c", "d", "e", "f", "g"],
   );
 });

+ 2 - 2
src/zindex.ts

@@ -23,7 +23,7 @@ export function moveOneLeft<T>(elements: T[], indicesToMove: number[]) {
 
 export function moveOneRight<T>(elements: T[], indicesToMove: number[]) {
   const reversedIndicesToMove = indicesToMove.sort(
-    (a: number, b: number) => b - a
+    (a: number, b: number) => b - a,
   );
   let isSorted = true;
 
@@ -166,7 +166,7 @@ export function moveAllLeft<T>(elements: T[], indicesToMove: number[]) {
 // And we are done!
 export function moveAllRight<T>(elements: T[], indicesToMove: number[]) {
   const reversedIndicesToMove = indicesToMove.sort(
-    (a: number, b: number) => b - a
+    (a: number, b: number) => b - a,
   );
 
   // Copy the elements to move