Keep centered popovers inside the viewport and place them before paint

Measure the popover in a hidden, out-of-flow state and position it in a
layout effect, so opening it no longer grows the page for a frame.
Centered (top/bottom) popovers are clamped to stay within the viewport.
Also ignore /test and /.tmp.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-25 04:58:51 +01:00
co-authored by Claude Opus 5.5
parent f9fa9da091
commit d9b1463db2
3 changed files with 80 additions and 10 deletions
+36 -8
View File
@@ -14,6 +14,17 @@ type Props = TWUI_MODAL_PROPS & {
popoverContentActiveRef: React.MutableRefObject<boolean>;
};
/**
* How the popover renders before it has been placed: out of the flow and
* invisible, so it can be measured without moving anything.
*/
const UnplacedStyle: React.CSSProperties = {
position: "absolute",
top: 0,
left: 0,
visibility: "hidden",
};
/**
* # Modal Main Component
*/
@@ -30,16 +41,32 @@ export default function PopoverComponent({
isPopover,
...props
}: Props) {
const [style, setStyle] = React.useState({});
const contentRef = React.useRef<HTMLDivElement>(null);
const [style, setStyle] = React.useState<React.CSSProperties | null>(
null,
);
React.useEffect(() => {
if (open && targetElRef?.current) {
const popoverStyle = twuiGrabPopoverStyles({
/**
* Placed before the browser paints, against the popover's own size:
* until then it is rendered out of the flow and hidden, so opening it
* never grows the page for a frame (a scrollbar appearing and the
* layout jumping).
*/
React.useLayoutEffect(() => {
if (!open) {
setStyle(null);
return;
}
if (!targetElRef?.current) return;
setStyle(
twuiGrabPopoverStyles({
position,
targetElRef,
});
setStyle(popoverStyle);
}
contentEl: contentRef.current,
}),
);
}, [open, targetElRef, position]);
const closeTimeoutRef = React.useRef<any>(null);
@@ -79,7 +106,8 @@ export default function PopoverComponent({
"twui-popover-content",
props.className,
)}
style={{ ...style, ...props.style }}
componentRef={contentRef}
style={{ ...(style || UnplacedStyle), ...props.style }}
onMouseEnter={
trigger === "hover" ? popoverEnterFn : props.onMouseEnter
}