Skip to content

Commit

Permalink
fix(modals): react modals now scroll when content is greater than vie…
Browse files Browse the repository at this point in the history
…wport

- Body no longer scrolls when modal is open
- Upgrade bootstrap from 3.3.1 to 3.3.5

[#97701138]
  • Loading branch information
Geoff Pleiss, Kenny Wang and Matt Royal authored and Geoff Pleiss and Kenny Wang committed Jul 8, 2015
1 parent db9dc9e commit 4355e94
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 39 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"babel-core": "^5.4.7",
"babel-eslint": "^3.1.10",
"babel-loader": "^5.1.3",
"bootstrap-sass": "3.3.1",
"bootstrap-sass": "3.3.5",
"classlist-polyfill": "^1.0.1",
"classnames": "^2.1.2",
"conventional-changelog": "0.1.0-alpha.1",
"conventional-recommended-bump": "0.0.1",
Expand Down
79 changes: 53 additions & 26 deletions spec/pivotal-ui-react/modals/modals_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe('Modals', function() {
});

describe('when mounting', function() {
it('removes the key up event listener', function() {
it('adds the key up event listener', function() {
expect(document.body.addEventListener).toHaveBeenCalledWith('keyup', subject.refs.modal.onKeyUp, false);
});
});
Expand All @@ -74,34 +74,61 @@ describe('Modals', function() {
});
});

describe('clicking on the modal trigger', function() {
beforeEach(function() {
$('#openButton').simulate('click');
});

function itOpensTheModal() {
it('renders a modal', function() {
expect('.modal').toExist();
expect('.modal').toHaveClass('modal-basic');
expect('.modal .modal-backdrop').toHaveClass('fade');
expect('.modal .modal-backdrop').toHaveClass('in');
expect('.modal .modal-header').toContainText('What a Header!');
expect('.modal .modal-body').toContainText('Text in a body');
expect('.modal .modal-footer').toContainText('Text in a footer');
});

it('adds the modal-open class to the body', () => {
expect('body').toHaveClass('modal-open');
});

it('renders a modal-backdrop', function() {
expect('.modal-backdrop').toExist();
});
}

function itKeepsTheModalOpen() { itOpensTheModal(); }

function itClosesTheModal() {
it('closes the modal', function() {
expect('.modal').not.toExist();
});

it('removes the modal-backdrop', function() {
expect('.modal-backdrop').not.toExist();
});

it('removes the modal-open class from the body', function() {
expect('body').not.toHaveClass('modal-open');
});
}

describe('clicking on the modal trigger', function() {
beforeEach(function() {
$('#openButton').simulate('click');
});

itOpensTheModal();

describe('pressing any key', function() {
describe('for the escape key', function() {
it('closes the modal', function() {
beforeEach(function() {
document.body.addEventListener.calls.mostRecent().args[1]({keyCode: 27});
expect(subject.refs.modal.state.isVisible).toBe(false);
});

itClosesTheModal();
});

describe('any other key', function() {
it('does not close the modal', function() {
beforeEach(function() {
document.body.addEventListener.calls.mostRecent().args[1]({keyCode: 13});
expect(subject.refs.modal.state.isVisible).toBe(true);
});

itKeepsTheModalOpen();
});
});

Expand All @@ -110,39 +137,39 @@ describe('Modals', function() {
$('.modal button.close').simulate('click');
});

it('closes the modal', function() {
expect(subject.refs.modal.state.isVisible).toBe(false);
});
itClosesTheModal();

describe('opening the modal again', function() {
beforeEach(function() {
$('#openButton').simulate('click');
});

it('opens the modal', function() {
expect(subject.refs.modal.state.isVisible).toBe(true);
});
itOpensTheModal();
});
});

describe('clicking on the modal backdrop', function() {
describe('clicking inside the modal-dialog', function() {
beforeEach(function() {
$('.modal .modal-backdrop').simulate('click');
$('.modal-dialog').simulate('click');
});

it('closes the modal', function() {
expect(subject.refs.modal.state.isVisible).toBe(false);
itKeepsTheModalOpen();
});

describe('clicking outside the modal-dialog', function() {
beforeEach(function() {
$('.modal').simulate('click');
});

itClosesTheModal();
});

describe('clicking the close button', function() {
beforeEach(function() {
$('#closeButton').simulate('click');
});

it('closes the modal', function() {
expect(subject.refs.modal.state.isVisible).toBe(false);
});
itClosesTheModal();
});
});
});
Expand Down
42 changes: 33 additions & 9 deletions src/pivotal-ui-react/modals/modals.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
var React = require('react/addons');
var {DefaultH4} = require('pui-react-typography');
require('classlist-polyfill');
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;

/**
Expand Down Expand Up @@ -56,7 +57,16 @@ var Modal = React.createClass({
},

getInitialState() {
return ({isVisible: false});
return {isVisible: false};
},

componentWillUpdate(nextProps, nextState) {
if (nextState.isVisible) {
document.body.classList.add('modal-open');
}
else {
document.body.classList.remove('modal-open');
}
},

open() {
Expand All @@ -67,17 +77,24 @@ var Modal = React.createClass({
this.setState({isVisible: false});
},

childrenClick(e) {
if (e.target === this.refs.modal.getDOMNode()) {
this.close();
}
},

onKeyUp(e) {
if (e.keyCode === 27) {
this.close();
}
},

render() {
var modalInnards = this.state.isVisible ?
(
<div className="modal modal-basic" style={{display: 'block'}} key="bananas">
<div className="modal-backdrop fade in" onClick={this.close} style={{height: window.innerHeight}}></div>
let modal = null;
let backdrop = null;
if (this.state.isVisible) {
modal = (
<div className="modal modal-basic" style={{ display: 'block'}} key="bananas" ref="modal" onClick={this.childrenClick}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
Expand All @@ -87,14 +104,21 @@ var Modal = React.createClass({
</button>
<DefaultH4 className="modal-title">{this.props.title}</DefaultH4>
</div>
{this.props.children}
{this.props.children}
</div>
</div>
</div>
) :
null;
);
backdrop = (<div className="modal-backdrop in" key="tangerine" onClick={this.close}></div>);
}

return (
<div>
<ReactCSSTransitionGroup transitionName="modal-backdrop-fade">{backdrop}</ReactCSSTransitionGroup>
<ReactCSSTransitionGroup transitionName="modal-fade">{modal}</ReactCSSTransitionGroup>
</div>
);

return <ReactCSSTransitionGroup transitionName="modal-fade">{modalInnards}</ReactCSSTransitionGroup>;
}
});

Expand Down
3 changes: 2 additions & 1 deletion src/pivotal-ui-react/modals/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"description": "React components for opening and closing modal windows",
"homepage": "http://styleguide.pivotal.io/react_beta.html#modal_react",
"dependencies": {
"classlist-polyfill": "^1.0.1",
"pui-css-modals": "1.10.0",
"pui-react-typography": "1.10.0"
}
}
}
2 changes: 1 addition & 1 deletion src/pivotal-ui/components/bootstrap/bootstrap.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
@import "../pui-variables.scss";
@import "../mixins.scss";

@import "../../frameworks/bootstrap-sass-v3.2.0.scss";
@import "../../frameworks/bootstrap-sass-v3.3.5.scss";
18 changes: 17 additions & 1 deletion src/pivotal-ui/components/modals/modals.scss
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,22 @@
opacity: 1;
}

.modal-backdrop.in {
// Bootstrap defines the modal-backdrop opacity on the .modal-backdrop.in rule
// so we have to create more specific rules for our React transition group to
// actually see a transition :(

//Class created in React Animations
&.modal-backdrop-fade-enter, &.modal-backdrop-fade-leave {
@include transition(opacity .15s linear);
opacity: 0;
}

//Class created in React Animations
&.modal-backdrop-fade-enter-active {
opacity: $modal-backdrop-opacity;
}
}

/*doc
---
Expand Down Expand Up @@ -91,7 +107,7 @@ Modals bring desired content to the foreground and de-emphasize the rest of the
.modal {

.modal-dialog {
padding-top: 50px;
margin-top: 50px;
}
.modal-content {
border-radius: $modal-basic-content-border-radius;
Expand Down
6 changes: 6 additions & 0 deletions src/pivotal-ui/components/pui-variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,10 @@ $btn-disabled-color: $gray-5;

$btn-link-disabled-color: $gray-light !default;

$btn-border-radius-base: $border-radius-base;
$btn-border-radius-large: $border-radius-large;
$btn-border-radius-small: $border-radius-small;


// Forms
// -------------------------
Expand All @@ -462,6 +466,8 @@ $input-height-base: ($line-height-computed + ($padding-base-vertica
$input-height-large: (floor($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
$input-height-small: (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;

$form-group-margin-bottom: 15px;

$legend-color: $gray-dark !default;
$legend-border-color: #e5e5e5 !default;

Expand Down

0 comments on commit 4355e94

Please sign in to comment.