Browse Source

Merge pull request #269 from loeck/master

Receive funds Modal
master
Loëck Vézien 7 years ago
committed by GitHub
parent
commit
c7d00df715
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 41
      package.json
  2. 83
      src/components/Breadcrumb/Step.js
  3. 118
      src/components/Breadcrumb/index.js
  4. 34
      src/components/Breadcrumb/stories.js
  5. 206
      src/components/CurrentAddress/index.js
  6. 22
      src/components/CurrentAddress/stories.js
  7. 69
      src/components/DeviceCheckAddress.js
  8. 178
      src/components/DeviceConfirm/index.js
  9. 11
      src/components/DeviceConfirm/stories.js
  10. 2
      src/components/DeviceMonitNew/index.js
  11. 74
      src/components/RequestAmount/index.js
  12. 11
      src/components/RequestAmount/stories.js
  13. 5
      src/components/SelectAccount/index.js
  14. 5
      src/components/SelectAccount/stories.js
  15. 8
      src/components/base/Button/index.js
  16. 14
      src/components/base/CopyToClipboard.js
  17. 5
      src/components/base/InputCurrency/index.js
  18. 2
      src/components/base/Label.js
  19. 5
      src/components/base/Modal/ModalBody.js
  20. 32
      src/components/base/Modal/index.js
  21. 32
      src/components/base/Print.js
  22. 3
      src/components/base/QRCode/index.js
  23. 109
      src/components/base/Select/index.js
  24. 2
      src/components/base/Select/stories.js
  25. 50
      src/components/layout/Print.js
  26. 2
      src/components/modals/AddAccount/index.js
  27. 2
      src/components/modals/Receive/01-step-account.js
  28. 68
      src/components/modals/Receive/03-step-confirm-address.js
  29. 49
      src/components/modals/Receive/04-step-receive-funds.js
  30. 246
      src/components/modals/Receive/index.js
  31. 2
      src/components/modals/Send/index.js
  32. 8
      src/components/modals/StepConnectDevice.js
  33. 12
      src/icons/AngleLeft.js
  34. 12
      src/icons/Copy.js
  35. 12
      src/icons/Print.js
  36. 12
      src/icons/Share.js
  37. 49
      src/icons/Shield.js
  38. 2
      src/internals/usb/manager/helpers.js
  39. 2
      src/main/bridge.js
  40. 2
      src/renderer/index.js
  41. 5
      src/styles/theme.js
  42. 2
      static/i18n/en/common.yml
  43. 1
      static/i18n/en/currentAddress.yml
  44. 11
      static/i18n/en/receive.yml
  45. 283
      yarn.lock

41
package.json

@ -49,8 +49,9 @@
"@ledgerhq/hw-app-eth": "^4.7.3",
"@ledgerhq/hw-transport": "^4.7.3",
"@ledgerhq/hw-transport-node-hid": "^4.7.6",
"@ledgerhq/wallet-common": "^0.12.0",
"@ledgerhq/wallet-common": "^0.13.2",
"axios": "^0.18.0",
"babel-runtime": "^6.26.0",
"bcryptjs": "^2.4.3",
"bitcoinjs-lib": "^3.3.2",
"bs58check": "^2.1.1",
@ -58,23 +59,23 @@
"cross-env": "^5.1.4",
"d3": "^5.0.0",
"debug": "^3.1.0",
"downshift": "^1.31.2",
"downshift": "^1.31.6",
"electron-store": "^1.3.0",
"electron-updater": "^2.21.4",
"fuse.js": "^3.2.0",
"history": "^4.7.2",
"i18next": "^10.6.0",
"i18next": "^11.1.1",
"i18next-node-fs-backend": "^1.0.0",
"ledger-test-library": "KhalilBellakrid/ledger-test-library-nodejs#7d37482",
"lodash": "^4.17.5",
"moment": "^2.22.0",
"object-path": "^0.11.4",
"qrcode": "^1.2.0",
"query-string": "^6.0.0",
"raven": "^2.4.2",
"raven-js": "^3.24.0",
"react": "^16.3.0",
"react-dom": "^16.3.0",
"qs": "^6.5.1",
"raven": "^2.5.0",
"raven-js": "^3.24.1",
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-i18next": "^7.5.1",
"react-mortal": "^3.2.0",
"react-motion": "^0.5.2",
@ -92,28 +93,28 @@
"source-map-support": "^0.5.4",
"styled-components": "^3.2.5",
"styled-system": "^2.2.1",
"tippy.js": "^2.4.1",
"tippy.js": "^2.5.0",
"ws": "^5.1.1"
},
"devDependencies": {
"@babel/core": "7.0.0-beta.42",
"@babel/polyfill": "7.0.0-beta.42",
"@babel/preset-env": "7.0.0-beta.42",
"@babel/preset-flow": "7.0.0-beta.42",
"@babel/preset-react": "7.0.0-beta.42",
"@babel/preset-stage-0": "7.0.0-beta.42",
"@storybook/addon-actions": "^3.4.0",
"@storybook/addon-knobs": "^3.4.0",
"@storybook/addon-links": "^3.4.0",
"@storybook/addon-options": "^3.4.0",
"@storybook/addons": "^3.4.0",
"@storybook/react": "^3.4.0",
"@storybook/addon-actions": "^3.4.1",
"@storybook/addon-knobs": "^3.4.1",
"@storybook/addon-links": "^3.4.1",
"@storybook/addon-options": "^3.4.1",
"@storybook/addons": "^3.4.1",
"@storybook/react": "^3.4.1",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "^8.2.1",
"babel-jest": "^22.4.3",
"babel-loader": "^8.0.0-beta.2",
"babel-plugin-module-resolver": "^3.1.1",
"babel-plugin-styled-components": "^1.5.0",
"babel-polyfill": "^6.26.0",
"chalk": "^2.3.1",
"chance": "^1.0.13",
"concurrently": "^3.5.1",
@ -137,14 +138,14 @@
"husky": "^0.14.3",
"jest": "^22.4.3",
"js-yaml": "^3.10.0",
"lint-staged": "^7.0.2",
"lint-staged": "^7.0.4",
"node-loader": "^0.6.0",
"prettier": "^1.11.1",
"react-hot-loader": "^4.0.1",
"react-test-renderer": "^16.3.0",
"webpack": "^4.4.1",
"react-test-renderer": "^16.3.1",
"webpack": "^4.5.0",
"webpack-bundle-analyzer": "^2.11.1",
"webpack-cli": "^2.0.13",
"webpack-cli": "^2.0.14",
"yaml-loader": "^0.5.0"
}
}

83
src/components/Breadcrumb/Step.js

@ -1,16 +1,21 @@
// @flow
import React, { Fragment } from 'react'
import React from 'react'
import styled from 'styled-components'
import Box from 'components/base/Box'
const RADIUS = 17
import IconCheck from 'icons/Check'
import IconCross from 'icons/Cross'
const RADIUS = 18
const Wrapper = styled(Box).attrs({
align: 'center',
justify: 'center',
color: p => (p.isActive ? 'wallet' : 'fog'),
alignItems: 'center',
color: p =>
['active', 'valid'].includes(p.status) ? 'wallet' : p.status === 'error' ? 'alertRed' : 'grey',
grow: true,
justifyContent: 'center',
})`
width: ${RADIUS}px;
flex-shrink: 0;
@ -18,44 +23,20 @@ const Wrapper = styled(Box).attrs({
font-size: 9px;
`
const Number = styled(Box).attrs({
align: 'center',
justify: 'center',
const StepNumber = styled(Box).attrs({
alignItems: 'center',
justifyContent: 'center',
color: 'white',
bg: p => (p.isActive ? 'wallet' : 'fog'),
bg: p =>
['active', 'valid'].includes(p.status) ? 'wallet' : p.status === 'error' ? 'alertRed' : 'fog',
ff: 'Rubik|Regular',
})`
width: ${RADIUS}px;
height: ${RADIUS}px;
border-radius: 50%;
font-size: 10px;
height: ${RADIUS}px;
line-height: 10px;
box-shadow: ${p => `0 0 0 ${p.isActive ? 4 : 0}px ${p.theme.colors.lightGrey}`};
transition: all ease-in-out 0.1s ${p => (p.isActive ? 0.4 : 0)}s;
`
const Bar = styled.div`
height: 2px;
background: ${p => p.theme.colors.fog};
flex-grow: 1;
max-width: 100px;
position: relative;
margin-top: -2px;
&:after {
background: ${p => p.theme.colors.pearl};
content: '';
display: block;
left: 0;
right: 0;
top: 0;
bottom: 0;
position: absolute;
background: ${p => p.theme.colors.wallet};
transition: transform ease-in-out 0.4s;
transform-origin: center left;
transform: scaleX(${p => (p.isActive ? 1 : 0)});
}
transition: all ease-in-out 0.1s ${p => (['active', 'valid'].includes(p.status) ? 0.4 : 0)}s;
width: ${RADIUS}px;
`
const Label = styled(Box).attrs({
@ -63,27 +44,31 @@ const Label = styled(Box).attrs({
ff: 'Museo Sans|Bold',
})`
position: absolute;
margin-top: 27px;
transition: color ease-in-out 0.1s ${p => (p.isActive ? 0.4 : 0)}s;
margin-top: 23px;
transition: color ease-in-out 0.1s ${p => (['active', 'valid'].includes(p.status) ? 0.4 : 0)}s;
`
type Props = {
number: number,
isActive: boolean,
isFirst: boolean,
status: 'next' | 'active' | 'valid' | 'error' | 'disable',
children: any,
}
function Step(props: Props) {
const { number, isActive, isFirst, children } = props
const { number, status, children } = props
return (
<Fragment>
{!isFirst && <Bar isActive={isActive} />}
<Wrapper isActive={isActive}>
<Number isActive={isActive}>{number}</Number>
<Label isActive={isActive}>{children}</Label>
</Wrapper>
</Fragment>
<Wrapper status={status}>
<StepNumber status={status}>
{status === 'active' || status === 'next' ? (
number
) : status === 'valid' ? (
<IconCheck size={10} />
) : (
<IconCross size={10} />
)}
</StepNumber>
<Label status={status}>{children}</Label>
</Wrapper>
)
}

118
src/components/Breadcrumb/index.js

@ -8,36 +8,116 @@ import styled from 'styled-components'
import Box from 'components/base/Box'
import Step from './Step'
type Props = {
items: Array<Object>,
currentStep: number | string,
}
const Wrapper = styled(Box).attrs({
horizontal: true,
align: 'center',
justify: 'center',
alignItems: 'center',
justifyContent: 'center',
relative: true,
})`
margin-bottom: 25px;
z-index: 2;
`
const Bar = styled.div`
background: ${p => p.theme.colors.fog};
flex-grow: 1;
height: 1px;
left: ${p => p.start}%;
position: absolute;
right: ${p => p.end}%;
top: 8px;
z-index: 1;
&:after,
&:before {
bottom: 0;
content: '';
display: block;
left: 0;
position: absolute;
right: auto;
top: 0;
transition: right ease-in-out 0.4s;
}
&:after {
background: ${p => p.theme.colors.wallet};
right: ${p => (p.current === 0 ? 0 : `${p.current}%`)};
z-index: 1;
}
&:before {
background: ${p => p.theme.colors.fog};
left: ${p => (p.disabled ? `${p.disabled[0]}%` : 0)};
right: ${p => (p.disabled ? `${p.disabled[1]}%` : 'auto')};
z-index: 2;
}
`
const indexToPurcent = (index, itemsLength) => 100 - 100 / (itemsLength - 1) * parseInt(index, 10)
type Props = {
currentStep: number | string,
items: Array<Object>,
stepsDisabled: Array<number>,
stepsErrors: Array<number>,
}
class Breadcrumb extends PureComponent<Props> {
static defaultProps = {
stepsDisabled: [],
stepsErrors: [],
}
render() {
const { items, currentStep, ...props } = this.props
const { items, stepsDisabled, stepsErrors, currentStep, ...props } = this.props
const itemsLength = items.length
const start = 100 / itemsLength / 2
return (
<Box {...props}>
<Box {...props} relative>
<Wrapper>
{items.map((item, i) => (
<Step
key={i}
isActive={i <= parseInt(currentStep, 10)}
isFirst={i === 0}
number={i + 1}
>
{item.label}
</Step>
))}
{items.map((item, i) => {
let status = 'next'
const stepIndex = parseInt(currentStep, 10)
if (i === stepIndex) {
status = 'active'
}
if (i < stepIndex) {
status = 'valid'
}
if (stepsErrors.includes(i)) {
status = 'error'
}
if (stepsDisabled.includes(i)) {
status = 'disable'
}
return (
<Step key={i} status={status} number={i + 1}>
{item.label}
</Step>
)
})}
</Wrapper>
<Bar
end={start}
start={start}
disabled={
stepsDisabled.length > 0
? [
stepsDisabled[0] === 0 ? 0 : indexToPurcent(stepsDisabled[0] + 1, itemsLength),
indexToPurcent(stepsDisabled[stepsDisabled.length - 1], itemsLength),
]
: null
}
current={!currentStep ? 100 : indexToPurcent(currentStep, itemsLength)}
/>
</Box>
)
}

34
src/components/Breadcrumb/stories.js

@ -2,23 +2,31 @@
import React from 'react'
import { storiesOf } from '@storybook/react'
import { number } from '@storybook/addon-knobs'
import { array, number } from '@storybook/addon-knobs'
import Breadcrumb from 'components/Breadcrumb'
const stories = storiesOf('Components', module)
stories.add('Breadcrumb', () => (
<Breadcrumb
currentStep={number('currentStep', 1, {
min: 1,
max: 4,
})}
items={[
{ label: 'Amount' },
{ label: 'Summary' },
{ label: 'Secure validation' },
{ label: 'Confirmation' },
]}
/>
<div
style={{
width: 400,
}}
>
<Breadcrumb
currentStep={number('currentStep', 1, {
min: 0,
max: 3,
})}
stepsDisabled={array('stepsDisabled', []).map(a => Number(a))}
stepsErrors={array('stepsErrors', []).map(a => Number(a))}
items={[
{ label: 'Amount' },
{ label: 'Summary' },
{ label: 'Secure validation' },
{ label: 'Confirmation' },
]}
/>
</div>
))

206
src/components/CurrentAddress/index.js

@ -0,0 +1,206 @@
// @flow
import React, { PureComponent } from 'react'
import { translate } from 'react-i18next'
import styled from 'styled-components'
import noop from 'lodash/noop'
import type { T } from 'types/common'
import { rgba } from 'styles/helpers'
import Box from 'components/base/Box'
import CopyToClipboard from 'components/base/CopyToClipboard'
import Print from 'components/base/Print'
import QRCode from 'components/base/QRCode'
import IconCheck from 'icons/Check'
import IconCopy from 'icons/Copy'
import IconInfoCircle from 'icons/InfoCircle'
import IconPrint from 'icons/Print'
import IconShare from 'icons/Share'
import IconShield from 'icons/Shield'
const Container = styled(Box).attrs({
borderRadius: 1,
alignItems: 'center',
bg: p => (p.withQRCode ? 'lightGrey' : 'transparent'),
py: 5,
px: 7,
})``
const WrapperAddress = styled(Box).attrs({
alignItems: 'center',
borderRadius: 1,
py: p => (p.notValid ? 4 : 0),
px: 4,
})`
background: ${p => (p.notValid ? rgba(p.theme.colors.alertRed, 0.05) : 'transparent')};
border: ${p => (p.notValid ? `1px dashed ${rgba(p.theme.colors.alertRed, 0.26)}` : 'none')};
width: 100%;
`
const Address = styled(Box).attrs({
bg: p => (p.notValid ? 'transparent' : p.withQRCode ? 'white' : 'lightGrey'),
borderRadius: 1,
color: 'dark',
ff: 'Open Sans|SemiBold',
fontSize: 4,
mt: 2,
px: p => (p.notValid ? 0 : 4),
py: p => (p.notValid ? 0 : 3),
})`
border: ${p => (p.notValid ? 'none' : `1px dashed ${p.theme.colors.fog}`)};
cursor: text;
user-select: text;
`
const Label = styled(Box).attrs({
alignItems: 'center',
color: 'graphite',
ff: 'Open Sans|SemiBold',
fontSize: 4,
flow: 1,
horizontal: true,
})``
const Footer = styled(Box).attrs({
horizontal: true,
mt: 5,
})`
text-transform: uppercase;
width: 100%;
`
const FooterButtonWrapper = styled(Box).attrs({
color: 'grey',
alignItems: 'center',
justifyContent: 'center',
grow: true,
})`
cursor: pointer;
`
const FooterButton = ({
icon,
label,
onClick,
}: {
icon: any,
label: string,
onClick: Function,
}) => (
<FooterButtonWrapper onClick={onClick}>
{icon}
<Box fontSize={3} ff="Museo Sans|Bold" mt={1}>
{label}
</Box>
</FooterButtonWrapper>
)
type Props = {
address: string,
addressVerified?: boolean,
amount?: string,
onCopy: Function,
onPrint: Function,
onShare: Function,
onVerify: Function,
t: T,
withBadge: boolean,
withFooter: boolean,
withQRCode: boolean,
withVerify: boolean,
}
class CurrentAddress extends PureComponent<Props> {
static defaultProps = {
addressVerified: null,
amount: null,
onCopy: noop,
onPrint: noop,
onShare: noop,
onVerify: noop,
withBadge: false,
withFooter: false,
withQRCode: false,
withVerify: false,
}
render() {
const {
address,
addressVerified,
amount,
onCopy,
onPrint,
onShare,
onVerify,
t,
withBadge,
withFooter,
withQRCode,
withVerify,
...props
} = this.props
const notValid = addressVerified === false
return (
<Container withQRCode={withQRCode} notValid={notValid} {...props}>
<WrapperAddress notValid={notValid} grow>
{withQRCode && (
<Box mb={4}>
<QRCode size={150} data={`bitcoin:${address}${amount ? `?amount=${amount}` : ''}`} />
</Box>
)}
<Label>
<Box>{t('currentAddress:label')}</Box>
<IconInfoCircle size={12} />
</Label>
<Address withQRCode={withQRCode} notValid={notValid}>
{address}
</Address>
</WrapperAddress>
{withBadge && (
<Box horizontal flow={2} mt={2} alignItems="center">
<Box color={notValid ? 'alertRed' : 'wallet'}>
<IconShield height={32} width={28} />
</Box>
<Box shrink fontSize={12} color={notValid ? 'alertRed' : 'dark'} ff="Open Sans">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam blandit velit egestas leo
tincidunt
</Box>
</Box>
)}
{withFooter && (
<Footer>
{withVerify && (
<FooterButton icon={<IconCheck size={16} />} label="Verify" onClick={onVerify} />
)}
<CopyToClipboard
data={address}
render={copy => (
<FooterButton icon={<IconCopy size={16} />} label="Copy" onClick={copy} />
)}
/>
<Print
data={{ address, amount }}
render={(print, isLoading) => (
<FooterButton
icon={<IconPrint size={16} />}
label={isLoading ? '...' : 'Print'}
onClick={print}
/>
)}
/>
<FooterButton icon={<IconShare size={16} />} label="Share" onClick={onShare} />
</Footer>
)}
</Container>
)
}
}
export default translate()(CurrentAddress)

22
src/components/CurrentAddress/stories.js

@ -0,0 +1,22 @@
// @flow
import React from 'react'
import { storiesOf } from '@storybook/react'
import { boolean } from '@storybook/addon-knobs'
import CurrentAddress from 'components/CurrentAddress'
import { accounts } from 'components/SelectAccount/stories'
const stories = storiesOf('Components', module)
stories.add('CurrentAddress', () => (
<CurrentAddress
address={accounts[0].address}
addressVerified={boolean('addressVerified', true)}
withBadge={boolean('withBadge', false)}
withFooter={boolean('withFooter', false)}
withQRCode={boolean('withQRCode', false)}
withVerify={boolean('withVerify', false)}
/>
))

69
src/components/DeviceCheckAddress.js

@ -0,0 +1,69 @@
// @flow
import { PureComponent } from 'react'
import { ipcRenderer } from 'electron'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { Device } from 'types/common'
import { sendEvent } from 'renderer/events'
type Props = {
onCheck: Function,
render: Function,
account: Account,
device: Device,
}
type State = {
isVerified: null | boolean,
}
class CheckAddress extends PureComponent<Props, State> {
state = {
isVerified: null,
}
componentDidMount() {
const { device, account } = this.props
ipcRenderer.on('msg', this.handleMsgEvent)
this.verifyAddress({ device, account })
}
componentWillUnmount() {
ipcRenderer.removeListener('msg', this.handleMsgEvent)
}
handleMsgEvent = (e: any, { type }: { type: string }) => {
const { onCheck } = this.props
if (type === 'wallet.verifyAddress.success') {
this.setState({
isVerified: true,
})
onCheck(true)
}
if (type === 'wallet.verifyAddress.fail') {
this.setState({
isVerified: false,
})
onCheck(false)
}
}
verifyAddress = ({ device, account }: { device: Device, account: Account }) =>
sendEvent('usb', 'wallet.verifyAddress', {
pathDevice: device.path,
path: `${account.rootPath}${account.path}`,
})
render() {
const { render } = this.props
const { isVerified } = this.state
return render({ isVerified })
}
}
export default CheckAddress

178
src/components/DeviceConfirm/index.js

@ -0,0 +1,178 @@
// @flow
import React from 'react'
import styled, { keyframes } from 'styled-components'
import { rgba } from 'styles/helpers'
import Box from 'components/base/Box'
import IconCheck from 'icons/Check'
import IconCross from 'icons/Cross'
const pulseAnimation = p => keyframes`
0% {
box-shadow: 0 0 0 1px ${rgba(p.theme.colors.wallet, 0.4)};
}
70% {
box-shadow: 0 0 0 6px ${rgba(p.theme.colors.wallet, 0)};
}
100% {
box-shadow: 0 0 0 0 ${rgba(p.theme.colors.wallet, 0)};
}
`
const Wrapper = styled(Box).attrs({
color: p => (p.notValid ? 'alertRed' : 'wallet'),
relative: true,
})`
padding-top: ${p => (p.notValid ? 0 : 30)}px;
transition: color ease-in-out 0.1s;
`
const WrapperIcon = styled(Box)`
color: ${p => (p.notValid ? p.theme.colors.alertRed : p.theme.colors.positiveGreen)};
position: absolute;
left: ${p => (p.notValid ? 152 : 193)}px;
bottom: 16px;
svg {
transition: color ease-in-out 0.1s;
}
`
const Check = ({ notValid }: { notValid: boolean }) => (
<WrapperIcon notValid={notValid}>
{notValid ? <IconCross size={10} /> : <IconCheck size={10} />}
</WrapperIcon>
)
const PushButton = styled(Box)`
background: linear-gradient(to bottom, #ffffff, ${p => p.theme.colors.wallet});
bottom: 48px;
height: 28px;
left: 205px;
position: absolute;
width: 1px;
&:before {
animation: ${p => pulseAnimation(p)} 1s linear infinite;
background-color: ${p => p.theme.colors.wallet};
border-radius: 50%;
bottom: 0;
box-sizing: border-box;
content: ' ';
display: block;
height: 9px;
left: 50%;
margin-bottom: -4px;
margin-left: -4px;
position: absolute;
width: 9px;
z-index: 1;
}
`
type Props = {
notValid: boolean,
}
const SVG = (
<svg width="365" height="44">
<defs>
<rect id="DeviceConfirm-a" width="41.7112299" height="238.383838" rx="4.00000006" />
<rect
id="DeviceConfirm-b"
width="21.1764706"
height="62.0185596"
x="10.2673797"
y="20.6728532"
rx="1.60000002"
/>
<path
id="DeviceConfirm-c"
d="M20.855615 94.9659194c11.5182381 0 20.8556149 9.3373766 20.8556149 20.8556146v118.562304c0 2.209139-1.790861 4-4 4H4.00000006c-2.20913903 0-4.00000006-1.790861-4.00000006-4V115.821534c0-11.518238 9.33737688-20.8556146 20.855615-20.8556146z"
/>
<linearGradient id="DeviceConfirm-d" x1="50%" x2="50%" y1="0%" y2="100%">
<stop offset="0%" />
<stop offset="100%" stopColor="#FFF" />
</linearGradient>
</defs>
<g fill="none" fillRule="evenodd">
<g transform="rotate(-90 85.0909095 -41.5252525)">
<rect
width="4.49197861"
height="17.1197066"
x="38.3363042"
y="15.5046399"
fill="#142533"
rx="2"
/>
<rect
width="4.49197861"
height="17.1197066"
x="38.3363042"
y="70.0938929"
fill="#142533"
rx="2"
/>
<use fill="#FFF" xlinkHref="#DeviceConfirm-a" />
<use fill="currentColor" fillOpacity=".14999999" xlinkHref="#DeviceConfirm-a" />
<rect
width="39.7112299"
height="236.383838"
x="1"
y="1"
stroke="#142533"
strokeWidth="2"
rx="4.00000006"
/>
<use fill="#FFF" xlinkHref="#DeviceConfirm-b" />
<rect
width="20.1764706"
height="61.0185596"
x="10.7673797"
y="21.1728532"
stroke="currentColor"
rx="1.60000002"
/>
<use fill="#FFF" xlinkHref="#DeviceConfirm-c" />
<path
stroke="#142533"
strokeWidth="2"
d="M20.855615 95.9659194C9.88966163 95.9659194 1 104.855581 1 115.821534v118.562304c0 1.656855 1.34314578 3 3.00000006 3H37.7112299c1.6568543 0 3-1.343145 3-3V115.821534c0-10.965953-8.8896616-19.8556146-19.8556149-19.8556146z"
/>
<ellipse cx="21.0160428" cy="116.123293" stroke="#142533" rx="10.5695187" ry="10.6439599" />
</g>
<path
stroke="#1D2027"
strokeWidth="2"
d="M126.9617746 31.060606c0 .55228475-.4477153 1-1 1H99.7373741c-2.7614237 0-5-2.23857625-5-5v-8.4856683c0-2.7614238 2.2385763-5 5-5h26.2244005c.5522847 0 1 .4477152 1 1V31.060606z"
/>
<path
stroke="#142533"
strokeWidth="2"
d="M94.3535357 25.85229841H83.4242428V19.4170232h10.9292929v6.43527521z"
/>
<path
fill="url(#DeviceConfirm-d)"
d="M6.83618598 57.9245106h1.61616161v82.6510534H6.83618598V57.9245106zm5.65656562 0h1.6161617v82.6510534h-1.6161617V57.9245106z"
transform="matrix(0 -1 -1 0 140.606061 33.060606)"
/>
</g>
</svg>
)
const DeviceConfirm = (props: Props) => (
<Wrapper {...props}>
{!props.notValid && <PushButton />}
<Check notValid={props.notValid} />
{SVG}
</Wrapper>
)
DeviceConfirm.defaultProps = {
notValid: false,
}
export default DeviceConfirm

11
src/components/DeviceConfirm/stories.js

@ -0,0 +1,11 @@
// @flow
import React from 'react'
import { storiesOf } from '@storybook/react'
import { boolean } from '@storybook/addon-knobs'
import DeviceConfirm from 'components/DeviceConfirm'
const stories = storiesOf('Components', module)
stories.add('DeviceConfirm', () => <DeviceConfirm notValid={boolean('notValid', false)} />)

2
src/components/DeviceMonitNew/index.js

@ -140,7 +140,7 @@ class DeviceMonit extends PureComponent<Props, State> {
if (render) {
return render({
appStatus,
coinType: (account && account.coinType) || coinType,
coinType: account ? account.coinType : coinType,
devices,
deviceSelected: deviceStatus === 'connected' ? deviceSelected : null,
deviceStatus,

74
src/components/RequestAmount/index.js

@ -64,9 +64,17 @@ type Props = {
// used to calculate the opposite field value (right & left)
getCounterValue: CalculateCounterValue,
getReverseCounterValue: CalculateCounterValue,
// display max button
withMax: boolean,
}
export class RequestAmount extends PureComponent<Props> {
static defaultProps = {
max: Infinity,
withMax: true,
}
handleClickMax = () => {
this.props.onChange(this.props.max)
}
@ -81,35 +89,49 @@ export class RequestAmount extends PureComponent<Props> {
}
}
render() {
const { t, value, account, rightUnit, getCounterValue } = this.props
renderInputs(containerProps: Object) {
const { value, account, rightUnit, getCounterValue } = this.props
const right = getCounterValue(account.currency, rightUnit)(value)
return (
<Box horizontal flow="5">
<Box horizontal align="center">
<InputCurrency
containerProps={{ style: { width: 156 } }}
unit={account.unit}
value={value}
onChange={this.handleChangeAmount('left')}
renderRight={<InputRight>{account.unit.code}</InputRight>}
/>
<InputCenter>=</InputCenter>
<InputCurrency
containerProps={{ style: { width: 156 } }}
unit={rightUnit}
value={right}
onChange={this.handleChangeAmount('right')}
renderRight={<InputRight>{rightUnit.code}</InputRight>}
showAllDigits
/>
</Box>
<Box grow justify="flex-end">
<Button primary onClick={this.handleClickMax}>
{t('common:max')}
</Button>
</Box>
<Box horizontal grow shrink>
<InputCurrency
containerProps={containerProps}
unit={account.unit}
value={value}
onChange={this.handleChangeAmount('left')}
renderRight={<InputRight>{account.unit.code}</InputRight>}
/>
<InputCenter>=</InputCenter>
<InputCurrency
containerProps={containerProps}
unit={rightUnit}
value={right}
onChange={this.handleChangeAmount('right')}
renderRight={<InputRight>{rightUnit.code}</InputRight>}
showAllDigits
/>
</Box>
)
}
render() {
const { withMax, t } = this.props
return (
<Box horizontal flow={5} alignItems="center">
{withMax ? (
<Box horizontal>{this.renderInputs({ style: { width: 156 } })}</Box>
) : (
this.renderInputs({ grow: true })
)}
{withMax && (
<Box grow justify="flex-end">
<Button primary onClick={this.handleClickMax}>
{t('common:max')}
</Button>
</Box>
)}
</Box>
)
}

11
src/components/RequestAmount/stories.js

@ -2,6 +2,7 @@
import React, { PureComponent } from 'react'
import { storiesOf } from '@storybook/react'
import { text, boolean } from '@storybook/addon-knobs'
import { action } from '@storybook/addon-actions'
import { accounts } from 'components/SelectAccount/stories'
@ -23,17 +24,21 @@ class Wrapper extends PureComponent<any, State> {
this.setState({ value })
}
render() {
const { max, withMax } = this.props
const { value } = this.state
return (
<RequestAmount
counterValue="USD"
account={accounts[0]}
counterValue="USD"
max={max}
onChange={this.handleChange}
value={value}
max={4e8}
withMax={withMax}
/>
)
}
}
stories.add('RequestAmount', () => <Wrapper />)
stories.add('RequestAmount', () => (
<Wrapper withMax={boolean('withMax', true)} max={Number(text('max', '4e8'))} />
))

5
src/components/SelectAccount/index.js

@ -24,7 +24,7 @@ const renderItem = a => {
const Icon = getIconByCoinType(a.coinType)
const { color } = a.currency
return (
<Box horizontal alignItems="center" flow={2}>
<Box grow horizontal alignItems="center" flow={2}>
{Icon && (
<Box style={{ width: 16, height: 16, color }}>
<Icon size={16} />
@ -49,8 +49,9 @@ type Props = {
t: T,
}
const RawSelectAccount = ({ accounts, onChange, value, t }: Props) => (
const RawSelectAccount = ({ accounts, onChange, value, t, ...props }: Props) => (
<Select
{...props}
value={value && accounts.find(a => value && a.id === value.id)}
renderSelected={renderItem}
renderItem={renderItem}

5
src/components/SelectAccount/stories.js

@ -12,7 +12,10 @@ const stories = storiesOf('Components', module)
export const accounts = [...Array(20)].map(() => ({
id: chance.string(),
address: chance.string(),
address: chance.string({
pool: 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
length: 30,
}),
addresses: [],
balance: chance.integer({ min: 10000000000, max: 2000000000000 }),
balanceByDay: {},

8
src/components/base/Button/index.js

@ -11,7 +11,7 @@ import fontFamily from 'styles/styled/fontFamily'
const Base = styled.button.attrs({
ff: 'Museo Sans|Regular',
fontSize: 3,
fontSize: p => p.fontSize || 3,
px: p => (p.primary ? (p.small ? 2 : 3) : 1),
})`
${space};
@ -71,8 +71,8 @@ function getProps({ disabled, icon, primary }: Object) {
},
),
...props(disabled, {
color: 'white',
bg: 'fog',
color: 'grey',
bg: 'lightFog',
}),
}
}
@ -82,8 +82,8 @@ const Button = (props: Props) => {
return (
<Base
{...props}
{...getProps({ primary, disabled })}
{...props}
disabled={disabled}
onClick={disabled ? undefined : onClick}
>

14
src/components/base/CopyToClipboard.js

@ -1,6 +1,11 @@
// @flow
import { clipboard } from 'electron'
let clipboard = null
if (!process.env.STORYBOOK_ENV) {
const electron = require('electron')
clipboard = electron.clipboard // eslint-disable-line
}
type Props = {
data: string,
@ -9,7 +14,12 @@ type Props = {
function CopyToClipboard(props: Props) {
const { render, data } = props
return render(() => clipboard.writeText(data))
if (clipboard === null) {
return render()
}
return render(() => clipboard && clipboard.writeText(data))
}
export default CopyToClipboard

5
src/components/base/InputCurrency/index.js

@ -68,7 +68,7 @@ class InputCurrency extends PureComponent<Props, State> {
unit: this.props.unit,
}
componentWillMount() {
componentDidMount() {
this.syncInput({ isFocused: false })
}
@ -125,7 +125,8 @@ class InputCurrency extends PureComponent<Props, State> {
const { unit } = this.state
this.setState({
isFocused,
displayValue: value === 0 ? '' : format(unit, value, { isFocused, showAllDigits }),
displayValue:
value === '' || value === 0 ? '' : format(unit, value, { isFocused, showAllDigits }),
})
}

2
src/components/base/Label.js

@ -4,7 +4,7 @@ import { fontSize, color, alignItems } from 'styled-system'
import fontFamily from 'styles/styled/fontFamily'
export default styled.label.attrs({
fontSize: 3,
fontSize: p => p.fontSize || 3,
ff: 'Museo Sans|Regular',
color: 'grey',
align: 'center',

5
src/components/base/Modal/ModalBody.js

@ -22,6 +22,10 @@ type State = {
}
class ModalBody extends PureComponent<Props, State> {
static defaultProps = {
onClose: undefined,
}
state = {
isHidden: true,
}
@ -58,6 +62,7 @@ const CloseContainer = styled(Box).attrs({
position: absolute;
top: 0;
right: 0;
z-index: 1;
&:hover {
color: ${p => p.theme.colors.grey};

32
src/components/base/Modal/index.js

@ -28,13 +28,22 @@ const springConfig = {
const mapStateToProps: Function = (
state,
{ name, isOpened }: { name: string, isOpened?: boolean },
): Object => ({
isOpened: isOpened || (name && isModalOpened(state, name)),
data: getModalData(state, name),
})
{ name, isOpened, onBeforeOpen }: { name: string, isOpened?: boolean, onBeforeOpen: Function },
): * => {
const data = getModalData(state, name)
const modalOpened = isOpened || (name && isModalOpened(state, name))
if (onBeforeOpen) {
onBeforeOpen({ data, isOpened: modalOpened })
}
return {
isOpened: modalOpened,
data,
}
}
const mapDispatchToProps: Function = (dispatch, { name, onClose = noop }): Object => ({
const mapDispatchToProps: Function = (dispatch, { name, onClose = noop }): * => ({
onClose: name
? () => {
dispatch(closeModal(name))
@ -98,12 +107,12 @@ class Pure extends Component<any> {
}
type Props = {
data?: any,
isOpened?: boolean,
onClose: Function,
onHide?: Function,
preventBackdropClick?: boolean,
render: Function,
data?: any,
}
export class Modal extends Component<Props> {
@ -138,6 +147,7 @@ export class Modal extends Component<Props> {
domWrapper.focus()
}
}
if (didClose) {
if (this._lastFocusedElement) {
this._lastFocusedElement.focus()
@ -149,7 +159,7 @@ export class Modal extends Component<Props> {
_lastFocusedElement = null
render() {
const { preventBackdropClick, isOpened, onClose, onHide, render, data } = this.props
const { preventBackdropClick, isOpened, onHide, render, data, onClose } = this.props
return (
<Mortal
@ -187,11 +197,13 @@ export class Modal extends Component<Props> {
}
export const ModalTitle = styled(Box).attrs({
alignItems: 'center',
color: 'dark',
ff: 'Museo Sans|Regular',
fontSize: 6,
color: 'dark',
align: 'center',
justifyContent: 'center',
p: 5,
relative: true,
})``
export const ModalFooter = styled(Box).attrs({

32
src/components/base/Print.js

@ -1,10 +1,14 @@
// @flow
import { PureComponent } from 'react'
import { remote } from 'electron'
import queryString from 'query-string'
import qs from 'qs'
const { BrowserWindow } = remote
let BrowserWindow = null
if (!process.env.STORYBOOK_ENV) {
const { remote } = require('electron')
BrowserWindow = remote.BrowserWindow // eslint-disable-line
}
type Props = {
render: Function,
@ -21,6 +25,10 @@ class Print extends PureComponent<Props, State> {
}
handlePrint = () => {
if (BrowserWindow === null) {
return
}
const { data } = this.props
this.setState({ isLoading: true })
@ -33,22 +41,18 @@ class Print extends PureComponent<Props, State> {
},
})
w.webContents.openDevTools()
const url = __DEV__
? `http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT || ''}`
: `file://${__dirname}/index.html`
w.loadURL(`${url}/#/print?${queryString.stringify(data)}`)
w.loadURL(`${url}/#/print?${qs.stringify(data)}`)
w.webContents.on('did-finish-load', () => {
w.on('minimize', () => {
w.webContents.print({}, () => {
w.destroy()
this.setState({ isLoading: false })
})
})
})
w.webContents.on('did-finish-load', () =>
w.on('print-ready', () => {
w.webContents.print({}, () => w.destroy())
this.setState({ isLoading: false })
}),
)
}
render() {

3
src/components/base/QRCode/index.js

@ -28,6 +28,9 @@ class QRCode extends PureComponent<Props> {
qrcode.toCanvas(this._canvas, data, {
width: size,
margin: 0,
color: {
light: '#ffffff00', // transparent background
},
})
}

109
src/components/base/Select/index.js

@ -14,7 +14,6 @@ import Search from 'components/base/Search'
import Text from 'components/base/Text'
import IconCheck from 'icons/Check'
import IconAngleDown from 'icons/AngleDown'
type Props = {
bg?: string,
@ -34,32 +33,40 @@ type Props = {
renderSelected?: any => Element<*>,
searchable?: boolean,
value?: Object | null,
disabled: boolean,
}
const Container = styled(Box).attrs({ relative: true, color: 'graphite' })``
const TriggerBtn = styled(Box).attrs({
alignItems: 'center',
ff: 'Open Sans|SemiBold',
flow: 2,
fontSize: 4,
pl: 3,
pr: 5,
horizontal: true,
px: 3,
})`
${space};
height: 40px;
background: ${p => p.bg || p.theme.colors.white};
background: ${p => (p.disabled ? p.theme.colors.lightGrey : p.bg || p.theme.colors.white)};
border-bottom-left-radius: ${p => (p.flatLeft ? 0 : p.theme.radii[1])}px;
border-bottom-right-radius: ${p => (p.flatRight ? 0 : p.theme.radii[1])}px;
border-top-left-radius: ${p => (p.flatLeft ? 0 : p.theme.radii[1])}px;
border-top-right-radius: ${p => (p.flatRight ? 0 : p.theme.radii[1])}px;
border: 1px solid ${p => p.theme.colors.fog};
color: ${p => p.theme.colors.graphite};
cursor: pointer;
cursor: ${p => (p.disabled ? 'cursor' : 'pointer')};
display: flex;
width: 100%;
&:focus {
outline: none;
border-color: ${p => p.theme.colors.wallet};
box-shadow: rgba(0, 0, 0, 0.05) 0 2px 2px;
${p =>
p.disabled
? ''
: `
border-color: ${p.theme.colors.wallet};
box-shadow: rgba(0, 0, 0, 0.05) 0 2px 2px;`};
}
${p => {
@ -110,22 +117,6 @@ const Dropdown = styled(Box).attrs({
z-index: 1;
`
const FloatingDown = styled(Box).attrs({
alignItems: 'center',
justifyContent: 'center',
mr: 2,
})`
position: absolute;
top: 0;
right: 0;
bottom: 0;
color: ${p => p.theme.colors.grey};
// to "simulate" border to make arrows appears at the exact same place as
// the no-input version
padding-right: 1px;
`
const IconSelected = styled(Box).attrs({
color: 'wallet',
alignItems: 'center',
@ -136,12 +127,31 @@ const IconSelected = styled(Box).attrs({
opacity: ${p => (p.selected ? 1 : 0)};
`
const AngleDown = props => (
<Box color="grey" alignItems="center" justifyContent="center" {...props}>
<svg viewBox="0 0 16 16" width="16" height="16">
<path
fill="currentColor"
d="M7.70785815 10.86875l-5.08670521-4.5875c-.16153725-.146875-.16153725-.384375 0-.53125l.68051867-.61875c.16153726-.146875.42274645-.146875.58428371 0L8 8.834375l4.1140447-3.703125c.1615372-.146875.4227464-.146875.5842837 0l.6805187.61875c.1615372.146875.1615372.384375 0 .53125l-5.08670525 4.5875c-.16153726.146875-.42274644.146875-.5842837 0z"
/>
</svg>
</Box>
)
const renderSelectedItem = ({ selectedItem, renderSelected, placeholder }: any) =>
selectedItem && renderSelected ? (
renderSelected(selectedItem)
) : (
<Text color="fog">{placeholder}</Text>
)
class Select extends PureComponent<Props> {
static defaultProps = {
bg: undefined,
disabled: false,
fakeFocusRight: false,
flatLeft: false,
flatRight: false,
fakeFocusRight: false,
itemToString: (item: Object) => item && item.name,
keyProp: undefined,
maxHeight: 300,
@ -227,18 +237,19 @@ class Select extends PureComponent<Props> {
render() {
const {
disabled,
fakeFocusRight,
flatLeft,
flatRight,
fakeFocusRight,
items,
searchable,
itemToString,
fuseOptions,
highlight,
items,
itemToString,
onChange,
placeholder,
renderHighlight,
renderSelected,
placeholder,
onChange,
searchable,
value,
...props
} = this.props
@ -262,42 +273,46 @@ class Select extends PureComponent<Props> {
this._scrollToSelectedItem = true
}
if (disabled) {
return (
<Container {...getRootProps({ refKey: 'innerRef' })}>
<TriggerBtn disabled bg={props.bg} tabIndex={0}>
{renderSelectedItem({ selectedItem, renderSelected, placeholder })}
</TriggerBtn>
</Container>
)
}
return (
<Container
{...getRootProps({ refKey: 'innerRef' })}
{...props}
horizontal
onKeyDown={() => (this._useKeyboard = true)}
onKeyUp={() => (this._useKeyboard = false)}
>
{searchable ? (
<Box relative>
<Input keepEvent {...getInputProps({ placeholder })} onClick={openMenu} />
<FloatingDown>
<IconAngleDown size={16} />
</FloatingDown>
<Box grow>
<Input
keepEvent
{...getInputProps({ placeholder })}
onClick={openMenu}
renderRight={<AngleDown mr={2} />}
/>
</Box>
) : (
<TriggerBtn
{...getToggleButtonProps()}
bg={props.bg}
alignItems="center"
fakeFocusRight={fakeFocusRight}
flatLeft={flatLeft}
flatRight={flatRight}
fakeFocusRight={fakeFocusRight}
flow={2}
horizontal
tabIndex={0}
>
<Box grow>
{selectedItem && renderSelected ? (
renderSelected(selectedItem)
) : (
<Text color="fog">{placeholder}</Text>
)}
{renderSelectedItem({ selectedItem, renderSelected, placeholder })}
</Box>
<FloatingDown>
<IconAngleDown size={16} />
</FloatingDown>
<AngleDown mr={-1} />
</TriggerBtn>
)}
{isOpen &&

2
src/components/base/Select/stories.js

@ -2,6 +2,7 @@
import React, { PureComponent } from 'react'
import { storiesOf } from '@storybook/react'
import { boolean } from '@storybook/addon-knobs'
import Box from 'components/base/Box'
import Select from 'components/base/Select'
@ -57,6 +58,7 @@ stories.add('basic', () => (
<Wrapper>
{onChange => (
<Select
disabled={boolean('disabled', false)}
placeholder="Choose a chess player..."
items={itemsChessPlayers}
renderSelected={item => item.name}

50
src/components/layout/Print.js

@ -2,49 +2,43 @@
import React, { PureComponent } from 'react'
import { remote } from 'electron'
import queryString from 'query-string'
import qs from 'qs'
import QRCode from 'components/base/QRCode'
import Box from 'components/base/Box'
import { AddressBox } from 'components/ReceiveBox'
type State = {
data: Object | null,
}
class Print extends PureComponent<any, State> {
state = {
data: null,
}
componentWillMount() {
this.setState({
data: queryString.parse(this.props.location.search),
})
}
import CurrentAddress from 'components/CurrentAddress'
class Print extends PureComponent<any> {
componentDidMount() {
window.requestAnimationFrame(() =>
setTimeout(() => {
// hacky way to detect that render is ready
// from the parent window
remote.getCurrentWindow().minimize()
if (!this._node) {
return
}
const { height, width } = this._node.getBoundingClientRect()
const currentWindow = remote.getCurrentWindow()
currentWindow.setContentSize(width, height)
currentWindow.emit('print-ready')
}, 300),
)
}
_node = null
render() {
const { data } = this.state
const data = qs.parse(this.props.location.search, { ignoreQueryPrefix: true })
if (!data) {
return null
}
const { address, amount } = data
return (
<Box p={3} flow={3}>
<QRCode size={150} data={`bitcoin:${address}${amount ? `?amount=${amount}` : ''}`} />
<AddressBox>{address}</AddressBox>
{amount && <AddressBox>{amount}</AddressBox>}
</Box>
<CurrentAddress
innerRef={n => (this._node = n)}
amount={amount}
address={address}
withQRCode
/>
)
}
}

2
src/components/modals/AddAccount/index.js

@ -362,7 +362,7 @@ class AddAccountModal extends PureComponent<Props, State> {
<ModalBody onClose={onClose}>
<ModalTitle>{t('addAccount:title')}</ModalTitle>
<ModalContent>
<Breadcrumb mb={6} currentStep={stepIndex} items={this._steps} />
<Breadcrumb mb={5} currentStep={stepIndex} items={this._steps} />
{this.renderStep()}
</ModalContent>
{stepIndex !== 2 && (

2
src/components/modals/Receive/01-step-account.js

@ -10,7 +10,7 @@ import Label from 'components/base/Label'
import SelectAccount from 'components/SelectAccount'
type Props = {
account: Account | null,
account: ?Account,
onChangeAccount: Function,
t: T,
}

68
src/components/modals/Receive/03-step-confirm-address.js

@ -0,0 +1,68 @@
// @flow
import React, { Fragment } from 'react'
import styled from 'styled-components'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { Device, T } from 'types/common'
import Box from 'components/base/Box'
import CurrentAddress from 'components/CurrentAddress'
import DeviceConfirm from 'components/DeviceConfirm'
import DeviceCheckAddress from 'components/DeviceCheckAddress'
const Container = styled(Box).attrs({
alignItems: 'center',
fontSize: 4,
color: 'dark',
px: 7,
})``
const Title = styled(Box).attrs({
ff: 'Museo Sans|Regular',
fontSize: 6,
mb: 1,
})``
const Text = styled(Box).attrs({
color: 'smoke',
})`
text-align: center;
`
type Props = {
account: ?Account,
addressVerified: ?boolean,
device: ?Device,
onCheck: Function,
t: T,
}
export default (props: Props) => (
<Container>
{props.addressVerified === false ? (
<Fragment>
<Title>{props.t('receive:steps.confirmAddress.error.title')}</Title>
<Text mb={5}>{props.t('receive:steps.confirmAddress.error.text')}</Text>
<DeviceConfirm notValid />
</Fragment>
) : (
<Fragment>
<Title>{props.t('receive:steps.confirmAddress.action')}</Title>
<Text>{props.t('receive:steps.confirmAddress.text')}</Text>
{props.account && <CurrentAddress address={props.account.address} />}
{props.device &&
props.account && (
<Box mb={2} mt={-1}>
<DeviceCheckAddress
account={props.account}
device={props.device}
onCheck={props.onCheck}
render={({ isVerified }) => <DeviceConfirm notValid={isVerified === false} />}
/>
</Box>
)}
</Fragment>
)}
</Container>
)

49
src/components/modals/Receive/04-step-receive-funds.js

@ -0,0 +1,49 @@
// @flow
import React from 'react'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { T } from 'types/common'
import Box from 'components/base/Box'
import CurrentAddress from 'components/CurrentAddress'
import Label from 'components/base/Label'
import SelectAccount from 'components/SelectAccount'
import RequestAmount from 'components/RequestAmount'
type Props = {
account: ?Account,
addressVerified: ?boolean,
amount: string | number,
onChangeAmount: Function,
onVerify: Function,
t: T,
}
export default (props: Props) => (
<Box flow={5}>
<Box flow={1}>
<Label>{props.t('receive:steps.chooseAccount.label')}</Label>
<SelectAccount disabled value={props.account} />
</Box>
<Box flow={1}>
<Label>{props.t('receive:steps.receiveFunds.label')}</Label>
<RequestAmount
account={props.account}
onChange={props.onChangeAmount}
value={props.amount}
withMax={false}
/>
</Box>
<CurrentAddress
address={props.account && props.account.address}
addressVerified={props.addressVerified}
amount={props.amount}
onVerify={props.onVerify}
withBadge
withFooter
withQRCode
withVerify={props.addressVerified === false}
/>
</Box>
)

246
src/components/modals/Receive/index.js

@ -1,10 +1,10 @@
// @flow
import React, { PureComponent } from 'react'
import React, { Fragment, PureComponent } from 'react'
import styled from 'styled-components'
import { translate } from 'react-i18next'
import get from 'lodash/get'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { Account } from '@ledgerhq/wallet-common/lib/types'
import type { T, Device } from 'types/common'
import { MODAL_RECEIVE } from 'config/constants'
@ -15,7 +15,19 @@ import Breadcrumb from 'components/Breadcrumb'
import Modal, { ModalBody, ModalTitle, ModalContent, ModalFooter } from 'components/base/Modal'
import StepConnectDevice from 'components/modals/StepConnectDevice'
import IconAngleLeft from 'icons/AngleLeft'
import StepAccount from './01-step-account'
import StepConfirmAddress from './03-step-confirm-address'
import StepReceiveFunds from './04-step-receive-funds'
const PrevButton = styled(Button).attrs({
fontSize: 4,
ml: 4,
})`
position: absolute;
left: 0;
`
type Props = {
t: T,
@ -23,21 +35,31 @@ type Props = {
type State = {
account: Account | null,
deviceSelected: Device | null,
addressVerified: null | boolean,
amount: string | number,
appStatus: null | string,
deviceSelected: Device | null,
stepIndex: number,
stepsDisabled: Array<number>,
stepsErrors: Array<number>,
}
const GET_STEPS = t => [
{ label: t('receive:steps.chooseAccount.title'), Comp: StepAccount },
{ label: t('receive:steps.connectDevice.title'), Comp: StepConnectDevice },
{ label: t('receive:steps.confirmAddress.title'), Comp: StepConfirmAddress },
{ label: t('receive:steps.receiveFunds.title'), Comp: StepReceiveFunds },
]
const INITIAL_STATE = {
account: null,
deviceSelected: null,
addressVerified: null,
amount: '',
appStatus: null,
deviceSelected: null,
stepIndex: 0,
stepsDisabled: [],
stepsErrors: [],
}
class ReceiveModal extends PureComponent<Props, State> {
@ -45,11 +67,11 @@ class ReceiveModal extends PureComponent<Props, State> {
_steps = GET_STEPS(this.props.t)
canNext = acc => {
const { stepIndex } = this.state
canNext = () => {
const { account, stepIndex } = this.state
if (stepIndex === 0) {
return acc !== null
return account !== null
}
if (stepIndex === 1) {
@ -60,6 +82,34 @@ class ReceiveModal extends PureComponent<Props, State> {
return false
}
canClose = () => {
const { stepIndex, addressVerified } = this.state
if (stepIndex === 2) {
return addressVerified === false
}
return true
}
canPrev = () => {
const { addressVerified, stepIndex } = this.state
if (stepIndex === 1) {
return true
}
if (stepIndex === 2) {
return addressVerified === false
}
if (stepIndex === 3) {
return true
}
return false
}
handleReset = () => this.setState(INITIAL_STATE)
handleNextStep = () => {
@ -70,14 +120,78 @@ class ReceiveModal extends PureComponent<Props, State> {
this.setState({ stepIndex: stepIndex + 1 })
}
handlePrevStep = () => {
const { stepIndex } = this.state
let newStepIndex
switch (stepIndex) {
default:
case 1:
newStepIndex = 0
break
case 2:
case 3:
newStepIndex = 1
break
}
this.setState({
addressVerified: null,
appStatus: null,
deviceSelected: null,
stepIndex: newStepIndex,
stepsDisabled: [],
stepsErrors: [],
})
}
handleChangeDevice = d => this.setState({ deviceSelected: d })
handleChangeAccount = account => this.setState({ account })
handleChangeStatus = (deviceStatus, appStatus) => this.setState({ appStatus })
renderStep = acc => {
const { deviceSelected, stepIndex } = this.state
handleCheckAddress = isVerified => {
this.setState({
addressVerified: isVerified,
stepsErrors: isVerified === false ? [2] : [],
})
if (isVerified === true) {
this.handleNextStep()
}
}
handleRetryCheckAddress = () =>
this.setState({
addressVerified: null,
stepsErrors: [],
})
handleChangeAmount = amount => this.setState({ amount })
handleBeforeOpenModal = ({ data }) => {
const { account } = this.state
if (data && data.account && !account) {
this.setState({
account: data.account,
stepIndex: 1,
})
}
}
handleSkipStep = () =>
this.setState({
addressVerified: false,
stepsErrors: [],
stepsDisabled: [1, 2],
stepIndex: this._steps.length - 1, // last step
})
renderStep = () => {
const { account, amount, addressVerified, deviceSelected, stepIndex } = this.state
const { t } = this.props
const step = this._steps[stepIndex]
if (!step) {
@ -89,67 +203,119 @@ class ReceiveModal extends PureComponent<Props, State> {
const stepProps = {
t,
account: acc,
account,
...props(stepIndex === 0, {
onChangeAccount: this.handleChangeAccount,
}),
...props(stepIndex === 1, {
accountName: acc ? acc.name : undefined,
accountName: account ? account.name : undefined,
deviceSelected,
onChangeDevice: this.handleChangeDevice,
onStatusChange: this.handleChangeStatus,
}),
...props(stepIndex === 2, {
addressVerified,
onCheck: this.handleCheckAddress,
device: deviceSelected,
}),
...props(stepIndex === 3, {
addressVerified,
amount,
onChangeAmount: this.handleChangeAmount,
onVerify: this.handlePrevStep,
}),
}
return <Comp {...stepProps} />
}
renderButton = acc => {
renderButton = () => {
const { t } = this.props
const { stepIndex } = this.state
const { stepIndex, addressVerified } = this.state
let onClick
let props
switch (stepIndex) {
case 2:
props = {
primary: true,
onClick: this.handleRetryCheckAddress,
children: t('common:retry'),
}
break
default:
onClick = this.handleNextStep
props = {
primary: true,
disabled: !this.canNext(),
onClick,
children: t('common:next'),
}
}
const props = {
primary: true,
disabled: !this.canNext(acc),
onClick,
children: t('common:next'),
}
return <Button {...props} />
return (
<Fragment>
{stepIndex === 1 && (
<Button onClick={this.handleSkipStep} fontSize={4}>
{t('receive:steps.connectDevice.withoutDevice')}
</Button>
)}
{stepIndex === 2 &&
addressVerified === false && (
<Button fontSize={4}>{t('receive:steps.confirmAddress.support')}</Button>
)}
<Button {...props} />
</Fragment>
)
}
render() {
const { t } = this.props
const { stepIndex, account } = this.state
const { stepsErrors, stepsDisabled, stepIndex } = this.state
const canClose = this.canClose()
const canPrev = this.canPrev()
return (
<Modal
name={MODAL_RECEIVE}
onBeforeOpen={this.handleBeforeOpenModal}
onHide={this.handleReset}
render={({ data, onClose }) => {
const acc = account || get(data, 'account', null)
return (
<ModalBody onClose={onClose} deferHeight={344}>
<ModalTitle>{t('receive:title')}</ModalTitle>
<ModalContent>
<Breadcrumb mb={6} currentStep={stepIndex} items={this._steps} />
{this.renderStep(acc)}
</ModalContent>
<ModalFooter>
<Box horizontal alignItems="center" justifyContent="flex-end">
{this.renderButton(acc)}
</Box>
</ModalFooter>
</ModalBody>
)
}}
preventBackdropClick={!canClose}
render={({ onClose }) => (
<ModalBody onClose={canClose ? onClose : undefined}>
<ModalTitle>
{canPrev && (
<PrevButton onClick={this.handlePrevStep}>
<Box horizontal alignItems="center">
<IconAngleLeft size={16} />
{t('common:back')}
</Box>
</PrevButton>
)}
{t('receive:title')}
</ModalTitle>
<ModalContent>
<Breadcrumb
mb={5}
currentStep={stepIndex}
stepsErrors={stepsErrors}
stepsDisabled={stepsDisabled}
items={this._steps}
/>
{this.renderStep()}
</ModalContent>
{stepIndex !== 3 &&
canClose && (
<ModalFooter>
<Box horizontal alignItems="center" justifyContent="flex-end" flow={2}>
{this.renderButton()}
</Box>
</ModalFooter>
)}
</ModalBody>
)}
/>
)
}

2
src/components/modals/Send/index.js

@ -140,7 +140,7 @@ class SendModal extends PureComponent<Props, State> {
<ModalBody onClose={onClose} deferHeight={acc ? 630 : 355}>
<ModalTitle>{t('send:title')}</ModalTitle>
<ModalContent>
<Breadcrumb mb={6} mt={2} currentStep={stepIndex} items={this._steps} />
<Breadcrumb mb={5} mt={2} currentStep={stepIndex} items={this._steps} />
{this.renderStep(acc)}
</ModalContent>
{acc && (

8
src/components/modals/StepConnectDevice.js

@ -11,9 +11,9 @@ import DeviceMonit from 'components/DeviceMonitNew'
type Props = {
accountName?: string,
account?: Account,
currency?: Currency | null,
deviceSelected: Device | null,
account?: ?Account,
currency?: ?Currency,
deviceSelected: ?Device,
onChangeDevice: Function,
onStatusChange: Function,
}
@ -38,8 +38,8 @@ const StepConnectDevice = (props: Props) => (
)
StepConnectDevice.defaultProps = {
account: undefined,
accountName: undefined,
account: undefined,
currency: undefined,
}

12
src/icons/AngleLeft.js

@ -0,0 +1,12 @@
// @flow
import React from 'react'
export default ({ size, ...p }: { size: number }) => (
<svg viewBox="0 0 16 16" height={size} width={size} {...p}>
<path
fill="currentColor"
d="M5.78300939 7.734375l3.68125-3.625c.146875-.146875.384375-.146875.53125 0l.22187501.221875c.146875.146875.146875.384375 0 .53125L7.02050939 8l3.19375001 3.1375c.146875.146875.146875.384375 0 .53125l-.22187501.221875c-.146875.146875-.384375.146875-.53125 0l-3.68125-3.625c-.14375-.146875-.14375-.384375.003125-.53125z"
/>
</svg>
)

12
src/icons/Copy.js

@ -0,0 +1,12 @@
// @flow
import React from 'react'
export default ({ size, ...p }: { size: number }) => (
<svg viewBox="0 0 16 16" height={size} width={size} {...p}>
<path
fill="currentColor"
d="M8 6.75c-.69035594 0-1.25.55964406-1.25 1.25v4.6666667c0 .6903559.55964406 1.25 1.25 1.25h4.6666667c.6903559 0 1.25-.5596441 1.25-1.25V8c0-.69035594-.5596441-1.25-1.25-1.25H8zm0-1.5h4.6666667c1.518783 0 2.75 1.23121694 2.75 2.75v4.6666667c0 1.518783-1.231217 2.75-2.75 2.75H8c-1.51878306 0-2.75-1.231217-2.75-2.75V8c0-1.51878306 1.23121694-2.75 2.75-2.75zm-4.66666667 4c.41421357 0 .75.33578644.75.75 0 .4142136-.33578643.75-.75.75h-.66666666c-1.15059323 0-2.08333334-.9327401-2.08333334-2.08333333v-6c0-1.15059323.93274011-2.08333334 2.08333334-2.08333334h6C9.8172599.58333333 10.75 1.51607344 10.75 2.66666667v.66666666c0 .41421357-.3357864.75-.75.75-.41421356 0-.75-.33578643-.75-.75v-.66666666c0-.32216611-.26116723-.58333334-.58333333-.58333334h-6c-.32216611 0-.58333334.26116723-.58333334.58333334v6c0 .3221661.26116723.58333333.58333334.58333333h.66666666z"
/>
</svg>
)

12
src/icons/Print.js

@ -0,0 +1,12 @@
// @flow
import React from 'react'
export default ({ size, ...p }: { size: number }) => (
<svg viewBox="0 0 16 16" height={size} width={size} {...p}>
<path
fill="currentColor"
d="M4.75 2.08333333V6c0 .41421356-.33578644.75-.75.75s-.75-.33578644-.75-.75V1.33333333c0-.41421356.33578644-.75.75-.75h8c.4142136 0 .75.33578644.75.75V6c0 .41421356-.3357864.75-.75.75s-.75-.33578644-.75-.75V2.08333333h-6.5zM4 11.25c.41421356 0 .75.3357864.75.75s-.33578644.75-.75.75H2.66666667c-1.15059323 0-2.08333334-.9327401-2.08333334-2.0833333V7.33333333C.58333333 6.1827401 1.51607344 5.25 2.66666667 5.25H13.3333333c1.1505933 0 2.0833334.9327401 2.0833334 2.08333333v3.33333337c0 1.1505932-.9327401 2.0833333-2.0833334 2.0833333H12c-.4142136 0-.75-.3357864-.75-.75s.3357864-.75.75-.75h1.3333333c.3221661 0 .5833334-.2611672.5833334-.5833333V7.33333333c0-.3221661-.2611673-.58333333-.5833334-.58333333H2.66666667c-.32216611 0-.58333334.26116723-.58333334.58333333v3.33333337c0 .3221661.26116723.5833333.58333334.5833333H4zm.75 2.6666667h6.5v-3.8333334h-6.5v3.8333334zM4 8.58333333h8c.4142136 0 .75.33578644.75.75v5.33333337c0 .4142135-.3357864.75-.75.75H4c-.41421356 0-.75-.3357865-.75-.75V9.33333333c0-.41421356.33578644-.75.75-.75z"
/>
</svg>
)

12
src/icons/Share.js

@ -0,0 +1,12 @@
// @flow
import React from 'react'
export default ({ size, ...p }: { size: number }) => (
<svg viewBox="0 0 16 16" height={size} width={size} {...p}>
<path
fill="currentColor"
d="M2.58333333 8c0-.41421356.33578644-.75.75-.75.41421357 0 .75.33578644.75.75v4.6666667c0 .2301186.18654802.4166666.41666667.4166666h7c.2301186 0 .4166667-.186548.4166667-.4166666V8c0-.41421356.3357864-.75.75-.75.4142135 0 .75.33578644.75.75v4.6666667c0 1.0585457-.8581209 1.9166666-1.9166667 1.9166666h-7c-1.05854577 0-1.91666667-.8581209-1.91666667-1.9166666V8zm3.61366342-2.96966991c-.29289322.29289321-.76776695.29289321-1.06066017 0-.29289322-.29289322-.29289322-.76776696 0-1.06066018l2.33333333-2.33333333c.29289322-.29289322.76776696-.29289322 1.06066018 0l2.33333331 2.33333333c.2928932.29289322.2928932.76776696 0 1.06066018-.2928932.29289321-.7677669.29289321-1.06066015 0L8 3.22732684 6.19699675 5.03033009zM7.25 2.16666667c0-.41421357.33578644-.75.75-.75s.75.33578643.75.75V9.75c0 .4142136-.33578644.75-.75.75s-.75-.3357864-.75-.75V2.16666667z"
/>
</svg>
)

49
src/icons/Shield.js

@ -0,0 +1,49 @@
// @flow
import React from 'react'
export default (p: Object) => (
<svg viewBox="0 0 28 32" height={32} width={28} {...p}>
<defs>
<filter
id="a"
width="163.6%"
height="153.8%"
x="-31.8%"
y="-23.1%"
filterUnits="objectBoundingBox"
>
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1" />
<feGaussianBlur in="shadowOffsetOuter1" result="shadowBlurOuter1" stdDeviation="1.5" />
<feColorMatrix
in="shadowBlurOuter1"
result="shadowMatrixOuter1"
values="0 0 0 0 0.418261054 0 0 0 0 0.418261054 0 0 0 0 0.418261054 0 0 0 0.116196784 0"
/>
<feMerge>
<feMergeNode in="shadowMatrixOuter1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<path
id="b"
d="M11 25.5806452s11-3.7741936 11-11.9516129V4.08870968L11 0 0 4.08870968v9.54032262c0 8.1774193 11 11.9516129 11 11.9516129z"
/>
</defs>
<g fill="none" fillRule="evenodd" filter="url(#a)" transform="translate(3 2)">
<g strokeLinecap="round" strokeLinejoin="round">
<use fill="#FFF" stroke="currentColor" strokeWidth="1.5" xlinkHref="#b" />
<path
stroke="#FFF"
strokeWidth="2"
d="M10.6754629 26.5265181c-.1002644-.0344015-.2759634-.0990392-.5164692-.1943297-.39391814-.1560737-.83107448-.3435638-1.3008837-.5629688-1.3411669-.6263368-2.68247439-1.3856899-3.93963025-2.2843167C1.24412544 20.85844-1 17.5860312-1 13.6290323V3.39356402l12-4.46041056 12 4.46041056V13.6290323c0 3.9569989-2.2441254 7.2294077-5.9184797 9.8558706-1.2571559.8986268-2.5984634 1.6579799-3.9396303 2.2843167-.4698092.219405-.9069656.4068951-1.3008837.5629688-.2405058.0952905-.4162048.1599282-.5164692.1943297L11 26.6378696l-.3245371-.1113515z"
/>
</g>
<path
fill="currentColor"
fillRule="nonzero"
d="M14.4936649 8.7193017c-.3544349 0-.6426937.29661569-.6426937.66261516l-.0115902 2.97078244s.0011217.2071877-.1921725.2071877c-.1974068 0-.1919856-.2071877-.1919856-.2071877V8.06728684c0-.36580674-.28452-.64970207-.6391418-.64970207-.3549957 0-.6077362.28389533-.6077362.64970207v4.28521976s-.0216848.2095005-.2125488.2095005c-.1889945 0-.2033888-.2095005-.2033888-.2095005V7.35301931c0-.36561401-.2673217-.64334189-.6221304-.64334189-.3548088 0-.6243737.27772788-.6243737.64334189v4.99948729s-.0097208.200442-.2140443.200442c-.2007717 0-.2017064-.200442-.2017064-.200442V8.63854668c0-.36580674-.2777902-.5951587-.63241204-.5951587-.35499571 0-.61465292.22935196-.61465292.5951587v5.42793212s-.03477051.2413014-.37032465-.1572699c-.8604767-1.0209053-1.30931541-1.2238529-1.30931541-1.2238529s-.81673316-.412448-1.17845865.3322713c-.26208741.5400371.01551588.5691397.44416525 1.2323331.37911075.5872567 1.57831954 2.1318168 1.57831954 2.1318168s1.42241305 2.0687933 3.34189488 2.0687933c0 0 3.7595149.1653647 3.7595149-3.6694387l-.0130857-5.39921494c.0001869-.36599947-.2873241-.66261516-.6421328-.66261516"
/>
</g>
</svg>
)

2
src/internals/usb/manager/helpers.js

@ -3,7 +3,7 @@
import CommNodeHid from '@ledgerhq/hw-transport-node-hid'
import chalk from 'chalk'
import Websocket from 'ws'
import qs from 'query-string'
import qs from 'qs'
import noop from 'lodash/noop'
import type Transport from '@ledgerhq/hw-transport'

2
src/main/bridge.js

@ -1,6 +1,6 @@
// @flow
import 'babel-polyfill'
import '@babel/polyfill'
import { fork } from 'child_process'
import { BrowserWindow, ipcMain } from 'electron'
import objectPath from 'object-path'

2
src/renderer/index.js

@ -1,4 +1,4 @@
require('babel-polyfill')
require('@babel/polyfill')
const Raven = require('raven-js')
require('../env')

5
src/styles/theme.js

@ -66,13 +66,14 @@ export const colors = {
pearl: '#ff0000',
// new colors
alertRed: '#fa4352',
alertRed: '#ea2e49',
black: '#000000',
dark: '#1d2028',
dark: '#142533',
fog: '#d8d8d8',
graphite: '#767676',
grey: '#999999',
identity: '#41ccb4',
lightFog: '#eeeeee',
lightGraphite: '#fafafa',
lightGrey: '#f9f9f9',
positiveGreen: '#66be54',

2
static/i18n/en/common.yml

@ -11,3 +11,5 @@ editProfile: Edit profile
lockApplication: Lock application
max: Max
next: Next
back: Back
retry: Retry

1
static/i18n/en/currentAddress.yml

@ -0,0 +1 @@
label: Current address

11
static/i18n/en/receive.yml

@ -4,9 +4,20 @@ steps:
chooseAccount:
title: Choose Account
label: Account
connectDevice:
title: Connect Device
withoutDevice: I don't have my device
confirmAddress:
title: Confirm Address
action: Confirm address on device
text: To receive funds, confirm the address on your device.
support: Contact Support
error:
title: Houston, we have a problem!
text: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer non nibh diam. In eget ipsum arcu donec finibus
receiveFunds:
title: Receive Funds
label: Amount (Optional)

283
yarn.lock

@ -734,6 +734,13 @@
"@babel/helper-regex" "7.0.0-beta.42"
regexpu-core "^4.1.3"
"@babel/polyfill@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.0.0-beta.42.tgz#f7b0166370b4e0b407919bdf81ee4d0fcefbe77b"
dependencies:
core-js "^2.5.3"
regenerator-runtime "^0.11.1"
"@babel/preset-env@7.0.0-beta.42", "@babel/preset-env@^7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.0.0-beta.42.tgz#671e688057c010b22a7811b965f7da5d79c472d3"
@ -947,18 +954,16 @@
dependencies:
events "^2.0.0"
"@ledgerhq/wallet-common@^0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/wallet-common/-/wallet-common-0.12.0.tgz#50ac697929062772182735e4013266c41a661fe2"
"@ledgerhq/wallet-common@^0.13.2":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@ledgerhq/wallet-common/-/wallet-common-0.13.2.tgz#55bff35179acb8e4c12836eeea7885ebaa85e6c4"
dependencies:
"@ledgerhq/currencies" "^4.10.1"
axios "^0.18.0"
babel-jest "^22.4.3"
invariant "^2.2.2"
lodash "^4.17.4"
prando "^3.0.1"
react "^16.0.0"
timemachine "^0.3.0"
"@posthtml/esm@^1.0.0":
version "1.0.0"
@ -968,11 +973,11 @@
version "0.7.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd"
"@storybook/addon-actions@3.4.0", "@storybook/addon-actions@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-3.4.0.tgz#8f6f869f708856845dff210af9340e54b443f346"
"@storybook/addon-actions@3.4.1", "@storybook/addon-actions@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/addon-actions/-/addon-actions-3.4.1.tgz#6ec5dc337e4af301d2f0f8fbc0ad2dee812cfa29"
dependencies:
"@storybook/components" "3.4.0"
"@storybook/components" "3.4.1"
babel-runtime "^6.26.0"
deep-equal "^1.0.1"
glamor "^2.20.40"
@ -983,11 +988,11 @@
react-inspector "^2.2.2"
uuid "^3.2.1"
"@storybook/addon-knobs@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-3.4.0.tgz#2542f2871ec53f5db5a683a0fbbd06fc455c0f4b"
"@storybook/addon-knobs@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/addon-knobs/-/addon-knobs-3.4.1.tgz#9c23abf62944280d2d681f0a356fea67683a892f"
dependencies:
"@storybook/components" "3.4.0"
"@storybook/components" "3.4.1"
babel-runtime "^6.26.0"
deep-equal "^1.0.1"
global "^4.3.2"
@ -1000,58 +1005,58 @@
react-textarea-autosize "^5.2.1"
util-deprecate "^1.0.2"
"@storybook/addon-links@3.4.0", "@storybook/addon-links@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-3.4.0.tgz#638218a567b9318a72ab268963d7efcd47878164"
"@storybook/addon-links@3.4.1", "@storybook/addon-links@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/addon-links/-/addon-links-3.4.1.tgz#b5c5e942b8865b2489d8d1537699316d0b154b1b"
dependencies:
"@storybook/components" "3.4.0"
"@storybook/components" "3.4.1"
babel-runtime "^6.26.0"
global "^4.3.2"
prop-types "^15.6.1"
"@storybook/addon-options@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/addon-options/-/addon-options-3.4.0.tgz#e3da0f103a6bf89be7bf5b528795a971a7316a38"
"@storybook/addon-options@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/addon-options/-/addon-options-3.4.1.tgz#309f46c298b110442824b066e73df6dee17fc8b9"
dependencies:
babel-runtime "^6.26.0"
"@storybook/addons@3.4.0", "@storybook/addons@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-3.4.0.tgz#c1a96d32759df0117b7b9e50e33ff6c7f98b34c9"
"@storybook/addons@3.4.1", "@storybook/addons@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/addons/-/addons-3.4.1.tgz#ff80dc65a87607681b811a8cc4ff92124643f5ac"
"@storybook/channel-postmessage@3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-3.4.0.tgz#824ef774392e74802b9db368e1f97f2447652a14"
"@storybook/channel-postmessage@3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/channel-postmessage/-/channel-postmessage-3.4.1.tgz#17a84b8df1613196554f0450733a0b13d0954907"
dependencies:
"@storybook/channels" "3.4.0"
"@storybook/channels" "3.4.1"
global "^4.3.2"
json-stringify-safe "^5.0.1"
"@storybook/channels@3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-3.4.0.tgz#0702b8ddfee16aa69da942e18628e563fa7e1be0"
"@storybook/channels@3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/channels/-/channels-3.4.1.tgz#13536c0211f0b49d24b63c5e7cef87b11ae43f85"
"@storybook/client-logger@3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-3.4.0.tgz#130b1812cb5b5e9ea6962930da2c17265056defd"
"@storybook/client-logger@3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/client-logger/-/client-logger-3.4.1.tgz#5b24ea0fa105f0683a5e9797a41466e4267d2c7f"
"@storybook/components@3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-3.4.0.tgz#b9cb9aee02b9ff9311433d8b57c60d0350b21880"
"@storybook/components@3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/components/-/components-3.4.1.tgz#74e3bcf9590cb314a4845d2f3264aada79856c1f"
dependencies:
glamor "^2.20.40"
glamorous "^4.12.1"
prop-types "^15.6.1"
"@storybook/core@3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/core/-/core-3.4.0.tgz#7f0135047682e56503f5509cb2bd2dc6b27c0ca4"
"@storybook/core@3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/core/-/core-3.4.1.tgz#5ddbe754faa95c48ba272cfa30ca2e3272481aeb"
dependencies:
"@storybook/addons" "3.4.0"
"@storybook/channel-postmessage" "3.4.0"
"@storybook/client-logger" "3.4.0"
"@storybook/node-logger" "3.4.0"
"@storybook/ui" "3.4.0"
"@storybook/addons" "3.4.1"
"@storybook/channel-postmessage" "3.4.1"
"@storybook/client-logger" "3.4.1"
"@storybook/node-logger" "3.4.1"
"@storybook/ui" "3.4.1"
autoprefixer "^7.2.6"
babel-runtime "^6.26.0"
chalk "^2.3.2"
@ -1067,8 +1072,6 @@
postcss-loader "^2.1.2"
prop-types "^15.6.1"
qs "^6.5.1"
react "^16.0.0"
react-dom "^16.0.0"
serve-favicon "^2.4.5"
shelljs "^0.8.1"
style-loader "^0.20.3"
@ -1085,9 +1088,9 @@
"@storybook/react-simple-di" "^1.2.1"
babel-runtime "6.x.x"
"@storybook/node-logger@3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-3.4.0.tgz#ca06884967d98403b7524a424e60d7443c0080d1"
"@storybook/node-logger@3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/node-logger/-/node-logger-3.4.1.tgz#d1bddbaa5bcf995b97d408e46c1c2125d04b6e58"
dependencies:
npmlog "^4.1.2"
@ -1123,22 +1126,22 @@
dependencies:
babel-runtime "^6.5.0"
"@storybook/react@^3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/react/-/react-3.4.0.tgz#7c19d71ce27bb78b2d7a33d4fa2b30eceffe2677"
dependencies:
"@storybook/addon-actions" "3.4.0"
"@storybook/addon-links" "3.4.0"
"@storybook/addons" "3.4.0"
"@storybook/channel-postmessage" "3.4.0"
"@storybook/client-logger" "3.4.0"
"@storybook/core" "3.4.0"
"@storybook/node-logger" "3.4.0"
"@storybook/ui" "3.4.0"
"@storybook/react@^3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/react/-/react-3.4.1.tgz#db2b1c7980d9ed084aff4e28c5017e182b04bf3d"
dependencies:
"@storybook/addon-actions" "3.4.1"
"@storybook/addon-links" "3.4.1"
"@storybook/addons" "3.4.1"
"@storybook/channel-postmessage" "3.4.1"
"@storybook/client-logger" "3.4.1"
"@storybook/core" "3.4.1"
"@storybook/node-logger" "3.4.1"
"@storybook/ui" "3.4.1"
airbnb-js-shims "^1.4.1"
babel-loader "^7.1.4"
babel-plugin-macros "^2.2.0"
babel-plugin-react-docgen "^1.8.3"
babel-plugin-react-docgen "^1.9.0"
babel-plugin-transform-regenerator "^6.26.0"
babel-plugin-transform-runtime "^6.23.0"
babel-preset-env "^1.6.1"
@ -1167,11 +1170,11 @@
webpack "^3.11.0"
webpack-hot-middleware "^2.21.2"
"@storybook/ui@3.4.0":
version "3.4.0"
resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-3.4.0.tgz#4826b7e5b67c0c6d0515c0aedf8df48f8c2ea3da"
"@storybook/ui@3.4.1":
version "3.4.1"
resolved "https://registry.yarnpkg.com/@storybook/ui/-/ui-3.4.1.tgz#2f0109d806d7922e45b7f4dea67584d61536df46"
dependencies:
"@storybook/components" "3.4.0"
"@storybook/components" "3.4.1"
"@storybook/mantra-core" "^1.7.2"
"@storybook/podda" "^1.2.3"
"@storybook/react-komposer" "^2.0.3"
@ -2046,7 +2049,7 @@ babel-plugin-module-resolver@^3.1.1:
reselect "^3.0.1"
resolve "^1.4.0"
babel-plugin-react-docgen@^1.8.3:
babel-plugin-react-docgen@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-1.9.0.tgz#2e79aeed2f93b53a172398f93324fdcf9f02e01f"
dependencies:
@ -4668,9 +4671,9 @@ dotenv@^5.0.0, dotenv@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-5.0.1.tgz#a5317459bd3d79ab88cff6e44057a6a3fbb1fcef"
downshift@^1.31.2:
version "1.31.2"
resolved "https://registry.yarnpkg.com/downshift/-/downshift-1.31.2.tgz#6f638e9720d7540d9dffa0b4c4587cf10811cf8c"
downshift@^1.31.6:
version "1.31.6"
resolved "https://registry.yarnpkg.com/downshift/-/downshift-1.31.6.tgz#467ef5bb81e68d2377c7ed2c602a43f81e68478f"
duplexer2@~0.1.4:
version "0.1.4"
@ -4782,7 +4785,7 @@ electron-builder-lib@~20.6.2:
semver "^5.5.0"
temp-file "^3.1.1"
electron-builder@^20.8.1:
electron-builder@^20.0.4, electron-builder@^20.8.1:
version "20.8.1"
resolved "https://registry.yarnpkg.com/electron-builder/-/electron-builder-20.8.1.tgz#3d19607a7f7d3ee7f3e110a6fc66c720ed1d2cc0"
dependencies:
@ -4962,7 +4965,7 @@ electron-webpack@^2.0.1:
webpack-merge "^4.1.2"
yargs "^11.1.0"
electron@1.8.4:
electron@1.8.4, electron@^1.8.2:
version "1.8.4"
resolved "https://registry.yarnpkg.com/electron/-/electron-1.8.4.tgz#cca8d0e6889f238f55b414ad224f03e03b226a38"
dependencies:
@ -5035,6 +5038,10 @@ env-paths@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0"
envinfo@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-4.4.2.tgz#472c49f3a8b9bca73962641ce7cb692bf623cd1c"
errno@^0.1.3, errno@~0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
@ -6708,9 +6715,9 @@ i18next-node-fs-backend@^1.0.0:
js-yaml "3.5.4"
json5 "0.5.0"
i18next@^10.6.0:
version "10.6.0"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-10.6.0.tgz#90ffd9f9bc617f34b9a12e037260f524445f7684"
i18next@^11.1.1:
version "11.1.1"
resolved "https://registry.yarnpkg.com/i18next/-/i18next-11.1.1.tgz#df3a683542d7756a8aa8d6b884b61141239c394a"
iconv-lite@0.4, iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@^0.4.19, iconv-lite@~0.4.13:
version "0.4.19"
@ -7977,6 +7984,9 @@ ledger-test-library@KhalilBellakrid/ledger-test-library-nodejs#7d37482:
dependencies:
axios "^0.17.1"
bindings "^1.3.0"
electron "^1.8.2"
electron-builder "^20.0.4"
electron-rebuild "^1.7.3"
nan "^2.6.2"
prebuild-install "^2.2.2"
@ -7995,9 +8005,9 @@ levn@^0.3.0, levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
lint-staged@^7.0.2:
version "7.0.2"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-7.0.2.tgz#c99f6800e0525fa9c16f04c13ebe137edfd4fcd7"
lint-staged@^7.0.4:
version "7.0.4"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-7.0.4.tgz#1aa7f27427e4c4c85d4d6524ac98aac10cbaf1b8"
dependencies:
app-root-path "^2.0.1"
chalk "^2.3.1"
@ -8019,6 +8029,7 @@ lint-staged@^7.0.2:
pify "^3.0.0"
please-upgrade-node "^3.0.1"
staged-git-files "1.1.1"
string-argv "^0.0.2"
stringify-object "^3.2.2"
listenercount@~1.0.1:
@ -9391,9 +9402,9 @@ pngjs@^3.3.0:
version "3.3.2"
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.3.2.tgz#097c3c2a75feb223eadddea6bc9f0050cf830bc3"
popper.js@^1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.1.tgz#b8815e5cda6f62fc2042e47618649f75866e6753"
popper.js@^1.14.2:
version "1.14.3"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.3.tgz#1438f98d046acf7b4d78cd502bf418ac64d4f095"
portfinder@^1.0.9:
version "1.0.13"
@ -9946,13 +9957,6 @@ query-string@^5.0.1:
object-assign "^4.1.0"
strict-uri-encode "^1.0.0"
query-string@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.0.0.tgz#8b8f39447b73e8290d6f5e3581779218e9171142"
dependencies:
decode-uri-component "^0.2.0"
strict-uri-encode "^2.0.0"
querystring-es3@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
@ -10008,17 +10012,17 @@ range-parser@^1.0.3, range-parser@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e"
raven-js@^3.24.0:
version "3.24.0"
resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.24.0.tgz#59464d8bc4b3812ae87a282e9bb98ecad5b4b047"
raven-js@^3.24.1:
version "3.24.1"
resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.24.1.tgz#7327e08786248517eedd36205bf50f1047821ffa"
raven@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/raven/-/raven-2.4.2.tgz#0129e2adc30788646fd530b67d08a8ce25d4f6dc"
raven@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/raven/-/raven-2.5.0.tgz#7a2b4ce8b9ff884448924ad19ca33b574bce59a2"
dependencies:
cookie "0.3.1"
md5 "^2.2.1"
stack-trace "0.0.9"
stack-trace "0.0.10"
timed-out "4.0.1"
uuid "3.0.0"
@ -10094,9 +10098,9 @@ react-docgen@^3.0.0-beta11:
node-dir "^0.1.10"
recast "^0.12.6"
react-dom@^16.0.0, react-dom@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.0.tgz#b318e52184188ecb5c3e81117420cca40618643e"
react-dom@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.3.1.tgz#6a3c90a4fb62f915bdbcf6204422d93a7d4ca573"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.1.0"
@ -10157,9 +10161,9 @@ react-inspector@^2.2.2:
babel-runtime "^6.26.0"
is-dom "^1.0.9"
react-is@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.0.tgz#f0e8bfd8c09b480dd610b8639d9ed65c13601224"
react-is@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.1.tgz#ee66e6d8283224a83b3030e110056798488359ba"
react-modal@^3.3.2:
version "3.3.2"
@ -10264,14 +10268,14 @@ react-style-proptype@^3.0.0:
dependencies:
prop-types "^15.5.4"
react-test-renderer@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.0.tgz#7e88d8cb4c2b95c161b6c6c998991166f74d473e"
react-test-renderer@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.3.1.tgz#d9257936d8535bd40f57f3d5a84e7b0452fb17f2"
dependencies:
fbjs "^0.8.16"
object-assign "^4.1.1"
prop-types "^15.6.0"
react-is "^16.3.0"
react-is "^16.3.1"
react-textarea-autosize@^5.2.1:
version "5.2.1"
@ -10309,9 +10313,9 @@ react@^16.0.0, react@^16.2.0:
object-assign "^4.1.1"
prop-types "^15.6.0"
react@^16.3.0:
version "16.3.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.3.0.tgz#fc5a01c68f91e9b38e92cf83f7b795ebdca8ddff"
react@^16.3.1:
version "16.3.1"
resolved "https://registry.yarnpkg.com/react/-/react-16.3.1.tgz#4a2da433d471251c69b6033ada30e2ed1202cfd8"
dependencies:
fbjs "^0.8.16"
loose-envify "^1.1.0"
@ -10548,7 +10552,7 @@ regenerator-runtime@^0.10.5:
version "0.10.5"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
regenerator-runtime@^0.11.0:
regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
version "0.11.1"
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
@ -11449,9 +11453,9 @@ stable@~0.1.6:
version "0.1.6"
resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10"
stack-trace@0.0.9:
version "0.0.9"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695"
stack-trace@0.0.10:
version "0.0.10"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
stack-utils@^1.0.1:
version "1.0.1"
@ -11522,9 +11526,9 @@ strict-uri-encode@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
string-argv@^0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.0.2.tgz#dac30408690c21f3c3630a3ff3a05877bdcbd736"
string-length@^2.0.0:
version "2.0.0"
@ -11923,10 +11927,6 @@ timed-out@4.0.1, timed-out@^4.0.0, timed-out@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
timemachine@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/timemachine/-/timemachine-0.3.0.tgz#83e2eb696cbfe4696c1708e6a3700df4e62fc525"
timers-browserify@^2.0.4:
version "2.0.6"
resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae"
@ -11937,11 +11937,11 @@ tinycolor2@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
tippy.js@^2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-2.4.1.tgz#ae9b6418dbfed2563f46bd3cf9e277d893ccc740"
tippy.js@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-2.5.0.tgz#393826b42aa1750268e0d2a4d6f047abe4c96d50"
dependencies:
popper.js "^1.14.1"
popper.js "^1.14.2"
tmp@^0.0.33:
version "0.0.33"
@ -12555,6 +12555,37 @@ webpack-cli@^2.0.13:
yeoman-environment "^2.0.0"
yeoman-generator "^2.0.3"
webpack-cli@^2.0.14:
version "2.0.14"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-2.0.14.tgz#71d03d8c10547c1dfd674f71ff3b0457c33a74cd"
dependencies:
chalk "^2.3.2"
cross-spawn "^6.0.5"
diff "^3.5.0"
enhanced-resolve "^4.0.0"
envinfo "^4.4.2"
glob-all "^3.1.0"
global-modules "^1.0.0"
got "^8.2.0"
import-local "^1.0.0"
inquirer "^5.1.0"
interpret "^1.0.4"
jscodeshift "^0.5.0"
listr "^0.13.0"
loader-utils "^1.1.0"
lodash "^4.17.5"
log-symbols "^2.2.0"
mkdirp "^0.5.1"
p-each-series "^1.0.0"
p-lazy "^1.0.0"
prettier "^1.5.3"
supports-color "^5.3.0"
v8-compile-cache "^1.1.2"
webpack-addons "^1.1.5"
yargs "^11.1.0"
yeoman-environment "^2.0.0"
yeoman-generator "^2.0.3"
webpack-core@~0.6.0:
version "0.6.9"
resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2"
@ -12675,9 +12706,9 @@ webpack@^3.11.0:
webpack-sources "^1.0.1"
yargs "^8.0.2"
webpack@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.4.1.tgz#b0105789890c28bfce9f392623ef5850254328a4"
webpack@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.5.0.tgz#1e6f71e148ead02be265ff2879c9cd6bb30b8848"
dependencies:
acorn "^5.0.0"
acorn-dynamic-import "^3.0.0"

Loading…
Cancel
Save