All files / utils motionPrefs.js

100% Statements 18/18
90% Branches 9/10
100% Functions 6/6
100% Lines 16/16

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                                      9x 9x     9x 3x 6x     6x 5x 5x 3x 3x     5x                   7x 7x                 2x 2x 2x    
/*
 * Copyright (c) 2022-2023 Braun Nathanael
 *
 * This project is dual licensed under one of the following licenses:
 * - Creative Commons Attribution-NoDerivatives 4.0 International License.
 * - GNU AFFERO GENERAL PUBLIC LICENSE Version 3
 *
 * You should have received a copy of theses licenses along with this work.
 * If not, see <http://creativecommons.org/licenses/by-nd/4.0/> or <http://www.gnu.org/licenses/agpl-3.0.txt>.
 */
 
/**
 * prefers-reduced-motion detection — shared, lazily-initialised matchMedia watcher.
 *
 * SSR-safe: on the server (or any environment without window.matchMedia) the
 * preference always reads false. The media query list is created on first use and
 * shared by every Tweener / hook in the page.
 */
 
let mql, current = false;
const listeners = new Set();
 
function init() {
	if ( mql !== undefined )
		return;
	mql = (typeof window !== 'undefined' && window.matchMedia)
	      ? window.matchMedia('(prefers-reduced-motion: reduce)')
	      : null;
	if ( mql ) {
		current        = mql.matches;
		const onChange = e => {
			current = e.matches;
			listeners.forEach(l => l(current));
		};
		// Safari < 14 only implements the deprecated addListener API
		mql.addEventListener
		? mql.addEventListener('change', onChange)
		: mql.addListener(onChange);
	}
}
 
/**
 * @returns {boolean} true when the user's OS requests reduced motion
 */
export function prefersReducedMotion() {
	init();
	return current;
}
 
/**
 * Subscribe to preference changes.
 * @param {function(boolean)} cb called with the new preference value
 * @returns {function} unsubscribe
 */
export function onReducedMotionChange( cb ) {
	init();
	listeners.add(cb);
	return () => listeners.delete(cb);
}