diff --git a/docs/index.md b/docs/index.md index d3ddf032..4c621eba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -153,7 +153,16 @@ import ReactModal from 'react-modal'; contentRef={ setContentRef - /* Content ref callback. */}> + /* Content ref callback. */} + + overlayElement={ + (props, contentElement) =>
{contentElement}
+ /* Custom Overlay element. */} + + contentElement={ + (props, children) =>
{children}
+ /* Custom Content element. */} + >

Modal Content

``` diff --git a/specs/Modal.spec.js b/specs/Modal.spec.js index 4bd1fe2d..d13f1fe3 100644 --- a/specs/Modal.spec.js +++ b/specs/Modal.spec.js @@ -237,8 +237,8 @@ export default () => { it("supports id prop", () => { const modal = renderModal({ isOpen: true, id: "id" }); mcontent(modal) - .id.includes("id") - .should.be.ok(); + .id + .should.be.eql("id"); }); it("supports portalClassName", () => { @@ -256,6 +256,33 @@ export default () => { .should.be.ok(); }); + it("supports custom overlayElement", () => { + const overlayElement = (props, contentElement) => ( +
+ {contentElement} +
+ ); + + const modal = renderModal({ isOpen: true, overlayElement }); + const modalOverlay = moverlay(modal); + + modalOverlay.id.should.eql("custom"); + }); + + it("supports custom contentElement", () => { + const contentElement = (props, children) => ( +
+ {children} +
+ ); + + const modal = renderModal({ isOpen: true, contentElement }, "hello"); + const modalContent = mcontent(modal); + + modalContent.id.should.eql("custom"); + modalContent.textContent.should.be.eql("hello"); + }); + it("supports overlayClassName", () => { const modal = renderModal({ isOpen: true, diff --git a/src/components/Modal.js b/src/components/Modal.js index 79bc7734..9b4fa519 100644 --- a/src/components/Modal.js +++ b/src/components/Modal.js @@ -68,7 +68,10 @@ class Modal extends Component { contentLabel: PropTypes.string, shouldCloseOnEsc: PropTypes.bool, overlayRef: PropTypes.func, - contentRef: PropTypes.func + contentRef: PropTypes.func, + id: PropTypes.string, + overlayElement: PropTypes.func, + contentElement: PropTypes.func }; /* eslint-enable react/no-unused-prop-types */ @@ -84,7 +87,9 @@ class Modal extends Component { shouldCloseOnOverlayClick: true, shouldReturnFocusAfterClose: true, preventScroll: false, - parentSelector: () => document.body + parentSelector: () => document.body, + overlayElement: (props, contentEl) =>
{contentEl}
, + contentElement: (props, children) =>
{children}
}; static defaultStyles = { diff --git a/src/components/ModalPortal.js b/src/components/ModalPortal.js index 17768eae..c84a52f0 100644 --- a/src/components/ModalPortal.js +++ b/src/components/ModalPortal.js @@ -61,6 +61,8 @@ export default class ModalPortal extends Component { overlayRef: PropTypes.func, contentRef: PropTypes.func, id: PropTypes.string, + overlayElement: PropTypes.func, + contentElement: PropTypes.func, testId: PropTypes.string }; @@ -343,37 +345,40 @@ export default class ModalPortal extends Component { }, {}); render() { - const { id, className, overlayClassName, defaultStyles } = this.props; + const { id, className, overlayClassName, defaultStyles, children } = this.props; const contentStyles = className ? {} : defaultStyles.content; const overlayStyles = overlayClassName ? {} : defaultStyles.overlay; - return this.shouldBeClosed() ? null : ( -
-
- {this.props.children} -
-
- ); + if (this.shouldBeClosed()) { + return null; + } + + const overlayProps = { + ref: this.setOverlayRef, + className: this.buildClassName("overlay", overlayClassName), + style: { ...overlayStyles, ...this.props.style.overlay }, + onClick: this.handleOverlayOnClick, + onMouseDown: this.handleOverlayOnMouseDown + }; + + const contentProps = { + id, + ref: this.setContentRef, + style: { ...contentStyles, ...this.props.style.content }, + className: this.buildClassName("content", className), + tabIndex: "-1", + onKeyDown: this.handleKeyDown, + onMouseDown: this.handleContentOnMouseDown, + onMouseUp: this.handleContentOnMouseUp, + onClick: this.handleContentOnClick, + role: this.props.role, + "aria-label": this.props.contentLabel, + ...this.attributesFromObject("aria", this.props.aria || {}), + ...this.attributesFromObject("data", this.props.data || {}), + "data-testid": this.props.testId + }; + + const contentElement = this.props.contentElement(contentProps, children); + return this.props.overlayElement(overlayProps, contentElement); } }