diff --git a/web/modals/modal-overlay.css b/web/modals/modal-overlay.css
new file mode 100644
index 000000000..89037f396
--- /dev/null
+++ b/web/modals/modal-overlay.css
@@ -0,0 +1,13 @@
+div.modalOverlay {
+ position: fixed;
+ left: 0;
+ top: 0;
+ height: 100%;
+ z-index: 4;
+ width: 100%;
+ background-color: rgba(0, 0, 0, 0.9);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+}
diff --git a/web/modals/modal-overlay.react.js b/web/modals/modal-overlay.react.js
new file mode 100644
index 000000000..dbccb2fc9
--- /dev/null
+++ b/web/modals/modal-overlay.react.js
@@ -0,0 +1,63 @@
+// @flow
+
+import * as React from 'react';
+
+import css from './modal-overlay.css';
+
+type ModalOverlayProps = {
+ +onClose: () => void,
+ +children?: React.Node,
+};
+
+function ModalOverlay(props: ModalOverlayProps): React.Node {
+ const { children, onClose } = props;
+
+ const overlayRef = React.useRef();
+ const firstClickRef = React.useRef(null);
+
+ const onBackgroundMouseDown = React.useCallback(event => {
+ firstClickRef.current = event.target;
+ }, []);
+
+ const onBackgroundMouseUp = React.useCallback(
+ event => {
+ if (
+ event.target === overlayRef.current &&
+ firstClickRef.current === overlayRef.current
+ ) {
+ onClose();
+ }
+ },
+ [onClose],
+ );
+
+ const onKeyDown = React.useCallback(
+ event => {
+ if (event.keyCode === 27) {
+ onClose();
+ }
+ },
+ [onClose],
+ );
+
+ React.useEffect(() => {
+ if (overlayRef.current) {
+ overlayRef.current.focus();
+ }
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+}
+
+export default ModalOverlay;
diff --git a/web/modals/modal.css b/web/modals/modal.css
index 9cad1b387..2d64163bf 100644
--- a/web/modals/modal.css
+++ b/web/modals/modal.css
@@ -1,57 +1,43 @@
-div.modalOverlay {
- position: fixed;
- left: 0;
- top: 0;
- height: 100%;
- z-index: 4;
- width: 100%;
- background-color: rgba(0, 0, 0, 0.9);
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
-}
-
div.modalContainer {
display: flex;
background-color: var(--modal-bg);
border-radius: 8px;
flex-direction: column;
margin: 20px;
overflow: hidden;
}
div.modalContainerSmall {
width: 330px;
}
div.modalContainerLarge {
width: 500px;
}
span.modalClose {
display: flex;
color: var(--modal-close-color);
}
span.modalClose:hover {
cursor: pointer;
color: var(--modal-close-color-hover);
}
div.modalHeader {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32px 32px 0 32px;
}
h2.title {
font-size: 20px;
font-weight: 500;
line-height: 32px;
color: var(--fg);
display: flex;
align-items: center;
column-gap: 8px;
}
diff --git a/web/modals/modal.react.js b/web/modals/modal.react.js
index 169bd0470..567bef0a5 100644
--- a/web/modals/modal.react.js
+++ b/web/modals/modal.react.js
@@ -1,117 +1,78 @@
// @flow
import classNames from 'classnames';
import * as React from 'react';
import SWMansionIcon, { type Icon } from '../SWMansionIcon.react';
+import ModalOverlay from './modal-overlay.react';
import css from './modal.css';
export type ModalSize = 'small' | 'large' | 'fit-content';
export type ModalOverridableProps = {
+name: string,
+icon?: Icon,
+onClose: () => void,
+withCloseButton?: boolean,
+size?: ModalSize,
};
type ModalProps = {
...ModalOverridableProps,
+children?: React.Node,
};
function Modal(props: ModalProps): React.Node {
const {
size = 'small',
children,
onClose,
name,
icon,
withCloseButton = true,
} = props;
- const overlayRef = React.useRef();
- const firstClickRef = React.useRef(null);
-
- const onBackgroundMouseDown = React.useCallback(event => {
- firstClickRef.current = event.target;
- }, []);
-
- const onBackgroundMouseUp = React.useCallback(
- event => {
- if (
- event.target === overlayRef.current &&
- firstClickRef.current === overlayRef.current
- ) {
- onClose();
- }
- },
- [onClose],
- );
-
- const onKeyDown = React.useCallback(
- event => {
- if (event.keyCode === 27) {
- onClose();
- }
- },
- [onClose],
- );
-
- React.useEffect(() => {
- if (overlayRef.current) {
- overlayRef.current.focus();
- }
- }, []);
const modalContainerClasses = React.useMemo(
() =>
classNames(css.modalContainer, {
[css.modalContainerLarge]: size === 'large',
[css.modalContainerSmall]: size === 'small',
}),
[size],
);
const cornerCloseButton = React.useMemo(() => {
if (!withCloseButton) {
return null;
}
return (
);
}, [onClose, withCloseButton]);
const headerIcon = React.useMemo(() => {
if (!icon) {
return null;
}
return ;
}, [icon]);
return (
-
+
{headerIcon}
{name}
{cornerCloseButton}
{children}
-
+
);
}
export default Modal;