Use TypeScript for modal

[MAILPOET-2777]
This commit is contained in:
Jan Jakeš
2020-05-28 17:31:28 +02:00
committed by Veljko V
parent 73784d588e
commit 8b6f419426
7 changed files with 49 additions and 53 deletions

View File

@@ -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,

View File

@@ -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;

View File

@@ -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: () => {},

View File

@@ -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,

View File

@@ -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;

View File

@@ -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';