<commit_before>import { useMemo } from 'react';
import { Subscription, useSubscription } from 'use-subscription';
import json2mq, { QueryObject } from 'json2mq';

/**
 * To be used together with utilities in css.ts.
 * @returns Whether `mediaQuery` is/are matched.
 */
export default function useMediaQuery(mediaQuery: string | QueryObject | QueryObject[]) {
  const media = useMemo(() => (typeof mediaQuery === 'string' ? mediaQuery : json2mq(mediaQuery)), [
    mediaQuery,
  ]);

  const subscription = useMemo<Subscription<boolean>>(
    () => ({
      getCurrentValue: () => window.matchMedia(media).matches,
      subscribe(callback) {
        const mediaQueryList = window.matchMedia(media);
        mediaQueryList.addEventListener('change', callback);
        return () => {
          mediaQueryList.removeEventListener('change', callback);
        };
      },
    }),
    [media],
  );

  // TODO: Replace with useMutableSource after we adopt React concurrent mode. See:
  // Docs: https://github.com/reactjs/rfcs/blob/master/text/0147-use-mutable-source.md
  // Example: https://github.com/facebook/react/blob/36df483/packages/react-devtools-scheduling-profiler/src/hooks.js
  const matchedBreakpoint = useSubscription(subscription);

  return matchedBreakpoint;
}<commit_msg>Fix matchMedia.addEventListener bug on Safari < 14 (#3030)<commit_after>import { useMemo } from 'react';
import { Subscription, useSubscription } from 'use-subscription';
import json2mq, { QueryObject } from 'json2mq';

/**
 * To be used together with utilities in css.ts.
 * @returns Whether `mediaQuery` is/are matched.
 */
export default function useMediaQuery(mediaQuery: string | QueryObject | QueryObject[]) {
  const media = useMemo(() => (typeof mediaQuery === 'string' ? mediaQuery : json2mq(mediaQuery)), [
    mediaQuery,
  ]);

  const subscription = useMemo<Subscription<boolean>>(
    () => ({
      getCurrentValue: () => window.matchMedia(media).matches,
      subscribe(callback) {
        const mediaQueryList = window.matchMedia(media);
        if (mediaQueryList.addEventListener) {
          mediaQueryList.addEventListener('change', callback);
        } else {
          // To support quirk on Safari versions prior to Safari 14
          // See https://github.com/nusmodifications/nusmods/issues/3029
          mediaQueryList.addListener(callback);
        }
        return () => {
          if (mediaQueryList.removeEventListener) {
            mediaQueryList.removeEventListener('change', callback);
          } else {
            mediaQueryList.removeListener(callback);
          }
        };
      },
    }),
    [media],
  );

  // TODO: Replace with useMutableSource after we adopt React concurrent mode. See:
  // Docs: https://github.com/reactjs/rfcs/blob/master/text/0147-use-mutable-source.md
  // Example: https://github.com/facebook/react/blob/36df483/packages/react-devtools-scheduling-profiler/src/hooks.js
  const matchedBreakpoint = useSubscription(subscription);

  return matchedBreakpoint;
}
{'fraction_non_alphanumeric': 0.12814569536423842, 'fraction_numerical': 0.011920529801324504, 'mean_word_length': 3.4166666666666665, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 15, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4879464', 'n_tokens_mistral': 867, 'n_tokens_neox': 840, 'n_words': 182}