diff --git a/src/dialog.jsx b/src/dialog.jsx index 57be10775f86fb..b0f0a2cc5fccb5 100644 --- a/src/dialog.jsx +++ b/src/dialog.jsx @@ -512,6 +512,37 @@ const Dialog = React.createClass({ }; }, + getInitialState() { + return { + open: this.props.open, + closing: false, + }; + }, + + componentWillReceiveProps(nextProps, nextContext) { + let newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme; + + if (nextProps.open !== this.state.open) { + if (nextProps.open) { + this.setState({ + open: true, + closing: false, + muiTheme: newMuiTheme, + }); + } else { + this.setState({closing: true}); + this._timeout = setTimeout(() => { + if (this.isMounted()) { + this.setState({ + open: false, + muiTheme: newMuiTheme, + }); + } + }, 500); + } + } + }, + renderLayer() { return ( @@ -520,7 +551,7 @@ const Dialog = React.createClass({ render() { return ( - + ); }, diff --git a/src/popover/popover-animation-from-top.jsx b/src/popover/popover-animation-from-top.jsx index 339f2857d4364d..d9e338a455d397 100644 --- a/src/popover/popover-animation-from-top.jsx +++ b/src/popover/popover-animation-from-top.jsx @@ -23,7 +23,7 @@ function getStyles(props, state) { opacity: open ? 1 : 0, transform: open ? 'scaleY(1)' : 'scaleY(0)', transformOrigin: `${horizontal} ${targetOrigin.vertical}`, - position: 'fixed', + position: 'absolute', zIndex: zIndex.popover, transition: Transitions.easeOut('450ms', ['transform', 'opacity']), maxHeight: '100%', diff --git a/src/popover/popover-default-animation.jsx b/src/popover/popover-default-animation.jsx index 86a8bf325a0017..5d9b526dd1dcaf 100644 --- a/src/popover/popover-default-animation.jsx +++ b/src/popover/popover-default-animation.jsx @@ -23,7 +23,7 @@ function getStyles(props, state) { opacity: open ? 1 : 0, transform: open ? 'scale(1, 1)' : 'scale(0, 0)', transformOrigin: `${horizontal} ${targetOrigin.vertical}`, - position: 'fixed', + position: 'absolute', zIndex: zIndex.popover, transition: Transitions.easeOut('250ms', ['transform', 'opacity']), maxHeight: '100%', diff --git a/src/popover/popover.jsx b/src/popover/popover.jsx index 604f6223c5ed5e..9b40939ea24865 100644 --- a/src/popover/popover.jsx +++ b/src/popover/popover.jsx @@ -243,8 +243,8 @@ const Popover = React.createClass({ const a = { top: rect.top, left: rect.left, - width: el.offsetWidth, - height: el.offsetHeight, + width: rect.width, + height: rect.height, }; a.right = rect.right || a.left + a.width; diff --git a/src/render-to-layer.jsx b/src/render-to-layer.jsx index 460b5108fc863a..a532a3179d19e8 100644 --- a/src/render-to-layer.jsx +++ b/src/render-to-layer.jsx @@ -2,6 +2,8 @@ import React from 'react'; import ReactDOM from 'react-dom'; import Dom from './utils/dom'; import getMuiTheme from './styles/getMuiTheme'; +import WindowListenable from './mixins/window-listenable'; +import throttle from 'lodash.throttle'; // heavily inspired by https://github.com/Khan/react-components/blob/master/js/layered-component-mixin.jsx const RenderToLayer = React.createClass({ @@ -22,6 +24,10 @@ const RenderToLayer = React.createClass({ muiTheme: React.PropTypes.object, }, + mixins: [ + WindowListenable, + ], + getDefaultProps() { return { useLayerForClickAway: true, @@ -29,6 +35,7 @@ const RenderToLayer = React.createClass({ }, getInitialState() { + this._renderLayerThrottled = throttle(this._renderLayer, 100); return { muiTheme: this.context.muiTheme || getMuiTheme(), }; @@ -61,6 +68,11 @@ const RenderToLayer = React.createClass({ this._unrenderLayer(); }, + windowListeners: { + resize: '_renderLayerThrottled', + scroll: '_renderLayerThrottled', + }, + onClickAway(event) { if (event.defaultPrevented) { return; @@ -113,16 +125,12 @@ const RenderToLayer = React.createClass({ if (open) { if (!this._layer) { this._layer = document.createElement('div'); + this._layer.style.position = 'absolute'; document.body.appendChild(this._layer); if (this.props.useLayerForClickAway) { this._layer.addEventListener('touchstart', this.onClickAway); this._layer.addEventListener('click', this.onClickAway); - this._layer.style.position = 'fixed'; - this._layer.style.top = 0; - this._layer.style.bottom = 0; - this._layer.style.left = 0; - this._layer.style.right = 0; this._layer.style.zIndex = this.state.muiTheme.zIndex.layer; } else { setTimeout(() => { @@ -131,7 +139,15 @@ const RenderToLayer = React.createClass({ }, 0); } } - + const {documentElement, body} = document; + const top = window.pageYOffset || documentElement.scrollTop || body.scrollTop || 0; + const left = window.pageXOffset || documentElement.scrollLeft || body.scrollLeft || 0; + + this._layer.style.top = `${top}px`; + this._layer.style.height = `${body.clientHeight}px`; + this._layer.style.left = `${left}px`; + this._layer.style.width = `${body.clientWidth}px`; + // By calling this method in componentDidMount() and // componentDidUpdate(), you're effectively creating a "wormhole" that // funnels React's hierarchical updates through to a DOM node on an