UNPKG

@react-hook/media-query

Version:

React hooks that update when media queries change between matched and unmatched states.

150 lines (128 loc) 4.55 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react')) : typeof define === 'function' && define.amd ? define(['exports', 'react'], factory) : (global = global || self, factory(global.UseMediaQuery = {}, global.React)); }(this, (function (exports, React) { 'use strict'; function queriesDidChange(prevQueries, nextQueries) { if (nextQueries === prevQueries) return false; var nextQueriesArr = Object.values(nextQueries); var prevQueriesArr = Object.values(prevQueries); if (nextQueriesArr.length !== prevQueriesArr.length) return true; if (nextQueriesArr.some(function (q, i) { return q !== prevQueriesArr[i]; })) return true; var prevKeys = Object.keys(prevQueries); return Object.keys(nextQueries).some(function (n, i) { return n !== prevKeys[i]; }); } function _ref(curr, key) { curr.matches[key] = false; curr.mediaQueries[key] = {}; return curr; } function init(queries) { var queryKeys = Object.keys(queries); /* istanbul ignore next */ if (typeof window === 'undefined') return queryKeys.reduce(_ref, { mediaQueries: {}, matches: {} }); return queryKeys.reduce(function (state, name) { var mql = window.matchMedia(queries[name]); state.mediaQueries[name] = mql; state.matches[name] = mql.matches; return state; }, { mediaQueries: {}, matches: {} }); } function reducer(state, action) { function _ref2(prev, key) { prev[key] = state.mediaQueries[key].matches; return prev; } switch (action.type) { case 'updateMatches': return { matches: Object.keys(state.mediaQueries).reduce(_ref2, {}), mediaQueries: state.mediaQueries }; case 'setQueries': return init(action.queries); } } /** * A hook that returns a [`MediaQueryMatches`](#mediaquerymatches) object which will * tell you if specific media queries matched, all media queries matched, or * any media queries matched. Matches in this hook will always return `false` when * rendering on the server. * * @param queryMap The media queries you want to match against e.g. `{screen: "screen", width: "(min-width: 12em)"}` */ function useMediaQueries(queryMap) { var prevQueries = React.useRef(queryMap); var _React$useReducer = React.useReducer(reducer, queryMap, init), state = _React$useReducer[0], dispatch = _React$useReducer[1]; React.useEffect(function () { if (queriesDidChange(queryMap, prevQueries.current)) { dispatch({ type: 'setQueries', queries: queryMap }); prevQueries.current = queryMap; } }, [queryMap]); function _callback() { return dispatch({ type: 'updateMatches' }); } function _ref3(mq) { var callback = _callback; if (typeof mq.addListener !== 'undefined') mq.addListener(callback);else mq.addEventListener('change', callback); return callback; } React.useEffect(function () { var queries = Object.values(state.mediaQueries); var callbacks = queries.map(_ref3); function _ref4(mq, i) { if (typeof mq.addListener !== 'undefined') mq.removeListener(callbacks[i]);else mq.removeEventListener('change', callbacks[i]); } return function () { queries.forEach(_ref4); }; }, [state.mediaQueries]); var matches = state.matches; var matchValues = React.useMemo(function () { return Object.values(matches); }, [matches]); return { matches: matches, matchesAny: matchValues.some(Boolean), matchesAll: matchValues.length > 0 && matchValues.every(Boolean) }; } /** * A hook that returns `true` if the media query matched and `false` if not. This * hook will always return `false` when rendering on the server. * * @param query The media query you want to match against e.g. `"only screen and (min-width: 12em)"` */ function useMediaQuery(query) { return useMediaQueries(getObj(query)).matchesAll; } var cache = {}; function getObj(query) { if (cache[query] === void 0) cache[query] = { default: query }; return cache[query]; } exports.useMediaQueries = useMediaQueries; exports.useMediaQuery = useMediaQuery; Object.defineProperty(exports, '__esModule', { value: true }); }))); //# sourceMappingURL=use-media-query.dev.js.map