commit
5a8ca9d16e
@ -0,0 +1,13 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
set -e |
||||
set -u |
||||
set -o pipefail |
||||
|
||||
# Generate LavaMoat policies for the extension background script for each build |
||||
# type. |
||||
# ATTN: This may tax your device when running it locally. |
||||
concurrently --kill-others-on-fail -n main,beta,flask \ |
||||
"WRITE_AUTO_POLICY=1 yarn dist" \ |
||||
"WRITE_AUTO_POLICY=1 yarn dist --build-type beta" \ |
||||
"WRITE_AUTO_POLICY=1 yarn dist --build-type flask" |
@ -0,0 +1,55 @@ |
||||
{ |
||||
"resources": { |
||||
"browser-resolve": { |
||||
"packages": { |
||||
"core-js": true |
||||
} |
||||
}, |
||||
"babel-runtime": { |
||||
"packages": { |
||||
"@babel/runtime": true |
||||
} |
||||
}, |
||||
"node-fetch": { |
||||
"globals": { |
||||
"fetch": true |
||||
} |
||||
}, |
||||
"lodash": { |
||||
"globals": { |
||||
"setTimeout": true, |
||||
"clearTimeout": true |
||||
} |
||||
}, |
||||
"@ethersproject/random": { |
||||
"globals": { |
||||
"crypto.getRandomValues": true |
||||
} |
||||
}, |
||||
"browser-passworder": { |
||||
"globals": { |
||||
"crypto": true |
||||
} |
||||
}, |
||||
"randombytes": { |
||||
"globals": { |
||||
"crypto.getRandomValues": true |
||||
} |
||||
}, |
||||
"extensionizer": { |
||||
"globals": { |
||||
"console": true |
||||
} |
||||
}, |
||||
"web3": { |
||||
"globals": { |
||||
"XMLHttpRequest": true |
||||
} |
||||
}, |
||||
"storage": { |
||||
"globals": { |
||||
"localStorage": true |
||||
} |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,55 @@ |
||||
{ |
||||
"resources": { |
||||
"browser-resolve": { |
||||
"packages": { |
||||
"core-js": true |
||||
} |
||||
}, |
||||
"babel-runtime": { |
||||
"packages": { |
||||
"@babel/runtime": true |
||||
} |
||||
}, |
||||
"node-fetch": { |
||||
"globals": { |
||||
"fetch": true |
||||
} |
||||
}, |
||||
"lodash": { |
||||
"globals": { |
||||
"setTimeout": true, |
||||
"clearTimeout": true |
||||
} |
||||
}, |
||||
"@ethersproject/random": { |
||||
"globals": { |
||||
"crypto.getRandomValues": true |
||||
} |
||||
}, |
||||
"browser-passworder": { |
||||
"globals": { |
||||
"crypto": true |
||||
} |
||||
}, |
||||
"randombytes": { |
||||
"globals": { |
||||
"crypto.getRandomValues": true |
||||
} |
||||
}, |
||||
"extensionizer": { |
||||
"globals": { |
||||
"console": true |
||||
} |
||||
}, |
||||
"web3": { |
||||
"globals": { |
||||
"XMLHttpRequest": true |
||||
} |
||||
}, |
||||
"storage": { |
||||
"globals": { |
||||
"localStorage": true |
||||
} |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,94 @@ |
||||
import React from 'react'; |
||||
import { screen } from '@testing-library/react'; |
||||
|
||||
import { ETH } from '../../../helpers/constants/common'; |
||||
import { GasFeeContextProvider } from '../../../contexts/gasFee'; |
||||
import { renderWithProvider } from '../../../../test/jest'; |
||||
import configureStore from '../../../store/store'; |
||||
|
||||
import TransactionDetail from './transaction-detail.component'; |
||||
|
||||
jest.mock('../../../store/actions', () => ({ |
||||
disconnectGasFeeEstimatePoller: jest.fn(), |
||||
getGasFeeEstimatesAndStartPolling: jest |
||||
.fn() |
||||
.mockImplementation(() => Promise.resolve()), |
||||
addPollingTokenToAppState: jest.fn(), |
||||
})); |
||||
|
||||
const render = (props) => { |
||||
const store = configureStore({ |
||||
metamask: { |
||||
nativeCurrency: ETH, |
||||
preferences: { |
||||
useNativeCurrencyAsPrimaryCurrency: true, |
||||
}, |
||||
provider: {}, |
||||
cachedBalances: {}, |
||||
accounts: { |
||||
'0xAddress': { |
||||
address: '0xAddress', |
||||
balance: '0x176e5b6f173ebe66', |
||||
}, |
||||
}, |
||||
selectedAddress: '0xAddress', |
||||
featureFlags: { advancedInlineGas: true }, |
||||
}, |
||||
}); |
||||
|
||||
return renderWithProvider( |
||||
<GasFeeContextProvider {...props}> |
||||
<TransactionDetail |
||||
onEdit={() => { |
||||
console.log('on edit'); |
||||
}} |
||||
rows={[]} |
||||
{...props} |
||||
/> |
||||
</GasFeeContextProvider>, |
||||
store, |
||||
); |
||||
}; |
||||
|
||||
describe('TransactionDetail', () => { |
||||
beforeEach(() => { |
||||
process.env.EIP_1559_V2 = true; |
||||
}); |
||||
afterEach(() => { |
||||
process.env.EIP_1559_V2 = false; |
||||
}); |
||||
it('should render edit link with text low if low gas estimates are selected', () => { |
||||
render({ transaction: { userFeeLevel: 'low' } }); |
||||
expect(screen.queryByText('🐢')).toBeInTheDocument(); |
||||
expect(screen.queryByText('Low')).toBeInTheDocument(); |
||||
}); |
||||
it('should render edit link with text markey if medium gas estimates are selected', () => { |
||||
render({ transaction: { userFeeLevel: 'medium' } }); |
||||
expect(screen.queryByText('🦊')).toBeInTheDocument(); |
||||
expect(screen.queryByText('Market')).toBeInTheDocument(); |
||||
}); |
||||
it('should render edit link with text agressive if high gas estimates are selected', () => { |
||||
render({ transaction: { userFeeLevel: 'high' } }); |
||||
expect(screen.queryByText('🦍')).toBeInTheDocument(); |
||||
expect(screen.queryByText('Aggressive')).toBeInTheDocument(); |
||||
}); |
||||
it('should render edit link with text Site suggested if site suggested estimated are used', () => { |
||||
render({ |
||||
transaction: { |
||||
dappSuggestedGasFees: { maxFeePerGas: 1, maxPriorityFeePerGas: 1 }, |
||||
txParams: { maxFeePerGas: 1, maxPriorityFeePerGas: 1 }, |
||||
}, |
||||
}); |
||||
expect(screen.queryByText('🌐')).toBeInTheDocument(); |
||||
expect(screen.queryByText('Site suggested')).toBeInTheDocument(); |
||||
expect(document.getElementsByClassName('info-tooltip')).toHaveLength(1); |
||||
}); |
||||
it('should render edit link with text advance if custom gas estimates are used', () => { |
||||
render({ |
||||
defaultEstimateToUse: 'custom', |
||||
}); |
||||
expect(screen.queryByText('⚙')).toBeInTheDocument(); |
||||
expect(screen.queryByText('Advanced')).toBeInTheDocument(); |
||||
expect(screen.queryByText('Edit')).toBeInTheDocument(); |
||||
}); |
||||
}); |
@ -0,0 +1,42 @@ |
||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; |
||||
|
||||
import Card from '.'; |
||||
|
||||
# Card |
||||
|
||||
Cards are used to group related content or actions together. |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-ui-card-card-stories-js--default-story" /> |
||||
</Canvas> |
||||
|
||||
## Component API |
||||
|
||||
The `Card` component extends the `Box` component. See the `Box` component for an extended list of props. |
||||
|
||||
<ArgsTable of={Card} /> |
||||
|
||||
## Usage |
||||
|
||||
The following describes the props and example usage for this component. |
||||
|
||||
### Padding, Border and Background Color |
||||
|
||||
The Card component has a set of default props that should meet most card use cases. There is a strong recommendation to not overwrite these to ensure our cards stay consistent across the app. |
||||
|
||||
That being said all props can be overwritten if necessary. |
||||
|
||||
```jsx |
||||
import { COLORS } from '../../../helpers/constants/design-system'; |
||||
|
||||
// To remove the border |
||||
<Card border={false} /> |
||||
// All border related props of the Box component will work |
||||
|
||||
// To remove or change padding |
||||
<Card padding={0} /> |
||||
// All padding related props of the Box component will work |
||||
|
||||
// To change the background color |
||||
<Card backgroundColor={COLORS.UI4} /> |
||||
``` |
@ -1,23 +0,0 @@ |
||||
import React, { PureComponent } from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
import classnames from 'classnames'; |
||||
|
||||
export default class Card extends PureComponent { |
||||
static propTypes = { |
||||
className: PropTypes.string, |
||||
overrideClassName: PropTypes.bool, |
||||
title: PropTypes.string, |
||||
children: PropTypes.node, |
||||
}; |
||||
|
||||
render() { |
||||
const { className, overrideClassName, title } = this.props; |
||||
|
||||
return ( |
||||
<div className={classnames({ card: !overrideClassName }, className)}> |
||||
<div className="card__title">{title}</div> |
||||
{this.props.children} |
||||
</div> |
||||
); |
||||
} |
||||
} |
@ -1,21 +0,0 @@ |
||||
import React from 'react'; |
||||
import { shallow } from 'enzyme'; |
||||
import Card from './card.component'; |
||||
|
||||
describe('Card Component', () => { |
||||
it('should render a card with a title and child element', () => { |
||||
const wrapper = shallow( |
||||
<Card title="Test" className="card-test-class"> |
||||
<div className="child-test-class">Child</div> |
||||
</Card>, |
||||
); |
||||
|
||||
expect(wrapper.hasClass('card-test-class')).toStrictEqual(true); |
||||
const title = wrapper.find('.card__title'); |
||||
expect(title).toHaveLength(1); |
||||
expect(title.text()).toStrictEqual('Test'); |
||||
const child = wrapper.find('.child-test-class'); |
||||
expect(child).toHaveLength(1); |
||||
expect(child.text()).toStrictEqual('Child'); |
||||
}); |
||||
}); |
@ -0,0 +1,60 @@ |
||||
import React from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
|
||||
import Box from '../box'; |
||||
import { |
||||
BORDER_STYLE, |
||||
COLORS, |
||||
SIZES, |
||||
} from '../../../helpers/constants/design-system'; |
||||
|
||||
const Card = ({ |
||||
border = true, |
||||
padding = 4, |
||||
backgroundColor = COLORS.WHITE, |
||||
children, |
||||
...props |
||||
}) => { |
||||
const defaultBorderProps = { |
||||
borderColor: border && COLORS.UI2, |
||||
borderRadius: border && SIZES.MD, |
||||
borderStyle: border && BORDER_STYLE.SOLID, |
||||
}; |
||||
|
||||
return ( |
||||
<Box |
||||
{...{ |
||||
padding, |
||||
backgroundColor, |
||||
...defaultBorderProps, |
||||
...props, |
||||
}} |
||||
> |
||||
{children} |
||||
</Box> |
||||
); |
||||
}; |
||||
|
||||
Card.propTypes = { |
||||
/** |
||||
* Whether the Card has a border or not. |
||||
* Defaults to true |
||||
*/ |
||||
border: PropTypes.bool, |
||||
/** |
||||
* Padding of the Card component accepts number or an array of 2 numbers. |
||||
* Defaults to 4 (16px) |
||||
*/ |
||||
padding: Box.propTypes.padding, |
||||
/** |
||||
* The background color of the card |
||||
* Defaults to COLORS.WHITE |
||||
*/ |
||||
backgroundColor: Box.propTypes.backgroundColor, |
||||
/** |
||||
* The Card component accepts all Box component props |
||||
*/ |
||||
...Box.propTypes, |
||||
}; |
||||
|
||||
export default Card; |
@ -0,0 +1,169 @@ |
||||
import React from 'react'; |
||||
import { |
||||
ALIGN_ITEMS, |
||||
BLOCK_SIZES, |
||||
BORDER_STYLE, |
||||
COLORS, |
||||
DISPLAY, |
||||
JUSTIFY_CONTENT, |
||||
TEXT_ALIGN, |
||||
} from '../../../helpers/constants/design-system'; |
||||
|
||||
import README from './README.mdx'; |
||||
import Card from '.'; |
||||
|
||||
const sizeOptions = [undefined, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]; |
||||
|
||||
export default { |
||||
title: 'UI/Card', |
||||
id: __filename, |
||||
component: Card, |
||||
parameters: { |
||||
docs: { |
||||
page: README, |
||||
}, |
||||
}, |
||||
argTypes: { |
||||
children: { control: 'text' }, |
||||
border: { |
||||
control: 'boolean', |
||||
}, |
||||
borderStyle: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: Object.values(BORDER_STYLE), |
||||
}, |
||||
borderWidth: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
borderColor: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: Object.values(COLORS), |
||||
}, |
||||
backgroundColor: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: Object.values(COLORS), |
||||
}, |
||||
width: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: Object.values(BLOCK_SIZES), |
||||
}, |
||||
height: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: Object.values(BLOCK_SIZES), |
||||
}, |
||||
textAlign: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: Object.values(TEXT_ALIGN), |
||||
}, |
||||
margin: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
marginTop: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
marginRight: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
marginBottom: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
marginLeft: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
padding: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
paddingTop: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
paddingRight: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
paddingBottom: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
paddingLeft: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: [...sizeOptions], |
||||
}, |
||||
display: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: Object.values(DISPLAY), |
||||
}, |
||||
justifyContent: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: Object.values(JUSTIFY_CONTENT), |
||||
}, |
||||
alignItems: { |
||||
control: { |
||||
type: 'select', |
||||
}, |
||||
options: Object.values(ALIGN_ITEMS), |
||||
}, |
||||
}, |
||||
args: { |
||||
children: 'Card children', |
||||
}, |
||||
}; |
||||
|
||||
export const DefaultStory = (args) => <Card {...args}>{args.children}</Card>; |
||||
|
||||
DefaultStory.storyName = 'Default'; |
||||
|
||||
DefaultStory.args = { |
||||
padding: 4, |
||||
border: true, |
||||
borderWidth: 1, |
||||
borderColor: COLORS.UI2, |
||||
borderStyle: BORDER_STYLE.SOLID, |
||||
backgroundColor: COLORS.WHITE, |
||||
display: DISPLAY.BLOCK, |
||||
}; |
@ -0,0 +1,11 @@ |
||||
import * as React from 'react'; |
||||
import { render } from '@testing-library/react'; |
||||
import Card from '.'; |
||||
|
||||
describe('Card', () => { |
||||
it('should render the Card without crashing', () => { |
||||
const { getByText } = render(<Card>Card content</Card>); |
||||
|
||||
expect(getByText('Card content')).toBeDefined(); |
||||
}); |
||||
}); |
@ -1 +1 @@ |
||||
export { default } from './card.component'; |
||||
export { default } from './card'; |
||||
|
@ -1,11 +0,0 @@ |
||||
.card { |
||||
border-radius: 4px; |
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); |
||||
padding: 8px; |
||||
|
||||
&__title { |
||||
border-bottom: 1px solid #d8d8d8; |
||||
padding-bottom: 4px; |
||||
text-transform: capitalize; |
||||
} |
||||
} |
@ -0,0 +1,15 @@ |
||||
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs'; |
||||
|
||||
import Chip from '.'; |
||||
|
||||
# Chip |
||||
|
||||
Chips are compact elements that represent an input, status, or action. |
||||
|
||||
<Canvas> |
||||
<Story id="ui-components-ui-chip-chip-stories-js--default-story" /> |
||||
</Canvas> |
||||
|
||||
## Component API |
||||
|
||||
<ArgsTable of={Chip} /> |
@ -0,0 +1,37 @@ |
||||
import React, { createContext, useContext } from 'react'; |
||||
import PropTypes from 'prop-types'; |
||||
import { useGasFeeInputs } from '../hooks/gasFeeInput/useGasFeeInputs'; |
||||
|
||||
export const GasFeeContext = createContext({}); |
||||
|
||||
export const GasFeeContextProvider = ({ |
||||
children, |
||||
defaultEstimateToUse, |
||||
transaction, |
||||
minimumGasLimit, |
||||
editGasMode, |
||||
}) => { |
||||
const gasFeeDetails = useGasFeeInputs( |
||||
defaultEstimateToUse, |
||||
transaction, |
||||
minimumGasLimit, |
||||
editGasMode, |
||||
); |
||||
return ( |
||||
<GasFeeContext.Provider value={gasFeeDetails}> |
||||
{children} |
||||
</GasFeeContext.Provider> |
||||
); |
||||
}; |
||||
|
||||
export function useGasFeeContext() { |
||||
return useContext(GasFeeContext); |
||||
} |
||||
|
||||
GasFeeContextProvider.propTypes = { |
||||
children: PropTypes.node.isRequired, |
||||
defaultEstimateToUse: PropTypes.string, |
||||
transaction: PropTypes.object.isRequired, |
||||
minimumGasLimit: PropTypes.string, |
||||
editGasMode: PropTypes.string, |
||||
}; |
@ -0,0 +1,65 @@ |
||||
import React, { useState } from 'react'; |
||||
import { useHistory } from 'react-router-dom'; |
||||
import { useI18nContext } from '../../hooks/useI18nContext'; |
||||
import { DEFAULT_ROUTE } from '../../helpers/constants/routes'; |
||||
|
||||
import Box from '../../components/ui/box'; |
||||
import TextField from '../../components/ui/text-field'; |
||||
import PageContainer from '../../components/ui/page-container'; |
||||
|
||||
export default function AddCollectible() { |
||||
const t = useI18nContext(); |
||||
const history = useHistory(); |
||||
|
||||
const [address, setAddress] = useState(''); |
||||
const [tokenId, setTokenId] = useState(''); |
||||
|
||||
return ( |
||||
<PageContainer |
||||
title={t('addNFT')} |
||||
onSubmit={() => { |
||||
console.log( |
||||
`Adding collectible with ID: ${tokenId} and address ${address}`, |
||||
); |
||||
history.push(DEFAULT_ROUTE); |
||||
}} |
||||
submitText={t('add')} |
||||
onCancel={() => { |
||||
history.push(DEFAULT_ROUTE); |
||||
}} |
||||
onClose={() => { |
||||
history.push(DEFAULT_ROUTE); |
||||
}} |
||||
disabled={false} |
||||
contentComponent={ |
||||
<Box padding={4}> |
||||
<Box> |
||||
<TextField |
||||
id="address" |
||||
label={t('address')} |
||||
placeholder="0x..." |
||||
type="text" |
||||
value={address} |
||||
onChange={(e) => setAddress(e.target.value)} |
||||
fullWidth |
||||
autoFocus |
||||
margin="normal" |
||||
/> |
||||
</Box> |
||||
<Box> |
||||
<TextField |
||||
id="token-id" |
||||
label={t('id')} |
||||
placeholder={t('nftTokenIdPlaceholder')} |
||||
type="number" |
||||
value={tokenId} |
||||
onChange={(e) => setTokenId(e.target.value)} |
||||
fullWidth |
||||
margin="normal" |
||||
/> |
||||
</Box> |
||||
</Box> |
||||
} |
||||
/> |
||||
); |
||||
} |
@ -0,0 +1 @@ |
||||
export { default } from './add-collectible.component'; |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue