Make modal open state respond to window resize

This commit is contained in:
Kimmo Puputti 2017-08-09 11:06:36 +03:00
parent 6b92f44171
commit a258c65cf7
4 changed files with 46 additions and 32 deletions

View file

@ -14,9 +14,11 @@
import React, { Component, PropTypes } from 'react';
import classNames from 'classnames';
import { Modal } from '../../components';
import { withViewport } from '../../util/contextHelpers';
import css from './ModalInMobile.css';
class ModalInMobile extends Component {
class ModalInMobileComponent extends Component {
constructor(props) {
super(props);
this.state = {
@ -27,28 +29,25 @@ class ModalInMobile extends Component {
}
componentDidMount() {
const { isModalOpenOnMobile, showAsModalMaxWidth } = this.props;
const { isModalOpenOnMobile, showAsModalMaxWidth, viewport } = this.props;
// After Mounting, component can adapt to responsive screen size
const shouldShowAsModal = window.matchMedia
? window.matchMedia(`(max-width: ${showAsModalMaxWidth}px)`).matches
: false;
if (shouldShowAsModal && isModalOpenOnMobile) {
const isMobileLayout = viewport.width <= showAsModalMaxWidth;
if (isMobileLayout && isModalOpenOnMobile) {
this.changeOpenStatus(isModalOpenOnMobile);
}
}
componentWillReceiveProps(nextProps) {
const { isModalOpenOnMobile, showAsModalMaxWidth } = nextProps;
const { isModalOpenOnMobile, showAsModalMaxWidth, viewport } = nextProps;
const isChanging = isModalOpenOnMobile !== this.state.isOpen;
const shouldShowAsModal = window.matchMedia
? window.matchMedia(`(max-width: ${showAsModalMaxWidth}px)`).matches
: false;
const shouldBeClosedAsModal = !shouldShowAsModal && !isModalOpenOnMobile;
const isMobileLayout = viewport.width <= showAsModalMaxWidth;
const shouldBeClosedAsModal = !isMobileLayout && !isModalOpenOnMobile;
// Handle change if status is changing on mobile layout or it is closing (on desktop layout)
if (isChanging && (shouldShowAsModal || shouldBeClosedAsModal)) {
if (isChanging && (isMobileLayout || shouldBeClosedAsModal)) {
this.changeOpenStatus(isModalOpenOnMobile);
}
}
@ -72,13 +71,13 @@ class ModalInMobile extends Component {
id,
showAsModalMaxWidth,
onManageDisableScrolling,
viewport,
} = this.props;
const isMobileLayout = typeof window !== 'undefined' && window.matchMedia
? window.matchMedia(`(max-width: ${showAsModalMaxWidth}px)`).matches
: false;
const isMobileLayout = viewport.width <= showAsModalMaxWidth;
const isOpenInMobile = this.state.isOpen;
const isClosedInMobile = isMobileLayout && !isOpenInMobile;
const isOpen = isOpenInMobile && isMobileLayout;
// We have 3 view states:
// - default desktop layout (just an extra wrapper)
@ -92,7 +91,7 @@ class ModalInMobile extends Component {
className={classes}
contentClassName={css.modalContent}
id={id}
isOpen={isOpenInMobile}
isOpen={isOpen}
isClosedClassName={closedClassName}
onClose={this.handleClose}
onManageDisableScrolling={onManageDisableScrolling}
@ -103,16 +102,16 @@ class ModalInMobile extends Component {
}
}
ModalInMobile.defaultProps = {
ModalInMobileComponent.defaultProps = {
children: null,
className: '',
onClose: null,
showAsModalMaxWidth: 0,
};
const { bool, func, node, number, string } = PropTypes;
const { bool, func, node, number, string, shape } = PropTypes;
ModalInMobile.propTypes = {
ModalInMobileComponent.propTypes = {
children: node,
className: string,
id: string.isRequired,
@ -121,6 +120,14 @@ ModalInMobile.propTypes = {
showAsModalMaxWidth: number,
// eslint-disable-next-line react/no-unused-prop-types
onManageDisableScrolling: func.isRequired,
// from withViewport
viewport: shape({
width: number.isRequired,
height: number.isRequired,
}).isRequired,
};
const ModalInMobile = withViewport(ModalInMobileComponent);
export default ModalInMobile;

View file

@ -5,7 +5,7 @@ import { pickBy } from 'lodash';
import classNames from 'classnames';
import { Button, Modal, NamedLink, TopbarDesktop, TopbarMobileMenu } from '../../components';
import { TopbarSearchForm } from '../../containers';
import { withFlattenedRoutes } from '../../util/contextHelpers';
import { withFlattenedRoutes, withViewport } from '../../util/contextHelpers';
import { parse, stringify } from '../../util/urlHelpers';
import { ensureUser } from '../../util/data';
import { createResourceLocatorString, pathByRouteName } from '../../util/routes';
@ -16,6 +16,8 @@ import LogoIcon from './LogoIcon';
import SearchIcon from './SearchIcon';
import css from './Topbar.css';
const maxMobileScreenWidth = 768;
const redirectToURLWithModalState = (props, modalStateParam) => {
const { history, location } = props;
const { pathname, search, state } = location;
@ -89,6 +91,7 @@ class TopbarComponent extends Component {
currentUser,
currentUserHasListings,
notificationCount,
viewport,
intl,
location,
onManageDisableScrolling,
@ -103,8 +106,10 @@ class TopbarComponent extends Component {
const notificationDot = notificationCount > 0 ? <div className={css.notificationDot} /> : null;
const isMobileMenuOpen = mobilemenu === 'open';
const isMobileSearchOpen = mobilesearch === 'open';
const isMobileLayout = viewport.width < maxMobileScreenWidth;
const isMobileMenuOpen = isMobileLayout && mobilemenu === 'open';
const isMobileSearchOpen = isMobileLayout && mobilesearch === 'open';
const mobileMenu = (
<TopbarMobileMenu
isAuthenticated={isAuthenticated}
@ -223,6 +228,12 @@ TopbarComponent.propTypes = {
search: string.isRequired,
}).isRequired,
// from withViewport
viewport: shape({
width: number.isRequired,
height: number.isRequired,
}).isRequired,
// from withFlattenedRoutes
flattenedRoutes: arrayOf(propTypes.route).isRequired,
@ -230,7 +241,7 @@ TopbarComponent.propTypes = {
intl: intlShape.isRequired,
};
const Topbar = compose(withFlattenedRoutes, injectIntl)(TopbarComponent);
const Topbar = compose(withViewport, withFlattenedRoutes, injectIntl)(TopbarComponent);
Topbar.displayName = 'Topbar';

View file

@ -130,8 +130,7 @@ exports[`ListingPage matches snapshot 1`] = `
</div>
</div>
</div>
<ModalInMobile
className=""
<withViewport(ModalInMobileComponent)
id="BookingDatesFormInModal"
isModalOpenOnMobile={false}
onClose={[Function]}
@ -177,7 +176,7 @@ exports[`ListingPage matches snapshot 1`] = `
"currency": "USD",
}
} />
</ModalInMobile>
</withViewport(ModalInMobileComponent)>
<div>
<div>
<div

View file

@ -62,18 +62,15 @@ exports[`SearchPageComponent matches snapshot 1`] = `
search={Object {}} />
</div>
</div>
<ModalInMobile
className=""
<withViewport(ModalInMobileComponent)
id="SearchPage.map"
isModalOpenOnMobile={false}
onClose={null}
onManageDisableScrolling={[Function]}
showAsModalMaxWidth={0}>
onManageDisableScrolling={[Function]}>
<div>
<InjectIntl(SearchMapComponent)
listings={Array []} />
</div>
</ModalInMobile>
</withViewport(ModalInMobileComponent)>
</div>
</withRouter(PageLayout)>
`;