// 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]); }