// Applies the stored reduced-motion override (see `settings-storage.ts`) // as a `data-motion="reduce"|"allow"` attribute on ``, cleared // when the override is "system" (letting `prefers-reduced-motion` // alone decide, same as today). // // Built ahead of swarm-ui having any CSS animation to gate — the // settings surface itself was scoped to cover theme *and* motion // together (both named in the same go-ahead), and the marginal cost of // the storage/attribute plumbing was near zero riding alongside the // theme override's real wiring. `Shell`'s page-switch animation (the // nav indicator's slide + the page-body pop) is the first real // consumer — see `shell/Shell.css`'s file-top comment for the // three-rule gate shape every animation here follows: // @media (prefers-reduced-motion: reduce) { ... } // :root[data-motion='reduce'] { ... same rule ... } // :root[data-motion='allow'] { /* opt back in despite OS-level reduce */ } import { useEffect } from 'preact/hooks'; import { useLocalSetting } from './settings-storage.js'; export type MotionOverride = 'system' | 'reduce' | 'allow'; export const MOTION_OVERRIDE_KEY = 'swarm-ui:motion-override'; export function useMotionOverride() { return useLocalSetting(MOTION_OVERRIDE_KEY, 'system'); } // Mounted once alongside `useApplyThemeOverride` — see that module's // comment for why `Shell` is the right single mount point. export function useApplyMotionOverride(): void { const [override] = useMotionOverride(); useEffect(() => { const root = document.documentElement; if (override === 'system') { delete root.dataset.motion; } else { root.dataset.motion = override; } }, [override]); }