diff --git a/.circleci/config.yml b/.circleci/config.yml index 45575418bd..c6f07bfb6b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -151,7 +151,7 @@ jobs: react-version: << parameters.react-version >> - run: name: Run tests on JSDOM - command: pnpm test:jsdom --coverage + command: pnpm test:jsdom --coverage --project @base-ui-components/react --project docs - run: name: Check if coverage report is generated command: | @@ -290,7 +290,7 @@ jobs: browsers: true - run: name: Run tests on headless Chromium - command: pnpm test:chromium --coverage + command: pnpm test:chromium --coverage --project @base-ui-components/react --project docs - run: name: Check if coverage report is generated command: | diff --git a/.eslintrc.js b/.eslintrc.js index e0cc0660b8..ba0a13398b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -87,5 +87,12 @@ module.exports = { '@typescript-eslint/no-use-before-define': 'off', }, }, + { + files: ['test/**/*{.ts,.tsx}'], + rules: { + 'react/prop-types': 'off', + 'guard-for-in': 'off', + }, + }, ], }; diff --git a/package.json b/package.json index 9bb58bfeb7..d800820788 100644 --- a/package.json +++ b/package.json @@ -40,21 +40,21 @@ "test:coverage:ci": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc --reporter=lcov mocha 'packages/**/*.test.{js,ts,tsx}' 'docs/**/*.test.{js,ts,tsx}'", "test:coverage:html": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc --reporter=html mocha 'packages/**/*.test.{js,ts,tsx}' 'docs/**/*.test.{js,ts,tsx}'", "test:e2e": "cross-env NODE_ENV=production pnpm test:e2e:build && concurrently --success first --kill-others \"pnpm test:e2e:run\" \"pnpm test:e2e:server\"", - "test:e2e:build": "webpack --config test/e2e/webpack.config.js", - "test:e2e:dev": "concurrently \"pnpm test:e2e:build --watch\" \"pnpm test:e2e:server\"", - "test:e2e:run": "mocha --config test/e2e/.mocharc.js 'test/e2e/**/*.test.{js,ts,tsx}'", - "test:e2e:server": "serve test/e2e -p 5001", + "test:e2e:build": "vite build --config test/e2e/vite.config.mjs", + "test:e2e:dev": "vite --config test/e2e/vite.config.mjs -l info", + "test:e2e:run": "cross-env VITEST_ENV=chromium vitest --project e2e", + "test:e2e:server": "serve test/e2e -p 5173", "test:karma": "cross-env NODE_ENV=test karma start test/karma.conf.js", "test:karma:profile": "cross-env NODE_ENV=test karma start test/karma.conf.profile.js", "test:regressions": "cross-env NODE_ENV=production pnpm test:regressions:build && concurrently --success first --kill-others \"pnpm test:regressions:run\" \"pnpm test:regressions:server\"", - "test:regressions:build": "pnpm release:build && webpack --config test/regressions/webpack.config.js", - "test:regressions:dev": "concurrently \"pnpm test:regressions:build --watch\" \"pnpm test:regressions:server\"", - "test:regressions:run": "mocha --config test/regressions/.mocharc.js --delay 'test/regressions/**/*.test.js'", - "test:regressions:server": "serve test/regressions -p 5001", + "test:regressions:build": "vite build --config test/regressions/vite.config.mjs", + "test:regressions:dev": "vite --config test/regressions/vite.config.mjs", + "test:regressions:run": "cross-env VITEST_ENV=chromium vitest --project regressions", + "test:regressions:server": "serve test/regressions -p 5173", "test:unit": "cross-env NODE_ENV=test mocha 'packages/**/*.test.{js,ts,tsx}' 'docs/**/*.test.{js,ts,tsx}'", - "test:jsdom": "cross-env NODE_ENV=test VITEST_ENV=jsdom vitest", - "test:chromium": "cross-env NODE_ENV=test VITEST_ENV=chromium vitest", - "test:firefox": "cross-env NODE_ENV=test VITEST_ENV=firefox vitest", + "test:jsdom": "cross-env NODE_ENV=test VITEST_ENV=jsdom vitest --project @base-ui-components/react --project docs", + "test:chromium": "cross-env NODE_ENV=test VITEST_ENV=chromium vitest --project @base-ui-components/react --project docs", + "test:firefox": "cross-env NODE_ENV=test VITEST_ENV=firefox vitest --project @base-ui-components/react --project docs", "test:argos": "node ./scripts/pushArgos.mjs", "typescript": "tsc -b tsconfig.json", "validate-declarations": "tsx scripts/validateTypescriptDeclarations.mts", @@ -169,6 +169,7 @@ "typescript": "^5.7.2", "unist-util-visit": "^5.0.0", "url-join": "4.0.1", + "vite": "^6.0.3", "vitest": "^2.1.8", "webpack": "^5.97.1", "webpack-bundle-analyzer": "^4.10.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2273916670..c954b231e7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -106,10 +106,10 @@ importers: version: 7.18.0(eslint@8.57.1)(typescript@5.7.2) '@vitejs/plugin-react': specifier: ^4.3.4 - version: 4.3.4(vite@5.4.10(@types/node@18.19.69)(lightningcss@1.27.0)(terser@5.37.0)) + version: 4.3.4(vite@6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2)) '@vitest/browser': specifier: ^2.1.8 - version: 2.1.8(@types/node@18.19.69)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.10(@types/node@18.19.69)(lightningcss@1.27.0)(terser@5.37.0))(vitest@2.1.8) + version: 2.1.8(@types/node@18.19.69)(playwright@1.49.1)(typescript@5.7.2)(vite@6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2))(vitest@2.1.8) '@vitest/coverage-istanbul': specifier: 2.1.8 version: 2.1.8(vitest@2.1.8) @@ -344,6 +344,9 @@ importers: url-join: specifier: 4.0.1 version: 4.0.1 + vite: + specifier: ^6.0.3 + version: 6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2) vitest: specifier: ^2.1.8 version: 2.1.8(@types/node@18.19.69)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(lightningcss@1.27.0)(msw@2.6.5(@types/node@18.19.69)(typescript@5.7.2))(terser@5.37.0) @@ -710,12 +713,6 @@ importers: '@base-ui-components/react': specifier: workspace:* version: link:../packages/react/build - '@emotion/cache': - specifier: ^11.14.0 - version: 11.14.0 - '@emotion/react': - specifier: ^11.14.0 - version: 11.14.0(@types/react@19.0.2)(react@19.0.0) '@mui/internal-test-utils': specifier: ^1.0.24 version: 1.0.24(@babel/core@7.26.0)(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -731,9 +728,9 @@ importers: '@types/react': specifier: ^19.0.2 version: 19.0.2 - '@types/react-is': - specifier: ^19.0.0 - version: 19.0.0 + '@types/react-dom': + specifier: ^19.0.2 + version: 19.0.2(@types/react@19.0.2) '@types/sinon': specifier: ^17.0.3 version: 17.0.3 @@ -749,9 +746,6 @@ importers: fs-extra: specifier: ^11.2.0 version: 11.2.0 - html-webpack-plugin: - specifier: ^5.6.3 - version: 5.6.3(webpack@5.97.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1))) is-wsl: specifier: ^3.1.0 version: 3.1.0 @@ -761,42 +755,21 @@ importers: playwright: specifier: ^1.49.1 version: 1.49.1 - prop-types: - specifier: ^15.8.1 - version: 15.8.1 react: specifier: ^19.0.0 version: 19.0.0 react-dom: specifier: ^19.0.0 version: 19.0.0(react@19.0.0) - react-is: - specifier: ^19.0.0 - version: 19.0.0 react-router-dom: specifier: ^6.28.1 version: 6.28.1(react-dom@19.0.0(react@19.0.0))(react@19.0.0) sinon: specifier: ^17.0.1 version: 17.0.1 - styled-components: - specifier: ^6.1.13 - version: 6.1.13(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - stylis: - specifier: 4.3.4 - version: 4.3.4 - stylis-plugin-rtl: - specifier: ^2.1.1 - version: 2.1.1(stylis@4.3.4) - stylis-plugin-rtl-sc: - specifier: npm:stylis-plugin-rtl@^2.1.1 - version: stylis-plugin-rtl@2.1.1(stylis@4.3.4) util: specifier: ^0.12.5 version: 0.12.5 - webfontloader: - specifier: ^1.6.28 - version: 1.6.28 webpack: specifier: ^5.97.1 version: 5.97.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) @@ -1499,15 +1472,9 @@ packages: '@emotion/hash@0.9.2': resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} - '@emotion/is-prop-valid@1.2.2': - resolution: {integrity: sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==} - '@emotion/is-prop-valid@1.3.0': resolution: {integrity: sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==} - '@emotion/memoize@0.8.1': - resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} - '@emotion/memoize@0.9.0': resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} @@ -1547,9 +1514,6 @@ packages: '@emotion/unitless@0.10.0': resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} - '@emotion/unitless@0.8.1': - resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0': resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==} peerDependencies: @@ -1573,6 +1537,12 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.24.0': + resolution: {integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.21.5': resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} @@ -1585,6 +1555,12 @@ packages: cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.24.0': + resolution: {integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.21.5': resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} @@ -1597,6 +1573,12 @@ packages: cpu: [arm] os: [android] + '@esbuild/android-arm@0.24.0': + resolution: {integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.21.5': resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} @@ -1609,6 +1591,12 @@ packages: cpu: [x64] os: [android] + '@esbuild/android-x64@0.24.0': + resolution: {integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.21.5': resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} @@ -1621,6 +1609,12 @@ packages: cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.24.0': + resolution: {integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.21.5': resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} @@ -1633,6 +1627,12 @@ packages: cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.24.0': + resolution: {integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.21.5': resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} @@ -1645,6 +1645,12 @@ packages: cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.24.0': + resolution: {integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.21.5': resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} @@ -1657,6 +1663,12 @@ packages: cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.24.0': + resolution: {integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.21.5': resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} @@ -1669,6 +1681,12 @@ packages: cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.24.0': + resolution: {integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.21.5': resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} @@ -1681,6 +1699,12 @@ packages: cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.24.0': + resolution: {integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.21.5': resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} @@ -1693,6 +1717,12 @@ packages: cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.24.0': + resolution: {integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.21.5': resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} @@ -1705,6 +1735,12 @@ packages: cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.24.0': + resolution: {integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.21.5': resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} @@ -1717,6 +1753,12 @@ packages: cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.24.0': + resolution: {integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.21.5': resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} @@ -1729,6 +1771,12 @@ packages: cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.24.0': + resolution: {integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.21.5': resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} @@ -1741,6 +1789,12 @@ packages: cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.24.0': + resolution: {integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.21.5': resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} @@ -1753,6 +1807,12 @@ packages: cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.24.0': + resolution: {integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.21.5': resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} @@ -1765,6 +1825,12 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.24.0': + resolution: {integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-x64@0.21.5': resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} @@ -1777,12 +1843,24 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.24.0': + resolution: {integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.23.1': resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.24.0': + resolution: {integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.21.5': resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} @@ -1795,6 +1873,12 @@ packages: cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.24.0': + resolution: {integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/sunos-x64@0.21.5': resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} @@ -1807,6 +1891,12 @@ packages: cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.24.0': + resolution: {integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.21.5': resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} @@ -1819,6 +1909,12 @@ packages: cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.24.0': + resolution: {integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.21.5': resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} @@ -1831,6 +1927,12 @@ packages: cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.24.0': + resolution: {integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.21.5': resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} @@ -1843,6 +1945,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.24.0': + resolution: {integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3203,9 +3311,6 @@ packages: '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - '@types/html-minifier-terser@6.1.0': - resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} - '@types/istanbul-lib-coverage@2.0.6': resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} @@ -3262,9 +3367,6 @@ packages: peerDependencies: '@types/react': ^19.0.2 - '@types/react-is@19.0.0': - resolution: {integrity: sha512-71dSZeeJ0t3aoPyY9x6i+JNSvg5m9EF2i2OlSZI5QoJuI8Ocgor610i+4A10TQmURR+0vLwcVCEYFpXdzM1Biw==} - '@types/react@19.0.2': resolution: {integrity: sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg==} @@ -3283,9 +3385,6 @@ packages: '@types/statuses@2.0.5': resolution: {integrity: sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==} - '@types/stylis@4.2.5': - resolution: {integrity: sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==} - '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} @@ -3926,9 +4025,6 @@ packages: resolution: {integrity: sha512-SNMk0OONlQ01uk8EPeiBvTW7W4ovpL5b1O3t1sjpPgfxOQ6BqQJ6XjxinDPR79Z6HdcD5zBBwr5ssiTlgdNztQ==} engines: {node: '>=18'} - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - boxen@7.0.0: resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==} engines: {node: '>=14.16'} @@ -4018,9 +4114,6 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - camel-case@4.1.2: - resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} - camelcase-keys@6.2.2: resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} engines: {node: '>=8'} @@ -4037,9 +4130,6 @@ packages: resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} engines: {node: '>=14.16'} - camelize@1.0.1: - resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} - caniuse-lite@1.0.30001667: resolution: {integrity: sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw==} @@ -4133,10 +4223,6 @@ packages: cjs-module-lexer@1.4.1: resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} - clean-css@5.3.3: - resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} - engines: {node: '>= 10.0'} - clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -4443,10 +4529,6 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} - css-color-keywords@1.0.0: - resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} - engines: {node: '>=4'} - css-functions-list@3.2.3: resolution: {integrity: sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==} engines: {node: '>=12 || >=16'} @@ -4463,29 +4545,15 @@ packages: webpack: optional: true - css-select@4.3.0: - resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} - - css-to-react-native@3.2.0: - resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} - css-tree@3.1.0: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - css-what@6.1.0: - resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} - engines: {node: '>= 6'} - cssesc@3.0.0: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true - cssjanus@2.1.0: - resolution: {integrity: sha512-kAijbny3GmdOi9k+QT6DGIXqFvL96aksNlGr4Rhk9qXDZYWUojU4bRc3IHWxdaLNOqgEZHuXoe5Wl2l7dxLW5g==} - engines: {node: '>=10.0.0'} - cssstyle@4.1.0: resolution: {integrity: sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==} engines: {node: '>=18'} @@ -4708,28 +4776,9 @@ packages: dom-accessibility-api@0.7.0: resolution: {integrity: sha512-LjjdFmd9AITAet3Hy6Y6rwB7Sq1+x5NiwbOpnkLHC1bCXJqJKiV9DyppSSWobuSKvjKXt9G2u3hW402MPt6m+g==} - dom-converter@0.2.0: - resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==} - dom-serialize@2.2.1: resolution: {integrity: sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==} - dom-serializer@1.4.1: - resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@4.3.1: - resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} - engines: {node: '>= 4'} - - domutils@2.8.0: - resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} - - dot-case@3.0.4: - resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} - dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} engines: {node: '>=8'} @@ -4814,9 +4863,6 @@ packages: ent@2.2.0: resolution: {integrity: sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==} - entities@2.2.0: - resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} - entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -4902,6 +4948,11 @@ packages: engines: {node: '>=18'} hasBin: true + esbuild@0.24.0: + resolution: {integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -5777,11 +5828,6 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - html-minifier-terser@6.1.0: - resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} - engines: {node: '>=12'} - hasBin: true - html-tags@3.3.1: resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} engines: {node: '>=8'} @@ -5793,21 +5839,6 @@ packages: html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - html-webpack-plugin@5.6.3: - resolution: {integrity: sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==} - engines: {node: '>=10.13.0'} - peerDependencies: - '@rspack/core': 0.x || 1.x - webpack: ^5.20.0 - peerDependenciesMeta: - '@rspack/core': - optional: true - webpack: - optional: true - - htmlparser2@6.1.0: - resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} - http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} @@ -6705,9 +6736,6 @@ packages: loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} - lower-case@2.0.2: - resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} - lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -7257,9 +7285,6 @@ packages: nise@6.1.1: resolution: {integrity: sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==} - no-case@3.0.4: - resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} - node-cleanup@2.1.2: resolution: {integrity: sha512-qN8v/s2PAJwGUtr1/hYTpNKlD6Y9rc4p8KSmJXyGdYGZsDGKXrGThikLFP9OCHFeLeEpQzPwiAtdIvBLqm//Hw==} @@ -7380,9 +7405,6 @@ packages: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - nwsapi@2.2.16: resolution: {integrity: sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==} @@ -7608,9 +7630,6 @@ packages: engines: {node: ^16.14.0 || >=18.0.0} hasBin: true - param-case@3.0.4: - resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -7678,9 +7697,6 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} - pascal-case@3.1.2: - resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} - path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} @@ -7908,10 +7924,6 @@ packages: resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} - postcss@8.4.38: - resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} - engines: {node: ^10 || ^12 || >=14} - postcss@8.4.49: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} @@ -7980,9 +7992,6 @@ packages: engines: {node: '>=14'} hasBin: true - pretty-error@4.0.0: - resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} - pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -8338,10 +8347,6 @@ packages: rehype-recma@1.0.0: resolution: {integrity: sha512-lqA4rGUf1JmacCNWWZx0Wv1dHqMwxzsDWYMTowuplHF3xH0N/MmrZ/G3BDZnzAkRmxDadujCjaKM2hqYdCBOGw==} - relateurl@0.2.7: - resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} - engines: {node: '>= 0.10'} - release-zalgo@1.0.0: resolution: {integrity: sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==} engines: {node: '>=4'} @@ -8374,9 +8379,6 @@ packages: remark@15.0.1: resolution: {integrity: sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==} - renderkid@3.0.0: - resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} - require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -8580,9 +8582,6 @@ packages: resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} engines: {node: '>=8'} - shallowequal@1.1.0: - resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} - sharp@0.33.5: resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} @@ -8886,13 +8885,6 @@ packages: style-to-object@1.0.6: resolution: {integrity: sha512-khxq+Qm3xEyZfKd/y9L3oIWQimxuc4STrQKtQn8aSDRHb8mFgpukgX1hdzfrMEW6JCjyJ8p89x+IUMVnCBI1PA==} - styled-components@6.1.13: - resolution: {integrity: sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==} - engines: {node: '>= 16'} - peerDependencies: - react: '>= 16.8.0' - react-dom: '>= 16.8.0' - styled-jsx@5.1.6: resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} engines: {node: '>= 12.0.0'} @@ -8923,20 +8915,9 @@ packages: engines: {node: '>=18.12.0'} hasBin: true - stylis-plugin-rtl@2.1.1: - resolution: {integrity: sha512-q6xIkri6fBufIO/sV55md2CbgS5c6gg9EhSVATtHHCdOnbN/jcI0u3lYhNVeuI65c4lQPo67g8xmq5jrREvzlg==} - peerDependencies: - stylis: 4.x - stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} - stylis@4.3.2: - resolution: {integrity: sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==} - - stylis@4.3.4: - resolution: {integrity: sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==} - sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} @@ -9168,9 +9149,6 @@ packages: tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -9422,9 +9400,6 @@ packages: util@0.12.5: resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - utila@0.4.0: - resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} - utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -9512,6 +9487,46 @@ packages: terser: optional: true + vite@6.0.3: + resolution: {integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.19.69 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitest@2.1.8: resolution: {integrity: sha512-1vBKTZskHw/aosXqQUlVWWlGUxSJR8YtiyZDJAFeW2kPAeX6S3Sool0mjspO+kXLuxVWlEDDowBAeqeAQefqLQ==} engines: {node: ^18.0.0 || >=20.0.0} @@ -9558,9 +9573,6 @@ packages: web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - webfontloader@1.6.28: - resolution: {integrity: sha512-Egb0oFEga6f+nSgasH3E0M405Pzn6y3/9tOVanv/DLfa1YBIgcv90L18YyWnvXkRbIM17v5Kv6IT2N6g1x5tvQ==} - webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -10762,16 +10774,10 @@ snapshots: '@emotion/hash@0.9.2': {} - '@emotion/is-prop-valid@1.2.2': - dependencies: - '@emotion/memoize': 0.8.1 - '@emotion/is-prop-valid@1.3.0': dependencies: '@emotion/memoize': 0.9.0 - '@emotion/memoize@0.8.1': {} - '@emotion/memoize@0.9.0': {} '@emotion/react@11.14.0(@types/react@19.0.2)(react@19.0.0)': @@ -10824,8 +10830,6 @@ snapshots: '@emotion/unitless@0.10.0': {} - '@emotion/unitless@0.8.1': {} - '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.0.0)': dependencies: react: 19.0.0 @@ -10840,141 +10844,213 @@ snapshots: '@esbuild/aix-ppc64@0.23.1': optional: true + '@esbuild/aix-ppc64@0.24.0': + optional: true + '@esbuild/android-arm64@0.21.5': optional: true '@esbuild/android-arm64@0.23.1': optional: true + '@esbuild/android-arm64@0.24.0': + optional: true + '@esbuild/android-arm@0.21.5': optional: true '@esbuild/android-arm@0.23.1': optional: true + '@esbuild/android-arm@0.24.0': + optional: true + '@esbuild/android-x64@0.21.5': optional: true '@esbuild/android-x64@0.23.1': optional: true + '@esbuild/android-x64@0.24.0': + optional: true + '@esbuild/darwin-arm64@0.21.5': optional: true '@esbuild/darwin-arm64@0.23.1': optional: true + '@esbuild/darwin-arm64@0.24.0': + optional: true + '@esbuild/darwin-x64@0.21.5': optional: true '@esbuild/darwin-x64@0.23.1': optional: true + '@esbuild/darwin-x64@0.24.0': + optional: true + '@esbuild/freebsd-arm64@0.21.5': optional: true '@esbuild/freebsd-arm64@0.23.1': optional: true + '@esbuild/freebsd-arm64@0.24.0': + optional: true + '@esbuild/freebsd-x64@0.21.5': optional: true '@esbuild/freebsd-x64@0.23.1': optional: true + '@esbuild/freebsd-x64@0.24.0': + optional: true + '@esbuild/linux-arm64@0.21.5': optional: true '@esbuild/linux-arm64@0.23.1': optional: true + '@esbuild/linux-arm64@0.24.0': + optional: true + '@esbuild/linux-arm@0.21.5': optional: true '@esbuild/linux-arm@0.23.1': optional: true + '@esbuild/linux-arm@0.24.0': + optional: true + '@esbuild/linux-ia32@0.21.5': optional: true '@esbuild/linux-ia32@0.23.1': optional: true + '@esbuild/linux-ia32@0.24.0': + optional: true + '@esbuild/linux-loong64@0.21.5': optional: true '@esbuild/linux-loong64@0.23.1': optional: true + '@esbuild/linux-loong64@0.24.0': + optional: true + '@esbuild/linux-mips64el@0.21.5': optional: true '@esbuild/linux-mips64el@0.23.1': optional: true + '@esbuild/linux-mips64el@0.24.0': + optional: true + '@esbuild/linux-ppc64@0.21.5': optional: true '@esbuild/linux-ppc64@0.23.1': optional: true + '@esbuild/linux-ppc64@0.24.0': + optional: true + '@esbuild/linux-riscv64@0.21.5': optional: true '@esbuild/linux-riscv64@0.23.1': optional: true + '@esbuild/linux-riscv64@0.24.0': + optional: true + '@esbuild/linux-s390x@0.21.5': optional: true '@esbuild/linux-s390x@0.23.1': optional: true + '@esbuild/linux-s390x@0.24.0': + optional: true + '@esbuild/linux-x64@0.21.5': optional: true '@esbuild/linux-x64@0.23.1': optional: true + '@esbuild/linux-x64@0.24.0': + optional: true + '@esbuild/netbsd-x64@0.21.5': optional: true '@esbuild/netbsd-x64@0.23.1': optional: true + '@esbuild/netbsd-x64@0.24.0': + optional: true + '@esbuild/openbsd-arm64@0.23.1': optional: true + '@esbuild/openbsd-arm64@0.24.0': + optional: true + '@esbuild/openbsd-x64@0.21.5': optional: true '@esbuild/openbsd-x64@0.23.1': optional: true + '@esbuild/openbsd-x64@0.24.0': + optional: true + '@esbuild/sunos-x64@0.21.5': optional: true '@esbuild/sunos-x64@0.23.1': optional: true + '@esbuild/sunos-x64@0.24.0': + optional: true + '@esbuild/win32-arm64@0.21.5': optional: true '@esbuild/win32-arm64@0.23.1': optional: true + '@esbuild/win32-arm64@0.24.0': + optional: true + '@esbuild/win32-ia32@0.21.5': optional: true '@esbuild/win32-ia32@0.23.1': optional: true + '@esbuild/win32-ia32@0.24.0': + optional: true + '@esbuild/win32-x64@0.21.5': optional: true '@esbuild/win32-x64@0.23.1': optional: true + '@esbuild/win32-x64@0.24.0': + optional: true + '@eslint-community/eslint-utils@4.4.0(eslint@8.57.1)': dependencies: eslint: 8.57.1 @@ -12643,8 +12719,6 @@ snapshots: dependencies: '@types/unist': 3.0.3 - '@types/html-minifier-terser@6.1.0': {} - '@types/istanbul-lib-coverage@2.0.6': {} '@types/json-schema@7.0.15': {} @@ -12691,10 +12765,6 @@ snapshots: dependencies: '@types/react': 19.0.2 - '@types/react-is@19.0.0': - dependencies: - '@types/react': 19.0.2 - '@types/react@19.0.2': dependencies: csstype: 3.1.3 @@ -12711,8 +12781,6 @@ snapshots: '@types/statuses@2.0.5': {} - '@types/stylis@4.2.5': {} - '@types/tough-cookie@4.0.5': {} '@types/unist@2.0.10': {} @@ -12918,22 +12986,22 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react@4.3.4(vite@5.4.10(@types/node@18.19.69)(lightningcss@1.27.0)(terser@5.37.0))': + '@vitejs/plugin-react@4.3.4(vite@6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2))': dependencies: '@babel/core': 7.26.0 '@babel/plugin-transform-react-jsx-self': 7.25.9(@babel/core@7.26.0) '@babel/plugin-transform-react-jsx-source': 7.25.9(@babel/core@7.26.0) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.10(@types/node@18.19.69)(lightningcss@1.27.0)(terser@5.37.0) + vite: 6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2) transitivePeerDependencies: - supports-color - '@vitest/browser@2.1.8(@types/node@18.19.69)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.10(@types/node@18.19.69)(lightningcss@1.27.0)(terser@5.37.0))(vitest@2.1.8)': + '@vitest/browser@2.1.8(@types/node@18.19.69)(playwright@1.49.1)(typescript@5.7.2)(vite@6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2))(vitest@2.1.8)': dependencies: '@testing-library/dom': 10.4.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) - '@vitest/mocker': 2.1.8(msw@2.6.5(@types/node@18.19.69)(typescript@5.7.2))(vite@5.4.10(@types/node@18.19.69)(lightningcss@1.27.0)(terser@5.37.0)) + '@vitest/mocker': 2.1.8(msw@2.6.5(@types/node@18.19.69)(typescript@5.7.2))(vite@6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2)) '@vitest/utils': 2.1.8 magic-string: 0.30.12 msw: 2.6.5(@types/node@18.19.69)(typescript@5.7.2) @@ -12982,6 +13050,15 @@ snapshots: msw: 2.6.5(@types/node@18.19.69)(typescript@5.7.2) vite: 5.4.10(@types/node@18.19.69)(lightningcss@1.27.0)(terser@5.37.0) + '@vitest/mocker@2.1.8(msw@2.6.5(@types/node@18.19.69)(typescript@5.7.2))(vite@6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2))': + dependencies: + '@vitest/spy': 2.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.12 + optionalDependencies: + msw: 2.6.5(@types/node@18.19.69)(typescript@5.7.2) + vite: 6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2) + '@vitest/pretty-format@2.1.8': dependencies: tinyrainbow: 1.2.0 @@ -13522,8 +13599,6 @@ snapshots: transitivePeerDependencies: - supports-color - boolbase@1.0.0: {} - boxen@7.0.0: dependencies: ansi-align: 3.0.1 @@ -13652,11 +13727,6 @@ snapshots: callsites@3.1.0: {} - camel-case@4.1.2: - dependencies: - pascal-case: 3.1.2 - tslib: 2.8.1 - camelcase-keys@6.2.2: dependencies: camelcase: 5.3.1 @@ -13669,8 +13739,6 @@ snapshots: camelcase@7.0.1: {} - camelize@1.0.1: {} - caniuse-lite@1.0.30001667: {} ccount@2.0.1: {} @@ -13765,10 +13833,6 @@ snapshots: cjs-module-lexer@1.4.1: {} - clean-css@5.3.3: - dependencies: - source-map: 0.6.1 - clean-stack@2.2.0: {} cli-boxes@3.0.0: {} @@ -14085,8 +14149,6 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 - css-color-keywords@1.0.0: {} - css-functions-list@3.2.3: {} css-loader@7.1.2(webpack@5.97.1): @@ -14102,31 +14164,13 @@ snapshots: optionalDependencies: webpack: 5.97.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) - css-select@4.3.0: - dependencies: - boolbase: 1.0.0 - css-what: 6.1.0 - domhandler: 4.3.1 - domutils: 2.8.0 - nth-check: 2.1.1 - - css-to-react-native@3.2.0: - dependencies: - camelize: 1.0.1 - css-color-keywords: 1.0.0 - postcss-value-parser: 4.2.0 - css-tree@3.1.0: dependencies: mdn-data: 2.12.2 source-map-js: 1.2.1 - css-what@6.1.0: {} - cssesc@3.0.0: {} - cssjanus@2.1.0: {} - cssstyle@4.1.0: dependencies: rrweb-cssom: 0.7.1 @@ -14332,10 +14376,6 @@ snapshots: dom-accessibility-api@0.7.0: {} - dom-converter@0.2.0: - dependencies: - utila: 0.4.0 - dom-serialize@2.2.1: dependencies: custom-event: 1.0.1 @@ -14343,29 +14383,6 @@ snapshots: extend: 3.0.2 void-elements: 2.0.1 - dom-serializer@1.4.1: - dependencies: - domelementtype: 2.3.0 - domhandler: 4.3.1 - entities: 2.2.0 - - domelementtype@2.3.0: {} - - domhandler@4.3.1: - dependencies: - domelementtype: 2.3.0 - - domutils@2.8.0: - dependencies: - dom-serializer: 1.4.1 - domelementtype: 2.3.0 - domhandler: 4.3.1 - - dot-case@3.0.4: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - dot-prop@5.3.0: dependencies: is-obj: 2.0.0 @@ -14451,8 +14468,6 @@ snapshots: ent@2.2.0: {} - entities@2.2.0: {} - entities@4.5.0: {} env-paths@2.2.1: {} @@ -14641,6 +14656,33 @@ snapshots: '@esbuild/win32-ia32': 0.23.1 '@esbuild/win32-x64': 0.23.1 + esbuild@0.24.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.0 + '@esbuild/android-arm': 0.24.0 + '@esbuild/android-arm64': 0.24.0 + '@esbuild/android-x64': 0.24.0 + '@esbuild/darwin-arm64': 0.24.0 + '@esbuild/darwin-x64': 0.24.0 + '@esbuild/freebsd-arm64': 0.24.0 + '@esbuild/freebsd-x64': 0.24.0 + '@esbuild/linux-arm': 0.24.0 + '@esbuild/linux-arm64': 0.24.0 + '@esbuild/linux-ia32': 0.24.0 + '@esbuild/linux-loong64': 0.24.0 + '@esbuild/linux-mips64el': 0.24.0 + '@esbuild/linux-ppc64': 0.24.0 + '@esbuild/linux-riscv64': 0.24.0 + '@esbuild/linux-s390x': 0.24.0 + '@esbuild/linux-x64': 0.24.0 + '@esbuild/netbsd-x64': 0.24.0 + '@esbuild/openbsd-arm64': 0.24.0 + '@esbuild/openbsd-x64': 0.24.0 + '@esbuild/sunos-x64': 0.24.0 + '@esbuild/win32-arm64': 0.24.0 + '@esbuild/win32-ia32': 0.24.0 + '@esbuild/win32-x64': 0.24.0 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -15826,16 +15868,6 @@ snapshots: html-escaper@2.0.2: {} - html-minifier-terser@6.1.0: - dependencies: - camel-case: 4.1.2 - clean-css: 5.3.3 - commander: 8.3.0 - he: 1.2.0 - param-case: 3.0.4 - relateurl: 0.2.7 - terser: 5.37.0 - html-tags@3.3.1: {} html-tokenize@2.0.1: @@ -15848,23 +15880,6 @@ snapshots: html-void-elements@3.0.0: {} - html-webpack-plugin@5.6.3(webpack@5.97.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1))): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.21 - pretty-error: 4.0.0 - tapable: 2.2.1 - optionalDependencies: - webpack: 5.97.1(webpack-cli@5.1.4(webpack-bundle-analyzer@4.10.2)(webpack@5.97.1)) - - htmlparser2@6.1.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 4.3.1 - domutils: 2.8.0 - entities: 2.2.0 - http-cache-semantics@4.1.1: {} http-errors@2.0.0: @@ -16905,10 +16920,6 @@ snapshots: loupe@3.1.2: {} - lower-case@2.0.2: - dependencies: - tslib: 2.8.1 - lru-cache@10.4.3: {} lru-cache@11.0.1: {} @@ -17810,11 +17821,6 @@ snapshots: just-extend: 6.2.0 path-to-regexp: 8.2.0 - no-case@3.0.4: - dependencies: - lower-case: 2.0.2 - tslib: 2.8.1 - node-cleanup@2.1.2: {} node-dir@0.1.17: @@ -17961,10 +17967,6 @@ snapshots: path-key: 4.0.0 unicorn-magic: 0.3.0 - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 - nwsapi@2.2.16: {} nx@18.3.5: @@ -18296,11 +18298,6 @@ snapshots: - bluebird - supports-color - param-case@3.0.4: - dependencies: - dot-case: 3.0.4 - tslib: 2.8.1 - parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -18376,11 +18373,6 @@ snapshots: parseurl@1.3.3: {} - pascal-case@3.1.2: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - path-exists@3.0.0: {} path-exists@4.0.0: {} @@ -18561,12 +18553,6 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.4.38: - dependencies: - nanoid: 3.3.7 - picocolors: 1.1.1 - source-map-js: 1.2.1 - postcss@8.4.49: dependencies: nanoid: 3.3.7 @@ -18581,11 +18567,6 @@ snapshots: prettier@3.4.2: {} - pretty-error@4.0.0: - dependencies: - lodash: 4.17.21 - renderkid: 3.0.0 - pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -18990,8 +18971,6 @@ snapshots: transitivePeerDependencies: - supports-color - relateurl@0.2.7: {} - release-zalgo@1.0.0: dependencies: es6-error: 4.1.1 @@ -19066,14 +19045,6 @@ snapshots: transitivePeerDependencies: - supports-color - renderkid@3.0.0: - dependencies: - css-select: 4.3.0 - dom-converter: 0.2.0 - htmlparser2: 6.1.0 - lodash: 4.17.21 - strip-ansi: 6.0.1 - require-directory@2.1.1: {} require-from-string@2.0.2: {} @@ -19328,8 +19299,6 @@ snapshots: dependencies: kind-of: 6.0.3 - shallowequal@1.1.0: {} - sharp@0.33.5: dependencies: color: 4.2.3 @@ -19726,20 +19695,6 @@ snapshots: dependencies: inline-style-parser: 0.2.3 - styled-components@6.1.13(react-dom@19.0.0(react@19.0.0))(react@19.0.0): - dependencies: - '@emotion/is-prop-valid': 1.2.2 - '@emotion/unitless': 0.8.1 - '@types/stylis': 4.2.5 - css-to-react-native: 3.2.0 - csstype: 3.1.3 - postcss: 8.4.38 - react: 19.0.0 - react-dom: 19.0.0(react@19.0.0) - shallowequal: 1.1.0 - stylis: 4.3.2 - tslib: 2.6.2 - styled-jsx@5.1.6(@babel/core@7.26.0)(babel-plugin-macros@3.1.0)(react@19.0.0): dependencies: client-only: 0.0.1 @@ -19801,17 +19756,8 @@ snapshots: - supports-color - typescript - stylis-plugin-rtl@2.1.1(stylis@4.3.4): - dependencies: - cssjanus: 2.1.0 - stylis: 4.3.4 - stylis@4.2.0: {} - stylis@4.3.2: {} - - stylis@4.3.4: {} - sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.5 @@ -20039,8 +19985,6 @@ snapshots: tslib@1.14.1: {} - tslib@2.6.2: {} - tslib@2.8.1: {} tsscmp@1.0.6: {} @@ -20290,8 +20234,6 @@ snapshots: is-typed-array: 1.1.15 which-typed-array: 1.1.18 - utila@0.4.0: {} - utils-merge@1.0.1: {} uuid@10.0.0: {} @@ -20371,6 +20313,19 @@ snapshots: lightningcss: 1.27.0 terser: 5.37.0 + vite@6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2): + dependencies: + esbuild: 0.24.0 + postcss: 8.4.49 + rollup: 4.24.2 + optionalDependencies: + '@types/node': 18.19.69 + fsevents: 2.3.3 + jiti: 2.4.0 + lightningcss: 1.27.0 + terser: 5.37.0 + tsx: 4.19.2 + vitest@2.1.8(@types/node@18.19.69)(@vitest/browser@2.1.8)(@vitest/ui@2.1.8)(jsdom@25.0.1)(lightningcss@1.27.0)(msw@2.6.5(@types/node@18.19.69)(typescript@5.7.2))(terser@5.37.0): dependencies: '@vitest/expect': 2.1.8 @@ -20395,7 +20350,7 @@ snapshots: why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 18.19.69 - '@vitest/browser': 2.1.8(@types/node@18.19.69)(playwright@1.49.1)(typescript@5.7.2)(vite@5.4.10(@types/node@18.19.69)(lightningcss@1.27.0)(terser@5.37.0))(vitest@2.1.8) + '@vitest/browser': 2.1.8(@types/node@18.19.69)(playwright@1.49.1)(typescript@5.7.2)(vite@6.0.3(@types/node@18.19.69)(jiti@2.4.0)(lightningcss@1.27.0)(terser@5.37.0)(tsx@4.19.2))(vitest@2.1.8) '@vitest/ui': 2.1.8(vitest@2.1.8) jsdom: 25.0.1 transitivePeerDependencies: @@ -20428,8 +20383,6 @@ snapshots: web-namespaces@2.0.1: {} - webfontloader@1.6.28: {} - webidl-conversions@3.0.1: {} webidl-conversions@7.0.0: {} diff --git a/test/README.md b/test/README.md index 0304aaf8af..c26ee2aa0c 100644 --- a/test/README.md +++ b/test/README.md @@ -200,7 +200,7 @@ You can pass the same arguments as you could to `mocha`. For example, `pnpm test:regressions:run --watch --grep "docs-system-basic"` to take new screenshots of every demo in `docs/src/pages/system/basic`. You can view the screenshots in `test/regressions/screenshots/chrome`. -Alternatively, you might want to open `http://localhost:5001` (while `pnpm test:regressions:dev` is running) to view individual views separately. +Alternatively, you might want to open `http://localhost:5173` (while `pnpm test:regressions:dev` is running) to view individual views separately. ### Caveats diff --git a/test/e2e/.mocharc.js b/test/e2e/.mocharc.js deleted file mode 100644 index 95bb343e11..0000000000 --- a/test/e2e/.mocharc.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - extension: ['js', 'ts', 'tsx'], - recursive: true, - slow: 500, - timeout: (process.env.CIRCLECI === 'true' ? 4 : 2) * 1000, // Circle CI has low-performance CPUs. - reporter: 'dot', - require: ['@mui/internal-test-utils/setupBabelPlaywright'], -}; diff --git a/test/e2e/README.md b/test/e2e/README.md index f99a9e42ef..6517b9ba71 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -2,12 +2,12 @@ End-to-end tests (short e2e) are split into two parts: -1. The rendered UI (short: fixture) -2. Instrumentation of that UI +1. The rendered UI, or test fixtures +2. Instrumentation of fixtures with a simple Vite app ## Rendered UI -The composition of all tests happens in `./index.js`. +The composition of all tests happens in [`./main.tsx`](./main.tsx). The rendered UI is located inside a separate file in `./fixtures` and written as a React component. If you're adding a new test prefer a new component instead of editing existing files since that might unknowingly alter existing tests. @@ -24,7 +24,7 @@ For development `pnpm test:e2e:dev` and `pnpm test:e2e:run --watch` in separate | command | description | | :--------------------- | :-------------------------------------------------------------------------------------------- | | `pnpm test:e2e` | Full run | -| `pnpm test:e2e:dev` | Prepares the fixtures to be able to test in watchmode | +| `pnpm test:e2e:dev` | Prepares the fixtures and runs a Vite dev server | | `pnpm test:e2e:run` | Runs the tests (requires `pnpm test:e2e:dev` or `pnpm test:e2e:build`+`pnpm test:e2e:server`) | -| `pnpm test:e2e:build` | Builds the webpack bundle for viewing the fixtures | +| `pnpm test:e2e:build` | Builds the Vite bundle for viewing fixtures | | `pnpm test:e2e:server` | Serves the fixture bundle. | diff --git a/test/e2e/TestViewer.js b/test/e2e/TestViewer.tsx similarity index 81% rename from test/e2e/TestViewer.js rename to test/e2e/TestViewer.tsx index 09c21fd4d7..c3b048db96 100644 --- a/test/e2e/TestViewer.js +++ b/test/e2e/TestViewer.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; -import PropTypes from 'prop-types'; -function TestViewer(props) { +function TestViewer(props: { children: React.ReactNode }) { const { children } = props; // We're simulating `act(() => ReactDOM.render(children))` @@ -21,8 +20,4 @@ function TestViewer(props) { ); } -TestViewer.propTypes = { - children: PropTypes.node.isRequired, -}; - export default TestViewer; diff --git a/test/e2e/fixtures/Radio.tsx b/test/e2e/fixtures/Radio.tsx new file mode 100644 index 0000000000..71bdd74bb2 --- /dev/null +++ b/test/e2e/fixtures/Radio.tsx @@ -0,0 +1,50 @@ +import * as React from 'react'; +import { Radio } from '@base-ui-components/react/radio'; +import { RadioGroup } from '@base-ui-components/react/radio-group'; + +export default function ExampleRadioGroup() { + return ( + +
+ Best apple +
+ + + + + + +
+ ); +} diff --git a/test/e2e/template.html b/test/e2e/index.html similarity index 86% rename from test/e2e/template.html rename to test/e2e/index.html index fe0f2392e5..803a1e62db 100644 --- a/test/e2e/template.html +++ b/test/e2e/index.html @@ -12,5 +12,6 @@
+ diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts index 0c14cb3526..efbd9bba45 100644 --- a/test/e2e/index.test.ts +++ b/test/e2e/index.test.ts @@ -1,4 +1,6 @@ +import { expect } from 'chai'; import * as playwright from 'playwright'; +import { describe, it } from 'vitest'; import type { ByRoleMatcher, ByRoleOptions, @@ -9,6 +11,8 @@ import type { import '@mui/internal-test-utils/initMatchers'; import '@mui/internal-test-utils/initPlaywrightMatchers'; +const BASE_URL = 'http://localhost:5173'; + function sleep(duration: number): Promise { return new Promise((resolve) => { setTimeout(() => { @@ -63,10 +67,8 @@ async function attemptGoto(page: playwright.Page, url: string): Promise } describe('e2e', () => { - const baseUrl = 'http://localhost:5001'; let browser: playwright.Browser; let page: playwright.Page; - // eslint-disable-next-line @typescript-eslint/no-unused-vars const screen: PlaywrightScreen = { getByLabelText: (...inputArgs) => { return page.evaluateHandle( @@ -94,23 +96,22 @@ describe('e2e', () => { }, }; - // eslint-disable-next-line @typescript-eslint/no-unused-vars async function renderFixture(fixturePath: string) { - await page.goto(`${baseUrl}/e2e/${fixturePath}#no-dev`); + await page.goto(`${BASE_URL}/e2e-fixtures/${fixturePath}#no-dev`); await page.waitForSelector('[data-testid="testcase"]:not([aria-busy="true"])'); } before(async function beforeHook() { - this.timeout(20000); + this?.timeout(20000); browser = await playwright.chromium.launch({ headless: true, }); page = await browser.newPage(); - const isServerRunning = await attemptGoto(page, `${baseUrl}#no-dev`); + const isServerRunning = await attemptGoto(page, `${BASE_URL}#no-dev`); if (!isServerRunning) { throw new Error( - `Unable to navigate to ${baseUrl} after multiple attempts. Did you forget to run \`pnpm test:e2e:server\` and \`pnpm test:e2e:build\`?`, + `Unable to navigate to ${BASE_URL} after multiple attempts. Did you forget to run \`pnpm test:e2e:server\` and \`pnpm test:e2e:build\`?`, ); } }); @@ -118,4 +119,22 @@ describe('e2e', () => { after(async () => { await browser.close(); }); + + describe('', () => { + it('loops focus by default', async () => { + await renderFixture('Radio'); + + await page.keyboard.press('Tab'); + await expect(screen.getByTestId('one')).toHaveFocus(); + + await page.keyboard.press('ArrowRight'); + await expect(screen.getByTestId('two')).toHaveFocus(); + + await page.keyboard.press('ArrowLeft'); + await expect(screen.getByTestId('one')).toHaveFocus(); + + await page.keyboard.press('ArrowLeft'); + await expect(screen.getByTestId('three')).toHaveFocus(); + }); + }); }); diff --git a/test/e2e/index.js b/test/e2e/main.tsx similarity index 78% rename from test/e2e/index.js rename to test/e2e/main.tsx index e0c3ff8a1a..1ef70589ec 100644 --- a/test/e2e/index.js +++ b/test/e2e/main.tsx @@ -1,29 +1,34 @@ import * as React from 'react'; -import * as ReactDOM from 'react-dom'; import * as ReactDOMClient from 'react-dom/client'; import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; import * as DomTestingLibrary from '@testing-library/dom'; import TestViewer from './TestViewer'; +import 'docs/src/styles.css'; -const fixtures = []; +interface Fixture { + Component: React.LazyExoticComponent>; + name: string; + path: string; + suite: string; +} -const importFixtures = require.context('./fixtures', true, /\.(js|ts|tsx)$/, 'lazy'); -importFixtures.keys().forEach((path) => { - // require.context contains paths for module alias imports and relative imports - if (!path.startsWith('.')) { - return; - } +const globbedFixtures = import.meta.glob<{ default: React.ComponentType }>( + './fixtures/**/*.{js,jsx,ts,tsx}', +); +const fixtures: Fixture[] = []; + +for (const path in globbedFixtures) { const [suite, name] = path .replace('./', '') .replace(/\.\w+$/, '') .split('/'); fixtures.push({ path, - suite: `e2e/${suite}`, + suite: `e2e-${suite}`, name, - Component: React.lazy(() => importFixtures(path)), + Component: React.lazy(() => globbedFixtures[path]()), }); -}); +} function App() { function computeIsDev() { @@ -47,7 +52,7 @@ function App() { }; }, []); - function computePath(fixture) { + function computePath(fixture: Fixture) { return `/${fixture.suite}/${fixture.name}`; } @@ -65,7 +70,6 @@ function App() { return ( @@ -104,12 +108,10 @@ function App() { const container = document.getElementById('react-root'); const children = ; -if (typeof ReactDOM.unstable_createRoot === 'function') { - const root = ReactDOM.unstable_createRoot(container); - root.render(children); -} else { - const root = ReactDOMClient.createRoot(container); - root.render(children); + +if (container != null) { + const reactRoot = ReactDOMClient.createRoot(container); + reactRoot.render(children); } window.DomTestingLibrary = DomTestingLibrary; @@ -118,7 +120,7 @@ window.elementToString = function elementToString(element) { element != null && (element.nodeType === element.ELEMENT_NODE || element.nodeType === element.DOCUMENT_NODE) ) { - return window.DomTestingLibrary.prettyDOM(element, undefined, { + return window.DomTestingLibrary.prettyDOM(element as Element, undefined, { highlight: true, maxDepth: 1, }); diff --git a/test/e2e/postcss.config.js b/test/e2e/postcss.config.js new file mode 100644 index 0000000000..b4c177ee1f --- /dev/null +++ b/test/e2e/postcss.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: { + 'postcss-import': {}, + '@tailwindcss/postcss': {}, + 'postcss-custom-media': {}, + }, +}; diff --git a/test/e2e/serve.json b/test/e2e/serve.json index ef9da9b562..f89ff3f00c 100644 --- a/test/e2e/serve.json +++ b/test/e2e/serve.json @@ -1,4 +1,4 @@ { "public": "build", - "rewrites": [{ "source": "**", "destination": "index.html" }] + "rewrites": [{ "source": "**", "destination": "/index.html" }] } diff --git a/test/e2e/vite.config.mjs b/test/e2e/vite.config.mjs new file mode 100644 index 0000000000..3e3d69879e --- /dev/null +++ b/test/e2e/vite.config.mjs @@ -0,0 +1,10 @@ +import * as path from 'path'; +import { defineConfig, mergeConfig } from 'vite'; +import sharedConfig from '../vite.shared.config.mjs'; + +export default mergeConfig( + sharedConfig, + defineConfig({ + root: path.join(process.cwd(), 'test/e2e'), + }), +); diff --git a/test/e2e/vitest.config.mts b/test/e2e/vitest.config.mts new file mode 100644 index 0000000000..f8c7a2098a --- /dev/null +++ b/test/e2e/vitest.config.mts @@ -0,0 +1,20 @@ +import { mergeConfig, defineProject } from 'vitest/config'; +import sharedConfig from '../../vitest.shared.mts'; + +export default mergeConfig( + sharedConfig, + defineProject({ + test: { + environment: 'node', + testTimeout: (process.env.CIRCLECI === 'true' ? 4 : 2) * 1000, // Circle CI has low-performance CPUs. + browser: { + provider: 'playwright', + enabled: false, + name: 'node', + }, + env: { + VITEST_ENV: 'node', + }, + }, + }), +); diff --git a/test/e2e/webpack.config.js b/test/e2e/webpack.config.js deleted file mode 100644 index e938716194..0000000000 --- a/test/e2e/webpack.config.js +++ /dev/null @@ -1,42 +0,0 @@ -const path = require('path'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); - -module.exports = { - entry: path.resolve(__dirname, 'index.js'), - mode: process.env.NODE_ENV || 'development', - optimization: { - // Helps debugging and build perf. - // Bundle size is irrelevant for local serving - minimize: false, - }, - output: { - path: path.resolve(__dirname, './build'), - publicPath: '/', - filename: 'tests.js', - }, - plugins: [ - new HtmlWebpackPlugin({ - template: path.resolve(__dirname, './template.html'), - }), - ], - module: { - rules: [ - { - test: /\.(js|ts|tsx)$/, - exclude: /node_modules/, - loader: 'babel-loader', - options: { - cacheDirectory: true, - configFile: path.resolve(__dirname, '../../babel.config.js'), - envName: 'regressions', - }, - }, - { - test: /\.(jpg|gif|png)$/, - type: 'asset/inline', - }, - ], - }, - // TODO: 'browserslist:modern' - target: 'web', -}; diff --git a/test/package.json b/test/package.json index 2fbef0b6c1..baf6df1e4c 100644 --- a/test/package.json +++ b/test/package.json @@ -8,35 +8,25 @@ "devDependencies": { "@babel/runtime": "^7.26.0", "@base-ui-components/react": "workspace:*", - "@emotion/cache": "^11.14.0", - "@emotion/react": "^11.14.0", "@mui/internal-test-utils": "^1.0.24", "@playwright/test": "1.49.1", "@testing-library/dom": "^10.4.0", "@types/chai": "^4.3.20", "@types/react": "^19.0.2", - "@types/react-is": "^19.0.0", + "@types/react-dom": "^19.0.2", "@types/sinon": "^17.0.3", "chai": "^4.5.0", "docs": "workspace:^", "fast-glob": "^3.3.2", "fs-extra": "^11.2.0", - "html-webpack-plugin": "^5.6.3", "is-wsl": "^3.1.0", "lodash": "^4.17.21", "playwright": "^1.49.1", - "prop-types": "^15.8.1", "react": "^19.0.0", "react-dom": "^19.0.0", - "react-is": "^19.0.0", "react-router-dom": "^6.28.1", "sinon": "^17.0.1", - "styled-components": "^6.1.13", - "stylis": "4.3.4", - "stylis-plugin-rtl": "^2.1.1", - "stylis-plugin-rtl-sc": "npm:stylis-plugin-rtl@^2.1.1", "util": "^0.12.5", - "webfontloader": "^1.6.28", "webpack": "^5.97.1", "yargs": "^17.7.2" } diff --git a/test/regressions/.mocharc.js b/test/regressions/.mocharc.js deleted file mode 100644 index 5f79b51262..0000000000 --- a/test/regressions/.mocharc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - recursive: true, - slow: 500, - timeout: (process.env.CIRCLECI === 'true' ? 4 : 2) * 1000, // Circle CI has low-performance CPUs. - reporter: 'dot', - require: ['@mui/internal-test-utils/setupBabelPlaywright'], -}; diff --git a/test/regressions/README.md b/test/regressions/README.md index 765cfad59b..928beeb292 100644 --- a/test/regressions/README.md +++ b/test/regressions/README.md @@ -2,23 +2,23 @@ Visual regression tests are split into two parts: -1. The rendered UI (short: fixture) -2. Instrumentation of that UI +1. The rendered UI, or test fixtures +2. Instrumentation of fixtures with a simple Vite app ## Rendered UI -The composition of all tests happens in `./index.js`. +The composition of all tests happens in [`./main.tsx`](./main.tsx). The rendered UI is either: 1. located inside a separate file in `./fixtures` and written as a React component. Here is an [example](https://github.com/mui/material-ui/blob/814fb60bbd8e500517b2307b6a297a638838ca89/test/regressions/tests/Menu/SimpleMenuList.js#L6-L16) with the `Menu` component. -2. a demo from `docs/app/src` +2. a demo from `docs/src/app/(public)/(content)/react` By default all demos are included. We exclude demos if they are redundant or flaky etc. - The logic for this exclusion is handled (like the composition) in `./index.js` + The logic for this exclusion is handled (like the composition) in [`./main.tsx`](./main.tsx) If you introduce new behavior, prefer adding a demo to the documentation to solve documentation and testing with one file. If you're adding a new test prefer a new component instead of editing existing files since that might unknowingly alter existing tests. @@ -29,7 +29,7 @@ If you're adding a new test prefer a new component instead of editing existing f `pnpm test:regressions:dev` will build all fixtures and render an overview page that lists all fixtures. This can be used to debug individual fixtures. -By default, a devtools-like view is shown that can be disabled by appending `#no-dev` to the URL, for example `http://localhost:5001/docs-customization-typography/CustomResponsiveFontSizes#no-dev` or forced by appending `#dev` to the URL, for example `http://localhost:5001/docs-customization-typography/CustomResponsiveFontSizes#dev`. +By default, a devtools-like view is shown that can be disabled by appending `#no-dev` to the URL, for example `http://localhost:5173/docs-components-checkbox-group-demos-hero-tailwind/index.tsx#no-dev` or forced by appending `#dev` to the URL, for example `http://localhost:5173/docs-components-checkbox-group-demos-hero-tailwind/index.tsx#dev`. ### Automatic @@ -45,12 +45,12 @@ A fixture can be loaded with `await renderFixture(fixturePath)`, for example `re ## Commands -For development `pnpm test:regressions:dev` and `pnpm test:regressions:run --watch` in separate terminals is recommended. +For development run `pnpm test:regressions:dev`. | command | description | | :----------------------------- | :-------------------------------------------------------------------------------------------------------------------- | | `pnpm test:regressions` | Full run | -| `pnpm test:regressions:dev` | Prepares the fixtures to be able to test in watchmode | +| `pnpm test:regressions:dev` | Prepares the fixtures and runs a Vite dev server | | `pnpm test:regressions:run` | Runs the tests (requires `pnpm test:regressions:dev` or `pnpm test:regressions:build`+`pnpm test:regressions:server`) | -| `pnpm test:regressions:build` | Builds the webpack bundle for viewing the fixtures | +| `pnpm test:regressions:build` | Builds the Vite bundle for viewing fixtures | | `pnpm test:regressions:server` | Serves the fixture bundle. | diff --git a/test/regressions/TestViewer.js b/test/regressions/TestViewer.tsx similarity index 93% rename from test/regressions/TestViewer.js rename to test/regressions/TestViewer.tsx index 362139f7ff..6b6467923c 100644 --- a/test/regressions/TestViewer.js +++ b/test/regressions/TestViewer.tsx @@ -1,8 +1,7 @@ import * as React from 'react'; -import PropTypes from 'prop-types'; import { useFakeTimers } from 'sinon'; -function TestViewer(props) { +function TestViewer(props: { children: React.ReactNode }) { const { children } = props; // We're simulating `act(() => ReactDOM.render(children))` @@ -10,7 +9,7 @@ function TestViewer(props) { // React doesn't have any such guarantee outside of `act()` so we're approximating it. const [ready, setReady] = React.useState(false); React.useEffect(() => { - function handleFontsEvent(event) { + function handleFontsEvent(event: Event) { if (event.type === 'loading') { setReady(false); } else if (event.type === 'loadingdone') { @@ -78,8 +77,4 @@ function TestViewer(props) { ); } -TestViewer.propTypes = { - children: PropTypes.node.isRequired, -}; - export default TestViewer; diff --git a/test/regressions/template.html b/test/regressions/index.html similarity index 89% rename from test/regressions/template.html rename to test/regressions/index.html index 9b3b9b746b..271eef693e 100644 --- a/test/regressions/template.html +++ b/test/regressions/index.html @@ -15,5 +15,6 @@
+ diff --git a/test/regressions/index.test.js b/test/regressions/index.test.js deleted file mode 100644 index 87b62f5ad7..0000000000 --- a/test/regressions/index.test.js +++ /dev/null @@ -1,111 +0,0 @@ -const path = require('node:path'); -const fse = require('fs-extra'); -const playwright = require('playwright'); - -async function main() { - const baseUrl = 'http://localhost:5001'; - const screenshotDir = path.resolve(__dirname, './screenshots/chrome'); - - const browser = await playwright.chromium.launch({ - args: ['--font-render-hinting=none'], - // otherwise the loaded google Roboto font isn't applied - headless: false, - }); - // reuse viewport from `vrtest` - // https://github.com/nathanmarks/vrtest/blob/1185b852a6c1813cedf5d81f6d6843d9a241c1ce/src/server/runner.js#L44 - const page = await browser.newPage({ viewport: { width: 1000, height: 700 } }); - - // Block images since they slow down tests (need download). - // They're also most likely decorative for documentation demos - await page.route(/./, async (route, request) => { - const type = await request.resourceType(); - if (type === 'image') { - route.abort(); - } else { - route.continue(); - } - }); - - // Wait for all requests to finish. - // This should load shared resources such as fonts. - await page.goto(`${baseUrl}#no-dev`, { waitUntil: 'networkidle0' }); - // If we still get flaky fonts after awaiting this try `document.fonts.ready` - await page.waitForSelector('[data-webfontloader="active"]', { state: 'attached' }); - - // Simulate portrait mode for date pickers. - // See `useIsLandscape`. - await page.evaluate(() => { - Object.defineProperty(window.screen.orientation, 'angle', { - get() { - return 0; - }, - }); - }); - - let routes = await page.$$eval('#tests a', (links) => { - return links.map((link) => link.href); - }); - routes = routes.map((route) => route.replace(baseUrl, '')); - - async function renderFixture(index) { - // Use client-side routing which is much faster than full page navigation via page.goto(). - // Could become an issue with test isolation. - // If tests are flaky due to global pollution switch to page.goto(route); - // puppeteers built-in click() times out - await page.$eval(`#tests li:nth-of-type(${index + 1}) a`, (link) => { - link.click(); - }); - // Move cursor offscreen to not trigger unwanted hover effects. - page.mouse.move(0, 0); - - const testcase = await page.waitForSelector('[data-testid="testcase"]:not([aria-busy="true"])'); - - return testcase; - } - - async function takeScreenshot({ testcase, route }) { - const screenshotPath = path.resolve(screenshotDir, `.${route}.png`); - await fse.ensureDir(path.dirname(screenshotPath)); - - const explicitScreenshotTarget = await page.$('[data-testid="screenshot-target"]'); - const screenshotTarget = explicitScreenshotTarget || testcase; - - await screenshotTarget.screenshot({ path: screenshotPath, type: 'png' }); - } - - // prepare screenshots - await fse.emptyDir(screenshotDir); - - describe('visual regressions', () => { - beforeEach(async () => { - await page.evaluate(() => { - localStorage.clear(); - }); - }); - - after(async () => { - await browser.close(); - }); - - routes.forEach((route, index) => { - it(`creates screenshots of ${route}`, async function test() { - // With the playwright inspector we might want to call `page.pause` which would lead to a timeout. - if (process.env.PWDEBUG) { - this.timeout(0); - } - - const testcase = await renderFixture(index); - await takeScreenshot({ testcase, route }); - }); - }); - }); - - run(); -} - -main().catch((error) => { - // error during setup. - // Throwing lets mocha hang. - console.error(error); - process.exit(1); -}); diff --git a/test/regressions/index.test.ts b/test/regressions/index.test.ts new file mode 100644 index 0000000000..b864cc00da --- /dev/null +++ b/test/regressions/index.test.ts @@ -0,0 +1,106 @@ +import * as path from 'node:path'; +import * as fse from 'fs-extra'; +import * as playwright from 'playwright'; +import { describe, it } from 'vitest'; + +const baseUrl = 'http://localhost:5173'; +const screenshotDir = path.resolve(__dirname, './screenshots/chrome'); + +const browser = await playwright.chromium.launch({ + args: ['--font-render-hinting=none'], + // otherwise the loaded google Roboto font isn't applied + headless: false, +}); +// reuse viewport from `vrtest` +// https://github.com/nathanmarks/vrtest/blob/1185b852a6c1813cedf5d81f6d6843d9a241c1ce/src/server/runner.js#L44 +const page = await browser.newPage({ viewport: { width: 1000, height: 700 } }); + +// Block images since they slow down tests (need download). +// They're also most likely decorative for documentation demos +await page.route(/./, async (route, request) => { + const type = await request.resourceType(); + if (type === 'image') { + route.abort(); + } else { + route.continue(); + } +}); + +// Wait for all requests to finish. +// This should load shared resources such as fonts. +await page.goto(`${baseUrl}#no-dev`, { waitUntil: 'networkidle' }); + +// Simulate portrait mode for date pickers. +// See `useIsLandscape`. +await page.evaluate(() => { + Object.defineProperty(window.screen.orientation, 'angle', { + get() { + return 0; + }, + }); +}); + +let routes = await page.$$eval('#tests a', (links: HTMLAnchorElement[]) => { + return links.map((link) => link.href); +}); +routes = routes.map((route: string) => route.replace(baseUrl, '')); + +async function renderFixture(index: number) { + // Use client-side routing which is much faster than full page navigation via page.goto(). + // Could become an issue with test isolation. + // If tests are flaky due to global pollution switch to page.goto(route); + // puppeteers built-in click() times out + await page.$eval(`#tests li:nth-of-type(${index + 1}) a`, (link: HTMLAnchorElement) => { + link.click(); + }); + // Move cursor offscreen to not trigger unwanted hover effects. + page.mouse.move(0, 0); + + const testcase = page.locator('[data-testid="testcase"]:not([aria-busy="true"])'); + await testcase.waitFor(); + return testcase; +} + +async function takeScreenshot({ + testcase, + route, +}: { + testcase: playwright.Locator; + route: string; +}) { + const screenshotPath = path.resolve(screenshotDir, `.${route}.png`); + await fse.ensureDir(path.dirname(screenshotPath)); + + const explicitScreenshotTarget = await page.$('[data-testid="screenshot-target"]'); + const screenshotTarget = explicitScreenshotTarget || testcase; + + await screenshotTarget?.screenshot({ path: screenshotPath, type: 'png' }); +} + +// prepare screenshots +await fse.emptyDir(screenshotDir); + +describe('visual regressions', () => { + beforeEach(async () => { + await page.evaluate(() => { + localStorage.clear(); + }); + }); + + after(async () => { + await browser.close(); + }); + + routes.forEach((route: string, index: number) => { + it(`creates screenshots of ${route}`, async function test() { + // With the playwright inspector we might want to call `page.pause` which would lead to a timeout. + if (process.env.PWDEBUG) { + this?.timeout(0); + } + + const testcase = await renderFixture(index); + + await takeScreenshot({ testcase, route }); + }); + }); +}); diff --git a/test/regressions/index.js b/test/regressions/main.tsx similarity index 60% rename from test/regressions/index.js rename to test/regressions/main.tsx index a4d307e3f8..27e519e229 100644 --- a/test/regressions/index.js +++ b/test/regressions/main.tsx @@ -1,35 +1,41 @@ import * as React from 'react'; -import PropTypes from 'prop-types'; import * as ReactDOMClient from 'react-dom/client'; import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom'; -import webfontloader from 'webfontloader'; import TestViewer from './TestViewer'; import 'docs/src/styles.css'; +interface Fixture { + Component: React.LazyExoticComponent>; + name: string; + path: string; + suite: string; +} + // Get all the fixtures specifically written for preventing visual regressions. -const importRegressionFixtures = require.context('./fixtures', true, /\.(js|ts|tsx)$/, 'lazy'); -const regressionFixtures = []; -importRegressionFixtures - .keys() - .filter((path) => path.startsWith('./')) - .forEach((path) => { - const [suite, name] = path - .replace('./', '') - .replace(/\.\w+$/, '') - .split('/'); - regressionFixtures.push({ - path, - suite: `regression-${suite}`, - name, - Component: React.lazy(() => importRegressionFixtures(path)), - }); - }, []); +const globbedRegressionFixtures = import.meta.glob<{ default: React.ComponentType }>( + './fixtures/**/*.tsx', +); +const regressionFixtures: Fixture[] = []; + +for (const path in globbedRegressionFixtures) { + const [suite, name] = path + .replace(/\\/g, '/') + .replace('./', '') + .replace(/\.\w+$/, '') + .split('/'); + regressionFixtures.push({ + path, + suite: `regression-${suite}`, + name, + Component: React.lazy(() => globbedRegressionFixtures[path]()), + }); +} -const blacklist = []; +const blacklist: (string | RegExp)[] = []; const unusedBlacklistPatterns = new Set(blacklist); -function excludeDemoFixture(suite, name, path) { +function excludeDemoFixture(suite: string, name: string, path: string) { const blacklisted = blacklist.some((pattern) => { if (typeof pattern === 'string') { if (pattern === suite) { @@ -46,7 +52,6 @@ function excludeDemoFixture(suite, name, path) { return false; } - // assume regex if (pattern.test(suite)) { unusedBlacklistPatterns.delete(pattern); return true; @@ -67,31 +72,30 @@ function excludeDemoFixture(suite, name, path) { return false; } -// Also use some of the demos to avoid code duplication. -const importDemos = require.context( - 'docs/src/app/(public)/(content)/react', - true, - /\.tsx$/, - 'lazy', +// Also use all public demos to avoid code duplication. +const globbedDemos = import.meta.glob<{ default: React.ComponentType }>( + // technically it should be 'docs/src/app/\\(public\\)/\\(content\\)/react/**/*.tsx' but tinyglobby doesn't resolve this on Windows + 'docs/src/app/?public?/?content?/react/**/*.tsx', ); -const demoFixtures = []; - -importDemos - .keys() - .filter((path) => path.startsWith('./')) - .forEach((path) => { - const [name, ...suiteArray] = path.replace('./', '').replace('.js', '').split('/').reverse(); - const suite = `docs-${suiteArray.reverse().join('-')}`; - - if (!excludeDemoFixture(suite, name, path)) { - demoFixtures.push({ - path, - suite, - name, - Component: React.lazy(() => importDemos(path)), - }); - } - }, []); + +const demoFixtures: Fixture[] = []; + +for (const path in globbedDemos) { + const [name, ...suiteArray] = path.split('react')[1].split('/').reverse(); + const suite = `docs-${suiteArray + .filter((v) => v) + .reverse() + .join('-')}`; + + if (!excludeDemoFixture(suite, name, path)) { + demoFixtures.push({ + path, + suite, + name, + Component: React.lazy(() => globbedDemos[path]()), + }); + } +} if (unusedBlacklistPatterns.size > 0) { console.warn( @@ -103,8 +107,8 @@ if (unusedBlacklistPatterns.size > 0) { const viewerRoot = document.getElementById('test-viewer'); -function FixtureRenderer({ component: FixtureComponent }) { - const viewerReactRoot = React.useRef(null); +function FixtureRenderer({ component: FixtureComponent }: { component: React.ElementType }) { + const viewerReactRoot = React.useRef(null); React.useLayoutEffect(() => { const renderTimeout = setTimeout(() => { @@ -114,17 +118,17 @@ function FixtureRenderer({ component: FixtureComponent }) { ); - if (viewerReactRoot.current === null) { + if (viewerReactRoot.current == null && viewerRoot != null) { viewerReactRoot.current = ReactDOMClient.createRoot(viewerRoot); } - viewerReactRoot.current.render(children); + viewerReactRoot.current?.render(children); }); return () => { clearTimeout(renderTimeout); setTimeout(() => { - viewerReactRoot.current.unmount(); + viewerReactRoot.current?.unmount(); viewerReactRoot.current = null; }); }; @@ -133,11 +137,7 @@ function FixtureRenderer({ component: FixtureComponent }) { return null; } -FixtureRenderer.propTypes = { - component: PropTypes.elementType, -}; - -function App(props) { +function App(props: { fixtures: Fixture[] }) { const { fixtures } = props; function computeIsDev() { @@ -161,32 +161,19 @@ function App(props) { }; }, []); - // Using does not apply the google Roboto font in chromium headless/headfull. - const [fontState, setFontState] = React.useState('pending'); - React.useEffect(() => { - webfontloader.load({ - custom: { - families: ['Unica 77'], - urls: ['../../docs/src/styles.css'], - }, - timeout: 20000, - active: () => { - setFontState('active'); - }, - inactive: () => { - setFontState('inactive'); - }, - }); - }, []); - - const fixturePrepared = fontState !== 'pending'; - - function computePath(fixture) { + function computePath(fixture: Fixture) { return `/${fixture.suite}/${fixture.name}`; } return ( - + {fixtures.map((fixture) => { const path = computePath(fixture); @@ -199,16 +186,14 @@ function App(props) { return ( : null} + element={} /> ); })}