PlugSnatcher/src/components/common/Modal/Modal.tsx

114 lines
2.5 KiB
TypeScript

import React, { ReactNode, useEffect, useRef } from 'react';
import './Modal.css';
export interface ModalProps {
/**
* Title displayed at the top of the modal
*/
title?: string;
/**
* Content of the modal
*/
children: ReactNode;
/**
* Whether the modal is visible or not
*/
isOpen: boolean;
/**
* Function to call when the modal close button is clicked
*/
onClose: () => void;
/**
* Optional CSS class name to add to the modal for custom styling
*/
className?: string;
/**
* Whether to show the close button in the header
* @default true
*/
showCloseButton?: boolean;
/**
* Whether to close the modal when clicking outside of it
* @default true
*/
closeOnOutsideClick?: boolean;
}
/**
* A reusable modal component that can be used for various purposes
*/
const Modal: React.FC<ModalProps> = ({
title,
children,
isOpen,
onClose,
className = '',
showCloseButton = true,
closeOnOutsideClick = true
}) => {
const modalRef = useRef<HTMLDivElement>(null);
// Close modal when escape key is pressed
useEffect(() => {
const handleEscKey = (event: KeyboardEvent) => {
if (isOpen && event.key === 'Escape') {
onClose();
}
};
document.addEventListener('keydown', handleEscKey);
return () => {
document.removeEventListener('keydown', handleEscKey);
};
}, [isOpen, onClose]);
// Handle outside click
const handleBackdropClick = (event: React.MouseEvent<HTMLDivElement>) => {
if (closeOnOutsideClick && modalRef.current && !modalRef.current.contains(event.target as Node)) {
onClose();
}
};
if (!isOpen) {
return null;
}
return (
<div className="modal-backdrop" onClick={handleBackdropClick}>
<div
className={`modal-container ${className}`}
ref={modalRef}
role="dialog"
aria-modal="true"
aria-labelledby={title ? "modal-title" : undefined}
aria-describedby="modal-content"
>
{(title || showCloseButton) && (
<div className="modal-header">
{title && <h3 className="modal-title" id="modal-title">{title}</h3>}
{showCloseButton && (
<button
className="modal-close-button"
onClick={onClose}
aria-label="Close"
>
&times;
</button>
)}
</div>
)}
<div className="modal-content" id="modal-content">
{children}
</div>
</div>
</div>
);
};
export default Modal;