Panayiotis Lipiridis 4 years ago
parent
commit
fde1579884

+ 152 - 97
package-lock.json

@@ -1368,9 +1368,9 @@
       }
     },
     "@firebase/database": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.8.2.tgz",
-      "integrity": "sha512-E86yrom0Ii+61UScG44y1q3H3NuozzGGTGbYmiyTe1qK8Qvzuiu7yyfdDnqFW2fkeKvTRLoDeCpgZy27FgEndQ==",
+      "version": "0.8.3",
+      "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.8.3.tgz",
+      "integrity": "sha512-i29rr3kcPltIkA8La9M1lgsSxx9bfu5lCQ0T+tbJptZ3UpqpcL1NzCcZa24cJjiLgq3HQNPyLvUvCtcPSFDlRg==",
       "requires": {
         "@firebase/auth-interop-types": "0.1.5",
         "@firebase/component": "0.1.21",
@@ -1649,17 +1649,17 @@
       "dev": true
     },
     "@google-cloud/pubsub": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.7.0.tgz",
-      "integrity": "sha512-wc/XOo5Ibo3GWmuaLu80EBIhXSdu2vf99HUqBbdsSSkmRNIka2HqoIhLlOFnnncQn0lZnGL7wtKGIDLoH9LiBg==",
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/@google-cloud/pubsub/-/pubsub-2.8.0.tgz",
+      "integrity": "sha512-AoSKAbpHCoLq6jO9vMX+K6hJhkayafan24Rs2RKHU8Y0qF6IGSm1+ly0OG12TgziHWg818/6dljWWKgwDcp8KA==",
       "dev": true,
       "requires": {
         "@google-cloud/paginator": "^3.0.0",
         "@google-cloud/precise-date": "^2.0.0",
         "@google-cloud/projectify": "^2.0.0",
         "@google-cloud/promisify": "^2.0.0",
-        "@opentelemetry/api": "^0.11.0",
-        "@opentelemetry/tracing": "^0.11.0",
+        "@opentelemetry/api": "^0.12.0",
+        "@opentelemetry/tracing": "^0.12.0",
         "@types/duplexify": "^3.6.0",
         "@types/long": "^4.0.0",
         "arrify": "^2.0.0",
@@ -2460,28 +2460,28 @@
       }
     },
     "@opentelemetry/api": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.11.0.tgz",
-      "integrity": "sha512-K+1ADLMxduhsXoZ0GRfi9Pw162FvzBQLDQlHru1lg86rpIU+4XqdJkSGo6y3Kg+GmOWq1HNHOA/ydw/rzHQkRg==",
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-0.12.0.tgz",
+      "integrity": "sha512-Dn4vU5GlaBrIWzLpsM6xbJwKHdlpwBQ4Bd+cL9ofJP3hKT8jBXpBpribmyaqAzrajzzl2Yt8uTa9rFVLfjDAvw==",
       "dev": true,
       "requires": {
-        "@opentelemetry/context-base": "^0.11.0"
+        "@opentelemetry/context-base": "^0.12.0"
       }
     },
     "@opentelemetry/context-base": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/@opentelemetry/context-base/-/context-base-0.11.0.tgz",
-      "integrity": "sha512-ESRk+572bftles7CVlugAj5Azrz61VO0MO0TS2pE9MLVL/zGmWuUBQryART6/nsrFqo+v9HPt37GPNcECTZR1w==",
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/@opentelemetry/context-base/-/context-base-0.12.0.tgz",
+      "integrity": "sha512-UXwSsXo3F3yZ1dIBOG9ID8v2r9e+bqLWoizCtTb8rXtwF+N5TM7hzzvQz72o3nBU+zrI/D5e+OqAYK8ZgDd3DA==",
       "dev": true
     },
     "@opentelemetry/core": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-0.11.0.tgz",
-      "integrity": "sha512-ZEKjBXeDGBqzouz0uJmrbEKNExEsQOhsZ3tJDCLcz5dUNoVw642oIn2LYWdQK2YdIfZbEmltiF65/csGsaBtFA==",
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-0.12.0.tgz",
+      "integrity": "sha512-oLZIkmTNWTJXzo1eA4dGu/S7wOVtylsgnEsCmhSJGhrJVDXm1eW/aGuNs3DVBeuxp0ZvQLAul3/PThsC3YrnzA==",
       "dev": true,
       "requires": {
-        "@opentelemetry/api": "^0.11.0",
-        "@opentelemetry/context-base": "^0.11.0",
+        "@opentelemetry/api": "^0.12.0",
+        "@opentelemetry/context-base": "^0.12.0",
         "semver": "^7.1.3"
       },
       "dependencies": {
@@ -2506,32 +2506,32 @@
       }
     },
     "@opentelemetry/resources": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-0.11.0.tgz",
-      "integrity": "sha512-o7DwV1TcezqBtS5YW2AWBcn01nVpPptIbTr966PLlVBcS//w8LkjeOShiSZxQ0lmV4b2en0FiSouSDoXk/5qIQ==",
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-0.12.0.tgz",
+      "integrity": "sha512-8cYvIKB68cyupc7D6SWzkLtt13mbjgxMahL4JKCM6hWPyiGSJlPFEAey4XFXI5LLpPZRYTPHLVoLqI/xwCFZZA==",
       "dev": true,
       "requires": {
-        "@opentelemetry/api": "^0.11.0",
-        "@opentelemetry/core": "^0.11.0"
+        "@opentelemetry/api": "^0.12.0",
+        "@opentelemetry/core": "^0.12.0"
       }
     },
     "@opentelemetry/semantic-conventions": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.11.0.tgz",
-      "integrity": "sha512-xsthnI/J+Cx0YVDGgUzvrH0ZTtfNtl866M454NarYwDrc0JvC24sYw+XS5PJyk2KDzAHtb0vlrumUc1OAut/Fw==",
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-0.12.0.tgz",
+      "integrity": "sha512-BuCcDW0uLNYYTns0/LwXkJ8lp8aDm7kpS+WunEmPAPRSCe6ciOYRvzn5reqJfX93rf+6A3U2SgrBnCTH+0qoQQ==",
       "dev": true
     },
     "@opentelemetry/tracing": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/@opentelemetry/tracing/-/tracing-0.11.0.tgz",
-      "integrity": "sha512-QweFmxzl32BcyzwdWCNjVXZT1WeENNS/RWETq/ohqu+fAsTcMyGcr6cOq/yDdFmtBy+bm5WVVdeByEjNS+c4/w==",
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/@opentelemetry/tracing/-/tracing-0.12.0.tgz",
+      "integrity": "sha512-2TUGhTGkhgnxTciHCNAILPSeyXageJewRqfP9wOrx65sKd/jgvNYoY8nYf4EVWVMirDOxKDsmYgUkjdQrwb2dg==",
       "dev": true,
       "requires": {
-        "@opentelemetry/api": "^0.11.0",
-        "@opentelemetry/context-base": "^0.11.0",
-        "@opentelemetry/core": "^0.11.0",
-        "@opentelemetry/resources": "^0.11.0",
-        "@opentelemetry/semantic-conventions": "^0.11.0"
+        "@opentelemetry/api": "^0.12.0",
+        "@opentelemetry/context-base": "^0.12.0",
+        "@opentelemetry/core": "^0.12.0",
+        "@opentelemetry/resources": "^0.12.0",
+        "@opentelemetry/semantic-conventions": "^0.12.0"
       }
     },
     "@pmmmwh/react-refresh-webpack-plugin": {
@@ -2663,70 +2663,125 @@
       }
     },
     "@sentry/browser": {
-      "version": "5.29.2",
-      "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.29.2.tgz",
-      "integrity": "sha512-uxZ7y7rp85tJll+RZtXRhXPbnFnOaxZqJEv05vJlXBtBNLQtlczV5iCtU9mZRLVHDtmZ5VVKUV8IKXntEqqDpQ==",
+      "version": "5.30.0",
+      "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.30.0.tgz",
+      "integrity": "sha512-rOb58ZNVJWh1VuMuBG1mL9r54nZqKeaIlwSlvzJfc89vyfd7n6tQ1UXMN383QBz/MS5H5z44Hy5eE+7pCrYAfw==",
       "requires": {
-        "@sentry/core": "5.29.2",
-        "@sentry/types": "5.29.2",
-        "@sentry/utils": "5.29.2",
+        "@sentry/core": "5.30.0",
+        "@sentry/types": "5.30.0",
+        "@sentry/utils": "5.30.0",
         "tslib": "^1.9.3"
+      },
+      "dependencies": {
+        "@sentry/types": {
+          "version": "5.30.0",
+          "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz",
+          "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw=="
+        },
+        "@sentry/utils": {
+          "version": "5.30.0",
+          "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz",
+          "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==",
+          "requires": {
+            "@sentry/types": "5.30.0",
+            "tslib": "^1.9.3"
+          }
+        }
       }
     },
     "@sentry/core": {
-      "version": "5.29.2",
-      "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.29.2.tgz",
-      "integrity": "sha512-7WYkoxB5IdlNEbwOwqSU64erUKH4laavPsM0/yQ+jojM76ErxlgEF0u//p5WaLPRzh3iDSt6BH+9TL45oNZeZw==",
-      "requires": {
-        "@sentry/hub": "5.29.2",
-        "@sentry/minimal": "5.29.2",
-        "@sentry/types": "5.29.2",
-        "@sentry/utils": "5.29.2",
+      "version": "5.30.0",
+      "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.30.0.tgz",
+      "integrity": "sha512-TmfrII8w1PQZSZgPpUESqjB+jC6MvZJZdLtE/0hZ+SrnKhW3x5WlYLvTXZpcWePYBku7rl2wn1RZu6uT0qCTeg==",
+      "requires": {
+        "@sentry/hub": "5.30.0",
+        "@sentry/minimal": "5.30.0",
+        "@sentry/types": "5.30.0",
+        "@sentry/utils": "5.30.0",
         "tslib": "^1.9.3"
+      },
+      "dependencies": {
+        "@sentry/types": {
+          "version": "5.30.0",
+          "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz",
+          "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw=="
+        },
+        "@sentry/utils": {
+          "version": "5.30.0",
+          "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz",
+          "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==",
+          "requires": {
+            "@sentry/types": "5.30.0",
+            "tslib": "^1.9.3"
+          }
+        }
       }
     },
     "@sentry/hub": {
-      "version": "5.29.2",
-      "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.2.tgz",
-      "integrity": "sha512-LaAIo2hwUk9ykeh9RF0cwLy6IRw+DjEee8l1HfEaDFUM6TPGlNNGObMJNXb9/95jzWp7jWwOpQjoIE3jepdQJQ==",
+      "version": "5.30.0",
+      "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.30.0.tgz",
+      "integrity": "sha512-2tYrGnzb1gKz2EkMDQcfLrDTvmGcQPuWxLnJKXJvYTQDGLlEvi2tWz1VIHjunmOvJrB5aIQLhm+dcMRwFZDCqQ==",
       "requires": {
-        "@sentry/types": "5.29.2",
-        "@sentry/utils": "5.29.2",
+        "@sentry/types": "5.30.0",
+        "@sentry/utils": "5.30.0",
         "tslib": "^1.9.3"
+      },
+      "dependencies": {
+        "@sentry/types": {
+          "version": "5.30.0",
+          "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz",
+          "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw=="
+        },
+        "@sentry/utils": {
+          "version": "5.30.0",
+          "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz",
+          "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==",
+          "requires": {
+            "@sentry/types": "5.30.0",
+            "tslib": "^1.9.3"
+          }
+        }
       }
     },
     "@sentry/integrations": {
-      "version": "5.29.2",
-      "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-5.29.2.tgz",
-      "integrity": "sha512-bH50B0xubbHrJFq8xZRxOc5BgXe1PXKfC0OqQkhhSd+Bu2WDLCHcn0CEzV+8thZTYkipAoFAFJNdEWcsM2Wcew==",
+      "version": "5.30.0",
+      "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-5.30.0.tgz",
+      "integrity": "sha512-Fqh4ALLoQWdd+1ih0iBduANWFyNmFWMxwvBu3V/wLDRi8OcquI0lEzWai1InzTJTiNhRHPnhuU++l/vkO0OCww==",
       "requires": {
-        "@sentry/types": "5.29.2",
-        "@sentry/utils": "5.29.2",
+        "@sentry/types": "5.30.0",
+        "@sentry/utils": "5.30.0",
         "localforage": "1.8.1",
         "tslib": "^1.9.3"
       }
     },
     "@sentry/minimal": {
-      "version": "5.29.2",
-      "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.2.tgz",
-      "integrity": "sha512-0aINSm8fGA1KyM7PavOBe1GDZDxrvnKt+oFnU0L+bTcw8Lr+of+v6Kwd97rkLRNOLw621xP076dL/7LSIzMuhw==",
+      "version": "5.30.0",
+      "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.30.0.tgz",
+      "integrity": "sha512-BwWb/owZKtkDX+Sc4zCSTNcvZUq7YcH3uAVlmh/gtR9rmUvbzAA3ewLuB3myi4wWRAMEtny6+J/FN/x+2wn9Xw==",
       "requires": {
-        "@sentry/hub": "5.29.2",
-        "@sentry/types": "5.29.2",
+        "@sentry/hub": "5.30.0",
+        "@sentry/types": "5.30.0",
         "tslib": "^1.9.3"
+      },
+      "dependencies": {
+        "@sentry/types": {
+          "version": "5.30.0",
+          "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz",
+          "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw=="
+        }
       }
     },
     "@sentry/types": {
-      "version": "5.29.2",
-      "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.2.tgz",
-      "integrity": "sha512-dM9wgt8wy4WRty75QkqQgrw9FV9F+BOMfmc0iaX13Qos7i6Qs2Q0dxtJ83SoR4YGtW8URaHzlDtWlGs5egBiMA=="
+      "version": "5.30.0",
+      "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.30.0.tgz",
+      "integrity": "sha512-R8xOqlSTZ+htqrfteCWU5Nk0CDN5ApUTvrlvBuiH1DyP6czDZ4ktbZB0hAgBlVcK0U+qpD3ag3Tqqpa5Q67rPw=="
     },
     "@sentry/utils": {
-      "version": "5.29.2",
-      "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.2.tgz",
-      "integrity": "sha512-nEwQIDjtFkeE4k6yIk4Ka5XjGRklNLThWLs2xfXlL7uwrYOH2B9UBBOOIRUraBm/g/Xrra3xsam/kRxuiwtXZQ==",
+      "version": "5.30.0",
+      "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.30.0.tgz",
+      "integrity": "sha512-zaYmoH0NWWtvnJjC9/CBseXMtKHm/tm40sz3YfJRxeQjyzRqNQPgivpd9R/oDJCYj999mzdW382p/qi2ypjLww==",
       "requires": {
-        "@sentry/types": "5.29.2",
+        "@sentry/types": "5.30.0",
         "tslib": "^1.9.3"
       }
     },
@@ -2992,9 +3047,9 @@
       }
     },
     "@testing-library/jest-dom": {
-      "version": "5.11.8",
-      "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.8.tgz",
-      "integrity": "sha512-ScyKrWQM5xNcr79PkSewnA79CLaoxVskE+f7knTOhDD9ftZSA1Jw8mj+pneqhEu3x37ncNfW84NUr7lqK+mXjA==",
+      "version": "5.11.9",
+      "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.9.tgz",
+      "integrity": "sha512-Mn2gnA9d1wStlAIT2NU8J15LNob0YFBVjs2aEQ3j8rsfRQo+lAs7/ui1i2TGaJjapLmuNPLTsrm+nPjmZDwpcQ==",
       "requires": {
         "@babel/runtime": "^7.9.2",
         "@types/testing-library__jest-dom": "^5.9.1",
@@ -3360,9 +3415,9 @@
       }
     },
     "@types/socket.io-client": {
-      "version": "1.4.34",
-      "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.34.tgz",
-      "integrity": "sha512-Lzia5OTQFJZJ5R4HsEEldywiiqT9+W2rDbyHJiiTGqOcju89sCsQ8aUXDljY6Ls33wKZZGC0bfMhr/VpOyjtXg=="
+      "version": "1.4.35",
+      "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.35.tgz",
+      "integrity": "sha512-MI8YmxFS+jMkIziycT5ickBWK1sZwDwy16mgH/j99Mcom6zRG/NimNGQ3vJV0uX5G6g/hEw0FG3w3b3sT5OUGw=="
     },
     "@types/source-list-map": {
       "version": "0.1.2",
@@ -8497,9 +8552,9 @@
           }
         },
         "qs": {
-          "version": "6.9.4",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
-          "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==",
+          "version": "6.9.6",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz",
+          "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==",
           "dev": true
         },
         "semver": {
@@ -9012,15 +9067,15 @@
       }
     },
     "firebase": {
-      "version": "8.2.2",
-      "resolved": "https://registry.npmjs.org/firebase/-/firebase-8.2.2.tgz",
-      "integrity": "sha512-a07aW2TTAA9S7p4mx5pu8hvtVokJEjAQlAocHKOWwmRJRIduE9Vvr/3i50FtujT5gGNr0Qm+EyWyB+/7TJiwnw==",
+      "version": "8.2.3",
+      "resolved": "https://registry.npmjs.org/firebase/-/firebase-8.2.3.tgz",
+      "integrity": "sha512-WdbcGSiLxiW/kGZT+EyqD9z3Md7kR35+k9qMjDn/twiIrm6Hh7Qi/Z69cqxhKW6+4uK5ghXIF28CjK67OyD9Qw==",
       "requires": {
         "@firebase/analytics": "0.6.2",
         "@firebase/app": "0.6.13",
         "@firebase/app-types": "0.6.1",
         "@firebase/auth": "0.16.1",
-        "@firebase/database": "0.8.2",
+        "@firebase/database": "0.8.3",
         "@firebase/firestore": "2.1.2",
         "@firebase/functions": "0.6.1",
         "@firebase/installations": "0.4.19",
@@ -9033,9 +9088,9 @@
       }
     },
     "firebase-tools": {
-      "version": "9.1.2",
-      "resolved": "https://registry.npmjs.org/firebase-tools/-/firebase-tools-9.1.2.tgz",
-      "integrity": "sha512-YUiqMuQ+nbdCNpahSO0eyKxxVfT0nDdijkUEUplTGArkDwqdOKPIxVqHj1edq7GEPXTRWlk7zibnbOnCCHaedw==",
+      "version": "9.2.1",
+      "resolved": "https://registry.npmjs.org/firebase-tools/-/firebase-tools-9.2.1.tgz",
+      "integrity": "sha512-sD4wfB5hs/8IKXV6AJOmkpvXf/St7gVc9QeW4Qz21PG7CkirgRf6FqcYkPKtBcro4wfj48dihnYx/IO1+XPTGg==",
       "dev": true,
       "requires": {
         "@google-cloud/pubsub": "^2.7.0",
@@ -10138,9 +10193,9 @@
       },
       "dependencies": {
         "@types/node": {
-          "version": "13.13.39",
-          "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.39.tgz",
-          "integrity": "sha512-wct+WgRTTkBm2R3vbrFOqyZM5w0g+D8KnhstG9463CJBVC3UVZHMToge7iMBR1vDl/I+NWFHUeK9X+JcF0rWKw==",
+          "version": "13.13.40",
+          "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.40.tgz",
+          "integrity": "sha512-eKaRo87lu1yAXrzEJl0zcJxfUMDT5/mZalFyOkT44rnQps41eS2pfWzbaulSPpQLFNy29bFqn+Y5lOTL8ATlEQ==",
           "dev": true
         },
         "duplexify": {
@@ -10776,9 +10831,9 @@
       "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="
     },
     "husky": {
-      "version": "4.3.7",
-      "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.7.tgz",
-      "integrity": "sha512-0fQlcCDq/xypoyYSJvEuzbDPHFf8ZF9IXKJxlrnvxABTSzK1VPT2RKYQKrcgJ+YD39swgoB6sbzywUqFxUiqjw==",
+      "version": "4.3.8",
+      "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.8.tgz",
+      "integrity": "sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow==",
       "dev": true,
       "requires": {
         "chalk": "^4.0.0",
@@ -17645,9 +17700,9 @@
       }
     },
     "proxy-agent": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-4.0.0.tgz",
-      "integrity": "sha512-8P0Y2SkwvKjiGU1IkEfYuTteioMIDFxPL4/j49zzt5Mz3pG1KO+mIrDG1qH0PQUHTTczjwGcYl+EzfXiFj5vUQ==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-4.0.1.tgz",
+      "integrity": "sha512-ODnQnW2jc/FUVwHHuaZEfN5otg/fMbvMxz9nMSUQfJ9JU7q2SZvSULSsjLloVgJOiv9yhc8GlNMKc4GkFmcVEA==",
       "dev": true,
       "requires": {
         "agent-base": "^6.0.0",

+ 7 - 7
package.json

@@ -19,17 +19,17 @@
     ]
   },
   "dependencies": {
-    "@sentry/browser": "5.29.2",
-    "@sentry/integrations": "5.29.2",
-    "@testing-library/jest-dom": "5.11.8",
+    "@sentry/browser": "5.30.0",
+    "@sentry/integrations": "5.30.0",
+    "@testing-library/jest-dom": "5.11.9",
     "@testing-library/react": "11.2.3",
     "@types/jest": "26.0.20",
     "@types/react": "17.0.0",
     "@types/react-dom": "17.0.0",
-    "@types/socket.io-client": "1.4.34",
+    "@types/socket.io-client": "1.4.35",
     "browser-nativefs": "0.12.0",
     "clsx": "1.1.1",
-    "firebase": "8.2.2",
+    "firebase": "8.2.3",
     "i18next-browser-languagedetector": "6.0.1",
     "lodash.throttle": "4.1.1",
     "nanoid": "3.1.20",
@@ -53,8 +53,8 @@
     "@types/pako": "1.0.1",
     "eslint-config-prettier": "7.1.0",
     "eslint-plugin-prettier": "3.3.1",
-    "firebase-tools": "9.1.2",
-    "husky": "4.3.7",
+    "firebase-tools": "9.2.1",
+    "husky": "4.3.8",
     "jest-canvas-mock": "2.3.0",
     "lint-staged": "10.5.3",
     "pepjs": "0.5.3",

+ 2 - 2
src/actions/actionMenu.tsx

@@ -74,13 +74,13 @@ export const actionShortcuts = register({
     return {
       appState: {
         ...appState,
-        showShortcutsDialog: true,
+        showHelpDialog: true,
       },
       commitToHistory: false,
     };
   },
   PanelComponent: ({ updateData }) => (
-    <HelpIcon title={t("shortcutsDialog.title")} onClick={updateData} />
+    <HelpIcon title={t("helpDialog.title")} onClick={updateData} />
   ),
   keyTest: (event) => event.key === KEYS.QUESTION_MARK,
 });

+ 1 - 1
src/actions/shortcuts.ts

@@ -34,7 +34,7 @@ const shortcutMap: Record<ShortcutName, string[]> = {
   delete: [getShortcutKey("Del")],
   duplicateSelection: [
     getShortcutKey("CtrlOrCmd+D"),
-    getShortcutKey(`Alt+${t("shortcutsDialog.drag")}`),
+    getShortcutKey(`Alt+${t("helpDialog.drag")}`),
   ],
   sendBackward: [getShortcutKey("CtrlOrCmd+[")],
   bringForward: [getShortcutKey("CtrlOrCmd+]")],

+ 2 - 2
src/appState.ts

@@ -63,7 +63,7 @@ export const getDefaultAppState = (): Omit<
     selectionElement: null,
     shouldAddWatermark: false,
     shouldCacheIgnoreZoom: false,
-    showShortcutsDialog: false,
+    showHelpDialog: false,
     showStats: false,
     startBoundElement: null,
     suggestedBindings: [],
@@ -142,7 +142,7 @@ const APP_STATE_STORAGE_CONF = (<
   selectionElement: { browser: false, export: false },
   shouldAddWatermark: { browser: true, export: false },
   shouldCacheIgnoreZoom: { browser: true, export: false },
-  showShortcutsDialog: { browser: false, export: false },
+  showHelpDialog: { browser: false, export: false },
   showStats: { browser: true, export: false },
   startBoundElement: { browser: false, export: false },
   suggestedBindings: { browser: false, export: false },

+ 3 - 3
src/components/Actions.tsx

@@ -163,9 +163,9 @@ export const ShapesSwitcher = ({
     {SHAPES.map(({ value, icon, key }, index) => {
       const label = t(`toolBar.${value}`);
       const letter = typeof key === "string" ? key : key[0];
-      const shortcut = `${capitalizeString(letter)} ${t(
-        "shortcutsDialog.or",
-      )} ${index + 1}`;
+      const shortcut = `${capitalizeString(letter)} ${t("helpDialog.or")} ${
+        index + 1
+      }`;
       return (
         <ToolButton
           className="Shape"

+ 1 - 4
src/components/App.tsx

@@ -1249,7 +1249,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
 
     if (event.key === KEYS.QUESTION_MARK) {
       this.setState({
-        showShortcutsDialog: true,
+        showHelpDialog: true,
       });
     }
 
@@ -3587,9 +3587,6 @@ class App extends React.Component<ExcalidrawProps, AppState> {
       transformElements(
         pointerDownState,
         transformHandleType,
-        (newTransformHandle) => {
-          pointerDownState.resize.handleType = newTransformHandle;
-        },
         selectedElements,
         pointerDownState.resize.arrowDirection,
         getRotateWithDiscreteAngleKey(event),

+ 1 - 0
src/components/Dialog.scss

@@ -15,6 +15,7 @@
     padding: calc(var(--space-factor) * 2);
     text-align: center;
     font-variant: small-caps;
+    font-size: 1.2em;
   }
 
   .Dialog__titleContent {

+ 2 - 2
src/components/Dialog.tsx

@@ -80,7 +80,7 @@ export const Dialog = (props: {
       onCloseRequest={props.onCloseRequest}
     >
       <Island ref={setIslandNode}>
-        <h3 id="dialog-title" className="Dialog__title">
+        <h2 id="dialog-title" className="Dialog__title">
           <span className="Dialog__titleContent">{props.title}</span>
           <button
             className="Modal__close"
@@ -89,7 +89,7 @@ export const Dialog = (props: {
           >
             {useIsMobile() ? back : close}
           </button>
-        </h3>
+        </h2>
         <div className="Dialog__content">{props.children}</div>
       </Island>
     </Modal>

+ 21 - 8
src/components/ShortcutsDialog.scss → src/components/HelpDialog.scss

@@ -1,23 +1,28 @@
 @import "../css/_variables";
 
 .excalidraw {
-  .ShortcutsDialog-island {
+  .HelpDialog h3 {
+    border-bottom: 1px solid var(--button-gray-2);
+    padding-bottom: 4px;
+  }
+
+  .HelpDialog--island {
     border: 1px solid var(--button-gray-2);
     margin-bottom: 16px;
   }
 
-  .ShortcutsDialog-island-title {
+  .HelpDialog--island-title {
     margin: 0;
     padding: 4px;
     background-color: var(--button-gray-1);
     text-align: center;
   }
 
-  .ShorcutsDialog-shortcut {
+  .HelpDialog--shortcut {
     border-top: 1px solid var(--button-gray-2);
   }
 
-  .ShorcutsDialog-key {
+  .HelpDialog--key {
     word-break: keep-all;
     border: 1px solid var(--button-gray-2);
     padding: 2px 8px;
@@ -32,12 +37,20 @@
     font-family: inherit;
   }
 
-  .ShortcutsDialog-footer {
+  .HelpDialog--header {
     display: flex;
     flex-direction: row;
     justify-content: space-evenly;
-    border-top: 1px solid var(--button-gray-2);
-    margin-top: 8px;
-    padding-top: 16px;
+    margin-bottom: 32px;
+    padding-bottom: 16px;
+  }
+
+  .HelpDialog--btn {
+    border: 1px solid var(--link-color);
+    padding: 8px 32px;
+    border-radius: 4px;
+  }
+  .HelpDialog--btn:hover {
+    text-decoration: none;
   }
 }

+ 348 - 0
src/components/HelpDialog.tsx

@@ -0,0 +1,348 @@
+import React from "react";
+import { t } from "../i18n";
+import { isDarwin } from "../keys";
+import { Dialog } from "./Dialog";
+import { getShortcutKey } from "../utils";
+import "./HelpDialog.scss";
+
+const Header = () => (
+  <div className="HelpDialog--header">
+    <a
+      className="HelpDialog--btn"
+      href="https://github.com/excalidraw/excalidraw#documentation"
+      target="_blank"
+      rel="noopener noreferrer"
+    >
+      {t("helpDialog.documentation")}
+    </a>
+    <a
+      className="HelpDialog--btn"
+      href="https://blog.excalidraw.com"
+      target="_blank"
+      rel="noopener noreferrer"
+    >
+      {t("helpDialog.blog")}
+    </a>
+    <a
+      className="HelpDialog--btn"
+      href="https://github.com/excalidraw/excalidraw/issues"
+      target="_blank"
+      rel="noopener noreferrer"
+    >
+      {t("helpDialog.github")}
+    </a>
+  </div>
+);
+
+const Section = (props: { title: string; children: React.ReactNode }) => (
+  <>
+    <h3>{props.title}</h3>
+    {props.children}
+  </>
+);
+
+const Columns = (props: { children: React.ReactNode }) => (
+  <div
+    style={{
+      display: "flex",
+      flexDirection: "row",
+      flexWrap: "wrap",
+      justifyContent: "space-between",
+    }}
+  >
+    {props.children}
+  </div>
+);
+
+const Column = (props: { children: React.ReactNode }) => (
+  <div style={{ width: "49%" }}>{props.children}</div>
+);
+
+const ShortcutIsland = (props: {
+  caption: string;
+  children: React.ReactNode;
+}) => (
+  <div className="HelpDialog--island">
+    <h3 className="HelpDialog--island-title">{props.caption}</h3>
+    {props.children}
+  </div>
+);
+
+const Shortcut = (props: {
+  label: string;
+  shortcuts: string[];
+  isOr: boolean;
+}) => {
+  return (
+    <div className="HelpDialog--shortcut">
+      <div
+        style={{
+          display: "flex",
+          margin: "0",
+          padding: "4px 8px",
+          alignItems: "center",
+        }}
+      >
+        <div
+          style={{
+            lineHeight: 1.4,
+          }}
+        >
+          {props.label}
+        </div>
+        <div
+          style={{
+            display: "flex",
+            flex: "0 0 auto",
+            justifyContent: "flex-end",
+            marginInlineStart: "auto",
+            minWidth: "30%",
+          }}
+        >
+          {props.shortcuts.map((shortcut, index) => (
+            <React.Fragment key={index}>
+              <ShortcutKey>{shortcut}</ShortcutKey>
+              {props.isOr &&
+                index !== props.shortcuts.length - 1 &&
+                t("helpDialog.or")}
+            </React.Fragment>
+          ))}
+        </div>
+      </div>
+    </div>
+  );
+};
+
+Shortcut.defaultProps = {
+  isOr: true,
+};
+
+const ShortcutKey = (props: { children: React.ReactNode }) => (
+  <kbd className="HelpDialog--key" {...props} />
+);
+
+export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
+  const handleClose = React.useCallback(() => {
+    if (onClose) {
+      onClose();
+    }
+  }, [onClose]);
+
+  return (
+    <>
+      <Dialog
+        onCloseRequest={handleClose}
+        title={t("helpDialog.title")}
+        className={"HelpDialog"}
+      >
+        <Header />
+        <Section title={t("helpDialog.shortcuts")}>
+          <Columns>
+            <Column>
+              <ShortcutIsland caption={t("helpDialog.shapes")}>
+                <Shortcut
+                  label={t("toolBar.selection")}
+                  shortcuts={["V", "1"]}
+                />
+                <Shortcut
+                  label={t("toolBar.rectangle")}
+                  shortcuts={["R", "2"]}
+                />
+                <Shortcut label={t("toolBar.diamond")} shortcuts={["D", "3"]} />
+                <Shortcut label={t("toolBar.ellipse")} shortcuts={["E", "4"]} />
+                <Shortcut label={t("toolBar.arrow")} shortcuts={["A", "5"]} />
+                <Shortcut label={t("toolBar.line")} shortcuts={["P", "6"]} />
+                <Shortcut
+                  label={t("toolBar.draw")}
+                  shortcuts={["Shift+P", "7"]}
+                />
+                <Shortcut label={t("toolBar.text")} shortcuts={["T", "8"]} />
+                <Shortcut
+                  label={t("helpDialog.textNewLine")}
+                  shortcuts={[
+                    getShortcutKey("Enter"),
+                    getShortcutKey("Shift+Enter"),
+                  ]}
+                />
+                <Shortcut
+                  label={t("helpDialog.textFinish")}
+                  shortcuts={[
+                    getShortcutKey("Esc"),
+                    getShortcutKey("CtrlOrCmd+Enter"),
+                  ]}
+                />
+                <Shortcut
+                  label={t("helpDialog.curvedArrow")}
+                  shortcuts={[
+                    "A",
+                    t("helpDialog.click"),
+                    t("helpDialog.click"),
+                    t("helpDialog.click"),
+                  ]}
+                  isOr={false}
+                />
+                <Shortcut
+                  label={t("helpDialog.curvedLine")}
+                  shortcuts={[
+                    "L",
+                    t("helpDialog.click"),
+                    t("helpDialog.click"),
+                    t("helpDialog.click"),
+                  ]}
+                  isOr={false}
+                />
+                <Shortcut label={t("toolBar.lock")} shortcuts={["Q"]} />
+                <Shortcut
+                  label={t("helpDialog.preventBinding")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd")]}
+                />
+              </ShortcutIsland>
+              <ShortcutIsland caption={t("helpDialog.view")}>
+                <Shortcut
+                  label={t("buttons.zoomIn")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd++")]}
+                />
+                <Shortcut
+                  label={t("buttons.zoomOut")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+-")]}
+                />
+                <Shortcut
+                  label={t("buttons.resetZoom")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+0")]}
+                />
+                <Shortcut
+                  label={t("helpDialog.zoomToFit")}
+                  shortcuts={["Shift+1"]}
+                />
+                <Shortcut
+                  label={t("helpDialog.zoomToSelection")}
+                  shortcuts={["Shift+2"]}
+                />
+                <Shortcut label={t("buttons.fullScreen")} shortcuts={["F"]} />
+                <Shortcut
+                  label={t("buttons.zenMode")}
+                  shortcuts={[getShortcutKey("Alt+Z")]}
+                />
+                <Shortcut
+                  label={t("labels.gridMode")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+'")]}
+                />
+              </ShortcutIsland>
+            </Column>
+            <Column>
+              <ShortcutIsland caption={t("helpDialog.editor")}>
+                <Shortcut
+                  label={t("labels.selectAll")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+A")]}
+                />
+                <Shortcut
+                  label={t("labels.multiSelect")}
+                  shortcuts={[getShortcutKey(`Shift+${t("helpDialog.click")}`)]}
+                />
+                <Shortcut
+                  label={t("labels.moveCanvas")}
+                  shortcuts={[
+                    getShortcutKey(`Space+${t("helpDialog.drag")}`),
+                    getShortcutKey(`Wheel+${t("helpDialog.drag")}`),
+                  ]}
+                  isOr={true}
+                />
+                <Shortcut
+                  label={t("labels.cut")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+X")]}
+                />
+                <Shortcut
+                  label={t("labels.copy")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+C")]}
+                />
+                <Shortcut
+                  label={t("labels.paste")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+V")]}
+                />
+                <Shortcut
+                  label={t("labels.copyAsPng")}
+                  shortcuts={[getShortcutKey("Shift+Alt+C")]}
+                />
+                <Shortcut
+                  label={t("labels.copyStyles")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+Alt+C")]}
+                />
+                <Shortcut
+                  label={t("labels.pasteStyles")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+Alt+V")]}
+                />
+                <Shortcut
+                  label={t("labels.delete")}
+                  shortcuts={[getShortcutKey("Del")]}
+                />
+                <Shortcut
+                  label={t("labels.sendToBack")}
+                  shortcuts={[
+                    isDarwin
+                      ? getShortcutKey("CtrlOrCmd+Alt+[")
+                      : getShortcutKey("CtrlOrCmd+Shift+["),
+                  ]}
+                />
+                <Shortcut
+                  label={t("labels.bringToFront")}
+                  shortcuts={[
+                    isDarwin
+                      ? getShortcutKey("CtrlOrCmd+Alt+]")
+                      : getShortcutKey("CtrlOrCmd+Shift+]"),
+                  ]}
+                />
+                <Shortcut
+                  label={t("labels.sendBackward")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+[")]}
+                />
+                <Shortcut
+                  label={t("labels.bringForward")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+]")]}
+                />
+                <Shortcut
+                  label={t("labels.alignTop")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Up")]}
+                />
+                <Shortcut
+                  label={t("labels.alignBottom")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Down")]}
+                />
+                <Shortcut
+                  label={t("labels.alignLeft")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Left")]}
+                />
+                <Shortcut
+                  label={t("labels.alignRight")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Right")]}
+                />
+                <Shortcut
+                  label={t("labels.duplicateSelection")}
+                  shortcuts={[
+                    getShortcutKey("CtrlOrCmd+D"),
+                    getShortcutKey(`Alt+${t("helpDialog.drag")}`),
+                  ]}
+                />
+                <Shortcut
+                  label={t("buttons.undo")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+Z")]}
+                />
+                <Shortcut
+                  label={t("buttons.redo")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Z")]}
+                />
+                <Shortcut
+                  label={t("labels.group")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+G")]}
+                />
+                <Shortcut
+                  label={t("labels.ungroup")}
+                  shortcuts={[getShortcutKey("CtrlOrCmd+Shift+G")]}
+                />
+              </ShortcutIsland>
+            </Column>
+          </Columns>
+        </Section>
+      </Dialog>
+    </>
+  );
+};

+ 2 - 12
src/components/HelpIcon.tsx

@@ -1,4 +1,5 @@
 import React from "react";
+import { questionCircle } from "../components/icons";
 
 type HelpIconProps = {
   title?: string;
@@ -7,19 +8,8 @@ type HelpIconProps = {
   onClick?(): void;
 };
 
-const ICON = (
-  <svg
-    width="30"
-    height="22"
-    viewBox="0 0 512 512"
-    xmlns="http://www.w3.org/2000/svg"
-  >
-    <path d="M528 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM128 180v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z" />
-  </svg>
-);
-
 export const HelpIcon = (props: HelpIconProps) => (
   <label title={`${props.title} — ?`} className="help-icon">
-    <div onClick={props.onClick}>{ICON}</div>
+    <div onClick={props.onClick}>{questionCircle}</div>
   </label>
 );

+ 3 - 5
src/components/LayerUI.tsx

@@ -36,7 +36,7 @@ import { LockIcon } from "./LockIcon";
 import { MobileMenu } from "./MobileMenu";
 import { PasteChartDialog } from "./PasteChartDialog";
 import { Section } from "./Section";
-import { ShortcutsDialog } from "./ShortcutsDialog";
+import { HelpDialog } from "./HelpDialog";
 import Stack from "./Stack";
 import { ToolButton } from "./ToolButton";
 import { Tooltip } from "./Tooltip";
@@ -566,10 +566,8 @@ const LayerUI = ({
           onClose={() => setAppState({ errorMessage: null })}
         />
       )}
-      {appState.showShortcutsDialog && (
-        <ShortcutsDialog
-          onClose={() => setAppState({ showShortcutsDialog: false })}
-        />
+      {appState.showHelpDialog && (
+        <HelpDialog onClose={() => setAppState({ showHelpDialog: false })} />
       )}
       {appState.pasteDialog.shown && (
         <PasteChartDialog

+ 0 - 321
src/components/ShortcutsDialog.tsx

@@ -1,321 +0,0 @@
-import React from "react";
-import { t } from "../i18n";
-import { isDarwin } from "../keys";
-import { Dialog } from "./Dialog";
-import { getShortcutKey } from "../utils";
-import "./ShortcutsDialog.scss";
-
-const Columns = (props: { children: React.ReactNode }) => (
-  <div
-    style={{
-      display: "flex",
-      flexDirection: "row",
-      flexWrap: "wrap",
-      justifyContent: "space-between",
-    }}
-  >
-    {props.children}
-  </div>
-);
-
-const Column = (props: { children: React.ReactNode }) => (
-  <div style={{ width: "49%" }}>{props.children}</div>
-);
-
-const ShortcutIsland = (props: {
-  caption: string;
-  children: React.ReactNode;
-}) => (
-  <div className="ShortcutsDialog-island">
-    <h3 className="ShortcutsDialog-island-title">{props.caption}</h3>
-    {props.children}
-  </div>
-);
-
-const Shortcut = (props: {
-  label: string;
-  shortcuts: string[];
-  isOr: boolean;
-}) => {
-  return (
-    <div className="ShorcutsDialog-shortcut">
-      <div
-        style={{
-          display: "flex",
-          margin: "0",
-          padding: "4px 8px",
-          alignItems: "center",
-        }}
-      >
-        <div
-          style={{
-            lineHeight: 1.4,
-          }}
-        >
-          {props.label}
-        </div>
-        <div
-          style={{
-            display: "flex",
-            flex: "0 0 auto",
-            justifyContent: "flex-end",
-            marginInlineStart: "auto",
-            minWidth: "30%",
-          }}
-        >
-          {props.shortcuts.map((shortcut, index) => (
-            <React.Fragment key={index}>
-              <ShortcutKey>{shortcut}</ShortcutKey>
-              {props.isOr &&
-                index !== props.shortcuts.length - 1 &&
-                t("shortcutsDialog.or")}
-            </React.Fragment>
-          ))}
-        </div>
-      </div>
-    </div>
-  );
-};
-
-Shortcut.defaultProps = {
-  isOr: true,
-};
-
-const ShortcutKey = (props: { children: React.ReactNode }) => (
-  <kbd className="ShorcutsDialog-key" {...props} />
-);
-
-const Footer = () => (
-  <div className="ShortcutsDialog-footer">
-    <a
-      href="https://blog.excalidraw.com"
-      target="_blank"
-      rel="noopener noreferrer"
-    >
-      {t("shortcutsDialog.blog")}
-    </a>
-    <a
-      href="https://github.com/excalidraw/excalidraw/issues"
-      target="_blank"
-      rel="noopener noreferrer"
-    >
-      {t("shortcutsDialog.github")}
-    </a>
-  </div>
-);
-
-export const ShortcutsDialog = ({ onClose }: { onClose?: () => void }) => {
-  const handleClose = React.useCallback(() => {
-    if (onClose) {
-      onClose();
-    }
-  }, [onClose]);
-
-  return (
-    <>
-      <Dialog onCloseRequest={handleClose} title={t("shortcutsDialog.title")}>
-        <Columns>
-          <Column>
-            <ShortcutIsland caption={t("shortcutsDialog.shapes")}>
-              <Shortcut label={t("toolBar.selection")} shortcuts={["V", "1"]} />
-              <Shortcut label={t("toolBar.rectangle")} shortcuts={["R", "2"]} />
-              <Shortcut label={t("toolBar.diamond")} shortcuts={["D", "3"]} />
-              <Shortcut label={t("toolBar.ellipse")} shortcuts={["E", "4"]} />
-              <Shortcut label={t("toolBar.arrow")} shortcuts={["A", "5"]} />
-              <Shortcut label={t("toolBar.line")} shortcuts={["P", "6"]} />
-              <Shortcut
-                label={t("toolBar.draw")}
-                shortcuts={["Shift+P", "7"]}
-              />
-              <Shortcut label={t("toolBar.text")} shortcuts={["T", "8"]} />
-              <Shortcut
-                label={t("shortcutsDialog.textNewLine")}
-                shortcuts={[
-                  getShortcutKey("Enter"),
-                  getShortcutKey("Shift+Enter"),
-                ]}
-              />
-              <Shortcut
-                label={t("shortcutsDialog.textFinish")}
-                shortcuts={[
-                  getShortcutKey("Esc"),
-                  getShortcutKey("CtrlOrCmd+Enter"),
-                ]}
-              />
-              <Shortcut
-                label={t("shortcutsDialog.curvedArrow")}
-                shortcuts={[
-                  "A",
-                  t("shortcutsDialog.click"),
-                  t("shortcutsDialog.click"),
-                  t("shortcutsDialog.click"),
-                ]}
-                isOr={false}
-              />
-              <Shortcut
-                label={t("shortcutsDialog.curvedLine")}
-                shortcuts={[
-                  "L",
-                  t("shortcutsDialog.click"),
-                  t("shortcutsDialog.click"),
-                  t("shortcutsDialog.click"),
-                ]}
-                isOr={false}
-              />
-              <Shortcut label={t("toolBar.lock")} shortcuts={["Q"]} />
-              <Shortcut
-                label={t("shortcutsDialog.preventBinding")}
-                shortcuts={[getShortcutKey("CtrlOrCmd")]}
-              />
-            </ShortcutIsland>
-            <ShortcutIsland caption={t("shortcutsDialog.view")}>
-              <Shortcut
-                label={t("buttons.zoomIn")}
-                shortcuts={[getShortcutKey("CtrlOrCmd++")]}
-              />
-              <Shortcut
-                label={t("buttons.zoomOut")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+-")]}
-              />
-              <Shortcut
-                label={t("buttons.resetZoom")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+0")]}
-              />
-              <Shortcut
-                label={t("shortcutsDialog.zoomToFit")}
-                shortcuts={["Shift+1"]}
-              />
-              <Shortcut
-                label={t("shortcutsDialog.zoomToSelection")}
-                shortcuts={["Shift+2"]}
-              />
-              <Shortcut label={t("buttons.fullScreen")} shortcuts={["F"]} />
-              <Shortcut
-                label={t("buttons.zenMode")}
-                shortcuts={[getShortcutKey("Alt+Z")]}
-              />
-              <Shortcut
-                label={t("labels.gridMode")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+'")]}
-              />
-            </ShortcutIsland>
-          </Column>
-          <Column>
-            <ShortcutIsland caption={t("shortcutsDialog.editor")}>
-              <Shortcut
-                label={t("labels.selectAll")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+A")]}
-              />
-              <Shortcut
-                label={t("labels.multiSelect")}
-                shortcuts={[
-                  getShortcutKey(`Shift+${t("shortcutsDialog.click")}`),
-                ]}
-              />
-              <Shortcut
-                label={t("labels.moveCanvas")}
-                shortcuts={[
-                  getShortcutKey(`Space+${t("shortcutsDialog.drag")}`),
-                  getShortcutKey(`Wheel+${t("shortcutsDialog.drag")}`),
-                ]}
-                isOr={true}
-              />
-              <Shortcut
-                label={t("labels.cut")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+X")]}
-              />
-              <Shortcut
-                label={t("labels.copy")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+C")]}
-              />
-              <Shortcut
-                label={t("labels.paste")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+V")]}
-              />
-              <Shortcut
-                label={t("labels.copyAsPng")}
-                shortcuts={[getShortcutKey("Shift+Alt+C")]}
-              />
-              <Shortcut
-                label={t("labels.copyStyles")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+Alt+C")]}
-              />
-              <Shortcut
-                label={t("labels.pasteStyles")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+Alt+V")]}
-              />
-              <Shortcut
-                label={t("labels.delete")}
-                shortcuts={[getShortcutKey("Del")]}
-              />
-              <Shortcut
-                label={t("labels.sendToBack")}
-                shortcuts={[
-                  isDarwin
-                    ? getShortcutKey("CtrlOrCmd+Alt+[")
-                    : getShortcutKey("CtrlOrCmd+Shift+["),
-                ]}
-              />
-              <Shortcut
-                label={t("labels.bringToFront")}
-                shortcuts={[
-                  isDarwin
-                    ? getShortcutKey("CtrlOrCmd+Alt+]")
-                    : getShortcutKey("CtrlOrCmd+Shift+]"),
-                ]}
-              />
-              <Shortcut
-                label={t("labels.sendBackward")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+[")]}
-              />
-              <Shortcut
-                label={t("labels.bringForward")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+]")]}
-              />
-              <Shortcut
-                label={t("labels.alignTop")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Up")]}
-              />
-              <Shortcut
-                label={t("labels.alignBottom")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Down")]}
-              />
-              <Shortcut
-                label={t("labels.alignLeft")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Left")]}
-              />
-              <Shortcut
-                label={t("labels.alignRight")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Right")]}
-              />
-              <Shortcut
-                label={t("labels.duplicateSelection")}
-                shortcuts={[
-                  getShortcutKey("CtrlOrCmd+D"),
-                  getShortcutKey(`Alt+${t("shortcutsDialog.drag")}`),
-                ]}
-              />
-              <Shortcut
-                label={t("buttons.undo")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+Z")]}
-              />
-              <Shortcut
-                label={t("buttons.redo")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+Shift+Z")]}
-              />
-              <Shortcut
-                label={t("labels.group")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+G")]}
-              />
-              <Shortcut
-                label={t("labels.ungroup")}
-                shortcuts={[getShortcutKey("CtrlOrCmd+Shift+G")]}
-              />
-            </ShortcutIsland>
-          </Column>
-        </Columns>
-        <Footer />
-      </Dialog>
-    </>
-  );
-};

+ 1 - 0
src/constants.ts

@@ -90,3 +90,4 @@ export const TAP_TWICE_TIMEOUT = 300;
 export const TITLE_TIMEOUT = 10000;
 export const TOAST_TIMEOUT = 5000;
 export const TOUCH_CTX_MENU_TIMEOUT = 500;
+export const VERSION_TIMEOUT = 15000;

+ 2 - 1
src/css/styles.scss

@@ -13,7 +13,7 @@
   a {
     font-weight: 500;
     text-decoration: none;
-    color: $oc-blue-7; /* OC Blue 7 */
+    color: var(--link-color);
 
     &:hover {
       text-decoration: underline;
@@ -431,6 +431,7 @@
     cursor: pointer;
     fill: $oc-gray-6;
     bottom: 14px;
+    width: 1.5rem;
 
     :root[dir="ltr"] & {
       right: 14px;

+ 1 - 0
src/css/theme.scss

@@ -19,6 +19,7 @@
   --input-label-color: #{$oc-gray-7};
   --island-bg-color: #{transparentize($oc-white, 0.12)};
   --keybinding-color: #{$oc-gray-5};
+  --link-color: #{$oc-blue-7};
   --overlay-bg-color: #{transparentize($oc-white, 0.12)};
   --popup-bg-color: #{$oc-white};
   --popup-secondary-bg-color: #{$oc-gray-1};

+ 0 - 1
src/element/index.ts

@@ -34,7 +34,6 @@ export {
 export {
   resizeTest,
   getCursorForResizingElement,
-  normalizeTransformHandleType,
   getElementWithTransformHandleType,
   getTransformHandleTypeFromCoords,
 } from "./resizeTest";

+ 111 - 206
src/element/resizeElements.ts

@@ -4,7 +4,6 @@ import { rescalePoints } from "../points";
 import {
   rotate,
   adjustXYWithRotation,
-  getFlipAdjustment,
   centerPoint,
   rotatePoint,
 } from "../math";
@@ -13,21 +12,16 @@ import {
   ExcalidrawTextElement,
   NonDeletedExcalidrawElement,
   NonDeleted,
-  ExcalidrawGenericElement,
-  ExcalidrawElement,
 } from "./types";
 import {
   getElementAbsoluteCoords,
   getCommonBounds,
   getResizedElementAbsoluteCoords,
 } from "./bounds";
-import { isGenericElement, isLinearElement, isTextElement } from "./typeChecks";
+import { isLinearElement, isTextElement } from "./typeChecks";
 import { mutateElement } from "./mutateElement";
 import { getPerfectElementSize } from "./sizeHelpers";
-import {
-  getCursorForResizingElement,
-  normalizeTransformHandleType,
-} from "./resizeTest";
+import { getCursorForResizingElement } from "./resizeTest";
 import { measureText, getFontString } from "../utils";
 import { updateBoundElements } from "./binding";
 import {
@@ -49,7 +43,6 @@ const normalizeAngle = (angle: number): number => {
 export const transformElements = (
   pointerDownState: PointerDownState,
   transformHandleType: MaybeTransformHandleType,
-  setTransformHandle: (nextTransformHandle: MaybeTransformHandleType) => void,
   selectedElements: readonly NonDeletedExcalidrawElement[],
   resizeArrowDirection: "origin" | "end",
   isRotateWithDiscreteAngle: boolean,
@@ -101,36 +94,15 @@ export const transformElements = (
       );
       updateBoundElements(element);
     } else if (transformHandleType) {
-      if (isGenericElement(element)) {
-        resizeSingleGenericElement(
-          pointerDownState.originalElements.get(element.id) as typeof element,
-          shouldKeepSidesRatio,
-          element,
-          transformHandleType,
-          isResizeCenterPoint,
-          pointerX,
-          pointerY,
-        );
-      } else {
-        const keepSquareAspectRatio = shouldKeepSidesRatio;
-        resizeSingleNonGenericElement(
-          element,
-          transformHandleType,
-          isResizeCenterPoint,
-          keepSquareAspectRatio,
-          pointerX,
-          pointerY,
-        );
-        setTransformHandle(
-          normalizeTransformHandleType(element, transformHandleType),
-        );
-        if (element.width < 0) {
-          mutateElement(element, { width: -element.width });
-        }
-        if (element.height < 0) {
-          mutateElement(element, { height: -element.height });
-        }
-      }
+      resizeSingleElement(
+        pointerDownState.originalElements.get(element.id) as typeof element,
+        shouldKeepSidesRatio,
+        element,
+        transformHandleType,
+        isResizeCenterPoint,
+        pointerX,
+        pointerY,
+      );
     }
 
     // update cursor
@@ -414,8 +386,8 @@ const resizeSingleTextElement = (
   }
 };
 
-const resizeSingleGenericElement = (
-  stateAtResizeStart: NonDeleted<ExcalidrawGenericElement>,
+const resizeSingleElement = (
+  stateAtResizeStart: NonDeletedExcalidrawElement,
   shouldKeepSidesRatio: boolean,
   element: NonDeletedExcalidrawElement,
   transformHandleDirection: TransformHandleDirection,
@@ -423,251 +395,184 @@ const resizeSingleGenericElement = (
   pointerX: number,
   pointerY: number,
 ) => {
-  const [x1, y1, x2, y2] = getElementAbsoluteCoords(stateAtResizeStart);
+  // Gets bounds corners
+  const [x1, y1, x2, y2] = getResizedElementAbsoluteCoords(
+    stateAtResizeStart,
+    stateAtResizeStart.width,
+    stateAtResizeStart.height,
+  );
   const startTopLeft: Point = [x1, y1];
   const startBottomRight: Point = [x2, y2];
   const startCenter: Point = centerPoint(startTopLeft, startBottomRight);
 
   // Calculate new dimensions based on cursor position
-  let newWidth = stateAtResizeStart.width;
-  let newHeight = stateAtResizeStart.height;
   const rotatedPointer = rotatePoint(
     [pointerX, pointerY],
     startCenter,
     -stateAtResizeStart.angle,
   );
+
+  //Get bounds corners rendered on screen
+  const [esx1, esy1, esx2, esy2] = getResizedElementAbsoluteCoords(
+    element,
+    element.width,
+    element.height,
+  );
+  const boundsCurrentWidth = esx2 - esx1;
+  const boundsCurrentHeight = esy2 - esy1;
+
+  // It's important we set the initial scale value based on the width and height at resize start,
+  // otherwise previous dimensions affected by modifiers will be taken into account.
+  const atStartBoundsWidth = startBottomRight[0] - startTopLeft[0];
+  const atStartBoundsHeight = startBottomRight[1] - startTopLeft[1];
+  let scaleX = atStartBoundsWidth / boundsCurrentWidth;
+  let scaleY = atStartBoundsHeight / boundsCurrentHeight;
+
   if (transformHandleDirection.includes("e")) {
-    newWidth = rotatedPointer[0] - startTopLeft[0];
+    scaleX = (rotatedPointer[0] - startTopLeft[0]) / boundsCurrentWidth;
   }
   if (transformHandleDirection.includes("s")) {
-    newHeight = rotatedPointer[1] - startTopLeft[1];
+    scaleY = (rotatedPointer[1] - startTopLeft[1]) / boundsCurrentHeight;
   }
   if (transformHandleDirection.includes("w")) {
-    newWidth = startBottomRight[0] - rotatedPointer[0];
+    scaleX = (startBottomRight[0] - rotatedPointer[0]) / boundsCurrentWidth;
   }
   if (transformHandleDirection.includes("n")) {
-    newHeight = startBottomRight[1] - rotatedPointer[1];
+    scaleY = (startBottomRight[1] - rotatedPointer[1]) / boundsCurrentHeight;
   }
+  // Linear elements dimensions differ from bounds dimensions
+  const eleInitialWidth = stateAtResizeStart.width;
+  const eleInitialHeight = stateAtResizeStart.height;
+  // We have to use dimensions of element on screen, otherwise the scaling of the
+  // dimensions won't match the cursor for linear elements.
+  let eleNewWidth = element.width * scaleX;
+  let eleNewHeight = element.height * scaleY;
 
   // adjust dimensions for resizing from center
   if (isResizeFromCenter) {
-    newWidth = 2 * newWidth - stateAtResizeStart.width;
-    newHeight = 2 * newHeight - stateAtResizeStart.height;
+    eleNewWidth = 2 * eleNewWidth - eleInitialWidth;
+    eleNewHeight = 2 * eleNewHeight - eleInitialHeight;
   }
 
   // adjust dimensions to keep sides ratio
   if (shouldKeepSidesRatio) {
-    const widthRatio = Math.abs(newWidth) / stateAtResizeStart.width;
-    const heightRatio = Math.abs(newHeight) / stateAtResizeStart.height;
+    const widthRatio = Math.abs(eleNewWidth) / eleInitialWidth;
+    const heightRatio = Math.abs(eleNewHeight) / eleInitialHeight;
     if (transformHandleDirection.length === 1) {
-      newHeight *= widthRatio;
-      newWidth *= heightRatio;
+      eleNewHeight *= widthRatio;
+      eleNewWidth *= heightRatio;
     }
     if (transformHandleDirection.length === 2) {
       const ratio = Math.max(widthRatio, heightRatio);
-      newWidth = stateAtResizeStart.width * ratio * Math.sign(newWidth);
-      newHeight = stateAtResizeStart.height * ratio * Math.sign(newHeight);
+      eleNewWidth = eleInitialWidth * ratio * Math.sign(eleNewWidth);
+      eleNewHeight = eleInitialHeight * ratio * Math.sign(eleNewHeight);
     }
   }
 
+  const [
+    newBoundsX1,
+    newBoundsY1,
+    newBoundsX2,
+    newBoundsY2,
+  ] = getResizedElementAbsoluteCoords(
+    stateAtResizeStart,
+    eleNewWidth,
+    eleNewHeight,
+  );
+  const newBoundsWidth = newBoundsX2 - newBoundsX1;
+  const newBoundsHeight = newBoundsY2 - newBoundsY1;
+
   // Calculate new topLeft based on fixed corner during resize
-  let newTopLeft = startTopLeft as [number, number];
+  let newTopLeft = [...startTopLeft] as [number, number];
   if (["n", "w", "nw"].includes(transformHandleDirection)) {
     newTopLeft = [
-      startBottomRight[0] - Math.abs(newWidth),
-      startBottomRight[1] - Math.abs(newHeight),
+      startBottomRight[0] - Math.abs(newBoundsWidth),
+      startBottomRight[1] - Math.abs(newBoundsHeight),
     ];
   }
   if (transformHandleDirection === "ne") {
-    const bottomLeft = [
-      stateAtResizeStart.x,
-      stateAtResizeStart.y + stateAtResizeStart.height,
-    ];
-    newTopLeft = [bottomLeft[0], bottomLeft[1] - Math.abs(newHeight)];
+    const bottomLeft = [startTopLeft[0], startBottomRight[1]];
+    newTopLeft = [bottomLeft[0], bottomLeft[1] - Math.abs(newBoundsHeight)];
   }
   if (transformHandleDirection === "sw") {
-    const topRight = [
-      stateAtResizeStart.x + stateAtResizeStart.width,
-      stateAtResizeStart.y,
-    ];
-    newTopLeft = [topRight[0] - Math.abs(newWidth), topRight[1]];
+    const topRight = [startBottomRight[0], startTopLeft[1]];
+    newTopLeft = [topRight[0] - Math.abs(newBoundsWidth), topRight[1]];
   }
 
   // Keeps opposite handle fixed during resize
   if (shouldKeepSidesRatio) {
     if (["s", "n"].includes(transformHandleDirection)) {
-      newTopLeft[0] = startCenter[0] - newWidth / 2;
+      newTopLeft[0] = startCenter[0] - newBoundsWidth / 2;
     }
     if (["e", "w"].includes(transformHandleDirection)) {
-      newTopLeft[1] = startCenter[1] - newHeight / 2;
+      newTopLeft[1] = startCenter[1] - newBoundsHeight / 2;
     }
   }
 
   // Flip horizontally
-  if (newWidth < 0) {
+  if (eleNewWidth < 0) {
     if (transformHandleDirection.includes("e")) {
-      newTopLeft[0] -= Math.abs(newWidth);
+      newTopLeft[0] -= Math.abs(newBoundsWidth);
     }
     if (transformHandleDirection.includes("w")) {
-      newTopLeft[0] += Math.abs(newWidth);
+      newTopLeft[0] += Math.abs(newBoundsWidth);
     }
   }
   // Flip vertically
-  if (newHeight < 0) {
+  if (eleNewHeight < 0) {
     if (transformHandleDirection.includes("s")) {
-      newTopLeft[1] -= Math.abs(newHeight);
+      newTopLeft[1] -= Math.abs(newBoundsHeight);
     }
     if (transformHandleDirection.includes("n")) {
-      newTopLeft[1] += Math.abs(newHeight);
+      newTopLeft[1] += Math.abs(newBoundsHeight);
     }
   }
 
   if (isResizeFromCenter) {
-    newTopLeft[0] = startCenter[0] - Math.abs(newWidth) / 2;
-    newTopLeft[1] = startCenter[1] - Math.abs(newHeight) / 2;
+    newTopLeft[0] = startCenter[0] - Math.abs(newBoundsWidth) / 2;
+    newTopLeft[1] = startCenter[1] - Math.abs(newBoundsHeight) / 2;
   }
 
   // adjust topLeft to new rotation point
   const angle = stateAtResizeStart.angle;
   const rotatedTopLeft = rotatePoint(newTopLeft, startCenter, angle);
   const newCenter: Point = [
-    newTopLeft[0] + Math.abs(newWidth) / 2,
-    newTopLeft[1] + Math.abs(newHeight) / 2,
+    newTopLeft[0] + Math.abs(newBoundsWidth) / 2,
+    newTopLeft[1] + Math.abs(newBoundsHeight) / 2,
   ];
   const rotatedNewCenter = rotatePoint(newCenter, startCenter, angle);
   newTopLeft = rotatePoint(rotatedTopLeft, rotatedNewCenter, -angle);
 
-  const resizedElement = {
-    width: Math.abs(newWidth),
-    height: Math.abs(newHeight),
-    x: newTopLeft[0],
-    y: newTopLeft[1],
-  };
-  updateBoundElements(element, {
-    newSize: { width: resizedElement.width, height: resizedElement.height },
-  });
-  mutateElement(element, resizedElement);
-};
-
-const resizeSingleNonGenericElement = (
-  element: NonDeleted<Exclude<ExcalidrawElement, ExcalidrawGenericElement>>,
-  transformHandleType: "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se",
-  isResizeFromCenter: boolean,
-  keepSquareAspectRatio: boolean,
-  pointerX: number,
-  pointerY: number,
-) => {
-  const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
-  const cx = (x1 + x2) / 2;
-  const cy = (y1 + y2) / 2;
-
-  // rotation pointer with reverse angle
-  const [rotatedX, rotatedY] = rotate(
-    pointerX,
-    pointerY,
-    cx,
-    cy,
-    -element.angle,
+  // Readjust points for linear elements
+  const rescaledPoints = rescalePointsInElement(
+    stateAtResizeStart,
+    eleNewWidth,
+    eleNewHeight,
   );
+  // For linear elements (x,y) are the coordinates of the first drawn point not the top-left corner
+  // So we need to readjust (x,y) to be where the first point should be
+  const newOrigin = [...newTopLeft];
+  newOrigin[0] += stateAtResizeStart.x - newBoundsX1;
+  newOrigin[1] += stateAtResizeStart.y - newBoundsY1;
 
-  let scaleX = 1;
-  let scaleY = 1;
-  if (
-    transformHandleType === "e" ||
-    transformHandleType === "ne" ||
-    transformHandleType === "se"
-  ) {
-    scaleX = (rotatedX - x1) / (x2 - x1);
-  }
-  if (
-    transformHandleType === "s" ||
-    transformHandleType === "sw" ||
-    transformHandleType === "se"
-  ) {
-    scaleY = (rotatedY - y1) / (y2 - y1);
-  }
-  if (
-    transformHandleType === "w" ||
-    transformHandleType === "nw" ||
-    transformHandleType === "sw"
-  ) {
-    scaleX = (x2 - rotatedX) / (x2 - x1);
-  }
-  if (
-    transformHandleType === "n" ||
-    transformHandleType === "nw" ||
-    transformHandleType === "ne"
-  ) {
-    scaleY = (y2 - rotatedY) / (y2 - y1);
-  }
-  let nextWidth = element.width * scaleX;
-  let nextHeight = element.height * scaleY;
-  if (keepSquareAspectRatio) {
-    nextWidth = nextHeight = Math.max(nextWidth, nextHeight);
-  }
-
-  const [nextX1, nextY1, nextX2, nextY2] = getResizedElementAbsoluteCoords(
-    element,
-    nextWidth,
-    nextHeight,
-  );
-  const deltaX1 = (x1 - nextX1) / 2;
-  const deltaY1 = (y1 - nextY1) / 2;
-  const deltaX2 = (x2 - nextX2) / 2;
-  const deltaY2 = (y2 - nextY2) / 2;
-
-  const rescaledPoints = rescalePointsInElement(element, nextWidth, nextHeight);
-
-  updateBoundElements(element, {
-    newSize: { width: nextWidth, height: nextHeight },
-  });
-  const [finalX1, finalY1, finalX2, finalY2] = getResizedElementAbsoluteCoords(
-    {
-      ...element,
-      ...rescaledPoints,
-    },
-    Math.abs(nextWidth),
-    Math.abs(nextHeight),
-  );
-  const [flipDiffX, flipDiffY] = getFlipAdjustment(
-    transformHandleType,
-    nextWidth,
-    nextHeight,
-    nextX1,
-    nextY1,
-    nextX2,
-    nextY2,
-    finalX1,
-    finalY1,
-    finalX2,
-    finalY2,
-    isLinearElement(element),
-    element.angle,
-  );
-  const [nextElementX, nextElementY] = adjustXYWithRotation(
-    getSidesForTransformHandle(transformHandleType, isResizeFromCenter),
-    element.x - flipDiffX,
-    element.y - flipDiffY,
-    element.angle,
-    deltaX1,
-    deltaY1,
-    deltaX2,
-    deltaY2,
-  );
+  const resizedElement = {
+    width: Math.abs(eleNewWidth),
+    height: Math.abs(eleNewHeight),
+    x: newOrigin[0],
+    y: newOrigin[1],
+    ...rescaledPoints,
+  };
 
   if (
-    nextWidth !== 0 &&
-    nextHeight !== 0 &&
-    Number.isFinite(nextElementX) &&
-    Number.isFinite(nextElementY)
+    resizedElement.width !== 0 &&
+    resizedElement.height !== 0 &&
+    Number.isFinite(resizedElement.x) &&
+    Number.isFinite(resizedElement.y)
   ) {
-    mutateElement(element, {
-      width: nextWidth,
-      height: nextHeight,
-      x: nextElementX,
-      y: nextElementY,
-      ...rescaledPoints,
+    updateBoundElements(element, {
+      newSize: { width: resizedElement.width, height: resizedElement.height },
     });
+    mutateElement(element, resizedElement);
   }
 };
 

+ 0 - 54
src/element/resizeTest.ts

@@ -173,57 +173,3 @@ export const getCursorForResizingElement = (resizingElement: {
 
   return cursor ? `${cursor}-resize` : "";
 };
-
-export const normalizeTransformHandleType = (
-  element: ExcalidrawElement,
-  transformHandleType: TransformHandleType,
-): TransformHandleType => {
-  if (element.width >= 0 && element.height >= 0) {
-    return transformHandleType;
-  }
-
-  if (element.width < 0 && element.height < 0) {
-    switch (transformHandleType) {
-      case "nw":
-        return "se";
-      case "ne":
-        return "sw";
-      case "se":
-        return "nw";
-      case "sw":
-        return "ne";
-    }
-  } else if (element.width < 0) {
-    switch (transformHandleType) {
-      case "nw":
-        return "ne";
-      case "ne":
-        return "nw";
-      case "se":
-        return "sw";
-      case "sw":
-        return "se";
-      case "e":
-        return "w";
-      case "w":
-        return "e";
-    }
-  } else {
-    switch (transformHandleType) {
-      case "nw":
-        return "sw";
-      case "ne":
-        return "se";
-      case "se":
-        return "ne";
-      case "sw":
-        return "nw";
-      case "n":
-        return "s";
-      case "s":
-        return "n";
-    }
-  }
-
-  return transformHandleType;
-};

+ 4 - 12
src/excalidraw-app/index.tsx

@@ -11,7 +11,7 @@ import { getDefaultAppState } from "../appState";
 import { ExcalidrawImperativeAPI } from "../components/App";
 import { ErrorDialog } from "../components/ErrorDialog";
 import { TopErrorBoundary } from "../components/TopErrorBoundary";
-import { APP_NAME, EVENT, TITLE_TIMEOUT } from "../constants";
+import { APP_NAME, EVENT, TITLE_TIMEOUT, VERSION_TIMEOUT } from "../constants";
 import { ImportedDataState } from "../data/types";
 import {
   ExcalidrawElement,
@@ -229,18 +229,10 @@ const ExcalidrawWrapper = (props: { collab: CollabAPI }) => {
   const { collab } = props;
 
   useEffect(() => {
-    // delayed by 15 sec so that the app has a time to load the latest SW
+    // Delayed so that the app has a time to load the latest SW
     setTimeout(() => {
-      const version = getVersion();
-      const loggedVersion = window.localStorage.getItem(
-        "excalidraw-lastLoggedVersion",
-      );
-      // prevent logging on multiple visits
-      if (version && version !== loggedVersion) {
-        window.localStorage.setItem("excalidraw-lastLoggedVersion", version);
-        trackEvent("load", "version", version);
-      }
-    }, 15000);
+      trackEvent("load", "version", getVersion());
+    }, VERSION_TIMEOUT);
 
     excalidrawRef.current!.readyPromise.then((excalidrawApi) => {
       initializeScene({

+ 13 - 11
src/locales/en.json

@@ -199,24 +199,26 @@
   "errorDialog": {
     "title": "Error"
   },
-  "shortcutsDialog": {
-    "title": "Keyboard shortcuts",
-    "shapes": "Shapes",
-    "or": "or",
+  "helpDialog": {
+    "blog": "Read our blog",
     "click": "click",
-    "drag": "drag",
     "curvedArrow": "Curved arrow",
     "curvedLine": "Curved line",
+    "documentation": "Documentation",
+    "drag": "drag",
     "editor": "Editor",
-    "view": "View",
-    "blog": "Read our blog",
-    "howto": "Follow our guides",
     "github": "Found an issue? Submit",
-    "textNewLine": "Add new line (text)",
+    "howto": "Follow our guides",
+    "or": "or",
+    "preventBinding": "Prevent arrow binding",
+    "shapes": "Shapes",
+    "shortcuts": "Keyboard shortcuts",
     "textFinish": "Finish editing (text)",
+    "textNewLine": "Add new line (text)",
+    "title": "Help",
+    "view": "View",
     "zoomToFit": "Zoom to fit all elements",
-    "zoomToSelection": "Zoom to selection",
-    "preventBinding": "Prevent arrow binding"
+    "zoomToSelection": "Zoom to selection"
   },
   "encrypted": {
     "tooltip": "Your drawings are end-to-end encrypted so Excalidraw's servers will never see them."

+ 0 - 58
src/math.ts

@@ -70,64 +70,6 @@ export const adjustXYWithRotation = (
   return [x, y];
 };
 
-export const getFlipAdjustment = (
-  side: "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se",
-  nextWidth: number,
-  nextHeight: number,
-  nextX1: number,
-  nextY1: number,
-  nextX2: number,
-  nextY2: number,
-  finalX1: number,
-  finalY1: number,
-  finalX2: number,
-  finalY2: number,
-  needsRotation: boolean,
-  angle: number,
-): [number, number] => {
-  const cos = Math.cos(angle);
-  const sin = Math.sin(angle);
-  let flipDiffX = 0;
-  let flipDiffY = 0;
-  if (nextWidth < 0) {
-    if (side === "e" || side === "ne" || side === "se") {
-      if (needsRotation) {
-        flipDiffX += (finalX2 - nextX1) * cos;
-        flipDiffY += (finalX2 - nextX1) * sin;
-      } else {
-        flipDiffX += finalX2 - nextX1;
-      }
-    }
-    if (side === "w" || side === "nw" || side === "sw") {
-      if (needsRotation) {
-        flipDiffX += (finalX1 - nextX2) * cos;
-        flipDiffY += (finalX1 - nextX2) * sin;
-      } else {
-        flipDiffX += finalX1 - nextX2;
-      }
-    }
-  }
-  if (nextHeight < 0) {
-    if (side === "s" || side === "se" || side === "sw") {
-      if (needsRotation) {
-        flipDiffY += (finalY2 - nextY1) * cos;
-        flipDiffX += (finalY2 - nextY1) * -sin;
-      } else {
-        flipDiffY += finalY2 - nextY1;
-      }
-    }
-    if (side === "n" || side === "ne" || side === "nw") {
-      if (needsRotation) {
-        flipDiffY += (finalY1 - nextY2) * cos;
-        flipDiffX += (finalY1 - nextY2) * -sin;
-      } else {
-        flipDiffY += finalY1 - nextY2;
-      }
-    }
-  }
-  return [flipDiffX, flipDiffY];
-};
-
 export const getPointOnAPath = (point: Point, path: Point[]) => {
   const [px, py] = point;
   const [start, ...other] = path;

+ 36 - 5
src/packages/excalidraw/CHANGELOG.md

@@ -12,15 +12,34 @@ The change should be grouped under one of the below section and must contain PR
 Please add the latest change on the top under the correct section.
 -->
 
-## [Unreleased]
+## 0.2.0
+
+## Excalidraw API
 
 ### Features
 
-- Add `cmd+o` shortcut to load scene [#2732](https://github.com/excalidraw/excalidraw/pull/2732)
+- Exported few [Extra API's](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#extra-apis) which can be used by the host to communicate with Excalidraw.
+
 - Remove language picker, and add `langCode`, `renderFooter` [#2644](https://github.com/excalidraw/excalidraw/pull/2644):
   - BREAKING: removed the language picker from UI. It is now the host app's responsibility to implement a language picker if desirable, using the newly added [`renderFooter`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#renderFooter) prop. The reasoning is that the i18n should be controlled by the app itself, not by the nested Excalidraw component.
   - Added [`langCode`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#langCode) prop to control the UI language.
 - Add support for `exportToBackend` prop to allow host apps to implement shareable links [#2612](https://github.com/excalidraw/excalidraw/pull/2612/files)
+
+### Fixes
+
+- Hide collaboration button when the prop `onCollabButtonClick` is not provided [#2598](https://github.com/excalidraw/excalidraw/pull/2598)
+
+## Excalidraw Library
+
+### Features
+
+- Add toast [#2772](https://github.com/excalidraw/excalidraw/pull/2772)
+- Add `cmd+o` shortcut to load scene [#2732](https://github.com/excalidraw/excalidraw/pull/2732)
+- Require use of a preset dialog size; adjust dialog sizing [#2684](https://github.com/excalidraw/excalidraw/pull/2684)
+- Add line chart and paste dialog selection [#2670](https://github.com/excalidraw/excalidraw/pull/2670)
+- Tweak editing behavior [#2668](https://github.com/excalidraw/excalidraw/pull/2668)
+- Change title to Excalidraw after a timeout
+- Checkmark to toggle context-menu-items [#2645](https://github.com/excalidraw/excalidraw/pull/2645)
 - Add zoom to selection [#2522](https://github.com/excalidraw/excalidraw/pull/2522)
 - Insert Library items in the middle of the screen [#2527](https://github.com/excalidraw/excalidraw/pull/2527)
 - Show shortcut context menu [#2501](https://github.com/excalidraw/excalidraw/pull/2501)
@@ -31,13 +50,16 @@ Please add the latest change on the top under the correct section.
 
 ### Fixes
 
+- Fix compile error [#2685](https://github.com/excalidraw/excalidraw/pull/2685)
+- Center zoom on iPhone and iPad [#2642](https://github.com/excalidraw/excalidraw/pull/2642)
 - Allow text-selecting in dialogs & reset cursor [#2783](https://github.com/excalidraw/excalidraw/pull/2783)
+- Don't render due to zoom after unmount [#2779](https://github.com/excalidraw/excalidraw/pull/2779)
+- Track the chart type correctly [#2773](https://github.com/excalidraw/excalidraw/pull/2773)
 - Fix late-render due to debounced zoom [#2779](https://github.com/excalidraw/excalidraw/pull/2779)
 - Fix initialization when browser tab not focused [#2677](https://github.com/excalidraw/excalidraw/pull/2677)
 - Consistent case for export locale strings [#2622](https://github.com/excalidraw/excalidraw/pull/2622)
 - Remove unnecessary console.error as it was polluting Sentry [#2637](https://github.com/excalidraw/excalidraw/pull/2637)
 - Fix scroll-to-center on init for non-zero canvas offsets [#2445](https://github.com/excalidraw/excalidraw/pull/2445)
-- Hide collab button when onCollabButtonClick not supplied [#2598](https://github.com/excalidraw/excalidraw/pull/2598)
 - Fix resizing the pasted charts [#2586](https://github.com/excalidraw/excalidraw/pull/2586)
 - Fix element visibility and zoom on cursor when canvas offset isn't 0. [#2534](https://github.com/excalidraw/excalidraw/pull/2534)
 - Fix Library Menu Layout [#2502](https://github.com/excalidraw/excalidraw/pull/2502)
@@ -47,6 +69,11 @@ Please add the latest change on the top under the correct section.
 ### Improvements
 
 - Added Zen Mode to the context menu [#2734](https://github.com/excalidraw/excalidraw/pull/2734)
+- Do not reset to selection for draw tool [#2721]((https://github.com/excalidraw/excalidraw/pull/2721)
+- Make dialogs look more like dialogs [#2686](https://github.com/excalidraw/excalidraw/pull/2686)
+- Browse libraries styles fixed [#2694](https://github.com/excalidraw/excalidraw/pull/2694)
+- Change hint for 2-point lines on resize [#2655](https://github.com/excalidraw/excalidraw/pull/2655)
+- Align items in context menu [#2640](https://github.com/excalidraw/excalidraw/pull/2640)
 - Do not reset to selection when using the draw tool [#2721](https://github.com/excalidraw/excalidraw/pull/2721)
 - Display proper tooltip for 2-point lines during resize, and normalize modifier key labels in hints [#2655](https://github.com/excalidraw/excalidraw/pull/2655)
 - Improve error message around importing images [#2619](https://github.com/excalidraw/excalidraw/pull/2619)
@@ -56,9 +83,13 @@ Please add the latest change on the top under the correct section.
 - Hide shortcuts on pickers for mobile [#2508](https://github.com/excalidraw/excalidraw/pull/2508)
 - Hide stats and scrollToContent-button when mobile menus open [#2509](https://github.com/excalidraw/excalidraw/pull/2509)
 
-### Chore
+### Refactor
 
-- Bump ini from 1.3.5 to 1.3.7 in /src/packages/excalidraw [#2500](https://github.com/excalidraw/excalidraw/pull/2500)
+- refactor: Converting span to kbd tag [#2774](https://github.com/excalidraw/excalidraw/pull/2774)
+- Media queries [#2680](https://github.com/excalidraw/excalidraw/pull/2680)
+- Remove duplicate entry from en.json[#2654](https://github.com/excalidraw/excalidraw/pull/2654)
+- Remove the word toggle from labels [#2648](https://github.com/excalidraw/excalidraw/pull/2648)
+-
 
 ### Docs
 

+ 45 - 0
src/packages/excalidraw/README.md

@@ -142,6 +142,51 @@ export default function App() {
 | [`langCode`](#langCode) | string | `en` | Language code string |
 | [`renderFooter `](#renderFooter) | Function |  | Function that renders custom UI footer |
 
+### `Extra API's`
+
+#### `getSceneVersion`
+
+**How to use**
+
+<pre>
+import { getSceneVersion } from "@excalidraw/excalidraw";
+getSceneVersion(elements:  <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement []</a>)
+</pre>
+
+This function returns the current scene version.
+
+#### `getSyncableElements`
+
+**_Signature_**
+
+<pre>
+getSyncableElements(elements:  <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement []</a>):<a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement []</a>
+</pre>
+
+**How to use**
+
+```js
+import { getSyncableElements } from "@excalidraw/excalidraw";
+```
+
+This function returns all the deleted elements of the scene.
+
+### `getElementMap`
+
+**_Signature_**
+
+<pre>
+getElementsMap(elements:  <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement []</a>): {[id: string]: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement</a>}
+</pre>
+
+**How to use**
+
+```js
+import { getElementsMap } from "@excalidraw/excalidraw";
+```
+
+This function returns an object where each element is mapped to its id.
+
 #### `width`
 
 This props defines the `width` of the Excalidraw component. Defaults to `window.innerWidth` if not passed.

+ 21 - 28
src/packages/excalidraw/package-lock.json

@@ -1,6 +1,6 @@
 {
   "name": "@excalidraw/excalidraw",
-  "version": "0.1.1",
+  "version": "0.2.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -1933,6 +1933,12 @@
         "prr": "~1.0.1"
       }
     },
+    "es-module-lexer": {
+      "version": "0.3.26",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz",
+      "integrity": "sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==",
+      "dev": true
+    },
     "escalade": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -2456,9 +2462,9 @@
       "dev": true
     },
     "mini-css-extract-plugin": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.3.tgz",
-      "integrity": "sha512-7lvliDSMiuZc81kI+5/qxvn47SCM7BehXex3f2c6l/pR3Goj58IQxZh9nuPQ3AkGQgoETyXuIqLDaO5Oa0TyBw==",
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.4.tgz",
+      "integrity": "sha512-dNjqyeogUd8ucUgw5sxm1ahvSfSUgef7smbmATRSbDm4EmNx5kQA6VdUEhEeCKSjX6CTYjb5vxgMUvRjqP3uHg==",
       "dev": true,
       "requires": {
         "loader-utils": "^2.0.0",
@@ -2841,9 +2847,9 @@
       "dev": true
     },
     "sass-loader": {
-      "version": "10.1.0",
-      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.1.0.tgz",
-      "integrity": "sha512-ZCKAlczLBbFd3aGAhowpYEy69Te3Z68cg8bnHHl6WnSCvnKpbM6pQrz957HWMa8LKVuhnD9uMplmMAHwGQtHeg==",
+      "version": "10.1.1",
+      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.1.1.tgz",
+      "integrity": "sha512-W6gVDXAd5hR/WHsPicvZdjAWHBcEJ44UahgxcIE196fW2ong0ZHMPO1kZuI5q0VlvMQZh32gpv69PLWQm70qrw==",
       "dev": true,
       "requires": {
         "klona": "^2.0.4",
@@ -3251,9 +3257,9 @@
       }
     },
     "webpack": {
-      "version": "5.12.3",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.12.3.tgz",
-      "integrity": "sha512-7tiQmcTnKhZwbf7X7sEfXe0pgkGjUZjT6JfYkZHvvIb4/ZsXl1rJu5PxsJoN7W3v5sNSP/8TgBoiOdDqVdvK5w==",
+      "version": "5.15.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.15.0.tgz",
+      "integrity": "sha512-y/xG+ONDz78yn3VvP6gAvGr1/gkxOgitvHSXBmquyN8KDtrGEyE3K9WkXOPB7QmfcOBCpO4ELXwNcCYQnEmexA==",
       "dev": true,
       "requires": {
         "@types/eslint-scope": "^3.7.0",
@@ -3264,7 +3270,8 @@
         "acorn": "^8.0.4",
         "browserslist": "^4.14.5",
         "chrome-trace-event": "^1.0.2",
-        "enhanced-resolve": "^5.3.1",
+        "enhanced-resolve": "^5.7.0",
+        "es-module-lexer": "^0.3.26",
         "eslint-scope": "^5.1.1",
         "events": "^3.2.0",
         "glob-to-regexp": "^0.4.1",
@@ -3282,9 +3289,9 @@
       },
       "dependencies": {
         "enhanced-resolve": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.5.0.tgz",
-          "integrity": "sha512-b4a6BasBCoLzri4MdaeOlDMpls2oioI28CF17csMiav9dq46yvQaKPFNUrCHB6VqQokBDG2VIEEL81jMiQ6Wtw==",
+          "version": "5.7.0",
+          "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz",
+          "integrity": "sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw==",
           "dev": true,
           "requires": {
             "graceful-fs": "^4.2.4",
@@ -3360,20 +3367,6 @@
           "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==",
           "dev": true
         },
-        "terser-webpack-plugin": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz",
-          "integrity": "sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==",
-          "dev": true,
-          "requires": {
-            "jest-worker": "^26.6.2",
-            "p-limit": "^3.1.0",
-            "schema-utils": "^3.0.0",
-            "serialize-javascript": "^5.0.1",
-            "source-map": "^0.6.1",
-            "terser": "^5.5.1"
-          }
-        },
         "webpack-sources": {
           "version": "2.2.0",
           "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.2.0.tgz",

+ 4 - 4
src/packages/excalidraw/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@excalidraw/excalidraw",
-  "version": "0.1.1",
+  "version": "0.2.0",
   "main": "dist/excalidraw.min.js",
   "files": [
     "dist/*"
@@ -54,11 +54,11 @@
     "cross-env": "7.0.3",
     "css-loader": "5.0.1",
     "file-loader": "6.2.0",
-    "mini-css-extract-plugin": "1.3.3",
-    "sass-loader": "10.1.0",
+    "mini-css-extract-plugin": "1.3.4",
+    "sass-loader": "10.1.1",
     "terser-webpack-plugin": "5.1.1",
     "ts-loader": "8.0.14",
-    "webpack": "5.12.3",
+    "webpack": "5.15.0",
     "webpack-bundle-analyzer": "4.3.0",
     "webpack-cli": "4.3.1"
   },

+ 17 - 10
src/packages/utils/package-lock.json

@@ -1109,9 +1109,9 @@
       "dev": true
     },
     "@types/node": {
-      "version": "14.14.20",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz",
-      "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==",
+      "version": "14.14.21",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.21.tgz",
+      "integrity": "sha512-cHYfKsnwllYhjOzuC5q1VpguABBeecUp24yFluHpn/BQaVxB1CuQ1FSRZCzrPxrkIfWISXV2LbeoBthLWg0+0A==",
       "dev": true
     },
     "@webassemblyjs/ast": {
@@ -1783,6 +1783,12 @@
         "prr": "~1.0.1"
       }
     },
+    "es-module-lexer": {
+      "version": "0.3.26",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz",
+      "integrity": "sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==",
+      "dev": true
+    },
     "escalade": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
@@ -2918,9 +2924,9 @@
       }
     },
     "webpack": {
-      "version": "5.12.3",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.12.3.tgz",
-      "integrity": "sha512-7tiQmcTnKhZwbf7X7sEfXe0pgkGjUZjT6JfYkZHvvIb4/ZsXl1rJu5PxsJoN7W3v5sNSP/8TgBoiOdDqVdvK5w==",
+      "version": "5.15.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.15.0.tgz",
+      "integrity": "sha512-y/xG+ONDz78yn3VvP6gAvGr1/gkxOgitvHSXBmquyN8KDtrGEyE3K9WkXOPB7QmfcOBCpO4ELXwNcCYQnEmexA==",
       "dev": true,
       "requires": {
         "@types/eslint-scope": "^3.7.0",
@@ -2931,7 +2937,8 @@
         "acorn": "^8.0.4",
         "browserslist": "^4.14.5",
         "chrome-trace-event": "^1.0.2",
-        "enhanced-resolve": "^5.3.1",
+        "enhanced-resolve": "^5.7.0",
+        "es-module-lexer": "^0.3.26",
         "eslint-scope": "^5.1.1",
         "events": "^3.2.0",
         "glob-to-regexp": "^0.4.1",
@@ -2949,9 +2956,9 @@
       },
       "dependencies": {
         "enhanced-resolve": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.5.0.tgz",
-          "integrity": "sha512-b4a6BasBCoLzri4MdaeOlDMpls2oioI28CF17csMiav9dq46yvQaKPFNUrCHB6VqQokBDG2VIEEL81jMiQ6Wtw==",
+          "version": "5.7.0",
+          "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz",
+          "integrity": "sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw==",
           "dev": true,
           "requires": {
             "graceful-fs": "^4.2.4",

+ 1 - 1
src/packages/utils/package.json

@@ -46,7 +46,7 @@
     "cross-env": "7.0.3",
     "file-loader": "6.2.0",
     "ts-loader": "8.0.14",
-    "webpack": "5.12.3",
+    "webpack": "5.15.0",
     "webpack-bundle-analyzer": "4.3.0",
     "webpack-cli": "4.3.1"
   },

+ 67 - 67
src/tests/__snapshots__/regressionTests.test.tsx.snap

@@ -70,7 +70,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -536,7 +536,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -984,7 +984,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -1760,7 +1760,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -1967,7 +1967,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -2418,7 +2418,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -2666,7 +2666,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -2831,7 +2831,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -3303,7 +3303,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -3612,7 +3612,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -3816,7 +3816,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -4056,7 +4056,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -4307,7 +4307,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -4708,7 +4708,7 @@ Object {
   },
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -4979,7 +4979,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -5304,7 +5304,7 @@ Object {
   },
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -5488,7 +5488,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -5650,7 +5650,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -6108,7 +6108,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -6417,7 +6417,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -8454,7 +8454,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -8815,7 +8815,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -9066,7 +9066,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -9318,7 +9318,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -9626,7 +9626,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -9788,7 +9788,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -9950,7 +9950,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -10112,7 +10112,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -10304,7 +10304,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -10496,7 +10496,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -10688,7 +10688,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -10880,7 +10880,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -11042,7 +11042,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -11204,7 +11204,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -11396,7 +11396,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -11558,7 +11558,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -11761,7 +11761,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -12468,7 +12468,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -12715,7 +12715,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": true,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -12813,7 +12813,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -12913,7 +12913,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -13075,7 +13075,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -13381,7 +13381,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -13687,7 +13687,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -13847,7 +13847,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -14043,7 +14043,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -14296,7 +14296,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -14612,7 +14612,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -15449,7 +15449,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -15755,7 +15755,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -16065,7 +16065,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -16441,7 +16441,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -16612,7 +16612,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -16925,7 +16925,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -17165,7 +17165,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -17420,7 +17420,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -17735,7 +17735,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -17835,7 +17835,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -18008,7 +18008,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -18814,7 +18814,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -18916,7 +18916,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -19692,7 +19692,7 @@ Object {
   },
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -20093,7 +20093,7 @@ Object {
   },
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -20340,7 +20340,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": true,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -20440,7 +20440,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -20934,7 +20934,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],
@@ -21032,7 +21032,7 @@ Object {
   "selectionElement": null,
   "shouldAddWatermark": false,
   "shouldCacheIgnoreZoom": false,
-  "showShortcutsDialog": false,
+  "showHelpDialog": false,
   "showStats": false,
   "startBoundElement": null,
   "suggestedBindings": Array [],

+ 1 - 1
src/tests/resize.test.tsx

@@ -41,7 +41,7 @@ describe("resize rectangle ellipses and diamond elements", () => {
     ${"s"}  | ${[_, 39]}      | ${[100, 139]} | ${[elemData.x, elemData.x]}
     ${"e"}  | ${[-20, _]}     | ${[80, 100]}  | ${[elemData.x, elemData.y]}
     ${"w"}  | ${[-20, _]}     | ${[120, 100]} | ${[-20, elemData.y]}
-    ${"ne"} | ${[10, 55]}     | ${[110, 45]}  | ${[elemData.x, 55]}
+    ${"ne"} | ${[5, 55]}      | ${[105, 45]}  | ${[elemData.x, 55]}
     ${"se"} | ${[-30, -10]}   | ${[70, 90]}   | ${[elemData.x, elemData.y]}
     ${"nw"} | ${[-300, -200]} | ${[400, 300]} | ${[-300, -200]}
     ${"sw"} | ${[40, -20]}    | ${[60, 80]}   | ${[40, 0]}

+ 1 - 1
src/types.ts

@@ -81,7 +81,7 @@ export type AppState = {
   selectedElementIds: { [id: string]: boolean };
   previousSelectedElementIds: { [id: string]: boolean };
   shouldCacheIgnoreZoom: boolean;
-  showShortcutsDialog: boolean;
+  showHelpDialog: boolean;
   toastMessage: string | null;
   zenModeEnabled: boolean;
   appearance: "light" | "dark";