From a78fc06f2b2dc86226ac5325bf2e571526d316f3 Mon Sep 17 00:00:00 2001 From: Michelle Date: Wed, 4 Mar 2026 11:12:56 +0100 Subject: [PATCH] feat(DateTimePicker): implement calendar open handler to preserve scroll position feat(Modal): remove max height restriction for modal body style: clean up z-index for datepicker popper --- src/components/DateTimePicker.jsx | 28 +++++++++++++++++++++++++--- src/components/Modal.jsx | 2 +- src/index.css | 5 ----- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/components/DateTimePicker.jsx b/src/components/DateTimePicker.jsx index 51afa3e..38e6853 100644 --- a/src/components/DateTimePicker.jsx +++ b/src/components/DateTimePicker.jsx @@ -1,7 +1,7 @@ import ReactDatePicker from 'react-datepicker'; import { de } from 'date-fns/locale'; import { Calendar as CalendarIcon, Clock } from 'lucide-react'; -import { forwardRef } from 'react'; +import { forwardRef, useRef, useCallback } from 'react'; import 'react-datepicker/dist/react-datepicker.css'; /** @@ -39,8 +39,29 @@ export default function DateTimePicker({ const Icon = icon === 'clock' ? Clock : CalendarIcon; - return ( -
+ // react-datepicker calls scrollIntoView on the selected time item when the + // calendar opens. This scrolls the nearest scrollable ancestor (page or + // modal). We capture every scrollable ancestor's position just before open + // and restore it in the next animation frame — after scrollIntoView fires. + const wrapperRef = useRef(null); + const handleCalendarOpen = useCallback(() => { + const snapshots = []; + let el = wrapperRef.current?.parentElement; + while (el && el !== document.body) { + const { overflow, overflowY } = getComputedStyle(el); + if (/(auto|scroll)/.test(overflow + overflowY)) { + snapshots.push({ el, top: el.scrollTop, left: el.scrollLeft }); + } + el = el.parentElement; + } + // also capture window scroll + const winY = window.scrollY; + requestAnimationFrame(() => { + snapshots.forEach(s => { s.el.scrollTop = s.top; s.el.scrollLeft = s.left; }); + window.scrollTo({ top: winY, behavior: 'instant' }); + }); + }, []); +
{label && (
{/* Body */} -
+
{children}
diff --git a/src/index.css b/src/index.css index 136d53c..be453d0 100644 --- a/src/index.css +++ b/src/index.css @@ -819,11 +819,6 @@ display: none; } -/* Must sit above the modal backdrop (z-50 stacking context) */ -.react-datepicker-popper { - z-index: 200 !important; -} - /* ── Header (custom rendered) ─────────────────────────────────── */ .dtp-calendar .react-datepicker__header { background: var(--bg-secondary);