Merge pull request #635 from 0xProject/feature/website/custom-onboarding-tooltip
Remove react-joyride and some more refactoring
This commit is contained in:
commit
e18d61b31a
@ -1,4 +1,12 @@
|
||||
[
|
||||
{
|
||||
"version": "0.5.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add types for `react-popper`, remove types for `react-joyride`"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "0.4.0",
|
||||
"changes": [
|
||||
|
@ -1,86 +0,0 @@
|
||||
// Type definitions for react-joyride 2.0.0-11
|
||||
// Project: https://github.com/gilbarbara/react-joyride
|
||||
|
||||
declare module 'react-joyride' {
|
||||
import * as React from 'react';
|
||||
export interface StyleOptions {
|
||||
arrowColor?: string;
|
||||
backgroundColor?: string;
|
||||
primaryColor?: string;
|
||||
textColor?: string;
|
||||
overlayColor?: string;
|
||||
spotlightShadow?: string;
|
||||
beaconSize?: number;
|
||||
zIndex?: number;
|
||||
}
|
||||
|
||||
export type Placement =
|
||||
| 'top'
|
||||
| 'top-left'
|
||||
| 'top-right'
|
||||
| 'bottom'
|
||||
| 'bottom-left'
|
||||
| 'bottom-right'
|
||||
| 'right'
|
||||
| 'left';
|
||||
|
||||
export interface Step {
|
||||
title?: string;
|
||||
content: React.ReactNode;
|
||||
target: string;
|
||||
placement?: Placement;
|
||||
type?: 'click' | 'hover';
|
||||
isFixed?: boolean;
|
||||
allowClicksThruHole?: boolean;
|
||||
disableBeacon?: boolean;
|
||||
style?: StyleOptions;
|
||||
[prop: string]: any;
|
||||
}
|
||||
|
||||
export interface StyleOptionsProp {
|
||||
options: StyleOptions;
|
||||
}
|
||||
|
||||
interface CallbackMetadata {
|
||||
type:
|
||||
| 'tour:start'
|
||||
| 'step:before'
|
||||
| 'beacon'
|
||||
| 'tooltip'
|
||||
| 'close'
|
||||
| 'step:after'
|
||||
| 'tour:end'
|
||||
| 'tour:status'
|
||||
| 'error:target_not_found'
|
||||
| 'error';
|
||||
step: number;
|
||||
}
|
||||
|
||||
export type CallbackData = CallbackMetadata & State;
|
||||
|
||||
export interface Props {
|
||||
steps?: Step[];
|
||||
beaconComponent?: React.ReactNode;
|
||||
disableOverlayClose?: boolean;
|
||||
run?: boolean;
|
||||
stepIndex?: number;
|
||||
callback?: (data: CallbackData) => void;
|
||||
debug?: boolean;
|
||||
styles?: StyleOptionsProp;
|
||||
}
|
||||
|
||||
export interface State {
|
||||
action: string;
|
||||
controlled: boolean;
|
||||
index: number;
|
||||
lifecycle: string;
|
||||
size: 0;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export default class Joyride extends React.Component<Props, State> {
|
||||
constructor(props: Props);
|
||||
|
||||
static defaultProps: Props;
|
||||
}
|
||||
}
|
49
packages/typescript-typings/types/react-popper/index.d.ts
vendored
Normal file
49
packages/typescript-typings/types/react-popper/index.d.ts
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
// Type definitions for react-popper 1.0.0-beta.6
|
||||
// Project: https://github.com/gilbarbara/react-joyride
|
||||
|
||||
declare module 'react-popper' {
|
||||
import * as React from 'react';
|
||||
import * as PopperJS from 'popper.js';
|
||||
|
||||
interface ManagerProps {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
export class Manager extends React.Component<ManagerProps, {}> {}
|
||||
|
||||
type RefHandler = (ref: HTMLElement | null) => void;
|
||||
|
||||
export interface ReferenceChildrenProps {
|
||||
ref: RefHandler;
|
||||
}
|
||||
|
||||
export interface ReferenceProps {
|
||||
children: (props: ReferenceChildrenProps) => React.ReactNode;
|
||||
}
|
||||
export class Reference extends React.Component<ReferenceProps, {}> {}
|
||||
|
||||
export interface PopperArrowProps {
|
||||
ref: RefHandler;
|
||||
style: React.CSSProperties;
|
||||
}
|
||||
|
||||
export type Placement = PopperJS.Placement;
|
||||
|
||||
export interface PopperChildrenProps {
|
||||
arrowProps: PopperArrowProps;
|
||||
outOfBoundaries: boolean | null;
|
||||
placement: PopperJS.Placement;
|
||||
ref: RefHandler;
|
||||
scheduleUpdate: () => void;
|
||||
style: React.CSSProperties;
|
||||
}
|
||||
|
||||
export interface PopperProps {
|
||||
children: (props: PopperChildrenProps) => React.ReactNode;
|
||||
eventsEnabled?: boolean;
|
||||
modifiers?: PopperJS.Modifiers;
|
||||
placement?: PopperJS.Placement;
|
||||
positionFixed?: boolean;
|
||||
referenceElement?: Element;
|
||||
}
|
||||
export class Popper extends React.Component<PopperProps, {}> {}
|
||||
}
|
@ -11,22 +11,19 @@
|
||||
"clean": "shx rm -f public/bundle*",
|
||||
"lint": "tslint --project . 'ts/**/*.ts' 'ts/**/*.tsx'",
|
||||
"watch": "webpack-dev-server --content-base public --https",
|
||||
"deploy_dogfood":
|
||||
"npm run build; aws s3 sync ./public/. s3://dogfood.0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
|
||||
"deploy_staging":
|
||||
"npm run build; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
|
||||
"deploy_live":
|
||||
"npm run build; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers"
|
||||
"deploy_dogfood": "npm run build; aws s3 sync ./public/. s3://dogfood.0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
|
||||
"deploy_staging": "npm run build; aws s3 sync ./public/. s3://staging-0xproject --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers",
|
||||
"deploy_live": "npm run build; aws s3 sync ./public/. s3://0xproject.com --profile 0xproject --region us-east-1 --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers"
|
||||
},
|
||||
"author": "Fabio Berger",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@0xproject/contract-wrappers": "^0.0.2",
|
||||
"@0xproject/react-docs": "^0.0.12",
|
||||
"@0xproject/react-shared": "^0.1.7",
|
||||
"@0xproject/subproviders": "^0.10.2",
|
||||
"@0xproject/contract-wrappers": "^0.0.2",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/types": "0.7.0",
|
||||
"@0xproject/typescript-typings": "^0.3.2",
|
||||
"@0xproject/utils": "^0.6.2",
|
||||
"@0xproject/web3-wrapper": "^0.6.4",
|
||||
"accounting": "^0.4.1",
|
||||
@ -46,7 +43,7 @@
|
||||
"react-document-title": "^2.0.3",
|
||||
"react-dom": "15.6.1",
|
||||
"react-ga": "^2.4.1",
|
||||
"react-joyride": "^2.0.0-11",
|
||||
"react-popper": "^1.0.0-beta.6",
|
||||
"react-redux": "^5.0.3",
|
||||
"react-router-dom": "^4.1.1",
|
||||
"react-scroll": "^1.5.2",
|
||||
|
@ -26,53 +26,53 @@
|
||||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-98720122-1"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() {
|
||||
dataLayer.push(arguments);
|
||||
}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'UA-98720122-1');
|
||||
</script>
|
||||
gtag('config', 'UA-98720122-1');
|
||||
</script>
|
||||
<!-- End Google Analytics -->
|
||||
<!-- Facebook SDK -->
|
||||
<div id="fb-root"></div>
|
||||
<script>
|
||||
(function(d, s, id) {
|
||||
var js,
|
||||
fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)) return;
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8&appId=1687545238205192';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
})(document, 'script', 'facebook-jssdk');
|
||||
</script>
|
||||
(function (d, s, id) {
|
||||
var js,
|
||||
fjs = d.getElementsByTagName(s)[0];
|
||||
if (d.getElementById(id)) return;
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = '//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.8&appId=1687545238205192';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
})(document, 'script', 'facebook-jssdk');
|
||||
</script>
|
||||
<div id="app"></div>
|
||||
<!-- End Facebook SDK -->
|
||||
<!-- Twitter SDK -->
|
||||
<script>
|
||||
window.twttr = (function(d, s, id) {
|
||||
var js,
|
||||
fjs = d.getElementsByTagName(s)[0],
|
||||
t = window.twttr || {};
|
||||
if (d.getElementById(id)) return t;
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = 'https://platform.twitter.com/widgets.js';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
window.twttr = (function (d, s, id) {
|
||||
var js,
|
||||
fjs = d.getElementsByTagName(s)[0],
|
||||
t = window.twttr || {};
|
||||
if (d.getElementById(id)) return t;
|
||||
js = d.createElement(s);
|
||||
js.id = id;
|
||||
js.src = 'https://platform.twitter.com/widgets.js';
|
||||
fjs.parentNode.insertBefore(js, fjs);
|
||||
|
||||
t._e = [];
|
||||
t.ready = function(f) {
|
||||
t._e.push(f);
|
||||
};
|
||||
return t;
|
||||
})(document, 'script', 'twitter-wjs');
|
||||
</script>
|
||||
t._e = [];
|
||||
t.ready = function (f) {
|
||||
t._e.push(f);
|
||||
};
|
||||
return t;
|
||||
})(document, 'script', 'twitter-wjs');
|
||||
</script>
|
||||
<!-- End Twitter SDK -->
|
||||
|
||||
<!-- Main -->
|
||||
<script type="text/javascript" crossorigin="anonymous" src="/bundle.js" charset="utf-8"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
@ -1,39 +1,96 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import Joyride, { CallbackData, Step, StyleOptions } from 'react-joyride';
|
||||
import { Placement, Popper, PopperChildrenProps } from 'react-popper';
|
||||
|
||||
import { ContinueButtonDisplay, OnboardingTooltip } from 'ts/components/onboarding/onboarding_tooltip';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Overlay } from 'ts/components/ui/overlay';
|
||||
import { zIndex } from 'ts/utils/style';
|
||||
|
||||
export interface Step {
|
||||
target: string;
|
||||
title?: string;
|
||||
content: React.ReactNode;
|
||||
placement?: Placement;
|
||||
hideBackButton?: boolean;
|
||||
hideNextButton?: boolean;
|
||||
continueButtonDisplay?: ContinueButtonDisplay;
|
||||
}
|
||||
|
||||
export interface OnboardingFlowProps {
|
||||
steps: Step[];
|
||||
stepIndex: number;
|
||||
isRunning: boolean;
|
||||
onClose: () => void;
|
||||
updateOnboardingStep: (stepIndex: number) => void;
|
||||
}
|
||||
|
||||
const joyrideStyleOptions: StyleOptions = {
|
||||
zIndex: zIndex.overlay,
|
||||
};
|
||||
|
||||
// Wrapper around Joyride with defaults and styles set
|
||||
export class OnboardingFlow extends React.Component<OnboardingFlowProps> {
|
||||
public render(): React.ReactNode {
|
||||
if (!this.props.isRunning) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Joyride
|
||||
run={this.props.isRunning}
|
||||
debug={true}
|
||||
steps={this.props.steps}
|
||||
stepIndex={this.props.stepIndex}
|
||||
styles={{ options: joyrideStyleOptions }}
|
||||
callback={this._handleChange.bind(this)}
|
||||
/>
|
||||
<Overlay>
|
||||
<Popper referenceElement={this._getElementForStep()} placement={this._getCurrentStep().placement}>
|
||||
{this._renderPopperChildren.bind(this)}
|
||||
</Popper>
|
||||
</Overlay>
|
||||
);
|
||||
}
|
||||
|
||||
private _handleChange(data: CallbackData): void {
|
||||
switch (data.action) {
|
||||
case 'close':
|
||||
this.props.onClose();
|
||||
private _getElementForStep(): Element {
|
||||
return document.querySelector(this._getCurrentStep().target);
|
||||
}
|
||||
|
||||
private _renderPopperChildren(props: PopperChildrenProps): React.ReactNode {
|
||||
return (
|
||||
<div ref={props.ref} style={props.style} data-placement={props.placement}>
|
||||
{this._renderToolTip()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private _renderToolTip(): React.ReactNode {
|
||||
const { steps, stepIndex } = this.props;
|
||||
const step = steps[stepIndex];
|
||||
const isLastStep = steps.length - 1 === stepIndex;
|
||||
return (
|
||||
<Container marginLeft="15px">
|
||||
<OnboardingTooltip
|
||||
title={step.title}
|
||||
content={step.content}
|
||||
isLastStep={isLastStep}
|
||||
hideBackButton={step.hideBackButton}
|
||||
hideNextButton={step.hideNextButton}
|
||||
onClose={this.props.onClose}
|
||||
onClickNext={this._goToNextStep.bind(this)}
|
||||
onClickBack={this._goToPrevStep.bind(this)}
|
||||
continueButtonDisplay={step.continueButtonDisplay}
|
||||
/>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
private _getCurrentStep(): Step {
|
||||
return this.props.steps[this.props.stepIndex];
|
||||
}
|
||||
|
||||
private _goToNextStep(): void {
|
||||
const nextStep = this.props.stepIndex + 1;
|
||||
if (nextStep < this.props.steps.length) {
|
||||
this.props.updateOnboardingStep(nextStep);
|
||||
} else {
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
private _goToPrevStep(): void {
|
||||
const nextStep = this.props.stepIndex - 1;
|
||||
if (nextStep >= 0) {
|
||||
this.props.updateOnboardingStep(nextStep);
|
||||
} else {
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,56 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { colors } from '@0xproject/react-shared';
|
||||
import { Container } from 'ts/components/ui/container';
|
||||
import { Island } from 'ts/components/ui/island';
|
||||
|
||||
export type ContinueButtonDisplay = 'enabled' | 'disabled';
|
||||
|
||||
export interface OnboardingTooltipProps {
|
||||
title?: string;
|
||||
content: React.ReactNode;
|
||||
isLastStep: boolean;
|
||||
onClose: () => void;
|
||||
onClickNext: () => void;
|
||||
onClickBack: () => void;
|
||||
continueButtonDisplay?: ContinueButtonDisplay;
|
||||
hideBackButton?: boolean;
|
||||
hideNextButton?: boolean;
|
||||
}
|
||||
|
||||
// TODO: Make this more general button.
|
||||
export interface ContinueButtonProps {
|
||||
display: ContinueButtonDisplay;
|
||||
children?: string;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export const ContinueButton: React.StatelessComponent<ContinueButtonProps> = (props: ContinueButtonProps) => {
|
||||
const isDisabled = props.display === 'disabled';
|
||||
return (
|
||||
<button disabled={isDisabled} onClick={isDisabled ? undefined : props.onClick}>
|
||||
{props.children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export const OnboardingTooltip: React.StatelessComponent<OnboardingTooltipProps> = (props: OnboardingTooltipProps) => (
|
||||
<Island>
|
||||
<Container paddingRight="30px" paddingLeft="30px" maxWidth={350} paddingTop="15px" paddingBottom="15px">
|
||||
<div className="flex flex-column">
|
||||
{props.title}
|
||||
{props.content}
|
||||
{props.continueButtonDisplay && (
|
||||
<ContinueButton onClick={props.onClickNext} display={props.continueButtonDisplay}>
|
||||
Continue
|
||||
</ContinueButton>
|
||||
)}
|
||||
{!props.hideBackButton && <button onClick={props.onClickBack}>Back</button>}
|
||||
{!props.hideNextButton && <button onClick={props.onClickNext}>Skip</button>}
|
||||
<button onClick={props.onClose}>Close</button>
|
||||
</div>
|
||||
</Container>
|
||||
</Island>
|
||||
);
|
||||
|
||||
OnboardingTooltip.displayName = 'OnboardingTooltip';
|
@ -1,32 +1,123 @@
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
import { Step } from 'react-joyride';
|
||||
|
||||
import { OnboardingFlow } from 'ts/components/onboarding/onboarding_flow';
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import { OnboardingFlow, Step } from 'ts/components/onboarding/onboarding_flow';
|
||||
import { ProviderType, TokenByAddress } from 'ts/types';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
export interface PortalOnboardingFlowProps {
|
||||
stepIndex: number;
|
||||
isRunning: boolean;
|
||||
onClose: () => void;
|
||||
userAddress: string;
|
||||
hasBeenSeen: boolean;
|
||||
providerType: ProviderType;
|
||||
injectedProviderName: string;
|
||||
blockchainIsLoaded: boolean;
|
||||
userEthBalanceInWei: BigNumber;
|
||||
tokenByAddress: TokenByAddress;
|
||||
updateIsRunning: (isRunning: boolean) => void;
|
||||
updateOnboardingStep: (stepIndex: number) => void;
|
||||
}
|
||||
|
||||
const steps: Step[] = [
|
||||
{
|
||||
target: '.wallet',
|
||||
content: 'You are onboarding right now!',
|
||||
placement: 'right',
|
||||
disableBeacon: true,
|
||||
},
|
||||
];
|
||||
|
||||
export class PortalOnboardingFlow extends React.Component<PortalOnboardingFlowProps> {
|
||||
public componentDidMount(): void {
|
||||
this._overrideOnboardingStateIfShould();
|
||||
}
|
||||
public componentDidUpdate(): void {
|
||||
this._overrideOnboardingStateIfShould();
|
||||
}
|
||||
public render(): React.ReactNode {
|
||||
return (
|
||||
<OnboardingFlow
|
||||
steps={steps}
|
||||
steps={this._getSteps()}
|
||||
stepIndex={this.props.stepIndex}
|
||||
isRunning={this.props.isRunning}
|
||||
onClose={this.props.onClose}
|
||||
onClose={this.props.updateIsRunning.bind(this, false)}
|
||||
updateOnboardingStep={this.props.updateOnboardingStep}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private _getSteps(): Step[] {
|
||||
const steps: Step[] = [
|
||||
{
|
||||
target: '.wallet',
|
||||
content:
|
||||
'Before you begin, you need to connect to a wallet. This will be used across all 0x relayers and dApps',
|
||||
placement: 'right',
|
||||
hideBackButton: true,
|
||||
hideNextButton: true,
|
||||
},
|
||||
{
|
||||
target: '.wallet',
|
||||
content: 'Unlock your metamask extension to begin',
|
||||
placement: 'right',
|
||||
hideBackButton: true,
|
||||
hideNextButton: true,
|
||||
},
|
||||
{
|
||||
target: '.wallet',
|
||||
content:
|
||||
'In order to start trading on any 0x relayer in the 0x ecosystem, you need to complete two simple steps',
|
||||
placement: 'right',
|
||||
hideBackButton: true,
|
||||
continueButtonDisplay: 'enabled',
|
||||
},
|
||||
{
|
||||
target: '.eth-row',
|
||||
content: 'Before you begin you will need to send some ETH to your metamask wallet',
|
||||
placement: 'right',
|
||||
continueButtonDisplay: this._userHasEth() ? 'enabled' : 'disabled',
|
||||
},
|
||||
{
|
||||
target: '.weth-row',
|
||||
content: 'You need to convert some of your ETH into tradeable Wrapped ETH (WETH)',
|
||||
placement: 'right',
|
||||
continueButtonDisplay: this._userHasWeth() ? 'enabled' : 'disabled',
|
||||
},
|
||||
];
|
||||
return steps;
|
||||
}
|
||||
|
||||
private _isAddressAvailable(): boolean {
|
||||
return !_.isEmpty(this.props.userAddress);
|
||||
}
|
||||
|
||||
private _userHasEth(): boolean {
|
||||
return this.props.userEthBalanceInWei > new BigNumber(0);
|
||||
}
|
||||
|
||||
private _userHasWeth(): boolean {
|
||||
// TODO: https://app.asana.com/0/681385331277907/690722374136933
|
||||
return false;
|
||||
}
|
||||
|
||||
private _overrideOnboardingStateIfShould(): void {
|
||||
this._autoStartOnboardingIfShould();
|
||||
this._adjustStepIfShould();
|
||||
}
|
||||
|
||||
private _adjustStepIfShould(): void {
|
||||
if (this._isAddressAvailable()) {
|
||||
if (this.props.stepIndex < 2) {
|
||||
this.props.updateOnboardingStep(2);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const isExternallyInjected = utils.isExternallyInjected(
|
||||
this.props.providerType,
|
||||
this.props.injectedProviderName,
|
||||
);
|
||||
if (isExternallyInjected) {
|
||||
this.props.updateOnboardingStep(1);
|
||||
return;
|
||||
}
|
||||
this.props.updateOnboardingStep(0);
|
||||
}
|
||||
private _autoStartOnboardingIfShould(): void {
|
||||
if (!this.props.isRunning && !this.props.hasBeenSeen && this.props.blockchainIsLoaded) {
|
||||
this.props.updateIsRunning(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import { Dispatcher } from 'ts/redux/dispatcher';
|
||||
import { ProviderType } from 'ts/types';
|
||||
import { colors } from 'ts/utils/colors';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
import { zIndex } from 'ts/utils/style';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
const ROOT_HEIGHT = 24;
|
||||
@ -39,8 +40,10 @@ const styles: Styles = {
|
||||
export class ProviderDisplay extends React.Component<ProviderDisplayProps, ProviderDisplayState> {
|
||||
public render(): React.ReactNode {
|
||||
const isAddressAvailable = !_.isEmpty(this.props.userAddress);
|
||||
const isExternallyInjectedProvider =
|
||||
this.props.providerType === ProviderType.Injected && this.props.injectedProviderName !== '0x Public';
|
||||
const isExternallyInjectedProvider = utils.isExternallyInjected(
|
||||
this.props.providerType,
|
||||
this.props.injectedProviderName,
|
||||
);
|
||||
const displayAddress = isAddressAvailable
|
||||
? utils.getAddressBeginAndEnd(this.props.userAddress)
|
||||
: isExternallyInjectedProvider
|
||||
@ -69,15 +72,13 @@ export class ProviderDisplay extends React.Component<ProviderDisplayProps, Provi
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
const hasInjectedProvider =
|
||||
this.props.injectedProviderName !== '0x Public' && this.props.providerType === ProviderType.Injected;
|
||||
const hasLedgerProvider = this.props.providerType === ProviderType.Ledger;
|
||||
const horizontalPosition = hasInjectedProvider || hasLedgerProvider ? 'left' : 'middle';
|
||||
const horizontalPosition = isExternallyInjectedProvider || hasLedgerProvider ? 'left' : 'middle';
|
||||
return (
|
||||
<div style={{ width: 'fit-content', height: 48, float: 'right' }}>
|
||||
<DropDown
|
||||
hoverActiveNode={hoverActiveNode}
|
||||
popoverContent={this.renderPopoverContent(hasInjectedProvider, hasLedgerProvider)}
|
||||
popoverContent={this.renderPopoverContent(isExternallyInjectedProvider, hasLedgerProvider)}
|
||||
anchorOrigin={{ horizontal: horizontalPosition, vertical: 'bottom' }}
|
||||
targetOrigin={{ horizontal: horizontalPosition, vertical: 'top' }}
|
||||
zDepth={1}
|
||||
|
@ -1,10 +1,17 @@
|
||||
import * as React from 'react';
|
||||
|
||||
type StringOrNum = string | number;
|
||||
|
||||
export interface ContainerProps {
|
||||
marginTop?: string | number;
|
||||
marginBottom?: string | number;
|
||||
marginRight?: string | number;
|
||||
marginLeft?: string | number;
|
||||
marginTop?: StringOrNum;
|
||||
marginBottom?: StringOrNum;
|
||||
marginRight?: StringOrNum;
|
||||
marginLeft?: StringOrNum;
|
||||
paddingTop?: StringOrNum;
|
||||
paddingBottom?: StringOrNum;
|
||||
paddingRight?: StringOrNum;
|
||||
paddingLeft?: StringOrNum;
|
||||
maxWidth?: StringOrNum;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
|
34
packages/website/ts/components/ui/overlay.tsx
Normal file
34
packages/website/ts/components/ui/overlay.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { colors } from '@0xproject/react-shared';
|
||||
import * as _ from 'lodash';
|
||||
import * as React from 'react';
|
||||
|
||||
import { zIndex } from 'ts/utils/style';
|
||||
|
||||
export interface OverlayProps {
|
||||
children?: React.ReactNode;
|
||||
style?: React.CSSProperties;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const style: React.CSSProperties = {
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
zIndex: zIndex.overlay,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
||||
};
|
||||
|
||||
export const Overlay: React.StatelessComponent = (props: OverlayProps) => (
|
||||
<div style={{ ...style, ...props.style }} onClick={props.onClick}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
||||
Overlay.defaultProps = {
|
||||
style: {},
|
||||
onClick: _.noop,
|
||||
};
|
||||
|
||||
Overlay.displayName = 'Overlay';
|
@ -46,6 +46,7 @@ import {
|
||||
import { backendClient } from 'ts/utils/backend_client';
|
||||
import { colors } from 'ts/utils/colors';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
import { zIndex } from 'ts/utils/style';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
import { styles as walletItemStyles } from 'ts/utils/wallet_item_styles';
|
||||
|
||||
@ -88,6 +89,8 @@ interface AccessoryItemConfig {
|
||||
const styles: Styles = {
|
||||
root: {
|
||||
width: '100%',
|
||||
zIndex: zIndex.aboveOverlay,
|
||||
position: 'relative',
|
||||
},
|
||||
headerItemInnerDiv: {
|
||||
paddingLeft: 65,
|
||||
@ -129,9 +132,6 @@ const styles: Styles = {
|
||||
};
|
||||
|
||||
const ETHER_ICON_PATH = '/images/ether.png';
|
||||
const ETHER_TOKEN_SYMBOL = 'WETH';
|
||||
const ZRX_TOKEN_SYMBOL = 'ZRX';
|
||||
const ETHER_SYMBOL = 'ETH';
|
||||
const ICON_DIMENSION = 24;
|
||||
const TOKEN_AMOUNT_DISPLAY_PRECISION = 3;
|
||||
const BODY_ITEM_KEY = 'BODY';
|
||||
@ -322,7 +322,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
||||
const primaryText = this._renderAmount(
|
||||
this.props.userEtherBalanceInWei,
|
||||
constants.DECIMAL_PLACES_ETH,
|
||||
ETHER_SYMBOL,
|
||||
constants.ETHER_SYMBOL,
|
||||
);
|
||||
const etherToken = this._getEthToken();
|
||||
const etherPrice = this.state.trackedTokenStateByAddress[etherToken.address].price;
|
||||
@ -341,13 +341,13 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
||||
? { ...walletItemStyles.focusedItem, ...styles.paddedItem }
|
||||
: { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
|
||||
const key = ETHER_ITEM_KEY;
|
||||
return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig);
|
||||
return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig, 'eth-row');
|
||||
}
|
||||
private _renderTokenRows(): React.ReactNode {
|
||||
const trackedTokens = this.props.trackedTokens;
|
||||
const trackedTokensStartingWithEtherToken = trackedTokens.sort(
|
||||
firstBy((t: Token) => t.symbol !== ETHER_TOKEN_SYMBOL)
|
||||
.thenBy((t: Token) => t.symbol !== ZRX_TOKEN_SYMBOL)
|
||||
firstBy((t: Token) => t.symbol !== constants.ETHER_TOKEN_SYMBOL)
|
||||
.thenBy((t: Token) => t.symbol !== constants.ZRX_TOKEN_SYMBOL)
|
||||
.thenBy('address'),
|
||||
);
|
||||
return _.map(trackedTokensStartingWithEtherToken, this._renderTokenRow.bind(this));
|
||||
@ -362,7 +362,8 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
||||
const icon = <TokenIcon token={token} diameter={ICON_DIMENSION} link={tokenLink} />;
|
||||
const primaryText = this._renderAmount(tokenState.balance, token.decimals, token.symbol);
|
||||
const secondaryText = this._renderValue(tokenState.balance, token.decimals, tokenState.price);
|
||||
const wrappedEtherDirection = token.symbol === ETHER_TOKEN_SYMBOL ? Side.Receive : undefined;
|
||||
const isWeth = token.symbol === constants.ETHER_TOKEN_SYMBOL;
|
||||
const wrappedEtherDirection = isWeth ? Side.Receive : undefined;
|
||||
const accessoryItemConfig: AccessoryItemConfig = {
|
||||
wrappedEtherDirection,
|
||||
allowanceToggleConfig: {
|
||||
@ -371,7 +372,14 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
||||
},
|
||||
};
|
||||
const key = token.address;
|
||||
return this._renderBalanceRow(key, icon, primaryText, secondaryText, accessoryItemConfig);
|
||||
return this._renderBalanceRow(
|
||||
key,
|
||||
icon,
|
||||
primaryText,
|
||||
secondaryText,
|
||||
accessoryItemConfig,
|
||||
isWeth ? 'weth-row' : undefined,
|
||||
);
|
||||
}
|
||||
private _renderBalanceRow(
|
||||
key: string,
|
||||
@ -379,6 +387,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
||||
primaryText: React.ReactNode,
|
||||
secondaryText: React.ReactNode,
|
||||
accessoryItemConfig: AccessoryItemConfig,
|
||||
className?: string,
|
||||
): React.ReactNode {
|
||||
const shouldShowWrapEtherItem =
|
||||
!_.isUndefined(this.state.wrappedEtherDirection) &&
|
||||
@ -388,7 +397,7 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
||||
: { ...styles.tokenItem, ...styles.borderedItem, ...styles.paddedItem };
|
||||
const etherToken = this._getEthToken();
|
||||
return (
|
||||
<div key={key} className="flex flex-column">
|
||||
<div key={key} className={`flex flex-column ${className || ''}`}>
|
||||
<div className="flex items-center" style={style}>
|
||||
<div className="px2">{icon}</div>
|
||||
<div className="flex-none pr2 pt2 pb2">
|
||||
@ -578,8 +587,6 @@ export class Wallet extends React.Component<WalletProps, WalletState> {
|
||||
});
|
||||
}
|
||||
private _getEthToken(): Token {
|
||||
const tokens = _.values(this.props.tokenByAddress);
|
||||
const etherToken = _.find(tokens, { symbol: ETHER_TOKEN_SYMBOL });
|
||||
return etherToken;
|
||||
return utils.getEthToken(this.props.tokenByAddress);
|
||||
}
|
||||
} // tslint:disable:max-file-line-count
|
||||
|
@ -6,6 +6,7 @@ import * as React from 'react';
|
||||
import { ProviderType } from 'ts/types';
|
||||
import { colors } from 'ts/utils/colors';
|
||||
import { constants } from 'ts/utils/constants';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
|
||||
export interface WalletDisconnectedItemProps {
|
||||
providerType: ProviderType;
|
||||
@ -38,8 +39,7 @@ const BUTTON_BOTTOM_PADDING = 80;
|
||||
export const WalletDisconnectedItem: React.StatelessComponent<WalletDisconnectedItemProps> = (
|
||||
props: WalletDisconnectedItemProps,
|
||||
) => {
|
||||
const isExternallyInjectedProvider =
|
||||
props.providerType === ProviderType.Injected && props.injectedProviderName !== '0x Public';
|
||||
const isExternallyInjectedProvider = utils.isExternallyInjected(props.providerType, props.injectedProviderName);
|
||||
return (
|
||||
<div className="flex flex-center">
|
||||
<div className="mx-auto">
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { BigNumber } from '@0xproject/utils';
|
||||
import * as React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { Dispatch } from 'redux';
|
||||
import { ActionTypes } from 'ts/types';
|
||||
import { ActionTypes, ProviderType, TokenByAddress } from 'ts/types';
|
||||
|
||||
import { PortalOnboardingFlow as PortalOnboardingFlowComponent } from 'ts/components/onboarding/portal_onboarding_flow';
|
||||
import { State } from 'ts/redux/reducer';
|
||||
@ -11,22 +12,43 @@ interface PortalOnboardingFlowProps {}
|
||||
interface ConnectedState {
|
||||
stepIndex: number;
|
||||
isRunning: boolean;
|
||||
userAddress: string;
|
||||
hasBeenSeen: boolean;
|
||||
providerType: ProviderType;
|
||||
injectedProviderName: string;
|
||||
blockchainIsLoaded: boolean;
|
||||
userEthBalanceInWei: BigNumber;
|
||||
tokenByAddress: TokenByAddress;
|
||||
}
|
||||
|
||||
interface ConnectedDispatch {
|
||||
onClose: () => void;
|
||||
updateIsRunning: (isRunning: boolean) => void;
|
||||
updateOnboardingStep: (stepIndex: number) => void;
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: State): ConnectedState => ({
|
||||
stepIndex: state.portalOnboardingStep,
|
||||
isRunning: state.isPortalOnboardingShowing,
|
||||
userAddress: state.userAddress,
|
||||
providerType: state.providerType,
|
||||
injectedProviderName: state.injectedProviderName,
|
||||
blockchainIsLoaded: state.blockchainIsLoaded,
|
||||
userEthBalanceInWei: state.userEtherBalanceInWei,
|
||||
tokenByAddress: state.tokenByAddress,
|
||||
hasBeenSeen: state.hasPortalOnboardingBeenSeen,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch<State>): ConnectedDispatch => ({
|
||||
onClose: (): void => {
|
||||
updateIsRunning: (isRunning: boolean): void => {
|
||||
dispatch({
|
||||
type: ActionTypes.UpdatePortalOnboardingShowing,
|
||||
data: false,
|
||||
data: isRunning,
|
||||
});
|
||||
},
|
||||
updateOnboardingStep: (stepIndex: number): void => {
|
||||
dispatch({
|
||||
type: ActionTypes.UpdatePortalOnboardingStep,
|
||||
data: stepIndex,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
@ -1,12 +1,9 @@
|
||||
// Polyfills
|
||||
import { MuiThemeProvider } from 'material-ui/styles';
|
||||
import * as React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom';
|
||||
import * as injectTapEventPlugin from 'react-tap-event-plugin';
|
||||
import { createStore, Store as ReduxStore } from 'redux';
|
||||
import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';
|
||||
import { Redirecter } from 'ts/components/redirecter';
|
||||
import { About } from 'ts/containers/about';
|
||||
import { FAQ } from 'ts/containers/faq';
|
||||
@ -16,11 +13,12 @@ import { Wiki } from 'ts/containers/wiki';
|
||||
import { createLazyComponent } from 'ts/lazy_component';
|
||||
import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
|
||||
import { tradeHistoryStorage } from 'ts/local_storage/trade_history_storage';
|
||||
import { reducer, State } from 'ts/redux/reducer';
|
||||
import { store } from 'ts/redux/store';
|
||||
import { WebsiteLegacyPaths, WebsitePaths } from 'ts/types';
|
||||
import { analytics } from 'ts/utils/analytics';
|
||||
import { muiTheme } from 'ts/utils/mui_theme';
|
||||
import { utils } from 'ts/utils/utils';
|
||||
// Polyfills
|
||||
import 'whatwg-fetch';
|
||||
injectTapEventPlugin();
|
||||
|
||||
@ -75,7 +73,7 @@ const LazyOrderUtilsDocumentation = createLazyComponent('Documentation', async (
|
||||
analytics.init();
|
||||
// tslint:disable-next-line:no-floating-promises
|
||||
analytics.logProviderAsync((window as any).web3);
|
||||
const store: ReduxStore<State> = createStore(reducer, devToolsEnhancer({ name: '0x Website Redux Store' }));
|
||||
|
||||
render(
|
||||
<Router>
|
||||
<div>
|
||||
|
@ -26,6 +26,16 @@ export const localStorage = {
|
||||
}
|
||||
window.localStorage.removeItem(key);
|
||||
},
|
||||
getObject(key: string): object | undefined {
|
||||
const item = localStorage.getItemIfExists(key);
|
||||
if (item) {
|
||||
return JSON.parse(item);
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
setObject(key: string, value: object): void {
|
||||
localStorage.setItem(key, JSON.stringify(value));
|
||||
},
|
||||
getAllKeys(): string[] {
|
||||
if (!this.doesExist) {
|
||||
return [];
|
||||
|
16
packages/website/ts/local_storage/state_storage.ts
Normal file
16
packages/website/ts/local_storage/state_storage.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { localStorage } from 'ts/local_storage/local_storage';
|
||||
import { INITIAL_STATE, State } from 'ts/redux/reducer';
|
||||
|
||||
const STORAGE_NAME = 'persistedState';
|
||||
|
||||
export const stateStorage = {
|
||||
saveState(partialState: Partial<State>): void {
|
||||
localStorage.setObject(STORAGE_NAME, partialState);
|
||||
},
|
||||
getPersistedState(): Partial<State> {
|
||||
return localStorage.getObject(STORAGE_NAME);
|
||||
},
|
||||
getPersistedDefaultState(): State {
|
||||
return { ...INITIAL_STATE, ...stateStorage.getPersistedState() };
|
||||
},
|
||||
};
|
@ -42,6 +42,7 @@ export interface State {
|
||||
userEtherBalanceInWei: BigNumber;
|
||||
portalOnboardingStep: number;
|
||||
isPortalOnboardingShowing: boolean;
|
||||
hasPortalOnboardingBeenSeen: boolean;
|
||||
// Note: cache of supplied orderJSON in fill order step. Do not use for anything else.
|
||||
userSuppliedOrderCache: Order;
|
||||
|
||||
@ -56,7 +57,7 @@ export interface State {
|
||||
translate: Translate;
|
||||
}
|
||||
|
||||
const INITIAL_STATE: State = {
|
||||
export const INITIAL_STATE: State = {
|
||||
// Portal
|
||||
blockchainErr: BlockchainErrs.NoError,
|
||||
blockchainIsLoaded: false,
|
||||
@ -84,6 +85,7 @@ const INITIAL_STATE: State = {
|
||||
userSuppliedOrderCache: undefined,
|
||||
portalOnboardingStep: 0,
|
||||
isPortalOnboardingShowing: false,
|
||||
hasPortalOnboardingBeenSeen: false,
|
||||
// Docs
|
||||
docsVersion: DEFAULT_DOCS_VERSION,
|
||||
availableDocVersions: [DEFAULT_DOCS_VERSION],
|
||||
@ -309,6 +311,7 @@ export function reducer(state: State = INITIAL_STATE, action: Action): State {
|
||||
return {
|
||||
...state,
|
||||
isPortalOnboardingShowing,
|
||||
hasPortalOnboardingBeenSeen: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
21
packages/website/ts/redux/store.ts
Normal file
21
packages/website/ts/redux/store.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import * as _ from 'lodash';
|
||||
import { createStore, Store as ReduxStore } from 'redux';
|
||||
import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly';
|
||||
import { stateStorage } from 'ts/local_storage/state_storage';
|
||||
import { reducer, State } from 'ts/redux/reducer';
|
||||
|
||||
const ONE_SECOND = 1000;
|
||||
|
||||
export const store: ReduxStore<State> = createStore(
|
||||
reducer,
|
||||
stateStorage.getPersistedDefaultState(),
|
||||
devToolsEnhancer({ name: '0x Website Redux Store' }),
|
||||
);
|
||||
store.subscribe(
|
||||
_.throttle(() => {
|
||||
// Persisted state
|
||||
stateStorage.saveState({
|
||||
hasPortalOnboardingBeenSeen: store.getState().hasPortalOnboardingBeenSeen,
|
||||
});
|
||||
}, ONE_SECOND),
|
||||
);
|
@ -4,6 +4,9 @@ import { BigNumber } from '@0xproject/utils';
|
||||
export const constants = {
|
||||
DECIMAL_PLACES_ETH: 18,
|
||||
DECIMAL_PLACES_ZRX: 18,
|
||||
ETHER_TOKEN_SYMBOL: 'WETH',
|
||||
ZRX_TOKEN_SYMBOL: 'ZRX',
|
||||
ETHER_SYMBOL: 'ETH',
|
||||
GENESIS_ORDER_BLOCK_BY_NETWORK_ID: {
|
||||
1: 4145578,
|
||||
42: 3117574,
|
||||
|
@ -1,4 +1,5 @@
|
||||
export const zIndex = {
|
||||
topBar: 1100,
|
||||
overlay: 1101,
|
||||
overlay: 1105,
|
||||
aboveOverlay: 1106,
|
||||
};
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
Environments,
|
||||
Order,
|
||||
Providers,
|
||||
ProviderType,
|
||||
ScreenWidths,
|
||||
Side,
|
||||
SideToAssetToken,
|
||||
@ -313,8 +314,16 @@ export const utils = {
|
||||
isStaging(): boolean {
|
||||
return _.includes(window.location.href, configs.DOMAIN_STAGING);
|
||||
},
|
||||
isExternallyInjected(providerType: ProviderType, injectedProviderName: string): boolean {
|
||||
return providerType === ProviderType.Injected && injectedProviderName !== constants.PROVIDER_NAME_PUBLIC;
|
||||
},
|
||||
isDogfood,
|
||||
shouldShowPortalV2(): boolean {
|
||||
return this.isDevelopment() || this.isStaging() || this.isDogfood();
|
||||
},
|
||||
getEthToken(tokenByAddress: TokenByAddress): Token {
|
||||
const tokens = _.values(tokenByAddress);
|
||||
const etherToken = _.find(tokens, { symbol: constants.ETHER_TOKEN_SYMBOL });
|
||||
return etherToken;
|
||||
},
|
||||
};
|
||||
|
109
yarn.lock
109
yarn.lock
@ -1443,7 +1443,7 @@ babel-register@^6.26.0, babel-register@^6.9.0:
|
||||
mkdirp "^0.5.1"
|
||||
source-map-support "^0.4.15"
|
||||
|
||||
babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
|
||||
babel-runtime@6.x.x, babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||
dependencies:
|
||||
@ -2890,6 +2890,13 @@ create-react-class@^15.5.2, create-react-class@^15.6.0:
|
||||
loose-envify "^1.3.1"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
create-react-context@^0.2.1:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.2.tgz#9836542f9aaa22868cd7d4a6f82667df38019dca"
|
||||
dependencies:
|
||||
fbjs "^0.8.0"
|
||||
gud "^1.0.0"
|
||||
|
||||
cross-fetch@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-2.1.0.tgz#7d4ea7e10a4f3bb73d5c2f0a3791ec3752d39b50"
|
||||
@ -3246,14 +3253,6 @@ dedent@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
|
||||
|
||||
deep-diff@^0.3.8:
|
||||
version "0.3.8"
|
||||
resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84"
|
||||
|
||||
deep-diff@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-1.0.0.tgz#0dd55f9412f22a07b2edbfbb11bb4633be6be40b"
|
||||
|
||||
deep-eql@^0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2"
|
||||
@ -3286,10 +3285,6 @@ deep-is@~0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
|
||||
|
||||
deepmerge@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.1.0.tgz#511a54fff405fc346f0240bb270a3e9533a31102"
|
||||
|
||||
default-require-extensions@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8"
|
||||
@ -4203,7 +4198,7 @@ execa@^0.8.0:
|
||||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
exenv@^1.2.1, exenv@^1.2.2:
|
||||
exenv@^1.2.1:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||
|
||||
@ -4395,7 +4390,7 @@ faye-websocket@~0.11.0:
|
||||
dependencies:
|
||||
websocket-driver ">=0.5.1"
|
||||
|
||||
fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.6, fbjs@^0.8.9:
|
||||
fbjs@^0.8.0, fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.4, fbjs@^0.8.6, fbjs@^0.8.9:
|
||||
version "0.8.16"
|
||||
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db"
|
||||
dependencies:
|
||||
@ -5219,6 +5214,10 @@ growl@1.9.2:
|
||||
version "1.9.2"
|
||||
resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f"
|
||||
|
||||
gud@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0"
|
||||
|
||||
gulp-sourcemaps@1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-1.6.0.tgz#b86ff349d801ceb56e1d9e7dc7bbcb4b7dee600c"
|
||||
@ -6041,10 +6040,6 @@ is-installed-globally@^0.1.0:
|
||||
global-dirs "^0.1.0"
|
||||
is-path-inside "^1.0.0"
|
||||
|
||||
is-lite@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/is-lite/-/is-lite-0.2.0.tgz#1532415467f1fd49aa693ba013a8669575df7cf3"
|
||||
|
||||
is-mobile@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/is-mobile/-/is-mobile-0.2.2.tgz#0e2e006d99ed2c2155b761df80f2a3619ae2ad9f"
|
||||
@ -7760,10 +7755,6 @@ neo-async@^2.5.0:
|
||||
version "2.5.1"
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.5.1.tgz#acb909e327b1e87ec9ef15f41b8a269512ad41ee"
|
||||
|
||||
nested-property@0.0.7, nested-property@^0.0.7:
|
||||
version "0.0.7"
|
||||
resolved "https://registry.yarnpkg.com/nested-property/-/nested-property-0.0.7.tgz#ff222f233ca8793c6828b4117091bea597130f4f"
|
||||
|
||||
newman@^3.9.3:
|
||||
version "3.9.3"
|
||||
resolved "https://registry.yarnpkg.com/newman/-/newman-3.9.3.tgz#939356026942474ba15482bd37a15c60bb200ca0"
|
||||
@ -8612,7 +8603,7 @@ plur@^2.1.2:
|
||||
dependencies:
|
||||
irregular-plurals "^1.0.0"
|
||||
|
||||
popper.js@^1.14.3:
|
||||
popper.js@^1.14.1:
|
||||
version "1.14.3"
|
||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.3.tgz#1438f98d046acf7b4d78cd502bf418ac64d4f095"
|
||||
|
||||
@ -9318,12 +9309,6 @@ quick-lru@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
|
||||
|
||||
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"
|
||||
|
||||
randomatic@^1.1.3:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
|
||||
@ -9430,16 +9415,6 @@ react-event-listener@^0.4.5:
|
||||
prop-types "^15.5.4"
|
||||
warning "^3.0.0"
|
||||
|
||||
react-floater@^0.5.4:
|
||||
version "0.5.4"
|
||||
resolved "https://registry.yarnpkg.com/react-floater/-/react-floater-0.5.4.tgz#411a57fd8631e96466e035ee6c91f1f118c8782a"
|
||||
dependencies:
|
||||
deepmerge "^2.1.0"
|
||||
exenv "^1.2.2"
|
||||
is-lite "^0.2.0"
|
||||
popper.js "^1.14.3"
|
||||
react-proptype-conditional-require "^1.0.4"
|
||||
|
||||
react-ga@^2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.4.1.tgz#dfbd5f028ed39a07067f7a8bf57dc0d240000767"
|
||||
@ -9456,22 +9431,6 @@ react-highlight@0xproject/react-highlight:
|
||||
react "^15.5.4"
|
||||
react-dom "^15.5.4"
|
||||
|
||||
react-joyride@^2.0.0-11:
|
||||
version "2.0.0-11"
|
||||
resolved "https://registry.yarnpkg.com/react-joyride/-/react-joyride-2.0.0-11.tgz#5cbf4f86b83dfbf9242e7d19482a0fd7cc69ad52"
|
||||
dependencies:
|
||||
deep-diff "^1.0.0"
|
||||
deepmerge "^2.1.0"
|
||||
exenv "^1.2.2"
|
||||
is-lite "^0.2.0"
|
||||
nested-property "^0.0.7"
|
||||
react-floater "^0.5.4"
|
||||
react-proptype-conditional-require "^1.0.4"
|
||||
scroll "^2.0.3"
|
||||
scroll-doc "^0.2.1"
|
||||
scrollparent "^2.0.1"
|
||||
tree-changes "^0.3.2"
|
||||
|
||||
react-markdown@^3.2.2:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-3.3.0.tgz#a87cdd822aa9302d6add9687961dd1a82a45d02e"
|
||||
@ -9482,9 +9441,16 @@ react-markdown@^3.2.2:
|
||||
unist-util-visit "^1.3.0"
|
||||
xtend "^4.0.1"
|
||||
|
||||
react-proptype-conditional-require@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-proptype-conditional-require/-/react-proptype-conditional-require-1.0.4.tgz#69c2d5741e6df5e08f230f36bbc2944ee1222555"
|
||||
react-popper@^1.0.0-beta.6:
|
||||
version "1.0.0-beta.6"
|
||||
resolved "https://registry.npmjs.org/react-popper/-/react-popper-1.0.0-beta.6.tgz#cb27a2ac56adccbaf5f9c4132387289069240834"
|
||||
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.3:
|
||||
version "5.0.7"
|
||||
@ -10175,20 +10141,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-doc@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/scroll-doc/-/scroll-doc-0.2.1.tgz#168f9e9ac598743dd682c992839b44a38ce4dd91"
|
||||
|
||||
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"
|
||||
|
||||
scrollparent@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/scrollparent/-/scrollparent-2.0.1.tgz#715d5b9cc57760fb22bdccc3befb5bfe06b1a317"
|
||||
|
||||
scrypt-js@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-2.0.3.tgz#bb0040be03043da9a012a2cea9fc9f852cfc87d4"
|
||||
@ -11491,13 +11443,6 @@ traverse-chain@~0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/traverse-chain/-/traverse-chain-0.1.0.tgz#61dbc2d53b69ff6091a12a168fd7d433107e40f1"
|
||||
|
||||
tree-changes@^0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/tree-changes/-/tree-changes-0.3.2.tgz#ad7d3b499155bd6176f2c9c6a472d8155df0a9ce"
|
||||
dependencies:
|
||||
deep-diff "^0.3.8"
|
||||
nested-property "0.0.7"
|
||||
|
||||
treeify@^1.0.1:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8"
|
||||
@ -11663,6 +11608,10 @@ 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.npmjs.org/typed-styles/-/typed-styles-0.0.5.tgz#a60df245d482a9b1adf9c06c078d0f06085ed1cf"
|
||||
|
||||
typedarray-to-buffer@^3.1.2:
|
||||
version "3.1.5"
|
||||
resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
|
||||
|
Loading…
x
Reference in New Issue
Block a user