All files / hooks useWindowSize.ts

88% Statements 22/25
80% Branches 12/15
100% Functions 7/7
95.45% Lines 21/22

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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120                                                                                                    28x   28x   25x 25x                     28x 3x           28x   25x   25x   25x 3x 1x 1x   2x       25x   25x 25x 25x       28x                                   6x 6x        
/**
 * useWindowSize - Shared hook for responsive window dimensions
 *
 * @korean 윈도우크기훅 - 반응형 창 크기를 위한 공유 훅
 *
 * Eliminates duplication across screen components
 */
 
import { useCallback, useEffect, useState } from "react";
 
export interface WindowSize {
  readonly width: number;
  readonly height: number;
}
 
export interface UseWindowSizeOptions {
  /**
   * Initial width if window is not available (SSR)
   * @default 1200
   */
  readonly initialWidth?: number;
 
  /**
   * Initial height if window is not available (SSR)
   * @default 800
   */
  readonly initialHeight?: number;
 
  /**
   * Debounce delay in milliseconds
   * @default 0
   */
  readonly debounceMs?: number;
}
 
/**
 * Hook to track window dimensions with optional debouncing
 *
 * @korean 윈도우 크기를 추적하는 훅 (선택적 디바운싱 지원)
 *
 * @param options - Configuration options
 * @returns Current window dimensions
 *
 * @example
 * ```tsx
 * const { width, height } = useWindowSize();
 * const isMobile = width < 768;
 * ```
 */
export function useWindowSize(options: UseWindowSizeOptions = {}): WindowSize {
  const { initialWidth = 1200, initialHeight = 800, debounceMs = 0 } = options;
 
  const [size, setSize] = useState<WindowSize>(() => {
    // Check if window is available (SSR safety)
    Eif (typeof window !== "undefined") {
      return {
        width: window.innerWidth,
        height: window.innerHeight,
      };
    }
    return {
      width: initialWidth,
      height: initialHeight,
    };
  });
 
  const handleResize = useCallback(() => {
    setSize({
      width: window.innerWidth,
      height: window.innerHeight,
    });
  }, []);
 
  useEffect(() => {
    // Safety check for SSR
    Iif (typeof window === "undefined") return;
 
    let timeoutId: ReturnType<typeof setTimeout> | null = null;
 
    const debouncedResize = () => {
      if (debounceMs > 0) {
        Iif (timeoutId) clearTimeout(timeoutId);
        timeoutId = setTimeout(handleResize, debounceMs);
      } else {
        handleResize();
      }
    };
 
    window.addEventListener("resize", debouncedResize);
 
    return () => {
      window.removeEventListener("resize", debouncedResize);
      if (timeoutId) clearTimeout(timeoutId);
    };
  }, [handleResize, debounceMs]);
 
  return size;
}
 
/**
 * Hook to determine if current viewport is mobile-sized
 *
 * @korean 현재 뷰포트가 모바일 크기인지 확인하는 훅
 *
 * @param breakpoint - Width threshold for mobile (default: 768)
 * @returns True if viewport width is less than breakpoint
 *
 * @example
 * ```tsx
 * const isMobile = useIsMobile();
 * const isMobileCustom = useIsMobile(640);
 * ```
 */
export function useIsMobile(breakpoint = 768): boolean {
  const { width } = useWindowSize();
  return width < breakpoint;
}
 
export default useWindowSize;