UNPKG

@mui/material

Version:

Quickly build beautiful React apps. MUI is a simple and customizable component library to build faster, beautiful, and more accessible React applications. Follow your own design system, or start with Material Design.

124 lines (103 loc) 4.41 kB
import * as React from 'react'; import { getThemeProps, useThemeWithoutDefault as useTheme } from '@mui/system'; import useEnhancedEffect from '../utils/useEnhancedEffect'; /** * @deprecated Not used internally. Use `MediaQueryListEvent` from lib.dom.d.ts instead. */ function useMediaQueryOld(query, defaultMatches, matchMedia, ssrMatchMedia, noSsr) { const supportMatchMedia = typeof window !== 'undefined' && typeof window.matchMedia !== 'undefined'; const [match, setMatch] = React.useState(() => { if (noSsr && supportMatchMedia) { 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; }); useEnhancedEffect(() => { let active = true; if (!supportMatchMedia) { return undefined; } const queryList = matchMedia(query); const updateMatch = () => { // Workaround Safari wrong implementation of matchMedia // TODO can we remove it? // https://github.com/mui-org/material-ui/pull/17315#issuecomment-528286677 if (active) { setMatch(queryList.matches); } }; updateMatch(); // TODO: Use `addEventListener` once support for Safari < 14 is dropped queryList.addListener(updateMatch); return () => { active = false; queryList.removeListener(updateMatch); }; }, [query, matchMedia, supportMatchMedia]); return match; } // eslint-disable-next-line no-useless-concat -- Workaround for https://github.com/webpack/webpack/issues/14814 const maybeReactUseSyncExternalStore = React['useSyncExternalStore' + '']; function useMediaQueryNew(query, defaultMatches, matchMedia, ssrMatchMedia) { const getDefaultSnapshot = React.useCallback(() => defaultMatches, [defaultMatches]); const getServerSnapshot = React.useMemo(() => { if (ssrMatchMedia !== null) { const { matches } = ssrMatchMedia(query); return () => matches; } return getDefaultSnapshot; }, [getDefaultSnapshot, query, ssrMatchMedia]); const [getSnapshot, subscribe] = React.useMemo(() => { if (matchMedia === null) { return [getDefaultSnapshot, () => () => {}]; } const mediaQueryList = matchMedia(query); return [() => mediaQueryList.matches, notify => { // TODO: Use `addEventListener` once support for Safari < 14 is dropped mediaQueryList.addListener(notify); return () => { mediaQueryList.removeListener(notify); }; }]; }, [getDefaultSnapshot, matchMedia, query]); const match = maybeReactUseSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); return match; } export default function useMediaQuery(queryInput, options = {}) { const theme = useTheme(); // 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 } = 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, ''); // TODO: Drop `useMediaQueryOld` and use `use-sync-external-store` shim in `useMediaQueryNew` once the package is stable 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; }