diff --git a/ui/components/multichain/address-copy-button/address-copy-button.js b/ui/components/multichain/address-copy-button/address-copy-button.js new file mode 100644 index 000000000000..f88fabdd8f40 --- /dev/null +++ b/ui/components/multichain/address-copy-button/address-copy-button.js @@ -0,0 +1,64 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import { ICON_NAMES, ButtonBase } from '../../component-library'; +import { + BackgroundColor, + TextVariant, + TextColor, + Size, + BorderRadius, + AlignItems, +} from '../../../helpers/constants/design-system'; +import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard'; +import { shortenAddress } from '../../../helpers/utils/util'; +import Tooltip from '../../ui/tooltip/tooltip'; +import { useI18nContext } from '../../../hooks/useI18nContext'; + +export const AddressCopyButton = ({ + address, + shorten = false, + wrap = false, +}) => { + const displayAddress = shorten ? shortenAddress(address) : address; + const [copied, handleCopy] = useCopyToClipboard(); + const t = useI18nContext(); + + return ( + + handleCopy(address)} + paddingRight={4} + paddingLeft={4} + size={Size.SM} + variant={TextVariant.bodyXs} + color={TextColor.primaryDefault} + endIconName={copied ? ICON_NAMES.COPY_SUCCESS : ICON_NAMES.COPY} + className={classnames('multichain-address-copy-button', { + 'multichain-address-copy-button__address--wrap': wrap, + })} + borderRadius={BorderRadius.pill} + alignItems={AlignItems.center} + data-testid="address-copy-button-text" + > + {displayAddress} + + + ); +}; + +AddressCopyButton.propTypes = { + /** + * Address to be copied + */ + address: PropTypes.string.isRequired, + /** + * Represents if the address should be shortened + */ + shorten: PropTypes.bool, + /** + * Represents if the element should wrap to multiple lines + */ + wrap: PropTypes.bool, +}; diff --git a/ui/components/multichain/address-copy-button/address-copy-button.stories.js b/ui/components/multichain/address-copy-button/address-copy-button.stories.js new file mode 100644 index 000000000000..869bfec255d7 --- /dev/null +++ b/ui/components/multichain/address-copy-button/address-copy-button.stories.js @@ -0,0 +1,36 @@ +import React from 'react'; +import { AddressCopyButton } from '.'; + +export default { + title: 'Components/Multichain/AddressCopyButton', + component: AddressCopyButton, + argTypes: { + address: { + control: 'text', + }, + shorten: { + control: 'boolean', + }, + wrap: { + control: 'boolean', + }, + }, + args: { + address: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', + }, +}; + +export const DefaultStory = (args) => ; +DefaultStory.storyName = 'Default'; + +export const ShortenedStory = (args) => ; +ShortenedStory.storyName = 'Shortened'; +ShortenedStory.args = { shorten: true }; + +export const WrappedStory = (args) => ( +
+ +
+); +WrappedStory.storyName = 'Wrapped'; +WrappedStory.args = { wrap: true }; diff --git a/ui/components/multichain/address-copy-button/address-copy-button.test.js b/ui/components/multichain/address-copy-button/address-copy-button.test.js new file mode 100644 index 000000000000..a885fe45dff9 --- /dev/null +++ b/ui/components/multichain/address-copy-button/address-copy-button.test.js @@ -0,0 +1,31 @@ +import React from 'react'; +import { fireEvent, render } from '@testing-library/react'; +import { AddressCopyButton } from '.'; + +const SAMPLE_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; + +describe('AccountListItem', () => { + it('renders the full address by default', () => { + render(); + expect( + document.querySelector('[data-testid="address-copy-button-text"]') + .textContent, + ).toStrictEqual(SAMPLE_ADDRESS); + }); + + it('renders a shortened address when it should', () => { + render(); + expect( + document.querySelector('[data-testid="address-copy-button-text"]') + .textContent, + ).toStrictEqual('0x0dc...e7bc'); + }); + + it('changes icon when clicked', () => { + render(); + fireEvent.click(document.querySelector('button')); + expect(document.querySelector('.mm-icon').style.maskImage).toContain( + 'copy-success.svg', + ); + }); +}); diff --git a/ui/components/multichain/address-copy-button/index.js b/ui/components/multichain/address-copy-button/index.js new file mode 100644 index 000000000000..8b93ba9b9378 --- /dev/null +++ b/ui/components/multichain/address-copy-button/index.js @@ -0,0 +1 @@ +export { AddressCopyButton } from './address-copy-button'; diff --git a/ui/components/multichain/address-copy-button/index.scss b/ui/components/multichain/address-copy-button/index.scss new file mode 100644 index 000000000000..12226fec171a --- /dev/null +++ b/ui/components/multichain/address-copy-button/index.scss @@ -0,0 +1,7 @@ +.multichain-address-copy-button { + &__address--wrap { + word-break: break-word; + min-height: 32px; + height: auto; + } +} diff --git a/ui/components/multichain/index.js b/ui/components/multichain/index.js index 29562dc8373a..edf6785b94cc 100644 --- a/ui/components/multichain/index.js +++ b/ui/components/multichain/index.js @@ -5,3 +5,4 @@ export { DetectedTokensBanner } from './detected-token-banner'; export { GlobalMenu } from './global-menu'; export { MultichainImportTokenLink } from './multichain-import-token-link'; export { MultichainTokenListItem } from './multichain-token-list-item'; +export { AddressCopyButton } from './address-copy-button'; diff --git a/ui/components/multichain/multichain-components.scss b/ui/components/multichain/multichain-components.scss index e8ee40ffa49e..8fe555f0ba21 100644 --- a/ui/components/multichain/multichain-components.scss +++ b/ui/components/multichain/multichain-components.scss @@ -4,6 +4,7 @@ * This will help improve specificity and reduce the chance of * unintended overrides. **/ +@import 'address-copy-button/index'; @import 'account-list-item/index'; @import 'account-list-menu/index'; @import 'multichain-token-list-item/multichain-token-list-item'; diff --git a/ui/components/ui/qr-code/qr-code.js b/ui/components/ui/qr-code/qr-code.js index 758620092839..995424c5f553 100644 --- a/ui/components/ui/qr-code/qr-code.js +++ b/ui/components/ui/qr-code/qr-code.js @@ -8,6 +8,8 @@ import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils import Tooltip from '../tooltip'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { Icon, ICON_NAMES, ICON_SIZES } from '../../component-library'; +import { AddressCopyButton } from '../../multichain/address-copy-button'; +import Box from '../box/box'; export default connect(mapStateToProps)(QrCodeView); @@ -56,25 +58,31 @@ function QrCodeView(props) { __html: qrImage.createTableTag(4), }} /> - -
{ - handleCopy(toChecksumHexAddress(data)); - }} + {process.env.MULTICHAIN ? ( + + + + ) : ( + -
{toChecksumHexAddress(data)}
- -
-
+
{ + handleCopy(toChecksumHexAddress(data)); + }} + > +
{toChecksumHexAddress(data)}
+ +
+ + )} ); }