Skip to content

Commit

Permalink
feat(modal): add fullscreen option to Modal component
Browse files Browse the repository at this point in the history
  • Loading branch information
Phoebe Gao authored and phwebi committed Oct 27, 2021
1 parent 4dc1dcd commit a580f23
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 0 deletions.
35 changes: 35 additions & 0 deletions docs/lib/Components/ModalsPage.js
Expand Up @@ -8,6 +8,7 @@ import ModalBackdropExample from '../examples/ModalBackdrop';
import ModalNestedExample from '../examples/ModalNested';
import ModalCustomTimeoutExample from '../examples/ModalCustomTimeout';
import ModalFadelessExample from '../examples/ModalFadeless';
import ModalFullscreenExample from '../examples/ModalFullscreen';
import ModalExternalExample from '../examples/ModalExternal';
import ModalCustomCloseIconExample from '../examples/ModalCustomCloseIcon';
import ModalCustomCloseButtonExample from '../examples/ModalCustomCloseButton';
Expand All @@ -21,6 +22,8 @@ const ModalCustomTimeoutExampleSource = require('!!raw-loader!../examples/ModalC
const ModalExampleSource = require('!!raw-loader!../examples/Modal');
const ModalExternalExampleSource = require('!!raw-loader!../examples/ModalExternal');
const ModalFadelessExampleSource = require('!!raw-loader!../examples/ModalFadeless');
const ModalFullscreenExampleSource = require('!!raw-loader!../examples/ModalFullscreen');

const ModalNestedExampleSource = require('!!raw-loader!../examples/ModalNested');
const ModalDestructuringExampleSource = require('!!raw-loader!../examples/ModalDestructuring');
const ModalFocusOnDestroyExampleSource = require('!!raw-loader!../examples/ModalFocusAfterClose');
Expand Down Expand Up @@ -56,6 +59,11 @@ const ModalsPage = () => {
autoFocus: PropTypes.bool,
// if modal should be centered vertically in viewport
centered: PropTypes.bool,
// if modal should be fullscreen
fullscreen: PropTypes.oneOfType([
PropTypes.bool, // always fullscreen
PropTypes.oneOf(['sm', 'md', 'lg', 'xl']), // fullscreen below breakpoints
]),
// corresponds to bootstrap's modal sizes, ie. 'lg' or 'sm'
size: PropTypes.string,
// callback for toggling isOpen in the controlling component
Expand Down Expand Up @@ -114,6 +122,33 @@ const ModalsPage = () => {
</PrismCode>
</pre>

<h4>Fullscreen Modals</h4>

<div className="docs-example">
<div className="btn-group">
<div className="btn">
<ModalFullscreenExample buttonLabel="Full screen" fullscreen />
</div>
<div className="btn">
<ModalFullscreenExample buttonLabel="Full screen below sm" fullscreen="sm" />
</div>
<div className="btn">
<ModalFullscreenExample buttonLabel="Full screen below md" fullscreen="md" />
</div>
<div className="btn">
<ModalFullscreenExample buttonLabel="Full screen below lg" fullscreen="lg" />
</div>
<div className="btn">
<ModalFullscreenExample buttonLabel="Full screen below xl" fullscreen="xl" />
</div>
</div>
</div>
<pre>
<PrismCode className="language-jsx">
{ModalFullscreenExampleSource}
</PrismCode>
</pre>

<h4>Backdrop</h4>
<div className="docs-example">
<div className="btn-group">
Expand Down
30 changes: 30 additions & 0 deletions docs/lib/examples/ModalFullscreen.js
@@ -0,0 +1,30 @@
/* eslint react/no-multi-comp: 0, react/prop-types: 0 */

import React, { useState } from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';

const ModalFullscreenExample = (props) => {
const { buttonLabel, fullscreen } = props;

const [modal, setModal] = useState(false);

const toggle = () => setModal(!modal);

return (
<div>
<Button color="danger" onClick={toggle}>{buttonLabel}</Button>
<Modal isOpen={modal} toggle={toggle} fullscreen={fullscreen}>
<ModalHeader toggle={toggle}>Modal title</ModalHeader>
<ModalBody>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={toggle}>Do Something</Button>{' '}
<Button color="secondary" onClick={toggle}>Cancel</Button>
</ModalFooter>
</Modal>
</div>
);
}

export default ModalFullscreenExample;
6 changes: 6 additions & 0 deletions src/Modal.js
Expand Up @@ -24,6 +24,10 @@ const propTypes = {
isOpen: PropTypes.bool,
autoFocus: PropTypes.bool,
centered: PropTypes.bool,
fullscreen: PropTypes.oneOfType([
PropTypes.bool,
PropTypes.oneOf(['sm', 'md', 'lg', 'xl']),
]),
scrollable: PropTypes.bool,
size: PropTypes.string,
toggle: PropTypes.func,
Expand Down Expand Up @@ -389,6 +393,8 @@ class Modal extends React.Component {
[`modal-${this.props.size}`]: this.props.size,
[`${dialogBaseClass}-centered`]: this.props.centered,
[`${dialogBaseClass}-scrollable`]: this.props.scrollable,
'modal-fullscreen': this.props.fullscreen === true,
[`modal-fullscreen-${this.props.fullscreen}-down`]: (typeof this.props.fullscreen) === 'string',
}), this.props.cssModule)}
role="document"
ref={(c) => {
Expand Down
30 changes: 30 additions & 0 deletions src/__tests__/Modal.spec.js
Expand Up @@ -168,6 +168,36 @@ describe('Modal', () => {
wrapper.unmount();
});

describe('fullscreen', () => {
it('should render non fullscreen by default', () => {
const wrapper = didMount(<Modal isOpen toggle={toggle}>Yo!</Modal>);
jest.runTimersToTime(300);

expect(document.getElementsByClassName('modal-dialog').length).toBe(1);
expect(document.getElementsByClassName('modal-fullscreen').length).toBe(0);
wrapper.unmount();
});

it('should always render fullscreen if true', () => {
const wrapper = didMount(<Modal isOpen toggle={toggle} fullscreen>Yo!</Modal>);
jest.runTimersToTime(300);

expect(document.getElementsByClassName('modal-dialog').length).toBe(1);
expect(document.getElementsByClassName('modal-fullscreen').length).toBe(1);
wrapper.unmount();
});

it('should render fullscreen below breakpoint if breakpoint is provided', () => {
const wrapper = didMount(<Modal isOpen toggle={toggle} fullscreen="lg">Yo!</Modal>);
jest.runTimersToTime(300);

expect(document.getElementsByClassName('modal-dialog').length).toBe(1);
expect(document.getElementsByClassName('modal-fullscreen').length).toBe(0);
expect(document.getElementsByClassName('modal-fullscreen-lg-down').length).toBe(1);
wrapper.unmount();
});
});

it('should render with additional props if provided', () => {
isOpen = true;
const wrapper = didMount(
Expand Down
1 change: 1 addition & 0 deletions types/lib/Modal.d.ts
Expand Up @@ -25,6 +25,7 @@ export interface ModalProps extends React.HTMLAttributes<HTMLElement> {
backdropTransition?: FadeProps;
modalTransition?: FadeProps;
centered?: boolean;
fullscreen?: boolean | 'sm' | 'md' | 'lg' | 'xl';
external?: React.ReactNode;
labelledBy?: string;
unmountOnClose?: boolean;
Expand Down

0 comments on commit a580f23

Please sign in to comment.