@ustack/uskin
Version:
A graceful framework which provides developers another chance to build an amazing site.
194 lines (170 loc) • 4.35 kB
JSX
import PropTypes from 'prop-types';
import React from 'react';
function noop() {}
class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
className: 'modal',
visible: true
};
this.mask = document.querySelector('.modal-mask');
['onClose', 'hide', 'show', 'keyboardListener'].forEach((func) => {
this[func] = this[func].bind(this);
});
}
onClose() {
const closeParent = this.props.closeParent;
if (this.props.parent) {
this.hide(true);
if (closeParent) {
this.props.parent.onClose();
} else {
this.props.parent.show(true);
}
} else {
this.hide();
}
}
hide(keepMask) {
const that = this;
const props = this.props;
if (!keepMask) {
this.mask.classList.add('modal-mask-leave');
this.mask.classList.add('modal-mask-leave-active');
}
this.setState({
className: 'modal modal-leave modal-leave-active'
}, () => {
setTimeout(function() {
that.setState({
className: 'modal hide'
});
if (!keepMask) {
that.mask.classList.remove('modal-mask-leave');
that.mask.classList.remove('modal-mask-leave-active');
that.mask.classList.add('hide');
}
if ((!keepMask && !props.parent) || (keepMask && props.parent)) {
props.onAfterClose();
}
}, props.animationDuration);
});
}
show(keepMask) {
const that = this;
if (!keepMask) {
that.mask.classList.remove('hide');
this.mask.classList.add('modal-mask-enter');
this.mask.classList.add('modal-mask-enter-active');
}
this.setState({
className: 'modal modal-enter modal-enter-active'
}, () => {
setTimeout(function() {
that.setState({
className: 'modal'
});
if (!keepMask) {
that.mask.classList.remove('modal-mask-enter');
that.mask.classList.remove('modal-mask-enter-active');
}
}, this.props.animationDuration);
});
}
componentWillMount() {
this.setState({
className: 'modal modal-enter'
});
this.props.parent && this.props.parent.hide(true);
}
componentDidMount() {
document.addEventListener('keyup', this.keyboardListener);
if (this.props.parent) {
this.show(true);
} else {
this.show();
}
}
keyboardListener(e) {
if(this.props.nokeyboard) {
return;
}
if(this.state.visible) {
switch(e.code) {
case 'Escape':
this.onCancel();
break;
case 'Enter':
case 'NumpadEnter':
this.onConfirm();
break;
default:
break;
}
}
}
componentWillUnmount() {
document.removeEventListener('keyup', this.keyboardListener);
}
componentWillReceiveProps(nextProps) {
if (nextProps.visible === this.props.visible) {
return;
}
if (nextProps.visible === true) {
this.show();
} else if (this.props.parent) {
const closeParent = nextProps.closeParent;
this.hide(true);
if (closeParent) {
this.props.parent.onClose();
} else {
this.props.parent.show(true);
}
} else {
this.hide();
}
}
onConfirm() {
this.props.onConfirm && this.props.onConfirm();
}
onCancel() {
this.props.onCancel && this.props.onCancel();
}
render() {
const props = this.props;
return (
<div className={this.state.className} style={{width: props.width}}>
{
props.title ?
<div className="modal-hd">
<h6>{props.title}</h6>
<span className="glyphicon icon-close close" onClick={this.onClose}></span>
</div>
: null
}
{props.children}
</div>
);
}
}
Modal.propTypes = {
parent: PropTypes.instanceOf(Modal),
closeParent: PropTypes.bool,
title: PropTypes.string,
width: PropTypes.number,
visible: PropTypes.bool,
children: PropTypes.oneOfType([
PropTypes.element,
PropTypes.arrayOf(PropTypes.element)
]),
animationDuration: PropTypes.number,
onAfterClose: PropTypes.func
};
Modal.defaultProps = {
width: 540,
animationDuration: 200,
visible: true,
onAfterClose: noop
};
export default Modal;