-
Notifications
You must be signed in to change notification settings - Fork 171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to use "closeOnOutsideClick" with full screen overlay? #2
Comments
@moroshko Yes, I also have modals with fullscreen overlay. In that case, you can't use So this is how it looks: <Portal closeOnEsc={true} openByClickOn={triggerButton}>
<Modal title="Modal title">
Modal content
</Modal>
</Portal> import React, {findDOMNode} from 'react';
export default class Modal extends React.Component {
constructor() {
super();
this.handleMouseClickOutside = this.handleMouseClickOutside.bind(this);
}
componentDidMount() {
document.addEventListener('mousedown', this.handleMouseClickOutside);
}
componentWillUnmount() {
document.removeEventListener('mousedown', this.handleMouseClickOutside);
}
render() {
return (
<div>
<div className="modal-overlay" />
<div className="modal" ref="content">
<h1>{this.props.title}</h1>
{React.cloneElement(this.props.children, {closePortal: this.props.closePortal})}
</div>
</div>
);
}
handleMouseClickOutside(e) {
if (isNodeInRoot(e.target, findDOMNode(this.refs.content))) {
return;
}
e.stopPropagation();
this.props.closePortal();
}
}
Modal.propTypes = {
title: React.PropTypes.string.isRequired,
closePortal: React.PropTypes.func,
children: React.PropTypes.element.isRequired
};
function isNodeInRoot(node, root) {
while (node) {
if (node === root) {
return true;
}
node = node.parentNode;
}
return false;
} It's good to have a general modal component (so you don't have to replicate the outside click logic anymore). I am React cloning the modal's children for the case, when the children is an another React component that needs to have access to the portal's closePortal() function. If you don't need that, you can just simply replace it with (I didn't run the code above, so sorry for possible typos.). |
@tajo Thanks for your detailed answer and code example. Now all works as expected :) |
You can if you add |
@RobinMalfait it will invoke a hover events for all the elements below the overlay layer. @tajo example works good. 👍 |
@tajo Could we include this as a portal feature? A lot of people will probably replicate this behaviour.
|
@AoDev Can you please send a PR? I am not sure how to integrate it. |
@tajo Sure. I'll start and we can discuss on the PR what is best. For example, in my project I have a hard coded value for the overlay styles but this is not what we want here. |
But one thing I wonder is that why you make it so "complicated" here. Maybe I am doing something wrong so let me know but, this is only what I need to do in my modal class: var overlayStyles = {
position: 'fixed',
top: 0,
right: 0,
bottom: 0,
left: 0,
background: 'rgba(0,0,0,0.4)',
zIndex: 1031 // because of bootstrap
}; The modal class with outsideclick: class Modal extends React.Component {
constructor() {
super();
this.closeMe = this.closeMe.bind(this);
}
render() {
var overlay;
var modal;
var {
...
onBody,
withOverlay,
// note: you could pass props that mimics Portal options like closeOnOutsideClick
} = this.props;
...
overlay = withOverlay ? <div style={overlayStyles} onClick={this.closeMe}/> : '';
modal =
<div className="my-modal">
{this.props.children}
</div>;
if (onBody) {
modal =
<Portal isOpened closeOnEsc ref="portal">
<div>
{overlay}
{modal}
</div>
</Portal>;
}
return modal;
}
closeMe() {
this.refs['portal'].closePortal();
}
}
Modal.propTypes = {
children: React.PropTypes.element
};
export default Modal; The idea is to get a ref from the portal and call the closePortal method. |
Looks good (I assume it works). Still, it's just a slightly different implementation, isn't? In other words, is there anything that needs to be changed in Portal to support this (support this better)? I agree that Modal is common use-case of Portal, but it's imo out of scope this lib. On the other hand, there could be (should be) another Modal lib using Portal. |
Another way, which don't require you to create a new component <Portal closeOnEsc onClose={this.handleCloseVideo} isOpened={isOpen}>
<div className={styles.videoPortal} onClick={(e) => this.handleCloseVideo()} >
<div className={styles.videoContainer} onClick={e => e.stopPropagation()}>
<VideoPlayer provider={videoSource.provider} providerId={videoSource.providerUid} />
</div>
</div>
</Portal> By doing this, you register the click event on the overlay, and register a click-event on the modal content. In this case the content is inside the portal-container. The click event-event on the content prevents propagation, so the parent onClick-event is not called. |
@tajo I'd like to have
closeOnOutsideClick={true}
with a modal that has a full screen overlay.The problem is that I cannot really click outside the full screen overlay, thus the expected "click outside the dialog to close it" behaviour doesn't work.
Is there a way to have a full screen overlay with a dialog on top, and close the dialog once the overlay is clicked (outside the dialog)?
Here is my attempt:
The text was updated successfully, but these errors were encountered: