Last active
December 26, 2017 02:40
-
-
Save vagusX/56a71ebff8aaa0428efcbf9ad2d11029 to your computer and use it in GitHub Desktop.
write a modal in react 15
This file contains hidden or 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 * as React from 'react' | |
import Overlay from './Overlay' | |
const styles = require('./styles.scss') | |
const Modal = props => { | |
const { show, onCancel, children } = props | |
return ( | |
<Overlay show={show} onCancel={onCancel}> | |
<div className={styles.content} onClick={e => e.stopPropagation()}> | |
{ React.cloneElement(children, {onCancel}) } | |
</div> | |
</Overlay> | |
) | |
} | |
export default Modal |
This file contains hidden or 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 * as React from 'react' | |
import * as ReactDOM from 'react-dom' | |
import { CSSTransitionGroup } from 'react-transition-group' | |
import * as PropTypes from 'prop-types' | |
const styles = require('./styles.scss') | |
interface Props { | |
show: boolean, | |
onCancel: Function, | |
closable?: boolean, | |
hasMask?: boolean | |
} | |
export default class Overlay extends React.PureComponent<Props, {}> { | |
static defaultProps = { | |
closable: true, | |
hasMask: true, | |
} | |
static propTypes = { | |
show: PropTypes.bool, | |
onCancel: PropTypes.func, | |
closable: PropTypes.bool, | |
hasMask: PropTypes.bool, | |
} | |
container?: HTMLElement | |
componentDidMount() { | |
this.getContainer() | |
this.renderIntoContainer(this.props) | |
} | |
componentWillReceiveProps(newProps) { | |
this.renderIntoContainer(newProps) | |
} | |
componentDidUpdate(prevProps) { | |
if (this.props.closable) { | |
// add event listener to close side panel | |
// use `touchstart` instead of `mousedown` | |
if (this.props.show) { | |
window.addEventListener('touchstart', this.handleClose, false) | |
} | |
if (!this.props.show) { | |
window.removeEventListener('touchstart', this.handleClose, false) | |
} | |
} else { | |
window.removeEventListener('touchstart', this.handleClose, false) | |
} | |
} | |
componentWillUnmount() { | |
this.removeContainer() | |
} | |
renderContent = props => { | |
const { show, onCancel, children, hasMask } = props | |
return ( | |
<div> | |
{ | |
hasMask | |
? <div className={styles.mask} data-disabled={!show} onClick={onCancel}></div> | |
: null | |
} | |
<CSSTransitionGroup | |
transitionName="flip" | |
transitionEnterTimeout={500} | |
transitionLeaveTimeout={300}> | |
{show && children} | |
</CSSTransitionGroup> | |
</div> | |
) | |
} | |
render() { | |
return null | |
} | |
renderIntoContainer = props => { | |
ReactDOM.unstable_renderSubtreeIntoContainer(this, this.renderContent(props), this.container) | |
} | |
handleClose = e => { | |
// close modal when click outside | |
if (e && this.container && this.container.contains(e.target)) return | |
this.props.show && this.props.onCancel() | |
} | |
getContainer() { | |
if (!this.container) { | |
this.container = document.createElement('div') | |
this.container.className = 'overlay' | |
document.body.appendChild(this.container) | |
} | |
return this.container | |
} | |
removeContainer() { | |
ReactDOM.unmountComponentAtNode(this.getContainer()) | |
document.body.removeChild(this.container) | |
this.container = null | |
} | |
} |
This file contains hidden or 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 "../../shared/styles/variables.scss"; | |
.mask { | |
position: fixed; | |
left: 0; | |
right: 0; | |
top: 0; | |
bottom: 0; | |
overflow: hidden; | |
background-color: rgba(#000, .3); | |
-webkit-overflow-scrolling: touch; | |
outline: 0; | |
box-shadow: -3px 0 3px rgba(0,0,0,.1); | |
z-index: 1000; | |
&[data-disabled] { | |
display: none; | |
} | |
} | |
.content { | |
position: fixed; | |
left: 0; | |
bottom: 0; | |
background-color: #fff; | |
width: 100%; | |
z-index: 1000; | |
} | |
:global { | |
// effect slide from Right | |
.flip-enter { | |
transform: translate3d(0, 100%, 0); | |
} | |
.flip-enter-active { | |
transform: none; | |
transition: transform 200ms ease; | |
} | |
.flip-leave { | |
transform: none; | |
} | |
.flip-leave-active { | |
transform: translate3d(0, 100%, 0); | |
transition: transform 200ms ease; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment