// Applies a stored reduced-motion override as a `data-motion="reduce"| // "allow"` attribute on ``, cleared when the override is "system" // (letting `prefers-reduced-motion` alone decide). Ported from swarm-ui // verbatim, only the storage key is now caller-supplied instead of a // module constant — see `theme-apply.ts`'s file comment for why. // // A consumer's CSS gates an animation with the three-rule shape this // was built for: // @media (prefers-reduced-motion: reduce) { ... } // :root[data-motion='reduce'] { ... same rule ... } // :root[data-motion='allow'] { /* opt back in despite OS-level reduce */ } // (see swarm-ui's `shell/Shell.css` file-top comment for a worked // example). A page with no motion-gated animation yet can still mount // this — the attribute is simply inert until something reads it. import { useEffect } from 'preact/hooks'; import { useLocalSetting } from './settings-storage.js'; export type MotionOverride = 'system' | 'reduce' | 'allow'; export function useMotionOverride(key: string, fallback: MotionOverride = 'system') { return useLocalSetting(key, fallback); } // Mounted once alongside `useApplyThemeOverride` — same single-mount- // point rationale. export function useApplyMotionOverride(key: string, fallback: MotionOverride = 'system'): void { const [override] = useMotionOverride(key, fallback); useEffect(() => { const root = document.documentElement; if (override === 'system') { delete root.dataset.motion; } else { root.dataset.motion = override; } }, [override]); }