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

[Dialog] create responsive HOC withResponsiveFullScreen #6898

Merged
merged 4 commits into from May 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .flowconfig
Expand Up @@ -26,3 +26,6 @@ module.name_mapper='^material-ui-icons\/\(.*\)$' -> '<PROJECT_ROOT>/packages/mat
module.ignore_non_literal_requires=true
module.system.node.resolve_dirname=node_modules
module.system.node.resolve_dirname=.

suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe
suppress_type=$FlowToDo
4 changes: 4 additions & 0 deletions docs/src/pages/component-demos/dialogs/dialogs.md
Expand Up @@ -44,3 +44,7 @@ Touching “Cancel” in a confirmation dialog, or pressing Back, cancels the ac
## Full-screen dialogs

{{demo='pages/component-demos/dialogs/FullScreenDialog.js'}}

## Responsive full-screen

You may make a `Dialog` responsively full screen the dialog using `withResponsiveFullScreen`. By default, `withResponsiveFullScreen()(Dialog)` responsively full screens *at or below* the `sm` [screen size](/layout/basics).
6 changes: 3 additions & 3 deletions package.json
Expand Up @@ -36,10 +36,10 @@
"prebuild": "npm run clean:build",
"start": "cd docs && npm start",
"test": "npm run lint && npm run flow && npm run test:unit",
"test:unit": "cross-env NODE_ENV=test mocha",
"test:unit": "cross-env NODE_ENV=test mocha test/integration/{,**/}*.spec.js src/{,**/}*.spec.js",
"test:watch": "cross-env NODE_ENV=test mocha -w",
"test:coverage": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha && nyc report -r lcovonly",
"test:coverage:html": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha && nyc report --reporter=html",
"test:coverage": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha test/integration/{,**/}*.spec.js src/{,**/}*.spec.js && nyc report -r lcovonly",
"test:coverage:html": "cross-env NODE_ENV=test BABEL_ENV=coverage nyc mocha test/integration/{,**/}*.spec.js src/{,**/}*.spec.js && nyc report --reporter=html",
"test:karma": "cross-env NODE_ENV=test karma start test/karma.conf.js --single-run",
"test:regressions": "webpack --config test/regressions/webpack.config.js && vrtest run --config test/vrtest.config.js",
"argos": "ARGOS_COMMIT=$CIRCLE_SHA1 ARGOS_BRANCH=$CIRCLE_BRANCH argos upload --ignore **/*.diff.png tmp/output/chrome --token $ARGOS_TOKEN || true",
Expand Down
344 changes: 171 additions & 173 deletions src/Dialog/Dialog.js
@@ -1,7 +1,6 @@
// @flow weak

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import React, { Element } from 'react';
import classNames from 'classnames';
import { createStyleSheet } from 'jss-theme-reactor';
import customPropTypes from '../utils/customPropTypes';
Expand Down Expand Up @@ -46,6 +45,92 @@ export const styleSheet = createStyleSheet('MuiDialog', (theme) => {
};
});

type Props = {
Copy link
Member

Choose a reason for hiding this comment

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

Hold on with the flow migration, I'm refactoring all the components to use withStyles. Let's try to avoid conflict 🙈 .

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 going to merge this as I've already had a rebase nightmare with it. Will hold off on more, and we can discuss any other things that need to be done on gutter and I'll get to it on Monday. Thanks for all the feedback, all good things and this code is better for it!

/**
* Dialog children, usually the included sub-components.
*/
children?: Element<*>,
/**
* @ignore
*/
className?: string,
/**
* If `true`, it will be full-screen
*/
fullScreen?: boolean,
/**
* If `true`, clicking the backdrop will not fire the `onRequestClose` callback.
*/
ignoreBackdropClick?: boolean,
/**
* If `true`, hitting escape will not fire the `onRequestClose` callback.
*/
ignoreEscapeKeyUp?: boolean,
/**
* Duration of the animation when the element is entering.
*/
enterTransitionDuration?: number, // eslint-disable-line react/sort-prop-types
/**
* Duration of the animation when the element is leaving.
*/
leaveTransitionDuration?: number,
/**
* Determine the max width of the dialog.
* The dialog width grows with the size of the screen, this property is useful
* on the desktop where you might need some coherent different width size across your
* application.
*/
maxWidth?: 'xs' | 'sm' | 'md',
/**
* Callback fired when the backdrop is clicked.
*/
onBackdropClick?: Function,
/**
* Callback fired before the dialog enters.
*/
onEnter?: Function,
/**
* Callback fired when the dialog is entering.
*/
onEntering?: Function,
/**
* Callback fired when the dialog has entered.
*/
onEntered?: Function, // eslint-disable-line react/sort-prop-types
/**
* Callback fires when the escape key is released and the modal is in focus.
*/
onEscapeKeyUp?: Function, // eslint-disable-line react/sort-prop-types
/**
* Callback fired before the dialog exits.
*/
onExit?: Function,
/**
* Callback fired when the dialog is exiting.
*/
onExiting?: Function,
/**
* Callback fired when the dialog has exited.
*/
onExited?: Function, // eslint-disable-line react/sort-prop-types
/**
* Callback fired when the dialog requests to be closed.
*/
onRequestClose?: Function,
/**
* If `true`, the Dialog is open.
*/
open?: boolean,
/**
* The CSS class name of the paper inner element.
*/
paperClassName?: string,
/**
* Transition component.
*/
transition?: Function | Element<*>,
};

/**
* Dialogs are overlaid modal paper based components with a backdrop.
*
Expand All @@ -56,184 +141,97 @@ export const styleSheet = createStyleSheet('MuiDialog', (theme) => {
* </Dialog>
* ```
*/
export default class Dialog extends Component {
function Dialog(props: Props, context: { styleManager: Object }) {
const {
children,
className,
fullScreen,
ignoreBackdropClick,
ignoreEscapeKeyUp,
enterTransitionDuration,
leaveTransitionDuration,
maxWidth: maxWidthProp,
open,
onBackdropClick,
onEscapeKeyUp,
onEnter,
onEntering,
onEntered,
onExit,
onExiting,
onExited,
onRequestClose,
paperClassName,
transition,
...other
} = props;

static propTypes = {
/**
* Dialog children, usually the included sub-components.
*/
children: PropTypes.node,
/**
* @ignore
*/
className: PropTypes.string,
/**
* If `true`, the dialog will be full-screen.
*/
fullScreen: PropTypes.bool,
/**
* If `true`, clicking the backdrop will not fire the `onRequestClose` callback.
*/
ignoreBackdropClick: PropTypes.bool,
/**
* If `true`, hitting escape will not fire the `onRequestClose` callback.
*/
ignoreEscapeKeyUp: PropTypes.bool,
/**
* Duration of the animation when the element is entering.
*/
enterTransitionDuration: PropTypes.number, // eslint-disable-line react/sort-prop-types
/**
* Duration of the animation when the element is leaving.
*/
leaveTransitionDuration: PropTypes.number,
/**
* Determine the max width of the dialog.
* The dialog width grows with the size of the screen, this property is useful
* on the desktop where you might need some coherent different width size across your
* application.
*/
maxWidth: PropTypes.oneOf([
'xs',
'sm',
'md',
]),
/**
* Callback fired when the backdrop is clicked.
*/
onBackdropClick: PropTypes.func,
/**
* Callback fired before the dialog enters.
*/
onEnter: PropTypes.func,
/**
* Callback fired when the dialog is entering.
*/
onEntering: PropTypes.func,
/**
* Callback fired when the dialog has entered.
*/
onEntered: PropTypes.func, // eslint-disable-line react/sort-prop-types
/**
* Callback fires when the escape key is released and the modal is in focus.
*/
onEscapeKeyUp: PropTypes.func, // eslint-disable-line react/sort-prop-types
/**
* Callback fired before the dialog exits.
*/
onExit: PropTypes.func,
/**
* Callback fired when the dialog is exiting.
*/
onExiting: PropTypes.func,
/**
* Callback fired when the dialog has exited.
*/
onExited: PropTypes.func, // eslint-disable-line react/sort-prop-types
/**
* Callback fired when the dialog requests to be closed.
*/
onRequestClose: PropTypes.func,
/**
* If `true`, the Dialog is open.
*/
open: PropTypes.bool,
/**
* The CSS class name of the paper inner element.
*/
paperClassName: PropTypes.string,
/**
* Transition component.
*/
transition: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
};
const classes = context.styleManager.render(styleSheet);

static defaultProps = {
fullScreen: false,
ignoreBackdropClick: false,
ignoreEscapeKeyUp: false,
enterTransitionDuration: duration.enteringScreen,
leaveTransitionDuration: duration.leavingScreen,
maxWidth: 'sm',
open: false,
transition: Fade,
};
// workaround: see #2 test case from https://github.com/facebook/flow/issues/1660#issuecomment-302468866
const maxWidth = maxWidthProp || Dialog.defaultProps.maxWidth;

static contextTypes = {
styleManager: customPropTypes.muiRequired,
const transitionProps = {
in: open,
transitionAppear: true,
enterTransitionDuration,
leaveTransitionDuration,
onEnter,
onEntering,
onEntered,
onExit,
onExiting,
onExited,
};

render() {
const {
children,
className,
fullScreen,
ignoreBackdropClick,
ignoreEscapeKeyUp,
enterTransitionDuration,
leaveTransitionDuration,
maxWidth,
open,
onBackdropClick,
onEscapeKeyUp,
onEnter,
onEntering,
onEntered,
onExit,
onExiting,
onExited,
onRequestClose,
paperClassName,
transition,
...other
} = this.props;
let createTransitionFn;

const classes = this.context.styleManager.render(styleSheet);
if (typeof transition === 'function') {
createTransitionFn = React.createElement;
} else {
createTransitionFn = React.cloneElement;
}

const transitionProps = {
in: open,
transitionAppear: true,
enterTransitionDuration,
leaveTransitionDuration,
onEnter,
onEntering,
onEntered,
onExit,
onExiting,
onExited,
};
return (
<Modal
className={classNames(classes.modal, className)}
backdropTransitionDuration={open ? enterTransitionDuration : leaveTransitionDuration}
ignoreBackdropClick={ignoreBackdropClick}
ignoreEscapeKeyUp={ignoreEscapeKeyUp}
onBackdropClick={onBackdropClick}
onEscapeKeyUp={onEscapeKeyUp}
onRequestClose={onRequestClose}
show={open}
{...other}
>
{/* $FlowFixMe */}
{createTransitionFn(transition, transitionProps, (
<Paper
data-mui-test="Dialog"
elevation={24}
className={classNames(classes.dialog, classes[`dialogWidth-${maxWidth}`],
paperClassName, { [classes.fullScreen]: fullScreen })}
>
{children}
</Paper>
))}
</Modal>
);
}

let createTransitionFn;
Dialog.defaultProps = {
fullScreen: false,
ignoreBackdropClick: false,
ignoreEscapeKeyUp: false,
enterTransitionDuration: duration.enteringScreen,
leaveTransitionDuration: duration.leavingScreen,
maxWidth: 'sm',
open: false,
transition: Fade,
};

if (typeof transition === 'function') {
createTransitionFn = React.createElement;
} else {
createTransitionFn = React.cloneElement;
}
Dialog.contextTypes = {
styleManager: customPropTypes.muiRequired,
};

return (
<Modal
className={classNames(classes.modal, className)}
backdropTransitionDuration={open ? enterTransitionDuration : leaveTransitionDuration}
ignoreBackdropClick={ignoreBackdropClick}
ignoreEscapeKeyUp={ignoreEscapeKeyUp}
onBackdropClick={onBackdropClick}
onEscapeKeyUp={onEscapeKeyUp}
onRequestClose={onRequestClose}
show={open}
{...other}
>
{createTransitionFn(transition, transitionProps, (
<Paper
data-mui-test="Dialog"
elevation={24}
className={classNames(classes.dialog, classes[`dialogWidth-${maxWidth}`],
paperClassName, { [classes.fullScreen]: fullScreen })}
>
{children}
</Paper>
))}
</Modal>
);
}
}
export default Dialog;