✨(react) position top datepicker
Position the datepicker on top of the input when the input is at the bottom of the screen and whenthere is enough space to display the datepicker on the top.
This commit is contained in:
committed by
Jean-Baptiste PENRATH
parent
6ea8544fed
commit
9edb9765db
@@ -1,4 +1,10 @@
|
||||
import React, { PropsWithChildren, RefObject } from "react";
|
||||
import React, {
|
||||
PropsWithChildren,
|
||||
RefObject,
|
||||
useLayoutEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import classNames from "classnames";
|
||||
import { useHandleClickOutside } from ":/hooks/useHandleClickOutside";
|
||||
|
||||
@@ -14,13 +20,54 @@ export const Popover = ({
|
||||
onClickOutside,
|
||||
borderless = false,
|
||||
}: PopoverProps) => {
|
||||
const popoverRef = useRef<HTMLDivElement>(null);
|
||||
useHandleClickOutside(parentRef, onClickOutside);
|
||||
const timeout = useRef<ReturnType<typeof setTimeout>>();
|
||||
const [topPosition, setTopPosition] = useState<number | undefined>();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const setPopoverTopPosition = () => {
|
||||
if (!parentRef.current || !popoverRef.current) return;
|
||||
|
||||
const parentBounds = parentRef.current.getBoundingClientRect();
|
||||
const popoverBounds = popoverRef.current.getBoundingClientRect();
|
||||
|
||||
const hasNotEnoughBottomPlace =
|
||||
window.innerHeight - parentBounds.bottom < popoverBounds.height;
|
||||
|
||||
const hasEnoughTopPlace = parentBounds.top >= popoverBounds.height;
|
||||
|
||||
if (hasNotEnoughBottomPlace && hasEnoughTopPlace) {
|
||||
setTopPosition(-popoverBounds.height);
|
||||
} else {
|
||||
setTopPosition(undefined);
|
||||
}
|
||||
};
|
||||
|
||||
const handleWindowResize = () => {
|
||||
if (timeout.current) clearTimeout(timeout.current);
|
||||
timeout.current = setTimeout(setPopoverTopPosition, 1000 / 30);
|
||||
};
|
||||
|
||||
window.addEventListener("resize", handleWindowResize);
|
||||
setPopoverTopPosition();
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("resize", handleWindowResize);
|
||||
if (timeout.current) clearTimeout(timeout.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={popoverRef}
|
||||
className={classNames("c__popover", {
|
||||
"c__popover--borderless": borderless,
|
||||
})}
|
||||
style={{
|
||||
top: topPosition,
|
||||
}}
|
||||
role="dialog"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user