Use TypeScript for modal
[MAILPOET-2777]
This commit is contained in:
@@ -1,13 +1,19 @@
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
type Props = {
|
||||
fullScreen?: boolean,
|
||||
role?: string,
|
||||
className?: string,
|
||||
children: React.ReactNode,
|
||||
};
|
||||
|
||||
function ModalFrame({
|
||||
children,
|
||||
className,
|
||||
role,
|
||||
fullScreen,
|
||||
}) {
|
||||
}: Props) {
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
@@ -16,20 +22,13 @@ function ModalFrame({
|
||||
className
|
||||
)}
|
||||
role={role}
|
||||
tabIndex="-1"
|
||||
tabIndex={-1}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ModalFrame.propTypes = {
|
||||
fullScreen: PropTypes.bool,
|
||||
role: PropTypes.string,
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
ModalFrame.defaultProps = {
|
||||
role: 'dialog',
|
||||
fullScreen: false,
|
@@ -1,9 +1,12 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import Heading from 'common/typography/heading/heading';
|
||||
|
||||
const ModalHeader = ({ title }) => (
|
||||
type Props = {
|
||||
title: string,
|
||||
};
|
||||
|
||||
const ModalHeader = ({ title }: Props) => (
|
||||
<div className="mailpoet-modal-header">
|
||||
<Heading level={3}>
|
||||
{ title }
|
||||
@@ -11,8 +14,4 @@ const ModalHeader = ({ title }) => (
|
||||
</div>
|
||||
);
|
||||
|
||||
ModalHeader.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default ModalHeader;
|
@@ -1,11 +1,23 @@
|
||||
import React from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import ModalFrame from './frame.jsx';
|
||||
import ModalHeader from './header.jsx';
|
||||
import ModalOverlay from './overlay.jsx';
|
||||
import closeIcon from './close_icon';
|
||||
import ModalFrame from './frame';
|
||||
import ModalHeader from './header';
|
||||
import ModalOverlay from './overlay';
|
||||
import ModalCloseIcon from './close_icon';
|
||||
|
||||
type Props = {
|
||||
isDismissible?: boolean,
|
||||
contentClassName?: string,
|
||||
overlayClassName?: string,
|
||||
title?: string,
|
||||
onRequestClose?: () => void,
|
||||
fullScreen?: boolean,
|
||||
shouldCloseOnEsc?: boolean,
|
||||
shouldCloseOnClickOutside?: boolean,
|
||||
role?: string,
|
||||
children: React.ReactNode,
|
||||
};
|
||||
|
||||
function Modal({
|
||||
onRequestClose,
|
||||
@@ -18,7 +30,7 @@ function Modal({
|
||||
contentClassName,
|
||||
overlayClassName,
|
||||
fullScreen,
|
||||
}) {
|
||||
}: Props) {
|
||||
return createPortal(
|
||||
<ModalOverlay
|
||||
onRequestClose={onRequestClose}
|
||||
@@ -35,7 +47,7 @@ function Modal({
|
||||
<ModalHeader title={title} />
|
||||
) }
|
||||
{ isDismissible && (
|
||||
<button type="button" onClick={onRequestClose} className="mailpoet-modal-close">{closeIcon}</button>
|
||||
<button type="button" onClick={onRequestClose} className="mailpoet-modal-close">{ModalCloseIcon}</button>
|
||||
) }
|
||||
<div
|
||||
className="mailpoet-modal-content"
|
||||
@@ -49,19 +61,6 @@ function Modal({
|
||||
);
|
||||
}
|
||||
|
||||
Modal.propTypes = {
|
||||
children: PropTypes.node,
|
||||
isDismissible: PropTypes.bool,
|
||||
contentClassName: PropTypes.string,
|
||||
overlayClassName: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
onRequestClose: PropTypes.func,
|
||||
fullScreen: PropTypes.bool,
|
||||
shouldCloseOnEsc: PropTypes.bool,
|
||||
shouldCloseOnClickOutside: PropTypes.bool,
|
||||
role: PropTypes.string,
|
||||
};
|
||||
|
||||
Modal.defaultProps = {
|
||||
bodyOpenClassName: 'modal-open',
|
||||
onRequestClose: () => {},
|
@@ -1,16 +1,23 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const ESCAPE = 27;
|
||||
|
||||
type Props = {
|
||||
onRequestClose?: (event: React.SyntheticEvent) => void,
|
||||
shouldCloseOnEsc?: boolean,
|
||||
shouldCloseOnClickOutside?: boolean,
|
||||
className?: string,
|
||||
children: React.ReactNode,
|
||||
};
|
||||
|
||||
function ModalOverlay({
|
||||
onRequestClose,
|
||||
shouldCloseOnEsc,
|
||||
shouldCloseOnClickOutside,
|
||||
className,
|
||||
children,
|
||||
}) {
|
||||
}: Props) {
|
||||
const overlayRef = useRef(null);
|
||||
|
||||
// get focus on render so keys such as ESC work immediately
|
||||
@@ -18,27 +25,27 @@ function ModalOverlay({
|
||||
overlayRef.current.focus();
|
||||
}, []);
|
||||
|
||||
function onClose(event) {
|
||||
function onClose(event: React.SyntheticEvent) {
|
||||
if (onRequestClose) {
|
||||
onRequestClose(event);
|
||||
}
|
||||
}
|
||||
|
||||
function handleFocusOutside(event) {
|
||||
function handleFocusOutside(event: React.MouseEvent) {
|
||||
// filter only to clicks on overlay
|
||||
if (shouldCloseOnClickOutside && overlayRef.current === event.target) {
|
||||
onClose(event);
|
||||
}
|
||||
}
|
||||
|
||||
function handleEscapeKeyDown(event) {
|
||||
function handleEscapeKeyDown(event: React.KeyboardEvent) {
|
||||
if (shouldCloseOnEsc) {
|
||||
event.stopPropagation();
|
||||
onClose(event);
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeyDown(event) {
|
||||
function handleKeyDown(event: React.KeyboardEvent) {
|
||||
if (event.keyCode === ESCAPE) {
|
||||
handleEscapeKeyDown(event);
|
||||
}
|
||||
@@ -54,21 +61,13 @@ function ModalOverlay({
|
||||
onKeyDown={handleKeyDown}
|
||||
onClick={handleFocusOutside}
|
||||
role="button"
|
||||
tabIndex="0"
|
||||
tabIndex={0}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ModalOverlay.propTypes = {
|
||||
onRequestClose: PropTypes.func,
|
||||
shouldCloseOnEsc: PropTypes.bool,
|
||||
shouldCloseOnClickOutside: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
ModalOverlay.defaultProps = {
|
||||
onRequestClose: () => {},
|
||||
shouldCloseOnEsc: true,
|
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
|
||||
import ReactStringReplace from 'react-string-replace';
|
||||
import jQuery from 'jquery';
|
||||
import MailPoet from 'mailpoet';
|
||||
import Modal from 'common/modal/modal.jsx';
|
||||
import Modal from 'common/modal/modal';
|
||||
import { GlobalContext } from 'context';
|
||||
|
||||
const mailPoetApiVersion = (window as any).mailpoet_api_version as string;
|
||||
|
@@ -8,7 +8,7 @@ import { Spinner, SelectControl } from '@wordpress/components';
|
||||
import { useDispatch, useSelect } from '@wordpress/data';
|
||||
|
||||
import Preview from 'common/preview/preview.jsx';
|
||||
import Modal from 'common/modal/modal.jsx';
|
||||
import Modal from 'common/modal/modal';
|
||||
import BelowPostsSettings from './below_posts_settings';
|
||||
import PopUpSettings from './popup_settings';
|
||||
import OtherSettings from './other_settings';
|
||||
|
Reference in New Issue
Block a user