diff --git a/src/components/Modal/Modal.jsx b/src/components/Modal/Modal.jsx
index b152754b..431486d8 100644
--- a/src/components/Modal/Modal.jsx
+++ b/src/components/Modal/Modal.jsx
@@ -1,9 +1,17 @@
import PropTypes from 'prop-types';
-import React, { useRef } from 'react';
+import React, {
+ useCallback,
+ useEffect,
+ useRef,
+} from 'react';
import { createPortal } from 'react-dom';
import { withGlobalProps } from '../../provider';
import { transferProps } from '../_helpers/transferProps';
import { classNames } from '../../utils/classNames';
+import { dialogOnCancelHandler } from './_helpers/dialogOnCancelHandler';
+import { dialogOnClickHandler } from './_helpers/dialogOnClickHandler';
+import { dialogOnCloseHandler } from './_helpers/dialogOnCloseHandler';
+import { dialogOnKeyDownHandler } from './_helpers/dialogOnKeyDownHandler';
import { getPositionClassName } from './_helpers/getPositionClassName';
import { getSizeClassName } from './_helpers/getSizeClassName';
import { useModalFocus } from './_hooks/useModalFocus';
@@ -12,41 +20,30 @@ import styles from './Modal.module.scss';
const preRender = (
children,
- childrenWrapperRef,
- closeButtonRef,
+ dialogRef,
position,
- restProps,
size,
+ events,
+ restProps,
) => (
-
{
- e.preventDefault();
- if (closeButtonRef?.current != null) {
- closeButtonRef.current.click();
- }
- }}
- role="presentation"
+
+ {children}
+
);
export const Modal = ({
+ allowCloseOnBackdropClick,
+ allowCloseOnEscapeKey,
+ allowPrimaryActionOnEnterKey,
autoFocus,
children,
closeButtonRef,
@@ -57,42 +54,66 @@ export const Modal = ({
size,
...restProps
}) => {
- const childrenWrapperRef = useRef();
+ const dialogRef = useRef();
- useModalFocus(
- autoFocus,
- childrenWrapperRef,
- primaryButtonRef,
- closeButtonRef,
- );
+ useEffect(() => {
+ dialogRef.current.showModal();
+ }, []);
+ useModalFocus(allowPrimaryActionOnEnterKey, autoFocus, dialogRef, primaryButtonRef);
useModalScrollPrevention(preventScrollUnderneath);
+ const onCancel = useCallback(
+ (e) => dialogOnCancelHandler(e, closeButtonRef),
+ [closeButtonRef],
+ );
+ const onClick = useCallback(
+ (e) => dialogOnClickHandler(e, closeButtonRef, dialogRef, allowCloseOnBackdropClick),
+ [allowCloseOnBackdropClick, closeButtonRef, dialogRef],
+ );
+ const onClose = useCallback(
+ (e) => dialogOnCloseHandler(e, closeButtonRef),
+ [closeButtonRef],
+ );
+ const onKeyDown = useCallback(
+ (e) => dialogOnKeyDownHandler(e, closeButtonRef, allowCloseOnEscapeKey),
+ [allowCloseOnEscapeKey, closeButtonRef],
+ );
+ const events = {
+ onCancel,
+ onClick,
+ onClose,
+ onKeyDown,
+ };
+
if (portalId === null) {
return preRender(
children,
- childrenWrapperRef,
- closeButtonRef,
+ dialogRef,
position,
- restProps,
size,
+ events,
+ restProps,
);
}
return createPortal(
preRender(
children,
- childrenWrapperRef,
- closeButtonRef,
+ dialogRef,
position,
- restProps,
size,
+ events,
+ restProps,
),
document.getElementById(portalId),
);
};
Modal.defaultProps = {
+ allowCloseOnBackdropClick: true,
+ allowCloseOnEscapeKey: true,
+ allowPrimaryActionOnEnterKey: true,
autoFocus: true,
children: null,
closeButtonRef: null,
@@ -104,6 +125,18 @@ Modal.defaultProps = {
};
Modal.propTypes = {
+ /**
+ * If `true`, the `Modal` can be closed by clicking on the backdrop.
+ */
+ allowCloseOnBackdropClick: PropTypes.bool,
+ /**
+ * If `true`, the `Modal` can be closed by pressing the Escape key.
+ */
+ allowCloseOnEscapeKey: PropTypes.bool,
+ /**
+ * If `true`, the `Modal` can be submitted by pressing the Enter key.
+ */
+ allowPrimaryActionOnEnterKey: PropTypes.bool,
/**
* If `true`, focus the first input element in the `Modal`, or primary button (referenced by the `primaryButtonRef`
* prop), or other focusable element when the `Modal` is opened. If there are none or `autoFocus` is set to `false`,
@@ -121,7 +154,7 @@ Modal.propTypes = {
*/
children: PropTypes.node,
/**
- * Reference to close button element. It is used to close modal when Escape key is pressed or the backdrop is clicked.
+ * Reference to close button element. It is used to close modal when Escape key is pressed.
*/
closeButtonRef: PropTypes.shape({
// eslint-disable-next-line react/forbid-prop-types
diff --git a/src/components/Modal/Modal.module.scss b/src/components/Modal/Modal.module.scss
index 95db9249..07697548 100644
--- a/src/components/Modal/Modal.module.scss
+++ b/src/components/Modal/Modal.module.scss
@@ -1,9 +1,15 @@
+// 1. Modal uses