UNPKG

@enact/core

Version:

Enact is an open source JavaScript framework containing everything you need to create a fast, scalable mobile or web application.

338 lines (324 loc) 11.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "Job", { enumerable: true, get: function get() { return _Job["default"]; } }); exports.shallowEqual = exports.setDefaultProps = exports.perfNow = exports.mergeClassNameMaps = exports.memoize = exports.mapAndFilterChildren = exports.isRenderable = exports.extractAriaProps = exports.coerceFunction = exports.coerceArray = exports.clamp = exports.cap = void 0; var _always = _interopRequireDefault(require("ramda/src/always")); var _is = _interopRequireDefault(require("ramda/src/is")); var _unless = _interopRequireDefault(require("ramda/src/unless")); var _react = require("react"); var ReactIs = _interopRequireWildcard(require("react-is")); var _Job = _interopRequireDefault(require("./Job")); function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, "default": e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (var _t in e) "default" !== _t && {}.hasOwnProperty.call(e, _t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, _t)) && (i.get || i.set) ? o(f, _t, i) : f[_t] = e[_t]); return f; })(e, t); } function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } /** * A collection of utility methods. * * @module core/util * @exports cap * @exports clamp * @exports coerceArray * @exports coerceFunction * @exports extractAriaProps * @exports isRenderable * @exports Job * @exports memoize * @exports mergeClassNameMaps * @exports perfNow * @exports mapAndFilterChildren * @exports shallowEqual */ /** * Capitalizes a given string (not locale-aware). * * @function * @param {String} str The string to capitalize. * * @returns {String} The capitalized string. * @memberof core/util * @public */ var cap = exports.cap = function cap(str) { return str.slice(0, 1).toUpperCase() + str.slice(1); }; /** * Limits `value` to be between `min` and `max`. * * If `min` is greater than `max`, `min` is returned. * * @function * @param {Number} min The minimum value of the range * @param {Number} max The maximum value of the range * @param {Number} value The value that must be within the range * * @returns {Number} The clamped value * @memberof core/util * @public */ var clamp = exports.clamp = function clamp(min, max, value) { if (min > max || value < min) return min; if (value > max) return max; return value; }; /** * If `arg` is a function, return it. Otherwise returns a function that returns `arg`. * * Example: * ``` * const returnsZero = coerceFunction(0); * const returnsArg = coerceFunction(() => 0); * ``` * @function * @param {*} arg Function or value * * @returns {Function} Either `arg` if `arg` is a function, or a function that returns `arg` * @memberof core/util * @public */ var coerceFunction = exports.coerceFunction = (0, _unless["default"])((0, _is["default"])(Function), _always["default"]); /** * If `arg` is array-like, return it. Otherwise returns a single element array containing `arg`. * * Example: * ``` * const returnsArray = coerceArray(0); // [0] * const returnsArg = coerceArray([0]); // [0] * const returnsObjArg = coerceArray({0: 'zeroth', length: 1}); * ``` * @see http://ramdajs.com/docs/#isArrayLike * @function * @param {*} array Array or value * * @returns {Array} Either `array` or `[array]` * @memberof core/util * @public */ var coerceArray = exports.coerceArray = function coerceArray(array) { return Array.isArray(array) ? array : [array]; }; /** * Loosely determines if `tag` is a renderable component (either a string or a function). * * @function * @param {*} tag Component to test * * @returns {Boolean} `true` if `tag` is either a string or a function * @memberof core/util * @public */ var isRenderable = exports.isRenderable = function isRenderable(tag) { return ReactIs.isValidElementType(tag); }; /** * Removes ARIA-related props from `props` and returns them in a new object. * * Specifically, it removes the `role` prop and any prop prefixed with `aria-`. This is useful when * redirecting ARIA-related props from a non-focusable root element to a focusable child element. * * @function * @param {Object} props Props object * * @returns {Object} ARIA-related props * @memberof core/util * @public */ var extractAriaProps = exports.extractAriaProps = function extractAriaProps(props) { var aria = {}; Object.keys(props).forEach(function (key) { if (key === 'role' || key.indexOf('aria-') === 0) { aria[key] = props[key]; delete props[key]; } }); return aria; }; /** * Gets the current timestamp of either `window.performance.now` or `Date.now` * * @function * * @returns {Number} The timestamp from `window.performance.now` or `Date.now` * @memberof core/util * @public */ /* istanbul ignore next */ var perfNow = exports.perfNow = function perfNow() { if (typeof window === 'object') { return window.performance.now(); } else { return Date.now(); } }; /** * Merges two class name maps into one. * * The resulting map will only contain the class names defined in the `baseMap` and will be appended * with the value from `additiveMap` if it exists. Further, `allowedClassNames` may optionally limit * which keys will be merged from `additiveMap` into `baseMap`. * * Example: * ``` * // merges all matching class names from additiveMap1 with baseMap1 * const newMap1 = mergeClassNameMaps(baseMap1, additiveMap1); * * // merge only 'a' and 'b' class names from additiveMap2 with baseMap2 * const newMap2 = mergeClassNameMaps(baseMap2, additiveMap2, ['a', 'b']); * ``` * * @function * @param {Object} baseMap The source mapping of logical class name to physical * class name * @param {Object} additiveMap Mapping of logical to physical class names which are * concatenated with `baseMap` where the logical names match * @param {String[]} [allowedClassNames] Array of logical class names that can be augmented. When * set, the logical class name must exist in `baseMap`, * `additiveMap`, and this array to be concatenated. * * @returns {Object} The merged class name map. * @memberof core/util * @public */ var mergeClassNameMaps = exports.mergeClassNameMaps = function mergeClassNameMaps(baseMap, additiveMap, allowedClassNames) { var css = baseMap; if (baseMap && additiveMap) { allowedClassNames = allowedClassNames || Object.keys(additiveMap); // if the props includes a css map, merge them together now css = Object.assign({}, baseMap); allowedClassNames.forEach(function (key) { if (baseMap[key] && additiveMap[key]) { css[key] = baseMap[key] + ' ' + additiveMap[key]; } }); if (process.env.NODE_ENV === 'test') { return new Proxy({}, { get: function get(target, key) { // use the merged value if it exists and the key otherwise return css[key] || key; } }); } } return css; }; /** * Creates a function that memoizes the result of `fn`. * * Note that this function is a naive implementation and only checks the first argument for * memoization. * * @function * @param {Function} fn The function to have its output memoized. * * @returns {Function} The new memoized function. * @memberof core/util * @public */ var memoize = exports.memoize = function memoize(fn) { var cache = {}; return function () { var n = arguments.length <= 0 ? undefined : arguments[0]; if (n in cache) { return cache[n]; } else { var result = fn.apply(void 0, arguments); cache[n] = result; return result; } }; }; /** * Maps over the `children`, discarding any `null` children before and after calling the callback. * * A replacement for `React.Children.map`. * * @function * @param {*} children Children to map over * @param {Function} callback Function to apply to each child. Will not be called if the child is * `null`. If `callback` returns `null`, the child will be removed from * the result. If `null` is returned, the item will not be included in * the final output, regardless of the filter function. * @param {Function} [filter] Filter function applied after mapping. * * @returns {*} The processed children or the value of `children` if not an array. * @memberof core/util * @see https://react.dev/reference/react/Children#children-map * @public */ var mapAndFilterChildren = exports.mapAndFilterChildren = function mapAndFilterChildren(children, callback, filter) { var result = _react.Children.map(children, function (child) { if (child != null) { for (var _len = arguments.length, rest = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { rest[_key - 1] = arguments[_key]; } return callback.apply(void 0, [child].concat(rest)); } else { return child; } }); if (result && filter) { return result.filter(filter); } else { return result; } }; /** * Sets props that are missing or `undefined` to default values * * @function * @param {Object} props Props object * @param {Object} defaultProps Default value object * * @returns {Object} Props with default values * @memberof core/util * @public */ var setDefaultProps = exports.setDefaultProps = function setDefaultProps(props) { var defaultProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var result = Object.assign({}, props); for (var prop in defaultProps) { // eslint-disable-next-line no-undefined if (props[prop] === undefined) { result[prop] = defaultProps[prop]; } } return result; }; /** * Performs shallow comparison for given objects. * * @function * @param {Object} a An object to compare. * @param {Object} b An object to compare. * * @returns {Boolean} `true` if the values of all keys are strictly equal. * @memberof core/util * @public */ var shallowEqual = exports.shallowEqual = function shallowEqual(a, b) { if (Object.is(a, b)) { return true; } if (typeof a !== 'object' || a === null || typeof b !== 'object' || b === null) { return false; } var aKeys = Object.keys(a); var bKeys = Object.keys(b); // early bail out if the objects have a different number of keys if (aKeys.length !== bKeys.length) { return false; } var hasOwn = Object.prototype.hasOwnProperty.bind(b); for (var i = 0; i < aKeys.length; i++) { var prop = aKeys[i]; if (!hasOwn(prop) || !Object.is(a[prop], b[prop])) { return false; } } return true; };