You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
77 lines
2.6 KiB
React
77 lines
2.6 KiB
React
1 year ago
|
import React, { useEffect, Fragment } from 'react';
|
||
|
import ReactDOM from 'react-dom';
|
||
|
import { Transition } from '@headlessui/react';
|
||
|
|
||
|
export default function Modal({ children, show = false, maxWidth = '2xl', closeable = true, onClose = () => {} }) {
|
||
|
useEffect(() => {
|
||
|
document.body.style.overflow = show ? 'hidden' : null;
|
||
|
}, [show]);
|
||
|
|
||
|
const close = () => {
|
||
|
if (closeable) {
|
||
|
onClose();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const closeOnEscape = (e) => {
|
||
|
if (e.key === 'Escape' && props.show) {
|
||
|
close();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
useEffect(() => {
|
||
|
document.addEventListener('keydown', closeOnEscape);
|
||
|
return () => {
|
||
|
document.removeEventListener('keydown', closeOnEscape);
|
||
|
document.body.style.overflow = null;
|
||
|
};
|
||
|
}, []);
|
||
|
|
||
|
const maxWidthClass = {
|
||
|
sm: 'sm:max-w-sm',
|
||
|
md: 'sm:max-w-md',
|
||
|
lg: 'sm:max-w-lg',
|
||
|
xl: 'sm:max-w-xl',
|
||
|
'2xl': 'sm:max-w-2xl',
|
||
|
}[maxWidth];
|
||
|
|
||
|
const modalRoot = document.getElementById('modal-root');
|
||
|
|
||
|
return ReactDOM.createPortal(
|
||
|
<Transition show={show} leave="duration-200">
|
||
|
<div className="fixed inset-0 overflow-y-auto px-4 py-6 sm:px-0 z-50">
|
||
|
<Transition.Child
|
||
|
as={Fragment}
|
||
|
enter="ease-out duration-300"
|
||
|
enterFrom="opacity-0"
|
||
|
enterTo="opacity-100"
|
||
|
leave="ease-in duration-200"
|
||
|
leaveFrom="opacity-100"
|
||
|
leaveTo="opacity-0"
|
||
|
>
|
||
|
<div className="fixed inset-0 transform transition-all" onClick={close}>
|
||
|
<div className="absolute inset-0 bg-gray-500 opacity-75"></div>
|
||
|
</div>
|
||
|
</Transition.Child>
|
||
|
|
||
|
<Transition.Child
|
||
|
as={Fragment}
|
||
|
enter="ease-out duration-300"
|
||
|
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||
|
enterTo="opacity-100 translate-y-0 sm:scale-100"
|
||
|
leave="ease-in duration-200"
|
||
|
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||
|
>
|
||
|
<div
|
||
|
className={`mb-6 bg-white rounded-lg overflow-hidden shadow-xl transform transition-all sm:w-full sm:mx-auto ${maxWidthClass}`}
|
||
|
>
|
||
|
{children}
|
||
|
</div>
|
||
|
</Transition.Child>
|
||
|
</div>
|
||
|
</Transition>,
|
||
|
modalRoot
|
||
|
);
|
||
|
}
|