useMediaQuery.js 5.13 KB
"use strict";
'use client';

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
exports.unstable_createUseMediaQuery = unstable_createUseMediaQuery;
var React = _interopRequireWildcard(require("react"));
var _useEnhancedEffect = _interopRequireDefault(require("@mui/utils/useEnhancedEffect"));
var _useThemeProps = require("../useThemeProps");
var _useThemeWithoutDefault = _interopRequireDefault(require("../useThemeWithoutDefault"));
// TODO React 17: Remove `useMediaQueryOld` once React 17 support is removed
function useMediaQueryOld(query, defaultMatches, matchMedia, ssrMatchMedia, noSsr) {
  const [match, setMatch] = React.useState(() => {
    if (noSsr && matchMedia) {
      return matchMedia(query).matches;
    }
    if (ssrMatchMedia) {
      return ssrMatchMedia(query).matches;
    }

    // Once the component is mounted, we rely on the
    // event listeners to return the correct matches value.
    return defaultMatches;
  });
  (0, _useEnhancedEffect.default)(() => {
    if (!matchMedia) {
      return undefined;
    }
    const queryList = matchMedia(query);
    const updateMatch = () => {
      setMatch(queryList.matches);
    };
    updateMatch();
    queryList.addEventListener('change', updateMatch);
    return () => {
      queryList.removeEventListener('change', updateMatch);
    };
  }, [query, matchMedia]);
  return match;
}

// See https://github.com/mui/material-ui/issues/41190#issuecomment-2040873379 for why
const safeReact = {
  ...React
};
const maybeReactUseSyncExternalStore = safeReact.useSyncExternalStore;
function useMediaQueryNew(query, defaultMatches, matchMedia, ssrMatchMedia, noSsr) {
  const getDefaultSnapshot = React.useCallback(() => defaultMatches, [defaultMatches]);
  const getServerSnapshot = React.useMemo(() => {
    if (noSsr && matchMedia) {
      return () => matchMedia(query).matches;
    }
    if (ssrMatchMedia !== null) {
      const {
        matches
      } = ssrMatchMedia(query);
      return () => matches;
    }
    return getDefaultSnapshot;
  }, [getDefaultSnapshot, query, ssrMatchMedia, noSsr, matchMedia]);
  const [getSnapshot, subscribe] = React.useMemo(() => {
    if (matchMedia === null) {
      return [getDefaultSnapshot, () => () => {}];
    }
    const mediaQueryList = matchMedia(query);
    return [() => mediaQueryList.matches, notify => {
      mediaQueryList.addEventListener('change', notify);
      return () => {
        mediaQueryList.removeEventListener('change', notify);
      };
    }];
  }, [getDefaultSnapshot, matchMedia, query]);
  const match = maybeReactUseSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
  return match;
}

// eslint-disable-next-line @typescript-eslint/naming-convention
function unstable_createUseMediaQuery(params = {}) {
  const {
    themeId
  } = params;
  return function useMediaQuery(queryInput, options = {}) {
    let theme = (0, _useThemeWithoutDefault.default)();
    if (theme && themeId) {
      theme = theme[themeId] || theme;
    }
    // Wait for jsdom to support the match media feature.
    // All the browsers MUI support have this built-in.
    // This defensive check is here for simplicity.
    // Most of the time, the match media logic isn't central to people tests.
    const supportMatchMedia = typeof window !== 'undefined' && typeof window.matchMedia !== 'undefined';
    const {
      defaultMatches = false,
      matchMedia = supportMatchMedia ? window.matchMedia : null,
      ssrMatchMedia = null,
      noSsr = false
    } = (0, _useThemeProps.getThemeProps)({
      name: 'MuiUseMediaQuery',
      props: options,
      theme
    });
    if (process.env.NODE_ENV !== 'production') {
      if (typeof queryInput === 'function' && theme === null) {
        console.error(['MUI: The `query` argument provided is invalid.', 'You are providing a function without a theme in the context.', 'One of the parent elements needs to use a ThemeProvider.'].join('\n'));
      }
    }
    let query = typeof queryInput === 'function' ? queryInput(theme) : queryInput;
    query = query.replace(/^@media( ?)/m, '');
    if (query.includes('print')) {
      console.warn([`MUI: You have provided a \`print\` query to the \`useMediaQuery\` hook.`, 'Using the print media query to modify print styles can lead to unexpected results.', 'Consider using the `displayPrint` field in the `sx` prop instead.', 'More information about `displayPrint` on our docs: https://mui.com/system/display/#display-in-print.'].join('\n'));
    }
    const useMediaQueryImplementation = maybeReactUseSyncExternalStore !== undefined ? useMediaQueryNew : useMediaQueryOld;
    const match = useMediaQueryImplementation(query, defaultMatches, matchMedia, ssrMatchMedia, noSsr);
    if (process.env.NODE_ENV !== 'production') {
      // eslint-disable-next-line react-hooks/rules-of-hooks
      React.useDebugValue({
        query,
        match
      });
    }
    return match;
  };
}
const useMediaQuery = unstable_createUseMediaQuery();
var _default = exports.default = useMediaQuery;