- useMediaQuery: SSR-safe hook with addEventListener for live breakpoint updates - usePullToRefresh: touch gesture hook with 64px threshold, haptic feedback via navigator.vibrate - PullToRefresh: visual wrapper with Loader2 spinner, pull/release text indicators
29 lines
837 B
TypeScript
29 lines
837 B
TypeScript
import { useEffect, useState } from "react";
|
|
|
|
/**
|
|
* Responsive breakpoint hook. Returns true when the media query matches.
|
|
* SSR-safe: defaults to false if window is undefined.
|
|
*/
|
|
export function useMediaQuery(query: string): boolean {
|
|
const [matches, setMatches] = useState<boolean>(() => {
|
|
if (typeof window === "undefined") return false;
|
|
return window.matchMedia(query).matches;
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (typeof window === "undefined") return;
|
|
const mediaQueryList = window.matchMedia(query);
|
|
setMatches(mediaQueryList.matches);
|
|
|
|
const handler = (event: MediaQueryListEvent) => {
|
|
setMatches(event.matches);
|
|
};
|
|
|
|
mediaQueryList.addEventListener("change", handler);
|
|
return () => {
|
|
mediaQueryList.removeEventListener("change", handler);
|
|
};
|
|
}, [query]);
|
|
|
|
return matches;
|
|
}
|