summaryrefslogtreecommitdiff
path: root/shared/components/src/stores/media-query.ts
blob: 83cc05561718c3dcaa987eb6495430d663524eb3 (plain)
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
61
62
63
// Based on https://github.com/cibernox/svelte-media
import { readable } from 'svelte/store';
import { ArtworkConfig } from '@amp/web-app-components/config/components/artwork';
import { getMediaConditions } from '@amp/web-app-components/src/utils/getMediaConditions';

const { BREAKPOINTS } = ArtworkConfig.get();
const mqConditions = getMediaConditions(BREAKPOINTS);

const DEFAULT_SETTING = 'medium';

/**
 * Filters media query results and outputs the breakpoint name with a matching media query.
 *
 * @param {Object} mqls media query configurations (pulled from getMediaConditions())
 * @returns {String|undefined} breakpoint string that matches current media query
 */
function calculateMediaQuery(mqls: Record<string, MediaQueryList>): string {
    return Object.entries(mqls)
        .filter(([_, query]) => query.matches)
        .map(([name, _]) => name)[0];
}

/**
 * This function allows to build a store that tracks which of the given media query conditions matches.
 * @param initialValue The inital value for the store. It only bears importance in server side rendering
 * as it will update immediately in the browser
 * @param mediaQueryConditions The dictionary with the media query names and the MQ condition to match against.
 * @returns Svelte.Store<string> The name of the matching media query
 */
export function buildMediaQueryStore(
    initialValue: string,
    mediaQueryConditions: Record<string, string> = mqConditions,
) {
    return readable(initialValue, (set) => {
        if (
            typeof window === 'undefined' ||
            typeof matchMedia === 'undefined'
        ) {
            set(initialValue);
            return;
        }

        let mqls = {};
        let updateMediaQuery = () => set(calculateMediaQuery(mqls));

        for (const key in mediaQueryConditions) {
            mqls[key] = window.matchMedia(mediaQueryConditions[key]);
            // `addListener` is deprecated but should still be used for compatibility with more browsers.
            mqls[key].addListener(updateMediaQuery);
        }

        updateMediaQuery();

        return function (): void {
            for (let key in mqls) {
                // `removeListener` is deprecated but should still be used for compatibility with more browsers.
                mqls[key].removeListener(updateMediaQuery);
            }
        };
    });
}

export const mediaQueries = buildMediaQueryStore(DEFAULT_SETTING, mqConditions);