diff --git a/package-lock.json b/package-lock.json index b7730315..84a1c3ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2038,6 +2038,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=12" } @@ -2198,6 +2199,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -4542,6 +4544,42 @@ "dev": true, "optional": true }, + "node_modules/@rollup/plugin-replace": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", + "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@rollup/plugin-replace/node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, "node_modules/@rollup/pluginutils": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", @@ -8012,6 +8050,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=12" } @@ -8028,6 +8067,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=12" } @@ -8044,6 +8084,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=12" } @@ -8060,6 +8101,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=12" } @@ -8076,6 +8118,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -8092,6 +8135,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -8108,6 +8152,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -8124,6 +8169,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -8140,6 +8186,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -8156,6 +8203,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -8172,6 +8220,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -8188,6 +8237,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -8204,6 +8254,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -8220,6 +8271,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=12" } @@ -8236,6 +8288,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -8252,6 +8305,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=12" } @@ -8284,6 +8338,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=12" } @@ -8300,6 +8355,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=12" } @@ -8316,6 +8372,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=12" } @@ -8332,6 +8389,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=12" } @@ -17707,7 +17765,7 @@ }, "packages/isomorphic-eventsource": { "name": "@tonconnect/isomorphic-eventsource", - "version": "0.0.1", + "version": "0.0.2", "license": "Apache-2.0", "dependencies": { "eventsource": "^2.0.2" @@ -17718,7 +17776,7 @@ }, "packages/isomorphic-fetch": { "name": "@tonconnect/isomorphic-fetch", - "version": "0.0.2", + "version": "0.0.3", "license": "Apache-2.0", "dependencies": { "node-fetch": "^2.6.9" @@ -17727,7 +17785,7 @@ }, "packages/protocol": { "name": "@tonconnect/protocol", - "version": "2.2.5", + "version": "2.2.6", "license": "Apache-2.0", "dependencies": { "tweetnacl": "^1.0.3", @@ -18044,14 +18102,15 @@ }, "packages/sdk": { "name": "@tonconnect/sdk", - "version": "3.0.0-beta.1", + "version": "3.0.3-beta.0", "license": "Apache-2.0", "dependencies": { - "@tonconnect/isomorphic-eventsource": "^0.0.1", - "@tonconnect/isomorphic-fetch": "^0.0.2", - "@tonconnect/protocol": "^2.2.5" + "@tonconnect/isomorphic-eventsource": "^0.0.2", + "@tonconnect/isomorphic-fetch": "^0.0.3", + "@tonconnect/protocol": "^2.2.6" }, "devDependencies": { + "@rollup/plugin-replace": "5.0.5", "@rollup/plugin-typescript": "^11.0.0", "rollup": "^3.18.0", "ts-loader": "^9.4.1", @@ -18547,16 +18606,17 @@ }, "packages/ui": { "name": "@tonconnect/ui", - "version": "2.0.0-beta.4", + "version": "2.0.3-beta.2", "license": "Apache-2.0", "dependencies": { - "@tonconnect/sdk": "^3.0.0-beta.1", + "@tonconnect/sdk": "3.0.3-beta.0", "classnames": "^2.3.2", "deepmerge": "^4.2.2", "ua-parser-js": "^1.0.35" }, "devDependencies": { "@floating-ui/dom": "^1.0.12", + "@rollup/plugin-replace": "5.0.5", "@solid-primitives/i18n": "^1.1.2", "@types/node": "^18.11.17", "@types/ua-parser-js": "^0.7.36", @@ -18578,10 +18638,10 @@ }, "packages/ui-react": { "name": "@tonconnect/ui-react", - "version": "2.0.0-beta.4", + "version": "2.0.3-beta.2", "license": "Apache-2.0", "dependencies": { - "@tonconnect/ui": "^2.0.0-beta.4" + "@tonconnect/ui": "2.0.3-beta.2" }, "devDependencies": { "@types/react": "^18.0.26", @@ -20473,7 +20533,8 @@ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.10.tgz", "integrity": "sha512-FNONeQPy/ox+5NBkcSbYJxoXj9GWu8gVGJTVmUyoOCKQFDTrHVKgNSzChdNt0I8Aj/iKcsDf2r9BFwv+FSNUXg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/android-arm64": { "version": "0.16.10", @@ -20543,7 +20604,8 @@ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.10.tgz", "integrity": "sha512-w0Ou3Z83LOYEkwaui2M8VwIp+nLi/NA60lBLMvaJ+vXVMcsARYdEzLNE7RSm4+lSg4zq4d7fAVuzk7PNQ5JFgg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "@esbuild/linux-mips64el": { "version": "0.16.10", @@ -22348,6 +22410,33 @@ "dev": true, "optional": true }, + "@rollup/plugin-replace": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", + "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + } + } + }, "@rollup/pluginutils": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", @@ -22841,10 +22930,11 @@ "@tonconnect/sdk": { "version": "file:packages/sdk", "requires": { + "@rollup/plugin-replace": "5.0.5", "@rollup/plugin-typescript": "^11.0.0", - "@tonconnect/isomorphic-eventsource": "^0.0.1", - "@tonconnect/isomorphic-fetch": "^0.0.2", - "@tonconnect/protocol": "^2.2.5", + "@tonconnect/isomorphic-eventsource": "^0.0.2", + "@tonconnect/isomorphic-fetch": "^0.0.3", + "@tonconnect/protocol": "^2.2.6", "rollup": "^3.18.0", "ts-loader": "^9.4.1", "ttypescript": "^1.5.13", @@ -23079,8 +23169,9 @@ "version": "file:packages/ui", "requires": { "@floating-ui/dom": "^1.0.12", + "@rollup/plugin-replace": "5.0.5", "@solid-primitives/i18n": "^1.1.2", - "@tonconnect/sdk": "^3.0.0-beta.1", + "@tonconnect/sdk": "3.0.3-beta.0", "@types/node": "^18.11.17", "@types/ua-parser-js": "^0.7.36", "classnames": "^2.3.2", @@ -23251,7 +23342,7 @@ "@tonconnect/ui-react": { "version": "file:packages/ui-react", "requires": { - "@tonconnect/ui": "^2.0.0-beta.4", + "@tonconnect/ui": "2.0.3-beta.2", "@types/react": "^18.0.26", "@types/react-dom": "^18.0.9", "@vitejs/plugin-react": "^3.0.0", @@ -25808,112 +25899,128 @@ "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.10.tgz", "integrity": "sha512-UI7krF8OYO1N7JYTgLT9ML5j4+45ra3amLZKx7LO3lmLt1Ibn8t3aZbX5Pu4BjWiqDuJ3m/hsvhPhK/5Y/YpnA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-android-arm64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.10.tgz", "integrity": "sha512-EOt55D6xBk5O05AK8brXUbZmoFj4chM8u3riGflLa6ziEoVvNjRdD7Cnp82NHQGfSHgYR06XsPI8/sMuA/cUwg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-darwin-64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.10.tgz", "integrity": "sha512-hbDJugTicqIm+WKZgp208d7FcXcaK8j2c0l+fqSJ3d2AzQAfjEYDRM3Z2oMeqSJ9uFxyj/muSACLdix7oTstRA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-darwin-arm64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.10.tgz", "integrity": "sha512-M1t5+Kj4IgSbYmunf2BB6EKLkWUq+XlqaFRiGOk8bmBapu9bCDrxjf4kUnWn59Dka3I27EiuHBKd1rSO4osLFQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-freebsd-64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.10.tgz", "integrity": "sha512-KMBFMa7C8oc97nqDdoZwtDBX7gfpolkk6Bcmj6YFMrtCMVgoU/x2DI1p74DmYl7CSS6Ppa3xgemrLrr5IjIn0w==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-freebsd-arm64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.10.tgz", "integrity": "sha512-m2KNbuCX13yQqLlbSojFMHpewbn8wW5uDS6DxRpmaZKzyq8Dbsku6hHvh2U+BcLwWY4mpgXzFUoENEf7IcioGg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-linux-32": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.10.tgz", "integrity": "sha512-guXrwSYFAvNkuQ39FNeV4sNkNms1bLlA5vF1H0cazZBOLdLFIny6BhT+TUbK/hdByMQhtWQ5jI9VAmPKbVPu1w==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-linux-64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.10.tgz", "integrity": "sha512-jd8XfaSJeucMpD63YNMO1JCrdJhckHWcMv6O233bL4l6ogQKQOxBYSRP/XLWP+6kVTu0obXovuckJDcA0DKtQA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-linux-arm": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.10.tgz", "integrity": "sha512-6N8vThLL/Lysy9y4Ex8XoLQAlbZKUyExCWyayGi2KgTBelKpPgj6RZnUaKri0dHNPGgReJriKVU6+KDGQwn10A==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-linux-arm64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.10.tgz", "integrity": "sha512-GByBi4fgkvZFTHFDYNftu1DQ1GzR23jws0oWyCfhnI7eMOe+wgwWrc78dbNk709Ivdr/evefm2PJiUBMiusS1A==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-linux-mips64le": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.10.tgz", "integrity": "sha512-BxP+LbaGVGIdQNJUNF7qpYjEGWb0YyHVSKqYKrn+pTwH/SiHUxFyJYSP3pqkku61olQiSBnSmWZ+YUpj78Tw7Q==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-linux-ppc64le": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.10.tgz", "integrity": "sha512-LoSQCd6498PmninNgqd/BR7z3Bsk/mabImBWuQ4wQgmQEeanzWd5BQU2aNi9mBURCLgyheuZS6Xhrw5luw3OkQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-linux-riscv64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.10.tgz", "integrity": "sha512-Lrl9Cr2YROvPV4wmZ1/g48httE8z/5SCiXIyebiB5N8VT7pX3t6meI7TQVHw/wQpqP/AF4SksDuFImPTM7Z32Q==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-linux-s390x": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.10.tgz", "integrity": "sha512-ReP+6q3eLVVP2lpRrvl5EodKX7EZ1bS1/z5j6hsluAlZP5aHhk6ghT6Cq3IANvvDdscMMCB4QEbI+AjtvoOFpA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-netbsd-64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.10.tgz", "integrity": "sha512-iGDYtJCMCqldMskQ4eIV+QSS/CuT7xyy9i2/FjpKvxAuCzrESZXiA1L64YNj6/afuzfBe9i8m/uDkFHy257hTw==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-openbsd-64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.10.tgz", "integrity": "sha512-ftMMIwHWrnrYnvuJQRJs/Smlcb28F9ICGde/P3FUTCgDDM0N7WA0o9uOR38f5Xe2/OhNCgkjNeb7QeaE3cyWkQ==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-plugin-solid": { "version": "0.4.2", @@ -25932,28 +26039,32 @@ "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.10.tgz", "integrity": "sha512-mf7hBL9Uo2gcy2r3rUFMjVpTaGpFJJE5QTDDqUFf1632FxteYANffDZmKbqX0PfeQ2XjUDE604IcE7OJeoHiyg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-windows-32": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.10.tgz", "integrity": "sha512-ttFVo+Cg8b5+qHmZHbEc8Vl17kCleHhLzgT8X04y8zudEApo0PxPg9Mz8Z2cKH1bCYlve1XL8LkyXGFjtUYeGg==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-windows-64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.10.tgz", "integrity": "sha512-2H0gdsyHi5x+8lbng3hLbxDWR7mKHWh5BXZGKVG830KUmXOOWFE2YKJ4tHRkejRduOGDrBvHBriYsGtmTv3ntA==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "esbuild-windows-arm64": { "version": "0.15.10", "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.10.tgz", "integrity": "sha512-S+th4F+F8VLsHLR0zrUcG+Et4hx0RKgK1eyHc08kztmLOES8BWwMiaGdoW9hiXuzznXQ0I/Fg904MNbr11Nktw==", "dev": true, - "optional": true + "optional": true, + "peer": true }, "escalade": { "version": "3.1.1", diff --git a/packages/ui/package.json b/packages/ui/package.json index 24f50e6c..2ff71530 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -47,30 +47,31 @@ } }, "dependencies": { + "@tonconnect/sdk": "3.0.3-beta.0", "classnames": "^2.3.2", "deepmerge": "^4.2.2", - "@tonconnect/sdk": "3.0.3-beta.0", "ua-parser-js": "^1.0.35" }, "devDependencies": { - "solid-js": "^1.5.1", - "solid-styled-components": "^0.28.5", - "solid-transition-group": "^0.0.12", - "@solid-primitives/i18n": "^1.1.2", "@floating-ui/dom": "^1.0.12", - "solid-floating-ui": "^0.2.0", + "@rollup/plugin-replace": "5.0.5", + "@solid-primitives/i18n": "^1.1.2", + "@types/node": "^18.11.17", + "@types/ua-parser-js": "^0.7.36", + "csstype": "^3.1.1", + "eslint-plugin-solid": "^0.7.3", "is-plain-object": "^5.0.0", "qrcode-generator": "^1.4.4", - "typescript": "^4.8.2", - "eslint-plugin-solid": "^0.7.3", - "vite": "^3.0.9", - "vite-plugin-solid": "^2.3.0", - "csstype": "^3.1.1", - "@types/node": "^18.11.17", - "rollup-plugin-dts": "^5.0.0", "rollup": "^3.8.0", + "rollup-plugin-dts": "^5.0.0", "solid-devtools": "^0.24.7", - "@types/ua-parser-js": "^0.7.36" + "solid-floating-ui": "^0.2.0", + "solid-js": "^1.5.1", + "solid-styled-components": "^0.28.5", + "solid-transition-group": "^0.0.12", + "typescript": "^4.8.2", + "vite": "^3.0.9", + "vite-plugin-solid": "^2.3.0" }, "typedoc": { "entryPoint": "./src/library.ts" diff --git a/packages/ui/src/app/utils/web-api.ts b/packages/ui/src/app/utils/web-api.ts index 7f4547a9..2d620a35 100644 --- a/packages/ui/src/app/utils/web-api.ts +++ b/packages/ui/src/app/utils/web-api.ts @@ -97,6 +97,16 @@ export async function createMacrotask(callback: () => void): Promise { callback(); } +/** + * Create a macrotask using `requestAnimationFrame()` to ensure that any pending microtasks, + * such as asynchronous operations from other developers and browser APIs, are executed before. + * @param callback + */ +export async function createMacrotaskAsync(callback: () => Promise): Promise { + await new Promise(resolve => requestAnimationFrame(resolve)); + return callback(); +} + /** * Preload images after page load to improve UX and Web Vitals metrics without affecting initial page load performance. */ diff --git a/packages/ui/src/app/views/modals/wallets-modal/mobile-connection-modal/index.tsx b/packages/ui/src/app/views/modals/wallets-modal/mobile-connection-modal/index.tsx index 18faa9ba..a071dc36 100644 --- a/packages/ui/src/app/views/modals/wallets-modal/mobile-connection-modal/index.tsx +++ b/packages/ui/src/app/views/modals/wallets-modal/mobile-connection-modal/index.tsx @@ -16,12 +16,11 @@ import { import { ConnectorContext } from 'src/app/state/connector.context'; import { Button, H3, QRIcon, RetryIcon } from 'src/app/components'; import { appState } from 'src/app/state/app.state'; -import { openLinkBlank } from 'src/app/utils/web-api'; import { setLastSelectedWalletInfo } from 'src/app/state/modals-state'; import { useTheme } from 'solid-styled-components'; import { MobileConnectionQR } from 'src/app/views/modals/wallets-modal/mobile-connection-modal/mobile-connection-qr'; import { Translation } from 'src/app/components/typography/Translation'; -import { addReturnStrategy, redirectToTelegram, redirectToWallet } from 'src/app/utils/url-strategy-helpers'; +import { redirectToTelegram, redirectToWallet } from 'src/app/utils/url-strategy-helpers'; export interface MobileConnectionProps { additionalRequest?: ConnectAdditionalRequest; diff --git a/packages/ui/src/app/views/modals/wallets-modal/wallets-modal.tsx b/packages/ui/src/app/views/modals/wallets-modal/wallets-modal.tsx index 7153975c..466b38e1 100644 --- a/packages/ui/src/app/views/modals/wallets-modal/wallets-modal.tsx +++ b/packages/ui/src/app/views/modals/wallets-modal/wallets-modal.tsx @@ -1,6 +1,7 @@ import { ConnectAdditionalRequest, isWalletInfoCurrentlyInjected, + Wallet, WalletInfo, WalletInfoRemote } from '@tonconnect/sdk'; @@ -17,7 +18,7 @@ import { useContext } from 'solid-js'; import { ConnectorContext } from 'src/app/state/connector.context'; -import { getWalletsModalIsOpened, setWalletsModalState } from 'src/app/state/modals-state'; +import { getWalletsModalIsOpened } from 'src/app/state/modals-state'; import { H1Styled, LoaderContainerStyled, StyledModal } from './style'; import { TonConnectUiContext } from 'src/app/state/ton-connect-ui.context'; import { useI18n } from '@solid-primitives/i18n'; @@ -43,6 +44,9 @@ export const WalletsModal: Component = () => { createEffect(() => { if (getWalletsModalIsOpened()) { + setSelectedWalletInfo(null); + setSelectedTab('universal'); + setInfoTab(false); updateIsMobile(); } }); @@ -107,7 +111,7 @@ export const WalletsModal: Component = () => { tonConnectUI!.closeModal(closeReason); }; - const unsubscribe = connector.onStatusChange(wallet => { + const unsubscribe = connector.onStatusChange((wallet: Wallet | null) => { if (wallet) { onClose('wallet-selected'); } diff --git a/packages/ui/src/constants/version.ts b/packages/ui/src/constants/version.ts new file mode 100644 index 00000000..a6cbee67 --- /dev/null +++ b/packages/ui/src/constants/version.ts @@ -0,0 +1,3 @@ +declare const TON_CONNECT_UI_VERSION: string; + +export const tonConnectUiVersion: string = TON_CONNECT_UI_VERSION; diff --git a/packages/ui/src/ton-connect-ui.ts b/packages/ui/src/ton-connect-ui.ts index 6c22817d..d10eff5f 100644 --- a/packages/ui/src/ton-connect-ui.ts +++ b/packages/ui/src/ton-connect-ui.ts @@ -18,7 +18,12 @@ import { widgetController } from 'src/app/widget-controller'; import { TonConnectUIError } from 'src/errors/ton-connect-ui.error'; import { TonConnectUiCreateOptions } from 'src/models/ton-connect-ui-create-options'; import { PreferredWalletStorage, WalletInfoStorage } from 'src/storage'; -import { getSystemTheme, preloadImages, subscribeToThemeChange } from 'src/app/utils/web-api'; +import { + createMacrotask, createMacrotaskAsync, + getSystemTheme, + preloadImages, + subscribeToThemeChange +} from 'src/app/utils/web-api'; import { TonConnectUiOptions } from 'src/models/ton-connect-ui-options'; import { setBorderRadius, setColors, setTheme } from 'src/app/state/theme-state'; import { mergeOptions } from 'src/app/utils/options'; @@ -38,6 +43,7 @@ import { redirectToTelegram, redirectToWallet } from 'src/app/utils/url-strategy import { SingleWalletModalManager } from 'src/managers/single-wallet-modal-manager'; import { SingleWalletModal, SingleWalletModalState } from 'src/models/single-wallet-modal'; import { TonConnectUITracker } from 'src/tracker/ton-connect-ui-tracker'; +import { tonConnectUiVersion } from 'src/constants/version'; export class TonConnectUI { public static getWallets(): Promise { @@ -197,7 +203,10 @@ export class TonConnectUI { ); } - this.tracker = new TonConnectUITracker(options?.eventDispatcher); + this.tracker = new TonConnectUITracker({ + eventDispatcher: options?.eventDispatcher, + tonConnectUiVersion: tonConnectUiVersion + }); this.modal = new WalletsModalManager({ connector: this.connector, @@ -232,8 +241,8 @@ export class TonConnectUI { this.subscribeToWalletChange(); if (options?.restoreConnection !== false) { - this.tracker.trackConnectionRestoringStarted(); - this.connectionRestored = new Promise(async resolve => { + this.connectionRestored = createMacrotaskAsync(async () => { + this.tracker.trackConnectionRestoringStarted(); await this.connector.restoreConnection(); if (!this.connector.connected) { @@ -243,7 +252,7 @@ export class TonConnectUI { this.tracker.trackConnectionRestoringCompleted(this.wallet); } - resolve(this.connector.connected); + return this.connector.connected; }); } @@ -654,7 +663,11 @@ export class TonConnectUI { const { transaction, signal } = options; if (signal.aborted) { - this.tracker.trackTransactionSigningFailed(this.wallet, transaction, 'Transaction was cancelled'); + this.tracker.trackTransactionSigningFailed( + this.wallet, + transaction, + 'Transaction was cancelled' + ); return reject(new TonConnectUIError('Transaction was not sent')); } @@ -667,9 +680,13 @@ export class TonConnectUI { const onErrorsHandler = (reason: TonConnectError): void => { reject(reason); }; - + const onCanceledHandler = (): void => { - this.tracker.trackTransactionSigningFailed(this.wallet, transaction, 'Transaction was cancelled'); + this.tracker.trackTransactionSigningFailed( + this.wallet, + transaction, + 'Transaction was cancelled' + ); reject(new TonConnectUIError('Transaction was not sent')); }; @@ -679,11 +696,11 @@ export class TonConnectUI { .sendTransaction(transaction, { onRequestSent: onRequestSent, signal: signal }) .then(result => { signal.removeEventListener('abort', onCanceledHandler); - return onTransactionHandler(result) + return onTransactionHandler(result); }) .catch(reason => { signal.removeEventListener('abort', onCanceledHandler); - return onErrorsHandler(reason) + return onErrorsHandler(reason); }); }); } diff --git a/packages/ui/src/tracker/ton-connect-ui-tracker.ts b/packages/ui/src/tracker/ton-connect-ui-tracker.ts index e7e5099d..71c79210 100644 --- a/packages/ui/src/tracker/ton-connect-ui-tracker.ts +++ b/packages/ui/src/tracker/ton-connect-ui-tracker.ts @@ -6,12 +6,33 @@ import { createConnectionRestoringStartedEvent, createConnectionStartedEvent, createDisconnectionEvent, + createRequestVersionEvent, + createResponseVersionEvent, createTransactionSentForSignatureEvent, createTransactionSignedEvent, createTransactionSigningFailedEvent, UserActionEvent } from './types'; -import { BrowserEventDispatcher, EventDispatcher } from '@tonconnect/sdk'; +import { + BrowserEventDispatcher, + createVersionInfo, + EventDispatcher, + ResponseVersionEvent, + Version, + WithoutVersion +} from '@tonconnect/sdk'; + +export type TonConnectUITrackerOptions = { + /** + * Event dispatcher to track user actions. + * @default new BrowserEventDispatcher() + */ + eventDispatcher?: EventDispatcher | null; + /** + * TonConnect UI version. + */ + tonConnectUiVersion: string; +}; /** * Tracker for TonConnectUI user actions, such as transaction signing, connection, etc. @@ -44,14 +65,84 @@ export class TonConnectUITracker { */ private readonly eventPrefix = 'ton-connect-ui-'; + /** + * TonConnect UI version. + */ + private readonly tonConnectUiVersion: string; + + /** + * TonConnect SDK version. + */ + private tonConnectSdkVersion: string | null = null; + + /** + * Version of the library. + */ + get version(): Version { + return createVersionInfo({ + ton_connect_sdk_lib: this.tonConnectSdkVersion, + ton_connect_ui_lib: this.tonConnectUiVersion + }); + } + /** * Event dispatcher to track user actions. By default, it uses `window.dispatchEvent` for browser environment. * @private */ private readonly eventDispatcher: EventDispatcher; - constructor(eventDispatcher?: EventDispatcher | null) { - this.eventDispatcher = eventDispatcher ?? new BrowserEventDispatcher(); + constructor(options: TonConnectUITrackerOptions) { + this.eventDispatcher = options?.eventDispatcher ?? new BrowserEventDispatcher(); + this.tonConnectUiVersion = options.tonConnectUiVersion; + + this.init().catch(); + } + + /** + * Called once when the tracker is created and request version other libraries. + */ + private async init(): Promise { + try { + await this.setRequestVersionHandler(); + this.tonConnectSdkVersion = await this.requestTonConnectSdkVersion(); + } catch (e) {} + } + + /** + * Set request version handler. + * @private + */ + private async setRequestVersionHandler(): Promise { + await this.eventDispatcher.addEventListener('ton-connect-ui-request-version', async () => { + await this.eventDispatcher.dispatchEvent( + 'ton-connect-ui-response-version', + createResponseVersionEvent(this.tonConnectUiVersion) + ); + }); + } + + /** + * Request TonConnect SDK version. + * @private + */ + private async requestTonConnectSdkVersion(): Promise { + return new Promise(async (resolve, reject) => { + try { + await this.eventDispatcher.addEventListener( + 'ton-connect-response-version', + (event: CustomEvent) => { + resolve(event.detail.version); + }, + { once: true } + ); + await this.eventDispatcher.dispatchEvent( + 'ton-connect-request-version', + createRequestVersionEvent() + ); + } catch (e) { + reject(e); + } + }); } /** @@ -61,8 +152,9 @@ export class TonConnectUITracker { */ private dispatchUserActionEvent(eventDetails: UserActionEvent): void { try { - const eventName = `${this.eventPrefix}${eventDetails.type}`; - this.eventDispatcher?.dispatchEvent(eventName, eventDetails).catch(); + this.eventDispatcher + ?.dispatchEvent(`${this.eventPrefix}${eventDetails.type}`, eventDetails) + .catch(); } catch (e) {} } @@ -70,9 +162,11 @@ export class TonConnectUITracker { * Track connection init event. * @param args */ - public trackConnectionStarted(...args: Parameters): void { + public trackConnectionStarted( + ...args: WithoutVersion> + ): void { try { - const event = createConnectionStartedEvent(...args); + const event = createConnectionStartedEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } @@ -82,10 +176,10 @@ export class TonConnectUITracker { * @param args */ public trackConnectionCompleted( - ...args: Parameters + ...args: WithoutVersion> ): void { try { - const event = createConnectionCompletedEvent(...args); + const event = createConnectionCompletedEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } @@ -94,9 +188,11 @@ export class TonConnectUITracker { * Track connection error event. * @param args */ - public trackConnectionError(...args: Parameters): void { + public trackConnectionError( + ...args: WithoutVersion> + ): void { try { - const event = createConnectionErrorEvent(...args); + const event = createConnectionErrorEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } @@ -106,10 +202,10 @@ export class TonConnectUITracker { * @param args */ public trackConnectionRestoringStarted( - ...args: Parameters + ...args: WithoutVersion> ): void { try { - const event = createConnectionRestoringStartedEvent(...args); + const event = createConnectionRestoringStartedEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } @@ -119,10 +215,10 @@ export class TonConnectUITracker { * @param args */ public trackConnectionRestoringCompleted( - ...args: Parameters + ...args: WithoutVersion> ): void { try { - const event = createConnectionRestoringCompletedEvent(...args); + const event = createConnectionRestoringCompletedEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } @@ -132,10 +228,10 @@ export class TonConnectUITracker { * @param args */ public trackConnectionRestoringError( - ...args: Parameters + ...args: WithoutVersion> ): void { try { - const event = createConnectionRestoringErrorEvent(...args); + const event = createConnectionRestoringErrorEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } @@ -144,9 +240,11 @@ export class TonConnectUITracker { * Track disconnect event. * @param args */ - public trackDisconnection(...args: Parameters): void { + public trackDisconnection( + ...args: WithoutVersion> + ): void { try { - const event = createDisconnectionEvent(...args); + const event = createDisconnectionEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } @@ -156,10 +254,10 @@ export class TonConnectUITracker { * @param args */ public trackTransactionSentForSignature( - ...args: Parameters + ...args: WithoutVersion> ): void { try { - const event = createTransactionSentForSignatureEvent(...args); + const event = createTransactionSentForSignatureEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } @@ -168,9 +266,11 @@ export class TonConnectUITracker { * Track transaction signed event. * @param args */ - public trackTransactionSigned(...args: Parameters): void { + public trackTransactionSigned( + ...args: WithoutVersion> + ): void { try { - const event = createTransactionSignedEvent(...args); + const event = createTransactionSignedEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } @@ -180,10 +280,10 @@ export class TonConnectUITracker { * @param args */ public trackTransactionSigningFailed( - ...args: Parameters + ...args: WithoutVersion> ): void { try { - const event = createTransactionSigningFailedEvent(...args); + const event = createTransactionSigningFailedEvent(this.version, ...args); this.dispatchUserActionEvent(event); } catch (e) {} } diff --git a/packages/ui/src/tracker/types.ts b/packages/ui/src/tracker/types.ts index a016f4d6..184ced5f 100644 --- a/packages/ui/src/tracker/types.ts +++ b/packages/ui/src/tracker/types.ts @@ -2,19 +2,23 @@ import { ConnectionEvent, ConnectionRestoringEvent, DisconnectionEvent, - TransactionSigningEvent + TransactionSigningEvent, + VersionEvent } from '@tonconnect/sdk'; /** * User action events. */ export type UserActionEvent = + | VersionEvent | ConnectionEvent | ConnectionRestoringEvent | DisconnectionEvent | TransactionSigningEvent; export { + createRequestVersionEvent, + createResponseVersionEvent, createConnectionStartedEvent, createConnectionErrorEvent, createConnectionCompletedEvent, diff --git a/packages/ui/vite.cdn-config.ts b/packages/ui/vite.cdn-config.ts index 4cc0b616..4c2c6db8 100644 --- a/packages/ui/vite.cdn-config.ts +++ b/packages/ui/vite.cdn-config.ts @@ -1,38 +1,40 @@ import * as path from 'path'; import { defineConfig } from 'vite'; import solidPlugin from 'vite-plugin-solid'; +// @ts-ignore +import * as packageJson from './package.json'; + +const version = packageJson.version; export default defineConfig({ - plugins: [ - solidPlugin({ extensions: ['ts'] }) - ], - resolve: { - alias: { - src: path.resolve('src/'), + plugins: [solidPlugin({ extensions: ['ts'] })], + resolve: { + alias: { + src: path.resolve('src/') + } }, - }, - optimizeDeps: { - exclude: ['csstype'] - }, - define: { - 'process.env': {} - }, - build: { - target: 'es6', - outDir: 'dist', - emptyOutDir: true, - minify: 'terser', - terserOptions: { - format: { - comments: false - } + optimizeDeps: { + exclude: ['csstype'] }, - sourcemap: true, - lib: { - formats: ['umd'], - entry: path.resolve('src/index.ts'), - name: 'TON_CONNECT_UI', - fileName: () => 'tonconnect-ui.min.js' + define: { + TON_CONNECT_UI_VERSION: JSON.stringify(version) }, - }, + build: { + target: 'es6', + outDir: 'dist', + emptyOutDir: true, + minify: 'terser', + terserOptions: { + format: { + comments: false + } + }, + sourcemap: true, + lib: { + formats: ['umd'], + entry: path.resolve('src/index.ts'), + name: 'TON_CONNECT_UI', + fileName: () => 'tonconnect-ui.min.js' + } + } }); diff --git a/packages/ui/vite.config.ts b/packages/ui/vite.config.ts index 15419890..7087da76 100644 --- a/packages/ui/vite.config.ts +++ b/packages/ui/vite.config.ts @@ -1,60 +1,64 @@ import * as path from 'path'; import { defineConfig } from 'vite'; import solidPlugin from 'vite-plugin-solid'; -import devtools from 'solid-devtools/vite' +import devtools from 'solid-devtools/vite'; +// @ts-ignore +import * as packageJson from './package.json'; + +const version = packageJson.version; export default defineConfig({ - plugins: [ - devtools({ - autoname: true, - }), - solidPlugin({ extensions: ['ts'] }) - ], - resolve: { - alias: { - src: path.resolve('src/'), - }, - }, - server: { - port: 3000, - }, - optimizeDeps: { - exclude: ['csstype'] - }, - define: { - 'process.env': {} - }, - build: { - target: 'es6', - outDir: 'lib', - emptyOutDir: true, - minify: false, - sourcemap: true, - lib: { - formats: ['es', 'cjs'], - entry: path.resolve('src/index.ts'), - name: 'TON_CONNECT_UI', - fileName: (format) => { - switch (format) { - case 'es': - return 'index.mjs'; - case 'cjs': - return 'index.cjs'; - default: - throw new Error('Unknown format'); + plugins: [ + devtools({ + autoname: true + }), + solidPlugin({ extensions: ['ts'] }) + ], + resolve: { + alias: { + src: path.resolve('src/') } - } }, - rollupOptions: { - external: ['classnames', 'deepmerge', '@tonconnect/sdk', 'ua-parser-js'], - output: { - globals: { - '@tonconnect/sdk': 'TonConnectSDK', - 'deepmerge': 'deepmerge', - 'classnames': 'classNames', - 'ua-parser-js': 'UAParser' - }, - }, + server: { + port: 3000 + }, + optimizeDeps: { + exclude: ['csstype'] }, - }, + define: { + TON_CONNECT_UI_VERSION: JSON.stringify(version) + }, + build: { + target: 'es6', + outDir: 'lib', + emptyOutDir: true, + minify: false, + sourcemap: true, + lib: { + formats: ['es', 'cjs'], + entry: path.resolve('src/index.ts'), + name: 'TON_CONNECT_UI', + fileName: format => { + switch (format) { + case 'es': + return 'index.mjs'; + case 'cjs': + return 'index.cjs'; + default: + throw new Error('Unknown format'); + } + } + }, + rollupOptions: { + external: ['classnames', 'deepmerge', '@tonconnect/sdk', 'ua-parser-js'], + output: { + globals: { + '@tonconnect/sdk': 'TonConnectSDK', + deepmerge: 'deepmerge', + classnames: 'classNames', + 'ua-parser-js': 'UAParser' + } + } + } + } });