diff --git a/packages/patternfly-4/react-core/src/components/Modal/Modal.js b/packages/patternfly-4/react-core/src/components/Modal/Modal.js index d7a436767e1..abac2922e44 100644 --- a/packages/patternfly-4/react-core/src/components/Modal/Modal.js +++ b/packages/patternfly-4/react-core/src/components/Modal/Modal.js @@ -2,6 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import ModalContent from './ModalContent'; +import safeHTMLElement from '../../internal/safeHTMLElement'; import { canUseDOM } from 'exenv'; import { KEY_CODES } from '../../internal/constants'; import { css } from '@patternfly/react-styles'; @@ -23,7 +24,9 @@ const propTypes = { /** A callback for when the close button is clicked */ onClose: PropTypes.func, /** Creates a large version of the Modal */ - isLarge: PropTypes.bool + isLarge: PropTypes.bool, + /** React application root element */ + reactRoot: PropTypes.instanceOf(safeHTMLElement).isRequired }; const defaultProps = { @@ -62,8 +65,10 @@ class Modal extends React.Component { componentDidUpdate() { if (this.props.isOpen) { document.body.classList.add(css(styles.backdropOpen)); + this.props.reactRoot.setAttribute('aria-hidden', true); } else { document.body.classList.remove(css(styles.backdropOpen)); + this.props.reactRoot.removeAttribute('aria-hidden'); } } @@ -73,6 +78,8 @@ class Modal extends React.Component { } render() { + const { reactRoot, ...props } = this.props; + if (!canUseDOM) { return null; } @@ -81,7 +88,7 @@ class Modal extends React.Component { this.container = document.createElement('div'); } - return ReactDOM.createPortal(, this.container); + return ReactDOM.createPortal(, this.container); } } diff --git a/packages/patternfly-4/react-core/src/components/Modal/Modal.test.js b/packages/patternfly-4/react-core/src/components/Modal/Modal.test.js index 398b851c7ac..10d5ccd5e1f 100644 --- a/packages/patternfly-4/react-core/src/components/Modal/Modal.test.js +++ b/packages/patternfly-4/react-core/src/components/Modal/Modal.test.js @@ -14,7 +14,8 @@ const props = { title: 'Modal', onClose: jest.fn(), isOpen: false, - children: 'modal content' + children: 'modal content', + reactRoot: document.createElement('div') }; test('Modal creates a container element once for div', () => { diff --git a/packages/patternfly-4/react-core/src/components/Modal/ModalContent.js b/packages/patternfly-4/react-core/src/components/Modal/ModalContent.js index d22930b4658..68535a49a3b 100644 --- a/packages/patternfly-4/react-core/src/components/Modal/ModalContent.js +++ b/packages/patternfly-4/react-core/src/components/Modal/ModalContent.js @@ -1,5 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; +import FocusTrap from 'focus-trap-react'; import ModalBoxBody from './ModalBoxBody'; import ModalBoxHeader from './ModalBoxHeader'; import ModalBoxHCloseButton from './ModalBoxCloseButton'; @@ -47,14 +48,16 @@ const ModalContent = ({ children, className, isOpen, title, hideTitle, actions, return ( - - - {modalBoxHeader} - - {children} - - {modalBoxFooter} - + + + + {modalBoxHeader} + + {children} + + {modalBoxFooter} + + ); diff --git a/packages/patternfly-4/react-core/src/components/Modal/__snapshots__/ModalContent.test.js.snap b/packages/patternfly-4/react-core/src/components/Modal/__snapshots__/ModalContent.test.js.snap index 48784b5434b..70fc58d1425 100644 --- a/packages/patternfly-4/react-core/src/components/Modal/__snapshots__/ModalContent.test.js.snap +++ b/packages/patternfly-4/react-core/src/components/Modal/__snapshots__/ModalContent.test.js.snap @@ -8,36 +8,48 @@ exports[`Modal Content Test isOpen 1`] = ` className="" component="div" > - - - - - Test Modal Content title - - - - This is a ModalBox header - - - - - - + + + + Test Modal Content title + + + + This is a ModalBox header + + + + + + + `; diff --git a/packages/patternfly-4/react-core/src/components/Modal/examples/LargeModal.js b/packages/patternfly-4/react-core/src/components/Modal/examples/LargeModal.js index 9a2a0d9ab90..4efa2795967 100644 --- a/packages/patternfly-4/react-core/src/components/Modal/examples/LargeModal.js +++ b/packages/patternfly-4/react-core/src/components/Modal/examples/LargeModal.js @@ -33,6 +33,7 @@ class LargeModal extends React.Component { Confirm ]} + reactRoot={document.querySelector('#___gatsby')} > Lorem ipsum dolor sit amet, consectetur adipiscing 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 diff --git a/packages/patternfly-4/react-core/src/components/Modal/examples/SimpleModal.js b/packages/patternfly-4/react-core/src/components/Modal/examples/SimpleModal.js index 80b465e58b9..009a17ca6f4 100644 --- a/packages/patternfly-4/react-core/src/components/Modal/examples/SimpleModal.js +++ b/packages/patternfly-4/react-core/src/components/Modal/examples/SimpleModal.js @@ -32,6 +32,7 @@ class SimpleModal extends React.Component { Confirm ]} + reactRoot={document.querySelector('#___gatsby')} > Lorem ipsum dolor sit amet, consectetur adipiscing 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 diff --git a/packages/patternfly-4/react-core/src/internal/safeHTMLElement.js b/packages/patternfly-4/react-core/src/internal/safeHTMLElement.js new file mode 100644 index 00000000000..3944bfa6a3d --- /dev/null +++ b/packages/patternfly-4/react-core/src/internal/safeHTMLElement.js @@ -0,0 +1,4 @@ +// https://github.com/reactjs/react-modal/blob/master/src/helpers/safeHTMLElement.js +import { canUseDOM } from 'exenv'; + +export default (canUseDOM ? window.HTMLElement : {});