Skip to content
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

Update Portal #208

Merged
merged 5 commits into from
Oct 14, 2017
Merged

Update Portal #208

merged 5 commits into from
Oct 14, 2017

Conversation

jquense
Copy link
Member

@jquense jquense commented Sep 27, 2017

Our tests are SO FLAKEY.

@jochenberger sorry i was working off your PR but needed to see what was required with just the new API. I think we can still switch between LegacyPortal and Portal for back compat.

I don't love how this turned out I had to add a callback to Portal because it takes two render cycles to get something rendered in order to fire the focus() callback

@jquense jquense requested a review from taion September 27, 2017 17:24
@jochenberger
Copy link
Contributor

Yeah, no worries, I just wanted to make some progress on the issue.

@@ -44,7 +44,7 @@
"react-dom": "^0.14.9 || >=15.3.0"
},
"devDependencies": {
"@monastic.panic/component-playground": "^2.0.0",
"@monastic.panic/component-playground": "^3.2.2",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to do that upgrade in a separate PR? Would be easier to review IMO.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated this to verify stuff was working apart from the tests which are flaky for me. I think it should be ok


render(
<Modal show>
<div className='modal'>
<div className='modal'>q
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

using vi? ;-)

@@ -11,6 +11,16 @@ import { render, shouldWarn } from './helpers';

const $ = componentOrNode => jQuery(ReactDOM.findDOMNode(componentOrNode));


class ErrorBoundary extends React.Component {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this related to the React.Children.only test failures (#207)? If so, a separate PR might be a good idea.

@@ -20,7 +20,7 @@ describe('Position', function () {
assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'SPAN');
});

it('Should warn about several children', function () {
xit('Should warn about several children', function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't that be it again?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ping?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is failing because of the other issues trying to be fixed in #207

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a FIXME

it('Should throw with multiple children', function () {
expect(function(){
render(
xit('Should throw with multiple children', function () {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't that be it again?

@@ -353,8 +371,7 @@ describe('Modal', function () {
});

it('Should focus on the Modal when it is opened', function () {

document.activeElement.should.equal(focusableContainer);
expect(document.activeElement).to.equal(focusableContainer);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does that make a difference?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems to locally. I'm not at all sure why

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be flakiness with the prototype manipulation stuff

render(
<ErrorBoundary
onError={err => {
console.log('hiii')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may want to remove this.

@@ -11,6 +11,16 @@ import { render, shouldWarn } from './helpers';

const $ = componentOrNode => jQuery(ReactDOM.findDOMNode(componentOrNode));


class ErrorBoundary extends React.Component {
componentDidCatch(error, info) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want to upgrade the React dev-dependencies to 16? Otherwise you want want to add support for unstable_handleError.

Copy link
Member

@taion taion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry for the delay

@@ -472,7 +475,7 @@ class Modal extends React.Component {
let autoFocus = this.props.autoFocus;
let modalContent = this.getDialogElement();
let current = activeElement(ownerDocument(this));
let focusInModal = current && contains(modalContent, current);
let focusInModal = modalContent && current && contains(modalContent, current);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see react-bootstrap/react-bootstrap#2726 (comment)

i think especially w/react 16 this might be a little flaky, since modalContent might not be the actual modal content... or at least not all of it

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure I understand that, don't we control this DOM node?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No – it's supposed to be the DOM node corresponding to children, but the actual node could be e.g. a comment or something per the linked React-Bootstrap issue if e.g. children don't end up rendering anything. Perhaps it could be something even weirder with React 16 – like a text node or something.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure how to deal with this without supplying our own wrapping div, children should render a single element

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'd make a <RefHolder> component, attach a ref to it, then findDOMNode it... but this isn't really a regression or anything, so i guess this is fine for now

}

export default Portal;
export default ReactDOM.createPortal ? Portal : LegacyPortal;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

neat

src/Portal.js Outdated
@@ -5,7 +5,7 @@ import ReactDOM from 'react-dom';

import getContainer from './utils/getContainer';
import ownerDocument from './utils/ownerDocument';

import LegacyPortal from './LegacyPortal'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newline after this

this._overlayInstance = null;
}
setContainer = (props = this.props) => {
this._portalContainerNode = getContainer(props.container, ownerDocument(this).body);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not just use setState here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we handle setting this in the ctor in cases where it is defined there (for whatever reason?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, is there any meaningful impact to no longer creating a <div> here? what if the container does end up being document?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think i understood what the div was doing in the old code, the container exists somewhere why were we then appending it to a different parent?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like an earlier path but it takes some reworking. right now we do findDOMNode on the result of the function or the value, and we can't reasonable know when to not do that, or when it will error. I think we need to change the API to provide a DOM node specifically vs a component instance. e.g. () => findDOMNode(this), i think we do that for target in Position so it's probably a good idea anyway

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@taion there are too many issues with doing a fast path. For instance, we default container to the owner document, which we get by doing findDOMNode on the component instance (Portal/Modal), in the early case that won't work because the component hasn't mounted yet.

these can can be individually handled, but gets harder across components, e.g Portal mounts early, and calls back to Modal's onShow which assumes/needs the owner document

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, forget the fast path then.

What are your thoughts around adding the <div>? Is that just a legacy thing to prevent trying to e.g. unmount the tree rooted at document?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure honestly but it seems safe to remove. if someone wants to try and mount over their application that's sort of their problem :P my guess as to why it's there is so you don't blow away the dom that's already there when you render() but createPortal already appends into it's container

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay, so just to confirm, nothing will go wrong with using document as the portal node?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

having the container be document wouldn't work before either. if it's document.body or any thing else i'll work fine

this._mountOverlayTarget();
ReactDOM.unstable_renderSubtreeIntoContainer(
this, overlay, this._overlayTarget, (inst) => {
this._overlayInstance = inst
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

semi

this._overlayInstance = inst

if (this.props.onRendered) {
this.props.onRendered()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

semi

@@ -76,29 +70,8 @@ describe('Portal', function () {
assert.equal(instance.overlay.getOverlayDOMNode(), null);
});

it('Should render only an overlay', function() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why does this test case no longer work?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i forget...

codeText={this.props.codeText}
collapsableCode
code={this.props.codeText}
collapsable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eww it's not "collapsible" like in react-bootstrap? ;p

@jquense
Copy link
Member Author

jquense commented Oct 10, 2017

lets get this in 👍

@jharris4
Copy link

I tried this out (with React 16 and react-bootstrap next branch) in a project I have that's using modals, and it's looking good to me.

Let me know if there's anything I can do to help test this out

@@ -472,7 +475,7 @@ class Modal extends React.Component {
let autoFocus = this.props.autoFocus;
let modalContent = this.getDialogElement();
let current = activeElement(ownerDocument(this));
let focusInModal = current && contains(modalContent, current);
let focusInModal = modalContent && current && contains(modalContent, current);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we'd make a <RefHolder> component, attach a ref to it, then findDOMNode it... but this isn't really a regression or anything, so i guess this is fine for now

@@ -20,7 +20,7 @@ describe('Position', function () {
assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'SPAN');
});

it('Should warn about several children', function () {
xit('Should warn about several children', function () {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a FIXME

@jquense jquense merged commit dea8d71 into master Oct 14, 2017
@jquense jquense deleted the hot-fix-portal branch October 14, 2017 12:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants