Skip to content

Commit

Permalink
[Security Solution][Resolver] Update the resolver element ref on scro…
Browse files Browse the repository at this point in the history
…ll events if the position of the element has changed within the page (#72461)
  • Loading branch information
kqualters-elastic authored Jul 20, 2020
1 parent 9947c67 commit c3263aa
Showing 1 changed file with 49 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down

0 comments on commit c3263aa

Please sign in to comment.