fix: correct popup fallback positioning offsets (#981)

This commit is contained in:
Sam Potts
2026-03-17 13:14:35 +11:00
committed by GitHub
parent 561d03eb5a
commit 82ede77322
12 changed files with 498 additions and 20 deletions
@@ -2,7 +2,7 @@
import type { TooltipState } from '@videojs/core';
import { TooltipCSSVars } from '@videojs/core';
import { getAnchorPositionStyle, resolveOffsets } from '@videojs/core/dom';
import { getAnchorPositionStyle, getPopupPositionRect, resolveOffsets } from '@videojs/core/dom';
import { supportsAnchorPositioning } from '@videojs/utils/dom';
import type { CSSProperties } from 'react';
import { forwardRef, useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
@@ -73,7 +73,7 @@ export const TooltipPopup = forwardRef<HTMLDivElement, TooltipPopupProps>(functi
if (!triggerEl || !popupEl) return;
const triggerRect = triggerEl.getBoundingClientRect();
const popupRect = popupEl.getBoundingClientRect();
const popupRect = getPopupPositionRect(popupEl);
const boundaryRect = document.documentElement.getBoundingClientRect();
const offsets = resolveOffsets(popupEl, TooltipCSSVars);
@@ -91,19 +91,40 @@ export const TooltipPopup = forwardRef<HTMLDivElement, TooltipPopupProps>(functi
}
measure();
const triggerEl = tooltip.triggerElement;
const popupEl = internalRef.current;
// Recompute on scroll/resize so the tooltip tracks its trigger.
let rafId = 0;
function reposition(): void {
cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(measure);
}
// Re-measure after the tooltip has entered the top layer and whenever
// its own size or the trigger size changes.
reposition();
const resizeObserver =
typeof ResizeObserver === 'function'
? new ResizeObserver(() => {
reposition();
})
: null;
if (triggerEl && resizeObserver) {
resizeObserver.observe(triggerEl);
}
if (popupEl && resizeObserver) {
resizeObserver.observe(popupEl);
}
window.addEventListener('scroll', reposition, { capture: true, passive: true });
window.addEventListener('resize', reposition);
return () => {
cancelAnimationFrame(rafId);
resizeObserver?.disconnect();
window.removeEventListener('scroll', reposition, true);
window.removeEventListener('resize', reposition);
};