Skip to content

Commit

Permalink
Merge 9719ff5 into a8b7aa0
Browse files Browse the repository at this point in the history
  • Loading branch information
cassln committed Feb 20, 2017
2 parents a8b7aa0 + 9719ff5 commit db7c094
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 21 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,26 @@ you can pass `className` and `overlayClassName` props to the Modal. If you do
this then none of the default styles will apply and you will have full control
over styling via CSS.

If you want to override default content and overlay classes you can pass object
with three required properties: `base`, `afterOpen`, `beforeClose`.

```jsx
<Modal
...
className={{
base: 'myClass',
afterOpen: 'myClass_after-open',
beforeClose: 'myClass_before-close'
}}
overlayClassName={{
base: 'myOverlayClass',
afterOpen: 'myOverlayClass_after-open',
beforeClose: 'myOverlayClass_before-close'
}}
...
>
```

You can also pass a `portalClassName` to change the wrapper's class (*ReactModalPortal*).
This doesn't affect styling as no styles are applied to this element by default.

Expand Down Expand Up @@ -112,6 +132,7 @@ function getParent() {
### Body class
When the modal is opened a `ReactModal__Body--open` class is added to the `body` tag.
You can use this to remove scrolling on the the body while the modal is open.
You can also pass a `bodyOpenClassName` to change the default class.

```CSS
/* Remove scroll on the body when react-modal is open */
Expand Down
8 changes: 5 additions & 3 deletions lib/components/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default class Modal extends Component {
overlay: React.PropTypes.object
}),
portalClassName: React.PropTypes.string,
bodyOpenClassName: React.PropTypes.string,
appElement: React.PropTypes.instanceOf(SafeHTMLElement),
onAfterOpen: React.PropTypes.func,
onRequestClose: React.PropTypes.func,
Expand All @@ -38,6 +39,7 @@ export default class Modal extends Component {
static defaultProps = {
isOpen: false,
portalClassName: 'ReactModalPortal',
bodyOpenClassName: 'ReactModal__Body--open',
ariaHideApp: true,
closeTimeoutMS: 0,
shouldCloseOnOverlayClick: true,
Expand Down Expand Up @@ -126,14 +128,14 @@ export default class Modal extends Component {
ReactDOM.unmountComponentAtNode(this.node);
const parent = getParentElement(this.props.parentSelector);
parent.removeChild(this.node);
elementClass(document.body).remove('ReactModal__Body--open');
elementClass(document.body).remove(this.props.bodyOpenClassName);
}

renderPortal (props) {
if (props.isOpen) {
elementClass(document.body).add('ReactModal__Body--open');
elementClass(document.body).add(this.props.bodyOpenClassName);
} else {
elementClass(document.body).remove('ReactModal__Body--open');
elementClass(document.body).remove(this.props.bodyOpenClassName);
}

if (props.ariaHideApp) {
Expand Down
45 changes: 27 additions & 18 deletions lib/components/ModalPortal.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,8 @@ import {

// so that our CSS is statically analyzable
const CLASS_NAMES = {
overlay: {
base: 'ReactModal__Overlay',
afterOpen: 'ReactModal__Overlay--after-open',
beforeClose: 'ReactModal__Overlay--before-close'
},
content: {
base: 'ReactModal__Content',
afterOpen: 'ReactModal__Content--after-open',
beforeClose: 'ReactModal__Content--before-close'
}
overlay: 'ReactModal__Overlay',
content: 'ReactModal__Content'
};

export default class ModalPortal extends Component {
Expand All @@ -30,8 +22,22 @@ export default class ModalPortal extends Component {
closeTimeoutMS: PropTypes.number,
shouldCloseOnOverlayClick: PropTypes.bool,
onRequestClose: PropTypes.func,
className: PropTypes.string,
overlayClassName: PropTypes.string,
className: PropTypes.oneOfType([
PropTypes.string,
PropTypes.shape({
base: PropTypes.string.isRequired,
afterOpen: PropTypes.string.isRequired,
beforeClose: PropTypes.string.isRequired
})
]),
overlayClassName: PropTypes.oneOfType([
PropTypes.string,
PropTypes.shape({
base: PropTypes.string.isRequired,
afterOpen: PropTypes.string.isRequired,
beforeClose: PropTypes.string.isRequired
})
]),
defaultStyles: PropTypes.shape({
content: PropTypes.object,
overlay: PropTypes.object
Expand Down Expand Up @@ -192,12 +198,15 @@ export default class ModalPortal extends Component {
}

buildClassName (which, additional) {
let className = CLASS_NAMES[which].base;
if (this.state.afterOpen) { className += ` ${CLASS_NAMES[which].afterOpen}`; }
if (this.state.beforeClose) {
className += ` ${CLASS_NAMES[which].beforeClose}`;
}
return additional ? `${className} ${additional}` : className;
const classNames = (typeof additional === 'object') ? additional : {
base: CLASS_NAMES[which],
afterOpen: `${CLASS_NAMES[which]}--after-open`,
beforeClose: `${CLASS_NAMES[which]}--before-close`
};
let className = classNames.base;
if (this.state.afterOpen) { className += ` ${classNames.afterOpen}`; }
if (this.state.beforeClose) { className += ` ${classNames.beforeClose}`; }
return (typeof additional === 'string' && additional) ? `${className} ${additional}` : className;
}

render () {
Expand Down
26 changes: 26 additions & 0 deletions specs/Modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,32 @@ describe('Modal', () => {
expect(modal.portal.overlay.className.indexOf('myOverlayClass')).toNotEqual(-1);
});

it('overrides the default content classes when a custom object className is used', () => {
const modal = renderModal({
isOpen: true,
className: {
base: 'myClass',
afterOpen: 'myClass_after-open',
beforeClose: 'myClass_before-close'
}
});
expect(modal.portal.content.className).toEqual('myClass myClass_after-open');
unmountModal();
});

it('overrides the default overlay classes when a custom object overlayClassName is used', () => {
const modal = renderModal({
isOpen: true,
overlayClassName: {
base: 'myOverlayClass',
afterOpen: 'myOverlayClass_after-open',
beforeClose: 'myOverlayClass_before-close'
}
});
expect(modal.portal.overlay.className).toEqual('myOverlayClass myOverlayClass_after-open');
unmountModal();
});

it('overrides the default styles when a custom classname is used', () => {
const modal = renderModal({ isOpen: true, className: 'myClass' });
expect(modal.portal.content.style.top).toEqual('');
Expand Down

0 comments on commit db7c094

Please sign in to comment.