element-react-codish
Version:
Element UI for React
146 lines (125 loc) • 4.11 kB
JSX
/* @flow */
import React from 'react';
import { Component, View, PropTypes } from '../../libs';
type State = {
bodyOverflow: string,
}
export default class Dialog extends Component {
state: State;
static defaultProps = {
visible: false,
title: '',
size: 'small',
top: '15%',
modal: true,
lockScroll: true,
closeOnClickModal: true,
closeOnPressEscape: true
}
constructor(props: Object) {
super(props);
this.state = {
bodyOverflow: ''
}
}
componentWillReceiveProps(nextProps: Object): void {
if (this.willOpen(this.props, nextProps)){
if (this.props.lockScroll && document.body && document.body.style) {
if (!this.state.bodyOverflow) {
this.setState({
bodyOverflow: document.body.style.overflow
});
}
document.body.style.overflow = 'hidden';
}
}
if (this.willClose(this.props, nextProps) && this.props.lockScroll) {
if (this.props.modal && this.state.bodyOverflow !== 'hidden' && document.body && document.body.style) {
document.body.style.overflow = this.state.bodyOverflow;
}
}
}
componentDidUpdate(prevProps: Object): void {
if (this.willOpen(prevProps, this.props)){
this.refs.wrap.focus();
}
}
componentWillUnmount(): void {
if (document.body && document.body.style) document.body.style.removeProperty('overflow');
}
onKeyDown(e: SyntheticKeyboardEvent): void {
if (this.props.closeOnPressEscape && e.keyCode === 27) {
this.close(e);
}
}
handleWrapperClick(e: SyntheticEvent): void {
if (e.target instanceof HTMLDivElement) {
if (this.props.closeOnClickModal && e.target === e.currentTarget) {
this.close(e);
}
}
}
close(e: SyntheticEvent | SyntheticKeyboardEvent): void {
this.props.onCancel(e);
}
willOpen(prevProps: Object, nextProps: Object): boolean {
return (!prevProps.visible && nextProps.visible);
}
willClose(prevProps: Object, nextProps: Object): boolean {
return (prevProps.visible && !nextProps.visible);
}
render(): React.Element<any> {
const { visible, title, size, top, modal, customClass } = this.props;
return (
<View show={ visible }>
<div
style={{ zIndex: 1013 }}
className={this.classNames('el-dialog__wrapper')}
onClick={ e => this.handleWrapperClick(e) }
ref="wrap"
tabIndex={ -1 }
onKeyDown={ e => this.onKeyDown(e) }
>
<div
ref="dialog"
style={this.style(size === 'full' ? {} : { 'marginBottom': '50px', 'top': top })}
className={ this.className("el-dialog", `el-dialog--${ size }`, customClass) }
>
<div className="el-dialog__header">
<span className="el-dialog__title">{ title }</span>
<div className="el-dialog__headerbtn">
<i className="el-dialog__close el-icon el-icon-close" onClick={ e => this.close(e) }></i>
</div>
</div>
{ this.props.children }
</div>
</div>
<View show={ modal } transition="v-modal" transitionKey="dialog-v-modal">
<div className="v-modal" style={{ zIndex: 1012 }}></div>
</View>
</View>
);
}
}
Dialog.propTypes = {
// 控制对话框是否可见
visible: PropTypes.bool.isRequired,
// 标题
title: PropTypes.string,
// 大小 (tiny/small/large/full)
size: PropTypes.string,
// top 值(仅在 size 不为 full 时有效)
top: PropTypes.string,
// 控制遮罩层展示
modal: PropTypes.bool,
// Dialog 的自定义类名
customClass: PropTypes.string,
// 是否在 Dialog 出现时将 body 滚动锁定
lockScroll: PropTypes.bool,
// 是否可以通过点击 modal 关闭 Dialog
closeOnClickModal: PropTypes.bool,
// 是否可以通过按下 ESC 关闭 Dialog
closeOnPressEscape: PropTypes.bool,
// 点击遮罩层或右上角叉或取消按钮的回调
onCancel: PropTypes.func.isRequired
};