diff --git a/.storybook/preview-head.html b/.storybook/preview-head.html index 9e769352..52da7032 100644 --- a/.storybook/preview-head.html +++ b/.storybook/preview-head.html @@ -1,2 +1,3 @@ + \ No newline at end of file diff --git a/package.json b/package.json index dd55ec56..c3c4d732 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "ethereumjs-abi": "^0.6.5", "extract-text-webpack-plugin": "^4.0.0-beta.0", "file-loader": "^1.1.11", - "flow-bin": "^0.66.0", + "flow-bin": "^0.79.1", "fs-extra": "^5.0.0", "html-loader": "^0.5.5", "html-webpack-plugin": "^3.0.4", @@ -102,8 +102,8 @@ }, "dependencies": { "@gnosis.pm/util-contracts": "^0.2.14", - "@material-ui/core": "^1.2.1", - "@material-ui/icons": "^1.1.0", + "@material-ui/core": "^3.0.1", + "@material-ui/icons": "^3.0.1", "final-form": "^4.2.1", "history": "^4.7.2", "react-final-form": "^3.1.2", diff --git a/public/favicon.ico b/public/favicon.ico index 9cb8601e..7b9d1cd1 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html index 832dad97..9e3064f4 100644 --- a/public/index.html +++ b/public/index.html @@ -5,6 +5,7 @@ + Multisig Safe diff --git a/src/components/Footer/index.jsx b/src/components/Footer/index.jsx index eb1e52ed..2c5882c5 100644 --- a/src/components/Footer/index.jsx +++ b/src/components/Footer/index.jsx @@ -2,16 +2,17 @@ import React from 'react' import Block from '~/components/layout/Block' import Link from '~/components/layout/Link' +import Paragraph from '~/components/layout/Paragraph' import { WELCOME_ADDRESS, SAFELIST_ADDRESS } from '~/routes/routes' import styles from './index.scss' const Footer = () => ( - - Welcome + + Welcome - Safe List + Safe List ) diff --git a/src/components/Footer/index.scss b/src/components/Footer/index.scss index c5036983..91887ad4 100644 --- a/src/components/Footer/index.scss +++ b/src/components/Footer/index.scss @@ -1,7 +1,12 @@ .footer { + font-size: $smallFontSize; display: grid; - grid-template-columns: 1fr auto auto; - justify-items: end; + grid-template-columns: 100px 100px 1fr; + grid-template-rows: 36px; + justify-items: center; + align-items: center; + border: solid 0.5px $border; + background-color: white; } @media only screen and (max-width: $(screenXs)px) { diff --git a/src/components/Footer/index.stories.js b/src/components/Footer/index.stories.js index 57711930..1af60805 100644 --- a/src/components/Footer/index.stories.js +++ b/src/components/Footer/index.stories.js @@ -11,6 +11,6 @@ const FrameDecorator = story => ( ) -storiesOf('Components', module) +storiesOf('Components /Footer', module) .addDecorator(FrameDecorator) - .add('Footer', () => ) + .add('Loaded', () => ) diff --git a/src/components/Header/actions.js b/src/components/Header/actions.js index 32069043..e96a2379 100644 --- a/src/components/Header/actions.js +++ b/src/components/Header/actions.js @@ -1,6 +1,12 @@ // @flow -import { fetchProvider } from '~/logic/wallets/store/actions' +import { fetchProvider, removeProvider } from '~/logic/wallets/store/actions' + +export type Actions = { + fetchProvider: typeof fetchProvider, + removeProvider: typeof removeProvider, +} export default { fetchProvider, + removeProvider, } diff --git a/src/components/Header/assets/connect-wallet.svg b/src/components/Header/assets/connect-wallet.svg new file mode 100644 index 00000000..a04fe2bd --- /dev/null +++ b/src/components/Header/assets/connect-wallet.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/components/Header/assets/connected-error.svg b/src/components/Header/assets/connected-error.svg new file mode 100644 index 00000000..8c351246 --- /dev/null +++ b/src/components/Header/assets/connected-error.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/Header/assets/connected.svg b/src/components/Header/assets/connected.svg new file mode 100644 index 00000000..1309cf1c --- /dev/null +++ b/src/components/Header/assets/connected.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/Header/assets/dotRinkeby.svg b/src/components/Header/assets/dotRinkeby.svg new file mode 100644 index 00000000..8b415e70 --- /dev/null +++ b/src/components/Header/assets/dotRinkeby.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Header/assets/gnosis-safe-logo.svg b/src/components/Header/assets/gnosis-safe-logo.svg new file mode 100644 index 00000000..f125e106 --- /dev/null +++ b/src/components/Header/assets/gnosis-safe-logo.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + TEAM EDITIO N + + + diff --git a/src/components/Header/assets/gnosis_logo.svg b/src/components/Header/assets/gnosis_logo.svg deleted file mode 100644 index 32b13cfd..00000000 --- a/src/components/Header/assets/gnosis_logo.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/components/Header/assets/icon_metamask.svg b/src/components/Header/assets/icon_metamask.svg deleted file mode 100644 index 7a96204f..00000000 --- a/src/components/Header/assets/icon_metamask.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/components/Header/assets/icon_parity.svg b/src/components/Header/assets/icon_parity.svg deleted file mode 100644 index 63da56db..00000000 --- a/src/components/Header/assets/icon_parity.svg +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - diff --git a/src/components/Header/assets/metamask.svg b/src/components/Header/assets/metamask.svg new file mode 100644 index 00000000..5c45d278 --- /dev/null +++ b/src/components/Header/assets/metamask.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/Header/component/Connected/index.jsx b/src/components/Header/component/Connected/index.jsx deleted file mode 100644 index 73c7b09e..00000000 --- a/src/components/Header/component/Connected/index.jsx +++ /dev/null @@ -1,40 +0,0 @@ -// @flow -import * as React from 'react' -import Img from '~/components/layout/Img' -import Span from '~/components/layout/Span' -import { upperFirst } from '~/utils/css' - -const IconParity = require('~/components/Header/assets/icon_parity.svg') -const IconMetamask = require('~/components/Header/assets/icon_metamask.svg') - -type Props = { - provider: string, -} - -const PROVIDER_METAMASK = 'METAMASK' -const PROVIDER_PARITY = 'PARITY' - -const PROVIDER_ICONS = { - [PROVIDER_METAMASK]: IconMetamask, - [PROVIDER_PARITY]: IconParity, -} - -const Connected = ({ provider }: Props) => { - const msg = `You are using ${upperFirst(provider.toLowerCase())} to connect to your Safe` - - return ( - - { PROVIDER_ICONS[provider] && - {msg} - } - Connected - - ) -} - -export default Connected diff --git a/src/components/Header/component/Layout.jsx b/src/components/Header/component/Layout.jsx index 7afbb088..224a62cc 100644 --- a/src/components/Header/component/Layout.jsx +++ b/src/components/Header/component/Layout.jsx @@ -1,30 +1,77 @@ // @flow -import React from 'react' +import * as React from 'react' +import { withStyles } from '@material-ui/core/styles' +import Grow from '@material-ui/core/Grow' +import ClickAwayListener from '@material-ui/core/ClickAwayListener' +import Popper from '@material-ui/core/Popper' +import List from '@material-ui/core/List' +import Divider from '~/components/layout/Divider' +import openHoc, { type Open } from '~/components/hoc/OpenHoc' import Col from '~/components/layout/Col' import Img from '~/components/layout/Img' -import Refresh from '~/components/Refresh' import Row from '~/components/layout/Row' +import Spacer from '~/components/Spacer' +import { border, sm, md } from '~/theme/variables' +import Provider from './Provider' -import Connected from './Connected' -import NotConnected from './NotConnected' +const logo = require('../assets/gnosis-safe-logo.svg') -const logo = require('../assets/gnosis_logo.svg') - -type Props = { - provider: string, - reloadWallet: Function, +type Props = Open & { + classes: Object, + providerDetails: React$Node, + providerInfo: React$Node, } -const Header = ({ provider, reloadWallet }: Props) => ( - - - Gnosis Safe - - - { provider ? : } - - - -) +const styles = () => ({ + root: { + backgroundColor: 'white', + padding: 0, + boxShadow: '0 0 10px 0 rgba(33, 48, 77, 0.1)', + minWidth: '280px', + left: '4px', + }, + summary: { + borderBottom: `solid 2px ${border}`, + alignItems: 'center', + height: '52px', + backgroundColor: 'white', + }, + logo: { + padding: `${sm} ${md}`, + flexBasis: '95px', + }, +}) -export default Header +const Layout = openHoc(({ + open, toggle, classes, providerInfo, providerDetails, +}: Props) => ( + + + + Gnosis Team Safe + + + + + + {providerRef => ( + + {({ TransitionProps }) => ( + + + + {providerDetails} + + + + )} + + )} + + + +)) + +export default withStyles(styles)(Layout) diff --git a/src/components/Header/component/Layout.stories.js b/src/components/Header/component/Layout.stories.js index 778744d4..354ee223 100644 --- a/src/components/Header/component/Layout.stories.js +++ b/src/components/Header/component/Layout.stories.js @@ -1,9 +1,12 @@ // @flow -import { select } from '@storybook/addon-knobs' import { storiesOf } from '@storybook/react' import * as React from 'react' import styles from '~/components/layout/PageFrame/index.scss' -import Component from './Layout' +import Layout from './Layout' +import ProviderInfo from './ProviderInfo' +import ProviderDetails from './ProviderInfo/UserDetails' +import ProviderDisconnected from './ProviderDisconnected' +import ConnectDetails from './ProviderDisconnected/ConnectDetails' const FrameDecorator = story => (
@@ -11,10 +14,34 @@ const FrameDecorator = story => (
) -storiesOf('Components', module) +storiesOf('Components /Header', module) .addDecorator(FrameDecorator) - .add('Header', () => { - // https://github.com/storybooks/storybook/tree/master/addons/knobs#select - const provider = select('Status by Provider', ['', 'UNKNOWN', 'METAMASK', 'PARITY'], 'METAMASK') - return {}} /> + .add('Connected', () => { + const provider = 'Metamask' + const userAddress = '0x873faa4cddd5b157e8e5a57e7a5479afc5d30moe' + const network = 'RINKEBY' + const info = + const details = + + return + }) + .add('Disconnected', () => { + const info = + const details = + + return + }) + .add('Connection Error', () => { + const provider = 'Metamask' + const userAddress = '0x873faa4cddd5b157e8e5a57e7a5479afc5d30moe' + const network = 'RINKEBY' + const info = + const details = () + + return }) diff --git a/src/components/Header/component/NotConnected/index.jsx b/src/components/Header/component/NotConnected/index.jsx deleted file mode 100644 index f2c75156..00000000 --- a/src/components/Header/component/NotConnected/index.jsx +++ /dev/null @@ -1,5 +0,0 @@ -// @flow -import React from 'react' -import Span from '~/components/layout/Span' - -export default () => Not Connected diff --git a/src/components/Header/component/Provider.jsx b/src/components/Header/component/Provider.jsx new file mode 100644 index 00000000..ca18ae35 --- /dev/null +++ b/src/components/Header/component/Provider.jsx @@ -0,0 +1,74 @@ +// @flow +import * as React from 'react' +import { withStyles } from '@material-ui/core/styles' +import IconButton from '@material-ui/core/IconButton' +import ExpandLess from '@material-ui/icons/ExpandLess' +import ExpandMore from '@material-ui/icons/ExpandMore' +import Col from '~/components/layout/Col' +import { type Open } from '~/components/hoc/OpenHoc' +import { sm, md } from '~/theme/variables' + +type Props = Open & { + classes: Object, + popupDetails: React$Node, + info: React$Node, + children: Function, +} + +const styles = () => ({ + root: { + height: '100%', + display: 'flex', + alignItems: 'center', + flexBasis: '250px', + }, + provider: { + padding: `${sm} ${md}`, + alignItems: 'center', + flex: '1 1 auto', + display: 'flex', + cursor: 'pointer', + }, + expand: { + width: '30px', + height: '30px', + }, +}) + +type ProviderRef = { current: null | HTMLDivElement } + +class Provider extends React.Component { + constructor(props: Props) { + super(props) + + this.myRef = React.createRef() + } + + myRef: ProviderRef + + render() { + const { + open, toggle, children, classes, info, + } = this.props + + return ( + +
+ + { info } + + { open ? : } + + +
+ { children(this.myRef) } +
+ ) + } +} + +export default withStyles(styles)(Provider) diff --git a/src/components/Header/component/ProviderDisconnected/ConnectDetails.jsx b/src/components/Header/component/ProviderDisconnected/ConnectDetails.jsx new file mode 100644 index 00000000..f885f162 --- /dev/null +++ b/src/components/Header/component/ProviderDisconnected/ConnectDetails.jsx @@ -0,0 +1,64 @@ +// @flow +import * as React from 'react' +import { withStyles } from '@material-ui/core/styles' +import Paragraph from '~/components/layout/Paragraph' +import Button from '~/components/layout/Button' +import Img from '~/components/layout/Img' +import Row from '~/components/layout/Row' +import { md, lg } from '~/theme/variables' + +const connectedLogo = require('../../assets/connect-wallet.svg') + +type Props = { + classes: Object, + onConnect: Function, +} + +const styles = () => ({ + container: { + padding: `${md} 12px`, + }, + logo: { + justifyContent: 'center', + }, + text: { + letterSpacing: '-0.6px', + flexGrow: 1, + textAlign: 'center', + }, + connect: { + padding: `${md} ${lg}`, + }, + connectText: { + letterSpacing: '1px', + }, + img: { + margin: '0px 2px', + }, +}) + +const ConnectDetails = ({ classes, onConnect }: Props) => ( + +
+ + Connect a Wallet + +
+ + Connect a Wallet + + + + +
+) + +export default withStyles(styles)(ConnectDetails) diff --git a/src/components/Header/component/ProviderDisconnected/index.jsx b/src/components/Header/component/ProviderDisconnected/index.jsx new file mode 100644 index 00000000..9c3bc715 --- /dev/null +++ b/src/components/Header/component/ProviderDisconnected/index.jsx @@ -0,0 +1,43 @@ +// @flow +import * as React from 'react' +import { withStyles } from '@material-ui/core/styles' +import Paragraph from '~/components/layout/Paragraph' +import Col from '~/components/layout/Col' +import Img from '~/components/layout/Img' +import { type Open } from '~/components/hoc/OpenHoc' +import { md } from '~/theme/variables' + +const connectWallet = require('../../assets/connect-wallet.svg') + +type Props = Open & { + classes: Object, + children: Function, +} + +const styles = () => ({ + network: { + fontFamily: 'Montserrat, sans-serif', + }, + account: { + padding: `0 ${md}`, + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + flexGrow: 1, + }, + connect: { + letterSpacing: '-0.5px', + }, +}) + +const ProviderDesconnected = ({ classes }: Props) => ( + + Status connected + + Not Connected + Connect Wallet + + +) + +export default withStyles(styles)(ProviderDesconnected) diff --git a/src/components/Header/component/ProviderInfo/UserDetails.jsx b/src/components/Header/component/ProviderInfo/UserDetails.jsx new file mode 100644 index 00000000..4559e8ea --- /dev/null +++ b/src/components/Header/component/ProviderInfo/UserDetails.jsx @@ -0,0 +1,151 @@ +// @flow +import * as React from 'react' +import OpenInNew from '@material-ui/icons/OpenInNew' +import { withStyles } from '@material-ui/core/styles' +import Paragraph from '~/components/layout/Paragraph' +import Button from '~/components/layout/Button' +import Identicon from '~/components/Identicon' +import Bold from '~/components/layout/Bold' +import Hairline from '~/components/layout/Hairline' +import Img from '~/components/layout/Img' +import Row from '~/components/layout/Row' +import Block from '~/components/layout/Block' +import Spacer from '~/components/Spacer' +import { xs, sm, md, lg, background } from '~/theme/variables' +import { upperFirst } from '~/utils/css' +import { shortVersionOf } from '~/logic/wallets/ethAddresses' +import { openInEtherScan } from '~/logic/wallets/getWeb3' + +const metamask = require('../../assets/metamask.svg') +const connectedLogo = require('../../assets/connected.svg') +const connectedWarning = require('../../assets/connected-error.svg') +const dot = require('../../assets/dotRinkeby.svg') + +type Props = { + provider: string, + connected: boolean, + network: string, + userAddress: string, + classes: Object, + onDisconnect: Function, +} + +const openIconStyle = { + height: '16px', + color: '#467ee5', +} + +const styles = () => ({ + container: { + padding: `${md} 12px`, + display: 'flex', + flexDirection: 'column', + }, + identicon: { + justifyContent: 'center', + padding: `0 ${md}`, + }, + user: { + borderRadius: '3px', + backgroundColor: background, + margin: '0 auto', + padding: sm, + }, + details: { + padding: `0 ${lg}`, + height: '20px', + alignItems: 'center', + }, + address: { + flexGrow: 1, + textAlign: 'center', + letterSpacing: '-0.5px', + }, + open: { + paddingLeft: sm, + width: 'auto', + '&:hover': { + cursor: 'pointer', + }, + }, + disconnect: { + padding: `${md} ${lg}`, + }, + disconnectText: { + letterSpacing: '1px', + }, + logo: { + margin: `0px ${xs}`, + }, +}) + +const UserDetails = ({ + provider, connected, network, userAddress, classes, onDisconnect, +}: Props) => { + const status = connected ? 'Connected' : 'Connection error' + const address = userAddress ? shortVersionOf(userAddress, 6) : 'Address not available' + const identiconAddress = userAddress || 'random' + const connectionLogo = connected ? connectedLogo : connectedWarning + const color = connected ? 'primary' : 'warning' + + return ( + + + + + + + {address} + { userAddress && + + } + + + + + Status + + Conection Status + + + {status} + + + + + + Client + + Metamask client + + + {upperFirst(provider)} + + + + + + Network + + Network + + {upperFirst(network)} + + + + + + + + ) +} + +export default withStyles(styles)(UserDetails) diff --git a/src/components/Header/component/ProviderInfo/index.jsx b/src/components/Header/component/ProviderInfo/index.jsx new file mode 100644 index 00000000..dd675235 --- /dev/null +++ b/src/components/Header/component/ProviderInfo/index.jsx @@ -0,0 +1,64 @@ +// @flow +import * as React from 'react' +import { withStyles } from '@material-ui/core/styles' +import Paragraph from '~/components/layout/Paragraph' +import Col from '~/components/layout/Col' +import Img from '~/components/layout/Img' +import { sm } from '~/theme/variables' +import Identicon from '~/components/Identicon' +import { shortVersionOf } from '~/logic/wallets/ethAddresses' + +const connectedLogo = require('../../assets/connected.svg') +const connectedWarning = require('../../assets/connected-error.svg') + +type Props = { + provider: string, + network: string, + classes: Object, + userAddress: string, + connected: boolean, +} + +const styles = () => ({ + network: { + fontFamily: 'Montserrat, sans-serif', + }, + logo: { + top: '10px', + position: 'relative', + right: '13px', + }, + account: { + paddingRight: sm, + display: 'flex', + flexDirection: 'column', + justifyContent: 'center', + flexGrow: 1, + }, + address: { + letterSpacing: '-0.5px', + }, +}) + +const ProviderInfo = ({ + provider, network, userAddress, connected, classes, +}: Props) => { + const providerText = `${provider} [${network}]` + const cutAddress = connected ? shortVersionOf(userAddress, 6) : 'Connection Error' + const color = connected ? 'primary' : 'warning' + const logo = connected ? connectedLogo : connectedWarning + const identiconAddress = userAddress || 'random' + + return ( + + + Connection status + + {providerText} + {cutAddress} + + + ) +} + +export default withStyles(styles)(ProviderInfo) diff --git a/src/components/Header/index.jsx b/src/components/Header/index.jsx index 83cefe88..f6ccca5d 100644 --- a/src/components/Header/index.jsx +++ b/src/components/Header/index.jsx @@ -1,29 +1,81 @@ // @flow import * as React from 'react' import { connect } from 'react-redux' +import { logComponentStack, type Info } from '~/utils/logBoundaries' +import ProviderInfo from './component/ProviderInfo' +import ProviderDetails from './component/ProviderInfo/UserDetails' +import ProviderDisconnected from './component/ProviderDisconnected' +import ConnectDetails from './component/ProviderDisconnected/ConnectDetails' import Layout from './component/Layout' -import actions from './actions' -import selector from './selector' +import actions, { type Actions } from './actions' +import selector, { type SelectorProps } from './selector' -type Props = { - provider: string, - fetchProvider: Function, +type Props = Actions & SelectorProps + +type State = { + hasError: boolean, } -class Header extends React.PureComponent { +class Header extends React.PureComponent { + state = { + hasError: false, + } + componentDidMount() { this.props.fetchProvider() } - reloadWallet = () => { + componentDidCatch(error: Error, info: Info) { + this.setState({ hasError: true }) + + logComponentStack(error, info) + } + + onDisconnect = () => { + this.props.removeProvider() + } + + onConnect = () => { this.props.fetchProvider() } + getProviderInfoBased = () => { + const { hasError } = this.state + const { + loaded, available, provider, network, userAddress, + } = this.props + + if (hasError || !loaded) { + return + } + + return + } + + getProviderDetailsBased = () => { + const { hasError } = this.state + const { + loaded, available, provider, network, userAddress, + } = this.props + + if (hasError || !loaded) { + return + } + + return () + } + render() { - const { provider } = this.props - return ( - - ) + const info = this.getProviderInfoBased() + const details = this.getProviderDetailsBased() + + return } } diff --git a/src/components/Header/selector.js b/src/components/Header/selector.js index 11b9dd34..76b98813 100644 --- a/src/components/Header/selector.js +++ b/src/components/Header/selector.js @@ -1,7 +1,19 @@ // @flow import { createStructuredSelector } from 'reselect' -import { providerNameSelector } from '~/logic/wallets/store/selectors' +import { providerNameSelector, userAccountSelector, networkSelector, availableSelector, loadedSelector } from '~/logic/wallets/store/selectors' + +export type SelectorProps = { + provider: string, + userAddress: string, + network: string, + loaded: boolean, + available: boolean, +} export default createStructuredSelector({ provider: providerNameSelector, + userAddress: userAccountSelector, + network: networkSelector, + loaded: loadedSelector, + available: availableSelector, }) diff --git a/src/components/Identicon/blockies.js b/src/components/Identicon/blockies.js new file mode 100644 index 00000000..1123ab5e --- /dev/null +++ b/src/components/Identicon/blockies.js @@ -0,0 +1,366 @@ +/* eslint-disable */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (factory((global.blockies = {}))); +}(this, (function (exports) { + 'use strict'; + + /** + * A handy class to calculate color values. + * + * @version 1.0 + * @author Robert Eisele + * @copyright Copyright (c) 2010, Robert Eisele + * @link http://www.xarg.org/2010/03/generate-client-side-png-files-using-javascript/ + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * + */ + + + // helper functions for that ctx + function write(buffer, offs) { + for (var i = 2; i < arguments.length; i++) { + for (var j = 0; j < arguments[i].length; j++) { + buffer[offs++] = arguments[i].charAt(j); + } + } + } + + function byte2(w) { + return String.fromCharCode((w >> 8) & 255, w & 255); + } + + function byte4(w) { + return String.fromCharCode((w >> 24) & 255, (w >> 16) & 255, (w >> 8) & 255, w & 255); + } + + function byte2lsb(w) { + return String.fromCharCode(w & 255, (w >> 8) & 255); + } + + var PNG = function (width, height, depth) { + + this.width = width; + this.height = height; + this.depth = depth; + + // pixel data and row filter identifier size + this.pix_size = height * (width + 1); + + // deflate header, pix_size, block headers, adler32 checksum + this.data_size = 2 + this.pix_size + 5 * Math.floor((0xfffe + this.pix_size) / 0xffff) + 4; + + // offsets and sizes of Png chunks + this.ihdr_offs = 0; // IHDR offset and size + this.ihdr_size = 4 + 4 + 13 + 4; + this.plte_offs = this.ihdr_offs + this.ihdr_size; // PLTE offset and size + this.plte_size = 4 + 4 + 3 * depth + 4; + this.trns_offs = this.plte_offs + this.plte_size; // tRNS offset and size + this.trns_size = 4 + 4 + depth + 4; + this.idat_offs = this.trns_offs + this.trns_size; // IDAT offset and size + this.idat_size = 4 + 4 + this.data_size + 4; + this.iend_offs = this.idat_offs + this.idat_size; // IEND offset and size + this.iend_size = 4 + 4 + 4; + this.buffer_size = this.iend_offs + this.iend_size; // total PNG size + + this.buffer = new Array(); + this.palette = new Object(); + this.pindex = 0; + + var _crc32 = new Array(); + + // initialize buffer with zero bytes + for (var i = 0; i < this.buffer_size; i++) { + this.buffer[i] = "\x00"; + } + + // initialize non-zero elements + write(this.buffer, this.ihdr_offs, byte4(this.ihdr_size - 12), 'IHDR', byte4(width), byte4(height), "\x08\x03"); + write(this.buffer, this.plte_offs, byte4(this.plte_size - 12), 'PLTE'); + write(this.buffer, this.trns_offs, byte4(this.trns_size - 12), 'tRNS'); + write(this.buffer, this.idat_offs, byte4(this.idat_size - 12), 'IDAT'); + write(this.buffer, this.iend_offs, byte4(this.iend_size - 12), 'IEND'); + + // initialize deflate header + var header = ((8 + (7 << 4)) << 8) | (3 << 6); + header += 31 - (header % 31); + + write(this.buffer, this.idat_offs + 8, byte2(header)); + + // initialize deflate block headers + for (var i = 0; (i << 16) - 1 < this.pix_size; i++) { + var size, bits; + if (i + 0xffff < this.pix_size) { + size = 0xffff; + bits = "\x00"; + } else { + size = this.pix_size - (i << 16) - i; + bits = "\x01"; + } + write(this.buffer, this.idat_offs + 8 + 2 + (i << 16) + (i << 2), bits, byte2lsb(size), byte2lsb(~size)); + } + + /* Create crc32 lookup table */ + for (var i = 0; i < 256; i++) { + var c = i; + for (var j = 0; j < 8; j++) { + if (c & 1) { + c = -306674912 ^ ((c >> 1) & 0x7fffffff); + } else { + c = (c >> 1) & 0x7fffffff; + } + } + _crc32[i] = c; + } + + // compute the index into a png for a given pixel + this.index = function (x, y) { + var i = y * (this.width + 1) + x + 1; + var j = this.idat_offs + 8 + 2 + 5 * Math.floor((i / 0xffff) + 1) + i; + return j; + }; + + // convert a color and build up the palette + this.color = function (red, green, blue, alpha) { + + alpha = alpha >= 0 ? alpha : 255; + var color = (((((alpha << 8) | red) << 8) | green) << 8) | blue; + + if (typeof this.palette[color] == "undefined") { + if (this.pindex == this.depth) return "\x00"; + + var ndx = this.plte_offs + 8 + 3 * this.pindex; + + this.buffer[ndx + 0] = String.fromCharCode(red); + this.buffer[ndx + 1] = String.fromCharCode(green); + this.buffer[ndx + 2] = String.fromCharCode(blue); + this.buffer[this.trns_offs + 8 + this.pindex] = String.fromCharCode(alpha); + + this.palette[color] = String.fromCharCode(this.pindex++); + } + return this.palette[color]; + }; + + // output a PNG string, Base64 encoded + this.getBase64 = function () { + + var s = this.getDump(); + + var ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + var c1, c2, c3, e1, e2, e3, e4; + var l = s.length; + var i = 0; + var r = ""; + + do { + c1 = s.charCodeAt(i); + e1 = c1 >> 2; + c2 = s.charCodeAt(i + 1); + e2 = ((c1 & 3) << 4) | (c2 >> 4); + c3 = s.charCodeAt(i + 2); + if (l < i + 2) { e3 = 64; } else { e3 = ((c2 & 0xf) << 2) | (c3 >> 6); } + if (l < i + 3) { e4 = 64; } else { e4 = c3 & 0x3f; } + r += ch.charAt(e1) + ch.charAt(e2) + ch.charAt(e3) + ch.charAt(e4); + } while ((i += 3) < l); + return r; + }; + + // output a PNG string + this.getDump = function () { + + // compute adler32 of output pixels + row filter bytes + var BASE = 65521; /* largest prime smaller than 65536 */ + var NMAX = 5552; /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + var s1 = 1; + var s2 = 0; + var n = NMAX; + + for (var y = 0; y < this.height; y++) { + for (var x = -1; x < this.width; x++) { + s1 += this.buffer[this.index(x, y)].charCodeAt(0); + s2 += s1; + if ((n -= 1) == 0) { + s1 %= BASE; + s2 %= BASE; + n = NMAX; + } + } + } + s1 %= BASE; + s2 %= BASE; + write(this.buffer, this.idat_offs + this.idat_size - 8, byte4((s2 << 16) | s1)); + + // compute crc32 of the PNG chunks + function crc32(png, offs, size) { + var crc = -1; + for (var i = 4; i < size - 4; i += 1) { + crc = _crc32[(crc ^ png[offs + i].charCodeAt(0)) & 0xff] ^ ((crc >> 8) & 0x00ffffff); + } + write(png, offs + size - 4, byte4(crc ^ -1)); + } + + crc32(this.buffer, this.ihdr_offs, this.ihdr_size); + crc32(this.buffer, this.plte_offs, this.plte_size); + crc32(this.buffer, this.trns_offs, this.trns_size); + crc32(this.buffer, this.idat_offs, this.idat_size); + crc32(this.buffer, this.iend_offs, this.iend_size); + + // convert PNG to string + return "\x89PNG\r\n\x1A\n" + this.buffer.join(''); + }; + + this.fillRect = function (x, y, w, h, color) { + for (var i = 0; i < w; i++) { + for (var j = 0; j < h; j++) { + this.buffer[this.index(x + i, y + j)] = color; + } + } + }; + }; + + // https://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion + /** + * Converts an HSL color value to RGB. Conversion formula + * adapted from http://en.wikipedia.org/wiki/HSL_color_space. + * Assumes h, s, and l are contained in the set [0, 1] and + * returns r, g, and b in the set [0, 255]. + * + * @param {number} h The hue + * @param {number} s The saturation + * @param {number} l The lightness + * @return {Array} The RGB representation + */ + + function hue2rgb(p, q, t) { + if (t < 0) t += 1; + if (t > 1) t -= 1; + if (t < 1 / 6) return p + (q - p) * 6 * t; + if (t < 1 / 2) return q; + if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + + function hsl2rgb(h, s, l) { + var r, g, b; + + if (s == 0) { + r = g = b = l; // achromatic + } else { + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), 255]; + } + + // The random number is a js implementation of the Xorshift PRNG + var randseed = new Array(4); // Xorshift: [x, y, z, w] 32 bit values + + function seedrand(seed) { + for (var i = 0; i < randseed.length; i++) { + randseed[i] = 0; + } + for (var i = 0; i < seed.length; i++) { + randseed[i % 4] = (randseed[i % 4] << 5) - randseed[i % 4] + seed.charCodeAt(i); + } + } + + function rand() { + // based on Java's String.hashCode(), expanded to 4 32bit values + var t = randseed[0] ^ (randseed[0] << 11); + + randseed[0] = randseed[1]; + randseed[1] = randseed[2]; + randseed[2] = randseed[3]; + randseed[3] = randseed[3] ^ (randseed[3] >> 19) ^ t ^ (t >> 8); + + return (randseed[3] >>> 0) / (1 << 31 >>> 0); + } + + function createColor() { + //saturation is the whole color spectrum + var h = Math.floor(rand() * 360); + //saturation goes from 40 to 100, it avoids greyish colors + var s = rand() * 60 + 40; + //lightness can be anything from 0 to 100, but probabilities are a bell curve around 50% + var l = (rand() + rand() + rand() + rand()) * 25; + + return [h / 360, s / 100, l / 100]; + } + + function createImageData(size) { + var width = size; // Only support square icons for now + var height = size; + + var dataWidth = Math.ceil(width / 2); + var mirrorWidth = width - dataWidth; + + var data = []; + for (var y = 0; y < height; y++) { + var row = []; + for (var x = 0; x < dataWidth; x++) { + // this makes foreground and background color to have a 43% (1/2.3) probability + // spot color has 13% chance + row[x] = Math.floor(rand() * 2.3); + } + var r = row.slice(0, mirrorWidth); + r.reverse(); + row = row.concat(r); + + for (var i = 0; i < row.length; i++) { + data.push(row[i]); + } + } + + return data; + } + + function buildOpts(opts) { + if (!opts.seed) { + throw 'No seed provided' + } + + seedrand(opts.seed); + + return Object.assign({ + size: 8, + scale: 16, + color: createColor(), + bgcolor: createColor(), + spotcolor: createColor(), + }, opts) + } + + function toDataUrl(address) { + const opts = buildOpts({ seed: address.toLowerCase() }); + + const imageData = createImageData(opts.size); + const width = Math.sqrt(imageData.length); + + const p = new PNG(opts.size * opts.scale, opts.size * opts.scale, 3); + const bgcolor = p.color(...hsl2rgb(...opts.bgcolor)); + const color = p.color(...hsl2rgb(...opts.color)); + const spotcolor = p.color(...hsl2rgb(...opts.spotcolor)); + + for (var i = 0; i < imageData.length; i++) { + var row = Math.floor(i / width); + var col = i % width; + // if data is 0, leave the background + if (imageData[i]) { + // if data is 2, choose spot color, if 1 choose foreground + const pngColor = imageData[i] == 1 ? color : spotcolor; + p.fillRect(col * opts.scale, row * opts.scale, opts.scale, opts.scale, pngColor); + } + } + return `data:image/png;base64,${p.getBase64()}`; + } + + exports.toDataUrl = toDataUrl; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/src/components/Identicon/index.jsx b/src/components/Identicon/index.jsx new file mode 100644 index 00000000..a6b3fecd --- /dev/null +++ b/src/components/Identicon/index.jsx @@ -0,0 +1,67 @@ +// @flow +import * as React from 'react' +import { toDataUrl } from './blockies' + +type Props = { + address: string, + diameter: number, +} + +type IdenticonRef = { current: null | HTMLDivElement } + +export default class Identicon extends React.PureComponent { + constructor(props: Props) { + super(props) + + this.identicon = React.createRef() + } + + componentDidMount = () => { + const { address, diameter } = this.props + const image = this.generateBlockieIdenticon(address, diameter) + if (this.identicon.current) { + this.identicon.current.appendChild(image) + } + } + + componentDidUpdate = () => { + const { address, diameter } = this.props + const image = this.generateBlockieIdenticon(address, diameter) + + if (!this.identicon.current) { + return + } + + const { children } = this.identicon.current + for (let i = 0; i < children.length; i += 1) { + this.identicon.current.removeChild(children[i]) + } + + this.identicon.current.appendChild(image) + } + + getStyleFrom = (diameter: number) => ({ + width: diameter, + height: diameter, + }) + + generateBlockieIdenticon = (address: string, diameter: number) => { + const image = new window.Image() + image.src = toDataUrl(address) + image.height = diameter + image.width = diameter + image.style.borderRadius = `${diameter / 2}px` + + return image + } + + identicon: IdenticonRef + + render() { + const style = this.getStyleFrom(this.props.diameter) + + return ( +
+ ) + } +} diff --git a/src/components/Spacer/index.jsx b/src/components/Spacer/index.jsx new file mode 100644 index 00000000..114a94f1 --- /dev/null +++ b/src/components/Spacer/index.jsx @@ -0,0 +1,8 @@ +// @flow +import * as React from 'react' + +const style = { + flexGrow: 1, +} + +export default () =>
diff --git a/src/components/Stepper/index.jsx b/src/components/Stepper/index.jsx index 20328615..5dc21fb6 100644 --- a/src/components/Stepper/index.jsx +++ b/src/components/Stepper/index.jsx @@ -164,6 +164,7 @@ class GnoStepper extends React.PureComponent { const styles = { root: { flex: '1 1 auto', + backgroundColor: 'transparent', }, } diff --git a/src/components/layout/Block/index.jsx b/src/components/layout/Block/index.jsx index a92dd060..d399bb82 100644 --- a/src/components/layout/Block/index.jsx +++ b/src/components/layout/Block/index.jsx @@ -2,12 +2,11 @@ import classNames from 'classnames/bind' import React, { PureComponent } from 'react' import { capitalize } from '~/utils/css' +import { type Size } from '~/theme/size' import styles from './index.scss' const cx = classNames.bind(styles) -type Size = 'sm' | 'md' | 'lg' | 'xl' - type Props = { margin?: Size, padding?: Size, diff --git a/src/components/layout/Block/index.scss b/src/components/layout/Block/index.scss index 62a278cb..8abbbde4 100644 --- a/src/components/layout/Block/index.scss +++ b/src/components/layout/Block/index.scss @@ -1,6 +1,9 @@ .block { - width: 100%; - overflow: hidden; + +} + +.xs { + margin-bottom: $xs; } .sm { @@ -19,6 +22,10 @@ margin-bottom: $xl; } +.paddingXs { + padding-top: $xs; +} + .paddingSm { padding-top: $sm; } diff --git a/src/components/layout/Button/index.jsx b/src/components/layout/Button/index.jsx index f0ee9a37..1c236242 100644 --- a/src/components/layout/Button/index.jsx +++ b/src/components/layout/Button/index.jsx @@ -1,4 +1,26 @@ // @flow +import * as React from 'react' import Button from '@material-ui/core/Button' +import { withStyles } from '@material-ui/core/styles' -export default Button +const styles = { + root: { + borderRadius: 0, + }, +} + +type Props = { + minWidth?: number +} + +const calculateStyleBased = minWidth => ({ + minWidth: `${minWidth}px`, +}) + +const GnoButton = ({ minWidth, ...props }: Props) => { + const style = minWidth ? calculateStyleBased(minWidth) : undefined + + return +) + +export const LoadSafe = ({ size, provider }: SafeProps) => ( + ) const Welcome = ({ provider }: Props) => ( - Safe Box + + Welcome to the Gnosis + + + Safe Team Edition + + + The Gnosis Safe Team Edition is geared towards teams managing
+ shared crypto funds. It is an improvement of the existing Gnosis
+ MultiSig wallet with redesigned smart contracts, cheaper setup and
+ transaction costs as well as an enhanced user experience. +
- + + + +
) diff --git a/src/routes/welcome/components/Layout.scss b/src/routes/welcome/components/Layout.scss index 681515f7..aeb5a001 100644 --- a/src/routes/welcome/components/Layout.scss +++ b/src/routes/welcome/components/Layout.scss @@ -1,18 +1,15 @@ .safe { - display: grid; justify-content: center; - grid-row-gap: $xl; + justify-items: center; + margin-top: $xl; } -.safeActions { +.summary { display: flex; justify-content: space-around; } -@media(max-width: $(screenXsMax)px) { - .safeActions { - grid-row-gap: $md; - display: grid; - justify-items: center; - } +.safeActions { + display: flex; + justify-content: center; } diff --git a/src/test/dailyLimit.blockchain.test.js b/src/test/dailyLimit.blockchain.test.js index fcb2bc9e..a4e8082a 100644 --- a/src/test/dailyLimit.blockchain.test.js +++ b/src/test/dailyLimit.blockchain.test.js @@ -28,6 +28,6 @@ describe('Safe Blockchain Test', () => { await executeWithdrawOn(safe, value) // THEN - expect(executeWithdrawOn(safe, value)).rejects.toThrow('VM Exception while processing transaction: revert') + expect(executeWithdrawOn(safe, value)).rejects.toThrow('VM Exception while processing transaction: revert Daily limit has been reached') }) }) diff --git a/src/theme/mui.js b/src/theme/mui.js index 325d2da9..300cf447 100644 --- a/src/theme/mui.js +++ b/src/theme/mui.js @@ -1,7 +1,7 @@ // @flow import red from '@material-ui/core/colors/red' import { createMuiTheme } from '@material-ui/core/styles' -import { primary, secondary } from './variables' +import { mediumFontSize, primary, secondary, md, lg } from './variables' export type WithStyles = { classes: Object, @@ -25,5 +25,21 @@ export default createMuiTheme({ typography: { fontFamily: 'Montserrat,sans-serif', }, + overrides: { + MuiButton: { + root: { + fontFamily: 'Roboto Mono, monospace', + letterSpacing: '1px', + }, + containedPrimary: { + backgroundColor: '#467ee5', + }, + sizeLarge: { + padding: `${md} ${lg}`, + minHeight: '52px', + fontSize: mediumFontSize, + }, + }, + }, palette, }) diff --git a/src/theme/size.js b/src/theme/size.js new file mode 100644 index 00000000..13e11797 --- /dev/null +++ b/src/theme/size.js @@ -0,0 +1,21 @@ +// @flow +import { xs, sm, md, lg, xl } from '~/theme/variables' + +export type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl' + +export const getSize = (size: Size) => { + switch (size) { + case 'xs': + return xs + case 'sm': + return sm + case 'md': + return md + case 'lg': + return lg + case 'xl': + return xl + default: + return md + } +} diff --git a/src/theme/variables.js b/src/theme/variables.js index 52c9a40d..94185584 100644 --- a/src/theme/variables.js +++ b/src/theme/variables.js @@ -1,31 +1,45 @@ // @flow -const primary = '#1798cc' +const border = '#eaebef' +const background = '#f4f4f9' +const primary = '#4a5579' const secondary = '#13222b' const tertiary = '#f6f9fc' +const fontColor = '#4a5579' +const fancyColor = '#fd7890' +const warningColor = '#c97c05' const xs = '4px' const sm = '8px' const md = '16px' const lg = '24px' -const xl = '42px' +const xl = '32px' +const xxl = '40px' module.exports = Object.assign({}, { primary, secondary, tertiary, + background, + fontColor, + fancy: fancyColor, + warning: warningColor, xs, sm, md, lg, xl, - fontSizeHeadingXs: 16, + xxl, + border, + fontSizeHeadingXs: 13, fontSizeHeadingSm: 18, fontSizeHeadingMd: 21, - fontSizeHeadingLg: 28, - regularFontWeight: 400, - boldFontWeight: 700, - smallFontSize: '12px', - mediumFontSize: '14px', - largeFontSize: '18px', + fontSizeHeadingLg: 32, + lightFont: 300, + regularFont: 400, + bolderFont: 500, + boldFont: 700, + smallFontSize: '11px', + mediumFontSize: '13px', + largeFontSize: '15px', extraLargeFontSize: '24px', screenXs: 480, screenXsMax: 767, diff --git a/src/utils/css.js b/src/utils/css.js index 3c556b23..34dddbe7 100644 --- a/src/utils/css.js +++ b/src/utils/css.js @@ -1,5 +1,5 @@ // @flow -export const upperFirst = (value: string) => value.charAt(0).toUpperCase() + value.slice(1) +export const upperFirst = (value: string) => value.charAt(0).toUpperCase() + value.toLowerCase().slice(1) type Value = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'center' | 'end' | 'start' | number | boolean diff --git a/src/utils/logBoundaries.js b/src/utils/logBoundaries.js new file mode 100644 index 00000000..9db3a6a6 --- /dev/null +++ b/src/utils/logBoundaries.js @@ -0,0 +1,12 @@ +// @flow +export type Info = { + componentStack: string, +} + +export const logComponentStack = (error: Error, info: Info) => { + // eslint-disable-next-line + console.log(error) + // eslint-disable-next-line + console.log(info.componentStack) +} + diff --git a/yarn.lock b/yarn.lock index 9264d541..af0f8771 100644 --- a/yarn.lock +++ b/yarn.lock @@ -860,12 +860,17 @@ "@babel/plugin-syntax-dynamic-import" "7.0.0-beta.51" "@babel/plugin-syntax-import-meta" "7.0.0-beta.51" -"@babel/runtime@^7.0.0-beta.42": - version "7.0.0-beta.51" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.51.tgz#48b8ed18307034c6620f643514650ca2ccc0165a" +"@babel/runtime@7.0.0", "@babel/runtime@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c" dependencies: - core-js "^2.5.7" - regenerator-runtime "^0.11.1" + regenerator-runtime "^0.12.0" + +"@babel/runtime@7.0.0-rc.1": + version "7.0.0-rc.1" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-rc.1.tgz#42f36fc5817911c89ea75da2b874054922967616" + dependencies: + regenerator-runtime "^0.12.0" "@babel/template@7.0.0-beta.44": version "7.0.0-beta.44" @@ -935,11 +940,11 @@ version "0.2.14" resolved "https://registry.yarnpkg.com/@gnosis.pm/util-contracts/-/util-contracts-0.2.14.tgz#587cd6268a7d08dbc0d08b1c7bd375e19549d833" -"@material-ui/core@^1.2.1": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-1.2.2.tgz#b074bdaa679d68af235b4d3f108f828ddcf6c1bc" +"@material-ui/core@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-3.0.1.tgz#e8476394a42d89ae404355ddbc093db4d044b225" dependencies: - "@babel/runtime" "^7.0.0-beta.42" + "@babel/runtime" "7.0.0" "@types/jss" "^9.5.3" "@types/react-transition-group" "^2.0.8" brcast "^3.0.1" @@ -949,6 +954,7 @@ deepmerge "^2.0.1" dom-helpers "^3.2.1" hoist-non-react-statics "^2.5.0" + is-plain-object "^2.0.4" jss "^9.3.3" jss-camel-case "^6.0.0" jss-default-unit "^8.0.2" @@ -958,20 +964,20 @@ jss-vendor-prefixer "^7.0.0" keycode "^2.1.9" normalize-scroll-left "^0.1.2" + popper.js "^1.14.1" prop-types "^15.6.0" - react-event-listener "^0.6.0" + react-event-listener "^0.6.2" react-jss "^8.1.0" - react-popper "^1.0.0" react-transition-group "^2.2.1" - recompose "^0.27.0" - scroll "^2.0.3" + recompose "^0.29.0" warning "^4.0.1" -"@material-ui/icons@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-1.1.0.tgz#4d025df7b0ba6ace8d6710079ed76013a4d26595" +"@material-ui/icons@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-3.0.1.tgz#671fb3d04dcaf9351dbbd2bf82ae2ae72e3d93cd" dependencies: - recompose "^0.26.0 || ^0.27.0" + "@babel/runtime" "7.0.0" + recompose "^0.29.0" "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" @@ -3963,13 +3969,6 @@ create-react-class@^15.5.2, create-react-class@^15.6.0, create-react-class@^15.6 loose-envify "^1.3.1" object-assign "^4.1.1" -create-react-context@^0.2.1: - version "0.2.2" - resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.2.2.tgz#9836542f9aaa22868cd7d4a6f82667df38019dca" - dependencies: - fbjs "^0.8.0" - gud "^1.0.0" - cross-spawn@5.1.0, cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" @@ -5370,7 +5369,7 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" -fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.12, fbjs@^0.8.16, fbjs@^0.8.9: +fbjs@^0.8.1, fbjs@^0.8.12, fbjs@^0.8.16, fbjs@^0.8.9: version "0.8.17" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.17.tgz#c4d598ead6949112653d6588b01a5cdcd9f90fdd" dependencies: @@ -5519,9 +5518,9 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" -flow-bin@^0.66.0: - version "0.66.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.66.0.tgz#a96dde7015dc3343fd552a7b4963c02be705ca26" +flow-bin@^0.79.1: + version "0.79.1" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.79.1.tgz#01c9f427baa6556753fa878c192d42e1ecb764b6" flow-parser@^0.*: version "0.74.0" @@ -5968,10 +5967,6 @@ growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" -gud@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" - gzip-size@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-3.0.0.tgz#546188e9bdc337f673772f81660464b389dce520" @@ -9670,12 +9665,6 @@ radium@^0.19.0, radium@^0.19.4: inline-style-prefixer "^2.0.5" prop-types "^15.5.8" -rafl@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rafl/-/rafl-1.2.2.tgz#fe930f758211020d47e38815f5196a8be4150740" - dependencies: - global "~4.3.0" - ramda@^0.24.1: version "0.24.1" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857" @@ -9790,11 +9779,11 @@ react-error-overlay@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4" -react-event-listener@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.1.tgz#41c7a80a66b398c27dd511e22712b02f3d4eccca" +react-event-listener@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/react-event-listener/-/react-event-listener-0.6.3.tgz#8eab88129a76e095ed8aa684c29679eded1e843d" dependencies: - "@babel/runtime" "^7.0.0-beta.42" + "@babel/runtime" "7.0.0-rc.1" prop-types "^15.6.0" warning "^4.0.1" @@ -9867,17 +9856,6 @@ react-onclickoutside@^6.5.0: version "6.7.1" resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.7.1.tgz#6a5b5b8b4eae6b776259712c89c8a2b36b17be93" -react-popper@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.0.0.tgz#b99452144e8fe4acc77fa3d959a8c79e07a65084" - dependencies: - babel-runtime "6.x.x" - create-react-context "^0.2.1" - popper.js "^1.14.1" - prop-types "^15.6.1" - typed-styles "^0.0.5" - warning "^3.0.0" - react-redux@^5.0.7: version "5.0.7" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8" @@ -10132,7 +10110,7 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" -"recompose@^0.26.0 || ^0.27.0", recompose@^0.27.0, recompose@^0.27.1: +recompose@^0.27.1: version "0.27.1" resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.27.1.tgz#1a49e931f183634516633bbb4f4edbfd3f38a7ba" dependencies: @@ -10143,6 +10121,17 @@ rechoir@^0.6.2: react-lifecycles-compat "^3.0.2" symbol-observable "^1.0.4" +recompose@^0.29.0: + version "0.29.0" + resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.29.0.tgz#f1a4e20d5f24d6ef1440f83924e821de0b1bccef" + dependencies: + "@babel/runtime" "^7.0.0" + change-emitter "^0.1.2" + fbjs "^0.8.1" + hoist-non-react-statics "^2.3.1" + react-lifecycles-compat "^3.0.2" + symbol-observable "^1.0.4" + recursive-readdir@2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.1.tgz#90ef231d0778c5ce093c9a48d74e5c5422d13a99" @@ -10214,6 +10203,10 @@ 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" +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd" @@ -10655,12 +10648,6 @@ scoped-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/scoped-regex/-/scoped-regex-1.0.0.tgz#a346bb1acd4207ae70bd7c0c7ca9e566b6baddb8" -scroll@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/scroll/-/scroll-2.0.3.tgz#0951b785544205fd17753bc3d294738ba16fc2ab" - dependencies: - rafl "~1.2.1" - scrypt.js@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/scrypt.js/-/scrypt.js-0.2.0.tgz#af8d1465b71e9990110bedfc593b9479e03a8ada" @@ -11820,10 +11807,6 @@ type-is@~1.6.15, type-is@~1.6.16: media-typer "0.3.0" mime-types "~2.1.18" -typed-styles@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.5.tgz#a60df245d482a9b1adf9c06c078d0f06085ed1cf" - typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"