diff --git a/web/modals/modal.react.js b/web/modals/modal.react.js index 532559495..e0a4f8afc 100644 --- a/web/modals/modal.react.js +++ b/web/modals/modal.react.js @@ -1,112 +1,120 @@ // @flow import classNames from 'classnames'; -import invariant from 'invariant'; import * as React from 'react'; import SWMansionIcon, { type Icon } from '../SWMansionIcon.react'; import css from './modal.css'; export type ModalSize = 'small' | 'large'; type Props = { +name: React.Node, +icon?: Icon, +onClose: () => void, +withCloseButton?: boolean, +children?: React.Node, +size?: ModalSize, +fixedHeight?: boolean, }; -class Modal extends React.PureComponent { - static defaultProps: { +size: ModalSize, fixedHeight: boolean } = { - size: 'small', - fixedHeight: true, - }; - overlay: ?HTMLDivElement; - componentDidMount() { - invariant(this.overlay, 'overlay ref unset'); - this.overlay.focus(); - } +function Modal(props: Props): React.Node { + const { + size = 'small', + children, + onClose, + fixedHeight, + name, + icon, + withCloseButton = true, + } = props; + const overlayRef = React.useRef(); - render(): React.Node { - const { - size, - children, - onClose, - fixedHeight, - name, - icon, - withCloseButton = true, - } = this.props; + const onBackgroundClick = React.useCallback( + event => { + if (event.target === overlayRef.current) { + onClose(); + } + }, + [onClose], + ); - const overlayClasses = classNames(css['modal-overlay'], { - [css['resizable-modal-overlay']]: !fixedHeight, - }); - const modalContainerClasses = classNames(css['modal-container'], { - [css['large-modal-container']]: size === 'large', - }); - const modalClasses = classNames(css['modal'], { - [css['fixed-height-modal']]: fixedHeight, - }); + const onKeyDown = React.useCallback( + event => { + if (event.keyCode === 27) { + onClose(); + } + }, + [onClose], + ); - let headerIcon; - if (icon) { - headerIcon = ; + React.useEffect(() => { + if (overlayRef.current) { + overlayRef.current.focus(); } + }, []); - let cornerCloseButton; - if (withCloseButton) { - cornerCloseButton = ( - - - - ); - } + const overlayClasses = React.useMemo( + () => + classNames(css['modal-overlay'], { + [css['resizable-modal-overlay']]: !fixedHeight, + }), + [fixedHeight], + ); + const modalContainerClasses = React.useMemo( + () => + classNames(css['modal-container'], { + [css['large-modal-container']]: size === 'large', + }), + [size], + ); + const modalClasses = React.useMemo( + () => + classNames(css['modal'], { + [css['fixed-height-modal']]: fixedHeight, + }), + [fixedHeight], + ); + const cornerCloseButton = React.useMemo(() => { + if (!withCloseButton) { + return null; + } return ( -
-
-
-
- {cornerCloseButton} -

- {headerIcon} - {name} -

-
- {children} -
-
-
+ + + ); - } + }, [onClose, withCloseButton]); - overlayRef: (overlay: ?HTMLDivElement) => void = overlay => { - this.overlay = overlay; - }; - - onBackgroundClick: ( - event: SyntheticEvent, - ) => void = event => { - if (event.target === this.overlay) { - this.props.onClose(); + const headerIcon = React.useMemo(() => { + if (!icon) { + return null; } - }; + return ; + }, [icon]); - onKeyDown: ( - event: SyntheticKeyboardEvent, - ) => void = event => { - if (event.keyCode === 27) { - this.props.onClose(); - } - }; + return ( +
+
+
+
+ {cornerCloseButton} +

+ {headerIcon} + {name} +

+
+ {children} +
+
+
+ ); } export default Modal;