import * as _ from 'lodash'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { DEFAULT_ZERO_EX_CONTAINER_SELECTOR, INJECTED_DIV_CLASS, INJECTED_DIV_ID } from './constants'; import { ZeroExInstantOverlay, ZeroExInstantOverlayProps } from './index'; import { assert } from './util/assert'; import { util } from './util/util'; export interface ZeroExInstantConfig extends ZeroExInstantOverlayProps { shouldDisablePushToHistory?: boolean; } export const render = (config: ZeroExInstantConfig, selector: string = DEFAULT_ZERO_EX_CONTAINER_SELECTOR) => { assert.isValidOrderSource('orderSource', config.orderSource); if (!_.isUndefined(config.defaultSelectedAssetData)) { assert.isHexString('defaultSelectedAssetData', config.defaultSelectedAssetData); } if (!_.isUndefined(config.additionalAssetMetaDataMap)) { assert.isValidAssetMetaDataMap('additionalAssetMetaDataMap', config.additionalAssetMetaDataMap); } if (!_.isUndefined(config.defaultAssetBuyAmount)) { assert.isNumber('defaultAssetBuyAmount', config.defaultAssetBuyAmount); } if (!_.isUndefined(config.networkId)) { assert.isNumber('networkId', config.networkId); } if (!_.isUndefined(config.availableAssetDatas)) { assert.areValidAssetDatas('availableAssetDatas', config.availableAssetDatas); } if (!_.isUndefined(config.onClose)) { assert.isFunction('onClose', config.onClose); } if (!_.isUndefined(config.zIndex)) { assert.isNumber('zIndex', config.zIndex); } if (!_.isUndefined(config.affiliateInfo)) { assert.isValidAffiliateInfo('affiliateInfo', config.affiliateInfo); } if (!_.isUndefined(config.provider)) { assert.isWeb3Provider('provider', config.provider); } if (!_.isUndefined(config.shouldDisablePushToHistory)) { assert.isBoolean('shouldDisablePushToHistory', config.shouldDisablePushToHistory); } assert.isString('selector', selector); // Render instant and return a callback that allows you to remove it from the DOM. const renderInstant = () => { const appendToIfExists = document.querySelector(selector); assert.assert(!_.isNull(appendToIfExists), `Could not find div with selector: ${selector}`); const appendTo = appendToIfExists as Element; const injectedDiv = document.createElement('div'); injectedDiv.setAttribute('id', INJECTED_DIV_ID); injectedDiv.setAttribute('class', INJECTED_DIV_CLASS); appendTo.appendChild(injectedDiv); const closeInstant = () => { if (!_.isUndefined(config.onClose)) { config.onClose(); } appendTo.removeChild(injectedDiv); }; const instantOverlayProps = { ...config, // If we are using the history API, just go back to close onClose: () => (config.shouldDisablePushToHistory ? closeInstant() : window.history.back()), }; ReactDOM.render(React.createElement(ZeroExInstantOverlay, instantOverlayProps), injectedDiv); return closeInstant; }; if (config.shouldDisablePushToHistory) { renderInstant(); } else { // Before we render, push to history saying that instant is showing for this part of the history. window.history.pushState({ zeroExInstantShowing: true }, '0x Instant'); let removeInstant = renderInstant(); let prevOnPopState = util.boundNoop; if (window.onpopstate) { prevOnPopState = window.onpopstate.bind(window); } window.onpopstate = (e: PopStateEvent) => { // Don't override integrators handler. prevOnPopState(e); // e.state represents the new state if (e.state && e.state.zeroExInstantShowing) { // The user pressed fowards, so re-render instant. removeInstant = renderInstant(); } else { // User pressed back, so close instant. removeInstant(); } }; } };