Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat(modal): add optional return focus after close (#1424)
  • Loading branch information
Kamen Minkov authored and TheSharpieOne committed Mar 5, 2019
1 parent a590880 commit 33cfce6
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 4 deletions.
16 changes: 16 additions & 0 deletions docs/lib/Components/ModalsPage.js
Expand Up @@ -12,6 +12,7 @@ import ModalExternalExample from '../examples/ModalExternal';
import ModalCustomCloseIconExample from '../examples/ModalCustomCloseIcon';
import ModalCustomCloseButtonExample from '../examples/ModalCustomCloseButton';
import ModalDestructuringExample from '../examples/ModalDestructuring';
import ModalFocusAfterClose from '../examples/ModalFocusAfterClose';

const ModalBackdropExampleSource = require('!!raw-loader!../examples/ModalBackdrop');
const ModalCustomCloseButtonExampleSource = require('!!raw-loader!../examples/ModalCustomCloseButton');
Expand All @@ -22,6 +23,7 @@ const ModalExternalExampleSource = require('!!raw-loader!../examples/ModalExtern
const ModalFadelessExampleSource = require('!!raw-loader!../examples/ModalFadeless');
const ModalNestedExampleSource = require('!!raw-loader!../examples/ModalNested');
const ModalDestructuringExampleSource = require('!!raw-loader!../examples/ModalDestructuring');
const ModalFocusOnDestroyExampleSource = require('!!raw-loader!../examples/ModalFocusAfterClose');

const ModalsPage = () => {
return (
Expand Down Expand Up @@ -215,6 +217,20 @@ const ModalsPage = () => {
{ModalDestructuringExampleSource}
</PrismCode>
</pre>

<h4>Focus after close</h4>
<div className="docs-example">
<div className="btn-group">
<div className="btn">
<ModalFocusAfterClose />
</div>
</div>
</div>
<pre>
<PrismCode className="language-jsx">
{ModalFocusOnDestroyExampleSource}
</PrismCode>
</pre>
</div>
);
};
Expand Down
51 changes: 51 additions & 0 deletions docs/lib/examples/ModalFocusAfterClose.js
@@ -0,0 +1,51 @@
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */

import React from 'react';
import { Button, Modal, ModalBody, ModalFooter, Label, Input, FormGroup, Form } from 'reactstrap';

class ModalFocusAfterClose extends React.Component {
constructor() {
super();
this.state = {
open: false,
focusAfterClose: true
};
this.toggle = this.toggle.bind(this);
this.handleSelectChange = this.handleSelectChange.bind(this);
}

toggle() {
this.setState(({ open }) => ({ open: !open }));
}

handleSelectChange({target: { value }}) {
this.setState({ focusAfterClose: JSON.parse(value) });
}

render() {
return (
<div>
<Form inline onSubmit={(e) => e.preventDefault()}>
<FormGroup>
<Label for="focusAfterClose">Focus After Close</Label>
<Input className="mx-2" type="select" id="focusAfterClose" onChange={this.handleSelectChange}>
<option value="true">Yes</option>
<option value="false">No</option>
</Input>
</FormGroup>
<Button color="danger" onClick={this.toggle}>Open</Button>
</Form>
<Modal returnFocusAfterClose={this.state.focusAfterClose} isOpen={this.state.open}>
<ModalBody>
Observe the "Open" button. It will be focused after close when "returnFocusAfterClose" is true and will not be focused if "returnFocusAfterClose" is false.
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={this.toggle}>Close</Button>
</ModalFooter>
</Modal>
</div>
)
}
}

export default ModalFocusAfterClose;
16 changes: 12 additions & 4 deletions src/Modal.js
Expand Up @@ -54,7 +54,8 @@ const propTypes = {
PropTypes.string,
PropTypes.func,
]),
unmountOnClose: PropTypes.bool
unmountOnClose: PropTypes.bool,
returnFocusAfterClose: PropTypes.bool
};

const propsToOmit = Object.keys(propTypes);
Expand All @@ -77,7 +78,8 @@ const defaultProps = {
mountOnEnter: true,
timeout: TransitionTimeouts.Fade, // uses standard fade transition
},
unmountOnClose: true
unmountOnClose: true,
returnFocusAfterClose: true
};

class Modal extends React.Component {
Expand All @@ -93,6 +95,7 @@ class Modal extends React.Component {
this.handleTab = this.handleTab.bind(this);
this.onOpened = this.onOpened.bind(this);
this.onClosed = this.onClosed.bind(this);
this.manageFocusAfterClose = this.manageFocusAfterClose.bind(this);

this.state = {
isOpen: props.isOpen,
Expand Down Expand Up @@ -281,8 +284,13 @@ class Modal extends React.Component {
this._element = null;
}

this.manageFocusAfterClose();
}

manageFocusAfterClose() {
if (this._triggeringElement) {
if (this._triggeringElement.focus) this._triggeringElement.focus();
const { returnFocusAfterClose } = this.props;
if (this._triggeringElement.focus && returnFocusAfterClose) this._triggeringElement.focus();
this._triggeringElement = null;
}
}
Expand All @@ -294,7 +302,7 @@ class Modal extends React.Component {
const modalOpenClassNameRegex = new RegExp(`(^| )${modalOpenClassName}( |$)`);
document.body.className = document.body.className.replace(modalOpenClassNameRegex, ' ').trim();
}

this.manageFocusAfterClose();
Modal.openCount = Math.max(0, Modal.openCount - 1);

setScrollbarWidth(this._originalBodyPadding);
Expand Down

0 comments on commit 33cfce6

Please sign in to comment.