From bbda0ae528cd41c63b699874b961a0597b620d08 Mon Sep 17 00:00:00 2001 From: Tim Connor Date: Thu, 27 Apr 2017 13:26:46 -0700 Subject: [PATCH] tc - allow content within modals to autofocus --- src/components/Modal.js | 25 ++++++++++- stories/Modal.js | 24 +++++++++-- test/components/Modal.spec.js | 80 ++++++++++++++++++++++++++++++++++- 3 files changed, 123 insertions(+), 6 deletions(-) diff --git a/src/components/Modal.js b/src/components/Modal.js index ca01edff2..229c592a2 100644 --- a/src/components/Modal.js +++ b/src/components/Modal.js @@ -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, diff --git a/stories/Modal.js b/stories/Modal.js index 33465b52f..a843161e5 100644 --- a/stories/Modal.js +++ b/stories/Modal.js @@ -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'; @@ -26,5 +26,23 @@ storiesOf('Modal', module) - ) -); + )) + .addWithInfo('With content focus', () => ( + + {}}>Modal title + + This input should have focus: + + + + + + + + + )); diff --git a/test/components/Modal.spec.js b/test/components/Modal.spec.js index a65fc5af1..c6c028f6b 100644 --- a/test/components/Modal.spec.js +++ b/test/components/Modal.spec.js @@ -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('', () => { - const component = mount(); +const noop = () => {}; + +describe.only('', () => { + 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(); assert(component); }); + + context('when autoFocus="true"', () => { + it('sets focus to the modal content', () => { + const originalActiveElement = document.activeElement; + component = mount( + + should not have focus + + ); + + // 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( + + should not have focus + + ); + + // 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( + + should have focus + + ); + + // 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); + }); + }); });