83 lines
2.3 KiB
TypeScript
83 lines
2.3 KiB
TypeScript
import * as React from "react";
|
|
|
|
const MOBILE_BREAKPOINT = 768;
|
|
const TABLET_BREAKPOINT = 1280;
|
|
|
|
export function useIsMobile() {
|
|
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
|
|
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<ViewportDevice>("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,
|
|
};
|
|
}
|