diff --git a/deploy/.utils/wrappedNameHelpers.ts b/deploy/.utils/wrappedNameHelpers.ts new file mode 100644 index 000000000..c91884c2d --- /dev/null +++ b/deploy/.utils/wrappedNameHelpers.ts @@ -0,0 +1,93 @@ +import type { Contract } from 'ethers' +import { ethers } from 'hardhat' +import type { Address } from 'viem' + +import { + makeCommitment as generateCommitment, + makeRegistrationTuple, + RegistrationParameters, +} from '@ensdomains/ensjs/utils' + +type ProcessedSubname = { + label: string + owner: Address + expiry: number + fuses: number +} + +type ProcessedNameData = RegistrationParameters & { + label: string + subnames: ProcessedSubname[] +} + +export const makeWrappedCommitment = + (controller: Contract) => + (nonce: number) => + async ({ owner, name, ...rest }: ProcessedNameData, index: number) => { + const commitment = generateCommitment({ owner, name, ...rest }) + + const _controller = controller.connect(await ethers.getSigner(owner)) + const commitTx = await _controller.commit(commitment, { nonce: nonce + index }) + console.log(`Commiting commitment for ${name} (tx: ${commitTx.hash})...`) + return 1 + } + +export const makeWrappedRenew = + (controller: Contract) => (nonce: number) => async (name: string, duration: number) => { + const [price] = await controller.rentPrice(name, duration) + return price + } + +export const makeWrappedRegistration = + (controller: Contract) => + (nonce: number) => + async ({ owner, name, duration, label, ...rest }: ProcessedNameData, index: number) => { + const [price] = await controller.rentPrice(label, duration) + + const _controller = controller.connect(await ethers.getSigner(owner)) + + const registerTx = await _controller.register( + ...makeRegistrationTuple({ owner, name, duration, ...rest }), + { + value: price, + nonce: nonce + index, + }, + ) + console.log(`Registering name ${name} (tx: ${registerTx.hash})...`) + + return 1 + } + +export const makeWrappedData = + (resolverAddress, allNamedAccts) => + ({ namedOwner, customDuration, fuses, name, subnames, ...rest }: Name) => { + const secret = + // eslint-disable-next-line no-restricted-syntax + '0x0000000000000000000000000000000000000000000000000000000000000000' as Address + const duration = customDuration || 31536000 + // 1659467455 is the approximate time of the transaction, this is for keeping block hashes the same + const wrapperExpiry = 1659467455 + duration + const owner = allNamedAccts[namedOwner] + + const processedSubnames: ProcessedSubname[] = + subnames?.map( + ({ label, namedOwner: subNamedOwner, fuses: subnameFuses, expiry: subnameExpiry }) => ({ + label, + owner: allNamedAccts[subNamedOwner], + expiry: subnameExpiry || wrapperExpiry, + fuses: subnameFuses || 0, + }), + ) || [] + + return { + resolverAddress, + secret, + duration, + owner, + name, + label: name.split('.')[0], + subnames: processedSubnames, + fuses: fuses || undefined, + ...rest, + } + } diff --git a/deploy/00_register_legacy.ts b/deploy/00_register_legacy.ts index 886248ac9..24ec379c0 100644 --- a/deploy/00_register_legacy.ts +++ b/deploy/00_register_legacy.ts @@ -2,11 +2,18 @@ /* eslint-disable no-await-in-loop */ import cbor from 'cbor' +import { Contract } from 'ethers' import { ethers } from 'hardhat' import { DeployFunction } from 'hardhat-deploy/types' import { HardhatRuntimeEnvironment } from 'hardhat/types' import pako from 'pako' -import { labelhash, namehash, stringToBytes } from 'viem' +import { Address, labelhash, namehash, stringToBytes } from 'viem' + +import { + makeWrappedCommitment, + makeWrappedData, + makeWrappedRegistration, +} from './.utils/wrappedNameHelpers' const dummyABI = [ { @@ -366,28 +373,15 @@ const names: Name[] = [ }, ] -const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { - const { getNamedAccounts, network } = hre - const allNamedAccts = await getNamedAccounts() - - const registry = await ethers.getContract('ENSRegistry') - const controller = await ethers.getContract('LegacyETHRegistrarController') - const publicResolver = await ethers.getContract('LegacyPublicResolver') - - const makeData = ({ - namedOwner, - namedController, - namedAddr, - customDuration, - subnames, - ...rest - }: Name) => { +const makeNameData = + (allNamedAccts: Record, publicResolverAddress: Address) => + ({ namedOwner, namedController, namedAddr, customDuration, subnames, ...rest }: Name) => { // eslint-disable-next-line no-restricted-syntax const secret = '0x0000000000000000000000000000000000000000000000000000000000000000' const registrant = allNamedAccts[namedOwner] const owner = namedController ? allNamedAccts[namedController] : undefined const addr = allNamedAccts[namedAddr] - const resolver = rest.resolver ?? publicResolver.address + const resolver = rest.resolver ?? publicResolverAddress const duration = customDuration || 31536000 return { @@ -402,203 +396,294 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { } } - const makeCommitment = - (nonce: number) => - async ( - { label, registrant, secret, resolver, addr }: ReturnType, - index: number, - ) => { - const commitment = await controller.makeCommitmentWithConfig( - label, - registrant, - secret, - resolver, - addr, - ) +const makeCommitment = + (controller: Contract) => + (nonce: number) => + async ( + { label, registrant, secret, resolver, addr }: ReturnType>, + index: number, + ) => { + const commitment = await controller.makeCommitmentWithConfig( + label, + registrant, + secret, + resolver, + addr, + ) - const _controller = controller.connect(await ethers.getSigner(registrant)) - const commitTx = await _controller.commit(commitment, { nonce: nonce + index }) - console.log(`Commiting commitment for ${label}.eth (tx: ${commitTx.hash})...`) + const _controller = controller.connect(await ethers.getSigner(registrant)) + const commitTx = await _controller.commit(commitment, { nonce: nonce + index }) + console.log(`Commiting commitment for ${label}.eth (tx: ${commitTx.hash})...`) - return 1 - } + return 1 + } - const makeRegistration = - (nonce: number) => - async ( - { label, registrant, secret, resolver, addr, duration }: ReturnType, - index: number, - ) => { - const price = await controller.rentPrice(label, duration) - - const _controller = controller.connect(await ethers.getSigner(registrant)) - - const registerTx = await _controller.registerWithConfig( - label, - registrant, - duration, - secret, - resolver, - addr, - { - value: price, - nonce: nonce + index, - }, - ) - console.log(`Registering name ${label}.eth (tx: ${registerTx.hash})...`) +const makeRegistration = + (controller: Contract) => + (nonce: number) => + async ( + { + label, + registrant, + secret, + resolver, + addr, + duration, + }: ReturnType>, + index: number, + ) => { + const price = await controller.rentPrice(label, duration) - return 1 - } + const _controller = controller.connect(await ethers.getSigner(registrant)) - const makeRecords = - (nonce: number) => - async ( - { label, records: _records, registrant }: ReturnType, - index: number, - ) => { - const records = _records! - let nonceRef = nonce + index - const _publicResolver = publicResolver.connect(await ethers.getSigner(registrant)) - - const hash = namehash(`${label}.eth`) - console.log(`Setting records for ${label}.eth...`) - if (records.text) { - console.log('TEXT') - for (const { key, value } of records.text) { - const setTextTx = await _publicResolver.setText(hash, key, value, { nonce: nonceRef }) - console.log(` - ${key} ${value} (tx: ${setTextTx.hash})...`) - nonceRef += 1 - } - } - if (records.addr) { - console.log('ADDR') - for (const { key, value } of records.addr) { - const setAddrTx = await _publicResolver['setAddr(bytes32,uint256,bytes)']( - hash, - key, - value, - { - nonce: nonceRef, - }, - ) - console.log(` - ${key} ${value} (tx: ${setAddrTx.hash})...`) - nonceRef += 1 - } - } - if (records.contenthash) { - console.log('CONTENTHASH') - const setContenthashTx = await _publicResolver.setContenthash(hash, records.contenthash, { - nonce: nonceRef, - }) - console.log(` - ${records.contenthash} (tx: ${setContenthashTx.hash})...`) + const registerTx = await _controller.registerWithConfig( + label, + registrant, + duration, + secret, + resolver, + addr, + { + value: price, + nonce: nonce + index, + }, + ) + console.log(`Registering name ${label}.eth (tx: ${registerTx.hash})...`) + + return 1 + } + +const makeRecords = + (publicResolver: Contract) => + (nonce: number) => + async ( + { label, records: _records, registrant }: ReturnType>, + index: number, + ) => { + const records = _records! + let nonceRef = nonce + index + const _publicResolver = publicResolver.connect(await ethers.getSigner(registrant)) + + const hash = namehash(`${label}.eth`) + console.log(`Setting records for ${label}.eth...`) + if (records.text) { + console.log('TEXT') + for (const { key, value } of records.text) { + const setTextTx = await _publicResolver.setText(hash, key, value, { nonce: nonceRef }) + console.log(` - ${key} ${value} (tx: ${setTextTx.hash})...`) nonceRef += 1 } - if (records.abi) { - const abis = Array.isArray(records.abi) ? records.abi : [records.abi] - for (const abi of abis) { - console.log('ABI') - const { contentType, data } = abi - let data_ - if (contentType === 1) data_ = stringToBytes(JSON.stringify(data)) - else if (contentType === 2) data_ = pako.deflate(JSON.stringify(abi.data)) - else if (contentType === 4) data_ = cbor.encode(abi.data) - else data_ = stringToBytes(data) - const setAbiTx = await _publicResolver.setABI(hash, contentType, data_, { - nonce: nonceRef, - }) - console.log(` - ${records.abi} (tx: ${setAbiTx.hash})...`) - nonceRef += 1 - } - } - return nonceRef - nonce - index } - - const makeSubnames = - (nonce: number) => - async ( - { label, subnames, registrant, resolver }: ReturnType, - index: number, - ) => { - if (!subnames) return 0 - for (let i = 0; i < subnames.length; i += 1) { - const { label: subnameLabel, namedOwner: namedSubOwner } = subnames[i] - const subOwner = allNamedAccts[namedSubOwner] - const _registry = registry.connect(await ethers.getSigner(registrant)) - const subnameTx = await _registry.setSubnodeRecord( - namehash(`${label}.eth`), - labelhash(subnameLabel), - subOwner, - resolver, - 0, + if (records.addr) { + console.log('ADDR') + for (const { key, value } of records.addr) { + const setAddrTx = await _publicResolver['setAddr(bytes32,uint256,bytes)']( + hash, + key, + value, { - nonce: nonce + index + i, + nonce: nonceRef, }, ) - console.log(`Creating subname ${subnameLabel}.${label}.eth (tx: ${subnameTx.hash})...`) + console.log(` - ${key} ${value} (tx: ${setAddrTx.hash})...`) + nonceRef += 1 } - return subnames.length } - - const makeController = - (nonce: number) => - async ({ label, owner, registrant }: ReturnType, index: number) => { - const _registry = registry.connect(await ethers.getSigner(registrant)) - const setControllerTx = await _registry.setOwner(namehash(`${label}.eth`), owner, { - nonce: nonce + index, + if (records.contenthash) { + console.log('CONTENTHASH') + const setContenthashTx = await _publicResolver.setContenthash(hash, records.contenthash, { + nonce: nonceRef, }) - console.log( - `Setting controller for ${label}.eth to ${owner} (tx: ${setControllerTx.hash})...`, - ) - - return 1 + console.log(` - ${records.contenthash} (tx: ${setContenthashTx.hash})...`) + nonceRef += 1 + } + if (records.abi) { + const abis = Array.isArray(records.abi) ? records.abi : [records.abi] + for (const abi of abis) { + console.log('ABI') + const { contentType, data } = abi + let data_ + if (contentType === 1) data_ = stringToBytes(JSON.stringify(data)) + else if (contentType === 2) data_ = pako.deflate(JSON.stringify(abi.data)) + else if (contentType === 4) data_ = cbor.encode(abi.data) + else data_ = stringToBytes(data) + const setAbiTx = await _publicResolver.setABI(hash, contentType, data_, { + nonce: nonceRef, + }) + console.log(` - ${records.abi} (tx: ${setAbiTx.hash})...`) + nonceRef += 1 + } } + return nonceRef - nonce - index + } - const allNameData = names.map(makeData) +const makeController = + (registry: Contract) => + (nonce: number) => + async ( + { label, owner, registrant }: ReturnType>, + index: number, + ) => { + const _registry = registry.connect(await ethers.getSigner(registrant)) + const setControllerTx = await _registry.setOwner(namehash(`${label}.eth`), owner, { + nonce: nonce + index, + }) + console.log(`Setting controller for ${label}.eth to ${owner} (tx: ${setControllerTx.hash})...`) + + return 1 + } - const getNonceAndApply = async ( - property: keyof ReturnType, - _func: typeof makeCommitment, - filter?: (data: ReturnType) => boolean, - nonceMap?: Record, +const makeSubnames = + (allNamedAccts: Record, registry: Contract) => + (nonce: number) => + async ( + { label, subnames, registrant, resolver }: ReturnType>, + index: number, ) => { - const newNonceMap = nonceMap || {} - for (const account of Object.values(allNamedAccts)) { - const namesWithAccount = allNameData.filter( - (data) => data[property] === account && (filter ? filter(data) : true), + if (!subnames) return 0 + for (let i = 0; i < subnames.length; i += 1) { + const { label: subnameLabel, namedOwner: namedSubOwner } = subnames[i] + const subOwner = allNamedAccts[namedSubOwner] + const _registry = registry.connect(await ethers.getSigner(registrant)) + const subnameTx = await _registry.setSubnodeRecord( + namehash(`${label}.eth`), + labelhash(subnameLabel), + subOwner, + resolver, + 0, + { + nonce: nonce + index + i, + }, ) - if (!newNonceMap[account]) { - const nonce = await ethers.provider.getTransactionCount(account) - newNonceMap[account] = nonce - } - let usedNonces = 0 + console.log(`Creating subname ${subnameLabel}.${label}.eth (tx: ${subnameTx.hash})...`) + } + return subnames.length + } - for (let i = 0; i < namesWithAccount.length; i += 1) { - const data = namesWithAccount[i] - usedNonces += await _func(newNonceMap[account])(data, usedNonces) - } - newNonceMap[account] += usedNonces +const getNonceAndApply = async ( + property: keyof ReturnType, + _func: typeof makeCommitment, + allNamedAccts: Record, + allNameData: ReturnType[], + filter?: (data: ReturnType) => boolean, + nonceMap?: Record, +) => { + const newNonceMap = nonceMap || {} + + for (const account of Object.values(allNamedAccts)) { + const namesWithAccount = allNameData.filter( + (data) => data[property] === account && (filter ? filter(data) : true), + ) + if (!newNonceMap[account]) { + const nonce = await ethers.provider.getTransactionCount(account) + newNonceMap[account] = nonce + } + let usedNonces = 0 + + for (let i = 0; i < namesWithAccount.length; i += 1) { + const data = namesWithAccount[i] + usedNonces += await _func(newNonceMap[account])(data, usedNonces) } - return newNonceMap + newNonceMap[account] += usedNonces } + return newNonceMap +} + +const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { + const { getNamedAccounts, network } = hre + const allNamedAccts = await getNamedAccounts() + const registry = await ethers.getContract('ENSRegistry') + const legacyController = await ethers.getContract('LegacyETHRegistrarController') + const controller = await ethers.getContract('ETHRegistrarController') + const publicResolver = await ethers.getContract('LegacyPublicResolver') + + const allNameData = names.map(makeNameData(allNamedAccts, publicResolver.address)) + await network.provider.send('evm_setAutomine', [false]) - await getNonceAndApply('registrant', makeCommitment) + await getNonceAndApply('registrant', makeCommitment(legacyController), allNamedAccts, allNameData) await network.provider.send('evm_mine') const oldTimestamp = (await ethers.provider.getBlock('latest')).timestamp await network.provider.send('evm_setNextBlockTimestamp', [oldTimestamp + 60]) await network.provider.send('evm_mine') - await getNonceAndApply('registrant', makeRegistration) + await getNonceAndApply( + 'registrant', + makeRegistration(legacyController), + allNamedAccts, + allNameData, + ) await network.provider.send('evm_mine') - const tempNonces = await getNonceAndApply('registrant', makeRecords, (data) => !!data.records) + const tempNonces = await getNonceAndApply( + 'registrant', + makeRecords(publicResolver), + allNamedAccts, + allNameData, + (data) => !!data.records, + ) const tempNonces2 = await getNonceAndApply( 'registrant', - makeController, + makeController(registry), + allNamedAccts, + allNameData, (data) => !!data.owner, tempNonces, ) - await getNonceAndApply('registrant', makeSubnames, (data) => !!data.subnames, tempNonces2) + await getNonceAndApply( + 'registrant', + makeSubnames(allNamedAccts, registry), + allNamedAccts, + allNameData, + (data) => !!data.subnames, + tempNonces2, + ) await network.provider.send('evm_mine') + const wrappedNames = [ + { + name: 'desynced.eth', + namedOwner: 'owner', + customDuration: 2419200, + }, + ] + + // Register desynced name ------------------------- + const wrappedFunctionData = wrappedNames.map( + makeWrappedData(publicResolver.address, allNamedAccts), + ) + console.log('****wrappedFunctionData', wrappedFunctionData) + await getNonceAndApply( + 'owner', + makeWrappedCommitment(controller), + allNamedAccts, + wrappedFunctionData, + ) + await network.provider.send('evm_mine') + await network.provider.send('evm_setNextBlockTimestamp', [ + (await ethers.provider.getBlock('latest')).timestamp + 60, + ]) + await network.provider.send('evm_mine') + await getNonceAndApply( + 'owner', + makeWrappedRegistration(controller), + allNamedAccts, + wrappedFunctionData, + ) + await network.provider.send('evm_mine') + + //Extend desynced.eth on the legacy controller + const [price] = await controller.rentPrice('desynced', 31556952) + const legacyControllerConnected = legacyController.connect( + await ethers.getSigner(allNamedAccts.owner), + ) + await legacyControllerConnected.renew('desynced', 31556952, { + value: price, + }) + + //--------------------------------- + + // await getNonceAndApply('owner', makeSubname) + // await network.provider.send('evm_mine') + // Skip forward 28 + 90 days so that minimum exp names go into premium await network.provider.send('anvil_setBlockTimestampInterval', [2419200 + 7776000]) await network.provider.send('evm_mine') @@ -623,9 +708,9 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { return true } -func.id = 'register-unwrapped-names' -func.tags = ['register-unwrapped-names'] -func.dependencies = ['LegacyETHRegistrarController'] -func.runAtTheEnd = true +func.id = 'register-legacy-names' +func.tags = ['register-legacy-names'] +func.dependencies = ['ETHRegistrarController'] +// func.runAtTheEnd = true export default func diff --git a/deploy/00_register_wrapped.ts b/deploy/00_register_wrapped.ts index 87a967d7b..8abe864dd 100644 --- a/deploy/00_register_wrapped.ts +++ b/deploy/00_register_wrapped.ts @@ -6,15 +6,14 @@ import { DeployFunction } from 'hardhat-deploy/types' import { HardhatRuntimeEnvironment } from 'hardhat/types' import { Address, namehash } from 'viem' -import { - encodeFuses, - makeCommitment as generateCommitment, - makeRegistrationTuple, - RecordOptions, - RegistrationParameters, -} from '@ensdomains/ensjs/utils' +import { encodeFuses, RecordOptions, RegistrationParameters } from '@ensdomains/ensjs/utils' import { nonceManager } from './.utils/nonceManager' +import { + makeWrappedCommitment, + makeWrappedData, + makeWrappedRegistration, +} from './.utils/wrappedNameHelpers' type Name = { name: string @@ -152,70 +151,6 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const publicResolver = await ethers.getContract('PublicResolver') const nameWrapper = await ethers.getContract('NameWrapper') - const makeData = ({ namedOwner, customDuration, fuses, name, subnames, ...rest }: Name) => { - const resolverAddress = publicResolver.address as Address - - const secret = - // eslint-disable-next-line no-restricted-syntax - '0x0000000000000000000000000000000000000000000000000000000000000000' as Address - const duration = customDuration || 31536000 - // 1659467455 is the approximate time of the transaction, this is for keeping block hashes the same - const wrapperExpiry = 1659467455 + duration - const owner = allNamedAccts[namedOwner] - - const processedSubnames: ProcessedSubname[] = - subnames?.map( - ({ label, namedOwner: subNamedOwner, fuses: subnameFuses, expiry: subnameExpiry }) => ({ - label, - owner: allNamedAccts[subNamedOwner], - expiry: subnameExpiry || wrapperExpiry, - fuses: subnameFuses || 0, - }), - ) || [] - - return { - resolverAddress, - secret, - duration, - owner, - name, - label: name.split('.')[0], - subnames: processedSubnames, - fuses: fuses || undefined, - ...rest, - } - } - - const makeCommitment = - (nonce: number) => - async ({ owner, name, ...rest }: ProcessedNameData, index: number) => { - const commitment = generateCommitment({ owner, name, ...rest }) - - const _controller = controller.connect(await ethers.getSigner(owner)) - const commitTx = await _controller.commit(commitment, { nonce: nonce + index }) - console.log(`Commiting commitment for ${name} (tx: ${commitTx.hash})...`) - return 1 - } - - const makeRegistration = - (nonce: number) => - async ({ owner, name, duration, label, ...rest }: ProcessedNameData, index: number) => { - const [price] = await controller.rentPrice(label, duration) - - const _controller = controller.connect(await ethers.getSigner(owner)) - - const registerTx = await _controller.register( - ...makeRegistrationTuple({ owner, name, duration, ...rest }), - { - value: price, - nonce: nonce + index, - }, - ) - console.log(`Registering name ${name} (tx: ${registerTx.hash})...`) - - return 1 - } - const makeSubname = (nonce: number) => async ({ name, subnames, owner }: ProcessedNameData, index: number) => { @@ -237,17 +172,17 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { return subnames.length } - const allNameData = names.map(makeData) + const allNameData = names.map(makeWrappedData(publicResolver.address, allNamedAccts)) const getNonceAndApply = nonceManager(ethers, allNamedAccts, allNameData) await network.provider.send('evm_setAutomine', [false]) - await getNonceAndApply('owner', makeCommitment) + await getNonceAndApply('owner', makeWrappedCommitment(controller)) await network.provider.send('evm_mine') const oldTimestamp = (await ethers.provider.getBlock('latest')).timestamp await network.provider.send('evm_setNextBlockTimestamp', [oldTimestamp + 60]) await network.provider.send('evm_mine') - await getNonceAndApply('owner', makeRegistration) + await getNonceAndApply('owner', makeWrappedRegistration(controller)) await network.provider.send('evm_mine') await getNonceAndApply('owner', makeSubname) await network.provider.send('evm_mine') @@ -256,6 +191,22 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { await network.provider.send('anvil_setBlockTimestampInterval', [1]) await network.provider.send('evm_mine') + /* + // Renew desynced.eth with the legacy ETH registrar + const legacyETHRegistrarController = await ethers.getContract('LegacyETHRegistrarController') + const owner = allNamedAccts.owner + const _legacyETHRegistrarController = legacyETHRegistrarController.connect( + await ethers.getSigner(owner), + ) + + const label = 'desynced' + const duration = 31536000 // 1 year in seconds + + const renewTx = await _legacyETHRegistrarController.renew(label, duration) + console.log(`Renewing desynced.eth for 1 year (tx: ${renewTx.hash})...`) + await renewTx.wait() + */ + return true } diff --git a/package.json b/package.json index 2bbfac934..cf91a174c 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": "4.0.0", - "@ensdomains/thorin": "0.6.50", + "@ensdomains/thorin": "0.0.0-feat-banner-action-button.20240809T010925661", "@metamask/mobile-provider": "^2.1.0", "@metamask/post-message-stream": "^6.1.2", "@metamask/providers": "^14.0.2", @@ -89,11 +89,11 @@ "react-hook-form": "7.51.0", "react-i18next": "^11.18.5", "react-is": "^17.0.2", - "react-transition-state": "^1.1.5", + "react-transition-state": "2.1.1", "react-use": "^17.4.0", "react-use-error-boundary": "^3.0.0", "react-use-intercom": "^5.1.4", - "styled-components": "^5.3.5", + "styled-components": "5.3.6", "ts-pattern": "^4.2.2", "use-immer": "^0.7.0", "viem": "2.19.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6643d884a..abf7bb09e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,8 +39,8 @@ importers: specifier: 4.0.0 version: 4.0.0(encoding@0.1.13)(typescript@5.4.5)(viem@2.19.0(bufferutil@4.0.7)(typescript@5.4.5)(utf-8-validate@6.0.3)(zod@3.23.8))(zod@3.23.8) '@ensdomains/thorin': - specifier: 0.6.50 - version: 0.6.50(react-dom@18.3.1(react@18.3.1))(react-transition-state@1.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1)) + specifier: 0.0.0-feat-banner-action-button.20240809T010925661 + version: 0.0.0-feat-banner-action-button.20240809T010925661(react-dom@18.3.1(react@18.3.1))(react-transition-state@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(styled-components@5.3.6(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1)) '@metamask/mobile-provider': specifier: ^2.1.0 version: 2.1.0 @@ -150,8 +150,8 @@ importers: specifier: ^17.0.2 version: 17.0.2 react-transition-state: - specifier: ^1.1.5 - version: 1.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: 2.1.1 + version: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-use: specifier: ^17.4.0 version: 17.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -162,8 +162,8 @@ importers: specifier: ^5.1.4 version: 5.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) styled-components: - specifier: ^5.3.5 - version: 5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1) + specifier: 5.3.6 + version: 5.3.6(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1) ts-pattern: specifier: ^4.2.2 version: 4.3.0 @@ -215,7 +215,7 @@ importers: version: 1.44.1 '@testing-library/jest-dom': specifier: ^6.4.2 - version: 6.4.5(vitest@1.6.0(@types/node@18.19.33)(jsdom@24.1.0(bufferutil@4.0.7)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.3))(terser@5.31.0)) + version: 6.4.5(@types/jest@29.5.12)(vitest@1.6.0(@types/node@18.19.33)(jsdom@24.1.0(bufferutil@4.0.7)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.3))(terser@5.31.0)) '@testing-library/react': specifier: ^14.0.0 version: 14.3.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1340,13 +1340,13 @@ packages: '@ensdomains/solsha1@0.0.3': resolution: {integrity: sha512-uhuG5LzRt/UJC0Ux83cE2rCKwSleRePoYdQVcqPN1wyf3/ekMzT/KZUF9+v7/AG5w9jlMLCQkUM50vfjr0Yu9Q==} - '@ensdomains/thorin@0.6.50': - resolution: {integrity: sha512-UA1Blyz1h/Yy9e2h8ykNwyIfFMa85+fM5viS1Jra7Ms/EbgLhiP/BEMNr1/oZvwLHE54UM/rZGij1GaxurrOoQ==} + '@ensdomains/thorin@0.0.0-feat-banner-action-button.20240809T010925661': + resolution: {integrity: sha512-/gw83sHi/40xNzzf0fsPoM0KMayYQP8Xm3ErGnFUSAdJwLt70M1tyO/yIUVvdHKU6yBBmpXC1W2mANxxDyMq2w==} peerDependencies: react: ^18.2.0 react-dom: ^18.2.0 - react-transition-state: ^1.1.4 - styled-components: ^5.3.3 + react-transition-state: ^2.1.1 + styled-components: ^5.3.6 '@esbuild-plugins/node-globals-polyfill@0.2.3': resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} @@ -1815,6 +1815,10 @@ packages: resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/fake-timers@29.7.0': resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3047,6 +3051,9 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/jest@29.5.12': + resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + '@types/js-cookie@2.2.7': resolution: {integrity: sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA==} @@ -5249,6 +5256,10 @@ packages: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + express@4.19.2: resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} @@ -6304,6 +6315,10 @@ packages: jest-canvas-mock@2.5.2: resolution: {integrity: sha512-vgnpPupjOL6+L5oJXzxTxFrlGEIbHdZqFU+LFNdtLxZ3lRDCl17FlTMM7IatoRQkrcyOTMlDinjUguqmQ6bR2A==} + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-environment-node@29.7.0: resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -6312,6 +6327,10 @@ packages: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@29.7.0: resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -8008,8 +8027,8 @@ packages: '@types/react': optional: true - react-transition-state@1.1.5: - resolution: {integrity: sha512-ITY2mZqc2dWG2eitJkYNdcSFW8aKeOlkL2A/vowRrLL8GH3J6Re/SpD/BLvQzrVOTqjsP0b5S9N10vgNNzwMUQ==} + react-transition-state@2.1.1: + resolution: {integrity: sha512-kQx5g1FVu9knoz1T1WkapjUgFz08qQ/g1OmuWGi3/AoEFfS0kStxrPlZx81urjCXdz2d+1DqLpU6TyLW/Ro04Q==} peerDependencies: react: ^18.2.0 react-dom: ^18.2.0 @@ -8758,8 +8777,8 @@ packages: style-search@0.1.0: resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} - styled-components@5.3.11: - resolution: {integrity: sha512-uuzIIfnVkagcVHv9nE0VPlHPSCmXIUGKfJ42LNjxCCTDTL5sgnJ8Z7GZBq0EnLYGln77tPpEpExt2+qa+cZqSw==} + styled-components@5.3.6: + resolution: {integrity: sha512-hGTZquGAaTqhGWldX7hhfzjnIYBZ0IXQXkCYdvF1Sq3DsUaLx6+NTHC5Jj1ooM2F68sBiVz3lvhfwQs/S3l6qg==} engines: {node: '>=10'} peerDependencies: react: ^18.2.0 @@ -11222,15 +11241,15 @@ snapshots: dependencies: hash-test-vectors: 1.3.2 - '@ensdomains/thorin@0.6.50(react-dom@18.3.1(react@18.3.1))(react-transition-state@1.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(styled-components@5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1))': + '@ensdomains/thorin@0.0.0-feat-banner-action-button.20240809T010925661(react-dom@18.3.1(react@18.3.1))(react-transition-state@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)(styled-components@5.3.6(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1))': dependencies: clsx: 1.2.1 focus-visible: 5.2.0 lodash: 4.17.21 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-transition-state: 1.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - styled-components: 5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1) + react-transition-state: 2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + styled-components: 5.3.6(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1) ts-pattern: 4.3.0 '@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19)': @@ -11747,6 +11766,11 @@ snapshots: '@types/node': 18.19.33 jest-mock: 29.7.0 + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + optional: true + '@jest/fake-timers@29.7.0': dependencies: '@jest/types': 29.6.3 @@ -13193,7 +13217,7 @@ snapshots: lz-string: 1.5.0 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.4.5(vitest@1.6.0(@types/node@18.19.33)(jsdom@24.1.0(bufferutil@4.0.7)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.3))(terser@5.31.0))': + '@testing-library/jest-dom@6.4.5(@types/jest@29.5.12)(vitest@1.6.0(@types/node@18.19.33)(jsdom@24.1.0(bufferutil@4.0.7)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.3))(terser@5.31.0))': dependencies: '@adobe/css-tools': 4.3.3 '@babel/runtime': 7.24.6 @@ -13204,6 +13228,7 @@ snapshots: lodash: 4.17.21 redent: 3.0.0 optionalDependencies: + '@types/jest': 29.5.12 vitest: 1.6.0(@types/node@18.19.33)(jsdom@24.1.0(bufferutil@4.0.7)(canvas@2.11.2(encoding@0.1.13))(utf-8-validate@6.0.3))(terser@5.31.0) '@testing-library/react-hooks@8.0.1(@types/react@18.2.21)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': @@ -13418,6 +13443,12 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 + '@types/jest@29.5.12': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + optional: true + '@types/js-cookie@2.2.7': {} '@types/js-levenshtein@1.1.3': {} @@ -14628,14 +14659,14 @@ snapshots: transitivePeerDependencies: - supports-color - babel-plugin-styled-components@2.1.4(@babel/core@7.24.6)(styled-components@5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1)): + babel-plugin-styled-components@2.1.4(@babel/core@7.24.6)(styled-components@5.3.6(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1)): dependencies: '@babel/helper-annotate-as-pure': 7.24.6 '@babel/helper-module-imports': 7.24.6 '@babel/plugin-syntax-jsx': 7.24.6(@babel/core@7.24.6) lodash: 4.17.21 picomatch: 2.3.1 - styled-components: 5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1) + styled-components: 5.3.6(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1) transitivePeerDependencies: - '@babel/core' @@ -16476,6 +16507,15 @@ snapshots: exit-hook@2.2.1: {} + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + optional: true + express@4.19.2: dependencies: accepts: 1.3.8 @@ -17710,6 +17750,14 @@ snapshots: cssfontparser: 1.2.1 moo-color: 1.0.3 + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + optional: true + jest-environment-node@29.7.0: dependencies: '@jest/environment': 29.7.0 @@ -17721,6 +17769,14 @@ snapshots: jest-get-type@29.6.3: {} + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + optional: true + jest-message-util@29.7.0: dependencies: '@babel/code-frame': 7.24.6 @@ -19660,7 +19716,7 @@ snapshots: optionalDependencies: '@types/react': 18.2.21 - react-transition-state@1.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-transition-state@2.1.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -20549,14 +20605,14 @@ snapshots: style-search@0.1.0: {} - styled-components@5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1): + styled-components@5.3.6(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1): dependencies: '@babel/helper-module-imports': 7.24.6 '@babel/traverse': 7.24.6(supports-color@5.5.0) '@emotion/is-prop-valid': 1.2.2 '@emotion/stylis': 0.8.5 '@emotion/unitless': 0.7.5 - babel-plugin-styled-components: 2.1.4(@babel/core@7.24.6)(styled-components@5.3.11(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1)) + babel-plugin-styled-components: 2.1.4(@babel/core@7.24.6)(styled-components@5.3.6(@babel/core@7.24.6)(react-dom@18.3.1(react@18.3.1))(react-is@17.0.2)(react@18.3.1)) css-to-react-native: 3.2.0 hoist-non-react-statics: 3.3.2 react: 18.3.1 diff --git a/public/locales/en/common.json b/public/locales/en/common.json index b00a83a10..46c459be9 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -218,7 +218,8 @@ "syncManager": "Sync manager", "updateProfileRecords": "Update profile", "resetProfile": "Reset profile", - "unwrapName": "Unwrap name" + "unwrapName": "Unwrap name", + "syncWrappedExpiry": "Repair name" }, "info": { "sendName": "Set the controller and registrant of the name", @@ -237,6 +238,7 @@ "burnFuses": "Burn the chosen permissions until name expiry", "commitName": "Start timer to register name", "approveNameWrapper": "Approve the NameWrapper to manage your names", + "syncWrappedExpiry": "Sync the wrapped name expiry", "fuses": { "revoke": "Revoke", "grant": "Grant", diff --git a/public/locales/en/profile.json b/public/locales/en/profile.json index fbe32cd47..18f33ebbf 100644 --- a/public/locales/en/profile.json +++ b/public/locales/en/profile.json @@ -16,6 +16,11 @@ "available": { "title": "{{name}} is available", "description": "This name expired on {{date}}. Click here to view the registration page." + }, + "expiryDesync": { + "title": "Name misconfigured", + "description": "A transaction is required to repair this name. Ownership data displayed may be inaccurate.", + "actionLabel": "Repair" } }, "tabs": { diff --git a/src/components/@atoms/ExpandableSection/ExpandableSection.test.tsx b/src/components/@atoms/ExpandableSection/ExpandableSection.test.tsx index e44c4517c..7ee60b1ae 100644 --- a/src/components/@atoms/ExpandableSection/ExpandableSection.test.tsx +++ b/src/components/@atoms/ExpandableSection/ExpandableSection.test.tsx @@ -1,8 +1,8 @@ import { render, screen, userEvent } from '@app/test-utils' -import { describe, expect, it } from 'vitest' +import { describe, expect, it, vi } from 'vitest' -import { ExpandableSection } from './ExpandableSection' +import { ExpandableSection, stateChangeHandler } from './ExpandableSection' describe('ExpandableSection', () => { it('should expand and close when header is clicked', async () => { @@ -15,3 +15,41 @@ describe('ExpandableSection', () => { expect(screen.getByText('CONTENT')).not.toBeVisible() }) }) + +describe('stateChangeHandler', () => { + it('should set height when status is preEnter or preExit', () => { + const setHeight = vi.fn() + const ref = { current: { getBoundingClientRect: () => ({ height: 100 }) } } + + const handler = stateChangeHandler(setHeight, ref) + + handler({ current: { status: 'preEnter' } }) + expect(setHeight).toHaveBeenCalledWith(100) + + handler({ current: { status: 'preExit' } }) + expect(setHeight).toHaveBeenCalledWith(100) + }) + + it('should not set height for other statuses', () => { + const setHeight = vi.fn() + const ref = { current: { getBoundingClientRect: () => ({ height: 100 }) } } + + const handler = stateChangeHandler(setHeight, ref) + + handler({ current: { status: 'entered' } }) + expect(setHeight).not.toHaveBeenCalled() + + handler({ current: { status: 'exited' } }) + expect(setHeight).not.toHaveBeenCalled() + }) + + it('should handle null ref', () => { + const setHeight = vi.fn() + const ref = { current: null } + + const handler = stateChangeHandler(setHeight, ref) + + handler({ current: { status: 'preEnter' } }) + expect(setHeight).toHaveBeenCalledWith(0) + }) +}) diff --git a/src/components/@atoms/ExpandableSection/ExpandableSection.tsx b/src/components/@atoms/ExpandableSection/ExpandableSection.tsx index 4721420a3..1ca850c2c 100644 --- a/src/components/@atoms/ExpandableSection/ExpandableSection.tsx +++ b/src/components/@atoms/ExpandableSection/ExpandableSection.tsx @@ -1,5 +1,5 @@ import { PropsWithChildren, useRef, useState } from 'react' -import { TransitionState, useTransition } from 'react-transition-state' +import { useTransition, type TransitionStatus } from 'react-transition-state' import styled, { css } from 'styled-components' import { DownChevronSVG, Typography } from '@ensdomains/thorin' @@ -38,7 +38,7 @@ const IconWrapper = styled.div<{ $open: boolean }>( `, ) -const Body = styled.div<{ $state: TransitionState; $height: number }>( +const Body = styled.div<{ $state: TransitionStatus; $height: number }>( ({ theme, $state, $height }) => css` overflow: hidden; width: 100%; @@ -86,6 +86,15 @@ type Props = { title: string } +export const stateChangeHandler = + (setHeight: React.Dispatch>, ref: React.RefObject) => + ({ current: newState }: { current: { status: TransitionStatus } }) => { + if (newState.status === 'preEnter' || newState.status === 'preExit') { + const height = ref.current?.getBoundingClientRect().height || 0 + setHeight(height) + } + } + export const ExpandableSection = ({ title, children }: PropsWithChildren) => { const ref = useRef(null) @@ -94,15 +103,10 @@ export const ExpandableSection = ({ title, children }: PropsWithChildren) timeout: 300, preEnter: true, preExit: true, - onChange: ({ state: _state }) => { - if (_state === 'preEnter' || _state === 'preExit') { - const _heigth = ref.current?.getBoundingClientRect().height || 0 - setHeight(_heigth) - } - }, + onStateChange: stateChangeHandler(setHeight, ref), }) - const open = ['entered', 'entering', 'preEnter'].includes(state) + const open = ['entered', 'entering', 'preEnter'].includes(state.status) return ( @@ -112,7 +116,7 @@ export const ExpandableSection = ({ title, children }: PropsWithChildren) - + {children} diff --git a/src/components/@molecules/AddRecordButton/AddRecordButton.tsx b/src/components/@molecules/AddRecordButton/AddRecordButton.tsx index 2ed6e8e60..1260c3f6d 100644 --- a/src/components/@molecules/AddRecordButton/AddRecordButton.tsx +++ b/src/components/@molecules/AddRecordButton/AddRecordButton.tsx @@ -1,6 +1,6 @@ import { ButtonHTMLAttributes, ReactNode, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import useTransition, { TransitionState } from 'react-transition-state' +import useTransition, { TransitionStatus } from 'react-transition-state' import styled, { css } from 'styled-components' import { Button, Input, MagnifyingGlassSimpleSVG, PlusSVG, Typography } from '@ensdomains/thorin' @@ -8,7 +8,7 @@ import { Button, Input, MagnifyingGlassSimpleSVG, PlusSVG, Typography } from '@e import UnsupportedSVG from '@app/assets/Unsupported.svg' import { formSafeKey } from '@app/utils/editor' -const Container = styled.div<{ $state: TransitionState }>( +const Container = styled.div<{ $state: TransitionStatus }>( ({ theme, $state }) => css` position: relative; border: 1px solid ${theme.colors.border}; @@ -43,7 +43,7 @@ const Container = styled.div<{ $state: TransitionState }>( `, ) -const ControlsContainer = styled.div<{ $state: TransitionState }>( +const ControlsContainer = styled.div<{ $state: TransitionStatus }>( ({ theme, $state }) => css` transition: all 0.3s ${theme.transitionTimingFunction.inOut}; top: 0; @@ -253,7 +253,7 @@ const SVGWrapper = styled.div( `, ) -const ButtonContainer = styled.div<{ $state: TransitionState }>( +const ButtonContainer = styled.div<{ $state: TransitionStatus }>( ({ theme, $state }) => css` transition: all 0.3s ${theme.transitionTimingFunction.inOut}; position: absolute; @@ -368,8 +368,8 @@ export const AddRecordButton = ({ } return ( - - + + {inputType === 'placeholder' ? ( @@ -427,7 +427,7 @@ export const AddRecordButton = ({ )} - +