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                                    1679x   1679x                   1679x 2117x       2117x 2117x 2117x 2117x 2117x 2117x 2117x   2117x 2098x             1970x     128x                     1679x 1140x 3x     1137x   1137x 980x     1137x   1137x   1137x 1083x   1083x 1083x   1083x       1679x   1679x          
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 };