30 lines
971 B
TypeScript
30 lines
971 B
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { useEffect, useState } from 'react';
|
||
|
|
|
||
|
|
const MOBILE_QUERY = '(max-width: 1023.98px)';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns true when the viewport is below the `lg` Tailwind breakpoint.
|
||
|
|
* Backed by a media-query listener; safe to call from any client component.
|
||
|
|
* Server renders return `false` (desktop default) — clients hydrate to the
|
||
|
|
* true viewport state on mount.
|
||
|
|
*
|
||
|
|
* Not unit-tested: the repo's vitest is configured for environment='node'
|
||
|
|
* (no @testing-library/react / DOM env). Verified through the mobile-shell
|
||
|
|
* Playwright visual snapshots in Task 23.
|
||
|
|
*/
|
||
|
|
export function useIsMobile(): boolean {
|
||
|
|
const [isMobile, setIsMobile] = useState(false);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
const mq = window.matchMedia(MOBILE_QUERY);
|
||
|
|
const update = (e: { matches: boolean }) => setIsMobile(e.matches);
|
||
|
|
setIsMobile(mq.matches);
|
||
|
|
mq.addEventListener('change', update);
|
||
|
|
return () => mq.removeEventListener('change', update);
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return isMobile;
|
||
|
|
}
|