import * as React from "react"; import { applyReducedMotionToDocument, readMotionPreference, resolveReducedMotion, subscribeMotionPreference, type MotionPreference, writeMotionPreference, } from "../../utils/motionPreference"; export interface MotionPreferenceControlProps { compact?: boolean; className?: string; } const OPTIONS: readonly { value: MotionPreference; label: string; help: string }[] = [ { value: "system", label: "System", help: "Follow the operating system reduced-motion setting.", }, { value: "reduce", label: "Reduced", help: "Pause autoplay and minimize interface transitions.", }, { value: "no-preference", label: "Full", help: "Allow smooth camera transitions and procedural animation.", }, ]; function useMotionPreferenceSnapshot(): { preference: MotionPreference; reducedMotion: boolean; setPreference: (preference: MotionPreference) => void; } { const subscribe = React.useCallback((listener: () => void) => subscribeMotionPreference(listener), []); const getSnapshot = React.useCallback(() => readMotionPreference(), []); const preference = React.useSyncExternalStore(subscribe, getSnapshot, getSnapshot); const reducedMotion = resolveReducedMotion(preference); React.useEffect(() => { applyReducedMotionToDocument(reducedMotion); }, [reducedMotion]); const setPreference = React.useCallback((nextPreference: MotionPreference) => { writeMotionPreference(nextPreference); }, []); return { preference, reducedMotion, setPreference }; } export function MotionPreferenceControl({ compact = false, className = "", }: MotionPreferenceControlProps): JSX.Element { const { preference, reducedMotion, setPreference } = useMotionPreferenceSnapshot(); if (compact) { return ( Motion preference Motion setPreference(event.currentTarget.value as MotionPreference)} > {OPTIONS.map((option) => ( {option.label} ))} ); } return ( Motion preference {reducedMotion ? "Reduced motion is active; autoplay is paused and camera transitions are minimized." : "Full motion is active; animations and smooth camera moves are enabled."} {reducedMotion ? "Reduced" : "Full"} {OPTIONS.map((option) => ( setPreference(option.value)} > {option.label} ))} ); }
{reducedMotion ? "Reduced motion is active; autoplay is paused and camera transitions are minimized." : "Full motion is active; animations and smooth camera moves are enabled."}