-
Notifications
You must be signed in to change notification settings - Fork 222
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
Update Portal #208
Conversation
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", |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
test/ModalSpec.js
Outdated
|
||
render( | ||
<Modal show> | ||
<div className='modal'> | ||
<div className='modal'>q |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using vi
? ;-)
test/ModalSpec.js
Outdated
@@ -11,6 +11,16 @@ import { render, shouldWarn } from './helpers'; | |||
|
|||
const $ = componentOrNode => jQuery(ReactDOM.findDOMNode(componentOrNode)); | |||
|
|||
|
|||
class ErrorBoundary extends React.Component { |
There was a problem hiding this comment.
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.
test/PositionSpec.js
Outdated
@@ -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 () { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ping?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a FIXME
test/ModalSpec.js
Outdated
it('Should throw with multiple children', function () { | ||
expect(function(){ | ||
render( | ||
xit('Should throw with multiple children', function () { |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
test/ModalSpec.js
Outdated
render( | ||
<ErrorBoundary | ||
onError={err => { | ||
console.log('hiii') |
There was a problem hiding this comment.
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.
test/ModalSpec.js
Outdated
@@ -11,6 +11,16 @@ import { render, shouldWarn } from './helpers'; | |||
|
|||
const $ = componentOrNode => jQuery(ReactDOM.findDOMNode(componentOrNode)); | |||
|
|||
|
|||
class ErrorBoundary extends React.Component { | |||
componentDidCatch(error, info) { |
There was a problem hiding this comment.
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
.
There was a problem hiding this 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); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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?)
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
src/LegacyPortal.js
Outdated
this._mountOverlayTarget(); | ||
ReactDOM.unstable_renderSubtreeIntoContainer( | ||
this, overlay, this._overlayTarget, (inst) => { | ||
this._overlayInstance = inst |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
semi
src/LegacyPortal.js
Outdated
this._overlayInstance = inst | ||
|
||
if (this.props.onRendered) { | ||
this.props.onRendered() |
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
lets get this in 👍 |
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); |
There was a problem hiding this comment.
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
test/PositionSpec.js
Outdated
@@ -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 () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a FIXME
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