mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Provide New UI Components for EIP-1559 Designs (#11357)
This commit is contained in:
parent
85de65f470
commit
6fa36cdf51
@ -798,6 +798,9 @@
|
|||||||
"gasFee": {
|
"gasFee": {
|
||||||
"message": "Gas Fee"
|
"message": "Gas Fee"
|
||||||
},
|
},
|
||||||
|
"gasFeeEstimate": {
|
||||||
|
"message": "Estimate"
|
||||||
|
},
|
||||||
"gasLimit": {
|
"gasLimit": {
|
||||||
"message": "Gas Limit"
|
"message": "Gas Limit"
|
||||||
},
|
},
|
||||||
@ -1085,6 +1088,12 @@
|
|||||||
"max": {
|
"max": {
|
||||||
"message": "Max"
|
"message": "Max"
|
||||||
},
|
},
|
||||||
|
"maxFee": {
|
||||||
|
"message": "Max fee"
|
||||||
|
},
|
||||||
|
"maxPriorityFee": {
|
||||||
|
"message": "Max priority fee"
|
||||||
|
},
|
||||||
"memo": {
|
"memo": {
|
||||||
"message": "memo"
|
"message": "memo"
|
||||||
},
|
},
|
||||||
@ -1478,6 +1487,9 @@
|
|||||||
"recipientAddressPlaceholder": {
|
"recipientAddressPlaceholder": {
|
||||||
"message": "Search, public address (0x), or ENS"
|
"message": "Search, public address (0x), or ENS"
|
||||||
},
|
},
|
||||||
|
"recommendedGasLabel": {
|
||||||
|
"message": "Recommended"
|
||||||
|
},
|
||||||
"recoveryPhraseReminderBackupStart": {
|
"recoveryPhraseReminderBackupStart": {
|
||||||
"message": "Start here"
|
"message": "Start here"
|
||||||
},
|
},
|
||||||
|
@ -433,6 +433,7 @@ function getEnvironmentVariables({ devMode, testing }) {
|
|||||||
PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '',
|
PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '',
|
||||||
PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '',
|
PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '',
|
||||||
CONF: devMode ? metamaskrc : {},
|
CONF: devMode ? metamaskrc : {},
|
||||||
|
SHOW_EIP_1559_UI: process.env.SHOW_EIP_1559_UI === '1',
|
||||||
SENTRY_DSN: process.env.SENTRY_DSN,
|
SENTRY_DSN: process.env.SENTRY_DSN,
|
||||||
SENTRY_DSN_DEV: metamaskrc.SENTRY_DSN_DEV,
|
SENTRY_DSN_DEV: metamaskrc.SENTRY_DSN_DEV,
|
||||||
INFURA_PROJECT_ID: testing
|
INFURA_PROJECT_ID: testing
|
||||||
|
@ -0,0 +1,87 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import Typography from '../../ui/typography/typography';
|
||||||
|
import {
|
||||||
|
COLORS,
|
||||||
|
TEXT_ALIGN,
|
||||||
|
DISPLAY,
|
||||||
|
TYPOGRAPHY,
|
||||||
|
FONT_WEIGHT,
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
import NumericInput from '../../ui/numeric-input/numeric-input.component';
|
||||||
|
import InfoTooltip from '../../ui/info-tooltip/info-tooltip';
|
||||||
|
|
||||||
|
export default function AdvancedGasControlsRow({
|
||||||
|
titleText,
|
||||||
|
tooltipText,
|
||||||
|
titleDetailText,
|
||||||
|
error,
|
||||||
|
onChange,
|
||||||
|
value,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('advanced-gas-controls__row', {
|
||||||
|
'advanced-gas-controls__row--error': error,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
<div className="advanced-gas-controls__row-heading">
|
||||||
|
<div className="advanced-gas-controls__row-heading-title">
|
||||||
|
<Typography
|
||||||
|
tag={TYPOGRAPHY.H6}
|
||||||
|
fontWeight={FONT_WEIGHT.BOLD}
|
||||||
|
variant={TYPOGRAPHY.H6}
|
||||||
|
boxProps={{ display: DISPLAY.INLINE_BLOCK }}
|
||||||
|
>
|
||||||
|
{titleText}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<InfoTooltip position="top" contentText={tooltipText} />
|
||||||
|
</div>
|
||||||
|
{titleDetailText && (
|
||||||
|
<Typography
|
||||||
|
className="advanced-gas-controls__row-heading-detail"
|
||||||
|
align={TEXT_ALIGN.END}
|
||||||
|
color={COLORS.UI4}
|
||||||
|
variant={TYPOGRAPHY.H8}
|
||||||
|
>
|
||||||
|
{titleDetailText}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<NumericInput error={error} onChange={onChange} value={value} />
|
||||||
|
{error && (
|
||||||
|
<Typography
|
||||||
|
color={COLORS.ERROR1}
|
||||||
|
variant={TYPOGRAPHY.H7}
|
||||||
|
className="advanced-gas-controls__row-error"
|
||||||
|
>
|
||||||
|
{error}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdvancedGasControlsRow.propTypes = {
|
||||||
|
titleText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
tooltipText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
titleDetailText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
error: PropTypes.string,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
value: PropTypes.number,
|
||||||
|
};
|
||||||
|
|
||||||
|
AdvancedGasControlsRow.defaultProps = {
|
||||||
|
titleText: '',
|
||||||
|
tooltipText: '',
|
||||||
|
titleDetailText: '',
|
||||||
|
error: '',
|
||||||
|
onChange: undefined,
|
||||||
|
value: 0,
|
||||||
|
};
|
@ -0,0 +1,75 @@
|
|||||||
|
import React, { useContext, useState } from 'react';
|
||||||
|
import { I18nContext } from '../../../contexts/i18n';
|
||||||
|
import Typography from '../../ui/typography/typography';
|
||||||
|
import {
|
||||||
|
FONT_WEIGHT,
|
||||||
|
TYPOGRAPHY,
|
||||||
|
COLORS,
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
import AdvancedGasControlsRow from './advanced-gas-controls-row.component';
|
||||||
|
|
||||||
|
export default function AdvancedGasControls() {
|
||||||
|
const t = useContext(I18nContext);
|
||||||
|
|
||||||
|
const [gasLimit, setGasLimit] = useState(0);
|
||||||
|
const [maxPriorityFee, setMaxPriorityFee] = useState(0);
|
||||||
|
const [maxFee, setMaxFee] = useState(0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="advanced-gas-controls">
|
||||||
|
<AdvancedGasControlsRow
|
||||||
|
titleText={t('gasLimit')}
|
||||||
|
onChange={setGasLimit}
|
||||||
|
tooltipText=""
|
||||||
|
titleDetailText=""
|
||||||
|
value={gasLimit}
|
||||||
|
/>
|
||||||
|
<AdvancedGasControlsRow
|
||||||
|
titleText={t('maxPriorityFee')}
|
||||||
|
tooltipText=""
|
||||||
|
onChange={setMaxPriorityFee}
|
||||||
|
value={maxPriorityFee}
|
||||||
|
titleDetailText={
|
||||||
|
<>
|
||||||
|
<Typography
|
||||||
|
tag="span"
|
||||||
|
color={COLORS.UI4}
|
||||||
|
variant={TYPOGRAPHY.H8}
|
||||||
|
fontWeight={FONT_WEIGHT.BOLD}
|
||||||
|
>
|
||||||
|
{t('gasFeeEstimate')}:
|
||||||
|
</Typography>{' '}
|
||||||
|
<Typography
|
||||||
|
tag="span"
|
||||||
|
color={COLORS.UI4}
|
||||||
|
variant={TYPOGRAPHY.H8}
|
||||||
|
></Typography>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<AdvancedGasControlsRow
|
||||||
|
titleText={t('maxFee')}
|
||||||
|
tooltipText=""
|
||||||
|
onChange={setMaxFee}
|
||||||
|
value={maxFee}
|
||||||
|
titleDetailText={
|
||||||
|
<>
|
||||||
|
<Typography
|
||||||
|
tag="span"
|
||||||
|
color={COLORS.UI4}
|
||||||
|
variant={TYPOGRAPHY.H8}
|
||||||
|
fontWeight={FONT_WEIGHT.BOLD}
|
||||||
|
>
|
||||||
|
{t('gasFeeEstimate')}:
|
||||||
|
</Typography>{' '}
|
||||||
|
<Typography
|
||||||
|
tag="span"
|
||||||
|
color={COLORS.UI4}
|
||||||
|
variant={TYPOGRAPHY.H8}
|
||||||
|
></Typography>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import AdvancedGasControls from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Advanced Gas Controls',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const simple = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '600px' }}>
|
||||||
|
<AdvancedGasControls />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
1
ui/components/app/advanced-gas-controls/index.js
Normal file
1
ui/components/app/advanced-gas-controls/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './advanced-gas-controls.component';
|
34
ui/components/app/advanced-gas-controls/index.scss
Normal file
34
ui/components/app/advanced-gas-controls/index.scss
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
.advanced-gas-controls {
|
||||||
|
&__row {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__row-heading {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-tooltip {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__row-heading-detail {
|
||||||
|
flex-grow: 1;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__row-error,
|
||||||
|
&__row--error h6 {
|
||||||
|
color: $error-1 !important;
|
||||||
|
padding-top: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h6 {
|
||||||
|
padding-bottom: 6px;
|
||||||
|
margin-inline-end: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
color: #dadada;
|
||||||
|
font-size: $font-size-h7;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
@import 'account-list-item/index';
|
@import 'account-list-item/index';
|
||||||
@import 'account-menu/index';
|
@import 'account-menu/index';
|
||||||
@import 'add-token-button/index';
|
@import 'add-token-button/index';
|
||||||
|
@import 'advanced-gas-controls/index';
|
||||||
@import 'alerts/alerts';
|
@import 'alerts/alerts';
|
||||||
@import 'app-header/index';
|
@import 'app-header/index';
|
||||||
@import 'asset-list-item/asset-list-item';
|
@import 'asset-list-item/asset-list-item';
|
||||||
@ -10,6 +11,7 @@
|
|||||||
@import 'connected-accounts-permissions/index';
|
@import 'connected-accounts-permissions/index';
|
||||||
@import 'connected-sites-list/index';
|
@import 'connected-sites-list/index';
|
||||||
@import 'connected-status-indicator/index';
|
@import 'connected-status-indicator/index';
|
||||||
|
@import 'edit-gas-display/index';
|
||||||
@import 'gas-customization/gas-modal-page-container/index';
|
@import 'gas-customization/gas-modal-page-container/index';
|
||||||
@import 'gas-customization/gas-price-button-group/index';
|
@import 'gas-customization/gas-price-button-group/index';
|
||||||
@import 'gas-customization/index';
|
@import 'gas-customization/index';
|
||||||
@ -32,10 +34,13 @@
|
|||||||
@import 'token-cell/token-cell';
|
@import 'token-cell/token-cell';
|
||||||
@import 'transaction-activity-log/index';
|
@import 'transaction-activity-log/index';
|
||||||
@import 'transaction-breakdown/index';
|
@import 'transaction-breakdown/index';
|
||||||
|
@import 'transaction-detail/index';
|
||||||
|
@import 'transaction-detail-item/index';
|
||||||
@import 'transaction-icon/transaction-icon';
|
@import 'transaction-icon/transaction-icon';
|
||||||
@import 'transaction-list-item-details/index';
|
@import 'transaction-list-item-details/index';
|
||||||
@import 'transaction-list-item/index';
|
@import 'transaction-list-item/index';
|
||||||
@import 'transaction-list/index';
|
@import 'transaction-list/index';
|
||||||
@import 'transaction-status/index';
|
@import 'transaction-status/index';
|
||||||
|
@import 'transaction-total-banner/index';
|
||||||
@import 'wallet-overview/index';
|
@import 'wallet-overview/index';
|
||||||
@import 'whats-new-popup/index';
|
@import 'whats-new-popup/index';
|
||||||
|
45
ui/components/app/edit-gas-display/edit-gas-display.js
Normal file
45
ui/components/app/edit-gas-display/edit-gas-display.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import React, { useState, useContext } from 'react';
|
||||||
|
|
||||||
|
import TransactionTotalBanner from '../transaction-total-banner/transaction-total-banner.component';
|
||||||
|
import RadioGroup from '../../ui/radio-group/radio-group.component';
|
||||||
|
|
||||||
|
import AdvancedGasControls from '../advanced-gas-controls/advanced-gas-controls.component';
|
||||||
|
|
||||||
|
import { I18nContext } from '../../../contexts/i18n';
|
||||||
|
|
||||||
|
export default function EditGasDisplay() {
|
||||||
|
const t = useContext(I18nContext);
|
||||||
|
const [showAdvancedForm, setShowAdvancedForm] = useState(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="edit-gas-display">
|
||||||
|
<TransactionTotalBanner
|
||||||
|
total="9.99"
|
||||||
|
detail="Up to $17.79 (0.01234 ETH)"
|
||||||
|
timing="Likely in < 30 seconds
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<RadioGroup
|
||||||
|
name="gas-recommendation"
|
||||||
|
options={[
|
||||||
|
{ value: 'low', label: 'Low', recommended: false },
|
||||||
|
{ value: 'medium', label: 'Medium', recommended: false },
|
||||||
|
{ value: 'high', label: 'High', recommended: true },
|
||||||
|
]}
|
||||||
|
selectedValue="high"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className="edit-gas-display__advanced-button"
|
||||||
|
onClick={() => setShowAdvancedForm(!showAdvancedForm)}
|
||||||
|
>
|
||||||
|
{t('advancedOptions')}{' '}
|
||||||
|
{showAdvancedForm ? (
|
||||||
|
<i className="fa fa-caret-up"></i>
|
||||||
|
) : (
|
||||||
|
<i className="fa fa-caret-down"></i>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
{showAdvancedForm && <AdvancedGasControls />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PopoverPortal from '../../ui/popover/popover.component';
|
||||||
|
import Button from '../../ui/button';
|
||||||
|
import EditGasDisplay from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Edit Gas Display',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const basic = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '600px' }}>
|
||||||
|
<EditGasDisplay />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const insidePopover = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '600px' }}>
|
||||||
|
<PopoverPortal
|
||||||
|
title="Edit gas fee"
|
||||||
|
onClose={() => console.log('Closing!')}
|
||||||
|
footer={
|
||||||
|
<>
|
||||||
|
<Button type="primary">Save</Button>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div style={{ padding: '20px' }}>
|
||||||
|
<EditGasDisplay />
|
||||||
|
</div>
|
||||||
|
</PopoverPortal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
1
ui/components/app/edit-gas-display/index.js
Normal file
1
ui/components/app/edit-gas-display/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './edit-gas-display';
|
17
ui/components/app/edit-gas-display/index.scss
Normal file
17
ui/components/app/edit-gas-display/index.scss
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
.edit-gas-display {
|
||||||
|
.radio-group {
|
||||||
|
margin: 20px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__advanced-button {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
background: transparent;
|
||||||
|
color: $primary-1;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advanced-gas-controls {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
}
|
1
ui/components/app/transaction-detail-item/index.js
Normal file
1
ui/components/app/transaction-detail-item/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './transaction-detail-item.component';
|
29
ui/components/app/transaction-detail-item/index.scss
Normal file
29
ui/components/app/transaction-detail-item/index.scss
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
.transaction-detail-item {
|
||||||
|
color: $ui-4;
|
||||||
|
|
||||||
|
&__row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-tooltip {
|
||||||
|
display: inline-block;
|
||||||
|
margin-inline-start: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__detail-text {
|
||||||
|
margin-inline-end: 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__total {
|
||||||
|
font-weight: bold;
|
||||||
|
color: $ui-black;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subtitle {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import Typography from '../../ui/typography/typography';
|
||||||
|
import {
|
||||||
|
COLORS,
|
||||||
|
FONT_WEIGHT,
|
||||||
|
TYPOGRAPHY,
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
export default function TransactionDetailItem({
|
||||||
|
detailTitle,
|
||||||
|
detailText,
|
||||||
|
detailTotal,
|
||||||
|
subTitle,
|
||||||
|
subText,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="transaction-detail-item">
|
||||||
|
<div className="transaction-detail-item__row">
|
||||||
|
<Typography
|
||||||
|
color={COLORS.BLACK}
|
||||||
|
fontWeight={FONT_WEIGHT.BOLD}
|
||||||
|
variant={TYPOGRAPHY.H6}
|
||||||
|
className="transaction-detail-item__title"
|
||||||
|
>
|
||||||
|
{detailTitle}
|
||||||
|
</Typography>
|
||||||
|
{detailText && (
|
||||||
|
<Typography className="transaction-detail-item__detail-text">
|
||||||
|
{detailText}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Typography
|
||||||
|
color={COLORS.BLACK}
|
||||||
|
fontWeight={FONT_WEIGHT.BOLD}
|
||||||
|
className="transaction-detail-item__total"
|
||||||
|
>
|
||||||
|
{detailTotal}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div className="transaction-detail-item__row">
|
||||||
|
{subTitle && (
|
||||||
|
<Typography
|
||||||
|
variant={TYPOGRAPHY.H7}
|
||||||
|
className="transaction-detail-item__subtitle"
|
||||||
|
>
|
||||||
|
{subTitle}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
<Typography variant={TYPOGRAPHY.H7}>{subText}</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionDetailItem.propTypes = {
|
||||||
|
detailTitle: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
detailText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
detailTotal: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
subTitle: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
subText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionDetailItem.defaultProps = {
|
||||||
|
detailTitle: '',
|
||||||
|
detailText: '',
|
||||||
|
detailTotal: '',
|
||||||
|
subTitle: '',
|
||||||
|
subText: '',
|
||||||
|
};
|
@ -0,0 +1,32 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import InfoTooltip from '../../ui/info-tooltip/info-tooltip';
|
||||||
|
import TransactionDetailItem from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Transaction Detail Item',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const basic = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '400px' }}>
|
||||||
|
<TransactionDetailItem
|
||||||
|
detailTitle={
|
||||||
|
<>
|
||||||
|
<strong>Estimated gas fee</strong>
|
||||||
|
<InfoTooltip contentText="This is the tooltip text" position="top">
|
||||||
|
<i className="fa fa-info-circle" />
|
||||||
|
</InfoTooltip>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
detailText="16565.30"
|
||||||
|
detailTotal="0.0089 ETH"
|
||||||
|
subTitle="Very likely in < 15 seconds"
|
||||||
|
subText={
|
||||||
|
<>
|
||||||
|
From <strong>$16565 - $19000</strong>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
1
ui/components/app/transaction-detail/index.js
Normal file
1
ui/components/app/transaction-detail/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './transaction-detail.component';
|
11
ui/components/app/transaction-detail/index.scss
Normal file
11
ui/components/app/transaction-detail/index.scss
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.transaction-detail {
|
||||||
|
.transaction-detail-item {
|
||||||
|
padding: 20px 0;
|
||||||
|
border-bottom: 1px solid $ui-3;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
padding-bottom: 0;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component';
|
||||||
|
|
||||||
|
export default function TransactionDetail({ rows }) {
|
||||||
|
return <div className="transaction-detail">{rows}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionDetail.propTypes = {
|
||||||
|
rows: PropTypes.arrayOf(TransactionDetailItem),
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionDetail.defaultProps = {
|
||||||
|
rows: [],
|
||||||
|
};
|
@ -0,0 +1,50 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import InfoTooltip from '../../ui/info-tooltip/info-tooltip';
|
||||||
|
import TransactionDetailItem from '../transaction-detail-item/transaction-detail-item.component';
|
||||||
|
import TransactionDetail from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Transaction Detail',
|
||||||
|
};
|
||||||
|
|
||||||
|
const rows = [
|
||||||
|
<TransactionDetailItem
|
||||||
|
key="line-1"
|
||||||
|
detailTitle={
|
||||||
|
<>
|
||||||
|
Estimated gas fee
|
||||||
|
<InfoTooltip contentText="This is the tooltip text" position="top">
|
||||||
|
<i className="fa fa-info-circle" />
|
||||||
|
</InfoTooltip>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
detailText="0.00896 ETH"
|
||||||
|
detailTotal="$15.73"
|
||||||
|
subTitle="Very likely in < 15 seconds"
|
||||||
|
subText={
|
||||||
|
<>
|
||||||
|
From <strong>$15.73 - $19.81</strong>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
<TransactionDetailItem
|
||||||
|
key="line-2"
|
||||||
|
detailTitle="Total"
|
||||||
|
detailText=".0312 ETH"
|
||||||
|
detailTotal="$15.77"
|
||||||
|
subTitle="Amount + gas fee"
|
||||||
|
subText={
|
||||||
|
<>
|
||||||
|
Up to <strong>$19.85</strong>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>,
|
||||||
|
];
|
||||||
|
|
||||||
|
export const basic = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '400px' }}>
|
||||||
|
<TransactionDetail rows={rows} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
1
ui/components/app/transaction-total-banner/index.js
Normal file
1
ui/components/app/transaction-total-banner/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './transaction-total-banner.component';
|
7
ui/components/app/transaction-total-banner/index.scss
Normal file
7
ui/components/app/transaction-total-banner/index.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.transaction-total-banner {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&__detail {
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
import Typography from '../../ui/typography/typography';
|
||||||
|
import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
export default function TransactionTotalBanner({ total, detail, timing }) {
|
||||||
|
return (
|
||||||
|
<div className="transaction-total-banner">
|
||||||
|
<Typography color={COLORS.BLACK} variant={TYPOGRAPHY.H1}>
|
||||||
|
{total}
|
||||||
|
</Typography>
|
||||||
|
{detail && (
|
||||||
|
<Typography
|
||||||
|
color={COLORS.BLACK}
|
||||||
|
variant={TYPOGRAPHY.H6}
|
||||||
|
className="transaction-total-banner__detail"
|
||||||
|
>
|
||||||
|
{detail}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{timing && (
|
||||||
|
<Typography
|
||||||
|
color={COLORS.UI4}
|
||||||
|
variant={TYPOGRAPHY.H7}
|
||||||
|
className="transaction-total-banner__timing"
|
||||||
|
>
|
||||||
|
{timing}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionTotalBanner.propTypes = {
|
||||||
|
total: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
detail: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
timing: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
|
||||||
|
};
|
||||||
|
|
||||||
|
TransactionTotalBanner.defaultProps = {
|
||||||
|
total: '',
|
||||||
|
detail: '',
|
||||||
|
timing: '',
|
||||||
|
};
|
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import TransactionTotalBanner from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Transaction Total Banner',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const basic = () => {
|
||||||
|
return (
|
||||||
|
<TransactionTotalBanner
|
||||||
|
total="~18.73"
|
||||||
|
detail={
|
||||||
|
<>
|
||||||
|
Up to <strong>$19.81</strong> (0.01234 ETH)
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
timing="Very likely in < 15 seconds"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
1
ui/components/ui/numeric-input/index.js
Normal file
1
ui/components/ui/numeric-input/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './numeric-input.component';
|
39
ui/components/ui/numeric-input/numeric-input.component.js
Normal file
39
ui/components/ui/numeric-input/numeric-input.component.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import Typography from '../typography/typography';
|
||||||
|
import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
export default function NumericInput({ detailText, value, onChange, error }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('numeric-input', { 'numeric-input--error': error })}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={value}
|
||||||
|
onChange={(e) => onChange?.(Number(e.target.value))}
|
||||||
|
min="0"
|
||||||
|
/>
|
||||||
|
{detailText && (
|
||||||
|
<Typography color={COLORS.UI4} variant={TYPOGRAPHY.H7} tag="span">
|
||||||
|
{detailText}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumericInput.propTypes = {
|
||||||
|
value: PropTypes.number,
|
||||||
|
detailText: PropTypes.string,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
error: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
NumericInput.defaultProps = {
|
||||||
|
value: 0,
|
||||||
|
detailText: '',
|
||||||
|
onChange: undefined,
|
||||||
|
error: '',
|
||||||
|
};
|
28
ui/components/ui/numeric-input/numeric-input.scss
Normal file
28
ui/components/ui/numeric-input/numeric-input.scss
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
.numeric-input {
|
||||||
|
border: 1px solid $ui-3;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
border-color: $error-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
border: 0;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
/* ensures the increment/decrement arrows always display */
|
||||||
|
&::-webkit-inner-spin-button,
|
||||||
|
&::-webkit-outer-spin-button {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
position: absolute;
|
||||||
|
right: 40px;
|
||||||
|
top: 7px;
|
||||||
|
}
|
||||||
|
}
|
36
ui/components/ui/numeric-input/numeric-input.stories.js
Normal file
36
ui/components/ui/numeric-input/numeric-input.stories.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import NumericInput from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'NumericInput',
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChange = (e) => console.log('changed value: ', e.target.value);
|
||||||
|
|
||||||
|
export const numericInput = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '600px' }}>
|
||||||
|
<NumericInput onChange={onChange} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const numericInputWithDetail = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '600px' }}>
|
||||||
|
<NumericInput detailText="= $0.06" onChange={onChange} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const numericInputWithError = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '600px' }}>
|
||||||
|
<NumericInput
|
||||||
|
detailText="= $0.06"
|
||||||
|
error="This number isn't great"
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
1
ui/components/ui/radio-group/index.js
Normal file
1
ui/components/ui/radio-group/index.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './radio-group.component';
|
49
ui/components/ui/radio-group/index.scss
Normal file
49
ui/components/ui/radio-group/index.scss
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
.radio-group {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
grid-template-rows: 100px;
|
||||||
|
width: 300px;
|
||||||
|
|
||||||
|
label {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column-recommended {
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column-line {
|
||||||
|
width: 1px;
|
||||||
|
height: 5px;
|
||||||
|
background-color: $ui-2;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column-horizontal-line {
|
||||||
|
height: 1px;
|
||||||
|
background-color: $ui-2;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column:first-child &__column-horizontal-line {
|
||||||
|
width: 50px;
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column:last-child &__column-horizontal-line {
|
||||||
|
width: 51px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column-radio {
|
||||||
|
margin-inline-end: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column-radio,
|
||||||
|
&__column-label {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__column-label {
|
||||||
|
padding-top: 6px;
|
||||||
|
}
|
||||||
|
}
|
64
ui/components/ui/radio-group/radio-group.component.js
Normal file
64
ui/components/ui/radio-group/radio-group.component.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import React, { useContext } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { I18nContext } from '../../../contexts/i18n';
|
||||||
|
import Typography from '../typography/typography';
|
||||||
|
import {
|
||||||
|
COLORS,
|
||||||
|
FONT_WEIGHT,
|
||||||
|
TYPOGRAPHY,
|
||||||
|
} from '../../../helpers/constants/design-system';
|
||||||
|
|
||||||
|
export default function RadioGroup({ options, name, selectedValue, onChange }) {
|
||||||
|
const t = useContext(I18nContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="radio-group">
|
||||||
|
{options.map((option) => {
|
||||||
|
return (
|
||||||
|
<div className="radio-group__column" key={`${name}-${option.value}`}>
|
||||||
|
<label>
|
||||||
|
<Typography
|
||||||
|
color={COLORS.SUCCESS3}
|
||||||
|
className="radio-group__column-recommended"
|
||||||
|
variant={TYPOGRAPHY.H7}
|
||||||
|
>
|
||||||
|
{option.recommended ? t('recommendedGasLabel') : ''}
|
||||||
|
</Typography>
|
||||||
|
|
||||||
|
<div className="radio-group__column-radio">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name={name}
|
||||||
|
defaultChecked={option.value === selectedValue}
|
||||||
|
value={option.value}
|
||||||
|
onChange={() => onChange?.(option.value)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="radio-group__column-line"></div>
|
||||||
|
<div className="radio-group__column-horizontal-line"></div>
|
||||||
|
<Typography
|
||||||
|
color={COLORS.UI4}
|
||||||
|
fontWeight={FONT_WEIGHT.BOLD}
|
||||||
|
variant={TYPOGRAPHY.H7}
|
||||||
|
className="radio-group__column-label"
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</Typography>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioGroup.propTypes = {
|
||||||
|
options: PropTypes.array,
|
||||||
|
selectedValue: PropTypes.string,
|
||||||
|
name: PropTypes.string,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
|
RadioGroup.defaultProps = {
|
||||||
|
options: [],
|
||||||
|
};
|
22
ui/components/ui/radio-group/radio-group.stories.js
Normal file
22
ui/components/ui/radio-group/radio-group.stories.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import RadioGroup from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'RadioGroup',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const radioGroup = () => {
|
||||||
|
return (
|
||||||
|
<div className="radio-group" style={{ minWidth: '600px' }}>
|
||||||
|
<RadioGroup
|
||||||
|
name="gas-recommendation"
|
||||||
|
options={[
|
||||||
|
{ value: 'low', label: 'Low', recommended: false },
|
||||||
|
{ value: 'medium', label: 'Medium', recommended: false },
|
||||||
|
{ value: 'high', label: 'High', recommended: true },
|
||||||
|
]}
|
||||||
|
selectedValue="high"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -25,9 +25,11 @@ export default function Typography({
|
|||||||
'typography',
|
'typography',
|
||||||
className,
|
className,
|
||||||
`typography--${variant}`,
|
`typography--${variant}`,
|
||||||
`typography--align-${align}`,
|
|
||||||
`typography--color-${color}`,
|
|
||||||
`typography--weight-${fontWeight}`,
|
`typography--weight-${fontWeight}`,
|
||||||
|
{
|
||||||
|
[`typography--align-${align}`]: Boolean(align),
|
||||||
|
[`typography--color-${color}`]: Boolean(color),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let Tag = tag ?? variant;
|
let Tag = tag ?? variant;
|
||||||
|
@ -33,10 +33,12 @@
|
|||||||
@import 'loading-indicator/loading-indicator';
|
@import 'loading-indicator/loading-indicator';
|
||||||
@import 'loading-screen/index';
|
@import 'loading-screen/index';
|
||||||
@import 'menu/menu';
|
@import 'menu/menu';
|
||||||
|
@import 'numeric-input/numeric-input';
|
||||||
@import 'page-container/index';
|
@import 'page-container/index';
|
||||||
@import 'popover/index';
|
@import 'popover/index';
|
||||||
@import 'pulse-loader/index';
|
@import 'pulse-loader/index';
|
||||||
@import 'qr-code/index';
|
@import 'qr-code/index';
|
||||||
|
@import 'radio-group/index';
|
||||||
@import 'readonly-input/index';
|
@import 'readonly-input/index';
|
||||||
@import 'sender-to-recipient/index';
|
@import 'sender-to-recipient/index';
|
||||||
@import 'snackbar/index';
|
@import 'snackbar/index';
|
||||||
|
@ -68,5 +68,5 @@ $sizes-strings:
|
|||||||
$border-style: solid, double, none, dashed, dotted;
|
$border-style: solid, double, none, dashed, dotted;
|
||||||
$directions: top, right, bottom, left;
|
$directions: top, right, bottom, left;
|
||||||
$display: block, grid, flex, inline-block, inline-grid, inline-flex, list-item;
|
$display: block, grid, flex, inline-block, inline-grid, inline-flex, list-item;
|
||||||
$text-align: left, right, center, justify;
|
$text-align: left, right, center, justify, end;
|
||||||
$font-weight: bold, normal, 100, 200, 300, 400, 500, 600, 700, 800, 900;
|
$font-weight: bold, normal, 100, 200, 300, 400, 500, 600, 700, 800, 900;
|
||||||
|
@ -139,6 +139,7 @@ export const TEXT_ALIGN = {
|
|||||||
CENTER: 'center',
|
CENTER: 'center',
|
||||||
RIGHT: 'right',
|
RIGHT: 'right',
|
||||||
JUSTIFY: 'justify',
|
JUSTIFY: 'justify',
|
||||||
|
END: 'end',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FONT_WEIGHT = {
|
export const FONT_WEIGHT = {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user