ultisuite-client/hooks/use-touch-nav.ts

50 lines
1.5 KiB
TypeScript

import { useLayoutEffect, useState } from "react"
import { readXsMatches, XS_MAX_PX } from "@/hooks/use-xs"
/** Primary input is touch without reliable hover (tablets, phones). */
export const COARSE_POINTER_MQ = "(hover: none) and (pointer: coarse)"
export function readCoarsePointerMatches(): boolean {
if (typeof window === "undefined") return false
return window.matchMedia(COARSE_POINTER_MQ).matches
}
/** Mobile layout or touch-first navigation (no hover peek, overlay when open). */
export function readTouchNavMatches(): boolean {
return readXsMatches() || readCoarsePointerMatches()
}
export function useTouchNav() {
const [touchNav, setTouchNav] = useState(false)
useLayoutEffect(() => {
const xsMq = `(max-width: ${XS_MAX_PX}px)`
const mqlXs = window.matchMedia(xsMq)
const mqlCoarse = window.matchMedia(COARSE_POINTER_MQ)
const update = () => setTouchNav(readTouchNavMatches())
update()
mqlXs.addEventListener("change", update)
mqlCoarse.addEventListener("change", update)
return () => {
mqlXs.removeEventListener("change", update)
mqlCoarse.removeEventListener("change", update)
}
}, [])
return touchNav
}
export function useCoarsePointer() {
const [coarse, setCoarse] = useState(false)
useLayoutEffect(() => {
const mql = window.matchMedia(COARSE_POINTER_MQ)
const update = () => setCoarse(readCoarsePointerMatches())
update()
mql.addEventListener("change", update)
return () => mql.removeEventListener("change", update)
}, [])
return coarse
}