57 lines
1.2 KiB
React
57 lines
1.2 KiB
React
|
|
import React, { useEffect, useRef } from 'react'
|
||
|
|
import { createPortal } from 'react-dom'
|
||
|
|
import { useModalScrollLock } from '../hooks/useModalScrollLock'
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Formular-Modal am document.body (Portal) — volle Viewport-Breite, kein Hintergrund-Scroll.
|
||
|
|
*/
|
||
|
|
export default function FormModalOverlay({
|
||
|
|
open,
|
||
|
|
children,
|
||
|
|
raised = false,
|
||
|
|
className = '',
|
||
|
|
onBackdropClick,
|
||
|
|
'data-testid': testId,
|
||
|
|
}) {
|
||
|
|
const overlayRef = useRef(null)
|
||
|
|
useModalScrollLock(open)
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
if (!open) return undefined
|
||
|
|
const t = window.setTimeout(() => {
|
||
|
|
overlayRef.current?.focus({ preventScroll: true })
|
||
|
|
}, 0)
|
||
|
|
return () => clearTimeout(t)
|
||
|
|
}, [open])
|
||
|
|
|
||
|
|
if (!open) return null
|
||
|
|
|
||
|
|
const overlayClass = [
|
||
|
|
'modal-overlay',
|
||
|
|
'modal-overlay--form',
|
||
|
|
raised ? 'modal-overlay--raised' : '',
|
||
|
|
className,
|
||
|
|
]
|
||
|
|
.filter(Boolean)
|
||
|
|
.join(' ')
|
||
|
|
|
||
|
|
return createPortal(
|
||
|
|
<div
|
||
|
|
ref={overlayRef}
|
||
|
|
tabIndex={-1}
|
||
|
|
data-testid={testId}
|
||
|
|
className={overlayClass}
|
||
|
|
onClick={
|
||
|
|
onBackdropClick
|
||
|
|
? (e) => {
|
||
|
|
if (e.target === e.currentTarget) onBackdropClick()
|
||
|
|
}
|
||
|
|
: undefined
|
||
|
|
}
|
||
|
|
>
|
||
|
|
{children}
|
||
|
|
</div>,
|
||
|
|
document.body,
|
||
|
|
)
|
||
|
|
}
|