diff --git a/e2e/pages/SiteMap.ts b/e2e/pages/SiteMap.ts index 66fb1cc..310ef94 100644 --- a/e2e/pages/SiteMap.ts +++ b/e2e/pages/SiteMap.ts @@ -2,7 +2,6 @@ import { type WebDriver } from 'selenium-webdriver'; import { getDocumentHtml, getLogs } from '../helpers/debug'; import { Welcome } from './Welcome'; import { Password } from './Password'; -import { RetroList } from './RetroList'; export class SiteMap { public constructor(public readonly driver: WebDriver) {} @@ -11,12 +10,6 @@ export class SiteMap { return new Welcome(this.driver).load(); } - public navigateToRetroList() { - // An unknown bug in chromedriver causes communication with the browser to hang for - // exactly 5 seconds at this point, so use at least a 6 second timeout to avoid flakiness: - return new RetroList(this.driver).load(6000); - } - public navigateToRetroPassword(slug: string) { return new Password(this.driver, slug).load(); } diff --git a/e2e/pages/SsoLogin.ts b/e2e/pages/SsoLogin.ts index f35c9fe..3758209 100644 --- a/e2e/pages/SsoLogin.ts +++ b/e2e/pages/SsoLogin.ts @@ -18,9 +18,7 @@ export class SsoLogin extends Page { public async submit(): Promise { await this.click(By.css('form button')); - // An unknown bug in chromedriver causes communication with the browser to hang for - // exactly 5 seconds at this point, so use at least a 6 second timeout to avoid flakiness: - return new this.ExpectedTarget(this.driver).wait(6000); + return new this.ExpectedTarget(this.driver).wait(); } public async loginAs(identifier: string): Promise { diff --git a/e2e/pages/common/Page.ts b/e2e/pages/common/Page.ts index 6e1b3ce..00323c0 100644 --- a/e2e/pages/common/Page.ts +++ b/e2e/pages/common/Page.ts @@ -27,16 +27,16 @@ export abstract class Page extends PageFragment { this.untilNavigated = until.elementLocated(By.css(expectedCSS)); } - public async load(loadTimeoutOverride?: number) { + public async load() { await this.navigate(); - await this.wait(loadTimeoutOverride); + await this.wait(); return this; } - public async wait(loadTimeoutOverride: number = 0) { + public async wait() { await this.driver.wait( this.untilNavigated, - Math.max(this.explicitWaitTimeout, loadTimeoutOverride), + this.explicitWaitTimeout, `Failed to load page '${this.constructor.name}'`, ); await this.driver.wait( diff --git a/e2e/pages/common/PageFragment.ts b/e2e/pages/common/PageFragment.ts index 5d90f4b..2b2fcdd 100644 --- a/e2e/pages/common/PageFragment.ts +++ b/e2e/pages/common/PageFragment.ts @@ -1,8 +1,10 @@ import { type By, type WebDriver } from 'selenium-webdriver'; export abstract class PageFragment { + // An unknown bug in chromedriver causes communication with the browser to hang for + // exactly 5 seconds at some points, so use at least a 6 second timeout to avoid flakiness: protected readonly explicitWaitTimeout = Number( - process.env['EXPLICIT_WAIT_TIMEOUT'] || '5000', + process.env['EXPLICIT_WAIT_TIMEOUT'] || '6000', ); protected constructor( diff --git a/e2e/pages/common/Popup.ts b/e2e/pages/common/Popup.ts index e53e35d..e53f107 100644 --- a/e2e/pages/common/Popup.ts +++ b/e2e/pages/common/Popup.ts @@ -1,4 +1,4 @@ -import { By, WebDriver } from 'selenium-webdriver'; +import { By, Key, WebDriver } from 'selenium-webdriver'; import { untilNoElementLocated } from '../../helpers/customUntil'; import { byButtonText } from '../../helpers/customBy'; import { PageFragment } from './PageFragment'; @@ -25,7 +25,10 @@ export class Popup extends PageFragment { return; } - await this.driver.findElement(By.css('.popup-overlay')).click(); + await this.driver + .actions({ async: false, bridge: false }) + .sendKeys(Key.ESCAPE) + .perform(); await this.waitUntilDismissed(); } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d031ddb..e952246 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -14,7 +14,6 @@ "react-dom": "18.x", "react-hook-awaited": "1.x", "react-hook-final-countdown": "2.x", - "react-modal": "3.x", "rxjs": "7.x", "shared-reducer": "5.x", "wouter": "2.10.1" @@ -32,7 +31,6 @@ "@types/jest": "29.x", "@types/react": "18.x", "@types/react-dom": "18.x", - "@types/react-modal": "3.x", "babel-jest": "29.x", "babel-loader": "9.x", "blocking-queue": "0.0.x", @@ -58,9 +56,9 @@ } }, "node_modules/@adobe/css-tools": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz", - "integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.1.tgz", + "integrity": "sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ==", "dev": true, "license": "MIT" }, @@ -1972,9 +1970,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.1.tgz", - "integrity": "sha512-CRICJIl0N5cXDONAdlTv5ShATZ4HEwk6kDDIW2/w9qOWKg+NU/5F8wYRWCrONad0/UKkloNSmmyN/wX4rtpbVA==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.2.tgz", + "integrity": "sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==", "dev": true, "license": "MIT", "dependencies": { @@ -2096,13 +2094,13 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", - "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/@types/node-forge": { @@ -2157,16 +2155,6 @@ "@types/react": "*" } }, - "node_modules/@types/react-modal": { - "version": "3.16.3", - "resolved": "https://registry.npmjs.org/@types/react-modal/-/react-modal-3.16.3.tgz", - "integrity": "sha512-xXuGavyEGaFQDgBv4UVm8/ZsG+qxeQ7f77yNrW3n+1J6XAstUy5rYHeIHPh1KzsGc6IkCIdu6lQ2xWzu1jBTLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/retry": { "version": "0.12.2", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", @@ -2937,9 +2925,9 @@ "license": "MIT" }, "node_modules/bonjour-service": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", - "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", "dev": true, "license": "MIT", "dependencies": { @@ -3122,9 +3110,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001679", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001679.tgz", - "integrity": "sha512-j2YqID/YwpLnKzCmBOS4tlZdWprXm3ZmQLBH9ZBXFOhoxLA46fwyBvx6toCBWBmnuwUY/qB3kEU6gFx8qgCroA==", + "version": "1.0.30001684", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", + "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", "dev": true, "funding": [ { @@ -3613,9 +3601,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", - "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -4273,9 +4261,9 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.55", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.55.tgz", - "integrity": "sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==", + "version": "1.5.67", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.67.tgz", + "integrity": "sha512-nz88NNBsD7kQSAGGJyp8hS6xSPtWwqNogA0mjtc2nUYeEf3nURK9qpV18TuBdDmEDgVWotS8Wkzf+V52dSQ/LQ==", "dev": true, "license": "ISC" }, @@ -4574,12 +4562,6 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/exenv": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", - "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==", - "license": "BSD-3-Clause" - }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -5112,13 +5094,16 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.1.0.tgz", + "integrity": "sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.1.3" + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6970,9 +6955,9 @@ } }, "node_modules/less": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", - "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.1.tgz", + "integrity": "sha512-CasaJidTIhWmjcqv0Uj5vccMI7pJgfD9lMkKtlnTHAdJdYK/7l8pM9tumLyJ0zhbD4KJLo/YvTj+xznQd5NBhg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -7411,9 +7396,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "dev": true, "funding": [ { @@ -7543,9 +7528,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.13", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.13.tgz", - "integrity": "sha512-cTGB9ptp9dY9A5VbMSe7fQBcl/tt22Vcqdq8+eN93rblOuE0aCFu4aZ2vMwct/2t+lFnosm8RkQW1I0Omb1UtQ==", + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", "dev": true, "license": "MIT" }, @@ -7553,6 +7538,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7692,9 +7678,9 @@ } }, "node_modules/p-retry": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.0.tgz", - "integrity": "sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8006,9 +7992,9 @@ } }, "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", "dev": true, "funding": [ { @@ -8027,7 +8013,7 @@ "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.1.0", + "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { @@ -8261,14 +8247,14 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", - "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.1.0.tgz", + "integrity": "sha512-rm0bdSv4jC3BDma3s9H19ZddW0aHX6EoqwDYU2IfZhRN+53QrufTRo2IdkAbRqLx4R2IYbZnbjKKxg4VN5oU9Q==", "dev": true, "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", + "postcss-selector-parser": "^7.0.0", "postcss-value-parser": "^4.1.0" }, "engines": { @@ -8278,14 +8264,28 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-modules-scope": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", - "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", "dev": true, "license": "ISC", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "postcss-selector-parser": "^7.0.0" }, "engines": { "node": "^10 || ^12 || >= 14" @@ -8294,6 +8294,20 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz", + "integrity": "sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/postcss-modules-values": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", @@ -8632,23 +8646,6 @@ "node": ">= 6" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -8682,9 +8679,9 @@ "optional": true }, "node_modules/psl": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.10.0.tgz", - "integrity": "sha512-KSKHEbjAnpUuAUserOq0FxGXCUrzC3WniuSJhvdbs102rL55266ZcHBqLWOsG30spQMlPdpy7icATiAQehg/iA==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.14.0.tgz", + "integrity": "sha512-Syk1bnf6fRZ9wQs03AtKJHcM12cKbOLo9L8JtCCdYj5/DTsHmTyXM4BK5ouWeG2P6kZ4nmFvuNTdtaqfobCOCg==", "dev": true, "license": "MIT", "dependencies": { @@ -8861,12 +8858,6 @@ "dev": true, "license": "MIT" }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", - "license": "MIT" - }, "node_modules/react-mock-element": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/react-mock-element/-/react-mock-element-1.0.3.tgz", @@ -8877,25 +8868,6 @@ "react": ">=16.8.0" } }, - "node_modules/react-modal": { - "version": "3.16.1", - "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.16.1.tgz", - "integrity": "sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==", - "license": "MIT", - "dependencies": { - "exenv": "^1.2.0", - "prop-types": "^15.7.2", - "react-lifecycles-compat": "^3.0.0", - "warning": "^4.0.3" - }, - "engines": { - "node": ">=8" - }, - "peerDependencies": { - "react": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18", - "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18" - } - }, "node_modules/react-shallow-renderer": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", @@ -9497,11 +9469,14 @@ } }, "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "dev": true, "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10261,9 +10236,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true, "license": "MIT" }, @@ -10443,15 +10418,6 @@ "makeerror": "1.0.12" } }, - "node_modules/warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.0.0" - } - }, "node_modules/watchpack": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 364a553..ad113f6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -18,7 +18,6 @@ "react-dom": "18.x", "react-hook-awaited": "1.x", "react-hook-final-countdown": "2.x", - "react-modal": "3.x", "rxjs": "7.x", "shared-reducer": "5.x", "wouter": "2.10.1" @@ -36,7 +35,6 @@ "@types/jest": "29.x", "@types/react": "18.x", "@types/react-dom": "18.x", - "@types/react-modal": "3.x", "babel-jest": "29.x", "babel-loader": "9.x", "blocking-queue": "0.0.x", diff --git a/frontend/src/components/common/Popup.less b/frontend/src/components/common/Popup.less index 45859b1..f7dad13 100644 --- a/frontend/src/components/common/Popup.less +++ b/frontend/src/components/common/Popup.less @@ -1,77 +1,67 @@ -.popup-overlay { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; +.popup-content { + --animate-in: 0.2s; + --animate-out: 0.15s; +} + +.popup-content, +.popup-content::backdrop { + opacity: 0; + transition: + display var(--animate-out) allow-discrete, + overlay var(--animate-out) allow-discrete, + transform var(--animate-out) ease-in, + opacity var(--animate-out) ease-in; +} + +.popup-content::backdrop { + transform: translateZ(0); /* use GPU to speed up blur effect */ background: rgba(128, 128, 128, 0.5); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); - z-index: 10; - - animation: 0.2s ease popup-fade-in; - - .popup-content { - position: absolute; - top: 50%; - left: 50%; - margin-right: -50%; - margin-bottom: -50%; - transform: translate(-50%, -50%); - max-width: calc(100% - 32px); - max-height: calc(100% - 32px); - box-sizing: border-box; - background: #ffffff; - padding: 16px 32px; - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); - outline: none; - overflow: auto; - --webkit-overflow-scrolling: touch; +} - animation: 0.2s ease-out popup-float-in; +.popup-content { + background: #ffffff; + padding: 16px 32px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); + transform: scale(0.97); - h1 { - font-weight: bolder; - font-size: 1.5em; - text-align: center; - margin-bottom: 16px; + h1 { + font-weight: bolder; + font-size: 1.5em; + text-align: center; + margin-bottom: 16px; - &.hidden { - /* still visible to screen readers due to aria-labelledby */ - display: none; - } + &.hidden { + /* still visible to screen readers due to aria-labelledby */ + display: none; } } } -@keyframes popup-fade-in { - from { - opacity: 0; - } - - to { - opacity: 1; - } +.popup-content[open], +.popup-content[open]::backdrop { + opacity: 1; + transform: none; + transition: + transform var(--animate-in) ease-out, + opacity var(--animate-in) ease-out; } -@keyframes popup-float-in { - from { - transform: translate(-50%, -50%) scale(0.9); +@starting-style { + .popup-content[open]::backdrop { + opacity: 0; } - to { - transform: translate(-50%, -50%); + .popup-content[open] { + opacity: 0; + transform: scale(0.9); } } @media (prefers-reduced-motion: reduce) { - @keyframes popup-float-in { - from { - transform: translate(-50%, -50%); - } - - to { - transform: translate(-50%, -50%); - } + .popup-content, + .popup-content[open] { + transform: none; } } diff --git a/frontend/src/components/common/Popup.tsx b/frontend/src/components/common/Popup.tsx index 329cbd2..ccfafb4 100644 --- a/frontend/src/components/common/Popup.tsx +++ b/frontend/src/components/common/Popup.tsx @@ -1,7 +1,13 @@ -import { type FC, useState, type PropsWithChildren } from 'react'; -import Modal from 'react-modal'; +import { + type FC, + type PropsWithChildren, + useRef, + useEffect, + type KeyboardEvent, + useId, + useState, +} from 'react'; import { useEvent } from '../../hooks/useEvent'; -import { useListener } from '../../hooks/useListener'; import './Popup.less'; interface PropsT { @@ -12,10 +18,6 @@ interface PropsT { onClose: () => void; } -function stopProp(e: Event) { - e.stopPropagation(); -} - export const Popup: FC> = ({ title, hideTitle = false, @@ -24,6 +26,8 @@ export const Popup: FC> = ({ onClose, children, }) => { + const [lagDisplay, setLagDisplay] = useState(false); + const handleKeyDown = useEvent((e: KeyboardEvent) => { e.stopPropagation(); const t = e.target as Element; @@ -43,28 +47,34 @@ export const Popup: FC> = ({ } }); - const [modal, setModal] = useState(); - useListener(modal, 'mousedown', stopProp); - useListener(modal, 'mouseup', stopProp); - useListener(modal, 'keyup', stopProp); - useListener(modal, 'keypress', stopProp); - useListener(modal, 'keydown', handleKeyDown); + const id = useId(); + const dialog = useRef(null); + useEffect(() => { + if (isOpen) { + setLagDisplay(true); + dialog.current?.showModal(); + return () => dialog.current?.close(); + } else { + const tm = setTimeout(() => setLagDisplay(false), 500); + return () => clearTimeout(tm); + } + }, [isOpen]); return ( - { + e.preventDefault(); + onClose(); + }} + onKeyDown={handleKeyDown} + aria-labelledby={id} > -

+

{title}

- {children} -
+ {isOpen || lagDisplay ? children : null} + ); }; diff --git a/frontend/src/components/common/Textarea.tsx b/frontend/src/components/common/Textarea.tsx index 1e8b50b..d9007d9 100644 --- a/frontend/src/components/common/Textarea.tsx +++ b/frontend/src/components/common/Textarea.tsx @@ -6,9 +6,9 @@ import { useLayoutEffect, TextareaHTMLAttributes, CSSProperties, + useEffect, } from 'react'; import classNames from 'classnames'; -import { useListener } from '../../hooks/useListener'; import { useDebounced } from '../../hooks/useDebounced'; import { getEmptyHeight, @@ -104,7 +104,10 @@ export const Textarea: FC = ({ } }, [textareaRef, baseHeightRef]); useLayoutEffect(updateSize, [updateSize, value]); - useListener(window, 'resize', updateSize); + useEffect(() => { + window.addEventListener('resize', updateSize); + return () => window.removeEventListener('resize', updateSize); + }, [updateSize]); const style: CSSProperties = {}; if (sizeToFit) { diff --git a/frontend/src/hooks/useListener.ts b/frontend/src/hooks/useListener.ts deleted file mode 100644 index 91d63f8..0000000 --- a/frontend/src/hooks/useListener.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { useEffect } from 'react'; - -export const useListener = ( - target: EventTarget | undefined, - type: string, - fn: (e: E) => void, -) => - useEffect(() => { - if (!target) { - return; - } - target.addEventListener(type, fn as EventListener); - return () => target.removeEventListener(type, fn as EventListener); - }, [target, type, fn]); diff --git a/frontend/src/index.less b/frontend/src/index.less index a743053..b9e4896 100644 --- a/frontend/src/index.less +++ b/frontend/src/index.less @@ -32,6 +32,18 @@ footer { color: inherit; } +dialog { + padding: 0; + border: none; + outline: none; + font: inherit; + color: inherit; +} + +dialog::backdrop { + background: none; +} + button { background: none; cursor: pointer; diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index 695038c..b9fc440 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -1,5 +1,4 @@ import { StrictMode } from 'react'; -import Modal from 'react-modal'; import { createRoot } from 'react-dom/client'; import { configService } from './api/api'; import { App } from './components/App'; @@ -19,7 +18,6 @@ if (navigator.userAgent === 'HeadlessEndToEndTest') { } const root = document.getElementById('root')!; -Modal.setAppElement(root); configService .load()