fix(modal): render Modal with React Portal to center it on the screen
fix(calendar): add type="button" to all buttons in PersianCalendar to prevent form submission
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { XMarkIcon } from '@heroicons/react/24/outline';
|
||||
|
||||
type ModalSize = 'sm' | 'md' | 'lg' | 'xl';
|
||||
@@ -29,7 +30,7 @@ export default function Modal({ open, title, size = 'md', onClose, children, foo
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
return (
|
||||
return createPortal(
|
||||
<div className="overlay" onClick={onClose}>
|
||||
<div
|
||||
className="modal"
|
||||
@@ -38,13 +39,14 @@ export default function Modal({ open, title, size = 'md', onClose, children, foo
|
||||
>
|
||||
<div className="modal-head">
|
||||
<h2>{title}</h2>
|
||||
<button className="mini-btn" onClick={onClose}>
|
||||
<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>
|
||||
</div>,
|
||||
document.body
|
||||
);
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ export default function PersianCalendar({ value, onChange, onClose, enableYearPi
|
||||
{/* Header */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={mode === 'year' ? () => setYearRangeStart(s => s - 12) : nextMonth}
|
||||
style={{ ...navBtnStyle, visibility: mode === 'month' ? 'hidden' : 'visible' }}
|
||||
>
|
||||
@@ -157,6 +158,7 @@ export default function PersianCalendar({ value, onChange, onClose, enableYearPi
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={mode === 'year' ? () => setYearRangeStart(s => s + 12) : prevMonth}
|
||||
style={{ ...navBtnStyle, visibility: mode === 'month' ? 'hidden' : 'visible' }}
|
||||
>
|
||||
@@ -182,6 +184,7 @@ export default function PersianCalendar({ value, onChange, onClose, enableYearPi
|
||||
return (
|
||||
<button
|
||||
key={i}
|
||||
type="button"
|
||||
onClick={() => selectDay(day)}
|
||||
style={{
|
||||
width: 32, height: 32, borderRadius: '50%', fontSize: 12,
|
||||
@@ -211,6 +214,7 @@ export default function PersianCalendar({ value, onChange, onClose, enableYearPi
|
||||
return (
|
||||
<button
|
||||
key={m}
|
||||
type="button"
|
||||
onClick={() => { setViewMonth(m); setMode('day'); }}
|
||||
style={{ ...gridItemStyle, background: active ? 'var(--primary)' : 'transparent', color: active ? '#fff' : 'var(--text)' }}
|
||||
onMouseEnter={e => { if (!active) (e.currentTarget as HTMLButtonElement).style.background = 'var(--surface-2)'; }}
|
||||
@@ -231,6 +235,7 @@ export default function PersianCalendar({ value, onChange, onClose, enableYearPi
|
||||
return (
|
||||
<button
|
||||
key={y}
|
||||
type="button"
|
||||
onClick={() => { setViewYear(y); setMode('month'); }}
|
||||
style={{ ...gridItemStyle, background: active ? 'var(--primary)' : 'transparent', color: active ? '#fff' : 'var(--text)' }}
|
||||
onMouseEnter={e => { if (!active) (e.currentTarget as HTMLButtonElement).style.background = 'var(--surface-2)'; }}
|
||||
|
||||
Reference in New Issue
Block a user