@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
JavaScript
(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