import * as React from "react"; const MOBILE_BREAKPOINT = 768; const TABLET_BREAKPOINT = 1280; export function useIsMobile() { const [isMobile, setIsMobile] = React.useState( undefined ); React.useEffect(() => { const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`); const onChange = () => { setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); }; mql.addEventListener("change", onChange); setIsMobile(window.innerWidth < MOBILE_BREAKPOINT); return () => mql.removeEventListener("change", onChange); }, []); return !!isMobile; } export type ViewportDevice = "mobile" | "tablet" | "desktop"; export function useViewportDevice(): ViewportDevice { const [device, setDevice] = React.useState("desktop"); React.useEffect(() => { const updateDevice = () => { const width = window.innerWidth; if (width < MOBILE_BREAKPOINT) { setDevice("mobile"); return; } if (width < TABLET_BREAKPOINT) { setDevice("tablet"); return; } setDevice("desktop"); }; updateDevice(); window.addEventListener("resize", updateDevice); return () => window.removeEventListener("resize", updateDevice); }, []); return device; } export function useViewportFlags() { const device = useViewportDevice(); const [isTouchLike, setIsTouchLike] = React.useState(false); const [prefersReducedMotion, setPrefersReducedMotion] = React.useState(false); React.useEffect(() => { const pointerMedia = window.matchMedia("(pointer: coarse)"); const motionMedia = window.matchMedia("(prefers-reduced-motion: reduce)"); const updateFlags = () => { setIsTouchLike(pointerMedia.matches || navigator.maxTouchPoints > 0); setPrefersReducedMotion(motionMedia.matches); }; updateFlags(); pointerMedia.addEventListener("change", updateFlags); motionMedia.addEventListener("change", updateFlags); return () => { pointerMedia.removeEventListener("change", updateFlags); motionMedia.removeEventListener("change", updateFlags); }; }, []); return { device, isMobile: device === "mobile", isTablet: device === "tablet", isDesktop: device === "desktop", isTouchLike, prefersReducedMotion, }; }