Modal.tsx

 1import React from "react";
 2
 3interface ModalProps {
 4  isOpen: boolean;
 5  onClose: () => void;
 6  title: string;
 7  titleRight?: React.ReactNode;
 8  children: React.ReactNode;
 9  className?: string;
10}
11
12function Modal({ isOpen, onClose, title, titleRight, children, className }: ModalProps) {
13  if (!isOpen) return null;
14
15  const handleBackdropClick = (e: React.MouseEvent) => {
16    if (e.target === e.currentTarget) {
17      onClose();
18    }
19  };
20
21  return (
22    <div className="modal-overlay" onClick={handleBackdropClick}>
23      <div className={`modal ${className || ""}`}>
24        {/* Header */}
25        <div className="modal-header">
26          <h2 className="modal-title">{title}</h2>
27          {titleRight && <div className="modal-title-right">{titleRight}</div>}
28          <button onClick={onClose} className="btn-icon" aria-label="Close modal">
29            <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
30              <path
31                strokeLinecap="round"
32                strokeLinejoin="round"
33                strokeWidth={2}
34                d="M6 18L18 6M6 6l12 12"
35              />
36            </svg>
37          </button>
38        </div>
39
40        {/* Content */}
41        <div className="modal-body">{children}</div>
42      </div>
43    </div>
44  );
45}
46
47export default Modal;