You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

68 lines
2.1 KiB
JavaScript

import { useEffect, useRef } from 'react';
import { createPortal } from 'react-dom';
import './FormOverlay.css';
export default function FormOverlay({ isOpen, onClose, title, children }) {
const overlayRef = useRef(null);
const mouseDownTargetRef = useRef(null);
// Escape key to close
useEffect(() => {
if (!isOpen) return;
const handleKeyDown = (e) => {
if (e.key === 'Escape') onClose();
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [isOpen, onClose]);
// Prevent body scroll when open
useEffect(() => {
if (isOpen) {
document.body.style.overflow = 'hidden';
return () => { document.body.style.overflow = ''; };
}
}, [isOpen]);
if (!isOpen) return null;
// Smart click handling: only close if mousedown AND mouseup both on backdrop
// This prevents closing when user selects text and drags to backdrop
const handleMouseDown = (e) => {
mouseDownTargetRef.current = e.target;
};
const handleMouseUp = (e) => {
if (mouseDownTargetRef.current === overlayRef.current && e.target === overlayRef.current) {
onClose();
}
mouseDownTargetRef.current = null;
};
return createPortal(
<div
className="nui-form-overlay"
ref={overlayRef}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
>
<div className="nui-form-modal" onClick={(e) => e.stopPropagation()}>
<div className="nui-form-modal-header">
<h3>{title}</h3>
<button
className="nui-form-modal-close"
onClick={onClose}
type="button"
>
&times;
</button>
</div>
<div className="nui-form-modal-content">
{children}
</div>
</div>
</div>,
document.body
);
}