[Security Solution][Resolver] Update the resolver element ref on scroll events if the position of the element has changed within the page (#72461)
This commit is contained in:
parent
9947c671ec
commit
c3263aa9a2
|
@ -281,17 +281,61 @@ export function useCamera(): {
|
|||
* handle that.
|
||||
*/
|
||||
export function useAutoUpdatingClientRect(): [DOMRect | null, (node: Element | null) => void] {
|
||||
// This hooks returns `rect`.
|
||||
const [rect, setRect] = useState<DOMRect | null>(null);
|
||||
// Using state as ref.current update does not trigger effect hook when reset
|
||||
|
||||
const { ResizeObserver, requestAnimationFrame } = useContext(SideEffectContext);
|
||||
|
||||
// Keep the current DOM node in state so that we can create a ResizeObserver for it via `useEffect`.
|
||||
const [currentNode, setCurrentNode] = useState<Element | null>(null);
|
||||
|
||||
// `ref` will be used with a react element. When the element is available, this function will be called.
|
||||
const ref = useCallback((node: Element | null) => {
|
||||
// track the node in state
|
||||
setCurrentNode(node);
|
||||
if (node !== null) {
|
||||
setRect(node.getBoundingClientRect());
|
||||
}
|
||||
}, []);
|
||||
const { ResizeObserver } = useContext(SideEffectContext);
|
||||
|
||||
/**
|
||||
* Any time the DOM node changes (to something other than `null`) recalculate the DOMRect and set it (which will cause it to be returned from the hook.
|
||||
* This effect re-runs when the DOM node has changed.
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (currentNode !== null) {
|
||||
// When the DOM node is received, immedaiately calculate its DOM Rect and return that
|
||||
setRect(currentNode.getBoundingClientRect());
|
||||
}
|
||||
}, [currentNode]);
|
||||
|
||||
/**
|
||||
* When scroll events occur, recalculate the DOMRect. DOMRect represents the position of an element relative to the viewport, so that may change during scroll (depending on the layout.)
|
||||
* This effect re-runs when the DOM node has changed.
|
||||
*/
|
||||
useEffect(() => {
|
||||
// the last scrollX and scrollY values that we handled
|
||||
let previousX: number = window.scrollX;
|
||||
let previousY: number = window.scrollY;
|
||||
|
||||
const handleScroll = () => {
|
||||
requestAnimationFrame(() => {
|
||||
// synchronously read from the DOM
|
||||
const currentX = window.scrollX;
|
||||
const currentY = window.scrollY;
|
||||
|
||||
if (currentNode !== null && (previousX !== currentX || previousY !== currentY)) {
|
||||
setRect(currentNode.getBoundingClientRect());
|
||||
}
|
||||
|
||||
previousX = currentX;
|
||||
previousY = currentY;
|
||||
});
|
||||
};
|
||||
|
||||
window.addEventListener('scroll', handleScroll, { passive: true });
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, [currentNode, requestAnimationFrame]);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentNode !== null) {
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
|
|
Loading…
Reference in a new issue