Skip to content

Instantly share code, notes, and snippets.

@tommymarshall
Last active August 9, 2017 18:17
Show Gist options
  • Save tommymarshall/facbb6152e0a4fba0dab0f396ce89fb4 to your computer and use it in GitHub Desktop.
Save tommymarshall/facbb6152e0a4fba0dab0f396ce89fb4 to your computer and use it in GitHub Desktop.
Simple Modal in React using react-portal-minimal and styled-components
import React from 'react';
import { TextBlock } from '../../text';
import { Modal } from '../';
class Demo extends React.Component {
state = {
open: false
};
handleOpenModel = () => this.setState({ open: !this.state.open });
closeModal = () => this.setState({ open: false });
render() {
return (
<div>
<h1>Modal</h1>
<button onClick={this.handleOpenModel}>Toggle Modal</button>
<Modal isOpen={this.state.open} closeModal={this.closeModal}>
<TextBlock>
This is a dialog. It works like you’d expect.
</TextBlock>
</Modal>
</div>
);
}
}
export default Demo;
import PropTypes from 'prop-types';
import React from 'react';
import Portal from 'react-portal-minimal';
import ModalContent from './ModalContent';
const KEYCODES = {
ESCAPE: 27
};
// eslint-disable-next-line react/prefer-stateless-function
class Modal extends React.Component {
componentDidMount() {
document.addEventListener('keydown', this.handleKeydown.bind(this));
}
componentWillUnmount() {
document.removeEventListener('keydown', this.handleKeydown.bind(this));
}
handleKeydown(e) {
const { isOpen, closeModal } = this.props;
if (e.keyCode === KEYCODES.ESCAPE && isOpen) {
closeModal();
}
}
render() {
const { isOpen, children, closeModal } = this.props;
return (
<Portal>
<ModalContent isOpen={isOpen} closeModal={closeModal}>
{children}
</ModalContent>
</Portal>
);
}
}
Modal.propTypes = {
isOpen: PropTypes.boolean,
closeModal: PropTypes.func,
children: PropTypes.any
};
Modal.defaultProps = {
isOpen: false,
closeModal() {},
children: null
};
export default Modal;
import PropTypes from 'prop-types';
import React from 'react';
import styled from 'styled-components';
import { Icon } from '@m/elements';
/* TODO: Update colors to use vars from the theme */
const StyledModalCover = styled.div`
align-items: center;
background: rgba(255,255,255,0.5);
bottom: 0;
display: flex;
justify-content: center;
left: 0;
opacity: ${({ isOpen }) => isOpen ? 1 : 0};
overflow-y: auto;
position: absolute;
position: fixed;
right: 0;
top: 0;
transition: all 0.1s ease-in-out;
visibility: ${({ isOpen }) => isOpen ? 'visible' : 'hidden'};
`;
const StyledModalContent = styled.div`
background: #fff;
border-radius: 5px;
border: 1px solid #b0c2d0;
box-shadow: 0 0 20px rgba(0,0,0,0.2);
padding: 20px;
position: relative;
`;
const StyledModalButton = styled.button`
background: #fff;
border: none;
position: absolute;
right: 0;
top: 0;
`;
const StyledModalTitle = styled.h1`
font-size: 20px;
`;
const ModalContent = ({ isOpen, title, children, closeModal }) => (
<StyledModalCover isOpen={isOpen}>
<StyledModalContent isOpen={isOpen}>
<StyledModalTitle>
{title}
</StyledModalTitle>
<StyledModalButton onClick={closeModal}>
<Icon name="close"/>
</StyledModalButton>
{children}
</StyledModalContent>
</StyledModalCover>
);
ModalContent.propTypes = {
title: PropTypes.string,
isOpen: PropTypes.bool.isRequired,
children: PropTypes.any,
closeModal: PropTypes.func.isRequired
};
ModalContent.defaultProps = {
title: '',
isOpen: false,
children: null,
closeModal: PropTypes.func.isRequired
};
export default ModalContent;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment