useBreakpoint.js 3.27 KB
Newer Older
Sangjune Bae's avatar
Sangjune Bae committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
"use strict";

exports.__esModule = true;
exports.createBreakpointHook = createBreakpointHook;
exports.default = void 0;

var _useMediaQuery = _interopRequireDefault(require("./useMediaQuery"));

var _react = require("react");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

/**
 * Create a responsive hook we a set of breakpoint names and widths.
 * You can use any valid css units as well as a numbers (for pixels).
 *
 * **NOTE:** The object key order is important! it's assumed to be in order from smallest to largest
 *
 * ```ts
 * const useBreakpoint = createBreakpointHook({
 *  xs: 0,
 *  sm: 576,
 *  md: 768,
 *  lg: 992,
 *  xl: 1200,
 * })
 * ```
 *
 * **Watch out!** using string values will sometimes construct media queries using css `calc()` which
 * is NOT supported in media queries by all browsers at the moment. use numbers for
 * the widest range of browser support.
 *
 * @param breakpointValues A object hash of names to breakpoint dimensions
 */
function createBreakpointHook(breakpointValues) {
  var names = Object.keys(breakpointValues);

  function and(query, next) {
    if (query === next) {
      return next;
    }

    return query ? query + " and " + next : next;
  }

  function getNext(breakpoint) {
    return names[Math.min(names.indexOf(breakpoint) + 1, names.length - 1)];
  }

  function getMaxQuery(breakpoint) {
    var next = getNext(breakpoint);
    var value = breakpointValues[next];
    if (typeof value === 'number') value = value - 0.2 + "px";else value = "calc(" + value + " - 0.2px)";
    return "(max-width: " + value + ")";
  }

  function getMinQuery(breakpoint) {
    var value = breakpointValues[breakpoint];

    if (typeof value === 'number') {
      value = value + "px";
    }

    return "(min-width: " + value + ")";
  }
  /**
   * Match a set of breakpoints
   *
   * ```tsx
   * const MidSizeOnly = () => {
   *   const isMid = useBreakpoint({ lg: 'down', sm: 'up' });
   *
   *   if (isMid) return <div>On a Reasonable sized Screen!</div>
   *   return null;
   * }
   * ```
   * @param breakpointMap An object map of breakpoints and directions, queries are constructed using "and" to join
   * breakpoints together
   */


  function useBreakpoint(breakpointOrMap, direction) {
    if (direction === void 0) {
      direction = true;
    }

    var breakpointMap;

    if (typeof breakpointOrMap === 'object') {
      breakpointMap = breakpointOrMap;
    } else {
      var _breakpointMap;

      breakpointMap = (_breakpointMap = {}, _breakpointMap[breakpointOrMap] = direction, _breakpointMap);
    }

    var query = (0, _react.useMemo)(function () {
      return Object.entries(breakpointMap).reduce(function (query, _ref) {
        var key = _ref[0],
            direction = _ref[1];

        if (direction === 'up' || direction === true) {
          query = and(query, getMinQuery(key));
        }

        if (direction === 'down' || direction === true) {
          query = and(query, getMaxQuery(key));
        }

        return query;
      }, '');
    }, [JSON.stringify(breakpointMap)]);
    return (0, _useMediaQuery.default)(query);
  }

  return useBreakpoint;
}

var useBreakpoint = createBreakpointHook({
  xs: 0,
  sm: 576,
  md: 768,
  lg: 992,
  xl: 1200
});
var _default = useBreakpoint;
exports.default = _default;