import * as React from "react"; import * as PropTypes from "prop-types"; import styled from "styled-components"; import Provider from "./Provider"; import { SimpleFunction, IProviderCallback } from "../helpers/types"; import { MODAL_LIGHTBOX_CLASSNAME, MODAL_CONTAINER_CLASSNAME, MODAL_HITBOX_CLASSNAME, MODAL_CARD_CLASSNAME } from "../helpers/constants"; declare global { // tslint:disable-next-line interface Window { ethereum: any; web3: any; updateWeb3ConnectModal: any; } } interface ILightboxStyleProps { show: boolean; offset: number; opacity?: number; } const SLightbox = styled.div` transition: opacity 0.1s ease-in-out; text-align: center; position: fixed; width: 100vw; height: 100vh; margin-left: -50vw; top: ${({ offset }) => (offset ? `-${offset}px` : 0)}; left: 50%; z-index: 2; will-change: opacity; background-color: ${({ opacity }) => { let alpha = 0.4; if (typeof opacity === "number") { alpha = opacity; } return `rgba(0, 0, 0, ${alpha})`; }}; opacity: ${({ show }) => (show ? 1 : 0)}; visibility: ${({ show }) => (show ? "visible" : "hidden")}; pointer-events: ${({ show }) => (show ? "auto" : "none")}; display: flex; justify-content: center; align-items: center; & * { box-sizing: border-box !important; } `; interface IModalContainerStyleProps { show: boolean; } const SModalContainer = styled.div` position: relative; width: 100%; height: 100%; padding: 15px; display: flex; align-items: center; justify-content: center; opacity: ${({ show }) => (show ? 1 : 0)}; visibility: ${({ show }) => (show ? "visible" : "hidden")}; pointer-events: ${({ show }) => (show ? "auto" : "none")}; `; const SHitbox = styled.div` position: absolute; top: 0; left: 0; right: 0; bottom: 0; `; interface IModalCardStyleProps { show: boolean; maxWidth?: number; } const SModalCard = styled.div` position: relative; width: 100%; background-color: rgb(255, 255, 255); border-radius: 12px; margin: 10px; padding: 0; opacity: ${({ show }) => (show ? 1 : 0)}; visibility: ${({ show }) => (show ? "visible" : "hidden")}; pointer-events: ${({ show }) => (show ? "auto" : "none")}; display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); max-width: ${({ maxWidth }) => (maxWidth ? `${maxWidth}px` : "800px")}; min-width: fit-content; max-height: 100%; overflow: auto; @media screen and (max-width: 768px) { max-width: ${({ maxWidth }) => (maxWidth ? `${maxWidth}px` : "500px")}; grid-template-columns: 1fr; } `; interface IModalProps { providers: IProviderCallback[]; onClose: SimpleFunction; resetState: SimpleFunction; lightboxOpacity: number; } interface IModalState { show: boolean; lightboxOffset: number; } const INITIAL_STATE: IModalState = { show: false, lightboxOffset: 0 }; class Modal extends React.Component { constructor(props: IModalProps) { super(props); window.updateWeb3ConnectModal = async (state: IModalState) => { this.setState(state); }; } public static propTypes = { providers: PropTypes.object.isRequired, onClose: PropTypes.func.isRequired, resetState: PropTypes.func.isRequired, lightboxOpacity: PropTypes.number.isRequired }; public lightboxRef?: HTMLDivElement | null; public mainModalCard?: HTMLDivElement | null; public state: IModalState = { ...INITIAL_STATE }; public componentDidUpdate(prevProps: IModalProps, prevState: IModalState) { if (prevState.show && !this.state.show) { this.props.resetState(); } if (this.lightboxRef) { const lightboxRect = this.lightboxRef.getBoundingClientRect(); const lightboxOffset = lightboxRect.top > 0 ? lightboxRect.top : 0; if ( lightboxOffset !== INITIAL_STATE.lightboxOffset && lightboxOffset !== this.state.lightboxOffset ) { this.setState({ lightboxOffset }); } } } public render = () => { const { show, lightboxOffset } = this.state; const { onClose, lightboxOpacity, providers } = this.props; return ( (this.lightboxRef = c)} show={show} > (this.mainModalCard = c)} > {providers.map(provider => !!provider ? ( ) : null )} ); }; } export default Modal;