2023-05-19 22:20:15 +02:00
|
|
|
import React, { forwardRef, useRef, useEffect } from 'react';
|
2023-03-23 01:17:19 +01:00
|
|
|
import classnames from 'classnames';
|
|
|
|
|
|
|
|
import {
|
|
|
|
BackgroundColor,
|
|
|
|
BorderRadius,
|
2023-07-26 17:48:31 +02:00
|
|
|
BlockSize,
|
|
|
|
Display,
|
2023-05-19 22:20:15 +02:00
|
|
|
JustifyContent,
|
|
|
|
AlignItems,
|
2023-03-23 01:17:19 +01:00
|
|
|
} from '../../../helpers/constants/design-system';
|
|
|
|
|
2023-07-26 17:48:31 +02:00
|
|
|
import { Box, ModalFocus, useModalContext } from '..';
|
2023-05-19 22:20:15 +02:00
|
|
|
|
2023-03-23 01:17:19 +01:00
|
|
|
import { ModalContentProps, ModalContentSize } from './modal-content.types';
|
|
|
|
|
2023-05-19 22:20:15 +02:00
|
|
|
export const ModalContent = forwardRef(
|
|
|
|
(
|
|
|
|
{
|
|
|
|
className = '',
|
|
|
|
children,
|
|
|
|
size = ModalContentSize.Sm,
|
|
|
|
modalDialogProps,
|
|
|
|
...props
|
|
|
|
}: ModalContentProps,
|
|
|
|
ref: React.Ref<HTMLElement>,
|
|
|
|
) => {
|
|
|
|
const {
|
|
|
|
onClose,
|
|
|
|
isClosedOnEscapeKey,
|
|
|
|
isClosedOnOutsideClick,
|
|
|
|
initialFocusRef,
|
|
|
|
finalFocusRef,
|
|
|
|
restoreFocus,
|
|
|
|
autoFocus,
|
|
|
|
} = useModalContext();
|
|
|
|
const modalDialogRef = useRef<HTMLElement>(null);
|
|
|
|
const handleEscKey = (event: KeyboardEvent) => {
|
|
|
|
if (isClosedOnEscapeKey && event.key === 'Escape') {
|
|
|
|
onClose();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleClickOutside = (event: MouseEvent) => {
|
2023-07-05 19:11:49 +02:00
|
|
|
// Popover should be launched from within Modal but
|
|
|
|
// the Popover containing element is a sibling to modal,
|
|
|
|
// so this is required to ensure `onClose` isn't triggered
|
|
|
|
// when clicking on a popover item
|
|
|
|
if (
|
|
|
|
isClosedOnOutsideClick &&
|
|
|
|
(event.target as HTMLElement).closest('.mm-popover')
|
|
|
|
) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-19 22:20:15 +02:00
|
|
|
if (
|
|
|
|
isClosedOnOutsideClick &&
|
|
|
|
modalDialogRef?.current &&
|
|
|
|
!modalDialogRef.current.contains(event.target as Node)
|
|
|
|
) {
|
|
|
|
onClose();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
document.addEventListener('keydown', handleEscKey);
|
|
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
document.removeEventListener('keydown', handleEscKey);
|
|
|
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
return (
|
|
|
|
<ModalFocus
|
|
|
|
initialFocusRef={initialFocusRef}
|
|
|
|
finalFocusRef={finalFocusRef}
|
|
|
|
restoreFocus={restoreFocus}
|
|
|
|
autoFocus={autoFocus}
|
|
|
|
>
|
|
|
|
<Box
|
|
|
|
className={classnames('mm-modal-content', className)}
|
|
|
|
ref={ref}
|
2023-07-26 17:48:31 +02:00
|
|
|
display={Display.Flex}
|
|
|
|
width={BlockSize.Screen}
|
|
|
|
height={BlockSize.Screen}
|
2023-05-19 22:20:15 +02:00
|
|
|
justifyContent={JustifyContent.center}
|
|
|
|
alignItems={AlignItems.flexStart}
|
|
|
|
padding={4}
|
|
|
|
{...props}
|
|
|
|
>
|
|
|
|
<Box
|
|
|
|
className={classnames(
|
|
|
|
'mm-modal-content__dialog',
|
|
|
|
`mm-modal-content__dialog--size-${size}`,
|
|
|
|
)}
|
|
|
|
as="section"
|
|
|
|
role="dialog"
|
|
|
|
aria-modal="true"
|
|
|
|
backgroundColor={BackgroundColor.backgroundDefault}
|
|
|
|
borderRadius={BorderRadius.LG}
|
2023-07-26 17:48:31 +02:00
|
|
|
width={BlockSize.Full}
|
|
|
|
marginTop={[null, 8, 12]}
|
|
|
|
marginBottom={[null, 8, 12]}
|
2023-05-19 22:20:15 +02:00
|
|
|
padding={4}
|
|
|
|
ref={modalDialogRef}
|
|
|
|
{...modalDialogProps}
|
|
|
|
>
|
|
|
|
{children}
|
|
|
|
</Box>
|
|
|
|
</Box>
|
|
|
|
</ModalFocus>
|
|
|
|
);
|
|
|
|
},
|
2023-03-23 01:17:19 +01:00
|
|
|
);
|