Skip to content

Commit

Permalink
tc - allow content within modals to autofocus
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Connor committed Apr 27, 2017
1 parent 2446a97 commit bbda0ae
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 6 deletions.
25 changes: 24 additions & 1 deletion src/components/Modal.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
import { Modal } from 'reactstrap';
import { Modal as ReactstrapModal } from 'reactstrap';

/**
* TODO
* As of 04/27/2017 the reactstrap Modal class will autofocus itself upon opening, preventing any
* elements within the modal from autofocusing.
*
* There is a PR open with a fix here https://github.com/reactstrap/reactstrap/pull/389 that solves
* the problem by allowing users to pass autofocus={false} to Modals. When the PR has been merged
* we can remove the togglePortal override below.
*/
class Modal extends ReactstrapModal {
togglePortal() {
if (this.props.isOpen) {
// See https://github.com/reactstrap/reactstrap/pull/389/files#diff-3ddc036af206541151e86f03cfc0c0eeR113
if (this.props.autoFocus !== false) {
this._focus = true;
}
this.show();
} else {
this.hide();
}
}
}

Modal.defaultProps = {
...Modal.defaultProps,
Expand Down
24 changes: 21 additions & 3 deletions stories/Modal.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Button, ButtonToolbar, Modal, ModalHeader, ModalBody, ModalFooter } from '../src';
import { Button, ButtonToolbar, Modal, ModalHeader, ModalBody, ModalFooter, Input } from '../src';
import { storiesOf } from '@kadira/storybook';
import { boolean, select } from '@kadira/storybook-addon-knobs';

Expand All @@ -26,5 +26,23 @@ storiesOf('Modal', module)
</ButtonToolbar>
</ModalFooter>
</Modal>
)
);
))
.addWithInfo('With content focus', () => (
<Modal
isOpen={boolean('isOpen', true)}
backdrop={boolean('backdrop', true)}
size={select('size', [null, 'sm', 'md', 'lg'], null)}
autoFocus={false}
>
<ModalHeader toggle={() => {}}>Modal title</ModalHeader>
<ModalBody>
This input should have focus: <Input autoFocus />
</ModalBody>
<ModalFooter>
<ButtonToolbar>
<Button color="primary">Do Something</Button>
<Button>Cancel</Button>
</ButtonToolbar>
</ModalFooter>
</Modal>
));
80 changes: 78 additions & 2 deletions test/components/Modal.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,88 @@ import 'jsdom-global/register';
import React from 'react';
import assert from 'assert';
import { mount } from 'enzyme';
import { Button } from 'reactstrap';

import { Modal } from '../../src';

describe('<Modal />', () => {
const component = mount(<Modal />);
const noop = () => {};

describe.only('<Modal />', () => {
let component;

afterEach(done => {
if (component && component.prop('isOpen')) {
component.setProps({ isOpen: false });
const interval = setInterval(() => {
if (!document.getElementsByClassName('modal').length) {
clearInterval(interval);
component = null;
done();
}
}, 100);
} else {
done();
}
});

it('should render correctly', () => {
component = mount(<Modal toggle={noop} />);
assert(component);
});

context('when autoFocus="true"', () => {
it('sets focus to the modal content', () => {
const originalActiveElement = document.activeElement;
component = mount(
<Modal isOpen={false} toggle={noop}>
<Button id="button">This button</Button> should not have focus
</Modal>
);

// After mounting the active element should not have changed
assert.equal(document.activeElement, originalActiveElement);

component.setProps({ isOpen: true });

// Now the modal is open the original focused element should still maintain focus
const content = document.getElementsByClassName('modal')[0];
assert.equal(document.activeElement, content);
});
});

context('when autoFocus="false"', () => {
it('leaves focus as-is if elements within the modal are not autofocus', () => {
const originalActiveElement = document.activeElement;
component = mount(
<Modal isOpen={false} autoFocus={false} toggle={noop}>
<Button id="button">This button</Button> should not have focus
</Modal>
);

// After mounting the active element should not have changed
assert.equal(document.activeElement, originalActiveElement);

component.setProps({ isOpen: true });

// Now the modal is open the original focused element should still maintain focus
assert.equal(document.activeElement, originalActiveElement);
});

it('allows elements within the modal to have focus', () => {
const originalActiveElement = document.activeElement;
component = mount(
<Modal isOpen={false} autoFocus={false} toggle={noop}>
<Button id="button" autoFocus>This button</Button> should have focus
</Modal>
);

// After mounting the active element should not have changed
assert.equal(document.activeElement, originalActiveElement);

component.setProps({ isOpen: true });

// Now the modal is open the button should have focus
assert.equal('button', document.activeElement.id);
});
});
});

0 comments on commit bbda0ae

Please sign in to comment.