omniscient
Version:
A library providing an abstraction for React components for passing the same data structure through the entire component flow using cursors and immutable data structures.
1,657 lines (1,472 loc) • 114 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("React"));
else if(typeof define === 'function' && define.amd)
define("omniscient", ["React"], factory);
else if(typeof exports === 'object')
exports["omniscient"] = factory(require("React"));
else
root["omniscient"] = factory(root["React"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 5);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports) {
// shim for using process in browser
var process = module.exports = {};
// cached from whatever global is present so that test runners that stub it
// don't break things. But we need to wrap it in a try catch in case it is
// wrapped in strict mode code which doesn't define any globals. It's inside a
// function because try/catches deoptimize in certain engines.
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error('setTimeout has not been defined');
}
function defaultClearTimeout () {
throw new Error('clearTimeout has not been defined');
}
(function () {
try {
if (typeof setTimeout === 'function') {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === 'function') {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
} ())
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
//normal enviroments in sane situations
return setTimeout(fun, 0);
}
// if setTimeout wasn't available but was latter defined
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedSetTimeout(fun, 0);
} catch(e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedSetTimeout.call(null, fun, 0);
} catch(e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
//normal enviroments in sane situations
return clearTimeout(marker);
}
// if clearTimeout wasn't available but was latter defined
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
// when when somebody has screwed with setTimeout but no I.E. maddness
return cachedClearTimeout(marker);
} catch (e){
try {
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
return cachedClearTimeout.call(null, marker);
} catch (e){
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
// Some versions of I.E. have different rules for clearTimeout vs setTimeout
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function (fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i = 1; i < arguments.length; i++) {
args[i - 1] = arguments[i];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
// v8 likes predictible objects
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function () {
this.fun.apply(null, this.array);
};
process.title = 'browser';
process.browser = true;
process.env = {};
process.argv = [];
process.version = ''; // empty string to avoid regexp issues
process.versions = {};
function noop() {}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;
process.listeners = function (name) { return [] }
process.binding = function (name) {
throw new Error('process.binding is not supported');
};
process.cwd = function () { return '/' };
process.chdir = function (dir) {
throw new Error('process.chdir is not supported');
};
process.umask = function() { return 0; };
/***/ }),
/* 1 */
/***/ (function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/* eslint-disable no-unused-vars */
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
function toObject(val) {
if (val === null || val === undefined) {
throw new TypeError('Object.assign cannot be called with null or undefined');
}
return Object(val);
}
function shouldUseNative() {
try {
if (!Object.assign) {
return false;
}
// Detect buggy property enumeration order in older V8 versions.
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
test1[5] = 'de';
if (Object.getOwnPropertyNames(test1)[0] === '5') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test2 = {};
for (var i = 0; i < 10; i++) {
test2['_' + String.fromCharCode(i)] = i;
}
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
return test2[n];
});
if (order2.join('') !== '0123456789') {
return false;
}
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
var test3 = {};
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
test3[letter] = letter;
});
if (Object.keys(Object.assign({}, test3)).join('') !==
'abcdefghijklmnopqrst') {
return false;
}
return true;
} catch (err) {
// We don't expect any of the above to throw, but better to be safe.
return false;
}
}
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
var from;
var to = toObject(target);
var symbols;
for (var s = 1; s < arguments.length; s++) {
from = Object(arguments[s]);
for (var key in from) {
if (hasOwnProperty.call(from, key)) {
to[key] = from[key];
}
}
if (getOwnPropertySymbols) {
symbols = getOwnPropertySymbols(from);
for (var i = 0; i < symbols.length; i++) {
if (propIsEnumerable.call(from, symbols[i])) {
to[symbols[i]] = from[symbols[i]];
}
}
}
}
return to;
};
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var isEqual = __webpack_require__(12);
/**
* Directly fetch `shouldComponentUpdate` mixin to use outside of Omniscient.
* You can do this if you don't want to use Omniscients syntactic sugar.
*
* @param {Object} nextProps Next props. Can be objects of cursors, values or immutable structures
* @param {Object} nextState Next state. Can be objects of values or immutable structures
*
* @property {Function} isCursor Get default isCursor
* @property {Function} isEqualState Get default isEqualState
* @property {Function} isEqualProps Get default isEqualProps
* @property {Function} isEqualCursor Get default isEqualCursor
* @property {Function} isEqualImmutable Get default isEqualImmutable
* @property {Function} isImmutable Get default isImmutable
* @property {Function} isIgnorable Get default isIgnorable
* @property {Function} debug Get default debug
*
* @module shouldComponentUpdate
* @returns {Component}
* @api public
*/
module.exports = factory();
/**
* Create a “local” instance of the shouldComponentUpdate with overriden defaults.
*
* ### Options
* ```js
* {
* isCursor: function (cursor), // check if is props
* isEqualCursor: function (oneCursor, otherCursor), // check cursor
* isEqualImmutable: function (oneImmutableStructure, otherImmutableStructure), // check immutable structures
* isEqualState: function (currentState, nextState), // check state
* isImmutable: function (currentState, nextState), // check if object is immutable
* isEqualProps: function (currentProps, nextProps), // check props
* isIgnorable: function (propertyValue, propertyKey), // check if property item is ignorable
* unCursor: function (cursor) // convert from cursor to object
* }
* ```
*
* @param {Object} [Options] Options with defaults to override
*
* @module shouldComponentUpdate.withDefaults
* @returns {Function} shouldComponentUpdate with overriden defaults
* @api public
*/
module.exports.withDefaults = factory;
function factory(methods) {
var debug;
methods = methods || {};
var _isCursor = methods.isCursor || isCursor,
_isEqualCursor = methods.isEqualCursor || isEqualCursor,
_isEqualImmutable = methods.isEqualImmutable || isEqualImmutable,
_isEqualState = methods.isEqualState || isEqualState,
_isEqualProps = methods.isEqualProps || isEqualProps,
_isImmutable = methods.isImmutable || isImmutable,
_isIgnorable = methods.isIgnorable || isIgnorable,
_unCursor = methods.unCursor || unCursor;
var isNotIgnorable = not(or(_isIgnorable, isChildren));
shouldComponentUpdate.isCursor = _isCursor;
shouldComponentUpdate.isEqualState = _isEqualState;
shouldComponentUpdate.isEqualProps = _isEqualProps;
shouldComponentUpdate.isEqualCursor = _isEqualCursor;
shouldComponentUpdate.isEqualImmutable = _isEqualImmutable;
shouldComponentUpdate.isImmutable = _isImmutable;
shouldComponentUpdate.debug = debugFn;
return shouldComponentUpdate;
function shouldComponentUpdate(nextProps, nextState) {
if (nextProps === this.props && nextState === this.state) {
if (debug)
debug.call(this, 'shouldComponentUpdate => false (equal input)');
return false;
}
if (!_isEqualState(this.state, nextState)) {
if (debug)
debug.call(this, 'shouldComponentUpdate => true (state has changed)');
return true;
}
var filteredNextProps = filter(nextProps, isNotIgnorable),
filteredCurrentProps = filter(this.props, isNotIgnorable);
if (!_isEqualProps(filteredCurrentProps, filteredNextProps)) {
if (debug)
debug.call(this, 'shouldComponentUpdate => true (props have changed)');
return true;
}
if (debug) debug.call(this, 'shouldComponentUpdate => false');
return false;
}
/**
* Predicate to check if state is equal. Checks in the tree for immutable structures
* and if it is, check by reference. Does not support cursors.
*
* Override through `shouldComponentUpdate.withDefaults`.
*
* @param {Object} value
* @param {Object} other
*
* @module shouldComponentUpdate.isEqualState
* @returns {Boolean}
* @api public
*/
function isEqualState(value, other) {
return isEqual(value, other, function(current, next) {
if (current === next) return true;
return compare(current, next, _isImmutable, _isEqualImmutable);
});
}
/**
* Predicate to check if props are equal. Checks in the tree for cursors and immutable structures
* and if it is, check by reference.
*
* Override through `shouldComponentUpdate.withDefaults`.
*
* @param {Object} value
* @param {Object} other
*
* @module shouldComponentUpdate.isEqualProps
* @returns {Boolean}
* @api public
*/
function isEqualProps(value, other) {
if (value === other) return true;
var cursorsEqual = compare(value, other, _isCursor, _isEqualCursor);
if (cursorsEqual !== void 0) return cursorsEqual;
var immutableEqual = compare(value, other, _isImmutable, _isEqualImmutable);
if (immutableEqual !== void 0) return immutableEqual;
return isEqual(value, other, function(current, next) {
if (current === next) return true;
var cursorsEqual = compare(current, next, _isCursor, _isEqualCursor);
if (cursorsEqual !== void 0) return cursorsEqual;
return compare(current, next, _isImmutable, _isEqualImmutable);
});
}
/**
* Predicate to check if cursors are equal through reference checks. Uses `unCursor`.
* Override through `shouldComponentUpdate.withDefaults` to support different cursor
* implementations.
*
* @param {Cursor} a
* @param {Cursor} b
*
* @module shouldComponentUpdate.isEqualCursor
* @returns {Boolean}
* @api public
*/
function isEqualCursor(a, b) {
return _unCursor(a) === _unCursor(b);
}
function debugFn(pattern, logFn) {
if (typeof pattern === 'function') {
logFn = pattern;
pattern = void 0;
}
var logger = logFn;
if (!logger && console.debug) {
logger = console.debug.bind(console);
}
if (!logger && console.info) {
logger = console.info.bind(console);
}
var regex = new RegExp(pattern || '.*');
debug = function(str) {
var element = this._reactInternalFiber
? this._reactInternalFiber
: this._reactInternalInstance
? this._reactInternalInstance._currentElement
: this._currentElement;
var key = element && element.key ? ' key=' + element.key : '';
var name = this.constructor.displayName;
if (!key && !name) {
name = 'Unknown';
}
var tag = name + key;
if (regex.test(tag)) logger('<' + tag + '>: ' + str);
};
return debug;
}
}
// Comparator used internally by isEqual implementation. Returns undefined
// if we should do recursive isEqual.
function compare(current, next, typeCheck, equalCheck) {
var isCurrent = typeCheck(current);
var isNext = typeCheck(next);
if (isCurrent && isNext) {
return equalCheck(current, next);
}
if (isCurrent || isNext) {
return false;
}
return void 0;
}
/**
* Predicate to check if immutable structures are equal through reference checks.
* Override through `shouldComponentUpdate.withDefaults` to customize behaviour.
*
* @param {Immutable} a
* @param {Immutable} b
*
* @module shouldComponentUpdate.isEqualImmutable
* @returns {Boolean}
* @api public
*/
function isEqualImmutable(a, b) {
return a === b;
}
/**
* Predicate to check if a potential is an immutable structure or not.
* Override through `shouldComponentUpdate.withDefaults` to support different cursor
* implementations.
*
* @param {maybeImmutable} value to check if it is immutable.
*
* @module shouldComponentUpdate.isImmutable
* @returns {Boolean}
* @api public
*/
var IS_ITERABLE_SENTINEL = '@@__IMMUTABLE_ITERABLE__@@';
function isImmutable(maybeImmutable) {
return !!(maybeImmutable && maybeImmutable[IS_ITERABLE_SENTINEL]);
}
/**
* Transforming function to take in cursor and return a non-cursor.
* Override through `shouldComponentUpdate.withDefaults` to support different cursor
* implementations.
*
* @param {cursor} cursor to transform
*
* @module shouldComponentUpdate.unCursor
* @returns {Object|Number|String|Boolean}
* @api public
*/
function unCursor(cursor) {
return !isCursor(cursor) ? cursor : cursor.deref();
}
/**
* Predicate to check if `potential` is Immutable cursor or not (defaults to duck testing
* Immutable.js cursors). Can override through `.withDefaults()`.
*
* @param {potential} potential to check if is cursor
*
* @module shouldComponentUpdate.isCursor
* @returns {Boolean}
* @api public
*/
function isCursor(potential) {
return !!(potential && typeof potential.deref === 'function');
}
function not(fn) {
return function() {
return !fn.apply(fn, arguments);
};
}
function filter(obj, predicate) {
return Object.keys(obj).reduce(function(acc, key) {
if (predicate(obj[key], key)) {
acc[key] = obj[key];
}
return acc;
}, {});
}
/**
* Predicate to check if a property on props should be ignored or not.
* For now this defaults to ignore if property key is `statics`, but that
* is deprecated behaviour, and will be removed by the next major release.
*
* Override through `shouldComponentUpdate.withDefaults`.
*
* @param {Object} value
* @param {String} key
*
* @module shouldComponentUpdate.isIgnorable
* @returns {Boolean}
* @api public
*/
function isIgnorable(_, key) {
return false;
}
function isChildren(_, key) {
return key === 'children';
}
function or(fn1, fn2) {
return function() {
return fn1.apply(null, arguments) || fn2.apply(null, arguments);
};
}
/***/ }),
/* 4 */
/***/ (function(module, exports) {
/**
* lodash 3.0.4 (Custom Build) <https://lodash.com/>
* Build: `lodash modern modularize exports="npm" -o ./`
* Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <https://lodash.com/license>
*/
/** `Object#toString` result references. */
var arrayTag = '[object Array]',
funcTag = '[object Function]';
/** Used to detect host constructors (Safari > 5). */
var reIsHostCtor = /^\[object .+?Constructor\]$/;
/**
* Checks if `value` is object-like.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
/** Used for native method references. */
var objectProto = Object.prototype;
/** Used to resolve the decompiled source of functions. */
var fnToString = Function.prototype.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
* of values.
*/
var objToString = objectProto.toString;
/** Used to detect if a method is native. */
var reIsNative = RegExp('^' +
fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
);
/* Native method references for those with the same name as other `lodash` methods. */
var nativeIsArray = getNative(Array, 'isArray');
/**
* Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
* of an array-like value.
*/
var MAX_SAFE_INTEGER = 9007199254740991;
/**
* Gets the native function at `key` of `object`.
*
* @private
* @param {Object} object The object to query.
* @param {string} key The key of the method to get.
* @returns {*} Returns the function if it's native, else `undefined`.
*/
function getNative(object, key) {
var value = object == null ? undefined : object[key];
return isNative(value) ? value : undefined;
}
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
*/
function isLength(value) {
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
/**
* Checks if `value` is classified as an `Array` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isArray([1, 2, 3]);
* // => true
*
* _.isArray(function() { return arguments; }());
* // => false
*/
var isArray = nativeIsArray || function(value) {
return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
};
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator
// in older versions of Chrome and Safari which return 'function' for regexes
// and Safari 8 equivalents which return 'object' for typed array constructors.
return isObject(value) && objToString.call(value) == funcTag;
}
/**
* Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @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(1);
* // => false
*/
function isObject(value) {
// Avoid a V8 JIT bug in Chrome 19-20.
// See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
/**
* Checks if `value` is a native function.
*
* @static
* @memberOf _
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a native function, else `false`.
* @example
*
* _.isNative(Array.prototype.push);
* // => true
*
* _.isNative(_);
* // => false
*/
function isNative(value) {
if (value == null) {
return false;
}
if (isFunction(value)) {
return reIsNative.test(fnToString.call(value));
}
return isObjectLike(value) && reIsHostCtor.test(value);
}
module.exports = isArray;
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var createClass = __webpack_require__(6);
var assign = __webpack_require__(2);
var React = __webpack_require__(1);
var shouldComponentUpdate = __webpack_require__(3);
var cached = __webpack_require__(19);
/**
* When present on the prototype of a component constructor in React 16,
* indicates that a component can be instantiated
*/
var isComponentSigil = {
isReactComponent: {}
};
/**
* Create components for functional views.
*
* The API of Omniscient is pretty simple, you create a Stateless React Component
* but memoized with a smart implemented `shouldComponentUpdate`.
*
* The provided `shouldComponentUpdate` handles immutable data and cursors by default.
* It also falls back to a deep value check if passed props isn't immutable structures.
*
* You can use an Omniscient component in the same way you'd use a React Stateless Function,
* or you can use some of the additional features, such as string defined display name and
* pass in life cycle methods. These are features normally not accessible for vanilla
* Stateless React Components.
*
* If you simply pass one cursor, the cursor will be accessible on the
* `props.cursor` accessor.
*
* @param {String} displayName Component's display name. Used when debug()'ing and by React
* @param {Array|Object} mixins React mixins. Object literals with functions, or array of object literals with functions.
* @param {Function} render Stateless component to add memoization on.
*
* @property {Function} shouldComponentUpdate Get default shouldComponentUpdate
* @module omniscient
* @returns {Component}
* @api public
*/
module.exports = factory();
/**
* Create a “local” instance of the Omniscient component creator by using the `.withDefaults` method.
* This also allows you to override any defaults that Omniscient use to check equality of objects,
* unwrap cursors, etc.
*
* ### Options
* ```js
* {
* // Goes directly to component
* shouldComponentUpdate: function(nextProps, nextState), // check update
* cursorField: '__singleCursor', // cursor property name to "unwrap" before passing in to render
* isNode: function(propValue), // determines if propValue is a valid React node
* classDecorator: function(Component), // Allows for decorating created class
*
* // Passed on to `shouldComponentUpdate`
* isCursor: function (cursor), // check if is props
* isEqualCursor: function (oneCursor, otherCursor), // check cursor
* isEqualImmutable: function (oneImmutableStructure, otherImmutableStructure), // check immutable structures
* isEqualState: function (currentState, nextState), // check state
* isImmutable: function (currentState, nextState), // check if object is immutable
* isEqualProps: function (currentProps, nextProps), // check props
* isIgnorable: function (propertyValue, propertyKey), // check if property item is ignorable
* unCursor: function (cursor) // convert from cursor to object
* }
* ```
*
* ### Examples
*
* #### Un-wrapping curors
* ```jsx
* var localComponent = component.withDefaults({
* cursorField: 'foobar'
* });
*
* var Component = localComponent(function (myCursor) {
* // Now you have myCursor directly instead of having to do props.foobar
* });
*
* React.render(<Component foobar={myCursor} />, mountingPoint);
* ```
*
* #### Decorating class components
* ```jsx
* // Some third party libraries requires you to decorate the
* // React class, not the created component. You can do that
* // by creating a decorated component factory
* var decoratedComponent = component.withDefaults({
* classDecorator: compose(Radium, function (Component) {
* var DecoratedComponent = doSomething(Component);
* return DecoratedComponent;
* })
* });
*
* var Component = decoratedComponent(function (props) {
* // ... some implementation
* });
*
* React.render(<Component />, mountingPoint);
* ```
*
* @param {Object} Options Options with defaults to override
*
* @property {Function} shouldComponentUpdate Get default shouldComponentUpdate
*
* @module omniscient.withDefaults
* @returns {Component}
* @api public
*/
module.exports.withDefaults = factory;
function factory(initialOptions) {
var debug;
initialOptions = initialOptions || {};
var _shouldComponentUpdate =
initialOptions.shouldComponentUpdate ||
shouldComponentUpdate.withDefaults(initialOptions);
var _isCursor = initialOptions.isCursor || shouldComponentUpdate.isCursor;
var _isImmutable =
initialOptions.isImmutable || shouldComponentUpdate.isImmutable;
var _hiddenCursorField = initialOptions.cursorField || '__singleCursor';
var _isNode = initialOptions.isNode || isNode;
var _classDecorator = initialOptions.classDecorator || identity;
var _cached = cached.withDefaults(_shouldComponentUpdate);
var CreatedComponent = ComponentCreatorFactory(_classDecorator);
/**
* Create components for functional views, with an attached local class decorator.
* Omniscient uses a `createClass()` internally to create an higher order
* component to attach performance boost and add some syntactic sugar to your
* components. Sometimes third party apps need to be added as decorator to this
* internal class. For instance Redux or Radium.
* This create factory behaves the same as normal Omniscient.js component
* creation, but with the additional first parameter for class decorator.
*
* The API of Omniscient is pretty simple, you create a Stateless React Component
* but memoized with a smart implemented `shouldComponentUpdate`.
*
* The provided `shouldComponentUpdate` handles immutable data and cursors by default.
* It also falls back to a deep value check if passed props isn't immutable structures.
*
* You can use an Omniscient component in the same way you'd use a React Stateless Function,
* or you can use some of the additional features, such as string defined display name and
* pass in life cycle methods. These are features normally not accessible for vanilla
* Stateless React Components.
*
* If you simply pass one cursor, the cursor will be accessible on the
* `props.cursor` accessor.
*
* #### Decorating class components
* ```jsx
* // Some third party libraries requires you to decorate the
* // React class, not the created component. You can do that
* // by creating a decorated component factory
* var someDecorator = compose(Radium, function (Component) {
* var DecoratedComponent = doSomething(Component);
* return DecoratedComponent;
* });
* var Component = component.classDecorator(someDecorator, function (props) {
* // ... some implementation
* });
*
* React.render(<Component />, mountingPoint);
* ```
*
* Also works by creating a component factory:
*
* ```jsx
* var someDecorator = compose(Radium, function (Component) {
* var DecoratedComponent = doSomething(Component);
* return DecoratedComponent;
* });
* var newFactory = component.classDecorator(someDecorator);
* var Component = newFactory(function (props) {
* // ... some implementation
* });
*
* React.render(<Component />, mountingPoint);
* ```
*
* @param {Function} classDecorator Decorator to use for internal class (e.g. Redux connect, Radium)
* @param {String} [displayName] Component's display name. Used when debug()'ing and by React
* @param {Array|Object} [mixins] React mixins. Object literals with functions, or array of object literals with functions.
* @param {Function} [render] Stateless component to add memoization on.
*
* @property {Function} shouldComponentUpdate Get default shouldComponentUpdate
* @module omniscient
* @returns {Component|Function}
* @api public
*/
CreatedComponent.classDecorator = function(classDecorator) {
var shouldPartiallyApply = arguments.length === 1;
if (shouldPartiallyApply) {
return ComponentCreatorFactory(classDecorator);
}
return ComponentCreatorFactory(classDecorator).apply(
null,
toArray(arguments).slice(1)
);
};
return CreatedComponent;
function ComponentCreatorFactory(passedClassDecorator) {
/**
* Activate debugging for components. Will log when a component renders,
* the outcome of `shouldComponentUpdate`, and why the component re-renders.
*
* ### Example
* ```js
* Search>: shouldComponentUpdate => true (cursors have changed)
* Search>: render
* SearchBox>: shouldComponentUpdate => true (cursors have changed)
* SearchBox>: render
* ```
*
* @example omniscient.debug(/Search/i);
*
* @param {RegExp} pattern Filter pattern. Only show messages matching pattern
*
* @module omniscient.debug
* @returns {Immstruct}
* @api public
*/
ComponentCreator.debug = debugFn;
ComponentCreator.cached = _cached;
ComponentCreator.shouldComponentUpdate = _shouldComponentUpdate;
return ComponentCreator;
function ComponentCreator(displayName, mixins, render) {
var options = createDefaultArguments(displayName, mixins, render);
var methodStatics = pickStaticMixins(options.mixins);
var componentObject = {
displayName: options.displayName || options.render.name,
mixins: options.mixins,
render: function render() {
if (debug) debug.call(this, 'render');
// If `props['__singleCursor']` is set a single cursor was passed
// to the component, pick it out and pass it.
var input = this.props[_hiddenCursorField] || this.props;
this.cursor = this.props[_hiddenCursorField];
return options.render.call(this, input);
}
};
if (methodStatics) {
componentObject.statics = methodStatics;
removeOldStaticMethods(options.mixins);
}
var Component = passedClassDecorator(createClass(componentObject));
/**
* Invoke component (rendering it)
*
* @param {String} displayName Component display name. Used in debug and by React
* @param {Object} props Properties (triggers update when changed). Can be cursors, object and immutable structures
* @param {Object} ...rest Child components (React elements, scalar values)
*
* @module Component
* @returns {ReactElement}
* @api public
*/
function create(keyOrProps, propsOrPublicContext, updater) {
// `create` must handle two scenarios (given a component like `var MyComponent = component(() => <div />)`)
//
// 1. direct calls: `MyComponent();`
// direct calls should return a new ReactElement
// 2. instantiation via React renderer: ReactDOM.render(<MyComponent />);
// instantiation should create a new instance of the underlying ReactClass
//
// To know which scenario we're in, we have to understand whether the current call
// was made with the `new` keyword (via a React renderer). If not, assume the function
// was called directly from userland
if (this && this.constructor === create) {
var publicProps = keyOrProps,
publicContext = propsOrPublicContext;
return new Component(publicProps, publicContext, updater);
}
var key = keyOrProps,
props = propsOrPublicContext;
if (typeof key === 'object') {
props = key;
key = void 0;
}
var isFirstLevel = true;
var children = flatten(
sliceFrom(arguments, props).filter(function(item, i) {
return _isNode(item, i, isFirstLevel);
})
);
var _props, inputCursor;
// If passed props is a single cursor we move it to `props[_hiddenCursorField]`
// to simplify should component update. The render function will move it back.
// The name '__singleCursor' is used to not clash with names of user passed properties
if (_isCursor(props) || _isImmutable(props)) {
inputCursor = props;
_props = {};
_props[_hiddenCursorField] = inputCursor;
} else {
_props = assign({}, props);
}
if (key) {
_props.key = key;
}
if (children.length) {
_props.children = children;
}
return React.createElement(Component, _props);
}
if (methodStatics) {
create = assign(create, methodStatics);
}
assign(create.prototype, isComponentSigil);
return assign(create, Component, { type: Component });
}
}
function debugFn(pattern, logFn) {
if (_shouldComponentUpdate.debug) {
debug = _shouldComponentUpdate.debug(pattern, logFn);
}
}
function createDefaultArguments(displayName, mixins, render) {
// (render)
if (typeof displayName === 'function') {
render = displayName;
mixins = [];
displayName = void 0;
}
// (mixins, render)
if (typeof displayName === 'object' && typeof mixins === 'function') {
render = mixins;
mixins = displayName;
displayName = void 0;
}
// (displayName, render)
if (typeof displayName === 'string' && typeof mixins === 'function') {
render = mixins;
mixins = [];
}
// Else (displayName, mixins, render)
if (!Array.isArray(mixins)) {
mixins = [mixins];
}
if (!hasShouldComponentUpdate(mixins)) {
mixins.unshift({
shouldComponentUpdate: _shouldComponentUpdate
});
}
return {
displayName: displayName,
mixins: mixins,
render: render
};
}
}
/**
* Predicate showing whether or not the argument is a valid React Node
* or not. Can be numbers, strings, bools, and React Elements.
*
* React's isNode check from ReactPropTypes validator
* but adjusted to not accept objects to avoid collision with props.
*
* @param {String} propValue Property value to check if is valid React Node
*
* @returns {Boolean}
* @api private
*/
function isNode(propValue, i, firstLevel) {
switch (typeof propValue) {
case 'number':
return true;
case 'string':
return i !== 0 || !firstLevel;
case 'boolean':
return !propValue;
case 'object':
if (Array.isArray(propValue)) {
return propValue.every(function(item, n) {
return isNode(item, n, false);
});
}
if (React.isValidElement(propValue)) {
return true;
}
return false;
default:
return false;
}
}
function pickStaticMixins(mixins) {
var filtered = mixins.filter(function(obj) {
return !!obj.statics;
});
if (!filtered.length) {
return void 0;
}
var statics = {};
filtered.forEach(function(obj) {
statics = assign(statics, obj.statics);
});
return statics;
}
function removeOldStaticMethods(mixins) {
mixins
.filter(function(obj) {
return !!obj.statics;
})
.forEach(function(obj) {
delete obj.statics;
});
}
function hasShouldComponentUpdate(mixins) {
return mixins.some(function(mixin) {
if (mixin.shouldComponentUpdate) return true;
if (!Array.isArray(mixin.mixins)) return false;
return hasShouldComponentUpdate(mixin.mixins);
});
}
function identity(fn) {
return fn;
}
function toArray(args) {
return Array.prototype.slice.call(args);
}
function sliceFrom(args, value) {
var array = toArray(args);
var index = Math.max(array.indexOf(value), 0);
return array.slice(index);
}
// Just a shallow flatten
function flatten(array) {
return Array.prototype.concat.apply([], array);
}
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
var React = __webpack_require__(1);
var factory = __webpack_require__(7);
if (typeof React === 'undefined') {
throw Error(
'create-react-class could not find the React object. If you are using script tags, ' +
'make sure that React is being loaded before create-react-class.'
);
}
// Hack to grab NoopUpdateQueue from isomorphic React
var ReactNoopUpdateQueue = new React.Component().updater;
module.exports = factory(
React.Component,
React.isValidElement,
ReactNoopUpdateQueue
);
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(process) {/**
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
var _assign = __webpack_require__(2);
var emptyObject = __webpack_require__(8);
var _invariant = __webpack_require__(9);
if (process.env.NODE_ENV !== 'production') {
var warning = __webpack_require__(10);
}
var MIXINS_KEY = 'mixins';
// Helper function to allow the creation of anonymous functions which do not
// have .name set to the name of the variable being assigned to.
function identity(fn) {
return fn;
}
var ReactPropTypeLocationNames;
if (process.env.NODE_ENV !== 'production') {
ReactPropTypeLocationNames = {
prop: 'prop',
context: 'context',
childContext: 'child context'
};
} else {
ReactPropTypeLocationNames = {};
}
function factory(ReactComponent, isValidElement, ReactNoopUpdateQueue) {
/**
* Policies that describe methods in `ReactClassInterface`.
*/
var injectedMixins = [];
/**
* Composite components are higher-level components that compose other composite
* or host components.
*
* To create a new type of `ReactClass`, pass a specification of
* your new class to `React.createClass`. The only requirement of your class
* specification is that you implement a `render` method.
*
* var MyComponent = React.createClass({
* render: function() {
* return <div>Hello World</div>;
* }
* });
*
* The class specification supports a specific protocol of methods that have
* special meaning (e.g. `render`). See `ReactClassInterface` for
* more the comprehensive protocol. Any other properties and methods in the
* class specification will be available on the prototype.
*
* @interface ReactClassInterface
* @internal
*/
var ReactClassInterface = {
/**
* An array of Mixin objects to include when defining your component.
*
* @type {array}
* @optional
*/
mixins: 'DEFINE_MANY',
/**
* An object containing properties and methods that should be defined on
* the component's constructor instead of its prototype (static methods).
*
* @type {object}
* @optional
*/
statics: 'DEFINE_MANY',
/**
* Definition of prop types for this component.
*
* @type {object}
* @optional
*/
propTypes: 'DEFINE_MANY',
/**
* Definition of context types for this component.
*
* @type {object}
* @optional
*/
contextTypes: 'DEFINE_MANY',
/**
* Definition of context types this component sets for its children.
*
* @type {object}
* @optional
*/
childContextTypes: 'DEFINE_MANY',
// ==== Definition methods ====
/**
* Invoked when the component is mounted. Values in the mapping will be set on
* `this.props` if that prop is not specified (i.e. using an `in` check).
*
* This method is invoked before `getInitialState` and therefore cannot rely
* on `this.state` or use `this.setState`.
*
* @return {object}
* @optional
*/
getDefaultProps: 'DEFINE_MANY_MERGED',
/**
* Invoked once before the component is mounted. The return value will be used
* as the initial value of `this.state`.
*
* getInitialState: function() {
* return {
* isOn: false,
* fooBaz: new BazFoo()
* }
* }
*
* @return {object}
* @optional
*/
getInitialState: 'DEFINE_MANY_MERGED',
/**
* @return {object}
* @optional
*/
getChildContext: 'DEFINE_MANY_MERGED',
/**
* Uses props from `this.props` and state from `this.state` to render the
* structure of the component.
*
* No guarantees are made about when or how often this method is invoked, so
* it must not have side effects.
*
* render: function() {
* var name = this.props.name;
* return <div>Hello, {name}!</div>;
* }
*
* @return {ReactComponent}
* @required
*/
render: 'DEFINE_ONCE',
// ==== Delegate methods ====
/**
* Invoked when the component is initially created and about to be mounted.
* This may have side effects, but any external subscriptions or data created
* by this method must be cleaned up in `componentWillUnmount`.
*
* @optional
*/
componentWillMount: 'DEFINE_MANY',
/**
* Invoked when the component has been mounted and has a DOM representation.
* However, there is no guarantee that the DOM node is in the document.
*
* Use this as an opportunity to operate on the DOM when the component has
* been mounted (initialized and rendered) for the first time.
*
* @param {DOMElement} rootNode DOM element representing the component.
* @optional
*/
componentDidMount: 'DEFINE_MANY',
/**
* Invoked before the component receives new props.
*
* Use this as an opportunity to react to a prop transition by updating the
* state using `this.setState`. Current props are accessed via `this.props`.
*
* componentWillReceiveProps: function(nextProps, nextContext) {
* this.setState({
* likesIncreasing: nextProps.likeCount > this.props.likeCount
* });
* }
*
* NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop
* transition may cause a state change, but the opposite is not true. If you
* need it, you are probably looking for `componentWillUpdate`.
*
* @param {object} nextProps
* @optional
*/
componentWillReceiveProps: 'DEFINE_MANY',
/**
* Invoked while deciding if the component should be updated as a result of
* receiving new props, state and/or context.
*
* Use this as an opportunity to `return false` when you're certain that the
* transition to the new props/state/context will not require a component
* update.
*
* shouldComponentUpdate: function(nextProps, nextState, nextContext) {
* return !equal(nextProps, this.props) ||
* !equal(nextState, this.state) ||
* !equal(nextContext, this.context);
* }
*
* @param {object} nextProps
* @param {?object} nextState
* @param {?object} nextContext
* @return {boolean} True if the component should update.
* @optional
*/
shouldComponentUpdate: 'DEFINE_ONCE',
/**
* Invoked when the component is about to update due to a transition from
* `this.props`, `this.state` and `this.context` to `nextProps`, `nextState`
* and `nextContext`.
*
* Use this as an opportunity to perform preparation before an update occurs.
*
* NOTE: You **cannot** use `this.setState()` in this method.
*
* @param {object} nextProps
* @param {?object} nextState
* @param {?object} nextContext
* @param {ReactReconcileTransaction} transaction
* @optional
*/
componentWillUpdate: 'DEFINE_MANY',
/**
* Invoked when the component's DOM representation has been updated.
*
* Use this as an opportunity to operate on the DOM when the component has
* been updated.
*
* @param {object} prevProps
* @param {?object} prevState
* @param {?object} prevContext
* @param {DOMElement} rootNode DOM element representing the component.
* @optional
*/
componentDidUpdate: 'DEFINE_MANY',
/**
* Invoked when the c