diff --git a/docs/lib/Components/ModalsPage.js b/docs/lib/Components/ModalsPage.js index 275b79813..4d6d63e77 100644 --- a/docs/lib/Components/ModalsPage.js +++ b/docs/lib/Components/ModalsPage.js @@ -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'; @@ -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'); @@ -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 @@ -114,6 +122,33 @@ const ModalsPage = () => { +

Fullscreen Modals

+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+        
+          {ModalFullscreenExampleSource}
+        
+      
+

Backdrop

diff --git a/docs/lib/examples/ModalFullscreen.js b/docs/lib/examples/ModalFullscreen.js new file mode 100644 index 000000000..6ae958416 --- /dev/null +++ b/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 ( +
+ + + Modal title + + 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. + + + {' '} + + + +
+ ); +} + +export default ModalFullscreenExample; diff --git a/src/Modal.js b/src/Modal.js index a31156542..91e5ca566 100644 --- a/src/Modal.js +++ b/src/Modal.js @@ -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, @@ -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) => { diff --git a/src/__tests__/Modal.spec.js b/src/__tests__/Modal.spec.js index 47ae15e5f..27afb0ef7 100644 --- a/src/__tests__/Modal.spec.js +++ b/src/__tests__/Modal.spec.js @@ -168,6 +168,36 @@ describe('Modal', () => { wrapper.unmount(); }); + describe('fullscreen', () => { + it('should render non fullscreen by default', () => { + const wrapper = didMount(Yo!); + 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(Yo!); + 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(Yo!); + 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( diff --git a/types/lib/Modal.d.ts b/types/lib/Modal.d.ts index 0b7eb5467..465535848 100644 --- a/types/lib/Modal.d.ts +++ b/types/lib/Modal.d.ts @@ -25,6 +25,7 @@ export interface ModalProps extends React.HTMLAttributes { backdropTransition?: FadeProps; modalTransition?: FadeProps; centered?: boolean; + fullscreen?: boolean | 'sm' | 'md' | 'lg' | 'xl'; external?: React.ReactNode; labelledBy?: string; unmountOnClose?: boolean;