icynet-admin/components/common/Modal/ModalRoot/ModalRoot.tsx

71 lines
1.9 KiB
TypeScript

import { useState, useEffect, useRef } from 'react';
import { ModalSetter } from '../../../../lib/types/modal.interface';
import ModalService from '../services/ModalService';
import styles from './ModalRoot.module.scss';
export default function ModalRoot() {
const [modal, setModal] = useState<ModalSetter<Object> | null>(null);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
ModalService.on('open', ({ component, props, target, resolve }) => {
setModal({
component,
props,
resolve,
close: (...args) => {
setModal(null);
resolve?.call(null, ...args);
target?.focus();
},
});
});
}, []);
useEffect(() => {
if (!modal) {
return;
}
function handleEscapeKey(e: KeyboardEvent) {
if (e.key === 'Escape') {
modal?.close?.call(null, false);
}
}
// Off click listener
function handleClickOutside(event: MouseEvent | TouchEvent) {
if (
ref.current &&
!(ref.current as unknown as HTMLElement).contains(
event.target as HTMLElement
)
) {
modal?.close?.call(null, false);
}
}
window.addEventListener('keyup', handleEscapeKey);
document.body.style.overflow = 'hidden';
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('touchstart', handleClickOutside);
return () => {
window.removeEventListener('keyup', handleEscapeKey);
document.body.style.overflow = '';
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('touchstart', handleClickOutside);
};
}, [modal]);
const ModalComponent = modal?.component ? modal.component : null;
return (
<section className={modal?.component ? styles.modalRoot : ''}>
{ModalComponent && (
<ModalComponent {...modal?.props} modalRef={ref} close={modal!.close} />
)}
</section>
);
}