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

fix(Modal): Lock focus #41

Merged
merged 7 commits into from
May 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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>