All files / platform/core/src/hooks useViewportSize.ts

96.87% Statements 31/32
92.3% Branches 12/13
100% Functions 7/7
96.77% Lines 30/31

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98                                    772x   772x                   772x 911x       911x 911x 911x 911x 911x 911x 911x   911x 892x             816x     76x                     772x 500x 3x     497x   497x 414x     497x   497x   497x 463x   463x 463x   463x       772x   772x          
import { useEffect, useState, useCallback, useMemo } from 'react';
import { useViewportRef } from './';
 
interface ViewportSize {
  width: number;
  height: number;
  offsetLeft: number;
  offsetTop: number;
  clientRect: DOMRect | null;
  isVisible: boolean;
}
 
/**
 * Hook that provides viewport size dimensions and monitors for changes
 * @param viewportId - The ID of the viewport to monitor
 * @returns ViewportSize object containing width, height, and visibility info
 */
function useViewportSize(viewportId: string): ViewportSize {
  const viewportElementRef = useViewportRef(viewportId);
 
  const [size, setSize] = useState<ViewportSize>({
    width: 0,
    height: 0,
    offsetLeft: 0,
    offsetTop: 0,
    clientRect: null,
    isVisible: false,
  });
 
  // Update viewport dimensions
  const updateViewportSize = useCallback(() => {
    Iif (!viewportElementRef?.current) {
      return;
    }
 
    const element = viewportElementRef.current;
    const clientRect = element.getBoundingClientRect();
    const newWidth = clientRect.width;
    const newHeight = clientRect.height;
    const newOffsetLeft = element.offsetLeft;
    const newOffsetTop = element.offsetTop;
    const newIsVisible = newWidth > 0 && newHeight > 0;
 
    setSize(prevSize => {
      if (
        prevSize.width === newWidth &&
        prevSize.height === newHeight &&
        prevSize.offsetLeft === newOffsetLeft &&
        prevSize.offsetTop === newOffsetTop &&
        prevSize.isVisible === newIsVisible
      ) {
        return prevSize;
      }
 
      return {
        width: newWidth,
        height: newHeight,
        offsetLeft: newOffsetLeft,
        offsetTop: newOffsetTop,
        clientRect,
        isVisible: newIsVisible,
      };
    });
  }, [viewportElementRef]);
 
  useEffect(() => {
    if (!viewportId || !viewportElementRef?.current) {
      return;
    }
 
    updateViewportSize();
 
    const resizeObserver = new ResizeObserver(() => {
      updateViewportSize();
    });
 
    resizeObserver.observe(viewportElementRef.current);
 
    window.addEventListener('resize', updateViewportSize);
 
    return () => {
      window.removeEventListener('resize', updateViewportSize);
 
      if (viewportElementRef.current) {
        resizeObserver.unobserve(viewportElementRef.current);
      }
      resizeObserver.disconnect();
    };
  }, [viewportId, viewportElementRef, updateViewportSize]);
 
  const memoizedSize = useMemo(() => size, [size]);
 
  return memoizedSize;
}
 
export default useViewportSize;
export { useViewportSize };