Skip to content
This repository has been archived by the owner on Oct 6, 2020. It is now read-only.

Commit

Permalink
fix(Modal): Lock focus (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
Claire Hsu authored May 2, 2019
1 parent b2758f5 commit 9e7b7d3
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 8 deletions.
65 changes: 65 additions & 0 deletions src/Modal/Modal.dropdownExample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import Modal from './Modal';
import Button from '../Button';
import Input from '../Form/Input';
import Dropdown from '../Dropdown';

export default class ModalDropdownDemo extends React.Component {
state = {
isModalOpen: false,
};

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

onCancel = () => {
this.toggle();

setTimeout(() => {
alert('Oh no! It has been canceled.');
}, 500);
};

render() {
const { body, ...props } = this.props;

return (
<div>
<Dropdown placement="top" width={250} trigger={<Button variant="success">Open Dropdown</Button>}>
<Dropdown.Header title="Dropdown" />

<Dropdown.Body>
<Dropdown.SectionTitle>Section One</Dropdown.SectionTitle>
<Dropdown.Item onClick={this.toggle} as="button">
Open Modal
</Dropdown.Item>
</Dropdown.Body>

<Dropdown.Footer>Footer</Dropdown.Footer>
</Dropdown>

<Modal
open={this.state.isModalOpen}
onClose={this.toggle}
title="Example Dropdown Modal"
{...props}>
<Modal.Body>
<>
{body}
<Input autoFocus name="password" label="Password" />
</>
</Modal.Body>

<Modal.Footer>
<Button.Group justifyContent="flex-end">
<Button variant="gray" onClick={this.onCancel}>
Cancel
</Button>
</Button.Group>
</Modal.Footer>
</Modal>
</div>
);
}
}
19 changes: 15 additions & 4 deletions src/Modal/Modal.example.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import Modal from './Modal';
import Button from '../Button';
import Box from '../Box';
import Input from '../Form/Input';

export default class ModalDemo extends React.Component {
state = {
Expand Down Expand Up @@ -32,11 +32,22 @@ export default class ModalDemo extends React.Component {
<div>
<Button onClick={this.toggle}>Open Modal</Button>

<Modal open={this.state.isModalOpen} onClose={this.toggle} title="Example Modal" {...props}>
<Modal
open={this.state.isModalOpen}
onClose={this.toggle}
title="Example Modal"
{...props}>
<Modal.Body>
{body}
<>
{body}
<Input autoFocus name="password" label="Password" />
</>

<Modal open={this.state.isModalTwoOpen} onClose={this.toggleModalTwo} title="Example Modal Two" {...props}>
<Modal
open={this.state.isModalTwoOpen}
onClose={this.toggleModalTwo}
title="Example Modal Two"
{...props}>
<Modal.Body>{bodyTwo}</Modal.Body>

<Modal.Footer>
Expand Down
11 changes: 7 additions & 4 deletions src/Modal/Modal.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { keyframes, css } from 'styled-components';
import * as animations from 'react-animations';
import { Transition } from 'react-transition-group';
import FocusLock from 'react-focus-lock';
import Portal from '../Portal';
import Flex from '../Flex';
import Box from '../Box';
Expand Down Expand Up @@ -105,10 +106,12 @@ function Modal({ children, title, animationDuration, showClose, onClose, open, .
<Transition in={isOpen} timeout={animationDuration}>
{state => (
<Backdrop transitionState={state} onClick={handleBackdropClick}>
<ModalContent transitionState={state} onClick={handleContentClick} {...props}>
{title && <Modal.Header title={title} showClose={showClose} />}
{children}
</ModalContent>
<FocusLock lockProps={{ style: { maxHeight: '100%' } }} disabled={!isOpen}>
<ModalContent transitionState={state} onClick={handleContentClick} {...props}>
{title && <Modal.Header title={title} showClose={showClose} />}
{children}
</ModalContent>
</FocusLock>
</Backdrop>
)}
</Transition>
Expand Down
9 changes: 9 additions & 0 deletions src/Modal/Modal.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ name: Modal
import { Playground, PropsTable } from 'docz'
import Modal from './Modal'
import ModalExample from './Modal.example'
import ModalDropdownExample from './Modal.dropdownexample'

# Modal

Expand All @@ -29,3 +30,11 @@ When modals become too long for the user’s viewport or device, they scroll ind
<Playground>
<ModalExample body={<div>{new Array(50).fill(null).map((_, i) => <p key={i}>I'm really long annoying content.</p>)}</div>} />
</Playground>

## Handling Dropdown Triggered Content

When modals are triggered by dropdowns with returnFocus set to true, modals still receive focus.

<Playground>
<ModalDropdownExample body="I'm triggered by a dropdown" />
</Playground>

0 comments on commit 9e7b7d3

Please sign in to comment.