fix(calendar): add type="button" to all buttons in PersianCalendar to prevent form submission
53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import { createPortal } from 'react-dom';
|
|
import { XMarkIcon } from '@heroicons/react/24/outline';
|
|
|
|
type ModalSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
|
|
const sizeMap: Record<ModalSize, string> = {
|
|
sm: '420px',
|
|
md: '540px',
|
|
lg: '720px',
|
|
xl: '960px',
|
|
};
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
title: string;
|
|
size?: ModalSize;
|
|
onClose: () => void;
|
|
children: React.ReactNode;
|
|
footer?: React.ReactNode;
|
|
}
|
|
|
|
export default function Modal({ open, title, size = 'md', onClose, children, footer }: Props) {
|
|
useEffect(() => {
|
|
if (!open) return;
|
|
const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); };
|
|
document.addEventListener('keydown', onKey);
|
|
return () => document.removeEventListener('keydown', onKey);
|
|
}, [open, onClose]);
|
|
|
|
if (!open) return null;
|
|
|
|
return createPortal(
|
|
<div className="overlay" onClick={onClose}>
|
|
<div
|
|
className="modal"
|
|
style={{ maxWidth: sizeMap[size] }}
|
|
onClick={(e) => e.stopPropagation()}
|
|
>
|
|
<div className="modal-head">
|
|
<h2>{title}</h2>
|
|
<button type="button" className="mini-btn" onClick={onClose}>
|
|
<XMarkIcon style={{ width: 18, height: 18 }} />
|
|
</button>
|
|
</div>
|
|
<div className="modal-body">{children}</div>
|
|
{footer && <div className="modal-foot">{footer}</div>}
|
|
</div>
|
|
</div>,
|
|
document.body
|
|
);
|
|
}
|