feat(DateTimePicker): implement custom popper container for improved layout handling
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m58s
All checks were successful
Build & Push Docker Image / build (push) Successful in 6m58s
feat(Modal): enhance modal styling with rounded corners and improved overflow handling style: adjust z-index for datepicker popper to ensure proper layering above modals
This commit is contained in:
@@ -1,9 +1,14 @@
|
|||||||
import ReactDatePicker from 'react-datepicker';
|
import ReactDatePicker from 'react-datepicker';
|
||||||
import { de } from 'date-fns/locale';
|
import { de } from 'date-fns/locale';
|
||||||
import { Calendar as CalendarIcon, Clock, X } from 'lucide-react';
|
import { Calendar as CalendarIcon, Clock } from 'lucide-react';
|
||||||
import { forwardRef } from 'react';
|
import { forwardRef } from 'react';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
import 'react-datepicker/dist/react-datepicker.css';
|
import 'react-datepicker/dist/react-datepicker.css';
|
||||||
|
|
||||||
|
// Renders the calendar popper into document.body so it never affects the form
|
||||||
|
// layout (prevents the "everything shifts down + auto-scroll" bug).
|
||||||
|
const PopperContainer = ({ children }) => createPortal(children, document.body);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom DateTimePicker that reads the app's CSS variables and
|
* Custom DateTimePicker that reads the app's CSS variables and
|
||||||
* fully matches whatever theme is active.
|
* fully matches whatever theme is active.
|
||||||
@@ -59,6 +64,7 @@ export default function DateTimePicker({
|
|||||||
minDate={minDate}
|
minDate={minDate}
|
||||||
required={required}
|
required={required}
|
||||||
popperPlacement="bottom-start"
|
popperPlacement="bottom-start"
|
||||||
|
popperContainer={PopperContainer}
|
||||||
popperModifiers={[
|
popperModifiers={[
|
||||||
{ name: 'offset', options: { offset: [0, 4] } },
|
{ name: 'offset', options: { offset: [0, 4] } },
|
||||||
{ name: 'preventOverflow', options: { rootBoundary: 'viewport', tether: false, altAxis: true } },
|
{ name: 'preventOverflow', options: { rootBoundary: 'viewport', tether: false, altAxis: true } },
|
||||||
@@ -68,8 +74,6 @@ export default function DateTimePicker({
|
|||||||
dayClassName={(date) => 'dtp-day'}
|
dayClassName={(date) => 'dtp-day'}
|
||||||
timeClassName={() => 'dtp-time-item'}
|
timeClassName={() => 'dtp-time-item'}
|
||||||
renderCustomHeader={CalendarHeader}
|
renderCustomHeader={CalendarHeader}
|
||||||
isClearable
|
|
||||||
clearButtonClassName="dtp-clear-btn"
|
|
||||||
wrapperClassName="dtp-dp-wrapper"
|
wrapperClassName="dtp-dp-wrapper"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ export default function Modal({ title, children, onClose, maxWidth = 'max-w-lg'
|
|||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||||
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm" onClick={onClose} />
|
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm" onClick={onClose} />
|
||||||
<div className={`relative bg-th-card rounded-2xl border border-th-border shadow-2xl w-full ${maxWidth} overflow-hidden`}>
|
<div className={`relative bg-th-card rounded-2xl border border-th-border shadow-2xl w-full ${maxWidth}`}>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between px-6 py-4 border-b border-th-border">
|
<div className="flex items-center justify-between px-6 py-4 border-b border-th-border rounded-t-2xl">
|
||||||
<h2 className="text-lg font-semibold text-th-text">{title}</h2>
|
<h2 className="text-lg font-semibold text-th-text">{title}</h2>
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
@@ -16,7 +16,7 @@ export default function Modal({ title, children, onClose, maxWidth = 'max-w-lg'
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/* Body */}
|
{/* Body */}
|
||||||
<div className="p-6">
|
<div className="p-6 overflow-y-auto max-h-[calc(90vh-4rem)]">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -823,6 +823,11 @@
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Portal-rendered popper must sit above modals (z-50 = 50 in Tailwind) */
|
||||||
|
.react-datepicker-popper {
|
||||||
|
z-index: 9999 !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Header (custom rendered) ─────────────────────────────────── */
|
/* ── Header (custom rendered) ─────────────────────────────────── */
|
||||||
.dtp-calendar .react-datepicker__header {
|
.dtp-calendar .react-datepicker__header {
|
||||||
background: var(--bg-secondary);
|
background: var(--bg-secondary);
|
||||||
|
|||||||
Reference in New Issue
Block a user