5abb3d8150
Render function for BundleContainer must not be methods. React doesn't know dependency of the method, so they won't rerender on property updates. In this case, when you close modal and open another modal immediately, old modal will be open instead of new one.
104 lines
2.8 KiB
JavaScript
104 lines
2.8 KiB
JavaScript
import React from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import TransitionMotion from 'react-motion/lib/TransitionMotion';
|
|
import spring from 'react-motion/lib/spring';
|
|
import BundleContainer from '../containers/bundle_container';
|
|
import BundleModalError from './bundle_modal_error';
|
|
import ModalLoading from './modal_loading';
|
|
import {
|
|
MediaModal,
|
|
OnboardingModal,
|
|
VideoModal,
|
|
BoostModal,
|
|
ConfirmationModal,
|
|
ReportModal,
|
|
} from '../../../features/ui/util/async-components';
|
|
|
|
const MODAL_COMPONENTS = {
|
|
'MEDIA': MediaModal,
|
|
'ONBOARDING': OnboardingModal,
|
|
'VIDEO': VideoModal,
|
|
'BOOST': BoostModal,
|
|
'CONFIRM': ConfirmationModal,
|
|
'REPORT': ReportModal,
|
|
};
|
|
|
|
export default class ModalRoot extends React.PureComponent {
|
|
|
|
static propTypes = {
|
|
type: PropTypes.string,
|
|
props: PropTypes.object,
|
|
onClose: PropTypes.func.isRequired,
|
|
};
|
|
|
|
handleKeyUp = (e) => {
|
|
if ((e.key === 'Escape' || e.key === 'Esc' || e.keyCode === 27)
|
|
&& !!this.props.type) {
|
|
this.props.onClose();
|
|
}
|
|
}
|
|
|
|
componentDidMount () {
|
|
window.addEventListener('keyup', this.handleKeyUp, false);
|
|
}
|
|
|
|
componentWillUnmount () {
|
|
window.removeEventListener('keyup', this.handleKeyUp);
|
|
}
|
|
|
|
willEnter () {
|
|
return { opacity: 0, scale: 0.98 };
|
|
}
|
|
|
|
willLeave () {
|
|
return { opacity: spring(0), scale: spring(0.98) };
|
|
}
|
|
|
|
renderLoading = () => {
|
|
return <ModalLoading />;
|
|
}
|
|
|
|
renderError = (props) => {
|
|
const { onClose } = this.props;
|
|
|
|
return <BundleModalError {...props} onClose={onClose} />;
|
|
}
|
|
|
|
render () {
|
|
const { type, props, onClose } = this.props;
|
|
const visible = !!type;
|
|
const items = [];
|
|
|
|
if (visible) {
|
|
items.push({
|
|
key: type,
|
|
data: { type, props },
|
|
style: { opacity: spring(1), scale: spring(1, { stiffness: 120, damping: 14 }) },
|
|
});
|
|
}
|
|
|
|
return (
|
|
<TransitionMotion
|
|
styles={items}
|
|
willEnter={this.willEnter}
|
|
willLeave={this.willLeave}
|
|
>
|
|
{interpolatedStyles =>
|
|
<div className='modal-root'>
|
|
{interpolatedStyles.map(({ key, data: { type }, style }) => (
|
|
<div key={key} style={{ pointerEvents: visible ? 'auto' : 'none' }}>
|
|
<div role='presentation' className='modal-root__overlay' style={{ opacity: style.opacity }} onClick={onClose} />
|
|
<div className='modal-root__container' style={{ opacity: style.opacity, transform: `translateZ(0px) scale(${style.scale})` }}>
|
|
<BundleContainer fetchComponent={MODAL_COMPONENTS[type]} loading={this.renderLoading} error={this.renderError} renderDelay={200}>
|
|
{(SpecificComponent) => <SpecificComponent {...props} onClose={onClose} />}
|
|
</BundleContainer>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
}
|
|
</TransitionMotion>
|
|
);
|
|
}
|
|
|
|
}
|