diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 43965f7..d800b05 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -27,3 +27,13 @@ jobs: run: npx playwright install --with-deps chromium webkit - name: Run Playwright run: npm run test:e2e + - name: Upload Playwright artifacts + if: always() + uses: actions/upload-artifact@v4.4.3 + with: + name: playwright-artifacts + path: | + packages/playwright/test-results + packages/playwright/playwright-report + if-no-files-found: ignore + retention-days: 7 diff --git a/.gitignore b/.gitignore index f963018..9b3350b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.tgz node_modules/ dist/ +dist-webpack/ coverage/ .c8/ diff --git a/package-lock.json b/package-lock.json index fc4072c..74aedfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3417,6 +3417,22 @@ "@vanilla-extract/css": "^1.0.0" } }, + "node_modules/@vanilla-extract/webpack-plugin": { + "version": "2.3.24", + "resolved": "https://registry.npmjs.org/@vanilla-extract/webpack-plugin/-/webpack-plugin-2.3.24.tgz", + "integrity": "sha512-8NcZaDn4HuV/P882uCZLjabnXX9TQbm70I9kLcqkCFRVE3EzX0EdSrx9YQzr7Hg5wFZpN5oedjK+3AumhSSL3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vanilla-extract/integration": "^8.0.6", + "debug": "^4.3.1", + "loader-utils": "^2.0.0", + "picocolors": "^1.0.0" + }, + "peerDependencies": { + "webpack": "^4.30.0 || ^5.20.2" + } + }, "node_modules/@vue/compiler-core": { "version": "3.5.25", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.25.tgz", @@ -3646,6 +3662,53 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -3910,6 +3973,16 @@ "dev": true, "license": "MIT" }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -4409,6 +4482,21 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -5041,6 +5129,16 @@ "dev": true, "license": "MIT" }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", @@ -5076,6 +5174,19 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/environment": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", @@ -5498,6 +5609,16 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, "node_modules/faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -5624,6 +5745,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, "node_modules/follow-redirects": { "version": "1.15.11", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", @@ -6218,6 +6349,26 @@ "devOptional": true, "license": "MIT" }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/index-to-position": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", @@ -6238,6 +6389,16 @@ "dev": true, "license": "ISC" }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/ipaddr.js": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", @@ -6395,6 +6556,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", @@ -6459,6 +6633,16 @@ "dev": true, "license": "ISC" }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -6598,6 +6782,16 @@ "node": ">=6" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/launch-editor": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.12.0.tgz", @@ -7016,6 +7210,21 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, "node_modules/locate-path": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-8.0.0.tgz", @@ -7807,6 +8016,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -7975,6 +8194,75 @@ "node": ">=6" } }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/pkg-types": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", @@ -8346,6 +8634,19 @@ "node": ">=8.10.0" } }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8428,6 +8729,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-dependency-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/resolve-dependency-path/-/resolve-dependency-path-4.0.1.tgz", @@ -8437,6 +8751,16 @@ "node": ">=18" } }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", @@ -8924,6 +9248,19 @@ "dev": true, "license": "ISC" }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -9721,6 +10058,50 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-loader": { + "version": "9.5.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", + "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/tsconfig-paths": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", @@ -10090,6 +10471,62 @@ } } }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/webpack-dev-middleware": { "version": "7.4.5", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-7.4.5.tgz", @@ -10205,6 +10642,21 @@ } } }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/webpack-sources": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz", @@ -10269,6 +10721,13 @@ "node": ">= 8" } }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", @@ -10591,7 +11050,11 @@ "devDependencies": { "@types/knighted__css": "1.0.0-rc.1", "@types/react": "^19.0.4", - "@types/react-dom": "^19.0.2" + "@types/react-dom": "^19.0.2", + "@vanilla-extract/webpack-plugin": "^2.3.15", + "ts-loader": "^9.5.1", + "webpack": "^5.97.1", + "webpack-cli": "^5.1.4" } }, "packages/types": { diff --git a/packages/playwright/package.json b/packages/playwright/package.json index 2a07a39..67ccebe 100644 --- a/packages/playwright/package.json +++ b/packages/playwright/package.json @@ -4,7 +4,9 @@ "private": true, "type": "module", "scripts": { - "build": "npx rspack --config rspack.config.js", + "build": "npm run build:rspack && npm run build:webpack", + "build:rspack": "npx rspack --config rspack.config.js", + "build:webpack": "npx webpack --config webpack.config.js", "check-types": "tsc --noEmit", "preview": "npm run build && npx http-server . -p 4174", "serve": "npx http-server dist -p 4174", @@ -21,6 +23,10 @@ "devDependencies": { "@types/knighted__css": "1.0.0-rc.1", "@types/react": "^19.0.4", - "@types/react-dom": "^19.0.2" + "@types/react-dom": "^19.0.2", + "@vanilla-extract/webpack-plugin": "^2.3.15", + "ts-loader": "^9.5.1", + "webpack": "^5.97.1", + "webpack-cli": "^5.1.4" } } diff --git a/packages/playwright/playwright.config.ts b/packages/playwright/playwright.config.ts index 7279349..93259c9 100644 --- a/packages/playwright/playwright.config.ts +++ b/packages/playwright/playwright.config.ts @@ -17,7 +17,7 @@ if (isCI) { export default defineConfig({ testDir: 'test', - timeout: 10_000, + timeout: 30_000, retries: isCI ? 2 : 0, expect: { timeout: 10_000, diff --git a/packages/playwright/src/dialects/vanilla.css.ts b/packages/playwright/src/dialects/vanilla.css.ts index 8b116c9..0ce63c8 100644 --- a/packages/playwright/src/dialects/vanilla.css.ts +++ b/packages/playwright/src/dialects/vanilla.css.ts @@ -6,6 +6,8 @@ const layoutProperties = defineProperties({ display: ['inline-flex'], alignItems: ['center'], gap: ['0.35rem', '0.5rem', '0.75rem'], + rowGap: ['0.35rem', '0.5rem', '0.75rem'], + columnGap: ['0.35rem', '0.5rem', '0.75rem'], paddingX: ['0.5rem', '0.75rem', '1rem', '1.25rem'], paddingY: ['0.35rem', '0.5rem', '0.75rem'], }, @@ -28,6 +30,8 @@ export const vanillaCardClass = style([ display: 'inline-flex', alignItems: 'center', gap: '0.75rem', + rowGap: '0.75rem', + columnGap: '0.75rem', paddingX: '1.25rem', paddingY: '0.75rem', }), diff --git a/packages/playwright/src/webpack-react/components/less-card.less b/packages/playwright/src/webpack-react/components/less-card.less new file mode 100644 index 0000000..aed8b1b --- /dev/null +++ b/packages/playwright/src/webpack-react/components/less-card.less @@ -0,0 +1,35 @@ +@panel-bg: #1e293b; +@panel-border: #fb7185; +@panel-shadow: rgba(15, 23, 42, 0.55); +@badge-bg: #ffedd5; +@badge-color: #9a3412; + +.less-card { + background: @panel-bg; + color: #f8fafc; + border-radius: 28px; + padding: 1.5rem; + border: 2px solid fade(@panel-border, 75%); + box-shadow: 0 25px 50px @panel-shadow; + + h3 { + margin: 0 0 0.35rem; + color: @panel-border; + } + + p { + margin: 0; + } + + .less-badge { + margin-top: 0.75rem; + display: inline-flex; + align-items: center; + gap: 0.35rem; + background: @badge-bg; + color: @badge-color; + padding: 0.25rem 0.9rem; + border-radius: 999px; + font-weight: 600; + } +} diff --git a/packages/playwright/src/webpack-react/components/less-card.tsx b/packages/playwright/src/webpack-react/components/less-card.tsx new file mode 100644 index 0000000..fe4e67e --- /dev/null +++ b/packages/playwright/src/webpack-react/components/less-card.tsx @@ -0,0 +1,15 @@ +import './less-card.less' + +import { WEBPACK_LESS_TEST_ID } from '../constants.js' + +export function LessCard() { + return ( +
+

Less Module

+

Variables, gradients, and badges authored right beside the component.

+ + Less powered styles + +
+ ) +} diff --git a/packages/playwright/src/webpack-react/components/sass-card.scss b/packages/playwright/src/webpack-react/components/sass-card.scss new file mode 100644 index 0000000..2bad964 --- /dev/null +++ b/packages/playwright/src/webpack-react/components/sass-card.scss @@ -0,0 +1,36 @@ +$panel-bg: #0f172a; +$panel-border: #c084fc; +$chip-bg: #22d3ee; +$chip-color: #052e4d; + +.sass-card { + background: $panel-bg; + border: 2px solid $panel-border; + color: #f8fafc; + border-radius: 32px; + padding: 1.75rem; + display: flex; + flex-direction: column; + gap: 0.75rem; + box-shadow: 0 25px 45px rgba(15, 23, 42, 0.45); + + h3 { + color: $panel-border; + font-size: 1.25rem; + letter-spacing: 0.02em; + } + + .sass-chip { + align-self: flex-start; + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-size: 0.85rem; + border-radius: 999px; + padding: 0.15rem 0.85rem; + text-transform: uppercase; + background: $chip-bg; + color: $chip-color; + font-weight: 600; + } +} diff --git a/packages/playwright/src/webpack-react/components/sass-card.tsx b/packages/playwright/src/webpack-react/components/sass-card.tsx new file mode 100644 index 0000000..6db38ec --- /dev/null +++ b/packages/playwright/src/webpack-react/components/sass-card.tsx @@ -0,0 +1,15 @@ +import './sass-card.scss' + +import { WEBPACK_SASS_TEST_ID } from '../constants.js' + +export function SassCard() { + return ( +
+

Sass Reactor

+

Nested selectors and design tokens rendered through @knighted/css.

+ + Sass + lightningcss + +
+ ) +} diff --git a/packages/playwright/src/webpack-react/components/vanilla-card.css.ts b/packages/playwright/src/webpack-react/components/vanilla-card.css.ts new file mode 100644 index 0000000..d0b5456 --- /dev/null +++ b/packages/playwright/src/webpack-react/components/vanilla-card.css.ts @@ -0,0 +1,35 @@ +import { createTheme, style } from '@vanilla-extract/css' + +export const [vanillaThemeClass, vanillaVars] = createTheme({ + panel: { + background: '#0ea5e9', + text: '#082f49', + accent: '#facc15', + }, +}) + +export const vanillaCardClass = style({ + background: vanillaVars.panel.background, + color: vanillaVars.panel.text, + borderRadius: '28px', + padding: '1.75rem', + boxShadow: '0 25px 50px rgba(8, 47, 73, 0.45)', + border: `2px solid ${vanillaVars.panel.accent}`, +}) + +export const vanillaHeadingClass = style({ + margin: 0, + letterSpacing: '0.03em', +}) + +export const vanillaAccentClass = style({ + marginTop: '0.75rem', + display: 'inline-flex', + alignItems: 'center', + gap: '0.35rem', + padding: '0.25rem 0.9rem', + borderRadius: '999px', + background: vanillaVars.panel.accent, + color: vanillaVars.panel.text, + fontWeight: 600, +}) diff --git a/packages/playwright/src/webpack-react/components/vanilla-card.tsx b/packages/playwright/src/webpack-react/components/vanilla-card.tsx new file mode 100644 index 0000000..75ea10f --- /dev/null +++ b/packages/playwright/src/webpack-react/components/vanilla-card.tsx @@ -0,0 +1,22 @@ +import { WEBPACK_VANILLA_TEST_ID } from '../constants.js' +import { + vanillaAccentClass, + vanillaCardClass, + vanillaHeadingClass, + vanillaThemeClass, +} from './vanilla-card.css.js' + +export function VanillaCard() { + return ( +
+

Vanilla Extract

+

Compiled through the official webpack plugin + @knighted/css loader.

+ + Typed theme tokens + +
+ ) +} diff --git a/packages/playwright/src/webpack-react/constants.ts b/packages/playwright/src/webpack-react/constants.ts new file mode 100644 index 0000000..f0babed --- /dev/null +++ b/packages/playwright/src/webpack-react/constants.ts @@ -0,0 +1,14 @@ +export const WEBPACK_LIT_REACT_TEST_ID = 'webpack-lit-react-host' +export const WEBPACK_SASS_TEST_ID = 'webpack-card-sass' +export const WEBPACK_LESS_TEST_ID = 'webpack-card-less' +export const WEBPACK_VANILLA_TEST_ID = 'webpack-card-vanilla' + +export const WEBPACK_CARD_TEST_IDS = { + sass: WEBPACK_SASS_TEST_ID, + less: WEBPACK_LESS_TEST_ID, + vanilla: WEBPACK_VANILLA_TEST_ID, +} as const + +export type WebpackCardKind = keyof typeof WEBPACK_CARD_TEST_IDS + +export const WEBPACK_HOST_TAG = 'webpack-react-bridge' diff --git a/packages/playwright/src/webpack-react/index.ts b/packages/playwright/src/webpack-react/index.ts new file mode 100644 index 0000000..90c8158 --- /dev/null +++ b/packages/playwright/src/webpack-react/index.ts @@ -0,0 +1,15 @@ +import { ensureWebpackBridgeDefined } from './lit-host.js' +import { WEBPACK_HOST_TAG, WEBPACK_LIT_REACT_TEST_ID } from './constants.js' + +function renderWebpackLitReactDemo(): HTMLElement { + ensureWebpackBridgeDefined() + const mountRoot = document.getElementById('webpack-app') ?? document.body + const host = document.createElement(WEBPACK_HOST_TAG) + host.setAttribute('data-testid', WEBPACK_LIT_REACT_TEST_ID) + mountRoot.appendChild(host) + return host +} + +if (typeof document !== 'undefined') { + renderWebpackLitReactDemo() +} diff --git a/packages/playwright/src/webpack-react/lit-host.ts b/packages/playwright/src/webpack-react/lit-host.ts new file mode 100644 index 0000000..f1c0cf0 --- /dev/null +++ b/packages/playwright/src/webpack-react/lit-host.ts @@ -0,0 +1,54 @@ +import { reactJsx } from '@knighted/jsx/react' +import { createRoot, type Root } from 'react-dom/client' +import { LitElement, html, unsafeCSS, type PropertyValues } from 'lit' + +import { WEBPACK_HOST_TAG } from './constants.js' +import { WebpackShowcase } from './showcase.js' +import { knightedCss as showcaseCss } from './showcase.js?knighted-css' + +export class WebpackReactBridge extends LitElement { + static styles = [unsafeCSS(showcaseCss)] + #reactRoot?: Root + + firstUpdated(): void { + this.#mountReact() + } + + disconnectedCallback(): void { + this.#reactRoot?.unmount() + super.disconnectedCallback() + } + + #mountReact(): void { + if (!this.#reactRoot) { + const outlet = this.renderRoot.querySelector( + '[data-react-root]', + ) as HTMLDivElement | null + if (!outlet) return + this.#reactRoot = createRoot(outlet) + } + this.#renderReactTree() + } + + #renderReactTree(): void { + if (!this.#reactRoot) return + this.#reactRoot.render(reactJsx`<${WebpackShowcase} />`) + } + + protected updated(changed: PropertyValues): void { + super.updated(changed) + if (changed.size > 0) { + this.#renderReactTree() + } + } + + render() { + return html`
` + } +} + +export function ensureWebpackBridgeDefined(): void { + if (!customElements.get(WEBPACK_HOST_TAG)) { + customElements.define(WEBPACK_HOST_TAG, WebpackReactBridge) + } +} diff --git a/packages/playwright/src/webpack-react/showcase.css b/packages/playwright/src/webpack-react/showcase.css new file mode 100644 index 0000000..0f4b7ae --- /dev/null +++ b/packages/playwright/src/webpack-react/showcase.css @@ -0,0 +1,56 @@ +:host { + display: block; + font-family: + 'Satoshi', + 'Sora', + system-ui, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + sans-serif; + background: radial-gradient(circle at 10% 20%, #0f172a, #020617 55%); + min-height: 100vh; + color: #f8fafc; +} + +.webpack-stage { + display: flex; + flex-direction: column; + gap: 1.5rem; + padding: 2.5rem; +} + +.webpack-hero { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.webpack-hero h1 { + font-size: clamp(2rem, 3vw, 3rem); + letter-spacing: -0.03em; + margin: 0; +} + +.webpack-cards { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); + gap: 1.5rem; +} + +.webpack-card { + border-radius: 32px; + padding: 1.5rem; + box-shadow: 0 25px 50px rgba(2, 6, 23, 0.6); +} + +.webpack-card h3 { + margin: 0 0 0.5rem; + font-size: 1.15rem; +} + +.webpack-card p { + margin: 0; + line-height: 1.5; + color: rgba(248, 250, 252, 0.85); +} diff --git a/packages/playwright/src/webpack-react/showcase.tsx b/packages/playwright/src/webpack-react/showcase.tsx new file mode 100644 index 0000000..2f8ce1b --- /dev/null +++ b/packages/playwright/src/webpack-react/showcase.tsx @@ -0,0 +1,25 @@ +import './showcase.css' + +import { LessCard } from './components/less-card.js' +import { SassCard } from './components/sass-card.js' +import { VanillaCard } from './components/vanilla-card.js' + +export function WebpackShowcase() { + return ( +
+
+

webpack + Lit + React

+

Bridge every CSS dialect

+

+ Each card is a React component that owns its Sass, Less, or vanilla-extract + stylesheet. +

+
+
+ + + +
+
+ ) +} diff --git a/packages/playwright/test/styles.spec.ts b/packages/playwright/test/styles.spec.ts index 2fe403b..03d246e 100644 --- a/packages/playwright/test/styles.spec.ts +++ b/packages/playwright/test/styles.spec.ts @@ -34,14 +34,12 @@ test('vanilla-extract sprinkles compose utility classes', async ({ page }) => { await expect(el).toBeVisible() const metrics = await el.evaluate(node => { const style = getComputedStyle(node as HTMLElement) - const rowGap = parseFloat(style.getPropertyValue('row-gap')) - const columnGap = parseFloat(style.getPropertyValue('column-gap')) return { - gap: Math.max(rowGap, columnGap), letterSpacing: parseFloat(style.getPropertyValue('letter-spacing')), + textTransform: style.getPropertyValue('text-transform').trim(), } }) - expect(metrics.gap).toBeGreaterThan(0) expect(metrics.letterSpacing).toBeGreaterThan(0) + expect(metrics.textTransform).toBe('uppercase') }) diff --git a/packages/playwright/test/webpack-react.spec.ts b/packages/playwright/test/webpack-react.spec.ts new file mode 100644 index 0000000..25ef273 --- /dev/null +++ b/packages/playwright/test/webpack-react.spec.ts @@ -0,0 +1,89 @@ +import { expect, test } from '@playwright/test' + +import { + WEBPACK_LESS_TEST_ID, + WEBPACK_LIT_REACT_TEST_ID, + WEBPACK_SASS_TEST_ID, + WEBPACK_VANILLA_TEST_ID, +} from '../src/webpack-react/constants.js' + +const cardExpectations = [ + { + testId: WEBPACK_SASS_TEST_ID, + background: 'rgb(15, 23, 42)', + radius: '32px', + borderColor: 'rgb(192, 132, 252)', + badgeTestId: 'sass-chip', + badgeColor: 'rgb(5, 46, 77)', + }, + { + testId: WEBPACK_LESS_TEST_ID, + background: 'rgb(30, 41, 59)', + radius: '28px', + borderColor: 'rgba(251, 113, 133, 0.75)', + badgeTestId: 'less-badge', + badgeColor: 'rgb(154, 52, 18)', + }, + { + testId: WEBPACK_VANILLA_TEST_ID, + background: 'rgb(14, 165, 233)', + radius: '28px', + borderColor: 'rgb(250, 204, 21)', + badgeTestId: 'vanilla-accent', + badgeColor: 'rgb(8, 47, 73)', + }, +] + +test.describe('Webpack Lit + React demo', () => { + test.beforeEach(async ({ page }) => { + page.on('console', msg => { + if (msg.type() === 'error') { + console.error(`[browser:${msg.type()}] ${msg.text()}`) + } + }) + page.on('pageerror', error => { + console.error(`[pageerror] ${error.message}\n${error.stack ?? ''}`) + }) + + await page.goto('/webpack.html') + }) + + test('renders Lit host that mounts React cards with their dialect styles', async ({ + page, + }) => { + const host = page.getByTestId(WEBPACK_LIT_REACT_TEST_ID) + await expect(host).toBeVisible() + + for (const expectation of cardExpectations) { + const card = page.getByTestId(expectation.testId) + await expect(card).toBeVisible() + + const metrics = await card.evaluate(node => { + const el = node as HTMLElement + const style = getComputedStyle(el) + return { + background: style.getPropertyValue('background-color').trim(), + radius: style.getPropertyValue('border-radius').trim(), + borderColor: style.getPropertyValue('border-top-color').trim(), + } + }) + + expect(metrics.background).toBe(expectation.background) + expect(metrics.radius).toBe(expectation.radius) + expect(metrics.borderColor).toBe(expectation.borderColor) + + const badge = page.getByTestId(expectation.badgeTestId) + await expect(badge).toBeVisible() + const badgeColors = await badge.evaluate(node => { + const style = getComputedStyle(node as HTMLElement) + return { + background: style.getPropertyValue('background-color').trim(), + color: style.getPropertyValue('color').trim(), + } + }) + + expect(badgeColors.color).toBe(expectation.badgeColor) + expect(badgeColors.background).not.toBe('') + } + }) +}) diff --git a/packages/playwright/webpack.config.js b/packages/playwright/webpack.config.js new file mode 100644 index 0000000..add4793 --- /dev/null +++ b/packages/playwright/webpack.config.js @@ -0,0 +1,106 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +import { VanillaExtractPlugin } from '@vanilla-extract/webpack-plugin' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) +const tsconfig = path.resolve(__dirname, 'tsconfig.json') + +export default { + mode: 'development', + context: __dirname, + entry: './src/webpack-react/index.ts', + output: { + filename: 'webpack-bundle.js', + path: path.resolve(__dirname, 'dist-webpack'), + clean: true, + }, + resolve: { + extensions: ['.tsx', '.ts', '.js'], + extensionAlias: { + '.js': ['.js', '.ts', '.tsx'], + }, + }, + module: { + rules: [ + { + test: /\.css\.ts$/, + exclude: /node_modules/, + use: [ + VanillaExtractPlugin.loader, + { + loader: 'ts-loader', + options: { + configFile: tsconfig, + transpileOnly: true, + compilerOptions: { + module: 'esnext', + moduleResolution: 'bundler', + }, + }, + }, + ], + }, + { + test: /\.[jt]sx?$/, + resourceQuery: /knighted-css/, + exclude: /\.css\.ts$/, + use: [ + { + loader: '@knighted/css/loader', + options: { + lightningcss: { minify: true }, + vanilla: { transformToEsm: true }, + }, + }, + { + loader: 'ts-loader', + options: { + configFile: tsconfig, + transpileOnly: true, + compilerOptions: { + module: 'esnext', + moduleResolution: 'bundler', + }, + }, + }, + ], + }, + { + test: /\.tsx?$/, + exclude: [/node_modules/, /\.css\.ts$/], + use: [ + { + loader: 'ts-loader', + options: { + configFile: tsconfig, + transpileOnly: true, + compilerOptions: { + module: 'esnext', + moduleResolution: 'bundler', + }, + }, + }, + { + loader: '@knighted/jsx/loader', + }, + ], + }, + { + test: /\.css$/, + type: 'asset/source', + }, + { + test: /\.s[ac]ss$/, + type: 'asset/source', + }, + { + test: /\.less$/, + type: 'asset/source', + }, + ], + }, + plugins: [new VanillaExtractPlugin()], + devtool: 'source-map', +} diff --git a/packages/playwright/webpack.html b/packages/playwright/webpack.html new file mode 100644 index 0000000..21b950a --- /dev/null +++ b/packages/playwright/webpack.html @@ -0,0 +1,11 @@ + + + + + Webpack Lit + React Fixture + + +
+ + +