diff --git a/resources/scripts/components/elements/Modal.tsx b/resources/scripts/components/elements/Modal.tsx index c37669b02..0ef756d3c 100644 --- a/resources/scripts/components/elements/Modal.tsx +++ b/resources/scripts/components/elements/Modal.tsx @@ -1,9 +1,10 @@ import React, { useEffect, useMemo, useState } from 'react'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTimes } from '@fortawesome/free-solid-svg-icons/faTimes'; -import { CSSTransition } from 'react-transition-group'; import Spinner from '@/components/elements/Spinner'; -import classNames from 'classnames'; +import tw from 'twin.macro'; +import styled from 'styled-components/macro'; +import Fade from '@/components/elements/Fade'; export interface RequiredModalProps { visible: boolean; @@ -12,20 +13,38 @@ export interface RequiredModalProps { top?: boolean; } -type Props = RequiredModalProps & { +interface Props extends RequiredModalProps { dismissable?: boolean; closeOnEscape?: boolean; closeOnBackground?: boolean; showSpinnerOverlay?: boolean; - children: React.ReactNode; } -export default ({ visible, appear, dismissable, showSpinnerOverlay, top = true, closeOnBackground = true, closeOnEscape = true, onDismissed, children }: Props) => { - const [render, setRender] = useState(visible); +const ModalMask = styled.div` + ${tw`fixed z-50 overflow-auto flex w-full inset-0`}; + background: rgba(0, 0, 0, 0.70); +`; + +const ModalContainer = styled.div<{ alignTop?: boolean }>` + ${tw`relative flex flex-col w-full m-auto`}; + max-width: 50%; + // @todo max-w-screen-lg perhaps? + ${props => props.alignTop && 'margin-top: 10%'}; + + & > .close-icon { + ${tw`absolute right-0 p-2 text-white cursor-pointer opacity-50 transition-all duration-150 ease-linear hover:opacity-100`}; + top: -2rem; + + &:hover {${tw`transform rotate-90`}} + } +`; + +const Modal: React.FC = ({ visible, appear, dismissable, showSpinnerOverlay, top = true, closeOnBackground = true, closeOnEscape = true, onDismissed, children }) => { + const [ render, setRender ] = useState(visible); const isDismissable = useMemo(() => { return (dismissable || true) && !(showSpinnerOverlay || false); - }, [dismissable, showSpinnerOverlay]); + }, [ dismissable, showSpinnerOverlay ]); const handleEscapeEvent = (e: KeyboardEvent) => { if (isDismissable && closeOnEscape && e.key === 'Escape') { @@ -33,52 +52,47 @@ export default ({ visible, appear, dismissable, showSpinnerOverlay, top = true, } }; - useEffect(() => { - setRender(visible); - }, [visible]); + useEffect(() => setRender(visible), [ visible ]); useEffect(() => { window.addEventListener('keydown', handleEscapeEvent); return () => window.removeEventListener('keydown', handleEscapeEvent); - }, [render]); + }, [ render ]); return ( - onDismissed()} - > -
{ - if (isDismissable && closeOnBackground) { - e.stopPropagation(); - if (e.target === e.currentTarget) { - setRender(false); + + { + if (isDismissable && closeOnBackground) { + e.stopPropagation(); + if (e.target === e.currentTarget) { + setRender(false); + } } - } - }}> -
+ }} + > + {isDismissable && -
setRender(false)}> +
setRender(false)}>
} {showSpinnerOverlay &&
} -
+
{children}
-
-
- +
+ + ); }; + +export default Modal; diff --git a/tailwind.config.js b/tailwind.config.js index ce51fe6f7..6ed79cdd9 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -116,6 +116,9 @@ module.exports = { fontSize: { '2xs': '0.625rem', }, + transitionDuration: { + 250: '250ms', + }, borderColor: theme => ({ default: theme('colors.neutral.400', 'cuurrentColor'), }),