UNPKG

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