wallet-connect-web-examples/dapps/react-dapp-v2/src/components/Modal.tsx

182 lines
4.0 KiB
TypeScript
Raw Normal View History

import * as React from "react";
import * as PropTypes from "prop-types";
import styled from "styled-components";
import { colors, transitions } from "../styles";
interface LightboxStyleProps {
show: boolean;
offset: number;
opacity?: number;
}
const SLightbox = styled.div<LightboxStyleProps>`
transition: opacity 0.1s ease-in-out;
text-align: center;
position: absolute;
width: 100vw;
height: 100%;
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;
`;
const SModalContainer = styled.div`
position: relative;
width: 100%;
height: 100%;
padding: 15px;
display: flex;
align-items: center;
justify-content: center;
`;
const SHitbox = styled.div`
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
`;
interface CloseButtonStyleProps {
size: number;
color: string;
onClick?: any;
}
const SCloseButton = styled.div<CloseButtonStyleProps>`
transition: ${transitions.short};
position: absolute;
width: ${({ size }) => `${size}px`};
height: ${({ size }) => `${size}px`};
right: ${({ size }) => `${size / 1.6667}px`};
top: ${({ size }) => `${size / 1.6667}px`};
opacity: 0.5;
cursor: pointer;
&:hover {
opacity: 1;
}
&:before,
&:after {
position: absolute;
content: " ";
height: ${({ size }) => `${size}px`};
width: 2px;
background: ${({ color }) => `rgb(${colors[color]})`};
}
&:before {
transform: rotate(45deg);
}
&:after {
transform: rotate(-45deg);
}
`;
const SCard = styled.div`
position: relative;
width: 100%;
max-width: 500px;
padding: 25px;
background-color: rgb(${colors.white});
border-radius: 6px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;
const SModalContent = styled.div`
position: relative;
width: 100%;
position: relative;
word-wrap: break-word;
`;
interface ModalState {
offset: number;
}
interface ModalProps {
children: React.ReactNode;
show: boolean;
closeModal: any;
opacity?: number;
}
const INITIAL_STATE: ModalState = {
offset: 0,
};
class Modal extends React.Component<ModalProps, ModalState> {
public static propTypes = {
children: PropTypes.node.isRequired,
show: PropTypes.bool.isRequired,
closeModal: PropTypes.func.isRequired,
opacity: PropTypes.number,
};
public lightbox?: HTMLDivElement | null;
public state: ModalState = {
...INITIAL_STATE,
};
public componentDidUpdate() {
if (this.lightbox) {
const lightboxRect = this.lightbox.getBoundingClientRect();
const offset = lightboxRect.top > 0 ? lightboxRect.top : 0;
if (offset !== INITIAL_STATE.offset && offset !== this.state.offset) {
this.setState({ offset });
}
}
}
public closeModal = async () => {
const d = typeof window !== "undefined" ? document : "";
const body = d ? d.body || d.getElementsByTagName("body")[0] : "";
if (body) {
if (this.props.show) {
body.style.position = "";
} else {
body.style.position = "fixed";
}
}
this.props.closeModal();
};
public render() {
const { offset } = this.state;
const { children, show, opacity } = this.props;
return (
2022-02-02 16:11:22 +00:00
<SLightbox show={show} offset={offset} opacity={opacity} ref={c => (this.lightbox = c)}>
<SModalContainer>
<SHitbox onClick={this.closeModal} />
<SCard>
<SCloseButton size={25} color={"dark"} onClick={this.closeModal} />
<SModalContent>{children}</SModalContent>
</SCard>
</SModalContainer>
</SLightbox>
);
}
}
export default Modal;