diff --git a/docs/src/app/components/pages/components/dialog.jsx b/docs/src/app/components/pages/components/dialog.jsx
index 9a35a697d79173..c5114b0816571f 100644
--- a/docs/src/app/components/pages/components/dialog.jsx
+++ b/docs/src/app/components/pages/components/dialog.jsx
@@ -212,6 +212,7 @@ export default class DialogPage extends React.Component {
title="Dialog With Standard Actions"
actions={standardActions}
actionFocus="submit"
+ modal={this.state.modal}
open={this.state.openDialogStandardActions}
onRequestClose={this._handleRequestClose}>
The actions in this window are created from the json that's passed in.
@@ -221,6 +222,7 @@ export default class DialogPage extends React.Component {
ref="customDialog"
title="Dialog With Custom Actions"
actions={customActions}
+ modal={this.state.modal}
open={this.state.openDialogCustomActions}
onRequestClose={this._handleRequestClose}>
The actions in this window were passed in as an array of react objects.
@@ -235,6 +237,7 @@ export default class DialogPage extends React.Component {
ref="scrollableContentDialog"
title="Dialog With Scrollable Content"
actions={scrollableCustomActions}
+ modal={this.state.modal}
autoDetectWindowHeight={true}
autoScrollBodyContent={true}
open={this.state.openDialogScrollable}
diff --git a/src/dialog.jsx b/src/dialog.jsx
index 33d2846908abfd..aa8cde57645639 100644
--- a/src/dialog.jsx
+++ b/src/dialog.jsx
@@ -7,6 +7,7 @@ const Transitions = require('./styles/transitions');
const StylePropable = require('./mixins/style-propable');
const FlatButton = require('./flat-button');
const Overlay = require('./overlay');
+const RenderToLayer = require('./render-to-layer');
const Paper = require('./paper');
const DefaultRawTheme = require('./styles/raw-themes/light-raw-theme');
const ThemeManager = require('./styles/theme-manager');
@@ -47,6 +48,10 @@ const TransitionItem = React.createClass({
},
componentWillEnter(callback) {
+ this.componentWillAppear(callback);
+ },
+
+ componentWillAppear(callback) {
let spacing = this.state.muiTheme.rawTheme.spacing;
this.setState({
@@ -84,7 +89,7 @@ const TransitionItem = React.createClass({
},
});
-let Dialog = React.createClass({
+const DialogInline = React.createClass({
mixins: [WindowListenable, StylePropable],
@@ -110,18 +115,10 @@ let Dialog = React.createClass({
bodyStyle: React.PropTypes.object,
contentClassName: React.PropTypes.string,
contentStyle: React.PropTypes.object,
- openImmediately: React.PropTypes.bool,
+ open: React.PropTypes.bool.isRequired,
repositionOnUpdate: React.PropTypes.bool,
style: React.PropTypes.object,
title: React.PropTypes.node,
- defaultOpen: React.PropTypes.bool,
- open: React.PropTypes.bool,
- modal: React.PropTypes.bool,
- onDismiss: React.PropTypes.func,
- onShow: React.PropTypes.func,
- onRequestClose: React.PropTypes.func,
- actionFocus: React.PropTypes.string,
- titleStyle: React.PropTypes.object,
},
windowListeners: {
@@ -129,58 +126,24 @@ let Dialog = React.createClass({
resize: '_handleResize',
},
+ getInitialState() {
+ return {
+ muiTheme: this.context.muiTheme ? this.context.muiTheme : ThemeManager.getMuiTheme(DefaultRawTheme),
+ };
+ },
+
getDefaultProps() {
return {
autoDetectWindowHeight: false,
autoScrollBodyContent: false,
actions: [],
repositionOnUpdate: true,
- defaultOpen: false,
open: null,
};
},
- getInitialState() {
- if (process.env.NODE_ENV !== 'production') {
- this._testDeprecations();
- }
-
- let open = this.props.open;
-
- if (open === null) {
- open = (this.props.openImmediately || this.props.defaultOpen);
- }
-
- return {
- open: open,
- muiTheme: this.context.muiTheme ? this.context.muiTheme : ThemeManager.getMuiTheme(DefaultRawTheme),
- };
- },
-
- //to update theme inside state whenever a new theme is passed down
- //from the parent / owner using context
- componentWillReceiveProps (nextProps, nextContext) {
- const newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;
- this.setState({muiTheme: newMuiTheme});
-
- if (process.env.NODE_ENV !== 'production') {
- this._testDeprecations();
- }
-
- if (nextProps.open !== this.props.open) {
- if (nextProps.open && !this.state.open) {
- this._show();
- } else if (!nextProps.open && this.state.open) {
- this._dismiss();
- }
- }
- },
-
componentDidMount() {
this._positionDialog();
- if (this.state.open) {
- this.refs.dialogOverlay.preventScrolling();
- }
},
componentDidUpdate() {
@@ -230,7 +193,7 @@ let Dialog = React.createClass({
};
- if (this.state.open) {
+ if (this.props.open) {
main = this.mergeStyles(main, {
left: 0,
transition: Transitions.easeOut('0ms', 'left', '0ms'),
@@ -262,8 +225,10 @@ let Dialog = React.createClass({
return (
-
- {this.state.open &&
+
+ {this.props.open &&
@@ -279,32 +244,12 @@ let Dialog = React.createClass({
}
);
},
- isOpen() {
- return this.state.open;
- },
-
- _testDeprecations() {
- warning(!this.props.hasOwnProperty('openImmediately'),
- 'openImmediately has been deprecated in favor of defaultOpen');
-
- warning(!(typeof this.props.onShow === 'function'),
- 'onShow will be removed in favor of explicitly setting open');
-
- warning(!(typeof this.props.onDismiss === 'function'),
- 'onDismiss will be removed in favor of explicitly setting open and can be replaced by onRequestClose');
-
- warning(!this.props.hasOwnProperty('modal'),
- 'modal will be removed in favor of explicitly setting open and onRequestClose');
- },
-
_getAction(actionJSON, key) {
let props = {
key: key,
@@ -372,40 +317,166 @@ let Dialog = React.createClass({
},
_positionDialog() {
- if (this.state.open) {
- let clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
- let container = ReactDOM.findDOMNode(this);
- let dialogWindow = ReactDOM.findDOMNode(this.refs.dialogWindow);
- let dialogContent = ReactDOM.findDOMNode(this.refs.dialogContent);
- let minPaddingTop = 16;
-
- //Reset the height in case the window was resized.
- dialogWindow.style.height = '';
- dialogContent.style.height = '';
-
- let dialogWindowHeight = dialogWindow.offsetHeight;
- let paddingTop = ((clientHeight - dialogWindowHeight) / 2) - 64;
- if (paddingTop < minPaddingTop) paddingTop = minPaddingTop;
-
- //Vertically center the dialog window, but make sure it doesn't
- //transition to that position.
- if (this.props.repositionOnUpdate || !container.style.paddingTop) {
- container.style.paddingTop = paddingTop + 'px';
- }
+ if (!this.props.open) {
+ return;
+ }
+
+ let clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
+ let container = ReactDOM.findDOMNode(this);
+ let dialogWindow = ReactDOM.findDOMNode(this.refs.dialogWindow);
+ let dialogContent = ReactDOM.findDOMNode(this.refs.dialogContent);
+ let minPaddingTop = 16;
+
+ //Reset the height in case the window was resized.
+ dialogWindow.style.height = '';
+ dialogContent.style.height = '';
+
+ let dialogWindowHeight = dialogWindow.offsetHeight;
+ let paddingTop = ((clientHeight - dialogWindowHeight) / 2) - 64;
+ if (paddingTop < minPaddingTop) paddingTop = minPaddingTop;
+
+ //Vertically center the dialog window, but make sure it doesn't
+ //transition to that position.
+ if (this.props.repositionOnUpdate || !container.style.paddingTop) {
+ container.style.paddingTop = paddingTop + 'px';
+ }
+
+ // Force a height if the dialog is taller than clientHeight
+ if (this.props.autoDetectWindowHeight || this.props.autoScrollBodyContent) {
+ let styles = this.getStyles();
+ let maxDialogContentHeight = clientHeight - 2 * (styles.body.padding + 64);
+
+ if (this.props.title) maxDialogContentHeight -= dialogContent.previousSibling.offsetHeight;
+ if (this.props.actions.length) maxDialogContentHeight -= dialogContent.nextSibling.offsetHeight;
+
+ dialogContent.style.maxHeight = maxDialogContentHeight + 'px';
+ }
+ },
+
+ _requestClose(buttonClicked) {
+
+ if (!buttonClicked && this.props.modal) {
+ return;
+ }
+
+ if (this.props.onRequestClose) {
+ this.props.onRequestClose(!!buttonClicked);
+ }
+ },
- // Force a height if the dialog is taller than clientHeight
- if (this.props.autoDetectWindowHeight || this.props.autoScrollBodyContent) {
- let styles = this.getStyles();
- let maxDialogContentHeight = clientHeight - 2 * (styles.body.padding + 64);
+ _handleOverlayTouchTap() {
+ this._requestClose(false);
+ },
+
+ _handleWindowKeyUp(event) {
+ if (event.keyCode === KeyCode.ESC) {
+ this._requestClose(false);
+ }
+ },
+
+ _handleResize() {
+ if (this.props.open) {
+ this._positionDialog();
+ }
+ },
+
+});
- if (this.props.title) maxDialogContentHeight -= dialogContent.previousSibling.offsetHeight;
- if (this.props.actions.length) maxDialogContentHeight -= dialogContent.nextSibling.offsetHeight;
- dialogContent.style.maxHeight = maxDialogContentHeight + 'px';
+const wrapperStyle = {position:'fixed', top:0, left:0, zIndex:20};
+const Dialog = React.createClass({
+
+ propTypes: {
+ actionFocus: React.PropTypes.string,
+ actions: React.PropTypes.array,
+ autoDetectWindowHeight: React.PropTypes.bool,
+ autoScrollBodyContent: React.PropTypes.bool,
+ bodyStyle: React.PropTypes.object,
+ contentClassName: React.PropTypes.string,
+ contentStyle: React.PropTypes.object,
+ defaultOpen: React.PropTypes.bool,
+ modal: React.PropTypes.bool,
+ onDismiss: React.PropTypes.func,
+ onRequestClose: React.PropTypes.func,
+ onShow: React.PropTypes.func,
+ open: React.PropTypes.bool,
+ openImmediately: React.PropTypes.bool,
+ repositionOnUpdate: React.PropTypes.bool,
+ style: React.PropTypes.object,
+ title: React.PropTypes.node,
+ titleStyle: React.PropTypes.object,
+ },
+
+ getInitialState() {
+ if (process.env.NODE_ENV !== 'production') {
+ this._testDeprecations();
+ }
+
+ let open = this.props.open;
+
+ if (open === null) {
+ open = (this.props.openImmediately || this.props.defaultOpen);
+ }
+
+ return {
+ open: open,
+ muiTheme: this.context.muiTheme ? this.context.muiTheme : ThemeManager.getMuiTheme(DefaultRawTheme),
+ };
+ },
+
+ getDefaultProps() {
+ return {
+ open:null,
+ defaultOpen:false,
+ modal:false,
+ }
+ },
+
+ //to update theme inside state whenever a new theme is passed down
+ //from the parent / owner using context
+ componentWillReceiveProps (nextProps, nextContext) {
+ const newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;
+ this.setState({muiTheme: newMuiTheme});
+
+ if (process.env.NODE_ENV !== 'production') {
+ this._testDeprecations();
+ }
+ if (nextProps.open !== this.props.open) {
+ if (nextProps.open && !this.state.open) {
+ this._show();
+ } else if (!nextProps.open && this.state.open) {
+ this._dismiss();
}
}
},
+ render() {
+ return (
+
+ );
+ },
+
+ renderLayer() {
+ return (
+
+
+
+ );
+ },
+
+ _testDeprecations() {
+ warning(!this.props.hasOwnProperty('openImmediately'),
+ 'openImmediately has been deprecated in favor of defaultOpen');
+
+ warning(!(typeof this.props.onShow === 'function'),
+ 'onShow will be removed in favor of explicitly setting open');
+
+ warning(!(typeof this.props.onDismiss === 'function'),
+ 'onDismiss will be removed in favor of explicitly setting open and can be replaced by onRequestClose');
+
+ },
+
+
show() {
warning(false, 'show has been deprecated in favor of explicitly setting the open property.');
@@ -419,7 +490,6 @@ let Dialog = React.createClass({
},
_show() {
- this.refs.dialogOverlay.preventScrolling();
this.setState({
open: true,
}, this._onShow);
@@ -438,47 +508,17 @@ let Dialog = React.createClass({
},
_dismiss() {
- CssEvent.onTransitionEnd(ReactDOM.findDOMNode(this), () => {
- this.refs.dialogOverlay.allowScrolling();
- });
-
this.setState({
open: false,
}, this._onDismiss);
},
- _requestClose(buttonClicked) {
- warning(!this.props.hasOwnProperty('modal'),
- 'modal will be removed in favor of explicitly setting open and onRequestClose');
-
- if (!buttonClicked && this.props.modal) {
- return;
- }
-
- // Close the dialog if the open state is not explicitly set.
- if (this.props.open === null) {
- this._dismiss();
- }
- if (this.props.onRequestClose) {
- this.props.onRequestClose(!!buttonClicked);
- }
- },
-
- _handleOverlayTouchTap() {
- this._requestClose(false);
+ layerWillUnmount() {
+ if (this.props.onDismiss) this.props.onDismiss();
},
- _handleWindowKeyUp(event) {
- if (event.keyCode === KeyCode.ESC) {
- this._requestClose(false);
- }
- },
-
- _handleResize() {
- if (this.state.open) {
- this.refs.dialogOverlay.preventScrolling();
- this._positionDialog();
- }
+ isOpen() {
+ return this.state.openImmediately;
},
});
diff --git a/src/overlay.jsx b/src/overlay.jsx
index 5e8b5e53fd7154..f64f9d6d0f614f 100644
--- a/src/overlay.jsx
+++ b/src/overlay.jsx
@@ -39,33 +39,30 @@ const Overlay = React.createClass({
componentWillReceiveProps (nextProps, nextContext) {
let newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;
this.setState({muiTheme: newMuiTheme});
+ if (this.props.show !== nextProps.show) {
+ this._applyAutoLockScrolling(nextProps);
+ }
},
propTypes: {
autoLockScrolling: React.PropTypes.bool,
- show: React.PropTypes.bool,
- transitionEnabled: React.PropTypes.bool,
+ show: React.PropTypes.bool.isRequired,
style: React.PropTypes.object,
+ transitionEnabled: React.PropTypes.bool,
},
getDefaultProps() {
return {
autoLockScrolling: true,
transitionEnabled: true,
+ style:{},
};
},
componentDidMount() {
this._originalBodyOverflow = document.getElementsByTagName('body')[0].style.overflow;
- },
-
- componentDidUpdate() {
- if (this.props.autoLockScrolling) {
- if (this.props.show) {
- this._preventScrolling();
- } else {
- this._allowScrolling();
- }
+ if (this.props.show) {
+ this._applyAutoLockScrolling(this.props);
}
},
@@ -126,12 +123,14 @@ const Overlay = React.createClass({
);
},
- preventScrolling() {
- if (!this.props.autoLockScrolling) this._preventScrolling();
- },
-
- allowScrolling() {
- if (!this.props.autoLockScrolling) this._allowScrolling();
+ _applyAutoLockScrolling(props) {
+ if (props.autoLockScrolling) {
+ if (props.show) {
+ this._preventScrolling();
+ } else {
+ this._allowScrolling();
+ }
+ }
},
_preventScrolling() {