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                                    2833x   2833x                   2833x 3446x       3446x 3446x 3446x 3446x 3446x 3446x 3446x   3446x 3415x             3218x     197x                     2833x 1820x 8x     1812x   1812x 1634x     1812x   1812x   1812x 1734x   1734x 1734x   1734x       2833x   2833x          
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 };