From 133fca9ef6c57f5d04fdc817b20e8f6cf2eb9b47 Mon Sep 17 00:00:00 2001 From: schakal00783 Date: Fri, 18 Sep 2026 11:21:00 +0200 Subject: [PATCH] fix(dialoge): Dialoge an den body haengen, damit sie nicht in Karten haengen bleiben Die Einblendanimationen laufen mit animation-fill-mode: both. Danach behaelt das Element den Wert des letzten Keyframes, bei transform also eine Einheitsmatrix statt "none". Das genuegt, um einen Bezugsrahmen fuer position: fixed zu erzeugen: Ein Dialog unterhalb einer solchen Karte hat sein Overlay nur noch ueber der Karte, deren overflow: hidden schneidet ihn ab. Sichtbar beim Bearbeiten eines Budgettopfs in der Projektansicht - das Fenster klebte an der Detailkarte und die Schaltflaechen waren abgeschnitten. Modal und ConfirmDialog rendern jetzt per createPortal in document.body. Co-Authored-By: Claude Opus 5 (1M context) --- src/components/ui/Modal.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/components/ui/Modal.tsx b/src/components/ui/Modal.tsx index 9db3acf..b8ad21b 100644 --- a/src/components/ui/Modal.tsx +++ b/src/components/ui/Modal.tsx @@ -1,6 +1,19 @@ import React, { useEffect, useRef } from 'react'; +import { createPortal } from 'react-dom'; import { Icon } from './Icon'; +/** + * Dialoge haengen immer direkt am . + * + * Grund: Die Einblendanimationen laufen mit "animation-fill-mode: both". Danach + * behaelt das Element den Wert des letzten Keyframes - bei transform also eine + * Einheitsmatrix statt "none". Das reicht, um einen Bezugsrahmen fuer + * position: fixed zu erzeugen. Steht ein Dialog im Baum unter so einer Karte, + * misst sein Overlay nur noch die Karte und deren overflow: hidden schneidet + * ihn ab (z. B. Budgettopf bearbeiten in der Projektansicht). + */ +const toBody = (node: React.ReactElement) => (typeof document === 'undefined' ? node : createPortal(node, document.body)); + interface ModalProps { title: string; subtitle?: React.ReactNode; @@ -54,7 +67,7 @@ function useDismiss(onClose: () => void) { */ export const Modal: React.FC = ({ title, subtitle, onClose, children, footer, size = 'md' }) => { const dismiss = useDismiss(onClose); - return ( + return toBody(
= ({ onCancel, }) => { const dismiss = useDismiss(onCancel); - return ( + return toBody(