Last active
August 9, 2017 18:17
-
-
Save tommymarshall/facbb6152e0a4fba0dab0f396ce89fb4 to your computer and use it in GitHub Desktop.
Simple Modal in React using react-portal-minimal and styled-components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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