All files / src/utils use-reduced-motion.ts

20% Statements 4/20
0% Branches 0/6
0% Functions 0/3
23.53% Lines 4/17

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 6730x 30x 30x                                                                                                   30x                            
import { useState } from "react"
import { motionValue, MotionValue } from "../value"
import { useOnChange } from "../value/use-on-change"
 
// Does this device prefer reduced motion? Returns `null` server-side.
let prefersReducedMotion: MotionValue<boolean | null>
 
function initPrefersReducedMotion() {
    prefersReducedMotion = motionValue(null)
 
    if (typeof window === "undefined") return
 
    if (window.matchMedia) {
        const motionMediaQuery = window.matchMedia("(prefers-reduced-motion)")
 
        const setReducedMotionPreferences = () =>
            prefersReducedMotion.set(motionMediaQuery.matches)
 
        motionMediaQuery.addListener(setReducedMotionPreferences)
 
        setReducedMotionPreferences()
    } else {
        prefersReducedMotion.set(false)
    }
}
 
/**
 * A hook that returns `true` if we should be using reduced motion based on the current device's Reduced Motion setting.
 *
 * This can be used to implement changes to your UI based on Reduced Motion. For instance, replacing motion-sickness inducing
 * `x`/`y` animations with `opacity`, disabling the autoplay of background videos, or turning off parallax motion.
 *
 * It will actively respond to changes and re-render your components with the latest setting.
 *
 * ```jsx
 * export function Sidebar({ isOpen }) {
 *   const shouldReduceMotion = useReducedMotion()
 *   const closedX = shouldReduceMotion ? 0 : "-100%"
 *
 *   return (
 *     <motion.div animate={{
 *       opacity: isOpen ? 1 : 0,
 *       x: isOpen ? 0 : closedX
 *     }} />
 *   )
 * }
 * ```
 *
 * @return boolean
 *
 * @public
 */
export function useReducedMotion() {
    /**
     * Lazy initialisation of prefersReducedMotion
     */
    !prefersReducedMotion && initPrefersReducedMotion()
 
    const [shouldReduceMotion, setShouldReduceMotion] = useState(
        prefersReducedMotion.get()
    )
 
    useOnChange(prefersReducedMotion, setShouldReduceMotion)
 
    return shouldReduceMotion
}