diff --git a/packages/components/src/components/form/Input/Input.tsx b/packages/components/src/components/form/Input/Input.tsx index 4abf4851425..ea361cac63e 100644 --- a/packages/components/src/components/form/Input/Input.tsx +++ b/packages/components/src/components/form/Input/Input.tsx @@ -16,6 +16,7 @@ import { InputState, InputSize } from '../inputTypes'; import { TopAddons } from '../TopAddons'; import { useElevation } from '../../ElevationContext/ElevationContext'; import { UIHorizontalAlignment } from '../../../config/types'; +import { IconName } from '@suite-common/icons'; const Wrapper = styled.div<{ $width?: number; $hasBottomPadding: boolean }>` display: inline-flex; @@ -90,6 +91,7 @@ export interface InputProps extends Omit, * @description pass `null` if bottom text can be `undefined` */ bottomText?: ReactNode; + bottomTextIcon?: IconName; isDisabled?: boolean; size?: InputSize; className?: string; @@ -115,6 +117,7 @@ const Input = ({ innerAddon, innerAddonAlign = 'right', bottomText, + bottomTextIcon, size = 'large', isDisabled, 'data-testid': dataTest, @@ -203,7 +206,7 @@ const Input = ({ {bottomText && ( - + {bottomText} )} diff --git a/packages/components/src/components/form/inputTypes.ts b/packages/components/src/components/form/inputTypes.ts index 8168312e5dc..608e6ae841e 100644 --- a/packages/components/src/components/form/inputTypes.ts +++ b/packages/components/src/components/form/inputTypes.ts @@ -1,5 +1,5 @@ import { UISize } from '../../config/types'; -export type InputState = 'warning' | 'error'; +export type InputState = 'warning' | 'error' | 'primary'; export type InputSize = Extract; diff --git a/packages/components/src/components/typography/Link/Link.tsx b/packages/components/src/components/typography/Link/Link.tsx index a7cb2827228..1c282162c18 100644 --- a/packages/components/src/components/typography/Link/Link.tsx +++ b/packages/components/src/components/typography/Link/Link.tsx @@ -89,6 +89,7 @@ const Link = ({ e.stopPropagation(); onClick?.(e); }} + $type={type} $variant={variant} className={className} > diff --git a/packages/suite/src/components/wallet/InputError.tsx b/packages/suite/src/components/wallet/InputError.tsx index ff8f5518272..424f3b5dbb9 100644 --- a/packages/suite/src/components/wallet/InputError.tsx +++ b/packages/suite/src/components/wallet/InputError.tsx @@ -12,6 +12,17 @@ const Wrapper = styled.div` gap: ${spacingsPx.xs}; `; +const ButtonWrapper = styled.div` + position: absolute; + top: 4px; + right: 16px; +`; + +const ContentWrapper = styled.div` + flex-grow: 1; + padding-right: 150px; +`; + type ButtonProps = { onClick: MouseEventHandler; text: string }; type LinkProps = { url: Url }; @@ -22,14 +33,16 @@ export type InputErrorProps = { export const InputError = ({ button, message }: InputErrorProps) => ( - {message} + {message} {button && ('url' in button ? ( ) : ( - + + + ))} ); diff --git a/packages/suite/src/views/wallet/send/Outputs/Address.tsx b/packages/suite/src/views/wallet/send/Outputs/Address.tsx index 1fe11709b27..724c9ab5a09 100644 --- a/packages/suite/src/views/wallet/send/Outputs/Address.tsx +++ b/packages/suite/src/views/wallet/send/Outputs/Address.tsx @@ -18,7 +18,10 @@ import { getInputState, } from '@suite-common/wallet-utils'; -import { AddressLabeling, Translation, MetadataLabeling } from 'src/components/suite'; +import { AddressLabeling, MetadataLabeling } from 'src/components/suite'; +import { Link } from '@trezor/components'; +import { Translation } from '../../../../components/suite/Translation'; + import { scanOrRequestSendFormThunk } from 'src/actions/wallet/send/sendFormThunks'; import { useDevice, useDispatch, useTranslation } from 'src/hooks/suite'; import { useSendFormContext } from 'src/hooks/wallet'; @@ -26,7 +29,10 @@ import { getProtocolInfo } from 'src/utils/suite/protocol'; import { PROTOCOL_TO_NETWORK } from 'src/constants/suite/protocol'; import { InputError } from 'src/components/wallet'; import { InputErrorProps } from 'src/components/wallet/InputError'; +import { Row } from '@trezor/components'; +import { HELP_CENTER_EVM_ADDRESS_CHECKSUM } from '@trezor/urls'; +import { spacings } from '@trezor/theme'; const Container = styled.div` position: relative; `; @@ -68,7 +74,6 @@ export const Address = ({ output, outputId, outputsCount }: AddressProps) => { setDraftSaveRequest, } = useSendFormContext(); const { translationString } = useTranslation(); - const { descriptor, networkType, symbol } = account; const inputName = `outputs.${outputId}.address` as const; // NOTE: compose errors are always associated with the amount. @@ -84,7 +89,16 @@ export const Address = ({ output, outputId, outputsCount }: AddressProps) => { const options = getDefaultValue('options', []); const broadcastEnabled = options.includes('broadcast'); const isOnline = useSelector(state => state.suite.online); - const inputState = getInputState(addressError); + const getInputErrorState = () => { + if (hasAddressChecksummed) { + return 'primary'; + } + if (addressError) { + return getInputState(addressError); + } + + return undefined; + }; const handleQrClick = useCallback(async () => { const uri = await dispatch(scanOrRequestSendFormThunk()).unwrap(); @@ -256,10 +270,49 @@ export const Address = ({ output, outputId, outputsCount }: AddressProps) => { }); const addressBottomText = isAddressWithLabel ? addressLabelComponent : null; + const getBottomText = () => { + if (hasAddressChecksummed) { + return ( + + ( + + {chunks} + + ), + }} + /> + + ); + } + if (addressError) { + return ( + + ); + } + + return addressBottomText; + }; + + const getBottomTextIcon = () => { + if (hasAddressChecksummed) { + return 'check'; + } + + return undefined; + }; + return ( @@ -321,16 +374,8 @@ export const Address = ({ output, outputId, outputsCount }: AddressProps) => { /> ) : undefined } - bottomText={ - addressError ? ( - - ) : ( - addressBottomText - ) - } + bottomText={getBottomText()} + bottomTextIcon={getBottomTextIcon()} data-testid={inputName} defaultValue={addressValue} maxLength={formInputsMaxLength.address}