import { useState, useEffect } from 'react'; /** * Device type enum */ export type DeviceType = 'mobile' | 'tablet' | 'desktop'; /** * Device detection result */ export interface DeviceInfo { isMobile: boolean; isTablet: boolean; isDesktop: boolean; deviceType: DeviceType; isTouchDevice: boolean; screenWidth: number; screenHeight: number; } /** * Breakpoints for device detection */ const BREAKPOINTS = { mobile: 768, // < 768px tablet: 1024, // 768px - 1024px desktop: 1024, // >= 1024px }; /** * Detect device type based on User Agent */ const detectDeviceFromUserAgent = (): DeviceType => { const ua = navigator.userAgent.toLowerCase(); // Mobile devices if (/(android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini)/i.test(ua)) { // Distinguish between tablet and mobile if (/(ipad|tablet|playbook|silk)|(android(?!.*mobile))/i.test(ua)) { return 'tablet'; } return 'mobile'; } return 'desktop'; }; /** * Detect device type based on screen width */ const detectDeviceFromScreenWidth = (width: number): DeviceType => { if (width < BREAKPOINTS.mobile) { return 'mobile'; } else if (width < BREAKPOINTS.desktop) { return 'tablet'; } return 'desktop'; }; /** * Check if device supports touch */ const isTouchDevice = (): boolean => { return ( 'ontouchstart' in window || navigator.maxTouchPoints > 0 || // @ts-ignore - for older browsers navigator.msMaxTouchPoints > 0 ); }; /** * Get current device information */ const getDeviceInfo = (): DeviceInfo => { const width = window.innerWidth; const height = window.innerHeight; // Combine User Agent and screen width detection const uaDevice = detectDeviceFromUserAgent(); const screenDevice = detectDeviceFromScreenWidth(width); // Prefer User Agent detection, but fall back to screen width const deviceType = uaDevice !== 'desktop' ? uaDevice : screenDevice; return { isMobile: deviceType === 'mobile', isTablet: deviceType === 'tablet', isDesktop: deviceType === 'desktop', deviceType, isTouchDevice: isTouchDevice(), screenWidth: width, screenHeight: height, }; }; /** * Custom hook to detect device type and screen size * * @returns DeviceInfo object with device detection results * * @example * ```tsx * const { isMobile, isDesktop, deviceType } = useDevice(); * * return ( *
* {isMobile && } * {isDesktop && } *
* ); * ``` */ export const useDevice = (): DeviceInfo => { const [deviceInfo, setDeviceInfo] = useState(getDeviceInfo); useEffect(() => { const handleResize = () => { setDeviceInfo(getDeviceInfo()); }; // Listen for window resize window.addEventListener('resize', handleResize); // Listen for orientation change (mobile devices) window.addEventListener('orientationchange', handleResize); return () => { window.removeEventListener('resize', handleResize); window.removeEventListener('orientationchange', handleResize); }; }, []); return deviceInfo; }; /** * Hook to check if current device is mobile * * @returns boolean indicating if device is mobile * * @example * ```tsx * const isMobile = useIsMobile(); * ``` */ export const useIsMobile = (): boolean => { const { isMobile } = useDevice(); return isMobile; }; /** * Hook to check if current device is desktop * * @returns boolean indicating if device is desktop * * @example * ```tsx * const isDesktop = useIsDesktop(); * ``` */ export const useIsDesktop = (): boolean => { const { isDesktop } = useDevice(); return isDesktop; }; /** * Hook to check if current device is tablet * * @returns boolean indicating if device is tablet * * @example * ```tsx * const isTablet = useIsTablet(); * ``` */ export const useIsTablet = (): boolean => { const { isTablet } = useDevice(); return isTablet; };