UNPKG

react-sizes

Version:

Hoc to easily map window sizes to props.

842 lines (729 loc) 26.7 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.ReactSizes = {}, global.React)); }(this, function (exports, React) { 'use strict'; var React__default = 'default' in React ? React['default'] : React; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; /** * lodash (Custom Build) <https://lodash.com/> * Build: `lodash modularize exports="npm" -o ./` * Copyright jQuery Foundation and other contributors <https://jquery.org/> * Released under MIT license <https://lodash.com/license> * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE> * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ /** Used as the `TypeError` message for "Functions" methods. */ var FUNC_ERROR_TEXT = 'Expected a function'; /** Used as references for various `Number` constants. */ var NAN = 0 / 0; /** `Object#toString` result references. */ var symbolTag = '[object Symbol]'; /** Used to match leading and trailing whitespace. */ var reTrim = /^\s+|\s+$/g; /** Used to detect bad signed hexadecimal string values. */ var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; /** Used to detect binary string values. */ var reIsBinary = /^0b[01]+$/i; /** Used to detect octal string values. */ var reIsOctal = /^0o[0-7]+$/i; /** Built-in method references without a dependency on `root`. */ var freeParseInt = parseInt; /** Detect free variable `global` from Node.js. */ var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal; /** Detect free variable `self`. */ var freeSelf = typeof self == 'object' && self && self.Object === Object && self; /** Used as a reference to the global object. */ var root = freeGlobal || freeSelf || Function('return this')(); /** Used for built-in method references. */ var objectProto = Object.prototype; /** * Used to resolve the * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) * of values. */ var objectToString = objectProto.toString; /* Built-in method references for those with the same name as other `lodash` methods. */ var nativeMax = Math.max, nativeMin = Math.min; /** * Gets the timestamp of the number of milliseconds that have elapsed since * the Unix epoch (1 January 1970 00:00:00 UTC). * * @static * @memberOf _ * @since 2.4.0 * @category Date * @returns {number} Returns the timestamp. * @example * * _.defer(function(stamp) { * console.log(_.now() - stamp); * }, _.now()); * // => Logs the number of milliseconds it took for the deferred invocation. */ var now = function() { return root.Date.now(); }; /** * Creates a debounced function that delays invoking `func` until after `wait` * milliseconds have elapsed since the last time the debounced function was * invoked. The debounced function comes with a `cancel` method to cancel * delayed `func` invocations and a `flush` method to immediately invoke them. * Provide `options` to indicate whether `func` should be invoked on the * leading and/or trailing edge of the `wait` timeout. The `func` is invoked * with the last arguments provided to the debounced function. Subsequent * calls to the debounced function return the result of the last `func` * invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the debounced function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until to the next tick, similar to `setTimeout` with a timeout of `0`. * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `_.debounce` and `_.throttle`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to debounce. * @param {number} [wait=0] The number of milliseconds to delay. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=false] * Specify invoking on the leading edge of the timeout. * @param {number} [options.maxWait] * The maximum time `func` is allowed to be delayed before it's invoked. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * * // Avoid costly calculations while the window size is in flux. * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); * * // Invoke `sendMail` when clicked, debouncing subsequent calls. * jQuery(element).on('click', _.debounce(sendMail, 300, { * 'leading': true, * 'trailing': false * })); * * // Ensure `batchLog` is invoked once after 1 second of debounced calls. * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); * var source = new EventSource('/stream'); * jQuery(source).on('message', debounced); * * // Cancel the trailing debounced invocation. * jQuery(window).on('popstate', debounced.cancel); */ function debounce(func, wait, options) { var lastArgs, lastThis, maxWait, result, timerId, lastCallTime, lastInvokeTime = 0, leading = false, maxing = false, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } wait = toNumber(wait) || 0; if (isObject(options)) { leading = !!options.leading; maxing = 'maxWait' in options; maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; trailing = 'trailing' in options ? !!options.trailing : trailing; } function invokeFunc(time) { var args = lastArgs, thisArg = lastThis; lastArgs = lastThis = undefined; lastInvokeTime = time; result = func.apply(thisArg, args); return result; } function leadingEdge(time) { // Reset any `maxWait` timer. lastInvokeTime = time; // Start the timer for the trailing edge. timerId = setTimeout(timerExpired, wait); // Invoke the leading edge. return leading ? invokeFunc(time) : result; } function remainingWait(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime, result = wait - timeSinceLastCall; return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result; } function shouldInvoke(time) { var timeSinceLastCall = time - lastCallTime, timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the // trailing edge, the system time has gone backwards and we're treating // it as the trailing edge, or we've hit the `maxWait` limit. return (lastCallTime === undefined || (timeSinceLastCall >= wait) || (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); } function timerExpired() { var time = now(); if (shouldInvoke(time)) { return trailingEdge(time); } // Restart the timer. timerId = setTimeout(timerExpired, remainingWait(time)); } function trailingEdge(time) { timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been // debounced at least once. if (trailing && lastArgs) { return invokeFunc(time); } lastArgs = lastThis = undefined; return result; } function cancel() { if (timerId !== undefined) { clearTimeout(timerId); } lastInvokeTime = 0; lastArgs = lastCallTime = lastThis = timerId = undefined; } function flush() { return timerId === undefined ? result : trailingEdge(now()); } function debounced() { var time = now(), isInvoking = shouldInvoke(time); lastArgs = arguments; lastThis = this; lastCallTime = time; if (isInvoking) { if (timerId === undefined) { return leadingEdge(lastCallTime); } if (maxing) { // Handle invocations in a tight loop. timerId = setTimeout(timerExpired, wait); return invokeFunc(lastCallTime); } } if (timerId === undefined) { timerId = setTimeout(timerExpired, wait); } return result; } debounced.cancel = cancel; debounced.flush = flush; return debounced; } /** * Creates a throttled function that only invokes `func` at most once per * every `wait` milliseconds. The throttled function comes with a `cancel` * method to cancel delayed `func` invocations and a `flush` method to * immediately invoke them. Provide `options` to indicate whether `func` * should be invoked on the leading and/or trailing edge of the `wait` * timeout. The `func` is invoked with the last arguments provided to the * throttled function. Subsequent calls to the throttled function return the * result of the last `func` invocation. * * **Note:** If `leading` and `trailing` options are `true`, `func` is * invoked on the trailing edge of the timeout only if the throttled function * is invoked more than once during the `wait` timeout. * * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred * until to the next tick, similar to `setTimeout` with a timeout of `0`. * * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) * for details over the differences between `_.throttle` and `_.debounce`. * * @static * @memberOf _ * @since 0.1.0 * @category Function * @param {Function} func The function to throttle. * @param {number} [wait=0] The number of milliseconds to throttle invocations to. * @param {Object} [options={}] The options object. * @param {boolean} [options.leading=true] * Specify invoking on the leading edge of the timeout. * @param {boolean} [options.trailing=true] * Specify invoking on the trailing edge of the timeout. * @returns {Function} Returns the new throttled function. * @example * * // Avoid excessively updating the position while scrolling. * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); * * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); * jQuery(element).on('click', throttled); * * // Cancel the trailing throttled invocation. * jQuery(window).on('popstate', throttled.cancel); */ function throttle(func, wait, options) { var leading = true, trailing = true; if (typeof func != 'function') { throw new TypeError(FUNC_ERROR_TEXT); } if (isObject(options)) { leading = 'leading' in options ? !!options.leading : leading; trailing = 'trailing' in options ? !!options.trailing : trailing; } return debounce(func, wait, { 'leading': leading, 'maxWait': wait, 'trailing': trailing }); } /** * Checks if `value` is the * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @since 0.1.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(_.noop); * // => true * * _.isObject(null); * // => false */ function isObject(value) { var type = typeof value; return !!value && (type == 'object' || type == 'function'); } /** * Checks if `value` is object-like. A value is object-like if it's not `null` * and has a `typeof` result of "object". * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. * @example * * _.isObjectLike({}); * // => true * * _.isObjectLike([1, 2, 3]); * // => true * * _.isObjectLike(_.noop); * // => false * * _.isObjectLike(null); * // => false */ function isObjectLike(value) { return !!value && typeof value == 'object'; } /** * Checks if `value` is classified as a `Symbol` primitive or object. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. * @example * * _.isSymbol(Symbol.iterator); * // => true * * _.isSymbol('abc'); * // => false */ function isSymbol(value) { return typeof value == 'symbol' || (isObjectLike(value) && objectToString.call(value) == symbolTag); } /** * Converts `value` to a number. * * @static * @memberOf _ * @since 4.0.0 * @category Lang * @param {*} value The value to process. * @returns {number} Returns the number. * @example * * _.toNumber(3.2); * // => 3.2 * * _.toNumber(Number.MIN_VALUE); * // => 5e-324 * * _.toNumber(Infinity); * // => Infinity * * _.toNumber('3.2'); * // => 3.2 */ function toNumber(value) { if (typeof value == 'number') { return value; } if (isSymbol(value)) { return NAN; } if (isObject(value)) { var other = typeof value.valueOf == 'function' ? value.valueOf() : value; value = isObject(other) ? (other + '') : other; } if (typeof value != 'string') { return value === 0 ? value : +value; } value = value.replace(reTrim, ''); var isBinary = reIsBinary.test(value); return (isBinary || reIsOctal.test(value)) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : (reIsBadHex.test(value) ? NAN : +value); } var lodash_throttle = throttle; var getDisplayName = function getDisplayName(Component) { return Component.displayName || Component.name || (typeof Component === 'string' && Component.length > 0 ? Component : 'Unknown'); }; var shallowDiff = function shallowDiff(a, b) { for (var i in a) { if (!(i in b)) return true; } for (var _i in b) { if (a[_i] !== b[_i]) return true; } return false; }; var getWindowSizes = function getWindowSizes(_ref) { var _ref$fallbackWidth = _ref.fallbackWidth, fallbackWidth = _ref$fallbackWidth === void 0 ? null : _ref$fallbackWidth, _ref$fallbackHeight = _ref.fallbackHeight, fallbackHeight = _ref$fallbackHeight === void 0 ? null : _ref$fallbackHeight, _ref$forceFallback = _ref.forceFallback, forceFallback = _ref$forceFallback === void 0 ? false : _ref$forceFallback; var canUseDOM = typeof window !== 'undefined'; return { width: canUseDOM && !forceFallback ? window.innerWidth : fallbackWidth, height: canUseDOM && !forceFallback ? window.innerHeight : fallbackHeight, canUseDOM: canUseDOM }; }; var SizesContext = React__default.createContext({ fallbackWidth: null, fallbackHeight: null, forceFallback: false, throttle: 200 }); SizesContext.displayName = 'SizesContext'; var isMobile = function isMobile(_ref) { var width = _ref.width; return width < 480; }; var isTablet = function isTablet(_ref2) { var width = _ref2.width; return width >= 480 && width < 1024; }; var isDesktop = function isDesktop(_ref3) { var width = _ref3.width; return width >= 1024; }; var isGtMobile = function isGtMobile(sizes) { return !isMobile(sizes); }; var isGtTablet = function isGtTablet(sizes) { return isDesktop(sizes); }; var isStTablet = function isStTablet(sizes) { return isMobile(sizes); }; var isStDesktop = function isStDesktop(sizes) { return !isDesktop(sizes); }; var isTabletAndGreater = function isTabletAndGreater(sizes) { return !isMobile(sizes); }; var isTabletAndSmaller = function isTabletAndSmaller(sizes) { return !isStDesktop(sizes); }; var presets = /*#__PURE__*/Object.freeze({ isMobile: isMobile, isTablet: isTablet, isDesktop: isDesktop, isGtMobile: isGtMobile, isGtTablet: isGtTablet, isStTablet: isStTablet, isStDesktop: isStDesktop, isTabletAndGreater: isTabletAndGreater, isTabletAndSmaller: isTabletAndSmaller }); var getWindowSizesWithFallback = function getWindowSizesWithFallback(props) { var fallbackHeight = props.fallbackHeight, fallbackWidth = props.fallbackWidth, forceFallback = props.forceFallback; return getWindowSizes({ fallbackHeight: fallbackHeight, fallbackWidth: fallbackWidth, forceFallback: forceFallback }); }; var withSizes = function withSizes() { for (var _len = arguments.length, mappedSizesToProps = new Array(_len), _key = 0; _key < _len; _key++) { mappedSizesToProps[_key] = arguments[_key]; } return function (WrappedComponent) { var parseMappedSizesToProps = function parseMappedSizesToProps(dimensions, props) { return mappedSizesToProps.map(function (check) { return check(dimensions, props); }).reduce(function (acc, props) { return _objectSpread({}, acc, props); }, {}); }; var ComponentWithSizes = /*#__PURE__*/ function (_PureComponent) { _inherits(ComponentWithSizes, _PureComponent); function ComponentWithSizes(props) { var _this; _classCallCheck(this, ComponentWithSizes); _this = _possibleConstructorReturn(this, _getPrototypeOf(ComponentWithSizes).call(this, props)); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "dispatchSizes", function () { var propsToPass = _this.getPropsToPass(); if (shallowDiff(propsToPass, _this.state.propsToPass)) { _this.setState({ propsToPass: propsToPass }); } }); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "throttledDispatchSizes", lodash_throttle(_this.dispatchSizes, _this.props.throttle)); _this.getPropsToPass = function () { return parseMappedSizesToProps(getWindowSizesWithFallback(_this.props), _this.props); }; _this.state = { propsToPass: _this.getPropsToPass() }; return _this; } /* Dispatching & Throttling */ _createClass(ComponentWithSizes, [{ key: "componentDidMount", value: function componentDidMount() { window.addEventListener('resize', this.throttledDispatchSizes); this.dispatchSizes(); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this.throttledDispatchSizes.cancel(); window.removeEventListener('resize', this.throttledDispatchSizes); } }, { key: "render", value: function render() { var _this$props = this.props, fallbackHeight = _this$props.fallbackHeight, fallbackWidth = _this$props.fallbackWidth, forceFallback = _this$props.forceFallback, otherProps = _objectWithoutProperties(_this$props, ["fallbackHeight", "fallbackWidth", "forceFallback"]); return React__default.createElement(WrappedComponent, _extends({}, otherProps, this.state.propsToPass)); } }], [{ key: "getDerivedStateFromProps", /* Lifecycles */ value: function getDerivedStateFromProps(props, state) { var propsToPass = parseMappedSizesToProps(getWindowSizesWithFallback(props), props); if (shallowDiff(propsToPass, state.propsToPass)) { return { propsToPass: propsToPass }; } return null; } }]); return ComponentWithSizes; }(React.PureComponent); _defineProperty(ComponentWithSizes, "displayName", "withSizes(".concat(getDisplayName(WrappedComponent), ")")); var WithSizes = function WithSizes(props) { return React__default.createElement(SizesContext.Consumer, null, function (config) { return React__default.createElement(ComponentWithSizes, _extends({}, config, props)); }); }; return WithSizes; }; }; var withSizes$1 = Object.assign(withSizes, _objectSpread({}, presets)); var SizesProvider = function SizesProvider(_ref) { var config = _ref.config, children = _ref.children; return React__default.createElement(SizesContext.Provider, { value: config }, children); }; var Conductor = function Conductor(_ref) { var children = _ref.children, render = _ref.render, props = _objectWithoutProperties(_ref, ["children", "render"]); var fn = children || render; return fn ? fn(props) : null; }; var createSizedComponent = function createSizedComponent() { for (var _len = arguments.length, mapSizesToProps = new Array(_len), _key = 0; _key < _len; _key++) { mapSizesToProps[_key] = arguments[_key]; } return withSizes$1(mapSizesToProps)(Conductor); }; exports.withSizes = withSizes$1; exports.SizesProvider = SizesProvider; exports.createSizedComponent = createSizedComponent; exports.presets = presets; exports.default = withSizes$1; Object.defineProperty(exports, '__esModule', { value: true }); }));