fix(datepicker): avoid offscreen calendar placement

This commit is contained in:
2026-06-07 15:37:26 +03:30
parent 666d04ff26
commit 03c7c07a9f

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react" import React, { useEffect, useRef, useState } from "react"
import DatePicker, { DateObject } from "react-multi-date-picker" import DatePicker, { DateObject } from "react-multi-date-picker"
import persian from "react-date-object/calendars/persian" import persian from "react-date-object/calendars/persian"
import persian_fa from "react-date-object/locales/persian_fa" import persian_fa from "react-date-object/locales/persian_fa"
@@ -18,6 +18,8 @@ interface JalaliDatePickerProps {
export default function JalaliDatePicker({ value, onChange, label, disabled, inputClassName = "", placeholder }: JalaliDatePickerProps) { export default function JalaliDatePicker({ value, onChange, label, disabled, inputClassName = "", placeholder }: JalaliDatePickerProps) {
const isFa = document.documentElement.dir === 'rtl' const isFa = document.documentElement.dir === 'rtl'
const [isDark, setIsDark] = useState(document.documentElement.classList.contains('dark')) const [isDark, setIsDark] = useState(document.documentElement.classList.contains('dark'))
const containerRef = useRef<HTMLDivElement>(null)
const [calendarPosition, setCalendarPosition] = useState("bottom-right")
// Listen for dark mode changes dynamically (optional but good for UX) // Listen for dark mode changes dynamically (optional but good for UX)
useEffect(() => { useEffect(() => {
@@ -37,8 +39,19 @@ export default function JalaliDatePicker({ value, onChange, label, disabled, inp
} }
} }
const updateCalendarPosition = () => {
const rect = containerRef.current?.getBoundingClientRect()
if (!rect) return
const estimatedHeight = 340
const hasMoreSpaceAbove = rect.top > window.innerHeight - rect.bottom
const shouldOpenTop = window.innerHeight - rect.bottom < estimatedHeight && hasMoreSpaceAbove
const horizontal = isFa ? "left" : "right"
setCalendarPosition(`${shouldOpenTop ? "top" : "bottom"}-${horizontal}`)
}
return ( return (
<div className="w-full"> <div ref={containerRef} className="w-full">
{label && ( {label && (
<label className="text-sm font-medium dark:text-slate-300 mb-1 block"> <label className="text-sm font-medium dark:text-slate-300 mb-1 block">
{label} {label}
@@ -52,10 +65,11 @@ export default function JalaliDatePicker({ value, onChange, label, disabled, inp
format="YYYY/MM/DD" format="YYYY/MM/DD"
placeholder={placeholder || "YYYY/MM/DD"} placeholder={placeholder || "YYYY/MM/DD"}
onOpenPickNewDate={false} onOpenPickNewDate={false}
onOpen={updateCalendarPosition}
inputClass={`w-full rounded-md border border-slate-300 bg-transparent px-3 py-2 text-sm dark:border-slate-700 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed ${inputClassName}`} inputClass={`w-full rounded-md border border-slate-300 bg-transparent px-3 py-2 text-sm dark:border-slate-700 dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:opacity-50 disabled:cursor-not-allowed ${inputClassName}`}
containerClassName="w-full" containerClassName="w-full"
className={isDark ? "bg-dark" : ""} className={isDark ? "bg-dark" : ""}
calendarPosition="bottom-right" calendarPosition={calendarPosition}
fixMainPosition fixMainPosition
disabled={disabled} disabled={disabled}
/> />