diff --git a/package.json b/package.json index 32bf7cde3..63ebfedb3 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "@ensdomains/content-hash": "^3.0.0-beta.5", "@ensdomains/ens-contracts": "1.2.0-beta.0", "@ensdomains/ensjs": "3.5.0-beta.2", - "@ensdomains/thorin": "0.6.44", + "@ensdomains/thorin": "workspace:*", "@metamask/mobile-provider": "^2.1.0", "@metamask/post-message-stream": "^6.1.2", "@metamask/providers": "^14.0.2", @@ -202,7 +202,9 @@ "bn.js": "npm:bn.js@^5.2.0", "@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers@0.3.0-beta.13", "@walletconnect/ethereum-provider": "2.11.1", - "@walletconnect/modal": "2.6.2" + "@walletconnect/modal": "2.6.2", + "react": "^18.2.0", + "react-dom": "^18.2.0" }, "patchedDependencies": { "react-confetti@6.1.0": "patches/react-confetti@6.1.0.patch", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dffe8a533..db67f4ce3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,6 +10,8 @@ overrides: '@nomiclabs/hardhat-ethers': npm:hardhat-deploy-ethers@0.3.0-beta.13 '@walletconnect/ethereum-provider': 2.11.1 '@walletconnect/modal': 2.6.2 + react: ^18.2.0 + react-dom: ^18.2.0 patchedDependencies: '@wagmi/core@2.6.5': @@ -39,8 +41,8 @@ importers: specifier: 3.5.0-beta.2 version: 3.5.0-beta.2(encoding@0.1.13)(typescript@5.3.3)(viem@2.7.13) '@ensdomains/thorin': - specifier: 0.6.44 - version: 0.6.44(react-dom@18.2.0)(react-transition-state@1.1.5)(react@18.2.0)(styled-components@5.3.6) + specifier: workspace:* + version: link:.yalc/@ensdomains/thorin '@metamask/mobile-provider': specifier: ^2.1.0 version: 2.1.0 @@ -451,6 +453,33 @@ importers: specifier: ^1.0.0-pre.53 version: 1.0.0-pre.53 + .yalc/@ensdomains/thorin: + dependencies: + clsx: + specifier: ^1.1.1 + version: 1.2.1 + focus-visible: + specifier: ^5.2.0 + version: 5.2.0 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + react-transition-state: + specifier: ^1.1.4 + version: 1.1.5(react-dom@18.2.0)(react@18.2.0) + styled-components: + specifier: ^5.3.3 + version: 5.3.6(react-dom@18.2.0)(react-is@17.0.2)(react@18.2.0) + ts-pattern: + specifier: ^4.3.0 + version: 4.3.0 + packages: /@aashutoshrathi/word-wrap@1.2.6: @@ -493,7 +522,8 @@ packages: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.18.6 + '@babel/highlight': 7.23.4 + dev: true /@babel/code-frame@7.23.5: resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} @@ -521,7 +551,7 @@ packages: '@babel/traverse': 7.23.9 '@babel/types': 7.23.9 convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -533,9 +563,10 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.9 - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.17 + '@jridgewell/gen-mapping': 0.3.4 + '@jridgewell/trace-mapping': 0.3.23 jsesc: 2.5.2 + dev: true /@babel/generator@7.23.6: resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} @@ -546,13 +577,6 @@ packages: '@jridgewell/trace-mapping': 0.3.17 jsesc: 2.5.2 - /@babel/helper-annotate-as-pure@7.18.6: - resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.9 - dev: false - /@babel/helper-annotate-as-pure@7.22.5: resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} engines: {node: '>=6.9.0'} @@ -626,7 +650,7 @@ packages: '@babel/core': 7.23.9 '@babel/helper-compilation-targets': 7.23.6 '@babel/helper-plugin-utils': 7.22.5 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.8 transitivePeerDependencies: @@ -636,6 +660,7 @@ packages: /@babel/helper-environment-visitor@7.18.9: resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} engines: {node: '>=6.9.0'} + dev: true /@babel/helper-environment-visitor@7.22.20: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} @@ -645,8 +670,9 @@ packages: resolution: {integrity: sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.20.7 + '@babel/template': 7.23.9 '@babel/types': 7.23.9 + dev: true /@babel/helper-function-name@7.23.0: resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} @@ -660,6 +686,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.9 + dev: true /@babel/helper-hoist-variables@7.22.5: resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} @@ -674,13 +701,6 @@ packages: '@babel/types': 7.23.9 dev: false - /@babel/helper-module-imports@7.18.6: - resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.3 - dev: false - /@babel/helper-module-imports@7.22.15: resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} @@ -758,6 +778,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.9 + dev: true /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} @@ -765,18 +786,10 @@ packages: dependencies: '@babel/types': 7.23.9 - /@babel/helper-string-parser@7.19.4: - resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} - engines: {node: '>=6.9.0'} - /@babel/helper-string-parser@7.23.4: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.19.1: - resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} - engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} engines: {node: '>=6.9.0'} @@ -809,14 +822,6 @@ packages: transitivePeerDependencies: - supports-color - /@babel/highlight@7.18.6: - resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.19.1 - chalk: 2.4.2 - js-tokens: 4.0.0 - /@babel/highlight@7.23.4: resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} engines: {node: '>=6.9.0'} @@ -839,6 +844,7 @@ packages: hasBin: true dependencies: '@babel/types': 7.23.9 + dev: true /@babel/parser@7.23.9: resolution: {integrity: sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==} @@ -1693,7 +1699,7 @@ packages: dependencies: '@babel/core': 7.23.9 '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-module-imports': 7.18.6 + '@babel/helper-module-imports': 7.22.15 '@babel/helper-plugin-utils': 7.22.5 '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.9) '@babel/types': 7.23.9 @@ -2042,14 +2048,6 @@ packages: dependencies: regenerator-runtime: 0.14.1 - /@babel/template@7.20.7: - resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.23.5 - '@babel/parser': 7.23.9 - '@babel/types': 7.23.9 - /@babel/template@7.23.9: resolution: {integrity: sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==} engines: {node: '>=6.9.0'} @@ -2070,31 +2068,30 @@ packages: '@babel/helper-split-export-declaration': 7.18.6 '@babel/parser': 7.21.3 '@babel/types': 7.21.3 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/traverse@7.21.3(supports-color@5.5.0): - resolution: {integrity: sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==} + /@babel/traverse@7.23.9: + resolution: {integrity: sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.21.3 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.21.3 - '@babel/types': 7.21.3 - debug: 4.3.4(supports-color@5.5.0) + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.9 + '@babel/types': 7.23.9 + debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: false - /@babel/traverse@7.23.9: + /@babel/traverse@7.23.9(supports-color@5.5.0): resolution: {integrity: sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==} engines: {node: '>=6.9.0'} dependencies: @@ -2110,14 +2107,16 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color + dev: false /@babel/types@7.21.3: resolution: {integrity: sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.19.4 - '@babel/helper-validator-identifier': 7.19.1 + '@babel/helper-string-parser': 7.23.4 + '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 + dev: true /@babel/types@7.23.9: resolution: {integrity: sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==} @@ -2282,22 +2281,12 @@ packages: resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} dev: false - /@emotion/is-prop-valid@1.2.0: - resolution: {integrity: sha512-3aDpDprjM0AwaxGE09bOPkNxHpBd+kA6jty3RnaEXdweX1DF1U3VQpPYb0g1IStAuK7SVQ1cy+bNBBKp4W3Fjg==} - dependencies: - '@emotion/memoize': 0.8.0 - dev: false - /@emotion/is-prop-valid@1.2.1: resolution: {integrity: sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==} dependencies: '@emotion/memoize': 0.8.1 dev: false - /@emotion/memoize@0.8.0: - resolution: {integrity: sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==} - dev: false - /@emotion/memoize@0.8.1: resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} dev: false @@ -2306,7 +2295,7 @@ packages: resolution: {integrity: sha512-Cnn0kuq4DoONOMcnoVsTOR8E+AdnKFf//6kUWc4LCdnxj31pZWn7rIULd6Y7/Js1PiPHzn7SKCM9vB/jBni8eA==} peerDependencies: '@types/react': '*' - react: '>=16.8.0' + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -2342,7 +2331,7 @@ packages: peerDependencies: '@emotion/react': ^11.0.0-rc.0 '@types/react': '*' - react: '>=16.8.0' + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -2373,7 +2362,7 @@ packages: /@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0): resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==} peerDependencies: - react: '>=16.8.0' + react: ^18.2.0 dependencies: react: 18.2.0 dev: false @@ -2534,24 +2523,6 @@ packages: hash-test-vectors: 1.3.2 dev: false - /@ensdomains/thorin@0.6.44(react-dom@18.2.0)(react-transition-state@1.1.5)(react@18.2.0)(styled-components@5.3.6): - resolution: {integrity: sha512-MoW0csfH/ql1q85IrWQvAFU/7gTlhM7GWBbSCN7uFN/v5hUr+f+C8zON/17QM9UT7bhigCur48DeL172eqiIMA==} - peerDependencies: - react: ^17 - react-dom: ^17 - react-transition-state: ^1.1.4 - styled-components: ^5.3.3 - dependencies: - clsx: 1.2.1 - focus-visible: 5.2.0 - lodash: 4.17.21 - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - react-transition-state: 1.1.5(react-dom@18.2.0)(react@18.2.0) - styled-components: 5.3.6(react-dom@18.2.0)(react-is@17.0.2)(react@18.2.0) - ts-pattern: 4.3.0 - dev: false - /@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19): resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} peerDependencies: @@ -2973,7 +2944,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 ignore: 5.3.1 @@ -3413,7 +3384,7 @@ packages: engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 2.0.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -3525,7 +3496,7 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/sourcemap-codec': 1.4.15 /@jridgewell/gen-mapping@0.3.2: resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} @@ -3588,8 +3559,8 @@ packages: /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.4.15 dev: true /@leichtgewicht/ip-codec@2.0.4: @@ -3865,7 +3836,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@types/debug': 4.1.12 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) semver: 7.6.0 superstruct: 1.0.3 transitivePeerDependencies: @@ -3878,7 +3849,7 @@ packages: dependencies: '@ethereumjs/tx': 4.1.2 '@types/debug': 4.1.7 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) semver: 7.5.4 superstruct: 1.0.3 transitivePeerDependencies: @@ -3893,7 +3864,7 @@ packages: '@noble/hashes': 1.3.3 '@scure/base': 1.1.5 '@types/debug': 4.1.12 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) pony-cause: 2.1.10 semver: 7.6.0 superstruct: 1.0.3 @@ -3978,7 +3949,7 @@ packages: '@open-draft/until': 1.0.3 '@types/debug': 4.1.7 '@xmldom/xmldom': 0.8.7 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) headers-polyfill: 3.2.5 outvariant: 1.4.0 strict-event-emitter: 0.2.8 @@ -4164,7 +4135,7 @@ packages: '@nomicfoundation/ethereumjs-trie': 5.0.0 '@nomicfoundation/ethereumjs-util': 8.0.0 abstract-level: 1.0.3 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) ethereum-cryptography: 0.1.3 level: 8.0.0 lru-cache: 5.1.1 @@ -4200,7 +4171,7 @@ packages: '@nomicfoundation/ethereumjs-util': 8.0.0 '@types/async-eventemitter': 0.2.1 async-eventemitter: 0.2.4 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) ethereum-cryptography: 0.1.3 mcl-wasm: 0.7.9 rustbn.js: 0.2.0 @@ -4221,7 +4192,7 @@ packages: '@nomicfoundation/ethereumjs-rlp': 4.0.0 '@nomicfoundation/ethereumjs-trie': 5.0.0 '@nomicfoundation/ethereumjs-util': 8.0.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) ethereum-cryptography: 0.1.3 functional-red-black-tree: 1.0.1 transitivePeerDependencies: @@ -4271,7 +4242,7 @@ packages: '@nomicfoundation/ethereumjs-util': 8.0.0 '@types/async-eventemitter': 0.2.1 async-eventemitter: 0.2.4 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) ethereum-cryptography: 0.1.3 functional-red-black-tree: 1.0.1 mcl-wasm: 0.7.9 @@ -4587,8 +4558,8 @@ packages: resolution: {integrity: sha512-htE5nI0/2Q4UcLuiVW4IDmA6bqSyEzIB/XNcD1MEvYyLLZRTdQ8YGUhXAlZfYCC2Q+TcfYAxS826XcfPXwh7nQ==} engines: {node: '>=12.4'} peerDependencies: - react: '>=17' - react-dom: '>=17' + react: ^18.2.0 + react-dom: ^18.2.0 viem: 2.x wagmi: 2.x dependencies: @@ -5252,7 +5223,7 @@ packages: engines: {node: '>=8'} peerDependencies: next: ^10.0.8 || ^11.0 || ^12.0 || ^13.0 - react: 16.x || 17.x || 18.x + react: ^18.2.0 webpack: '>= 4.0.0' peerDependenciesMeta: webpack: @@ -5315,7 +5286,7 @@ packages: resolution: {integrity: sha512-HWt0Eh+Y+Z/g+PWgeYWT6+5B+J82gauQ0GydjGeHeeSpoZRPRwWAoRFh+NKM/pe3neVr59VCyn4ghyoE3kODGA==} engines: {node: '>=8'} peerDependencies: - react: 15.x || 16.x || 17.x || 18.x + react: ^18.2.0 dependencies: '@sentry/browser': 7.43.0 '@sentry/types': 7.43.0 @@ -5769,7 +5740,7 @@ packages: resolution: {integrity: sha512-osAaQn2PDTaa2ApTLOAus7g8Y96LHfS2+Pgu/RoDlEJUEkX7xdEn0YuurxbnJaDJDESMfr+CH/eAX2y+lx02Fg==} peerDependencies: '@tanstack/react-query': ^5.22.2 - react: ^18.0.0 + react: ^18.2.0 dependencies: '@tanstack/query-persist-client-core': 5.22.2 '@tanstack/react-query': 5.22.2(react@18.2.0) @@ -5779,7 +5750,7 @@ packages: /@tanstack/react-query@5.22.2(react@18.2.0): resolution: {integrity: sha512-TaxJDRzJ8/NWRT4lY2jguKCrNI6MRN+67dELzPjNUlvqzTxGANlMp68l7aC7hG8Bd1uHNxHl7ihv7MT50i/43A==} peerDependencies: - react: ^18.0.0 + react: ^18.2.0 dependencies: '@tanstack/query-core': 5.22.2 react: 18.2.0 @@ -5836,8 +5807,8 @@ packages: engines: {node: '>=12'} peerDependencies: '@types/react': ^16.9.0 || ^17.0.0 - react: ^16.9.0 || ^17.0.0 - react-dom: ^16.9.0 || ^17.0.0 + react: ^18.2.0 + react-dom: ^18.2.0 react-test-renderer: ^16.9.0 || ^17.0.0 peerDependenciesMeta: '@types/react': @@ -5858,8 +5829,8 @@ packages: resolution: {integrity: sha512-sGdjws32ai5TLerhvzThYFbpnF9XtL65Cjf+gB0Dhr29BGqK+mAeN7SURSdu+eqgET4ANcWoC7FQpkaiGvBr+A==} engines: {node: '>=14'} peerDependencies: - react: ^18.0.0 - react-dom: ^18.0.0 + react: ^18.2.0 + react-dom: ^18.2.0 dependencies: '@babel/runtime': 7.19.0 '@testing-library/dom': 9.3.4 @@ -5897,7 +5868,7 @@ packages: big.js: 6.2.1 bn.js: 5.2.1 cbor: 5.2.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) lodash: 4.17.21 semver: 7.3.7 utf8: 3.0.0 @@ -5917,7 +5888,7 @@ packages: resolution: {integrity: sha512-wReyVZUPyU9Zy5PSCugBLG1nnruBmRAJ/gmoirQiJ9N2n+s1iGBTY49tkDqFMz3XUUE0kplfdb9YKZJlLkTWzQ==} dependencies: ajv: 6.12.6 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -5932,7 +5903,7 @@ packages: '@truffle/error': 0.1.1 '@truffle/interface-adapter': 0.5.25 bignumber.js: 7.2.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) ethers: 4.0.49 web3: 1.7.4 web3-core-helpers: 1.7.4 @@ -5952,7 +5923,7 @@ packages: '@trufflesuite/chromafi': 3.0.0 bn.js: 5.2.1 chalk: 2.4.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) highlightjs-solidity: 2.0.5 transitivePeerDependencies: - supports-color @@ -6396,7 +6367,7 @@ packages: '@typescript-eslint/type-utils': 6.21.0(eslint@8.50.0)(typescript@5.3.3) '@typescript-eslint/utils': 6.21.0(eslint@8.50.0)(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.50.0 graphemer: 1.4.0 ignore: 5.3.1 @@ -6422,7 +6393,7 @@ packages: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.50.0 typescript: 5.3.3 transitivePeerDependencies: @@ -6457,7 +6428,7 @@ packages: dependencies: '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.3.3) '@typescript-eslint/utils': 6.21.0(eslint@8.50.0)(typescript@5.3.3) - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) eslint: 8.50.0 ts-api-utils: 1.2.1(typescript@5.3.3) typescript: 5.3.3 @@ -6486,7 +6457,7 @@ packages: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 @@ -6507,7 +6478,7 @@ packages: dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 @@ -6630,7 +6601,7 @@ packages: dependencies: '@ampproject/remapping': 2.2.1 '@bcoe/v8-coverage': 0.2.3 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 istanbul-lib-source-maps: 4.0.1 @@ -7363,7 +7334,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -7371,7 +7342,7 @@ packages: resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} engines: {node: '>= 14'} dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -7840,8 +7811,8 @@ packages: peerDependencies: styled-components: '>= 2' dependencies: - '@babel/helper-annotate-as-pure': 7.18.6 - '@babel/helper-module-imports': 7.18.6 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-module-imports': 7.22.15 babel-plugin-syntax-jsx: 6.18.0 lodash: 4.17.21 picomatch: 2.3.1 @@ -8307,7 +8278,7 @@ packages: /capnp-ts@0.7.0: resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) tslib: 2.6.2 transitivePeerDependencies: - supports-color @@ -9240,6 +9211,7 @@ packages: dependencies: ms: 2.1.2 supports-color: 5.5.0 + dev: false /debug@4.3.4(supports-color@8.1.1): resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} @@ -9252,7 +9224,6 @@ packages: dependencies: ms: 2.1.2 supports-color: 8.1.1 - dev: true /decamelize-keys@1.1.0: resolution: {integrity: sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==} @@ -9689,7 +9660,7 @@ packages: resolution: {integrity: sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==} dependencies: '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) engine.io-parser: 5.2.2 ws: 8.11.0(bufferutil@4.0.8)(utf-8-validate@6.0.3) xmlhttprequest-ssl: 2.0.0 @@ -10132,7 +10103,7 @@ packages: eslint: '*' eslint-plugin-import: '*' dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) enhanced-resolve: 5.15.0 eslint: 8.50.0 eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.21.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.50.0) @@ -10363,7 +10334,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -11081,7 +11052,7 @@ packages: debug: optional: true dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) dev: true /for-each@0.3.3: @@ -11713,7 +11684,7 @@ packages: axios: 0.21.4(debug@4.3.4) chalk: 4.1.2 chokidar: 3.5.3 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) enquirer: 2.3.6 ethers: 5.7.2 form-data: 4.0.0 @@ -11764,7 +11735,7 @@ packages: chalk: 2.4.2 chokidar: 3.5.3 ci-info: 2.0.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) enquirer: 2.3.6 env-paths: 2.2.1 ethereum-cryptography: 1.1.2 @@ -12034,7 +12005,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -12074,7 +12045,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -12083,7 +12054,7 @@ packages: engines: {node: '>= 14'} dependencies: agent-base: 7.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: true @@ -12328,7 +12299,7 @@ packages: dependencies: '@ioredis/commands': 1.2.0 cluster-key-slot: 1.1.2 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -12740,7 +12711,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: @@ -13552,7 +13523,7 @@ packages: resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} engines: {node: '>=12'} dependencies: - '@jridgewell/sourcemap-codec': 1.4.14 + '@jridgewell/sourcemap-codec': 1.4.15 dev: false /magic-string@0.30.7: @@ -13616,7 +13587,7 @@ packages: resolution: {integrity: sha512-VI3TyyHlGkO8uFle0IOibzpO1c1iJDcXcS/zBrQrXQQvJ2tpdwVzVZ7XdKsyRz1NdRmre4dqQkMZzUHaKIG/1w==} engines: {node: '>= 10'} peerDependencies: - react: '>= 0.14.0' + react: ^18.2.0 dependencies: react: 18.2.0 dev: false @@ -14367,8 +14338,8 @@ packages: /nano-css@5.3.5(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-vSB9X12bbNu4ALBu7nigJgRViZ6ja3OU7CeuiV1zMIbXOdmkLahgtPmh3GBOlDxbKY0CitqlPdOReGlBLSp+yg==} peerDependencies: - react: '*' - react-dom: '*' + react: ^18.2.0 + react-dom: ^18.2.0 dependencies: css-tree: 1.1.3 csstype: 3.1.1 @@ -14431,7 +14402,7 @@ packages: hasBin: true peerDependencies: next: '>=12.0.0' - react: '>=16.0.0' + react: ^18.2.0 dependencies: arg: 5.0.2 next: 13.5.6(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0) @@ -14445,7 +14416,7 @@ packages: resolution: {integrity: sha512-PzKn70RSqO50GHyYyhd4WJb9I526Abfq2VDP+YPV8yqlaR38OKtQAcWr3njR75UG+Ik6HououZHm7ucxl6LSnA==} peerDependencies: next: '>=10.0.0' - react: '>=17.0.0' + react: ^18.2.0 dependencies: next: 13.5.6(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 @@ -15146,7 +15117,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.23.5 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -15772,7 +15743,7 @@ packages: resolution: {integrity: sha512-7Ypx4vz0+g8ECVxr88W9zhcQpbeujJAVqL14ZnXJ3I23mOI9/oBVTQ3dkJhUmB0D6XOtCZEM6N0Gm9PMngkORw==} engines: {node: '>=10.18'} peerDependencies: - react: ^16.3.0 || ^17.0.1 || ^18.0.0 + react: ^18.2.0 dependencies: react: 18.2.0 tween-functions: 1.2.0 @@ -15802,7 +15773,7 @@ packages: resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==} engines: {node: '>=10', npm: '>=6'} peerDependencies: - react: '>=16.13.1' + react: ^18.2.0 dependencies: '@babel/runtime': 7.19.0 react: 18.2.0 @@ -15812,7 +15783,7 @@ packages: resolution: {integrity: sha512-4Vc0W5EvXAXUN/wWyxvsAKDLLgtJ3oLmhYYssx+YzphJpejtOst6cbIHCIyF50Fdxuf5DDKqRYny24yJ2y7GFQ==} peerDependencies: prop-types: ^15.6.0 - react: ^15.6.2 || ^16.0 || ^17 || ^18 + react: ^18.2.0 dependencies: prop-types: 15.8.1 react: 18.2.0 @@ -15822,7 +15793,7 @@ packages: resolution: {integrity: sha512-BggOy5j58RdhdMzzRUHGOYhSz1oeylFAv6jUSG86OvCIvlAvS7KvnRY7yoAf2pfEiPN7BesnR0xx73nEk3qIiw==} engines: {node: '>=12.22.0'} peerDependencies: - react: ^16.8.0 || ^17 || ^18 + react: ^18.2.0 dependencies: react: 18.2.0 dev: false @@ -15831,7 +15802,7 @@ packages: resolution: {integrity: sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==} peerDependencies: i18next: '>= 19.0.0' - react: '>= 16.8.0' + react: ^18.2.0 react-dom: '*' react-native: '*' peerDependenciesMeta: @@ -15852,7 +15823,7 @@ packages: resolution: {integrity: sha512-CFJ5NDGJ2MUyBohEHxljOq/39NQ972rh1ajnadG9BjTk+UXbHLq4z5DKEbEQBDoIhUmmbuS/fIMJKo6VOax1HA==} peerDependencies: i18next: '>= 23.2.3' - react: '>= 16.8.0' + react: ^18.2.0 react-dom: '*' react-native: '*' peerDependenciesMeta: @@ -15881,7 +15852,7 @@ packages: /react-native-webview@11.26.1(react-native@0.73.5)(react@18.2.0): resolution: {integrity: sha512-hC7BkxOpf+z0UKhxFSFTPAM4shQzYmZHoELa6/8a/MspcjEP7ukYKpuSUTLDywQditT8yI9idfcKvfZDKQExGw==} peerDependencies: - react: '*' + react: ^18.2.0 react-native: '*' dependencies: escape-string-regexp: 2.0.0 @@ -15895,7 +15866,7 @@ packages: engines: {node: '>=18'} hasBin: true peerDependencies: - react: 18.2.0 + react: ^18.2.0 dependencies: '@jest/create-cache-key-function': 29.7.0 '@react-native-community/cli': 12.3.6 @@ -15953,7 +15924,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -15969,7 +15940,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -15986,7 +15957,7 @@ packages: /react-shallow-renderer@16.15.0(react@18.2.0): resolution: {integrity: sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==} peerDependencies: - react: ^16.0.0 || ^17.0.0 || ^18.0.0 + react: ^18.2.0 dependencies: object-assign: 4.1.1 react: 18.2.0 @@ -15998,7 +15969,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -16013,8 +15984,8 @@ packages: /react-transition-state@1.1.5(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-ITY2mZqc2dWG2eitJkYNdcSFW8aKeOlkL2A/vowRrLL8GH3J6Re/SpD/BLvQzrVOTqjsP0b5S9N10vgNNzwMUQ==} peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' + react: ^18.2.0 + react-dom: ^18.2.0 dependencies: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -16023,7 +15994,7 @@ packages: /react-universal-interface@0.6.2(react@18.2.0)(tslib@2.4.1): resolution: {integrity: sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==} peerDependencies: - react: '*' + react: ^18.2.0 tslib: '*' dependencies: react: 18.2.0 @@ -16033,7 +16004,7 @@ packages: /react-use-error-boundary@3.0.0(react@18.2.0): resolution: {integrity: sha512-5urkfyU3ZzInEMSHe1gxtDzlQAHs0krTt0V6h8H2L5nXhDKq3OYXnCs9lGHDkEkYvLmsphw8ap5g8uYfvrkJng==} peerDependencies: - react: '>= 16.8' + react: ^18.2.0 dependencies: react: 18.2.0 dev: false @@ -16041,8 +16012,8 @@ packages: /react-use-intercom@5.1.4(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-37dMuCg3H5KgMqpUMiZiu7Ni1LcRAkO8T7F1Zg4Xc+hL89j8OYFHzWWBy29EFgRsTdvCEJ2X8J5wAXerU9uuqw==} peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' + react: ^18.2.0 + react-dom: ^18.2.0 dependencies: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -16051,8 +16022,8 @@ packages: /react-use@17.4.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-TgbNTCA33Wl7xzIJegn1HndB4qTS9u03QUwyNycUnXaweZkE4Kq2SB+Yoxx8qbshkZGYBDvUXbXWRUmQDcZZ/Q==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^18.2.0 + react-dom: ^18.2.0 dependencies: '@types/js-cookie': 2.2.7 '@xobotyi/scrollbar-width': 1.9.5 @@ -17031,7 +17002,7 @@ packages: engines: {node: '>=10.0.0'} dependencies: '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) engine.io-client: 6.5.3(bufferutil@4.0.8)(utf-8-validate@6.0.3) socket.io-parser: 4.2.4 transitivePeerDependencies: @@ -17045,7 +17016,7 @@ packages: engines: {node: '>=10.0.0'} dependencies: '@socket.io/component-emitter': 3.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) transitivePeerDependencies: - supports-color dev: false @@ -17492,13 +17463,13 @@ packages: engines: {node: '>=10'} requiresBuild: true peerDependencies: - react: '>= 16.8.0' - react-dom: '>= 16.8.0' + react: ^18.2.0 + react-dom: ^18.2.0 react-is: '>= 16.8.0' dependencies: - '@babel/helper-module-imports': 7.18.6 - '@babel/traverse': 7.21.3(supports-color@5.5.0) - '@emotion/is-prop-valid': 1.2.0 + '@babel/helper-module-imports': 7.22.15 + '@babel/traverse': 7.23.9(supports-color@5.5.0) + '@emotion/is-prop-valid': 1.2.1 '@emotion/stylis': 0.8.5 '@emotion/unitless': 0.7.5 babel-plugin-styled-components: 2.0.7(styled-components@5.3.6) @@ -17517,7 +17488,7 @@ packages: peerDependencies: '@babel/core': '*' babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + react: ^18.2.0 peerDependenciesMeta: '@babel/core': optional: true @@ -17634,7 +17605,7 @@ packages: colord: 2.9.3 cosmiconfig: 7.0.1 css-functions-list: 3.1.0 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) fast-glob: 3.2.12 fastest-levenshtein: 1.0.16 file-entry-cache: 6.0.1 @@ -18505,7 +18476,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -18519,7 +18490,7 @@ packages: resolution: {integrity: sha512-Re4hjrP3a/2ABZjAc0b7AK9s626bnO+H33RO2VUhiDZ2StBz5B663K6WNNlr4QtHWaGUmvLpwt3whFvvWuolQw==} peerDependencies: immer: '>=2.0.0' - react: ^16.8.0 || ^17.0.1 || ^18.0.0 + react: ^18.2.0 dependencies: immer: 9.0.15 react: 18.2.0 @@ -18530,7 +18501,7 @@ packages: engines: {node: '>=10'} peerDependencies: '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -18544,7 +18515,7 @@ packages: /use-sync-external-store@1.2.0(react@18.2.0): resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^18.2.0 dependencies: react: 18.2.0 dev: false @@ -18656,7 +18627,7 @@ packages: engines: {node: '>=12.20.0'} peerDependencies: '@types/react': '>=16.8' - react: '>=16.8' + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true @@ -18738,7 +18709,7 @@ packages: hasBin: true dependencies: cac: 6.7.14 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) pathe: 1.1.2 picocolors: 1.0.0 vite: 5.1.4(@types/node@18.8.2) @@ -18842,7 +18813,7 @@ packages: '@vitest/utils': 1.3.1 acorn-walk: 8.3.2 chai: 4.4.1 - debug: 4.3.4(supports-color@5.5.0) + debug: 4.3.4(supports-color@8.1.1) execa: 8.0.1 jsdom: 24.0.0(canvas@2.11.2) local-pkg: 0.5.0 @@ -18927,7 +18898,7 @@ packages: resolution: {integrity: sha512-xSuteMXFKvra4xDddqZbZv/gQlcg3X+To5AoZW7WoAm0iVlF8/vEGpQzCWy6KZs2z1szxPrr0YnH3Zr1Qj4E/A==} peerDependencies: '@tanstack/react-query': '>=5.0.0' - react: '>=18' + react: ^18.2.0 typescript: '>=5.0.4' viem: 2.x peerDependenciesMeta: @@ -20247,7 +20218,7 @@ packages: peerDependencies: '@types/react': '>=16.8' immer: '>=9.0' - react: '>=16.8' + react: ^18.2.0 peerDependenciesMeta: '@types/react': optional: true diff --git a/public/locales/en/profile.json b/public/locales/en/profile.json index 12636fbce..7c7cdbdfc 100644 --- a/public/locales/en/profile.json +++ b/public/locales/en/profile.json @@ -14,7 +14,7 @@ "viewDetails": "View Details", "banner": { "available": { - "title": "{{name}} is available", + "title": "{{name}} is available", "description": "This name expired on {{date}}. Click here to view the registration page." } }, @@ -53,7 +53,7 @@ "name": "Ownership", "warning": { "ownerNotManager": "You are the owner but not the manager. This may be unintended if you’ve recently recieved this name from another address.", - "managerNotParentOwner": "The owner of {{parent}} can change ownership, roles, and settings. They cannot change the profile.", + "managerNotParentOwner": "The owner of {{parent}} can change ownership, roles, and settings. They cannot change the profile.", "managerNotDNSOwner": "You are the Manager but not DNS Owner of this name. DNS names can be reclaimed by the DNS Owner at any time. You can send this name to the Owner, or update the DNS record to match.", "dnsOwnerNotManager": "You cannot make changes to this name because you are the DNS Owner, but not the Manager. You can sync the manager to fix this." }, @@ -93,7 +93,7 @@ "tooltips": { "owner": "The owner of this name. The owner cannot change the profile.", "owner-emancipated": "The owner of this name.", - "parent-owner": "The owner of this name's parent ({{parent}}).", + "parent-owner": "The owner of this name's parent ({{parent}}).", "dns-owner": "The owner of this name, as set by DNS records. The owner cannot change the profile.", "manager": "The address that can change the profile, settings and profile editors.", "profile-editor": "An addres that can only change the profile", @@ -109,7 +109,7 @@ }, "permissions": { "name": "Permissions", - "parentUnlockedWarning": "You cannot change permissions on this name. You must first revoke ‘unwrap this name’ on the parent ({{parent}}). Click here to view the parent’s permissions.", + "parentUnlockedWarning": "You cannot change permissions on this name. You must first revoke ‘unwrap this name’ on the parent ({{parent}}). Click here to view the parent’s permissions.", "revokedLabel": "Revoked {{date}}", "grantedLabel": "Granted {{date}}", "role": { @@ -120,7 +120,7 @@ "ownership": { "title": "Ownership Permissions", "parentCanControl": { - "label": "This name can be controlled by its parent ({{parent}})", + "label": "This name can be controlled by its parent ({{parent}})", "list": { "title": "The owner of the parent name can:", "item1": "Control and modify the settings and records", @@ -129,7 +129,7 @@ } }, "parentCannotControl": { - "label": "This name cannot be controlled by its parent ({{parent}})", + "label": "This name cannot be controlled by its parent ({{parent}})", "sublabel": "The owner of the parent name cannot control, modify, remove or retake ownership of this name.", "list": { "title": "The name owner will retain ownership unless one of the following happens:", @@ -139,7 +139,7 @@ } }, "parentCanChange": { - "label": "The parent of this name ({{parent}}) can change permissions", + "label": "The parent of this name ({{parent}}) can change permissions", "list": { "title": "The parent can:", "item1": "Revoke permissions", @@ -437,7 +437,7 @@ "invalidName": "This name is invalid.", "invalidAddress": "Not a valid address", "expiringSoon": "The grace period for this name ends on {{date}}. If it isn’t extended before this date, it will become available for registration.", - "hasExpired": "{{ name }} has expired", + "hasExpired": "{{ name }} has expired", "ownerManagerChoice": "Must send owner or manager", "unknown": "Unknown error", "notMigrated": "This name is not migrated to the new registry.", diff --git a/public/locales/en/transactionFlow.json b/public/locales/en/transactionFlow.json index c7795973b..cdb067805 100644 --- a/public/locales/en/transactionFlow.json +++ b/public/locales/en/transactionFlow.json @@ -242,7 +242,7 @@ }, "revokePCC": { "title": "Give up ownership", - "subtitle": "This will give ownership of this name to the manager ({{account}}). Unless you are also the manager, you will no longer be able to make changes to this name." + "subtitle": "This will give ownership of this name to the manager ({{account}}). Unless you are also the manager, you will no longer be able to make changes to this name." }, "grantExtendExpiry": { "title": "Change permissions", @@ -252,8 +252,8 @@ }, "setExpiry": { "title": "Set name expiry", - "subtitle": "Set a date when permissions will expire. This date cannot be longer than the expiry of its parent ({{parent}}).", - "subtitleWithCEE": "Set a date when this name will expire. This will replace it’s existing permission expiry ({{expiry}}), and cannot be later than the expiry of its parent ({{parent}}).", + "subtitle": "Set a date when permissions will expire. This date cannot be longer than the expiry of its parent ({{parent}}).", + "subtitleWithCEE": "Set a date when this name will expire. This will replace it’s existing permission expiry ({{expiry}}), and cannot be later than the expiry of its parent ({{parent}}).", "options": { "max": "Max", "custom": "Choose an earlier date" @@ -319,7 +319,7 @@ }, "deleteSubnameNotParentWarning": { "title": "You cannot recreate this subname", - "message": "Only the {{ownershipTerm}} of the parent name ({{parentOwner}}) can recreate this subname. You will not be able to recreate this name yourself once it has been deleted." + "message": "Only the {{ownershipTerm}} of the parent name ({{parentOwner}}) can recreate this subname. You will not be able to recreate this name yourself once it has been deleted." }, "selectPrimaryName": { "title": "Select a primary name", @@ -387,7 +387,7 @@ }, "syncManager": { "title": "Sync manager", - "description": "Syncing the manager will make you the new manager of this name. The current manager ({{manager}}) will no longer be able to make changes.", + "description": "Syncing the manager will make you the new manager of this name. The current manager ({{manager}}) will no longer be able to make changes.", "warning": "Syncing the manager will also unwrap this name. This will burn the NFT and reset any permissions." } }, @@ -409,7 +409,7 @@ "warning": "Note that if you cancel this at any point your changes will not be saved." }, "syncManager": { - "description": "Syncing the manager will make you the new manager of this name. The current manager ({{manager}}) will no longer be able to make changes.", + "description": "Syncing the manager will make you the new manager of this name. The current manager ({{manager}}) will no longer be able to make changes.", "wrappedWarning": "Syncing the manager will also unwrap this name. This will burn the NFT and reset any permissions." }, "selectPrimaryName": { diff --git a/public/locales/zh/transactionFlow.json b/public/locales/zh/transactionFlow.json index ac08c39fd..aefcb410f 100644 --- a/public/locales/zh/transactionFlow.json +++ b/public/locales/zh/transactionFlow.json @@ -220,7 +220,7 @@ }, "revokePCC": { "title": "放弃所有权", - "subtitle": "此操作会把名称的所有权转让给管理员 ({{account}})。除非您同时也是管理员,否则您将无法再管理该名称。" + "subtitle": "此操作会把名称的所有权转让给管理员 ({{account}})。除非您同时也是管理员,否则您将无法再管理该名称。" }, "grantExtendExpiry": { "title": "更改权限", diff --git a/src/components/@atoms/BaseLink.tsx b/src/components/@atoms/BaseLink.tsx index 29a634c0a..d42968efe 100644 --- a/src/components/@atoms/BaseLink.tsx +++ b/src/components/@atoms/BaseLink.tsx @@ -2,17 +2,17 @@ import { UrlObject } from 'url' import Link, { LinkProps } from 'next/link' import { useRouter } from 'next/router' -import { PropsWithChildren, useMemo } from 'react' +import { forwardRef, PropsWithChildren, useMemo } from 'react' import { getDestination } from '@app/routes' // from: https://github.com/Velenir/nextjs-ipfs-example -const BaseLink = ({ href, ...rest }: PropsWithChildren) => { +const BaseLink = forwardRef(({ href, ...rest }: PropsWithChildren, ref) => { const newHref = useMemo(() => getDestination(href), [href]) - return -} + return +}) export const BaseLinkWithHistory = ({ href, diff --git a/src/components/@atoms/EllipsisName/EllipsisName.tsx b/src/components/@atoms/EllipsisName/EllipsisName.tsx new file mode 100644 index 000000000..a15ad0d6f --- /dev/null +++ b/src/components/@atoms/EllipsisName/EllipsisName.tsx @@ -0,0 +1,127 @@ +import { useEffect, useRef, useState } from 'react' +import styled, { css } from 'styled-components' + +import { StyledLink } from '../StyledLink' + +const Container = styled.span( + () => css` + word-break: keep-all; + overflow-wrap: normal; + /* display: flex; */ + overflow: hidden; + justify-content: left; + `, +) + +const HiddenSpan = styled.span( + () => css` + position: absolute; + pointer-events: none; + visibility: hidden; + white-space: nowrap; + `, +) + +const VisibleSpan = styled.span( + () => css` + white-space: nowrap; + `, +) + +type Props = { + children: string + padding?: number + containerRef?: React.RefObject +} + +const calculateSlice = ({ + node, + ellipsisWidth, + maxWidth, +}: { + node: HTMLSpanElement | null + ellipsisWidth: number + maxWidth?: number +}): number | null => { + if (!node) return null + + const parentElementWidth = maxWidth || node.parentElement?.offsetWidth || Infinity + const nodeWidth = node.offsetWidth || Infinity + if (nodeWidth <= parentElementWidth) return null + + const children = node?.children || [] + let slice = 0 + let total = ellipsisWidth + for (let index = 0; index < Math.floor((children.length - 1) / 2); index += 1) { + const element = children[index] as HTMLSpanElement + const matchElement = children[children.length - 1 - index] as HTMLSpanElement + total += element.offsetWidth + matchElement.offsetWidth + if (total > parentElementWidth) return slice + slice += 1 + } + + return null +} + +export const EllipsisName = ({ children, padding = 0, containerRef }: Props) => { + const charArray = children.split('') + + const [name, setName] = useState(children) + + const ref = useRef(null) + const ellipsisRef = useRef(null) + + const guide = (node: HTMLSpanElement) => { + const maxWidth = (containerRef?.current?.offsetWidth || Infinity) - padding + const ellipsisWidth = ellipsisRef.current?.offsetWidth || 0 + const slice = calculateSlice({ node, ellipsisWidth, maxWidth }) + const _name = + slice !== null + ? `${children.slice(0, slice)}\u2026${children.slice(children.length - slice!)}` + : name + setName(_name) + } + + useEffect(() => { + const updateName = () => { + if (ref.current) { + guide(ref.current) + } + } + updateName() + window.addEventListener('resize', updateName) + return () => { + window.removeEventListener('resize', updateName) + } + }, []) + + const dots = '\u2026' + + return ( + + {dots} + + {charArray.map((char, i) => ( + // eslint-disable-next-line react/no-array-index-key + {char} + ))} + + {name} + + ) +} + +export const TransComponentEllipsisName = ({ + children, + href, + ...props +}: { + href?: string + containerRef?: React.RefObject + padding?: number + children?: string[] +}) => { + const name = children?.[0] || '' + const baseComponent = {name} + return href ? {baseComponent} : baseComponent +} diff --git a/src/components/@atoms/Name/Name.tsx b/src/components/@atoms/Name/Name.tsx new file mode 100644 index 000000000..da6364ee1 --- /dev/null +++ b/src/components/@atoms/Name/Name.tsx @@ -0,0 +1,143 @@ +import { useEffect, useRef, useState } from 'react' +import styled, { css } from 'styled-components' +import { match } from 'ts-pattern' + +import { StyledLink } from '../StyledLink' +import { calculateInlineName } from './utils/calculateInlineName' +import { calculateWrapName } from './utils/calculateWrapName' + +const Container = styled.span( + () => css` + word-break: keep-all; + overflow-wrap: normal; + /* display: flex; */ + overflow: hidden; + justify-content: left; + position: relative; + `, +) + +const HiddenSpan = styled.span( + () => css` + position: absolute; + pointer-events: none; + visibility: hidden; + white-space: nowrap; + `, +) + +const VisibleSpan = styled.span<{ type: 'wrap' | 'inline' }>( + ({ type }) => css` + ${type === 'inline' && 'white-space: nowrap;'} + `, +) + +type BaseProps = { + children: string + type: 'wrap' | 'inline' + wrapLines?: number + containerWidth?: number + containerLeft?: number +} + +type InlineProps = { + type: 'inline' + containerWidth: number + wrapLines?: never + containerLeft?: never +} + +type WrapProps = { + type: 'wrap' + wrapLines: number + containerWidth: number + containerLeft: number +} + +type Props = BaseProps & (InlineProps | WrapProps) + +export const Name = ({ + type = 'inline', + wrapLines, + children, + containerWidth, + containerLeft, +}: Props) => { + const charArray = children.split('') + + const [name, setName] = useState(children) + + const ref = useRef(null) + const hiddenRef = useRef(null) + const ellipsisRef = useRef(null) + + const updateLayout = (node: HTMLSpanElement | null) => { + if (!node) return + const _name = match(type) + .with('wrap', () => { + // console.log('wrapper offsets', ref.current?.offsetWidth, ref.current?.offsetLeft) + const nodeRect = node.getBoundingClientRect() + const initialWidth = containerWidth + containerLeft! - nodeRect.left + const ellipsisWidth = ellipsisRef.current?.offsetWidth || 0 + return calculateWrapName({ + name_: children, + node, + ellipsisWidth, + maxWidth: containerWidth, + initialWidth, + maxLines: wrapLines, + }) + }) + .otherwise(() => { + console.log('containerWidth', containerWidth) + const ellipsisWidth = ellipsisRef.current?.offsetWidth || 0 + return calculateInlineName({ + name: children, + node, + ellipsisWidth, + maxWidth: containerWidth, + }) + }) + // console.log('name', _name) + setName(_name) + } + + useEffect(() => { + updateLayout(hiddenRef.current) + }, [containerWidth, containerLeft]) + + useEffect(() => { + const updateLayoutCallback = () => updateLayout(hiddenRef?.current) + window.addEventListener('resize', updateLayoutCallback) + return () => { + window.removeEventListener('resize', updateLayoutCallback) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + return ( + + + + {charArray.map((char, i) => ( + // eslint-disable-next-line react/no-array-index-key + {char} + ))} + + {name} + + ) +} + +export const TransComponentName = ({ + children, + href, + ...props +}: { + href?: string + children?: string[] +} & Omit) => { + const name = children?.[0] || '' + const baseComponent = {name} + return href ? {baseComponent} : baseComponent +} diff --git a/src/components/@atoms/Name/utils/calculateInlineName.test.ts b/src/components/@atoms/Name/utils/calculateInlineName.test.ts new file mode 100644 index 000000000..51377249c --- /dev/null +++ b/src/components/@atoms/Name/utils/calculateInlineName.test.ts @@ -0,0 +1,92 @@ +import { describe, it, expect } from 'vitest'; +import { calculateInlineName } from './calculateInlineName'; +const jsdom = require('jsdom'); +const { JSDOM } = jsdom; + +const longLabel = 'areallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylonglabel' +const longName = 'areallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname.eth' +const longSubname = `${longLabel}.${longName}` + +const createNode = (str: string) => { + const chars = str.split(''); + const innerHtml = chars.map((char) => `${char}`).join('') + const dom = new JSDOM(`
${innerHtml}
`) + const root = dom.window.document.getElementById('root') + + Object.defineProperties(dom.window.HTMLDivElement.prototype, { + offsetWidth: { + get() { + return chars.length * 5 + } + }, + offsetLeft: { + get() { + return 10 + } + } + }) + + Object.defineProperties(dom.window.HTMLSpanElement.prototype, { + offsetWidth: { + get() { + return 5 + } + }, + offsetLeft: { + get() { + return 10 + } + } + }) + + return dom.window.document.getElementById('root') +} + +const removeNonNameSymbols = (str: string) => str.replace(/[\u2026\u200B\u200C]/g, '') + +describe('calculateInlineName', () => { + it('should return the correct result if the first label ends on the right side', () => { + const result = calculateInlineName({ + name: longName, + node: createNode(longName), + ellipsisWidth: 5, + maxWidth: 100, + }) + expect(result).toBe('areallyre…​gname‌.eth') + const ZWNJSplit = result.split('\u200C') + expect(ZWNJSplit).toHaveLength(2) + const ZWSSplit = result.split('\u200B') + console.log(removeNonNameSymbols(ZWSSplit[0]), removeNonNameSymbols(ZWSSplit[1])) + expect(removeNonNameSymbols(ZWSSplit[0]).length).toBe(removeNonNameSymbols(ZWSSplit[1]).length) + }) + + it('should return the correct result if the first label ends on the left side', () => { + const shortSubname = `test.${longName}` + const result = calculateInlineName({ + name: shortSubname, + node: createNode(shortSubname), + ellipsisWidth: 5, + maxWidth: 100, + }) + expect(result).toBe('test\u200C.area…​gname.eth') + const ZWNJSplit = result.split('\u200C') + expect(ZWNJSplit).toHaveLength(2) + const ZWSSplit = result.split('\u200B') + console.log(removeNonNameSymbols(ZWSSplit[0]), removeNonNameSymbols(ZWSSplit[1])) + expect(removeNonNameSymbols(ZWSSplit[0]).length).toBe(removeNonNameSymbols(ZWSSplit[1]).length) + }) + + it('should return the correct result if the first label ends in the middle', () => { + const result = calculateInlineName({ + name: longSubname, + node: createNode(longSubname), + ellipsisWidth: 5, + maxWidth: 100, + }) + expect(result).toBe('areallyre…\u200C\u200Bgname.eth') + const ZWNJSplit = result.split('\u200C') + expect(ZWNJSplit).toHaveLength(2) + const ZWSSplit = result.split('\u200B') + expect(removeNonNameSymbols(ZWSSplit[0]).length).toBe(removeNonNameSymbols(ZWSSplit[1]).length) + }) +}) \ No newline at end of file diff --git a/src/components/@atoms/Name/utils/calculateInlineName.ts b/src/components/@atoms/Name/utils/calculateInlineName.ts new file mode 100644 index 000000000..9a8de35ce --- /dev/null +++ b/src/components/@atoms/Name/utils/calculateInlineName.ts @@ -0,0 +1,52 @@ +import { insertZeroWidthNonJoinerAtLabel } from './sharedFunctions' + +export const calculateInlineName = ({ + name, + node, + ellipsisWidth, + maxWidth, + tolerance = 5, + debug = false, +}: { + name: string + node: HTMLSpanElement | null + ellipsisWidth: number + maxWidth: number + tolerance?: number + debug?: boolean +}) => { + const _name = insertZeroWidthNonJoinerAtLabel(name) + if (debug) console.log('calculateInlineName', _name, node, ellipsisWidth, maxWidth) + if (!node) return _name + + const _maxWidth = maxWidth ?? node.parentElement?.offsetWidth ?? Infinity + const nodeWidth = node.offsetWidth || Infinity + + if (debug) console.log('nodeWidth', nodeWidth, 'parentElementWidth', _maxWidth) + if (nodeWidth <= _maxWidth) return _name + + // We use a tolerance because the offsetWidth of the individual characters are rounded to the nearest integer, which creates a potential for inaccuracies. + const _tolerance = 1 - Math.max(0, Math.min(100, tolerance)) / 100 + const maxWidthWithTolerance = _maxWidth * _tolerance + + const children = node?.children || [] + let slice = 0 + let total = ellipsisWidth + for (let index = 0; index < Math.floor((children.length - 1) / 2); index += 1) { + const element = children[index] as HTMLSpanElement + const matchElement = children[children.length - 1 - index] as HTMLSpanElement + total += element.offsetWidth + matchElement.offsetWidth + if (total >= maxWidthWithTolerance) { + const right = _name.slice(_name.length - slice) + if (right.includes('\u200C')) + return `${_name.slice(0, slice)}\u2026\u200B${_name.slice(_name.length - slice - 1)}` + const left = _name.slice(0, slice) + if (left.includes('\u200C')) + return `${_name.slice(0, slice + 1)}\u2026\u200B${_name.slice(_name.length - slice)}` + return `${left}\u2026\u200C\u200B${right}` + } + slice += 1 + } + if (debug) console.log('name', _name) + return _name +} diff --git a/src/components/@atoms/Name/utils/calculateWrapName.test.ts b/src/components/@atoms/Name/utils/calculateWrapName.test.ts new file mode 100644 index 000000000..96b1a0fdd --- /dev/null +++ b/src/components/@atoms/Name/utils/calculateWrapName.test.ts @@ -0,0 +1,147 @@ +import { describe, it, expect } from 'vitest' +import { calculateWrapName, findNumbersAddingUpToSum, insertSpecialSymbols, sliceStringByNumbers } from './calculateWrapName' +import { insertZeroWidthNonJoinerAtLabel } from './sharedFunctions' +const jsdom = require('jsdom') +const { JSDOM } = jsdom + +const longName = 'areallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname.eth' + +const createNode = (str: string) => { + const innerHtml = str.split('').map((char) => `${char}`).join('') + const dom = new JSDOM(`${innerHtml}`) + + Object.defineProperties(dom.window.HTMLSpanElement.prototype, { + offsetWidth: { + get() { + return 5 + } + }, + offsetLeft: { + get() { + return 10 + } + } + }) + + return dom.window.document.getElementById('root') +} + +const removeSpecialCharacters = (str: string) => str.replace(/[\u2026\u200B\u200C]/g, '') + +describe('findNumbersAddingUpToSum', () => { + it('should return numbers that add up just below the sum', () => { + const result = findNumbersAddingUpToSum([1, 2, 3, 4, 5], 7) + expect(result).toEqual([1, 2, 3]) + }) + + it('should return numbers that add up exactly to the sum', () => { + const result = findNumbersAddingUpToSum([1, 2, 3, 4, 5], 10) + expect(result).toEqual([1, 2, 3, 4]) + }) + + it('should return all the numbers if they do not add up to the sum', () => { + const result = findNumbersAddingUpToSum([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 700) + expect(result).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) + }) + + it('should return an empty array if the sum is 0', () => { + const result = findNumbersAddingUpToSum([1, 2, 3, 4, 5], 0) + expect(result).toEqual([]) + }) +}) + +describe('sliceStringByNumbers', () => { + it('should fill in the array with characters as long as there is a number available', () => { + const result = sliceStringByNumbers([1, 2, 3, 4, 5], 'helloworld!') + expect(result).toEqual(['h', 'el', 'low', 'orld', '!']) + }) + + it('should stop splitting the array once it has run out of characters', () => { + const result = sliceStringByNumbers([1, 2, 3, 4, 5, 6, 7], 'helloworld!') + expect(result).toEqual(['h', 'el', 'low', 'orld', '!']) + }) + + it('should stop splitting the array once it has run out of numbers', () => { + const result = sliceStringByNumbers([1], 'helloworld!') + expect(result).toEqual(['h']) + }) +}) + +describe('injectSpecialSymbols', () => { + const label = 'onetwothreefourfivesixseveneightnine' + const name = `${label}.eth` + const subname = `${label}.${name}` + + it('should return name if array is slices is single value', () => { + const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(name) + const result = insertSpecialSymbols(nameWithZWNJ, [name.length]) + expect(result).toEqual(nameWithZWNJ) + }) + + it('should return correct an ellipsis string ', () => { + const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(name) + const result = insertSpecialSymbols(nameWithZWNJ, [5,5]) + expect(result).toEqual('onetw\u2026\u200Be\u200C.eth') + }) + + it('should return correct an ellipsis string ', () => { + const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(name) + const result = insertSpecialSymbols(nameWithZWNJ, [5,5,5]) + expect(result).toEqual('onetw\u2026\u200Bothre\u2026\u200Be\u200C.eth') + }) + + it('should return correct an ellipsis string ', () => { + const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(name) + const result = insertSpecialSymbols(nameWithZWNJ, [10,10,10,10]) + expect(result).toEqual('onetwothre\u2026\u200Befourfives\u2026\u200Bixseveneig\u2026\u200Bhtnine\u200C.eth') + }) + + it('should return correct result if ZWNJ is on left side', () => { + const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(`123.${name}`) + const result = insertSpecialSymbols(nameWithZWNJ, [5,5]) + expect(result).toEqual('123\u200C.o\u2026\u200Be.eth') + }) + + it('should return correct result if ZWNJ is in middle side', () => { + const nameWithZWNJ = insertZeroWidthNonJoinerAtLabel(subname) + const result = insertSpecialSymbols(nameWithZWNJ, [5,5]) + expect(result).toEqual('onetw\u2026\u200B\u200Ce.eth') + }) + +}) + +describe('calculateWrapName', () => { + it('should return the correct result', () => { + const result = calculateWrapName({ + name: longName, + node: createNode(longName), + ellipsisWidth: 5, + initialWidth: 100, + maxWidth: 500, + maxLines: Infinity + }) + expect(result).toEqual('areallyreallyreally…​reallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyrea…​llyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreally…​reallylongname.eth') + console.log('areallyreallyreally…​reallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyrea…​llyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreally…​eallylongname‌.eth') + const resultParts = result.split('…​') + expect(resultParts[0]).toHaveLength(19) + expect(resultParts[1]).toHaveLength(99) + expect(resultParts[2]).toHaveLength(99) + expect(resultParts[3]).toHaveLength(longName.length - 19 - 99 - 99) + }) + + it.only('should return the correct result', () => { + const result = calculateWrapName({ + name: longName, + node: createNode(longName), + ellipsisWidth: 5, + initialWidth: 100, + maxWidth: 500, + maxLines: 2, + debug: true + }) + expect(result).toEqual('areallyreallyreall…​allyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongname\u200C.eth') + const resultParts = result.split('…​') + expect(resultParts[0]).toHaveLength(19) + expect(resultParts[1]).toHaveLength(100) + }) +}) diff --git a/src/components/@atoms/Name/utils/calculateWrapName.ts b/src/components/@atoms/Name/utils/calculateWrapName.ts new file mode 100644 index 000000000..69abf7d90 --- /dev/null +++ b/src/components/@atoms/Name/utils/calculateWrapName.ts @@ -0,0 +1,141 @@ +import { insertZeroWidthNonJoinerAtLabel } from './sharedFunctions' + +export const findNumbersAddingUpToSum = (numbers: number[], sum: number) => { + let index = 0 + let total = 0 + while (index < numbers.length) { + const num = numbers[index] + if (total + num > sum) break + total += num + index += 1 + } + return numbers.slice(0, index) +} + +export const sliceStringByNumbers = (numbers: number[], str: string): string[] => { + const result = [] + let startIdx = 0 + for (let i = 0; i < numbers.length; i += 1) { + const sliceLength = numbers[i] + const slice = str.slice(startIdx, startIdx + sliceLength) + if (slice.length > 0) result.push(slice) + startIdx += sliceLength + } + + return result +} + +const sliceByLengthAndDirection = (str: string, start: number, length: number, reverse: boolean) => + reverse ? str.slice(-length) : str.slice(start, start + length) + +export const insertSpecialSymbols = (name: string, slices: number[]): string => { + let slicedName = '' + let sliceStart = 0 + let hasFoundZWNJ = false + + for (let i = 0; i < slices.length; i += 1) { + const isLastSlice = i === slices.length - 1 + const sliceLength = slices[i] + const slice = sliceByLengthAndDirection(name, sliceStart, sliceLength, isLastSlice) + + const sliceContainsZWNJ = slice.includes('\u200C') + const adjustedSliceLength = sliceContainsZWNJ ? sliceLength + 1 : sliceLength + const adjustedSlice = sliceContainsZWNJ + ? sliceByLengthAndDirection(name, sliceStart, adjustedSliceLength, isLastSlice) + : slice + + hasFoundZWNJ = hasFoundZWNJ || sliceContainsZWNJ + const prefix = isLastSlice && !hasFoundZWNJ ? '\u200C' : '' + const postfix = isLastSlice ? '' : '…\u200B' + + sliceStart += adjustedSliceLength + slicedName += `${prefix}${adjustedSlice}${postfix}` + } + return slicedName +} + +export const calculateWrapName = ({ + name, + node, + ellipsisWidth, + maxWidth, + initialWidth = maxWidth, + minInitialWidth = 0, + maxLines = Infinity, + tolerance = 3, + debug = false, +}: { + name: string + node: HTMLSpanElement | null + ellipsisWidth: number + maxWidth: number + initialWidth?: number + minInitialWidth?: number + maxLines?: number + tolerance?: number + debug?: boolean +}): string => { + if (debug) + console.log( + 'calculateWrapName', + name, + node, + ellipsisWidth, + maxWidth, + initialWidth, + minInitialWidth, + maxLines, + ) + + const name_ = insertZeroWidthNonJoinerAtLabel(name) || '' + if (!node) { + console.error('node is null') + + return name_ || '' + } + + const initialWidth_ = initialWidth < minInitialWidth ? maxWidth : initialWidth + + const decimalTolerance = 1 - Math.max(0, Math.min(100, tolerance)) / 100 + const initialWidthWithTolerance = initialWidth_ * decimalTolerance + const maxWidthWithTolerance = maxWidth * decimalTolerance + + let currentGroup: number[] = [] + let currentGroupTotal = 0 + let result: number[][] = [] + console.log('testing', maxWidth, maxWidthWithTolerance) + const children = node?.children || [] + for (let index = 0; index < children.length; index += 1) { + const element = children[index] as HTMLSpanElement + const charWidth = element.offsetWidth + currentGroupTotal += charWidth + const currentMaxWidth = result.length === 0 ? initialWidthWithTolerance : maxWidthWithTolerance + // if (debug) + // console.log('charWidth', charWidth, 'currentGroupTotal', currentGroupTotal, currentMaxWidth) + if (currentGroupTotal + ellipsisWidth > currentMaxWidth) { + result.push(currentGroup) + currentGroup = [charWidth] + currentGroupTotal = charWidth + } else { + currentGroup.push(charWidth) + } + } + if (currentGroup.length) result.push(currentGroup) + + // console.log(result.length, lines) + if (result.length > maxLines) { + const left = result.slice(0, maxLines - 1) + const right = result + .slice(maxLines - 1) + .reverse() + .flat() + // console.log('left', left, right) + const filteredRight = findNumbersAddingUpToSum(right, maxWidthWithTolerance) + result = [...left, filteredRight] + } + + const slices = result.map((group) => group.length) + console.log('slices', slices) + + return insertSpecialSymbols(name_, slices) +} diff --git a/src/components/@atoms/Name/utils/sharedFunctions.test.ts b/src/components/@atoms/Name/utils/sharedFunctions.test.ts new file mode 100644 index 000000000..3d448e7a8 --- /dev/null +++ b/src/components/@atoms/Name/utils/sharedFunctions.test.ts @@ -0,0 +1,23 @@ +import { describe, it, expect } from 'vitest' + +import { insertZeroWidthNonJoinerAtLabel } from './sharedFunctions' + + +describe('insertZeroWidthNonJoinerAtLabel', () => { + it('should insert a ZWNJ after the first label', () => { + const name = insertZeroWidthNonJoinerAtLabel('name.com') + expect(name).toBe('name\u200C.com') + }) + + it('should insert a ZWNJ after the first label with multiple labels', () => { + const name = insertZeroWidthNonJoinerAtLabel('name.co.uk') + expect(name).toBe('name\u200C.co.uk') + }) + + it('should be able to split resulting name by ZWNJ', () => { + const name = insertZeroWidthNonJoinerAtLabel('name.co.uk') + const [label, ...rest] = name.split('\u200C') + expect(label).toBe('name') + expect(rest.join('')).toBe('.co.uk') + }) +}) \ No newline at end of file diff --git a/src/components/@atoms/Name/utils/sharedFunctions.ts b/src/components/@atoms/Name/utils/sharedFunctions.ts new file mode 100644 index 000000000..af7b0fe78 --- /dev/null +++ b/src/components/@atoms/Name/utils/sharedFunctions.ts @@ -0,0 +1,5 @@ +export const insertZeroWidthNonJoinerAtLabel = (name: string) => { + if (!name) return + const [label, ...rest] = name.split('.') + return [`${label}\u200C`, ...rest].join('.') +} diff --git a/src/components/@atoms/Name2/Name.tsx b/src/components/@atoms/Name2/Name.tsx new file mode 100644 index 000000000..33fb862f1 --- /dev/null +++ b/src/components/@atoms/Name2/Name.tsx @@ -0,0 +1,211 @@ +import { useRef, useSyncExternalStore } from 'react' +import styled, { css } from 'styled-components' +import { match } from 'ts-pattern' + +import { calculateInlineName } from '../Name/utils/calculateInlineName' +import { calculateWrapName } from '../Name/utils/calculateWrapName' +import { StyledLink } from '../StyledLink' + +const Container = styled.span( + () => css` + word-break: keep-all; + overflow-wrap: normal; + /* display: flex; */ + overflow: hidden; + justify-content: left; + position: relative; + `, +) + +const HiddenSpan = styled.span( + () => css` + position: absolute; + pointer-events: none; + visibility: hidden; + white-space: nowrap; + font-weight: bold; + `, +) + +const VisibleSpan = styled.span<{ type: 'wrap' | 'inline' }>( + ({ type }) => css` + ${type === 'inline' && 'white-space: nowrap;'} + `, +) + +const LeadSpan = styled.span( + () => css` + /* font-weight: bold; */ + `, +) + +const TrailingSpan = styled.span( + ({ theme }) => css` + color: ${theme.colors.textTertiary}; + /* font-weight: bold; */ + `, +) + +type BaseProps = { + children: string + type: 'wrap' | 'inline' + wrapLines?: number + maxWidth?: number + initialWidth?: number + minInitialWidth?: number + rootRef?: React.RefObject + nextTick?: boolean + debug?: boolean + tolerance?: number +} + +type InlineProps = { + type: 'inline' + maxWidth: number + wrapLines?: never + initialWidth?: never +} + +type WrapProps = { + type: 'wrap' + wrapLines: number + maxWidth: number + initialWidth: number + minInitialWidth?: number +} + +type Props = BaseProps & (InlineProps | WrapProps) + +export const Name = ({ + type = 'inline', + wrapLines, + children, + maxWidth, + initialWidth, + minInitialWidth, + rootRef, + nextTick, + tolerance, + debug, +}: Props) => { + if (debug) + console.log( + 'Name', + children, + 'type', + type, + 'maxWidth', + maxWidth, + 'initialWidth', + initialWidth, + 'minInitialWidth', + minInitialWidth, + 'wrapLines', + wrapLines, + 'rootRef', + rootRef, + 'debug', + debug, + ) + const name = children + const charArray = name.split('') + + const ref = useRef(null) + const hiddenRef = useRef(null) + const ellipsisRef = useRef(null) + + const rootOrComponentRef = rootRef || ref + + const updateLayout = () => { + return match(type) + .with('wrap', () => { + console.log(rootOrComponentRef) + const ellipsisWidth = ellipsisRef.current?.offsetWidth || 0 + const maxWidth_ = + maxWidth ?? rootOrComponentRef.current?.offsetParent?.offsetWidth ?? Infinity + const hiddenLeft = hiddenRef.current?.getBoundingClientRect().left ?? 0 + const rootLeft = rootOrComponentRef.current?.offsetParent?.getBoundingClientRect().left ?? 0 + const initialWidth_ = initialWidth ?? maxWidth_ - hiddenLeft + rootLeft + + console.log('maxWidth_', maxWidth_, initialWidth_) + return calculateWrapName({ + name: children, + node: hiddenRef.current, + ellipsisWidth, + maxWidth: maxWidth_, + initialWidth: initialWidth_, + minInitialWidth, + maxLines: wrapLines, + tolerance, + debug, + }) + }) + .otherwise(() => { + const ellipsisWidth = ellipsisRef.current?.offsetWidth || 0 + return calculateInlineName({ + name: children, + node: hiddenRef.current, + ellipsisWidth, + maxWidth, + tolerance, + debug, + }) + }) + } + + const name2 = useSyncExternalStore( + (onStoreChange) => { + console.log('SUBSCRIBE') + window.addEventListener('resize', onStoreChange) + if (nextTick) + process.nextTick(() => { + onStoreChange() + }) + return () => { + window.removeEventListener('resize', onStoreChange) + } + }, + () => updateLayout(), + () => '', + ) + + const nameParts = name2?.split('\u200C') + return ( + + + + {charArray.map((char, i) => ( + // eslint-disable-next-line react/no-array-index-key + {char} + ))} + + + {nameParts?.[0]} + {nameParts?.[1]} + + + ) +} + +export const TransComponentName = ({ + children, + href, + ...props +}: { + href?: string + children?: string[] +} & Omit) => { + const rootRef = useRef(null) + const name = Array.isArray(children) ? children[0] : children + console.log('TRANS COMPONENT NAME', 'name', name, 'children', children) + if (href) { + return ( + + + {name} + + + ) + } + return {name} +} diff --git a/src/components/@atoms/StyledLink.tsx b/src/components/@atoms/StyledLink.tsx index eaa58b83a..2098556ef 100644 --- a/src/components/@atoms/StyledLink.tsx +++ b/src/components/@atoms/StyledLink.tsx @@ -1,4 +1,4 @@ -import { PropsWithChildren } from 'react' +import { forwardRef, PropsWithChildren } from 'react' import styled, { css } from 'styled-components' import BaseLink from '@app/components/@atoms/BaseLink' @@ -25,14 +25,21 @@ const StyledAnchor = styled.a<{ `} `, ) -export const StyledLink = ({ - href, - color = 'accent', - children, -}: PropsWithChildren<{ href: string; color?: 'accent' | 'grey' }>) => { - return ( - - {children} - - ) -} +export const StyledLink = forwardRef( + ( + { + href, + color = 'accent', + children, + }: PropsWithChildren<{ href: string; color?: 'accent' | 'grey' }>, + ref, + ) => { + return ( + + + {children} + + + ) + }, +) diff --git a/src/components/@molecules/AvatarWithIdentifier/AvatarWithIdentifier.tsx b/src/components/@molecules/AvatarWithIdentifier/AvatarWithIdentifier.tsx index bf3a6cfe4..2a201fc88 100644 --- a/src/components/@molecules/AvatarWithIdentifier/AvatarWithIdentifier.tsx +++ b/src/components/@molecules/AvatarWithIdentifier/AvatarWithIdentifier.tsx @@ -1,9 +1,13 @@ +import { useRef } from 'react' import styled, { css } from 'styled-components' import { Address } from 'viem' import { Typography } from '@ensdomains/thorin' +import { Name } from '@app/components/@atoms/Name2/Name' import { AvatarWithZorb } from '@app/components/AvatarWithZorb' +import { useElementDimensions } from '@app/hooks/dom/useElementDimensions' +import { useRemPixelValue } from '@app/hooks/dom/useRemPixelValue' import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName' import { QuerySpace } from '@app/types' import { shortenAddress } from '@app/utils/utils' @@ -15,11 +19,15 @@ const Container = styled.div( align-items: center; justify-content: flex-start; gap: ${theme.space['2']}; + position: relative; + overflow: hidden; `, ) const TextContainer = styled.div( () => css` + flex: 1; + overflow: hidden; display: flex; flex-direction: column; align-items: flex-start; @@ -41,6 +49,7 @@ type Props = { subtitle?: string size?: QuerySpace shortenAddressAsTitle?: boolean + maxWidth?: number } export const AvatarWithIdentifier = ({ @@ -49,6 +58,7 @@ export const AvatarWithIdentifier = ({ subtitle, size = '10', shortenAddressAsTitle = true, + maxWidth, }: Props) => { const primary = usePrimaryName({ address, @@ -60,16 +70,21 @@ export const AvatarWithIdentifier = ({ const _subtitle = subtitle || (_name ? shortenAddress(address) : undefined) const isTitleFullAddress = !shortenAddressAsTitle && !_name + const ref = useRef(null) + const { width } = useElementDimensions({ ref }) + const remPixelValue = useRemPixelValue() + console.log('remPixelValue', remPixelValue) + console.log('AvatarWithIdentifier', maxWidth, width) return ( - + {isTitleFullAddress ? ( {_title} ) : ( - - {_title} + + {_title} )} {_subtitle && ( diff --git a/src/components/@molecules/NameListView/NameListView.tsx b/src/components/@molecules/NameListView/NameListView.tsx index c9d490bfb..f2f7bc7fb 100644 --- a/src/components/@molecules/NameListView/NameListView.tsx +++ b/src/components/@molecules/NameListView/NameListView.tsx @@ -164,7 +164,7 @@ export const NameListView = ({ address, selfAddress, setError, setLoading }: Nam ) const isLoading = isNamesLoading || !address - + console.log('names', names) let InnerContent: ReactNode if (!isMounted) { InnerContent = null diff --git a/src/components/@molecules/RecordItemWithName/RecordItemWithName.tsx b/src/components/@molecules/RecordItemWithName/RecordItemWithName.tsx new file mode 100644 index 000000000..9dd615f43 --- /dev/null +++ b/src/components/@molecules/RecordItemWithName/RecordItemWithName.tsx @@ -0,0 +1,60 @@ +import { ComponentProps, useRef, useSyncExternalStore } from 'react' + +import { RecordItem, Typography } from '@ensdomains/thorin' + +import { Name } from '@app/components/@atoms/Name2/Name' +import { useRemPixelValue } from '@app/hooks/dom/useRemPixelValue' +import { useBreakpoint } from '@app/utils/BreakpointProvider' + +type RecordItemProps = ComponentProps +type Props = { name: string } & RecordItemProps +export const RecordItemWithName = ({ name, keyLabel, ...props }: Props) => { + const ref = useRef(null) + const ref2 = useRef(null) + + const breakpoints = useBreakpoint() + const remPixelValue = useRemPixelValue() + + const maxWidth = useSyncExternalStore( + (onStoreChange) => { + window.addEventListener('resize', onStoreChange) + return () => { + window.removeEventListener('resize', onStoreChange) + } + }, + () => { + if (!ref.current || !ref2.current || !ref.current.parentElement) return undefined + const label = ref2.current.offsetWidth + const width = ref.current.parentElement.offsetWidth + const padding = remPixelValue * 2 * 0.75 + const gap = remPixelValue * 2 * 0.5 + const ellipsis = remPixelValue * 0.75 + const result = width - padding - gap - label - ellipsis + return result + }, + () => { + return undefined + }, + ) + + return ( + + {keyLabel} + + } + > + + {name} + + + ) +} diff --git a/src/components/@molecules/TransactionDialogManager/DisplayItems.tsx b/src/components/@molecules/TransactionDialogManager/DisplayItems.tsx index 20d967577..0c6ff28cd 100644 --- a/src/components/@molecules/TransactionDialogManager/DisplayItems.tsx +++ b/src/components/@molecules/TransactionDialogManager/DisplayItems.tsx @@ -5,6 +5,7 @@ import { Address } from 'viem' import { Typography } from '@ensdomains/thorin' +import { Name } from '@app/components/@atoms/Name2/Name' import { AvatarWithZorb, NameAvatar } from '@app/components/AvatarWithZorb' import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName' import { useBeautifiedName } from '@app/hooks/useBeautifiedName' @@ -134,7 +135,10 @@ const NameValue = ({ value }: { value: string }) => { return ( - {beautifiedName} + {/* {beautifiedName} */} + + {beautifiedName} + diff --git a/src/components/pages/import/[name]/steps/CompleteImport.tsx b/src/components/pages/import/[name]/steps/CompleteImport.tsx index 36eafa632..86c99ece0 100644 --- a/src/components/pages/import/[name]/steps/CompleteImport.tsx +++ b/src/components/pages/import/[name]/steps/CompleteImport.tsx @@ -49,6 +49,7 @@ const TitleContainer = styled.div( flex-direction: column; align-items: center; justify-content: center; + word-break: break-all; gap: ${theme.space['2']}; `, ) diff --git a/src/components/pages/profile/ProfileButton.tsx b/src/components/pages/profile/ProfileButton.tsx index cafe870f3..ce344e596 100644 --- a/src/components/pages/profile/ProfileButton.tsx +++ b/src/components/pages/profile/ProfileButton.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react' +import { useMemo, useRef } from 'react' import { useTranslation } from 'react-i18next' import styled, { css } from 'styled-components' import { Address, isAddress } from 'viem' @@ -10,6 +10,9 @@ import { RecordItem, Typography } from '@ensdomains/thorin' import { DynamicAddressIcon } from '@app/assets/address/DynamicAddressIcon' import { dynamicAddressIcons } from '@app/assets/address/dynamicAddressIcons' import { DynamicSocialIcon, socialIconTypes } from '@app/assets/social/DynamicSocialIcon' +import { Name } from '@app/components/@atoms/Name/Name' +import { RecordItemWithName } from '@app/components/@molecules/RecordItemWithName/RecordItemWithName' +import { useElementDimensions } from '@app/hooks/dom/useElementDimensions' import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName' import { getDestination } from '@app/routes' import { useBreakpoint } from '@app/utils/BreakpointProvider' @@ -254,6 +257,24 @@ export const OwnerProfileButton = ({ t, ]) + const isAddressWithName = dataType === 'address' && primary.data?.name + const isParentWithName = dataType === 'name' + const isRecordItemWithName = isAddressWithName || isParentWithName + if (isRecordItemWithName) { + const name = isAddressWithName ? primary.data?.name : addressOrNameOrDate + return ( + + ) + } return ( css` + position: relative; + overflow: hidden; + width: 100%; + `, +) + const SectionTitle = styled(Typography)(({ theme }) => [ css` color: ${theme.colors.greyPrimary}; @@ -74,7 +82,7 @@ const ProfileSection = ({ : [] return condition ? ( -
+ {t(label)} {supportedArray.map((item: { key: string; value: string; type?: 'text' | 'address' }) => ( @@ -87,7 +95,7 @@ const ProfileSection = ({ ), )} -
+ ) : null } diff --git a/src/components/pages/profile/[name]/Profile.tsx b/src/components/pages/profile/[name]/Profile.tsx index 7fcec0d60..a57c47ba2 100644 --- a/src/components/pages/profile/[name]/Profile.tsx +++ b/src/components/pages/profile/[name]/Profile.tsx @@ -7,6 +7,7 @@ import { useAccount } from 'wagmi' import { Banner, CheckCircleSVG, Typography } from '@ensdomains/thorin' import BaseLink from '@app/components/@atoms/BaseLink' +import { TransComponentName } from '@app/components/@atoms/Name2/Name' import { Outlink } from '@app/components/Outlink' import { useAbilities } from '@app/hooks/abilities/useAbilities' import { useChainName } from '@app/hooks/chain/useChainName' @@ -79,14 +80,24 @@ export const NameAvailableBanner = ({ normalisedName: string expiryDate?: Date }) => { - const { t } = useTranslation('profile') return ( } - title={t('banner.available.title', { name: normalisedName })} + title={ + , + }} + /> + } > }} + components={{ + strong: , + }} /> diff --git a/src/components/pages/profile/[name]/registration/steps/Complete.tsx b/src/components/pages/profile/[name]/registration/steps/Complete.tsx index 0901eef0f..3062ce131 100644 --- a/src/components/pages/profile/[name]/registration/steps/Complete.tsx +++ b/src/components/pages/profile/[name]/registration/steps/Complete.tsx @@ -70,6 +70,12 @@ const TitleContainer = styled.div( `, ) +const NameContainer = styled.span( + () => css` + word-break: break-all; + `, +) + const Title = styled(Typography)( ({ theme }) => css` font-size: ${theme.fontSizes.headingOne}; @@ -282,7 +288,10 @@ const Complete = ({ name, beautifiedName, callback, isMoonpayFlow }: Props) => { {t('steps.complete.heading')} {t('steps.complete.subheading')} - {nameWithColourEmojis} +
+ + {nameWithColourEmojis} +
{t('steps.complete.description')} diff --git a/src/components/pages/profile/[name]/tabs/OwnershipTab/hooks/useOwnershipWarning.tsx b/src/components/pages/profile/[name]/tabs/OwnershipTab/hooks/useOwnershipWarning.tsx index 104397773..c87795488 100644 --- a/src/components/pages/profile/[name]/tabs/OwnershipTab/hooks/useOwnershipWarning.tsx +++ b/src/components/pages/profile/[name]/tabs/OwnershipTab/hooks/useOwnershipWarning.tsx @@ -2,6 +2,7 @@ import { useMemo } from 'react' import { Trans, useTranslation } from 'react-i18next' import { match, P } from 'ts-pattern' +import { TransComponentName } from '@app/components/@atoms/Name2/Name' import { useAccountSafely } from '@app/hooks/account/useAccountSafely' import type { useNameType } from '@app/hooks/nameType/useNameType' import type { useNameDetails } from '@app/hooks/useNameDetails' @@ -87,10 +88,13 @@ export const useOwnershipWarning = ({ name, nameType, details }: Input) => { t={t} i18nKey="tabs.ownership.warning.managerNotParentOwner" values={{ parent: parentName(name) }} + components={{ + nameComponent: , + }} /> ), ) - .otherwise(() => undefined) + .otherwise(() => null) }, [ isLoading, name, diff --git a/src/components/pages/profile/[name]/tabs/OwnershipTab/sections/RolesSection/components/RoleRow.tsx b/src/components/pages/profile/[name]/tabs/OwnershipTab/sections/RolesSection/components/RoleRow.tsx index b96775d79..368c3ea8f 100644 --- a/src/components/pages/profile/[name]/tabs/OwnershipTab/sections/RolesSection/components/RoleRow.tsx +++ b/src/components/pages/profile/[name]/tabs/OwnershipTab/sections/RolesSection/components/RoleRow.tsx @@ -1,4 +1,4 @@ -import { useMemo } from 'react' +import { useMemo, useRef } from 'react' import { useTranslation } from 'react-i18next' import { useCopyToClipboard } from 'react-use' import styled, { css } from 'styled-components' @@ -16,6 +16,7 @@ import { import { AvatarWithIdentifier } from '@app/components/@molecules/AvatarWithIdentifier/AvatarWithIdentifier' import { useChainName } from '@app/hooks/chain/useChainName' +import { useElementDimensions } from '@app/hooks/dom/useElementDimensions' import { usePrimaryName } from '@app/hooks/ensjs/public/usePrimaryName' import type { Role } from '@app/hooks/ownership/useRoles/useRoles' import { useRouterWithHistory } from '@app/hooks/useRouterWithHistory' @@ -42,6 +43,7 @@ const InnerContainer = styled.div( flex-flow: row wrap; justify-content: space-between; align-items: center; + overflow: hidden; gap: ${theme.space[4]}; `, @@ -67,6 +69,7 @@ type Props = { export const RoleRow = ({ name, address, roles, actions, isWrapped, isEmancipated }: Props) => { const router = useRouterWithHistory() const { t } = useTranslation('common') + const containerRef = useRef(null) const primary = usePrimaryName({ address: address!, enabled: !!address }) const networkName = useChainName() @@ -127,12 +130,20 @@ export const RoleRow = ({ name, address, roles, actions, isWrapped, isEmancipate const { isLoading } = primary + const { width: maxContentWidth } = useElementDimensions({ ref: containerRef }) + console.log('test', maxContentWidth) + if (!address || address === emptyAddress || isLoading) return null return ( <> - - + + {roles?.map((role) => ( diff --git a/src/components/pages/profile/[name]/tabs/OwnershipTab/sections/RolesSection/components/RoleTag.tsx b/src/components/pages/profile/[name]/tabs/OwnershipTab/sections/RolesSection/components/RoleTag.tsx index e95b41bb1..48a439943 100644 --- a/src/components/pages/profile/[name]/tabs/OwnershipTab/sections/RolesSection/components/RoleTag.tsx +++ b/src/components/pages/profile/[name]/tabs/OwnershipTab/sections/RolesSection/components/RoleTag.tsx @@ -1,10 +1,12 @@ import { TOptions } from 'i18next' -import { useTranslation } from 'react-i18next' +import { Trans, useTranslation } from 'react-i18next' import styled, { css } from 'styled-components' import { OutlinkSVG, QuestionCircleSVG, Tooltip, Typography } from '@ensdomains/thorin' +import { TransComponentName } from '@app/components/@atoms/Name2/Name' import { Role } from '@app/hooks/ownership/useRoles/useRoles' +import { useBreakpoint } from '@app/utils/BreakpointProvider' import { parentName } from '@app/utils/name' import { getSupportLink } from '@app/utils/supportLinks' @@ -17,6 +19,8 @@ const TooltipContent = styled.div( text-align: center; color: ${theme.colors.indigo}; pointer-events: all; + position: relative; + overflow: hidden; `, ) @@ -59,8 +63,10 @@ export const RoleTag = ({ isEmancipated: boolean }) => { const { t } = useTranslation('profile') + const breakpoints = useBreakpoint() const _role = isEmancipated && role === 'owner' ? 'owner-emancipated' : role const tOptions: TOptions = role === 'parent-owner' ? { parent: parentName(name) } : {} + const maxWidth = breakpoints.sm ? 200 : 120 const link = getSupportLink(_role) return ( - {t(`tabs.ownership.tooltips.${_role}`, tOptions)} + , + }} + /> + {/* {t(`tabs.ownership.tooltips.${_role}`, tOptions)} */} {link && ( diff --git a/src/components/pages/profile/[name]/tabs/PermissionsTab/OwnershipPermissions.tsx b/src/components/pages/profile/[name]/tabs/PermissionsTab/OwnershipPermissions.tsx index e9e914fc1..79428b08d 100644 --- a/src/components/pages/profile/[name]/tabs/PermissionsTab/OwnershipPermissions.tsx +++ b/src/components/pages/profile/[name]/tabs/PermissionsTab/OwnershipPermissions.tsx @@ -1,11 +1,11 @@ -import { useMemo } from 'react' +import { useMemo, useRef } from 'react' import { Trans, useTranslation } from 'react-i18next' import styled, { css } from 'styled-components' import { GetWrapperDataReturnType } from '@ensdomains/ensjs/public' import { Button, Typography } from '@ensdomains/thorin' -import { StyledLink } from '@app/components/@atoms/StyledLink' +import { TransComponentName } from '@app/components/@atoms/Name2/Name' import type { useFusesSetDates } from '@app/hooks/fuses/useFusesSetDates' import type { useFusesStates } from '@app/hooks/fuses/useFusesStates' import { useTransactionFlow } from '@app/transaction-flow/TransactionFlowProvider' @@ -50,6 +50,9 @@ export const OwnershipPermissions = ({ }: Props) => { const { t } = useTranslation('profile') + const ownershipStatusContainerRef = useRef(null) + const editorStatusContainerRef = useRef(null) + const { usePreparedDataInput } = useTransactionFlow() const showRevokePermissionsInput = usePreparedDataInput('RevokePermissions') @@ -128,13 +131,27 @@ export const OwnershipPermissions = ({ return (
{ownershipStatus === 'parent-cannot-control' && ( - + }} + components={{ + nameComponent: ( + + ), + }} /> {fusesSetDates?.PARENT_CANNOT_CONTROL && ( @@ -163,13 +180,22 @@ export const OwnershipPermissions = ({ )} {ownershipStatus === 'parent-can-control' && ( - - + + }} + components={{ + nameComponent: ( + + ), + }} /> @@ -207,13 +233,27 @@ export const OwnershipPermissions = ({ )} {editorStatus === 'parent-can-change-permissions' && ( - + }} + components={{ + nameComponent: ( + + ), + }} /> diff --git a/src/components/pages/profile/[name]/tabs/PermissionsTab/PermissionsTab.tsx b/src/components/pages/profile/[name]/tabs/PermissionsTab/PermissionsTab.tsx index 7945798b7..a6428bb81 100644 --- a/src/components/pages/profile/[name]/tabs/PermissionsTab/PermissionsTab.tsx +++ b/src/components/pages/profile/[name]/tabs/PermissionsTab/PermissionsTab.tsx @@ -1,3 +1,4 @@ +import { useRef } from 'react' import { Trans, useTranslation } from 'react-i18next' import styled, { css } from 'styled-components' @@ -6,6 +7,7 @@ import { Banner } from '@ensdomains/thorin' import BaseLink from '@app/components/@atoms/BaseLink' import { CacheableComponent } from '@app/components/@atoms/CacheableComponent' +import { TransComponentName } from '@app/components/@atoms/Name2/Name' import { useAbilities } from '@app/hooks/abilities/useAbilities' import { useFusesSetDates } from '@app/hooks/fuses/useFusesSetDates' import { useFusesStates } from '@app/hooks/fuses/useFusesStates' @@ -32,11 +34,22 @@ const Container = styled(CacheableComponent)( `, ) +const BannerContent = styled.div( + () => css` + overflow: hidden; + width: 100%; + position: relative; + `, +) + export const PermissionsTab = ({ name, wrapperData, isCached: isBasicCached }: Props) => { const { t } = useTranslation('profile') + const bannerRef = useRef(null) + const nameParts = name.split('.') const parentName = nameParts.slice(1).join('.') + console.log('>>>', parentName) const is2LDEth = nameParts.length === 2 && nameParts[1] === 'eth' const isSubname = nameParts.length > 2 @@ -60,11 +73,18 @@ export const PermissionsTab = ({ name, wrapperData, isCached: isBasicCached }: P {showUnwrapWarning && ( - + + + ), + }} + /> + )} diff --git a/src/components/pages/profile/[name]/tabs/PermissionsTab/Section.tsx b/src/components/pages/profile/[name]/tabs/PermissionsTab/Section.tsx index 6c9d8b71c..c8db4ac58 100644 --- a/src/components/pages/profile/[name]/tabs/PermissionsTab/Section.tsx +++ b/src/components/pages/profile/[name]/tabs/PermissionsTab/Section.tsx @@ -1,4 +1,4 @@ -import { PropsWithChildren } from 'react' +import { forwardRef, PropsWithChildren } from 'react' import styled, { css } from 'styled-components' import { DisabledSVG, InfoCircleSVG, Typography } from '@ensdomains/thorin' @@ -68,6 +68,8 @@ const SectionItemIcon = styled.svg<{ $color: Color }>( const SectionItemContent = styled.div( ({ theme }) => css` display: flex; + position: relative; + overflow: hidden; flex-direction: column; gap: ${theme.space['1']}; `, @@ -77,23 +79,20 @@ type SectionItemProps = { icon?: 'info' | 'disabled' screen?: Screen } -export const SectionItem = ({ - icon, - screen, - children, - ...props -}: PropsWithChildren) => { - return ( - - {icon === 'info' ? ( - - ) : ( - - )} - {children} - - ) -} +export const SectionItem = forwardRef>( + ({ icon, screen, children, ...props }, ref) => { + return ( + + {icon === 'info' ? ( + + ) : ( + + )} + {children} + + ) + }, +) type SectionListProps = { title: string diff --git a/src/hooks/dom/useElementDimensions.ts b/src/hooks/dom/useElementDimensions.ts new file mode 100644 index 000000000..eafbc00eb --- /dev/null +++ b/src/hooks/dom/useElementDimensions.ts @@ -0,0 +1,60 @@ +import { RefObject, useRef, useSyncExternalStore } from 'react' + +const defaultRect = { width: undefined, height: undefined, top: undefined, left: undefined } + +const getBoundingClientRect = (node?: HTMLDivElement) => { + if (!node) return defaultRect + const rect = node.getBoundingClientRect() + return { + width: Math.round(rect.width), + height: Math.round(rect.height), + top: Math.round(rect.top), + left: Math.round(rect.left), + } +} + +export const useElementDimensions = ({ + ref, + boundingRect = false, +}: { + ref: RefObject + boundingRect?: boolean +}) => { + const store = useRef<{ width?: number; height?: number; top?: number; left?: number }>( + defaultRect, + ) + return useSyncExternalStore( + (onStoreChange) => { + console.log('>>>>>>>>> SUBSCRIBE') + window.addEventListener('resize', onStoreChange) + return () => { + console.log('>>>>>>>>> UNSUBSCRIBE') + window.removeEventListener('resize', onStoreChange) + } + }, + () => { + console.log('>>>>>>>> useELEMENTDIMENSIONS') + if (!ref.current) return store.current + const rect = boundingRect + ? getBoundingClientRect(ref.current) + : { + width: ref.current.offsetWidth, + height: ref.current.offsetHeight, + top: undefined, + left: undefined, + } + if ( + store.current.width !== rect.width || + store.current.height !== rect.height || + store.current.top !== rect.top || + store.current.left !== rect.left + ) { + store.current = rect + } + return store.current + }, + () => { + return store.current + }, + ) +} diff --git a/src/hooks/dom/useRemPixelValue.ts b/src/hooks/dom/useRemPixelValue.ts new file mode 100644 index 000000000..632440287 --- /dev/null +++ b/src/hooks/dom/useRemPixelValue.ts @@ -0,0 +1,22 @@ +import { useSyncExternalStore } from 'react' + +const DEFAULT_PIXEL_VALUE = 16 + +export const useRemPixelValue = () => { + return useSyncExternalStore( + (onStoreChange) => { + window.addEventListener('resize', onStoreChange) + return () => { + window.removeEventListener('resize', onStoreChange) + } + }, + () => { + const { fontSize } = window.getComputedStyle(document.documentElement) + const pixelValue = parseInt(fontSize, 10) + return pixelValue + }, + () => { + return DEFAULT_PIXEL_VALUE + }, + ) +} diff --git a/src/hooks/useNameDetails.tsx b/src/hooks/useNameDetails.tsx index 2e6e07e5f..7f4a4b3cf 100644 --- a/src/hooks/useNameDetails.tsx +++ b/src/hooks/useNameDetails.tsx @@ -1,8 +1,10 @@ import { ReactNode, useMemo } from 'react' -import { useTranslation } from 'react-i18next' +import { Trans, useTranslation } from 'react-i18next' +import { TransComponentName } from '@app/components/@atoms/Name2/Name' import { formatFullExpiry } from '@app/utils/utils' +import i18n from '../i18n' import { useDnsOwner } from './ensjs/dns/useDnsOwner' import { useBasicName } from './useBasicName' import { useProfile } from './useProfile' @@ -88,7 +90,16 @@ export const useNameDetails = ({ name, subgraphEnabled = true }: UseNameDetailsP const errorTitle = useMemo(() => { if (registrationStatus === 'gracePeriod') { - return t('errors.hasExpired', { name }) + return ( + , + }} + /> + ) } if (normalisedName !== '[root]' && !profile && !isProfileLoading) { return t('errors.networkError.title', { ns: 'common' }) diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 5328d2348..98421b98f 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -87,6 +87,29 @@ const StyledLeadingHeading = styled(LeadingHeading)( `, ) +const Test = styled.div` + resize: both; + overflow: hidden; + max-width: 1000px; + position: relative; +` + +const Wrapper = styled.div` + width: 100%; + display: flex; + overflow: hidden; +` + +const Left = styled.div` + flex: 1; + overflow: ellipsis; +` + +const Right = styled.div` + flex: 1; + overflow: ellipsis; +` + export default function Page() { const { t } = useTranslation('common') @@ -110,6 +133,12 @@ export default function Page() { {t('description')} + + + helooworld. + something.seomt.eth + + diff --git a/src/transaction-flow/input/DeleteSubnameNotParentWarning/DeleteSubnameNotParentWarning-flow.tsx b/src/transaction-flow/input/DeleteSubnameNotParentWarning/DeleteSubnameNotParentWarning-flow.tsx index 84ed7cc5d..64386f668 100644 --- a/src/transaction-flow/input/DeleteSubnameNotParentWarning/DeleteSubnameNotParentWarning-flow.tsx +++ b/src/transaction-flow/input/DeleteSubnameNotParentWarning/DeleteSubnameNotParentWarning-flow.tsx @@ -4,6 +4,7 @@ import { Address } from 'viem' import { Button, Dialog, mq } from '@ensdomains/thorin' +import { TransComponentName } from '@app/components/@atoms/Name2/Name' import { usePrimaryNameOrAddress } from '@app/hooks/reverseRecord/usePrimaryNameOrAddress' import { useNameDetails } from '@app/hooks/useNameDetails' import { useOwners } from '@app/hooks/useOwners' @@ -17,6 +18,8 @@ import { CenterAlignedTypography } from '../RevokePermissions/components/CenterA const MessageContainer = styled(CenterAlignedTypography)(({ theme }) => [ css` width: 100%; + position: relative; + overflow: hidden; `, mq.sm.min(css` width: calc(80vw - 2 * ${theme.space['6']}); @@ -79,7 +82,10 @@ const DeleteSubnameNotParentWarning = ({ data, dispatch, onDismiss }: Props) => }} + components={{ + b: , + nameComponent: , + }} values={{ ownershipTerm: t(ownerTarget.label, { ns: 'common' }).toLocaleLowerCase(), parentOwner: parentPrimaryOrAddress.nameOrAddr, diff --git a/src/transaction-flow/input/EditRoles/views/MainView/components/RoleCard.tsx b/src/transaction-flow/input/EditRoles/views/MainView/components/RoleCard.tsx index b4b0a0c8d..cf85a43a4 100644 --- a/src/transaction-flow/input/EditRoles/views/MainView/components/RoleCard.tsx +++ b/src/transaction-flow/input/EditRoles/views/MainView/components/RoleCard.tsx @@ -34,15 +34,24 @@ const Divider = styled.div( ) const Footer = styled.button( - () => css` + ({ theme }) => css` display: flex; + overflow: hidden; justify-content: space-between; align-items: center; + gap: ${theme.space['4']}; `, ) +const FooterLeft = styled.div( + () => css` + flex: 1; + overflow: hidden; + `, +) const FooterRight = styled.div( ({ theme }) => css` + flex: 0 0 auto; display: flex; align-items: center; gap: ${theme.space['2']}; @@ -109,7 +118,9 @@ export const RoleCard = ({ address, role, dirty, onClick }: Props) => {