/** * @file Modal * @description * @author fex */ import React from 'react'; import Transition, { ENTERED, ENTERING, EXITING } from 'react-transition-group/Transition'; import {Portal} from 'react-overlays'; import {current, addModal, removeModal} from './ModalManager'; import {ClassNamesFn, themeable, ThemeProps} from '../theme'; import {Icon} from './icons'; import {LocaleProps, localeable} from '../locale'; import {getScrollbarWidth} from '../utils/helper'; export interface ModalProps extends ThemeProps, LocaleProps { className?: string; contentClassName?: string; size?: any; overlay?: boolean; onHide: (e: any) => void; closeOnEsc?: boolean; container?: any; show?: boolean; disabled?: boolean; onExited?: () => void; onEntered?: () => void; } export interface ModalState {} const fadeStyles: { [propName: string]: string; } = { [ENTERING]: 'in', [ENTERED]: 'in', [EXITING]: 'out' }; export class Modal extends React.Component { static defaultProps = { container: document.body, size: '', overlay: true }; static Header = themeable( localeable( ({ classnames: cx, className, showCloseButton, onClose, children, classPrefix, translate: __, ...rest }: ThemeProps & LocaleProps & { className?: string; showCloseButton?: boolean; onClose?: () => void; children?: React.ReactNode; } & React.HTMLAttributes) => (
{showCloseButton !== false ? ( ) : null} {children}
) ) ); static Title = themeable( ({ classnames: cx, className, children, classPrefix, ...rest }: ThemeProps & { className?: string; children?: React.ReactNode; } & React.HTMLAttributes) => (
{children}
) ); static Body = themeable( ({ classnames: cx, className, children, classPrefix, ...rest }: ThemeProps & { className?: string; children?: React.ReactNode; } & React.HTMLAttributes) => (
{children}
) ); static Footer = themeable( ({ classnames: cx, className, children, classPrefix, ...rest }: ThemeProps & { className?: string; children?: React.ReactNode; } & React.HTMLAttributes) => (
{children}
) ); componentDidMount() { if (this.props.show) { this.handleEnter(); this.handleEntered(); } } componentWillUnmount() { if (this.props.show) { this.handleExited(); } } handleEnter = () => { document.body.classList.add(`is-modalOpened`); if ( window.innerWidth - document.documentElement.clientWidth > 0 || document.body.scrollHeight > document.body.clientHeight ) { const scrollbarWidth = getScrollbarWidth(); document.body.style.width = `calc(100% - ${scrollbarWidth}px)`; } }; handleEntered = () => { const onEntered = this.props.onEntered; onEntered && onEntered(); }; handleExited = () => { const onExited = this.props.onExited; onExited && onExited(); setTimeout(() => { if (!document.querySelector('.amis-dialog-widget')) { document.body.classList.remove(`is-modalOpened`); document.body.style.width = ''; } }, 200); }; modalRef = (ref: any) => { const {classPrefix: ns} = this.props; if (ref) { addModal(this); (ref as HTMLElement).classList.add(`${ns}Modal--${current()}th`); } else { removeModal(); } }; render() { const { className, contentClassName, children, container, show, size, overlay, classnames: cx } = this.props; return ( {(status: string) => (
{overlay ? (
) : null}
{children}
)} ); } } const FinalModal = themeable(localeable(Modal)); export default FinalModal as typeof FinalModal & { Header: typeof Modal.Header; Title: typeof Modal.Title; Body: typeof Modal.Body; Footer: typeof Modal.Footer; };