32 lines
1.1 KiB
TypeScript
32 lines
1.1 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import { usePreferencesStore } from '../stores/preferences-store'
|
|
|
|
/**
|
|
* Returns true when motion should be reduced. Combines:
|
|
* - The user's `reduceMotion` app preference
|
|
* - The OS-level `prefers-reduced-motion: reduce` media query
|
|
*
|
|
* Either source can opt the user in. Components can use the result to
|
|
* skip large entry/exit animations or replace springs with instant
|
|
* transitions.
|
|
*/
|
|
export function useReducedMotion(): boolean {
|
|
const userPref = usePreferencesStore(s => s.reduceMotion)
|
|
const [osPref, setOsPref] = useState(false)
|
|
|
|
useEffect(() => {
|
|
if (typeof window === 'undefined' || !window.matchMedia) return
|
|
const mq = window.matchMedia('(prefers-reduced-motion: reduce)')
|
|
setOsPref(mq.matches)
|
|
const listener = (e: MediaQueryListEvent) => setOsPref(e.matches)
|
|
if (mq.addEventListener) mq.addEventListener('change', listener)
|
|
else mq.addListener(listener)
|
|
return () => {
|
|
if (mq.removeEventListener) mq.removeEventListener('change', listener)
|
|
else mq.removeListener(listener)
|
|
}
|
|
}, [])
|
|
|
|
return userPref || osPref
|
|
}
|