import { useEffect, useState } from 'react'; // Breakpoints (px): mobile <768, tablet 768-1023, desktop >=1024. const MOBILE_MAX = 767; const TABLET_MAX = 1023; export interface ViewportSnapshot { isMobile: boolean; isTablet: boolean; width: number; } function snapshot(): ViewportSnapshot { if (typeof window === 'undefined') { return { isMobile: false, isTablet: false, width: 1280 }; } const width = window.innerWidth; return { isMobile: width <= MOBILE_MAX, isTablet: width > MOBILE_MAX && width <= TABLET_MAX, width, }; } // matchMedia-based, no resize polling. We listen to two breakpoint queries // and recompute the snapshot on any change. export function useViewport(): ViewportSnapshot { const [state, setState] = useState(snapshot); useEffect(() => { if (typeof window === 'undefined') return; const mobileMq = window.matchMedia(`(max-width: ${MOBILE_MAX}px)`); const tabletMq = window.matchMedia(`(min-width: ${MOBILE_MAX + 1}px) and (max-width: ${TABLET_MAX}px)`); const update = () => setState(snapshot()); mobileMq.addEventListener('change', update); tabletMq.addEventListener('change', update); update(); return () => { mobileMq.removeEventListener('change', update); tabletMq.removeEventListener('change', update); }; }, []); return state; }