[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:
Kevin Qualters 2020-07-20 17:41:25 -04:00 committed by GitHub
parent 9947c671ec
commit c3263aa9a2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -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) => {