add CopyButton component
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
import type { Story } from '@ladle/react';
|
||||
|
||||
import { CopyButton, type CopyButtonProps } from '@/components/CopyButton';
|
||||
|
||||
import { StoryWrapper } from '.ladle/components';
|
||||
|
||||
export const CopyButtonStory: Story<CopyButtonProps> = (args) => (
|
||||
<StoryWrapper>
|
||||
<CopyButton {...args} />
|
||||
</StoryWrapper>
|
||||
);
|
||||
|
||||
CopyButtonStory.args = {
|
||||
value: 'some text to copy',
|
||||
};
|
||||
|
||||
CopyButtonStory.argTypes = {
|
||||
shownAsText: {
|
||||
options: [true, false],
|
||||
control: { type: 'select' },
|
||||
defaultValue: false,
|
||||
},
|
||||
children: {
|
||||
options: ['some text to copy'],
|
||||
control: { type: 'select' },
|
||||
defaultValue: undefined,
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
import { useState } from 'react';
|
||||
import styled, { css, type AnyStyledComponent } from 'styled-components';
|
||||
|
||||
import { ButtonAction } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
|
||||
import { useStringGetter } from '@/hooks';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
import { Button, ButtonProps } from './Button';
|
||||
import { Icon, IconName } from './Icon';
|
||||
|
||||
export type CopyButtonProps = {
|
||||
value?: string;
|
||||
shownAsText?: boolean;
|
||||
children?: React.ReactNode;
|
||||
} & ButtonProps;
|
||||
|
||||
export const CopyButton = ({ value, shownAsText, children, ...buttonProps }: CopyButtonProps) => {
|
||||
const stringGetter = useStringGetter();
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const onCopy = () => {
|
||||
if (!value) return;
|
||||
|
||||
setCopied(true);
|
||||
navigator.clipboard.writeText(value);
|
||||
setTimeout(() => setCopied(false), 500);
|
||||
};
|
||||
|
||||
return shownAsText ? (
|
||||
<Styled.InlineRow onClick={onCopy} copied={copied}>
|
||||
{children}
|
||||
<Icon iconName={IconName.Copy} />
|
||||
</Styled.InlineRow>
|
||||
) : (
|
||||
<Button
|
||||
{...buttonProps}
|
||||
action={copied ? ButtonAction.Create : ButtonAction.Primary}
|
||||
onClick={onCopy}
|
||||
>
|
||||
<Icon iconName={IconName.Copy} />
|
||||
{children ?? stringGetter({ key: copied ? STRING_KEYS.COPIED : STRING_KEYS.COPY })}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.InlineRow = styled.div<{ copied: boolean }>`
|
||||
${layoutMixins.inlineRow}
|
||||
cursor: pointer;
|
||||
|
||||
${({ copied }) =>
|
||||
copied
|
||||
? css`
|
||||
filter: brightness(0.8);
|
||||
`
|
||||
: css`
|
||||
&:hover {
|
||||
filter: brightness(1.1);
|
||||
text-decoration: underline;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
@@ -9,7 +9,7 @@ import { breakpoints } from '@/styles';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
|
||||
import { AlertMessage } from '@/components/AlertMessage';
|
||||
import { Button } from '@/components/Button';
|
||||
import { CopyButton } from '@/components/CopyButton';
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import { Checkbox } from '@/components/Checkbox';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
@@ -30,21 +30,12 @@ export const MnemonicExportDialog = ({ setIsOpen }: ElementProps) => {
|
||||
const [hasAcknowledged, setHasAcknowledged] = useState(false);
|
||||
const [currentStep, setCurrentStep] = useState(MnemonicExportStep.AcknowledgeRisk);
|
||||
const [isShowing, setIsShowing] = useState(false);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const stringGetter = useStringGetter();
|
||||
|
||||
const { hdKey } = useAccounts();
|
||||
const { mnemonic } = hdKey ?? {};
|
||||
|
||||
const onCopy = () => {
|
||||
setCopied(true);
|
||||
if (mnemonic) {
|
||||
navigator.clipboard.writeText(mnemonic);
|
||||
}
|
||||
setTimeout(() => setCopied(false), 500);
|
||||
};
|
||||
|
||||
const title = {
|
||||
[MnemonicExportStep.AcknowledgeRisk]: stringGetter({ key: STRING_KEYS.REVEAL_SECRET_PHRASE }),
|
||||
[MnemonicExportStep.DisplayMnemonic]: stringGetter({ key: STRING_KEYS.EXPORT_SECRET_PHRASE }),
|
||||
@@ -116,10 +107,7 @@ export const MnemonicExportDialog = ({ setIsOpen }: ElementProps) => {
|
||||
</Styled.WordList>
|
||||
}
|
||||
>
|
||||
<Button action={copied ? ButtonAction.Create : ButtonAction.Primary} onClick={onCopy}>
|
||||
<Icon iconName={IconName.Copy} />
|
||||
{stringGetter({ key: copied ? STRING_KEYS.COPIED : STRING_KEYS.COPY })}
|
||||
</Button>
|
||||
<CopyButton value={mnemonic} />
|
||||
</WithReceipt>
|
||||
</>
|
||||
),
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import styled, { type AnyStyledComponent } from 'styled-components';
|
||||
|
||||
import { ButtonAction } from '@/constants/buttons';
|
||||
import { STRING_KEYS } from '@/constants/localization';
|
||||
import { DydxChainAsset } from '@/constants/wallets';
|
||||
|
||||
@@ -10,9 +9,8 @@ import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { useAccounts, useStringGetter } from '@/hooks';
|
||||
|
||||
import { AssetIcon } from '@/components/AssetIcon';
|
||||
import { Button } from '@/components/Button';
|
||||
import { CopyButton } from '@/components/CopyButton';
|
||||
import { Dialog } from '@/components/Dialog';
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
import { QrCode } from '@/components/QrCode';
|
||||
import { SelectItem, SelectMenu } from '@/components/SelectMenu';
|
||||
import { WithDetailsReceipt } from '@/components/WithDetailsReceipt';
|
||||
@@ -31,14 +29,6 @@ export const ReceiveDialog = ({ selectedAsset = DydxChainAsset.DYDX, setIsOpen }
|
||||
const { dydxAddress } = useAccounts();
|
||||
|
||||
const [asset, setAsset] = useState(selectedAsset);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const onCopy = () => {
|
||||
if (!dydxAddress) return;
|
||||
setCopied(true);
|
||||
navigator.clipboard.writeText(dydxAddress);
|
||||
setTimeout(() => setCopied(false), 500);
|
||||
};
|
||||
|
||||
const assetOptions = [
|
||||
{
|
||||
@@ -89,10 +79,7 @@ export const ReceiveDialog = ({ selectedAsset = DydxChainAsset.DYDX, setIsOpen }
|
||||
>
|
||||
<QrCode hasLogo value={dydxAddress!} />
|
||||
</Styled.WithDetailsReceipt>
|
||||
<Button action={copied ? ButtonAction.Create : ButtonAction.Primary} onClick={onCopy}>
|
||||
<Icon iconName={IconName.Copy} />
|
||||
{stringGetter({ key: copied ? STRING_KEYS.COPIED : STRING_KEYS.COPY_ADDRESS })}
|
||||
</Button>
|
||||
<CopyButton value={dydxAddress} />
|
||||
</>
|
||||
)}
|
||||
</Styled.Content>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useState } from 'react';
|
||||
import styled, { type AnyStyledComponent, css } from 'styled-components';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import type { ColumnSize } from '@react-types/table';
|
||||
|
||||
import { type SubaccountTransfer } from '@/constants/abacus';
|
||||
import { ButtonAction } from '@/constants/buttons';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { STRING_KEYS, StringGetterFunction } from '@/constants/localization';
|
||||
|
||||
import { useBreakpoints, useStringGetter } from '@/hooks';
|
||||
@@ -11,20 +12,19 @@ import { useBreakpoints, useStringGetter } from '@/hooks';
|
||||
import { layoutMixins } from '@/styles/layoutMixins';
|
||||
import { tradeViewMixins } from '@/styles/tradeViewMixins';
|
||||
|
||||
import { Icon, IconName } from '@/components/Icon';
|
||||
import { Button } from '@/components/Button';
|
||||
import { CopyButton } from '@/components/CopyButton';
|
||||
import { Icon } from '@/components/Icon';
|
||||
import { Link } from '@/components/Link';
|
||||
import { Output, OutputType } from '@/components/Output';
|
||||
import { Table, TableCell, TableColumnHeader, type ColumnDef } from '@/components/Table';
|
||||
import { OnboardingTriggerButton } from '@/views/dialogs/OnboardingTriggerButton';
|
||||
|
||||
import { getSubaccountTransfers } from '@/state/accountSelectors';
|
||||
import { calculateCanAccountTrade } from '@/state/accountCalculators';
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
|
||||
import { truncateAddress } from '@/lib/wallet';
|
||||
import { Button } from '@/components/Button';
|
||||
import { ButtonAction } from '@/constants/buttons';
|
||||
import { openDialog } from '@/state/dialogs';
|
||||
import { DialogTypes } from '@/constants/dialogs';
|
||||
import { Link } from '@/components/Link';
|
||||
import { calculateCanAccountTrade } from '@/state/accountCalculators';
|
||||
import { OnboardingTriggerButton } from '../dialogs/OnboardingTriggerButton';
|
||||
|
||||
const MOBILE_TRANSFERS_PER_PAGE = 50;
|
||||
|
||||
@@ -79,8 +79,12 @@ const getTransferHistoryTableColumnDef = ({
|
||||
),
|
||||
renderCell: ({ fromAddress, toAddress }) => (
|
||||
<TableCell stacked>
|
||||
<CopyableAddress address={fromAddress ?? undefined} />
|
||||
<CopyableAddress address={toAddress ?? undefined} />
|
||||
<CopyButton shownAsText value={fromAddress ?? undefined}>
|
||||
{fromAddress ? truncateAddress(fromAddress) : '-'}
|
||||
</CopyButton>{' '}
|
||||
<CopyButton shownAsText value={toAddress ?? undefined}>
|
||||
{toAddress ? truncateAddress(toAddress) : '-'}
|
||||
</CopyButton>
|
||||
</TableCell>
|
||||
),
|
||||
},
|
||||
@@ -168,26 +172,6 @@ export const TransferHistoryTable = ({
|
||||
);
|
||||
};
|
||||
|
||||
const CopyableAddress = ({ address }: { address?: string }) => {
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const onCopy = () => {
|
||||
if (!address) return;
|
||||
setCopied(true);
|
||||
navigator.clipboard.writeText(address);
|
||||
setTimeout(() => setCopied(false), 500);
|
||||
};
|
||||
|
||||
return address ? (
|
||||
<Styled.CopyableAddress onClick={onCopy} copied={copied}>
|
||||
{truncateAddress(address)}
|
||||
<Icon iconName={IconName.Copy} />
|
||||
</Styled.CopyableAddress>
|
||||
) : (
|
||||
'-'
|
||||
);
|
||||
};
|
||||
|
||||
const Styled: Record<string, AnyStyledComponent> = {};
|
||||
|
||||
Styled.Table = styled(Table)`
|
||||
@@ -209,19 +193,3 @@ Styled.TimeOutput = styled(Output)`
|
||||
Styled.TxHash = styled(Link)`
|
||||
justify-content: flex-end;
|
||||
`;
|
||||
|
||||
Styled.CopyableAddress = styled(Styled.InlineRow)<{ copied: boolean }>`
|
||||
cursor: pointer;
|
||||
|
||||
${({ copied }) =>
|
||||
copied
|
||||
? css`
|
||||
filter: brightness(0.8);
|
||||
`
|
||||
: css`
|
||||
&:hover {
|
||||
filter: brightness(1.1);
|
||||
text-decoration: underline;
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user