Skip to content

Instantly share code, notes, and snippets.

@blvdmitry
Last active December 26, 2017 13:10
Show Gist options
  • Save blvdmitry/dbf558b016e384632d2af32482ffac84 to your computer and use it in GitHub Desktop.
Save blvdmitry/dbf558b016e384632d2af32482ffac84 to your computer and use it in GitHub Desktop.
tooltip
// @flow
import * as React from 'react';
import { connect } from 'react-redux';
import { Gateway } from 'react-gateway';
import get from 'lodash/get';
import cssVars from 'sj/css/variables/animations.scss';
import { hideModal, hideModalWithoutNavigation, showModal, addModal, removeModal } from 'sj/actions/modalActions';
import { MODAL_QUERY_PARAM, MODAL_GATEWAY_NAME } from 'sj/constants/modals';
import ModalManagerHolder from '../ModalManagerHolder/ModalManagerHolder';
type OwnProps = {
children?: ReactElementType,
id: string,
modalKey?: number | string,
onClose?: Function,
withUrl?: boolean,
disableOutsideClick?: boolean,
}
type Props = OwnProps & {
dispatch: Dispatch,
stateKey: string,
shown: boolean,
isModalRoute: boolean,
};
export type ModalManagerPortalPropsType = OwnProps;
type State = {
unmountLocked: boolean,
};
const UNMOUNT_TIMEOUT = parseInt(cssVars.modalsAnimationTime, 10);
class ModalManagerPortal extends React.PureComponent<Props, State> {
state = {
unmountLocked: false,
};
rendered;
componentDidMount() {
const { dispatch, isModalRoute, id, modalKey, withUrl } = this.props;
const payload = { id, modalKey, withUrl };
this.rendered = true;
dispatch(addModal(payload));
if (isModalRoute) {
dispatch(showModal({ ...payload, isInitial: true }));
}
}
componentWillUnmount() {
const { dispatch, id, modalKey } = this.props;
const payload = { id, modalKey };
this.rendered = false;
dispatch(removeModal(payload));
}
componentWillReceiveProps(nextProps) {
const { shown } = this.props;
// Оставляем модалку в доме на время анимации закрытия
if ((nextProps.shown !== shown) && !nextProps.shown) {
this.setState({ unmountLocked: true });
setTimeout(() => {
if (this.rendered) this.setState({ unmountLocked: false });
}, UNMOUNT_TIMEOUT);
}
}
handleClickOutside = () => {
const { dispatch, onClose, disableOutsideClick } = this.props;
if (disableOutsideClick) return;
dispatch(hideModal());
if (onClose) {
onClose();
}
};
handleBack = () => {
const { dispatch, onClose } = this.props;
dispatch(hideModalWithoutNavigation());
if (onClose) {
onClose();
}
};
render() {
const { shown } = this.props;
const { unmountLocked } = this.state;
if (!shown && !unmountLocked) {
return null;
}
const { id, data, stateKey, children } = this.props;
const childrenWithProps = React.Children.map(children, (child) => {
return React.cloneElement(child, { ...data, id });
});
return (
<Gateway into={MODAL_GATEWAY_NAME}>
<ModalManagerHolder
stateKey={stateKey}
onClickOutside={this.handleClickOutside}
onBack={this.handleBack}
>
{ childrenWithProps }
</ModalManagerHolder>
</Gateway>
);
}
}
const mapStateToProps = ({ modals, currentRoute }, { id, modalKey }: OwnProps) => {
// Во доме сидят такие куча порталов и ждут, огда они в stack окажутся последними
// Да так, чтобы роут еще с нужным параметром был
const { routeParams } = currentRoute;
const modalRouteKey = routeParams[MODAL_QUERY_PARAM];
const stack = get(modals, 'stack', []);
const data = get(modals, 'data', {});
const stateKey = modalKey ? `${id}:${modalKey}` : id;
const shown = stack[stack.length - 1] === stateKey;
const isModalRoute = stateKey === modalRouteKey;
return { stateKey, data, shown, isModalRoute };
};
export default connect(mapStateToProps)(ModalManagerPortal);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment