diff --git a/.gitignore b/.gitignore
index a7d12a3..de81349 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,3 @@
node_modules
coverage
_book
-lib
diff --git a/lib/CSSPropertyOperations.js b/lib/CSSPropertyOperations.js
new file mode 100644
index 0000000..7cf7fdf
--- /dev/null
+++ b/lib/CSSPropertyOperations.js
@@ -0,0 +1,129 @@
+/**
+ * CSS Property Operations
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.setStyle = setStyle;
+exports.removeStyle = removeStyle;
+exports.patchStyle = patchStyle;
+
+function setStyle(elemStyle, styles) {
+ for (var styleName in styles) {
+ if (styles.hasOwnProperty(styleName)) {
+ setStyleValue(elemStyle, styleName, styles[styleName]);
+ }
+ }
+}
+
+function removeStyle(elemStyle, styles) {
+ for (var styleName in styles) {
+ if (styles.hasOwnProperty(styleName)) {
+ elemStyle[styleName] = '';
+ }
+ }
+}
+
+function patchStyle(elemStyle, style, newStyle) {
+ if (style === newStyle) {
+ return;
+ }
+ if (!newStyle && style) {
+ removeStyle(elemStyle, style);
+ return;
+ } else if (newStyle && !style) {
+ setStyle(elemStyle, newStyle);
+ return;
+ }
+
+ for (var key in style) {
+ if (newStyle.hasOwnProperty(key)) {
+ if (newStyle[key] !== style[key]) {
+ setStyleValue(elemStyle, key, newStyle[key]);
+ }
+ } else {
+ elemStyle[key] = '';
+ }
+ }
+ for (var key in newStyle) {
+ if (!style.hasOwnProperty(key)) {
+ setStyleValue(elemStyle, key, newStyle[key]);
+ }
+ }
+}
+
+/**
+ * CSS properties which accept numbers but are not in units of "px".
+ */
+var isUnitlessNumber = {
+ animationIterationCount: 1,
+ borderImageOutset: 1,
+ borderImageSlice: 1,
+ borderImageWidth: 1,
+ boxFlex: 1,
+ boxFlexGroup: 1,
+ boxOrdinalGroup: 1,
+ columnCount: 1,
+ flex: 1,
+ flexGrow: 1,
+ flexPositive: 1,
+ flexShrink: 1,
+ flexNegative: 1,
+ flexOrder: 1,
+ gridRow: 1,
+ gridColumn: 1,
+ fontWeight: 1,
+ lineClamp: 1,
+ lineHeight: 1,
+ opacity: 1,
+ order: 1,
+ orphans: 1,
+ tabSize: 1,
+ widows: 1,
+ zIndex: 1,
+ zoom: 1,
+
+ // SVG-related properties
+ fillOpacity: 1,
+ floodOpacity: 1,
+ stopOpacity: 1,
+ strokeDasharray: 1,
+ strokeDashoffset: 1,
+ strokeMiterlimit: 1,
+ strokeOpacity: 1,
+ strokeWidth: 1
+};
+
+function prefixKey(prefix, key) {
+ return prefix + key.charAt(0).toUpperCase() + key.substring(1);
+}
+
+var prefixes = ['Webkit', 'ms', 'Moz', 'O'];
+
+Object.keys(isUnitlessNumber).forEach(function (prop) {
+ prefixes.forEach(function (prefix) {
+ isUnitlessNumber[prefixKey(prefix, prop)] = 1;
+ });
+});
+
+var RE_NUMBER = /^-?\d+(\.\d+)?$/;
+function setStyleValue(elemStyle, styleName, styleValue) {
+
+ if (!isUnitlessNumber[styleName] && RE_NUMBER.test(styleValue)) {
+ elemStyle[styleName] = styleValue + 'px';
+ return;
+ }
+
+ if (styleName === 'float') {
+ styleName = 'cssFloat';
+ }
+
+ if (styleValue == null || typeof styleValue === 'boolean') {
+ styleValue = '';
+ }
+
+ elemStyle[styleName] = styleValue;
+}
\ No newline at end of file
diff --git a/lib/Children.js b/lib/Children.js
new file mode 100644
index 0000000..374df69
--- /dev/null
+++ b/lib/Children.js
@@ -0,0 +1,124 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.only = only;
+exports.forEach = forEach;
+exports.map = map;
+exports.count = count;
+exports.toArray = toArray;
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+var _util = require('./util');
+
+var _ = _interopRequireWildcard(_util);
+
+var _createElement = require('./createElement');
+
+function only(children) {
+ if ((0, _createElement.isValidElement)(children)) {
+ return children;
+ }
+ throw new Error('expect only one child');
+}
+
+function forEach(children, iteratee, context) {
+ if (children == null) {
+ return children;
+ }
+ var index = 0;
+ if (_.isArr(children)) {
+ _.flatEach(children, function (child) {
+ // from traverseAllChildrenImpl in react
+ var type = typeof child;
+ if (type === 'undefined' || type === 'boolean') {
+ // All of the above are perceived as null.
+ child = null;
+ }
+
+ iteratee.call(context, child, index++);
+ });
+ } else {
+ // from traverseAllChildrenImpl in react
+ var type = typeof children;
+ if (type === 'undefined' || type === 'boolean') {
+ // All of the above are perceived as null.
+ children = null;
+ }
+ iteratee.call(context, children, index);
+ }
+}
+
+function map(children, iteratee, context) {
+ if (children == null) {
+ return children;
+ }
+ var store = [];
+ var keyMap = {};
+ forEach(children, function (child, index) {
+ var data = {};
+ data.child = iteratee.call(context, child, index) || child;
+ data.isEqual = data.child === child;
+ var key = data.key = getKey(child, index);
+ if (keyMap.hasOwnProperty(key)) {
+ keyMap[key] += 1;
+ } else {
+ keyMap[key] = 0;
+ }
+ data.index = keyMap[key];
+ _.addItem(store, data);
+ });
+ var result = [];
+ store.forEach(function (_ref) {
+ var child = _ref.child;
+ var key = _ref.key;
+ var index = _ref.index;
+ var isEqual = _ref.isEqual;
+
+ if (child == null || typeof child === 'boolean') {
+ return;
+ }
+ if (!(0, _createElement.isValidElement)(child) || key == null) {
+ _.addItem(result, child);
+ return;
+ }
+ if (keyMap[key] !== 0) {
+ key += ':' + index;
+ }
+ if (!isEqual) {
+ key = escapeUserProvidedKey(child.key || '') + '/' + key;
+ }
+ child = (0, _createElement.cloneElement)(child, { key: key });
+ _.addItem(result, child);
+ });
+ return result;
+}
+
+function count(children) {
+ var count = 0;
+ forEach(children, function () {
+ count++;
+ });
+ return count;
+}
+
+function toArray(children) {
+ return map(children, _.identity) || [];
+}
+
+function getKey(child, index) {
+ var key = undefined;
+ if ((0, _createElement.isValidElement)(child) && typeof child.key === 'string') {
+ key = '.$' + child.key;
+ } else {
+ key = '.' + index.toString(36);
+ }
+ return key;
+}
+
+var userProvidedKeyEscapeRegex = /\/(?!\/)/g;
+function escapeUserProvidedKey(text) {
+ return ('' + text).replace(userProvidedKeyEscapeRegex, '//');
+}
\ No newline at end of file
diff --git a/lib/Component.js b/lib/Component.js
new file mode 100644
index 0000000..fe9a1a5
--- /dev/null
+++ b/lib/Component.js
@@ -0,0 +1,243 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports['default'] = Component;
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+var _util = require('./util');
+
+var _ = _interopRequireWildcard(_util);
+
+var _virtualDom = require('./virtual-dom');
+
+var updateQueue = {
+ updaters: [],
+ isPending: false,
+ add: function add(updater) {
+ _.addItem(this.updaters, updater);
+ },
+ batchUpdate: function batchUpdate() {
+ if (this.isPending) {
+ return;
+ }
+ this.isPending = true;
+ /*
+ each updater.update may add new updater to updateQueue
+ clear them with a loop
+ event bubbles from bottom-level to top-level
+ reverse the updater order can merge some props and state and reduce the refresh times
+ see Updater.update method below to know why
+ */
+ var updaters = this.updaters;
+
+ var updater = undefined;
+ while (updater = updaters.pop()) {
+ updater.updateComponent();
+ }
+ this.isPending = false;
+ }
+};
+
+exports.updateQueue = updateQueue;
+function Updater(instance) {
+ this.instance = instance;
+ this.pendingStates = [];
+ this.pendingCallbacks = [];
+ this.isPending = false;
+ this.nextProps = this.nextContext = null;
+ this.clearCallbacks = this.clearCallbacks.bind(this);
+}
+
+Updater.prototype = {
+ emitUpdate: function emitUpdate(nextProps, nextContext) {
+ this.nextProps = nextProps;
+ this.nextContext = nextContext;
+ // receive nextProps!! should update immediately
+ nextProps || !updateQueue.isPending ? this.updateComponent() : updateQueue.add(this);
+ },
+ updateComponent: function updateComponent() {
+ var instance = this.instance;
+ var pendingStates = this.pendingStates;
+ var nextProps = this.nextProps;
+ var nextContext = this.nextContext;
+
+ if (nextProps || pendingStates.length > 0) {
+ nextProps = nextProps || instance.props;
+ nextContext = nextContext || instance.context;
+ this.nextProps = this.nextContext = null;
+ // merge the nextProps and nextState and update by one time
+ shouldUpdate(instance, nextProps, this.getState(), nextContext, this.clearCallbacks);
+ }
+ },
+ addState: function addState(nextState) {
+ if (nextState) {
+ _.addItem(this.pendingStates, nextState);
+ if (!this.isPending) {
+ this.emitUpdate();
+ }
+ }
+ },
+ replaceState: function replaceState(nextState) {
+ var pendingStates = this.pendingStates;
+
+ pendingStates.pop();
+ // push special params to point out should replace state
+ _.addItem(pendingStates, [nextState]);
+ },
+ getState: function getState() {
+ var instance = this.instance;
+ var pendingStates = this.pendingStates;
+ var state = instance.state;
+ var props = instance.props;
+
+ if (pendingStates.length) {
+ state = _.extend({}, state);
+ pendingStates.forEach(function (nextState) {
+ var isReplace = _.isArr(nextState);
+ if (isReplace) {
+ nextState = nextState[0];
+ }
+ if (_.isFn(nextState)) {
+ nextState = nextState.call(instance, state, props);
+ }
+ // replace state
+ if (isReplace) {
+ state = _.extend({}, nextState);
+ } else {
+ _.extend(state, nextState);
+ }
+ });
+ pendingStates.length = 0;
+ }
+ return state;
+ },
+ clearCallbacks: function clearCallbacks() {
+ var pendingCallbacks = this.pendingCallbacks;
+ var instance = this.instance;
+
+ if (pendingCallbacks.length > 0) {
+ this.pendingCallbacks = [];
+ pendingCallbacks.forEach(function (callback) {
+ return callback.call(instance);
+ });
+ }
+ },
+ addCallback: function addCallback(callback) {
+ if (_.isFn(callback)) {
+ _.addItem(this.pendingCallbacks, callback);
+ }
+ }
+};
+
+function Component(props, context) {
+ this.$updater = new Updater(this);
+ this.$cache = { isMounted: false };
+ this.props = props;
+ this.state = {};
+ this.refs = {};
+ this.context = context;
+}
+
+var ReactComponentSymbol = {};
+
+Component.prototype = {
+ constructor: Component,
+ isReactComponent: ReactComponentSymbol,
+ // getChildContext: _.noop,
+ // componentWillUpdate: _.noop,
+ // componentDidUpdate: _.noop,
+ // componentWillReceiveProps: _.noop,
+ // componentWillMount: _.noop,
+ // componentDidMount: _.noop,
+ // componentWillUnmount: _.noop,
+ // shouldComponentUpdate(nextProps, nextState) {
+ // return true
+ // },
+ forceUpdate: function forceUpdate(callback) {
+ var $updater = this.$updater;
+ var $cache = this.$cache;
+ var props = this.props;
+ var state = this.state;
+ var context = this.context;
+
+ if (!$cache.isMounted) {
+ return;
+ }
+ // if updater is pending, add state to trigger nexttick update
+ if ($updater.isPending) {
+ $updater.addState(state);
+ return;
+ }
+ var nextProps = $cache.props || props;
+ var nextState = $cache.state || state;
+ var nextContext = $cache.context || context;
+ var parentContext = $cache.parentContext;
+ var node = $cache.node;
+ var vnode = $cache.vnode;
+ $cache.props = $cache.state = $cache.context = null;
+ $updater.isPending = true;
+ if (this.componentWillUpdate) {
+ this.componentWillUpdate(nextProps, nextState, nextContext);
+ }
+ this.state = nextState;
+ this.props = nextProps;
+ this.context = nextContext;
+ var newVnode = (0, _virtualDom.renderComponent)(this);
+ var newNode = (0, _virtualDom.compareTwoVnodes)(vnode, newVnode, node, (0, _virtualDom.getChildContext)(this, parentContext));
+ if (newNode !== node) {
+ newNode.cache = newNode.cache || {};
+ (0, _virtualDom.syncCache)(newNode.cache, node.cache, newNode);
+ }
+ $cache.vnode = newVnode;
+ $cache.node = newNode;
+ (0, _virtualDom.clearPending)();
+ if (this.componentDidUpdate) {
+ this.componentDidUpdate(props, state, context);
+ }
+ if (callback) {
+ callback.call(this);
+ }
+ $updater.isPending = false;
+ $updater.emitUpdate();
+ },
+ setState: function setState(nextState, callback) {
+ var $updater = this.$updater;
+
+ $updater.addCallback(callback);
+ $updater.addState(nextState);
+ },
+ replaceState: function replaceState(nextState, callback) {
+ var $updater = this.$updater;
+
+ $updater.addCallback(callback);
+ $updater.replaceState(nextState);
+ },
+ getDOMNode: function getDOMNode() {
+ var node = this.$cache.node;
+ return node && node.nodeName === '#comment' ? null : node;
+ },
+ isMounted: function isMounted() {
+ return this.$cache.isMounted;
+ }
+};
+
+function shouldUpdate(component, nextProps, nextState, nextContext, callback) {
+ var shouldComponentUpdate = true;
+ if (component.shouldComponentUpdate) {
+ shouldComponentUpdate = component.shouldComponentUpdate(nextProps, nextState, nextContext);
+ }
+ if (shouldComponentUpdate === false) {
+ component.props = nextProps;
+ component.state = nextState;
+ component.context = nextContext || {};
+ return;
+ }
+ var cache = component.$cache;
+ cache.props = nextProps;
+ cache.state = nextState;
+ cache.context = nextContext || {};
+ component.forceUpdate(callback);
+}
\ No newline at end of file
diff --git a/lib/DOM.js b/lib/DOM.js
new file mode 100644
index 0000000..8c94f52
--- /dev/null
+++ b/lib/DOM.js
@@ -0,0 +1,22 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+var _util = require('./util');
+
+var _ = _interopRequireWildcard(_util);
+
+var _createElement = require('./createElement');
+
+var tagNames = 'a|abbr|address|area|article|aside|audio|b|base|bdi|bdo|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|data|datalist|dd|del|details|dfn|dialog|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|main|map|mark|menu|menuitem|meta|meter|nav|noscript|object|ol|optgroup|option|output|p|param|picture|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strong|style|sub|summary|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|track|u|ul|var|video|wbr|circle|clipPath|defs|ellipse|g|image|line|linearGradient|mask|path|pattern|polygon|polyline|radialGradient|rect|stop|svg|text|tspan';
+var DOM = {};
+tagNames.split('|').forEach(function (tagName) {
+ DOM[tagName] = (0, _createElement.createFactory)(tagName);
+});
+
+exports['default'] = DOM;
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/lib/DOMConfig.js b/lib/DOMConfig.js
new file mode 100644
index 0000000..d1702c4
--- /dev/null
+++ b/lib/DOMConfig.js
@@ -0,0 +1,549 @@
+/**
+ * DOM config
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+var ATTRIBUTE_NAME_START_CHAR = ':A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD';
+var ATTRIBUTE_NAME_CHAR = ATTRIBUTE_NAME_START_CHAR + '\\-.0-9\\uB7\\u0300-\\u036F\\u203F-\\u2040';
+
+var VALID_ATTRIBUTE_NAME_REGEX = new RegExp('^[' + ATTRIBUTE_NAME_START_CHAR + '][' + ATTRIBUTE_NAME_CHAR + ']*$');
+
+exports.VALID_ATTRIBUTE_NAME_REGEX = VALID_ATTRIBUTE_NAME_REGEX;
+var isCustomAttribute = RegExp.prototype.test.bind(new RegExp('^(data|aria)-[' + ATTRIBUTE_NAME_CHAR + ']*$'));
+exports.isCustomAttribute = isCustomAttribute;
+// will merge some data in properties below
+var properties = {};
+
+exports.properties = properties;
+/**
+ * Mapping from normalized, camelcased property names to a configuration that
+ * specifies how the associated DOM property should be accessed or rendered.
+ */
+var MUST_USE_PROPERTY = 0x1;
+var HAS_BOOLEAN_VALUE = 0x4;
+var HAS_NUMERIC_VALUE = 0x8;
+var HAS_POSITIVE_NUMERIC_VALUE = 0x10 | 0x8;
+var HAS_OVERLOADED_BOOLEAN_VALUE = 0x20;
+
+// html config
+var HTMLDOMPropertyConfig = {
+ props: {
+ /**
+ * Standard Properties
+ */
+ accept: 0,
+ acceptCharset: 0,
+ accessKey: 0,
+ action: 0,
+ allowFullScreen: HAS_BOOLEAN_VALUE,
+ allowTransparency: 0,
+ alt: 0,
+ async: HAS_BOOLEAN_VALUE,
+ autoComplete: 0,
+ autoFocus: HAS_BOOLEAN_VALUE,
+ autoPlay: HAS_BOOLEAN_VALUE,
+ capture: HAS_BOOLEAN_VALUE,
+ cellPadding: 0,
+ cellSpacing: 0,
+ charSet: 0,
+ challenge: 0,
+ checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ cite: 0,
+ classID: 0,
+ className: 0,
+ cols: HAS_POSITIVE_NUMERIC_VALUE,
+ colSpan: 0,
+ content: 0,
+ contentEditable: 0,
+ contextMenu: 0,
+ controls: HAS_BOOLEAN_VALUE,
+ coords: 0,
+ crossOrigin: 0,
+ data: 0, // For `` acts as `src`.
+ dateTime: 0,
+ 'default': HAS_BOOLEAN_VALUE,
+ // not in regular react, they did it in other way
+ defaultValue: MUST_USE_PROPERTY,
+ // not in regular react, they did it in other way
+ defaultChecked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ defer: HAS_BOOLEAN_VALUE,
+ dir: 0,
+ disabled: HAS_BOOLEAN_VALUE,
+ download: HAS_OVERLOADED_BOOLEAN_VALUE,
+ draggable: 0,
+ encType: 0,
+ form: 0,
+ formAction: 0,
+ formEncType: 0,
+ formMethod: 0,
+ formNoValidate: HAS_BOOLEAN_VALUE,
+ formTarget: 0,
+ frameBorder: 0,
+ headers: 0,
+ height: 0,
+ hidden: HAS_BOOLEAN_VALUE,
+ high: 0,
+ href: 0,
+ hrefLang: 0,
+ htmlFor: 0,
+ httpEquiv: 0,
+ icon: 0,
+ id: 0,
+ inputMode: 0,
+ integrity: 0,
+ is: 0,
+ keyParams: 0,
+ keyType: 0,
+ kind: 0,
+ label: 0,
+ lang: 0,
+ list: 0,
+ loop: HAS_BOOLEAN_VALUE,
+ low: 0,
+ manifest: 0,
+ marginHeight: 0,
+ marginWidth: 0,
+ max: 0,
+ maxLength: 0,
+ media: 0,
+ mediaGroup: 0,
+ method: 0,
+ min: 0,
+ minLength: 0,
+ // Caution; `option.selected` is not updated if `select.multiple` is
+ // disabled with `removeAttribute`.
+ multiple: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ muted: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ name: 0,
+ nonce: 0,
+ noValidate: HAS_BOOLEAN_VALUE,
+ open: HAS_BOOLEAN_VALUE,
+ optimum: 0,
+ pattern: 0,
+ placeholder: 0,
+ poster: 0,
+ preload: 0,
+ profile: 0,
+ radioGroup: 0,
+ readOnly: HAS_BOOLEAN_VALUE,
+ referrerPolicy: 0,
+ rel: 0,
+ required: HAS_BOOLEAN_VALUE,
+ reversed: HAS_BOOLEAN_VALUE,
+ role: 0,
+ rows: HAS_POSITIVE_NUMERIC_VALUE,
+ rowSpan: HAS_NUMERIC_VALUE,
+ sandbox: 0,
+ scope: 0,
+ scoped: HAS_BOOLEAN_VALUE,
+ scrolling: 0,
+ seamless: HAS_BOOLEAN_VALUE,
+ selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE,
+ shape: 0,
+ size: HAS_POSITIVE_NUMERIC_VALUE,
+ sizes: 0,
+ span: HAS_POSITIVE_NUMERIC_VALUE,
+ spellCheck: 0,
+ src: 0,
+ srcDoc: 0,
+ srcLang: 0,
+ srcSet: 0,
+ start: HAS_NUMERIC_VALUE,
+ step: 0,
+ style: 0,
+ summary: 0,
+ tabIndex: 0,
+ target: 0,
+ title: 0,
+ // Setting .type throws on non- tags
+ type: 0,
+ useMap: 0,
+ value: MUST_USE_PROPERTY,
+ width: 0,
+ wmode: 0,
+ wrap: 0,
+
+ /**
+ * RDFa Properties
+ */
+ about: 0,
+ datatype: 0,
+ inlist: 0,
+ prefix: 0,
+ // property is also supported for OpenGraph in meta tags.
+ property: 0,
+ resource: 0,
+ 'typeof': 0,
+ vocab: 0,
+
+ /**
+ * Non-standard Properties
+ */
+ // autoCapitalize and autoCorrect are supported in Mobile Safari for
+ // keyboard hints.
+ autoCapitalize: 0,
+ autoCorrect: 0,
+ // autoSave allows WebKit/Blink to persist values of input fields on page reloads
+ autoSave: 0,
+ // color is for Safari mask-icon link
+ color: 0,
+ // itemProp, itemScope, itemType are for
+ // Microdata support. See http://schema.org/docs/gs.html
+ itemProp: 0,
+ itemScope: HAS_BOOLEAN_VALUE,
+ itemType: 0,
+ // itemID and itemRef are for Microdata support as well but
+ // only specified in the WHATWG spec document. See
+ // https://html.spec.whatwg.org/multipage/microdata.html#microdata-dom-api
+ itemID: 0,
+ itemRef: 0,
+ // results show looking glass icon and recent searches on input
+ // search fields in WebKit/Blink
+ results: 0,
+ // IE-only attribute that specifies security restrictions on an iframe
+ // as an alternative to the sandbox attribute on IE<10
+ security: 0,
+ // IE-only attribute that controls focus behavior
+ unselectable: 0
+ },
+ attrNS: {},
+ domAttrs: {
+ acceptCharset: 'accept-charset',
+ className: 'class',
+ htmlFor: 'for',
+ httpEquiv: 'http-equiv'
+ },
+ domProps: {}
+};
+
+// svg config
+var xlink = 'http://www.w3.org/1999/xlink';
+var xml = 'http://www.w3.org/XML/1998/namespace';
+
+// We use attributes for everything SVG so let's avoid some duplication and run
+// code instead.
+// The following are all specified in the HTML config already so we exclude here.
+// - class (as className)
+// - color
+// - height
+// - id
+// - lang
+// - max
+// - media
+// - method
+// - min
+// - name
+// - style
+// - target
+// - type
+// - width
+var ATTRS = {
+ accentHeight: 'accent-height',
+ accumulate: 0,
+ additive: 0,
+ alignmentBaseline: 'alignment-baseline',
+ allowReorder: 'allowReorder',
+ alphabetic: 0,
+ amplitude: 0,
+ arabicForm: 'arabic-form',
+ ascent: 0,
+ attributeName: 'attributeName',
+ attributeType: 'attributeType',
+ autoReverse: 'autoReverse',
+ azimuth: 0,
+ baseFrequency: 'baseFrequency',
+ baseProfile: 'baseProfile',
+ baselineShift: 'baseline-shift',
+ bbox: 0,
+ begin: 0,
+ bias: 0,
+ by: 0,
+ calcMode: 'calcMode',
+ capHeight: 'cap-height',
+ clip: 0,
+ clipPath: 'clip-path',
+ clipRule: 'clip-rule',
+ clipPathUnits: 'clipPathUnits',
+ colorInterpolation: 'color-interpolation',
+ colorInterpolationFilters: 'color-interpolation-filters',
+ colorProfile: 'color-profile',
+ colorRendering: 'color-rendering',
+ contentScriptType: 'contentScriptType',
+ contentStyleType: 'contentStyleType',
+ cursor: 0,
+ cx: 0,
+ cy: 0,
+ d: 0,
+ decelerate: 0,
+ descent: 0,
+ diffuseConstant: 'diffuseConstant',
+ direction: 0,
+ display: 0,
+ divisor: 0,
+ dominantBaseline: 'dominant-baseline',
+ dur: 0,
+ dx: 0,
+ dy: 0,
+ edgeMode: 'edgeMode',
+ elevation: 0,
+ enableBackground: 'enable-background',
+ end: 0,
+ exponent: 0,
+ externalResourcesRequired: 'externalResourcesRequired',
+ fill: 0,
+ fillOpacity: 'fill-opacity',
+ fillRule: 'fill-rule',
+ filter: 0,
+ filterRes: 'filterRes',
+ filterUnits: 'filterUnits',
+ floodColor: 'flood-color',
+ floodOpacity: 'flood-opacity',
+ focusable: 0,
+ fontFamily: 'font-family',
+ fontSize: 'font-size',
+ fontSizeAdjust: 'font-size-adjust',
+ fontStretch: 'font-stretch',
+ fontStyle: 'font-style',
+ fontVariant: 'font-variant',
+ fontWeight: 'font-weight',
+ format: 0,
+ from: 0,
+ fx: 0,
+ fy: 0,
+ g1: 0,
+ g2: 0,
+ glyphName: 'glyph-name',
+ glyphOrientationHorizontal: 'glyph-orientation-horizontal',
+ glyphOrientationVertical: 'glyph-orientation-vertical',
+ glyphRef: 'glyphRef',
+ gradientTransform: 'gradientTransform',
+ gradientUnits: 'gradientUnits',
+ hanging: 0,
+ horizAdvX: 'horiz-adv-x',
+ horizOriginX: 'horiz-origin-x',
+ ideographic: 0,
+ imageRendering: 'image-rendering',
+ 'in': 0,
+ in2: 0,
+ intercept: 0,
+ k: 0,
+ k1: 0,
+ k2: 0,
+ k3: 0,
+ k4: 0,
+ kernelMatrix: 'kernelMatrix',
+ kernelUnitLength: 'kernelUnitLength',
+ kerning: 0,
+ keyPoints: 'keyPoints',
+ keySplines: 'keySplines',
+ keyTimes: 'keyTimes',
+ lengthAdjust: 'lengthAdjust',
+ letterSpacing: 'letter-spacing',
+ lightingColor: 'lighting-color',
+ limitingConeAngle: 'limitingConeAngle',
+ local: 0,
+ markerEnd: 'marker-end',
+ markerMid: 'marker-mid',
+ markerStart: 'marker-start',
+ markerHeight: 'markerHeight',
+ markerUnits: 'markerUnits',
+ markerWidth: 'markerWidth',
+ mask: 0,
+ maskContentUnits: 'maskContentUnits',
+ maskUnits: 'maskUnits',
+ mathematical: 0,
+ mode: 0,
+ numOctaves: 'numOctaves',
+ offset: 0,
+ opacity: 0,
+ operator: 0,
+ order: 0,
+ orient: 0,
+ orientation: 0,
+ origin: 0,
+ overflow: 0,
+ overlinePosition: 'overline-position',
+ overlineThickness: 'overline-thickness',
+ paintOrder: 'paint-order',
+ panose1: 'panose-1',
+ pathLength: 'pathLength',
+ patternContentUnits: 'patternContentUnits',
+ patternTransform: 'patternTransform',
+ patternUnits: 'patternUnits',
+ pointerEvents: 'pointer-events',
+ points: 0,
+ pointsAtX: 'pointsAtX',
+ pointsAtY: 'pointsAtY',
+ pointsAtZ: 'pointsAtZ',
+ preserveAlpha: 'preserveAlpha',
+ preserveAspectRatio: 'preserveAspectRatio',
+ primitiveUnits: 'primitiveUnits',
+ r: 0,
+ radius: 0,
+ refX: 'refX',
+ refY: 'refY',
+ renderingIntent: 'rendering-intent',
+ repeatCount: 'repeatCount',
+ repeatDur: 'repeatDur',
+ requiredExtensions: 'requiredExtensions',
+ requiredFeatures: 'requiredFeatures',
+ restart: 0,
+ result: 0,
+ rotate: 0,
+ rx: 0,
+ ry: 0,
+ scale: 0,
+ seed: 0,
+ shapeRendering: 'shape-rendering',
+ slope: 0,
+ spacing: 0,
+ specularConstant: 'specularConstant',
+ specularExponent: 'specularExponent',
+ speed: 0,
+ spreadMethod: 'spreadMethod',
+ startOffset: 'startOffset',
+ stdDeviation: 'stdDeviation',
+ stemh: 0,
+ stemv: 0,
+ stitchTiles: 'stitchTiles',
+ stopColor: 'stop-color',
+ stopOpacity: 'stop-opacity',
+ strikethroughPosition: 'strikethrough-position',
+ strikethroughThickness: 'strikethrough-thickness',
+ string: 0,
+ stroke: 0,
+ strokeDasharray: 'stroke-dasharray',
+ strokeDashoffset: 'stroke-dashoffset',
+ strokeLinecap: 'stroke-linecap',
+ strokeLinejoin: 'stroke-linejoin',
+ strokeMiterlimit: 'stroke-miterlimit',
+ strokeOpacity: 'stroke-opacity',
+ strokeWidth: 'stroke-width',
+ surfaceScale: 'surfaceScale',
+ systemLanguage: 'systemLanguage',
+ tableValues: 'tableValues',
+ targetX: 'targetX',
+ targetY: 'targetY',
+ textAnchor: 'text-anchor',
+ textDecoration: 'text-decoration',
+ textRendering: 'text-rendering',
+ textLength: 'textLength',
+ to: 0,
+ transform: 0,
+ u1: 0,
+ u2: 0,
+ underlinePosition: 'underline-position',
+ underlineThickness: 'underline-thickness',
+ unicode: 0,
+ unicodeBidi: 'unicode-bidi',
+ unicodeRange: 'unicode-range',
+ unitsPerEm: 'units-per-em',
+ vAlphabetic: 'v-alphabetic',
+ vHanging: 'v-hanging',
+ vIdeographic: 'v-ideographic',
+ vMathematical: 'v-mathematical',
+ values: 0,
+ vectorEffect: 'vector-effect',
+ version: 0,
+ vertAdvY: 'vert-adv-y',
+ vertOriginX: 'vert-origin-x',
+ vertOriginY: 'vert-origin-y',
+ viewBox: 'viewBox',
+ viewTarget: 'viewTarget',
+ visibility: 0,
+ widths: 0,
+ wordSpacing: 'word-spacing',
+ writingMode: 'writing-mode',
+ x: 0,
+ xHeight: 'x-height',
+ x1: 0,
+ x2: 0,
+ xChannelSelector: 'xChannelSelector',
+ xlinkActuate: 'xlink:actuate',
+ xlinkArcrole: 'xlink:arcrole',
+ xlinkHref: 'xlink:href',
+ xlinkRole: 'xlink:role',
+ xlinkShow: 'xlink:show',
+ xlinkTitle: 'xlink:title',
+ xlinkType: 'xlink:type',
+ xmlBase: 'xml:base',
+ xmlns: 0,
+ xmlnsXlink: 'xmlns:xlink',
+ xmlLang: 'xml:lang',
+ xmlSpace: 'xml:space',
+ y: 0,
+ y1: 0,
+ y2: 0,
+ yChannelSelector: 'yChannelSelector',
+ z: 0,
+ zoomAndPan: 'zoomAndPan'
+};
+
+var SVGDOMPropertyConfig = {
+ props: {},
+ attrNS: {
+ xlinkActuate: xlink,
+ xlinkArcrole: xlink,
+ xlinkHref: xlink,
+ xlinkRole: xlink,
+ xlinkShow: xlink,
+ xlinkTitle: xlink,
+ xlinkType: xlink,
+ xmlBase: xml,
+ xmlLang: xml,
+ xmlSpace: xml
+ },
+ domAttrs: {},
+ domProps: {}
+};
+
+Object.keys(ATTRS).map(function (key) {
+ SVGDOMPropertyConfig.props[key] = 0;
+ if (ATTRS[key]) {
+ SVGDOMPropertyConfig.domAttrs[key] = ATTRS[key];
+ }
+});
+
+// merge html and svg config into properties
+mergeConfigToProperties(HTMLDOMPropertyConfig);
+mergeConfigToProperties(SVGDOMPropertyConfig);
+
+function mergeConfigToProperties(config) {
+ var
+ // all react/react-lite supporting property names in here
+ props = config.props;
+ var
+ // attributes namespace in here
+ attrNS = config.attrNS;
+ var
+ // propName in props which should use to be dom-attribute in here
+ domAttrs = config.domAttrs;
+ var
+ // propName in props which should use to be dom-property in here
+ domProps = config.domProps;
+
+ for (var propName in props) {
+ if (!props.hasOwnProperty(propName)) {
+ continue;
+ }
+ var propConfig = props[propName];
+ properties[propName] = {
+ attributeName: domAttrs.hasOwnProperty(propName) ? domAttrs[propName] : propName.toLowerCase(),
+ propertyName: domProps.hasOwnProperty(propName) ? domProps[propName] : propName,
+ attributeNamespace: attrNS.hasOwnProperty(propName) ? attrNS[propName] : null,
+ mustUseProperty: checkMask(propConfig, MUST_USE_PROPERTY),
+ hasBooleanValue: checkMask(propConfig, HAS_BOOLEAN_VALUE),
+ hasNumericValue: checkMask(propConfig, HAS_NUMERIC_VALUE),
+ hasPositiveNumericValue: checkMask(propConfig, HAS_POSITIVE_NUMERIC_VALUE),
+ hasOverloadedBooleanValue: checkMask(propConfig, HAS_OVERLOADED_BOOLEAN_VALUE)
+ };
+ }
+}
+
+function checkMask(value, bitmask) {
+ return (value & bitmask) === bitmask;
+}
\ No newline at end of file
diff --git a/lib/DOMPropertyOperations.js b/lib/DOMPropertyOperations.js
new file mode 100644
index 0000000..9040925
--- /dev/null
+++ b/lib/DOMPropertyOperations.js
@@ -0,0 +1,84 @@
+/**
+ * DOM Property Operations
+ */
+
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.setPropValue = setPropValue;
+exports.removePropValue = removePropValue;
+
+var _DOMConfig = require('./DOMConfig');
+
+/**
+ * Sets the value for a property on a node.
+ *
+ * @param {DOMElement} node
+ * @param {string} name
+ * @param {*} value
+ */
+
+function setPropValue(node, name, value) {
+ var propInfo = _DOMConfig.properties.hasOwnProperty(name) && _DOMConfig.properties[name];
+ if (propInfo) {
+ // should delete value from dom
+ if (value == null || propInfo.hasBooleanValue && !value || propInfo.hasNumericValue && isNaN(value) || propInfo.hasPositiveNumericValue && value < 1 || propInfo.hasOverloadedBooleanValue && value === false) {
+ removePropValue(node, name);
+ } else if (propInfo.mustUseProperty) {
+ var propName = propInfo.propertyName;
+ // dom.value has side effect
+ if (propName !== 'value' || '' + node[propName] !== '' + value) {
+ node[propName] = value;
+ }
+ } else {
+ var attributeName = propInfo.attributeName;
+ var namespace = propInfo.attributeNamespace;
+
+ // `setAttribute` with objects becomes only `[object]` in IE8/9,
+ // ('' + value) makes it output the correct toString()-value.
+ if (namespace) {
+ node.setAttributeNS(namespace, attributeName, '' + value);
+ } else if (propInfo.hasBooleanValue || propInfo.hasOverloadedBooleanValue && value === true) {
+ node.setAttribute(attributeName, '');
+ } else {
+ node.setAttribute(attributeName, '' + value);
+ }
+ }
+ } else if ((0, _DOMConfig.isCustomAttribute)(name) && _DOMConfig.VALID_ATTRIBUTE_NAME_REGEX.test(name)) {
+ if (value == null) {
+ node.removeAttribute(name);
+ } else {
+ node.setAttribute(name, '' + value);
+ }
+ }
+}
+
+/**
+ * Deletes the value for a property on a node.
+ *
+ * @param {DOMElement} node
+ * @param {string} name
+ */
+
+function removePropValue(node, name) {
+ var propInfo = _DOMConfig.properties.hasOwnProperty(name) && _DOMConfig.properties[name];
+ if (propInfo) {
+ if (propInfo.mustUseProperty) {
+ var propName = propInfo.propertyName;
+ if (propInfo.hasBooleanValue) {
+ node[propName] = false;
+ } else {
+ // dom.value accept string value has side effect
+ if (propName !== 'value' || '' + node[propName] !== '') {
+ node[propName] = '';
+ }
+ }
+ } else {
+ node.removeAttribute(propInfo.attributeName);
+ }
+ } else if ((0, _DOMConfig.isCustomAttribute)(name)) {
+ node.removeAttribute(name);
+ }
+}
\ No newline at end of file
diff --git a/lib/LinkedStateMixin.js b/lib/LinkedStateMixin.js
new file mode 100644
index 0000000..a12e8ce
--- /dev/null
+++ b/lib/LinkedStateMixin.js
@@ -0,0 +1,35 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule LinkedStateMixin
+ * @typechecks static-only
+ */
+'use strict';
+
+var ReactLink = require('./ReactLink');
+var ReactStateSetters = require('./ReactStateSetters');
+
+/**
+ * A simple mixin around ReactLink.forState().
+ */
+var LinkedStateMixin = {
+ /**
+ * Create a ReactLink that's linked to part of this component's state. The
+ * ReactLink will have the current value of this.state[key] and will call
+ * setState() when a change is requested.
+ *
+ * @param {string} key state key to update. Note: you may want to use keyOf()
+ * if you're using Google Closure Compiler advanced mode.
+ * @return {ReactLink} ReactLink instance linking to the state.
+ */
+ linkState: function linkState(key) {
+ return new ReactLink(this.state[key], ReactStateSetters.createStateKeySetter(this, key));
+ }
+};
+
+module.exports = LinkedStateMixin;
\ No newline at end of file
diff --git a/lib/PropTypes.js b/lib/PropTypes.js
new file mode 100644
index 0000000..16e1487
--- /dev/null
+++ b/lib/PropTypes.js
@@ -0,0 +1,29 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+var check = function check() {
+ return check;
+};
+check.isRequired = check;
+var PropTypes = {
+ "array": check,
+ "bool": check,
+ "func": check,
+ "number": check,
+ "object": check,
+ "string": check,
+ "any": check,
+ "arrayOf": check,
+ "element": check,
+ "instanceOf": check,
+ "node": check,
+ "objectOf": check,
+ "oneOf": check,
+ "oneOfType": check,
+ "shape": check
+};
+
+exports["default"] = PropTypes;
+module.exports = exports["default"];
\ No newline at end of file
diff --git a/lib/PureComponent.js b/lib/PureComponent.js
new file mode 100644
index 0000000..0dbac90
--- /dev/null
+++ b/lib/PureComponent.js
@@ -0,0 +1,30 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports['default'] = PureComponent;
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _shallowEqual = require('./shallowEqual');
+
+var _shallowEqual2 = _interopRequireDefault(_shallowEqual);
+
+var _Component = require('./Component');
+
+var _Component2 = _interopRequireDefault(_Component);
+
+function PureComponent(props, context) {
+ _Component2['default'].call(this, props, context);
+}
+
+PureComponent.prototype = Object.create(_Component2['default'].prototype);
+PureComponent.prototype.constructor = PureComponent;
+PureComponent.prototype.isPureReactComponent = true;
+PureComponent.prototype.shouldComponentUpdate = shallowCompare;
+
+function shallowCompare(nextProps, nextState) {
+ return !(0, _shallowEqual2['default'])(this.props, nextProps) || !(0, _shallowEqual2['default'])(this.state, nextState);
+}
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/lib/ReactCSSTransitionGroup.js b/lib/ReactCSSTransitionGroup.js
new file mode 100644
index 0000000..25b692f
--- /dev/null
+++ b/lib/ReactCSSTransitionGroup.js
@@ -0,0 +1,81 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks
+ * @providesModule ReactCSSTransitionGroup
+ */
+
+'use strict';
+
+var React = require('../dist/react-lite.common');
+var ReactTransitionGroup = require('./ReactTransitionGroup');
+var ReactCSSTransitionGroupChild = require('./ReactCSSTransitionGroupChild');
+var assign = Object.assign;
+
+function createTransitionTimeoutPropValidator(transitionType) {
+ var timeoutPropName = 'transition' + transitionType + 'Timeout';
+ var enabledPropName = 'transition' + transitionType;
+
+ return function (props) {
+ // If the transition is enabled
+ if (props[enabledPropName]) {
+ // If no timeout duration is provided
+ if (props[timeoutPropName] == null) {
+ return new Error(timeoutPropName + ' wasn\'t supplied to ReactCSSTransitionGroup: ' + 'this can cause unreliable animations and won\'t be supported in ' + 'a future version of React. See ' + 'https://fb.me/react-animation-transition-group-timeout for more ' + 'information.');
+
+ // If the duration isn't a number
+ } else if (typeof props[timeoutPropName] !== 'number') {
+ return new Error(timeoutPropName + ' must be a number (in milliseconds)');
+ }
+ }
+ };
+}
+
+var ReactCSSTransitionGroup = React.createClass({
+ displayName: 'ReactCSSTransitionGroup',
+
+ propTypes: {
+ transitionName: ReactCSSTransitionGroupChild.propTypes.name,
+
+ transitionAppear: React.PropTypes.bool,
+ transitionEnter: React.PropTypes.bool,
+ transitionLeave: React.PropTypes.bool,
+ transitionAppearTimeout: createTransitionTimeoutPropValidator('Appear'),
+ transitionEnterTimeout: createTransitionTimeoutPropValidator('Enter'),
+ transitionLeaveTimeout: createTransitionTimeoutPropValidator('Leave')
+ },
+
+ getDefaultProps: function getDefaultProps() {
+ return {
+ transitionAppear: false,
+ transitionEnter: true,
+ transitionLeave: true
+ };
+ },
+
+ _wrapChild: function _wrapChild(child) {
+ // We need to provide this childFactory so that
+ // ReactCSSTransitionGroupChild can receive updates to name, enter, and
+ // leave while it is leaving.
+ return React.createElement(ReactCSSTransitionGroupChild, {
+ name: this.props.transitionName,
+ appear: this.props.transitionAppear,
+ enter: this.props.transitionEnter,
+ leave: this.props.transitionLeave,
+ appearTimeout: this.props.transitionAppearTimeout,
+ enterTimeout: this.props.transitionEnterTimeout,
+ leaveTimeout: this.props.transitionLeaveTimeout
+ }, child);
+ },
+
+ render: function render() {
+ return React.createElement(ReactTransitionGroup, assign({}, this.props, { childFactory: this._wrapChild }));
+ }
+});
+
+module.exports = ReactCSSTransitionGroup;
\ No newline at end of file
diff --git a/lib/ReactCSSTransitionGroupChild.js b/lib/ReactCSSTransitionGroupChild.js
new file mode 100644
index 0000000..bfeee9a
--- /dev/null
+++ b/lib/ReactCSSTransitionGroupChild.js
@@ -0,0 +1,164 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks
+ * @providesModule ReactCSSTransitionGroupChild
+ */
+'use strict';
+
+var React = require('../dist/react-lite.common');
+var ReactDOM = React;
+var Children = ReactDOM.Children;
+var CSSCore = require('./utils/CSSCore');
+var ReactTransitionEvents = require('./ReactTransitionEvents');
+
+var onlyChild = Children.only;
+
+// We don't remove the element from the DOM until we receive an animationend or
+// transitionend event. If the user screws up and forgets to add an animation
+// their node will be stuck in the DOM forever, so we detect if an animation
+// does not start and if it doesn't, we just call the end listener immediately.
+var TICK = 17;
+
+var ReactCSSTransitionGroupChild = React.createClass({
+ displayName: 'ReactCSSTransitionGroupChild',
+
+ propTypes: {
+ name: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.shape({
+ enter: React.PropTypes.string,
+ leave: React.PropTypes.string,
+ active: React.PropTypes.string
+ }), React.PropTypes.shape({
+ enter: React.PropTypes.string,
+ enterActive: React.PropTypes.string,
+ leave: React.PropTypes.string,
+ leaveActive: React.PropTypes.string,
+ appear: React.PropTypes.string,
+ appearActive: React.PropTypes.string
+ })]).isRequired,
+
+ // Once we require timeouts to be specified, we can remove the
+ // boolean flags (appear etc.) and just accept a number
+ // or a bool for the timeout flags (appearTimeout etc.)
+ appear: React.PropTypes.bool,
+ enter: React.PropTypes.bool,
+ leave: React.PropTypes.bool,
+ appearTimeout: React.PropTypes.number,
+ enterTimeout: React.PropTypes.number,
+ leaveTimeout: React.PropTypes.number
+ },
+
+ transition: function transition(animationType, finishCallback, userSpecifiedDelay) {
+ var node = ReactDOM.findDOMNode(this);
+
+ if (!node) {
+ if (finishCallback) {
+ finishCallback();
+ }
+ return;
+ }
+
+ var className = this.props.name[animationType] || this.props.name + '-' + animationType;
+ var activeClassName = this.props.name[animationType + 'Active'] || className + '-active';
+ var timeout = null;
+
+ var endListener = function endListener(e) {
+ if (e && e.target !== node) {
+ return;
+ }
+
+ clearTimeout(timeout);
+
+ CSSCore.removeClass(node, className);
+ CSSCore.removeClass(node, activeClassName);
+
+ ReactTransitionEvents.removeEndEventListener(node, endListener);
+
+ // Usually this optional callback is used for informing an owner of
+ // a leave animation and telling it to remove the child.
+ if (finishCallback) {
+ finishCallback();
+ }
+ };
+
+ CSSCore.addClass(node, className);
+
+ // Need to do this to actually trigger a transition.
+ this.queueClass(activeClassName);
+
+ // If the user specified a timeout delay.
+ if (userSpecifiedDelay) {
+ // Clean-up the animation after the specified delay
+ timeout = setTimeout(endListener, userSpecifiedDelay);
+ this.transitionTimeouts.push(timeout);
+ } else {
+ // DEPRECATED: this listener will be removed in a future version of react
+ ReactTransitionEvents.addEndEventListener(node, endListener);
+ }
+ },
+
+ queueClass: function queueClass(className) {
+ this.classNameQueue.push(className);
+
+ if (!this.timeout) {
+ this.timeout = setTimeout(this.flushClassNameQueue, TICK);
+ }
+ },
+
+ flushClassNameQueue: function flushClassNameQueue() {
+ if (this.isMounted()) {
+ this.classNameQueue.forEach(CSSCore.addClass.bind(CSSCore, ReactDOM.findDOMNode(this)));
+ }
+ this.classNameQueue.length = 0;
+ this.timeout = null;
+ },
+
+ componentWillMount: function componentWillMount() {
+ this.classNameQueue = [];
+ this.transitionTimeouts = [];
+ },
+
+ componentWillUnmount: function componentWillUnmount() {
+ if (this.timeout) {
+ clearTimeout(this.timeout);
+ }
+ this.transitionTimeouts.forEach(function (timeout) {
+ clearTimeout(timeout);
+ });
+ },
+
+ componentWillAppear: function componentWillAppear(done) {
+ if (this.props.appear) {
+ this.transition('appear', done, this.props.appearTimeout);
+ } else {
+ done();
+ }
+ },
+
+ componentWillEnter: function componentWillEnter(done) {
+ if (this.props.enter) {
+ this.transition('enter', done, this.props.enterTimeout);
+ } else {
+ done();
+ }
+ },
+
+ componentWillLeave: function componentWillLeave(done) {
+ if (this.props.leave) {
+ this.transition('leave', done, this.props.leaveTimeout);
+ } else {
+ done();
+ }
+ },
+
+ render: function render() {
+ return onlyChild(this.props.children);
+ }
+});
+
+module.exports = ReactCSSTransitionGroupChild;
\ No newline at end of file
diff --git a/lib/ReactChildren.js b/lib/ReactChildren.js
new file mode 100644
index 0000000..1aec529
--- /dev/null
+++ b/lib/ReactChildren.js
@@ -0,0 +1,187 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactChildren
+ */
+'use strict';
+
+var React = require('../dist/react-lite.common');
+var PooledClass = require('./utils/PooledClass');
+var emptyFunction = require('./utils/emptyFunction');
+var traverseAllChildren = require('./utils/traverseAllChildren');
+var isValidElement = React.isValidElement;
+var cloneElement = React.cloneElement;
+
+var twoArgumentPooler = PooledClass.twoArgumentPooler;
+var fourArgumentPooler = PooledClass.fourArgumentPooler;
+
+var cloneAndReplaceKey = function cloneAndReplaceKey(oldElement, newKey) {
+ var newElement = cloneElement(oldElement, { key: newKey });
+
+ return newElement;
+};
+
+var userProvidedKeyEscapeRegex = /\/(?!\/)/g;
+function escapeUserProvidedKey(text) {
+ return ('' + text).replace(userProvidedKeyEscapeRegex, '//');
+}
+
+/**
+ * PooledClass representing the bookkeeping associated with performing a child
+ * traversal. Allows avoiding binding callbacks.
+ *
+ * @constructor ForEachBookKeeping
+ * @param {!function} forEachFunction Function to perform traversal with.
+ * @param {?*} forEachContext Context to perform context with.
+ */
+function ForEachBookKeeping(forEachFunction, forEachContext) {
+ this.func = forEachFunction;
+ this.context = forEachContext;
+ this.count = 0;
+}
+ForEachBookKeeping.prototype.destructor = function () {
+ this.func = null;
+ this.context = null;
+ this.count = 0;
+};
+PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler);
+
+function forEachSingleChild(bookKeeping, child, name) {
+ var func = bookKeeping.func;
+ var context = bookKeeping.context;
+ func.call(context, child, bookKeeping.count++);
+}
+
+/**
+ * Iterates through children that are typically specified as `props.children`.
+ *
+ * The provided forEachFunc(child, index) will be called for each
+ * leaf child.
+ *
+ * @param {?*} children Children tree container.
+ * @param {function(*, int)} forEachFunc
+ * @param {*} forEachContext Context for forEachContext.
+ */
+function forEachChildren(children, forEachFunc, forEachContext) {
+ if (children == null) {
+ return children;
+ }
+ var traverseContext = ForEachBookKeeping.getPooled(forEachFunc, forEachContext);
+ traverseAllChildren(children, forEachSingleChild, traverseContext);
+ ForEachBookKeeping.release(traverseContext);
+}
+
+/**
+ * PooledClass representing the bookkeeping associated with performing a child
+ * mapping. Allows avoiding binding callbacks.
+ *
+ * @constructor MapBookKeeping
+ * @param {!*} mapResult Object containing the ordered map of results.
+ * @param {!function} mapFunction Function to perform mapping with.
+ * @param {?*} mapContext Context to perform mapping with.
+ */
+function MapBookKeeping(mapResult, keyPrefix, mapFunction, mapContext) {
+ this.result = mapResult;
+ this.keyPrefix = keyPrefix;
+ this.func = mapFunction;
+ this.context = mapContext;
+ this.count = 0;
+}
+MapBookKeeping.prototype.destructor = function () {
+ this.result = null;
+ this.keyPrefix = null;
+ this.func = null;
+ this.context = null;
+ this.count = 0;
+};
+PooledClass.addPoolingTo(MapBookKeeping, fourArgumentPooler);
+
+function mapSingleChildIntoContext(bookKeeping, child, childKey) {
+ var result = bookKeeping.result;
+ var keyPrefix = bookKeeping.keyPrefix;
+ var func = bookKeeping.func;
+ var context = bookKeeping.context;
+
+ var mappedChild = func.call(context, child, bookKeeping.count++);
+ if (Array.isArray(mappedChild)) {
+ mapIntoWithKeyPrefixInternal(mappedChild, result, childKey, emptyFunction.thatReturnsArgument);
+ } else if (mappedChild != null) {
+ if (isValidElement(mappedChild)) {
+ mappedChild = cloneAndReplaceKey(mappedChild,
+ // Keep both the (mapped) and old keys if they differ, just as
+ // traverseAllChildren used to do for objects as children
+ keyPrefix + (mappedChild !== child ? escapeUserProvidedKey(mappedChild.key || '') + '/' : '') + childKey);
+ }
+ result.push(mappedChild);
+ }
+}
+
+function mapIntoWithKeyPrefixInternal(children, array, prefix, func, context) {
+ var escapedPrefix = '';
+ if (prefix != null) {
+ escapedPrefix = escapeUserProvidedKey(prefix) + '/';
+ }
+ var traverseContext = MapBookKeeping.getPooled(array, escapedPrefix, func, context);
+ traverseAllChildren(children, mapSingleChildIntoContext, traverseContext);
+ MapBookKeeping.release(traverseContext);
+}
+
+/**
+ * Maps children that are typically specified as `props.children`.
+ *
+ * The provided mapFunction(child, key, index) will be called for each
+ * leaf child.
+ *
+ * @param {?*} children Children tree container.
+ * @param {function(*, int)} func The map function.
+ * @param {*} context Context for mapFunction.
+ * @return {object} Object containing the ordered map of results.
+ */
+function mapChildren(children, func, context) {
+ if (children == null) {
+ return children;
+ }
+ var result = [];
+ mapIntoWithKeyPrefixInternal(children, result, null, func, context);
+ return result;
+}
+
+function forEachSingleChildDummy(traverseContext, child, name) {
+ return null;
+}
+
+/**
+ * Count the number of children that are typically specified as
+ * `props.children`.
+ *
+ * @param {?*} children Children tree container.
+ * @return {number} The number of children.
+ */
+function countChildren(children, context) {
+ return traverseAllChildren(children, forEachSingleChildDummy, null);
+}
+
+/**
+ * Flatten a children object (typically specified as `props.children`) and
+ * return an array with appropriately re-keyed children.
+ */
+function toArray(children) {
+ var result = [];
+ mapIntoWithKeyPrefixInternal(children, result, null, emptyFunction.thatReturnsArgument);
+ return result;
+}
+
+var ReactChildren = {
+ forEach: forEachChildren,
+ map: mapChildren,
+ mapIntoWithKeyPrefixInternal: mapIntoWithKeyPrefixInternal,
+ count: countChildren,
+ toArray: toArray
+};
+
+module.exports = ReactChildren;
\ No newline at end of file
diff --git a/lib/ReactComponentWithPureRenderMixin.js b/lib/ReactComponentWithPureRenderMixin.js
new file mode 100644
index 0000000..857ecbc
--- /dev/null
+++ b/lib/ReactComponentWithPureRenderMixin.js
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactComponentWithPureRenderMixin
+ */
+'use strict';
+
+var shallowCompare = require('./shallowCompare');
+
+/**
+ * If your React component's render function is "pure", e.g. it will render the
+ * same result given the same props and state, provide this Mixin for a
+ * considerable performance boost.
+ *
+ * Most React components have pure render functions.
+ *
+ * Example:
+ *
+ * var ReactComponentWithPureRenderMixin =
+ * require('ReactComponentWithPureRenderMixin');
+ * React.createClass({
+ * mixins: [ReactComponentWithPureRenderMixin],
+ *
+ * render: function() {
+ * return
foo
;
+ * }
+ * });
+ *
+ * Note: This only checks shallow equality for props and state. If these contain
+ * complex data structures this mixin may have false-negatives for deeper
+ * differences. Only mixin to components which have simple props and state, or
+ * use `forceUpdate()` when you know deep data structures have changed.
+ */
+var ReactComponentWithPureRenderMixin = {
+ shouldComponentUpdate: function shouldComponentUpdate(nextProps, nextState) {
+ return shallowCompare(this, nextProps, nextState);
+ }
+};
+
+module.exports = ReactComponentWithPureRenderMixin;
\ No newline at end of file
diff --git a/lib/ReactDOM.js b/lib/ReactDOM.js
new file mode 100644
index 0000000..baf97b9
--- /dev/null
+++ b/lib/ReactDOM.js
@@ -0,0 +1,130 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.render = render;
+exports.unstable_renderSubtreeIntoContainer = unstable_renderSubtreeIntoContainer;
+exports.unmountComponentAtNode = unmountComponentAtNode;
+exports.findDOMNode = findDOMNode;
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+var _util = require('./util');
+
+var _ = _interopRequireWildcard(_util);
+
+var _constant = require('./constant');
+
+var _virtualDom = require('./virtual-dom');
+
+var _Component = require('./Component');
+
+function isValidContainer(node) {
+ return !!(node && (node.nodeType === _constant.ELEMENT_NODE_TYPE || node.nodeType === _constant.DOC_NODE_TYPE || node.nodeType === _constant.DOCUMENT_FRAGMENT_NODE_TYPE));
+}
+
+var pendingRendering = {};
+var vnodeStore = {};
+function renderTreeIntoContainer(vnode, container, callback, parentContext) {
+ if (!vnode.vtype) {
+ throw new Error('cannot render ' + vnode + ' to container');
+ }
+ if (!isValidContainer(container)) {
+ throw new Error('container ' + container + ' is not a DOM element');
+ }
+ var id = container[_constant.COMPONENT_ID] || (container[_constant.COMPONENT_ID] = _.getUid());
+ var argsCache = pendingRendering[id];
+
+ // component lify cycle method maybe call root rendering
+ // should bundle them and render by only one time
+ if (argsCache) {
+ if (argsCache === true) {
+ pendingRendering[id] = argsCache = { vnode: vnode, callback: callback, parentContext: parentContext };
+ } else {
+ argsCache.vnode = vnode;
+ argsCache.parentContext = parentContext;
+ argsCache.callback = argsCache.callback ? _.pipe(argsCache.callback, callback) : callback;
+ }
+ return;
+ }
+
+ pendingRendering[id] = true;
+ var oldVnode = null;
+ var rootNode = null;
+ if (oldVnode = vnodeStore[id]) {
+ rootNode = (0, _virtualDom.compareTwoVnodes)(oldVnode, vnode, container.firstChild, parentContext);
+ } else {
+ rootNode = (0, _virtualDom.initVnode)(vnode, parentContext, container.namespaceURI);
+ var childNode = null;
+ while (childNode = container.lastChild) {
+ container.removeChild(childNode);
+ }
+ container.appendChild(rootNode);
+ }
+ vnodeStore[id] = vnode;
+ var isPending = _Component.updateQueue.isPending;
+ _Component.updateQueue.isPending = true;
+ (0, _virtualDom.clearPending)();
+ argsCache = pendingRendering[id];
+ delete pendingRendering[id];
+
+ var result = null;
+ if (typeof argsCache === 'object') {
+ result = renderTreeIntoContainer(argsCache.vnode, container, argsCache.callback, argsCache.parentContext);
+ } else if (vnode.vtype === _constant.VELEMENT) {
+ result = rootNode;
+ } else if (vnode.vtype === _constant.VCOMPONENT) {
+ result = rootNode.cache[vnode.uid];
+ }
+
+ if (!isPending) {
+ _Component.updateQueue.isPending = false;
+ _Component.updateQueue.batchUpdate();
+ }
+
+ if (callback) {
+ callback.call(result);
+ }
+
+ return result;
+}
+
+function render(vnode, container, callback) {
+ return renderTreeIntoContainer(vnode, container, callback);
+}
+
+function unstable_renderSubtreeIntoContainer(parentComponent, subVnode, container, callback) {
+ var context = parentComponent.$cache.parentContext;
+ return renderTreeIntoContainer(subVnode, container, callback, context);
+}
+
+function unmountComponentAtNode(container) {
+ if (!container.nodeName) {
+ throw new Error('expect node');
+ }
+ var id = container[_constant.COMPONENT_ID];
+ var vnode = null;
+ if (vnode = vnodeStore[id]) {
+ (0, _virtualDom.destroyVnode)(vnode, container.firstChild);
+ container.removeChild(container.firstChild);
+ delete vnodeStore[id];
+ return true;
+ }
+ return false;
+}
+
+function findDOMNode(node) {
+ if (node == null) {
+ return null;
+ }
+ if (node.nodeName) {
+ return node;
+ }
+ var component = node;
+ // if component.node equal to false, component must be unmounted
+ if (component.getDOMNode && component.$cache.isMounted) {
+ return component.getDOMNode();
+ }
+ throw new Error('findDOMNode can not find Node');
+}
\ No newline at end of file
diff --git a/lib/ReactFragment.js b/lib/ReactFragment.js
new file mode 100644
index 0000000..831242e
--- /dev/null
+++ b/lib/ReactFragment.js
@@ -0,0 +1,56 @@
+/**
+ * Copyright 2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactFragment
+ */
+'use strict';
+
+var React = require('../dist/react-lite.common');
+var isValidElement = React.isValidElement;
+var ReactChildren = require('./ReactChildren');
+var emptyFunction = require('./utils/emptyFunction');
+var invariant = function invariant() {};
+var warning = function warning() {};
+/**
+ * We used to allow keyed objects to serve as a collection of ReactElements,
+ * or nested sets. This allowed us a way to explicitly key a set a fragment of
+ * components. This is now being replaced with an opaque data structure.
+ * The upgrade path is to call React.addons.createFragment({ key: value }) to
+ * create a keyed fragment. The resulting data structure is an array.
+ */
+
+var numericPropertyRegex = /^\d+$/;
+
+var warnedAboutNumeric = false;
+
+var ReactFragment = {
+ // Wrap a keyed object in an opaque proxy that warns you if you access any
+ // of its properties.
+ create: function create(object) {
+ if (typeof object !== 'object' || !object || Array.isArray(object)) {
+ warning(false, 'React.addons.createFragment only accepts a single object. Got: %s', object);
+ return object;
+ }
+ if (isValidElement(object)) {
+ warning(false, 'React.addons.createFragment does not accept a ReactElement ' + 'without a wrapper object.');
+ return object;
+ }
+
+ invariant(object.nodeType !== 1, 'React.addons.createFragment(...): Encountered an invalid child; DOM ' + 'elements are not valid children of React components.');
+
+ var result = [];
+
+ for (var key in object) {
+ ReactChildren.mapIntoWithKeyPrefixInternal(object[key], result, key, emptyFunction.thatReturnsArgument);
+ }
+
+ return result;
+ }
+};
+
+module.exports = ReactFragment;
\ No newline at end of file
diff --git a/lib/ReactLink.js b/lib/ReactLink.js
new file mode 100644
index 0000000..432ce14
--- /dev/null
+++ b/lib/ReactLink.js
@@ -0,0 +1,68 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactLink
+ * @typechecks static-only
+ */
+
+/**
+ * ReactLink encapsulates a common pattern in which a component wants to modify
+ * a prop received from its parent. ReactLink allows the parent to pass down a
+ * value coupled with a callback that, when invoked, expresses an intent to
+ * modify that value. For example:
+ *
+ * React.createClass({
+ * getInitialState: function() {
+ * return {value: ''};
+ * },
+ * render: function() {
+ * var valueLink = new ReactLink(this.state.value, this._handleValueChange);
+ * return ;
+ * },
+ * _handleValueChange: function(newValue) {
+ * this.setState({value: newValue});
+ * }
+ * });
+ *
+ * We have provided some sugary mixins to make the creation and
+ * consumption of ReactLink easier; see LinkedValueUtils and LinkedStateMixin.
+ */
+'use strict';
+
+var React = require('../dist/react-lite.common');
+
+/**
+ * @param {*} value current value of the link
+ * @param {function} requestChange callback to request a change
+ */
+function ReactLink(value, requestChange) {
+ this.value = value;
+ this.requestChange = requestChange;
+}
+
+/**
+ * Creates a PropType that enforces the ReactLink API and optionally checks the
+ * type of the value being passed inside the link. Example:
+ *
+ * MyComponent.propTypes = {
+ * tabIndexLink: ReactLink.PropTypes.link(React.PropTypes.number)
+ * }
+ */
+function createLinkTypeChecker(linkType) {
+ var shapes = {
+ value: typeof linkType === 'undefined' ? React.PropTypes.any.isRequired : linkType.isRequired,
+ requestChange: React.PropTypes.func.isRequired
+ };
+ return React.PropTypes.shape(shapes);
+}
+
+ReactLink.PropTypes = {
+ link: createLinkTypeChecker
+};
+
+module.exports = ReactLink;
\ No newline at end of file
diff --git a/lib/ReactStateSetters.js b/lib/ReactStateSetters.js
new file mode 100644
index 0000000..5172205
--- /dev/null
+++ b/lib/ReactStateSetters.js
@@ -0,0 +1,104 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactStateSetters
+ */
+
+'use strict';
+
+var ReactStateSetters = {
+ /**
+ * Returns a function that calls the provided function, and uses the result
+ * of that to set the component's state.
+ *
+ * @param {ReactCompositeComponent} component
+ * @param {function} funcReturningState Returned callback uses this to
+ * determine how to update state.
+ * @return {function} callback that when invoked uses funcReturningState to
+ * determined the object literal to setState.
+ */
+ createStateSetter: function createStateSetter(component, funcReturningState) {
+ return function (a, b, c, d, e, f) {
+ var partialState = funcReturningState.call(component, a, b, c, d, e, f);
+ if (partialState) {
+ component.setState(partialState);
+ }
+ };
+ },
+
+ /**
+ * Returns a single-argument callback that can be used to update a single
+ * key in the component's state.
+ *
+ * Note: this is memoized function, which makes it inexpensive to call.
+ *
+ * @param {ReactCompositeComponent} component
+ * @param {string} key The key in the state that you should update.
+ * @return {function} callback of 1 argument which calls setState() with
+ * the provided keyName and callback argument.
+ */
+ createStateKeySetter: function createStateKeySetter(component, key) {
+ // Memoize the setters.
+ var cache = component.__keySetters || (component.__keySetters = {});
+ return cache[key] || (cache[key] = _createStateKeySetter(component, key));
+ }
+};
+
+function _createStateKeySetter(component, key) {
+ // Partial state is allocated outside of the function closure so it can be
+ // reused with every call, avoiding memory allocation when this function
+ // is called.
+ var partialState = {};
+ return function stateKeySetter(value) {
+ partialState[key] = value;
+ component.setState(partialState);
+ };
+}
+
+ReactStateSetters.Mixin = {
+ /**
+ * Returns a function that calls the provided function, and uses the result
+ * of that to set the component's state.
+ *
+ * For example, these statements are equivalent:
+ *
+ * this.setState({x: 1});
+ * this.createStateSetter(function(xValue) {
+ * return {x: xValue};
+ * })(1);
+ *
+ * @param {function} funcReturningState Returned callback uses this to
+ * determine how to update state.
+ * @return {function} callback that when invoked uses funcReturningState to
+ * determined the object literal to setState.
+ */
+ createStateSetter: function createStateSetter(funcReturningState) {
+ return ReactStateSetters.createStateSetter(this, funcReturningState);
+ },
+
+ /**
+ * Returns a single-argument callback that can be used to update a single
+ * key in the component's state.
+ *
+ * For example, these statements are equivalent:
+ *
+ * this.setState({x: 1});
+ * this.createStateKeySetter('x')(1);
+ *
+ * Note: this is memoized function, which makes it inexpensive to call.
+ *
+ * @param {string} key The key in the state that you should update.
+ * @return {function} callback of 1 argument which calls setState() with
+ * the provided keyName and callback argument.
+ */
+ createStateKeySetter: function createStateKeySetter(key) {
+ return ReactStateSetters.createStateKeySetter(this, key);
+ }
+};
+
+module.exports = ReactStateSetters;
\ No newline at end of file
diff --git a/lib/ReactTransitionChildMapping.js b/lib/ReactTransitionChildMapping.js
new file mode 100644
index 0000000..15cc187
--- /dev/null
+++ b/lib/ReactTransitionChildMapping.js
@@ -0,0 +1,98 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @typechecks static-only
+ * @providesModule ReactTransitionChildMapping
+ */
+
+'use strict';
+
+var flattenChildren = require('./utils/flattenChildren');
+
+var ReactTransitionChildMapping = {
+ /**
+ * Given `this.props.children`, return an object mapping key to child. Just
+ * simple syntactic sugar around flattenChildren().
+ *
+ * @param {*} children `this.props.children`
+ * @return {object} Mapping of key to child
+ */
+ getChildMapping: function getChildMapping(children) {
+ if (!children) {
+ return children;
+ }
+ return flattenChildren(children);
+ },
+
+ /**
+ * When you're adding or removing children some may be added or removed in the
+ * same render pass. We want to show *both* since we want to simultaneously
+ * animate elements in and out. This function takes a previous set of keys
+ * and a new set of keys and merges them with its best guess of the correct
+ * ordering. In the future we may expose some of the utilities in
+ * ReactMultiChild to make this easy, but for now React itself does not
+ * directly have this concept of the union of prevChildren and nextChildren
+ * so we implement it here.
+ *
+ * @param {object} prev prev children as returned from
+ * `ReactTransitionChildMapping.getChildMapping()`.
+ * @param {object} next next children as returned from
+ * `ReactTransitionChildMapping.getChildMapping()`.
+ * @return {object} a key set that contains all keys in `prev` and all keys
+ * in `next` in a reasonable order.
+ */
+ mergeChildMappings: function mergeChildMappings(prev, next) {
+ prev = prev || {};
+ next = next || {};
+
+ function getValueForKey(key) {
+ if (next.hasOwnProperty(key)) {
+ return next[key];
+ } else {
+ return prev[key];
+ }
+ }
+
+ // For each key of `next`, the list of keys to insert before that key in
+ // the combined list
+ var nextKeysPending = {};
+
+ var pendingKeys = [];
+ for (var prevKey in prev) {
+ if (next.hasOwnProperty(prevKey)) {
+ if (pendingKeys.length) {
+ nextKeysPending[prevKey] = pendingKeys;
+ pendingKeys = [];
+ }
+ } else {
+ pendingKeys.push(prevKey);
+ }
+ }
+
+ var i;
+ var childMapping = {};
+ for (var nextKey in next) {
+ if (nextKeysPending.hasOwnProperty(nextKey)) {
+ for (i = 0; i < nextKeysPending[nextKey].length; i++) {
+ var pendingNextKey = nextKeysPending[nextKey][i];
+ childMapping[nextKeysPending[nextKey][i]] = getValueForKey(pendingNextKey);
+ }
+ }
+ childMapping[nextKey] = getValueForKey(nextKey);
+ }
+
+ // Finally, add the keys which didn't appear before any key in `next`
+ for (i = 0; i < pendingKeys.length; i++) {
+ childMapping[pendingKeys[i]] = getValueForKey(pendingKeys[i]);
+ }
+
+ return childMapping;
+ }
+};
+
+module.exports = ReactTransitionChildMapping;
\ No newline at end of file
diff --git a/lib/ReactTransitionEvents.js b/lib/ReactTransitionEvents.js
new file mode 100644
index 0000000..dfb5b53
--- /dev/null
+++ b/lib/ReactTransitionEvents.js
@@ -0,0 +1,105 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactTransitionEvents
+ */
+
+'use strict';
+
+/**
+ * EVENT_NAME_MAP is used to determine which event fired when a
+ * transition/animation ends, based on the style property used to
+ * define that event.
+ */
+var EVENT_NAME_MAP = {
+ transitionend: {
+ 'transition': 'transitionend',
+ 'WebkitTransition': 'webkitTransitionEnd',
+ 'MozTransition': 'mozTransitionEnd',
+ 'OTransition': 'oTransitionEnd',
+ 'msTransition': 'MSTransitionEnd'
+ },
+
+ animationend: {
+ 'animation': 'animationend',
+ 'WebkitAnimation': 'webkitAnimationEnd',
+ 'MozAnimation': 'mozAnimationEnd',
+ 'OAnimation': 'oAnimationEnd',
+ 'msAnimation': 'MSAnimationEnd'
+ }
+};
+
+var endEvents = [];
+
+function detectEvents() {
+ var testEl = document.createElement('div');
+ var style = testEl.style;
+
+ // On some platforms, in particular some releases of Android 4.x,
+ // the un-prefixed "animation" and "transition" properties are defined on the
+ // style object but the events that fire will still be prefixed, so we need
+ // to check if the un-prefixed events are useable, and if not remove them
+ // from the map
+ if (!('AnimationEvent' in window)) {
+ delete EVENT_NAME_MAP.animationend.animation;
+ }
+
+ if (!('TransitionEvent' in window)) {
+ delete EVENT_NAME_MAP.transitionend.transition;
+ }
+
+ for (var baseEventName in EVENT_NAME_MAP) {
+ var baseEvents = EVENT_NAME_MAP[baseEventName];
+ for (var styleName in baseEvents) {
+ if (styleName in style) {
+ endEvents.push(baseEvents[styleName]);
+ break;
+ }
+ }
+ }
+}
+
+detectEvents();
+
+// We use the raw {add|remove}EventListener() call because EventListener
+// does not know how to remove event listeners and we really should
+// clean up. Also, these events are not triggered in older browsers
+// so we should be A-OK here.
+
+function addEventListener(node, eventName, eventListener) {
+ node.addEventListener(eventName, eventListener, false);
+}
+
+function removeEventListener(node, eventName, eventListener) {
+ node.removeEventListener(eventName, eventListener, false);
+}
+
+var ReactTransitionEvents = {
+ addEndEventListener: function addEndEventListener(node, eventListener) {
+ if (endEvents.length === 0) {
+ // If CSS transitions are not supported, trigger an "end animation"
+ // event immediately.
+ window.setTimeout(eventListener, 0);
+ return;
+ }
+ endEvents.forEach(function (endEvent) {
+ addEventListener(node, endEvent, eventListener);
+ });
+ },
+
+ removeEndEventListener: function removeEndEventListener(node, eventListener) {
+ if (endEvents.length === 0) {
+ return;
+ }
+ endEvents.forEach(function (endEvent) {
+ removeEventListener(node, endEvent, eventListener);
+ });
+ }
+};
+
+module.exports = ReactTransitionEvents;
\ No newline at end of file
diff --git a/lib/ReactTransitionGroup.js b/lib/ReactTransitionGroup.js
new file mode 100644
index 0000000..4359733
--- /dev/null
+++ b/lib/ReactTransitionGroup.js
@@ -0,0 +1,203 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactTransitionGroup
+ */
+
+'use strict';
+
+var React = require('../dist/react-lite.common');
+var ReactTransitionChildMapping = require('./ReactTransitionChildMapping');
+var emptyFunction = require('./utils/emptyFunction');
+var assign = Object.assign;
+var ReactTransitionGroup = React.createClass({
+ displayName: 'ReactTransitionGroup',
+
+ propTypes: {
+ component: React.PropTypes.any,
+ childFactory: React.PropTypes.func
+ },
+
+ getDefaultProps: function getDefaultProps() {
+ return {
+ component: 'span',
+ childFactory: emptyFunction.thatReturnsArgument
+ };
+ },
+
+ getInitialState: function getInitialState() {
+ return {
+ children: ReactTransitionChildMapping.getChildMapping(this.props.children)
+ };
+ },
+
+ componentWillMount: function componentWillMount() {
+ this.currentlyTransitioningKeys = {};
+ this.keysToEnter = [];
+ this.keysToLeave = [];
+ },
+
+ componentDidMount: function componentDidMount() {
+ var initialChildMapping = this.state.children;
+ for (var key in initialChildMapping) {
+ if (initialChildMapping[key]) {
+ this.performAppear(key);
+ }
+ }
+ },
+
+ componentWillReceiveProps: function componentWillReceiveProps(nextProps) {
+ var nextChildMapping = ReactTransitionChildMapping.getChildMapping(nextProps.children);
+ var prevChildMapping = this.state.children;
+
+ this.setState({
+ children: ReactTransitionChildMapping.mergeChildMappings(prevChildMapping, nextChildMapping)
+ });
+
+ var key;
+
+ for (key in nextChildMapping) {
+ var hasPrev = prevChildMapping && prevChildMapping.hasOwnProperty(key);
+ if (nextChildMapping[key] && !hasPrev && !this.currentlyTransitioningKeys[key]) {
+ this.keysToEnter.push(key);
+ }
+ }
+
+ for (key in prevChildMapping) {
+ var hasNext = nextChildMapping && nextChildMapping.hasOwnProperty(key);
+ if (prevChildMapping[key] && !hasNext && !this.currentlyTransitioningKeys[key]) {
+ this.keysToLeave.push(key);
+ }
+ }
+
+ // If we want to someday check for reordering, we could do it here.
+ },
+
+ componentDidUpdate: function componentDidUpdate() {
+ var keysToEnter = this.keysToEnter;
+ this.keysToEnter = [];
+ keysToEnter.forEach(this.performEnter);
+
+ var keysToLeave = this.keysToLeave;
+ this.keysToLeave = [];
+ keysToLeave.forEach(this.performLeave);
+ },
+
+ performAppear: function performAppear(key) {
+ this.currentlyTransitioningKeys[key] = true;
+
+ var component = this.refs[key];
+
+ if (component.componentWillAppear) {
+ component.componentWillAppear(this._handleDoneAppearing.bind(this, key));
+ } else {
+ this._handleDoneAppearing(key);
+ }
+ },
+
+ _handleDoneAppearing: function _handleDoneAppearing(key) {
+ var component = this.refs[key];
+ if (component.componentDidAppear) {
+ component.componentDidAppear();
+ }
+
+ delete this.currentlyTransitioningKeys[key];
+
+ var currentChildMapping = ReactTransitionChildMapping.getChildMapping(this.props.children);
+
+ if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
+ // This was removed before it had fully appeared. Remove it.
+ this.performLeave(key);
+ }
+ },
+
+ performEnter: function performEnter(key) {
+ this.currentlyTransitioningKeys[key] = true;
+
+ var component = this.refs[key];
+
+ if (component.componentWillEnter) {
+ component.componentWillEnter(this._handleDoneEntering.bind(this, key));
+ } else {
+ this._handleDoneEntering(key);
+ }
+ },
+
+ _handleDoneEntering: function _handleDoneEntering(key) {
+ var component = this.refs[key];
+ if (component.componentDidEnter) {
+ component.componentDidEnter();
+ }
+
+ delete this.currentlyTransitioningKeys[key];
+
+ var currentChildMapping = ReactTransitionChildMapping.getChildMapping(this.props.children);
+
+ if (!currentChildMapping || !currentChildMapping.hasOwnProperty(key)) {
+ // This was removed before it had fully entered. Remove it.
+ this.performLeave(key);
+ }
+ },
+
+ performLeave: function performLeave(key) {
+ this.currentlyTransitioningKeys[key] = true;
+
+ var component = this.refs[key];
+ if (component.componentWillLeave) {
+ component.componentWillLeave(this._handleDoneLeaving.bind(this, key));
+ } else {
+ // Note that this is somewhat dangerous b/c it calls setState()
+ // again, effectively mutating the component before all the work
+ // is done.
+ this._handleDoneLeaving(key);
+ }
+ },
+
+ _handleDoneLeaving: function _handleDoneLeaving(key) {
+ var component = this.refs[key];
+
+ if (component.componentDidLeave) {
+ component.componentDidLeave();
+ }
+
+ delete this.currentlyTransitioningKeys[key];
+
+ var currentChildMapping = ReactTransitionChildMapping.getChildMapping(this.props.children);
+
+ if (currentChildMapping && currentChildMapping.hasOwnProperty(key)) {
+ // This entered again before it fully left. Add it again.
+ this.performEnter(key);
+ } else {
+ this.setState(function (state) {
+ var newChildren = assign({}, state.children);
+ delete newChildren[key];
+ return { children: newChildren };
+ });
+ }
+ },
+
+ render: function render() {
+ // TODO: we could get rid of the need for the wrapper node
+ // by cloning a single child
+ var childrenToRender = [];
+ for (var key in this.state.children) {
+ var child = this.state.children[key];
+ if (child) {
+ // You may need to apply reactive updates to a child as it is leaving.
+ // The normal React way to do it won't work since the child will have
+ // already been removed. In case you need this behavior you can provide
+ // a childFactory function to wrap every child, even the ones that are
+ // leaving.
+ childrenToRender.push(React.cloneElement(this.props.childFactory(child), { ref: key, key: key }));
+ }
+ }
+ return React.createElement(this.props.component, this.props, childrenToRender);
+ }
+});
+
+module.exports = ReactTransitionGroup;
\ No newline at end of file
diff --git a/lib/ReactWithAddons.js b/lib/ReactWithAddons.js
new file mode 100644
index 0000000..0c1cabf
--- /dev/null
+++ b/lib/ReactWithAddons.js
@@ -0,0 +1,50 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule ReactWithAddons
+ */
+
+/**
+ * This module exists purely in the open source project, and is meant as a way
+ * to create a separate standalone build of React. This build has "addons", or
+ * functionality we've built and think might be useful but doesn't have a good
+ * place to live inside React core.
+ */
+'use strict';
+
+var React = require('../dist/react-lite.common');
+var LinkedStateMixin = require('./LinkedStateMixin');
+var ReactComponentWithPureRenderMixin = require('./ReactComponentWithPureRenderMixin');
+var ReactCSSTransitionGroup = require('./ReactCSSTransitionGroup');
+var ReactFragment = require('./ReactFragment');
+var ReactTransitionGroup = require('./ReactTransitionGroup');
+var ReactUpdates = React;
+var shallowCompare = require('./shallowCompare');
+var update = require('./update');
+
+var warning = function warning() {};
+
+var cloneWithProps = React.cloneElement;
+
+var warnedAboutBatchedUpdates = false;
+
+React.addons = {
+ CSSTransitionGroup: ReactCSSTransitionGroup,
+ LinkedStateMixin: LinkedStateMixin,
+ PureRenderMixin: ReactComponentWithPureRenderMixin,
+ TransitionGroup: ReactTransitionGroup,
+ batchedUpdates: function batchedUpdates() {
+ return ReactUpdates.batchedUpdates.apply(this, arguments);
+ },
+ cloneWithProps: cloneWithProps,
+ createFragment: ReactFragment.create,
+ shallowCompare: shallowCompare,
+ update: update
+};
+
+module.exports = React;
\ No newline at end of file
diff --git a/lib/constant.js b/lib/constant.js
new file mode 100644
index 0000000..dfccb51
--- /dev/null
+++ b/lib/constant.js
@@ -0,0 +1,36 @@
+/*
+ key/value configs
+*/
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+var HTML_KEY = 'dangerouslySetInnerHTML';
+exports.HTML_KEY = HTML_KEY;
+var SVGNamespaceURI = 'http://www.w3.org/2000/svg';
+exports.SVGNamespaceURI = SVGNamespaceURI;
+var COMPONENT_ID = 'liteid';
+exports.COMPONENT_ID = COMPONENT_ID;
+var VTEXT = 1;
+exports.VTEXT = VTEXT;
+var VELEMENT = 2;
+exports.VELEMENT = VELEMENT;
+var VSTATELESS = 3;
+exports.VSTATELESS = VSTATELESS;
+var VCOMPONENT = 4;
+exports.VCOMPONENT = VCOMPONENT;
+var VCOMMENT = 5;
+exports.VCOMMENT = VCOMMENT;
+var CREATE = 1;
+exports.CREATE = CREATE;
+var REMOVE = 2;
+exports.REMOVE = REMOVE;
+var UPDATE = 3;
+exports.UPDATE = UPDATE;
+var ELEMENT_NODE_TYPE = 1;
+exports.ELEMENT_NODE_TYPE = ELEMENT_NODE_TYPE;
+var DOC_NODE_TYPE = 9;
+exports.DOC_NODE_TYPE = DOC_NODE_TYPE;
+var DOCUMENT_FRAGMENT_NODE_TYPE = 11;
+exports.DOCUMENT_FRAGMENT_NODE_TYPE = DOCUMENT_FRAGMENT_NODE_TYPE;
\ No newline at end of file
diff --git a/lib/createClass.js b/lib/createClass.js
new file mode 100644
index 0000000..4ec41dc
--- /dev/null
+++ b/lib/createClass.js
@@ -0,0 +1,119 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports['default'] = createClass;
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+var _util = require('./util');
+
+var _ = _interopRequireWildcard(_util);
+
+var _Component = require('./Component');
+
+var _Component2 = _interopRequireDefault(_Component);
+
+function eachMixin(mixins, iteratee) {
+ mixins.forEach(function (mixin) {
+ if (mixin) {
+ if (_.isArr(mixin.mixins)) {
+ eachMixin(mixin.mixins, iteratee);
+ }
+ iteratee(mixin);
+ }
+ });
+}
+
+function combineMixinToProto(proto, mixin) {
+ for (var key in mixin) {
+ if (!mixin.hasOwnProperty(key)) {
+ continue;
+ }
+ var value = mixin[key];
+ if (key === 'getInitialState') {
+ _.addItem(proto.$getInitialStates, value);
+ continue;
+ }
+ var curValue = proto[key];
+ if (_.isFn(curValue) && _.isFn(value)) {
+ proto[key] = _.pipe(curValue, value);
+ } else {
+ proto[key] = value;
+ }
+ }
+}
+
+function combineMixinToClass(Component, mixin) {
+ if (mixin.propTypes) {
+ Component.propTypes = Component.propTypes || {};
+ _.extend(Component.propTypes, mixin.propTypes);
+ }
+ if (mixin.contextTypes) {
+ Component.contextTypes = Component.contextTypes || {};
+ _.extend(Component.contextTypes, mixin.contextTypes);
+ }
+ _.extend(Component, mixin.statics);
+ if (_.isFn(mixin.getDefaultProps)) {
+ Component.defaultProps = Component.defaultProps || {};
+ _.extend(Component.defaultProps, mixin.getDefaultProps());
+ }
+}
+
+function bindContext(obj, source) {
+ for (var key in source) {
+ if (source.hasOwnProperty(key)) {
+ if (_.isFn(source[key])) {
+ obj[key] = source[key].bind(obj);
+ }
+ }
+ }
+}
+
+var Facade = function Facade() {};
+Facade.prototype = _Component2['default'].prototype;
+
+function getInitialState() {
+ var _this = this;
+
+ var state = {};
+ var setState = this.setState;
+ this.setState = Facade;
+ this.$getInitialStates.forEach(function (getInitialState) {
+ if (_.isFn(getInitialState)) {
+ _.extend(state, getInitialState.call(_this));
+ }
+ });
+ this.setState = setState;
+ return state;
+}
+
+function createClass(spec) {
+ if (!_.isFn(spec.render)) {
+ throw new Error('createClass: spec.render is not function');
+ }
+ var specMixins = spec.mixins || [];
+ var mixins = specMixins.concat(spec);
+ spec.mixins = null;
+ function Klass(props, context) {
+ _Component2['default'].call(this, props, context);
+ this.constructor = Klass;
+ spec.autobind !== false && bindContext(this, Klass.prototype);
+ this.state = this.getInitialState() || this.state;
+ }
+ Klass.displayName = spec.displayName;
+ var proto = Klass.prototype = new Facade();
+ proto.$getInitialStates = [];
+ eachMixin(mixins, function (mixin) {
+ combineMixinToProto(proto, mixin);
+ combineMixinToClass(Klass, mixin);
+ });
+ proto.getInitialState = getInitialState;
+ spec.mixins = specMixins;
+ return Klass;
+}
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/lib/createElement.js b/lib/createElement.js
new file mode 100644
index 0000000..9e392b0
--- /dev/null
+++ b/lib/createElement.js
@@ -0,0 +1,116 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports['default'] = createElement;
+exports.isValidElement = isValidElement;
+exports.cloneElement = cloneElement;
+exports.createFactory = createFactory;
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+var _util = require('./util');
+
+var _ = _interopRequireWildcard(_util);
+
+var _constant = require('./constant');
+
+var _virtualDom = require('./virtual-dom');
+
+function createElement(type, props, children) {
+ var vtype = null;
+ if (typeof type === 'string') {
+ vtype = _constant.VELEMENT;
+ } else if (typeof type === 'function') {
+ if (type.prototype && type.prototype.isReactComponent) {
+ vtype = _constant.VCOMPONENT;
+ } else {
+ vtype = _constant.VSTATELESS;
+ }
+ } else {
+ throw new Error('React.createElement: unexpect type [ ' + type + ' ]');
+ }
+
+ var key = null;
+ var ref = null;
+ var finalProps = {};
+ if (props != null) {
+ for (var propKey in props) {
+ if (!props.hasOwnProperty(propKey)) {
+ continue;
+ }
+ if (propKey === 'key') {
+ if (props.key !== undefined) {
+ key = '' + props.key;
+ }
+ } else if (propKey === 'ref') {
+ if (props.ref !== undefined) {
+ ref = props.ref;
+ }
+ } else {
+ finalProps[propKey] = props[propKey];
+ }
+ }
+ }
+
+ var defaultProps = type.defaultProps;
+
+ if (defaultProps) {
+ for (var propKey in defaultProps) {
+ if (finalProps[propKey] === undefined) {
+ finalProps[propKey] = defaultProps[propKey];
+ }
+ }
+ }
+
+ var argsLen = arguments.length;
+ var finalChildren = children;
+
+ if (argsLen > 3) {
+ finalChildren = Array(argsLen - 2);
+ for (var i = 2; i < argsLen; i++) {
+ finalChildren[i - 2] = arguments[i];
+ }
+ }
+
+ if (finalChildren !== undefined) {
+ finalProps.children = finalChildren;
+ }
+
+ return (0, _virtualDom.createVnode)(vtype, type, finalProps, key, ref);
+}
+
+function isValidElement(obj) {
+ return obj != null && !!obj.vtype;
+}
+
+function cloneElement(originElem, props) {
+ var type = originElem.type;
+ var key = originElem.key;
+ var ref = originElem.ref;
+
+ var newProps = _.extend(_.extend({ key: key, ref: ref }, originElem.props), props);
+
+ for (var _len = arguments.length, children = Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
+ children[_key - 2] = arguments[_key];
+ }
+
+ var vnode = createElement.apply(undefined, [type, newProps].concat(children));
+ if (vnode.ref === originElem.ref) {
+ vnode.refs = originElem.refs;
+ }
+ return vnode;
+}
+
+function createFactory(type) {
+ var factory = function factory() {
+ for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+ args[_key2] = arguments[_key2];
+ }
+
+ return createElement.apply(undefined, [type].concat(args));
+ };
+ factory.type = type;
+ return factory;
+}
\ No newline at end of file
diff --git a/lib/event-system.js b/lib/event-system.js
new file mode 100644
index 0000000..24f5323
--- /dev/null
+++ b/lib/event-system.js
@@ -0,0 +1,187 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.getEventName = getEventName;
+exports.addEvent = addEvent;
+exports.removeEvent = removeEvent;
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+var _Component = require('./Component');
+
+var _util = require('./util');
+
+var _ = _interopRequireWildcard(_util);
+
+// event config
+var unbubbleEvents = {
+ /**
+ * should not bind mousemove in document scope
+ * even though mousemove event can bubble
+ */
+ onmousemove: 1,
+ ontouchmove: 1,
+ onmouseleave: 1,
+ onmouseenter: 1,
+ onload: 1,
+ onunload: 1,
+ onscroll: 1,
+ onfocus: 1,
+ onblur: 1,
+ onrowexit: 1,
+ onbeforeunload: 1,
+ onstop: 1,
+ ondragdrop: 1,
+ ondragenter: 1,
+ ondragexit: 1,
+ ondraggesture: 1,
+ ondragover: 1,
+ oncontextmenu: 1,
+ onerror: 1
+};
+
+exports.unbubbleEvents = unbubbleEvents;
+
+function getEventName(key) {
+ if (key === 'onDoubleClick') {
+ key = 'ondblclick';
+ } else if (key === 'onTouchTap') {
+ key = 'onclick';
+ }
+
+ return key.toLowerCase();
+}
+
+// Mobile Safari does not fire properly bubble click events on
+// non-interactive elements, which means delegated click listeners do not
+// fire. The workaround for this bug involves attaching an empty click
+// listener on the target node.
+var inMobile = ('ontouchstart' in document);
+var emptyFunction = function emptyFunction() {};
+var ON_CLICK_KEY = 'onclick';
+
+var eventTypes = {};
+
+function addEvent(elem, eventType, listener) {
+ eventType = getEventName(eventType);
+
+ var eventStore = elem.eventStore || (elem.eventStore = {});
+ eventStore[eventType] = listener;
+
+ if (unbubbleEvents[eventType] === 1) {
+ elem[eventType] = dispatchUnbubbleEvent;
+ return;
+ } else if (!eventTypes[eventType]) {
+ // onclick -> click
+ document.addEventListener(eventType.substr(2), dispatchEvent, false);
+ eventTypes[eventType] = true;
+ }
+
+ if (inMobile && eventType === ON_CLICK_KEY) {
+ elem.addEventListener('click', emptyFunction, false);
+ return;
+ }
+
+ var nodeName = elem.nodeName;
+
+ if (eventType === 'onchange' && supportInputEvent(elem)) {
+ addEvent(elem, 'oninput', listener);
+ }
+}
+
+function removeEvent(elem, eventType) {
+ eventType = getEventName(eventType);
+
+ var eventStore = elem.eventStore || (elem.eventStore = {});
+ delete eventStore[eventType];
+
+ if (unbubbleEvents[eventType] === 1) {
+ elem[eventType] = null;
+ return;
+ } else if (inMobile && eventType === ON_CLICK_KEY) {
+ elem.removeEventListener('click', emptyFunction, false);
+ return;
+ }
+
+ var nodeName = elem.nodeName;
+
+ if (eventType === 'onchange' && supportInputEvent(elem)) {
+ delete eventStore['oninput'];
+ }
+}
+
+function dispatchEvent(event) {
+ var target = event.target;
+ var type = event.type;
+
+ var eventType = 'on' + type;
+ var syntheticEvent = undefined;
+
+ _Component.updateQueue.isPending = true;
+ while (target) {
+ var _target = target;
+ var eventStore = _target.eventStore;
+
+ var listener = eventStore && eventStore[eventType];
+ if (!listener) {
+ target = target.parentNode;
+ continue;
+ }
+ if (!syntheticEvent) {
+ syntheticEvent = createSyntheticEvent(event);
+ }
+ syntheticEvent.currentTarget = target;
+ listener.call(target, syntheticEvent);
+ if (syntheticEvent.$cancelBubble) {
+ break;
+ }
+ target = target.parentNode;
+ }
+ _Component.updateQueue.isPending = false;
+ _Component.updateQueue.batchUpdate();
+}
+
+function dispatchUnbubbleEvent(event) {
+ var target = event.currentTarget || event.target;
+ var eventType = 'on' + event.type;
+ var syntheticEvent = createSyntheticEvent(event);
+
+ syntheticEvent.currentTarget = target;
+ _Component.updateQueue.isPending = true;
+
+ var eventStore = target.eventStore;
+
+ var listener = eventStore && eventStore[eventType];
+ if (listener) {
+ listener.call(target, syntheticEvent);
+ }
+
+ _Component.updateQueue.isPending = false;
+ _Component.updateQueue.batchUpdate();
+}
+
+function createSyntheticEvent(nativeEvent) {
+ var syntheticEvent = {};
+ var cancelBubble = function cancelBubble() {
+ return syntheticEvent.$cancelBubble = true;
+ };
+ syntheticEvent.nativeEvent = nativeEvent;
+ syntheticEvent.persist = _.noop;
+ for (var key in nativeEvent) {
+ if (typeof nativeEvent[key] !== 'function') {
+ syntheticEvent[key] = nativeEvent[key];
+ } else if (key === 'stopPropagation' || key === 'stopImmediatePropagation') {
+ syntheticEvent[key] = cancelBubble;
+ } else {
+ syntheticEvent[key] = nativeEvent[key].bind(nativeEvent);
+ }
+ }
+ return syntheticEvent;
+}
+
+function supportInputEvent(elem) {
+ var nodeName = elem.nodeName && elem.nodeName.toLowerCase();
+ return nodeName !== 'select' && !(nodeName === 'input' && elem.type === 'file');
+}
\ No newline at end of file
diff --git a/lib/index.js b/lib/index.js
new file mode 100644
index 0000000..f61c7d0
--- /dev/null
+++ b/lib/index.js
@@ -0,0 +1,64 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+var _Component = require('./Component');
+
+var _Component2 = _interopRequireDefault(_Component);
+
+var _PureComponent = require('./PureComponent');
+
+var _PureComponent2 = _interopRequireDefault(_PureComponent);
+
+var _createClass = require('./createClass');
+
+var _createClass2 = _interopRequireDefault(_createClass);
+
+var _createElement = require('./createElement');
+
+var _createElement2 = _interopRequireDefault(_createElement);
+
+var _Children = require('./Children');
+
+var Children = _interopRequireWildcard(_Children);
+
+var _ReactDOM = require('./ReactDOM');
+
+var ReactDOM = _interopRequireWildcard(_ReactDOM);
+
+var _PropTypes = require('./PropTypes');
+
+var _PropTypes2 = _interopRequireDefault(_PropTypes);
+
+var _DOM = require('./DOM');
+
+var _DOM2 = _interopRequireDefault(_DOM);
+
+var _util = require('./util');
+
+var _ = _interopRequireWildcard(_util);
+
+var React = _.extend({
+ version: '0.15.1',
+ cloneElement: _createElement.cloneElement,
+ isValidElement: _createElement.isValidElement,
+ createElement: _createElement2['default'],
+ createFactory: _createElement.createFactory,
+ Component: _Component2['default'],
+ PureComponent: _PureComponent2['default'],
+ createClass: _createClass2['default'],
+ Children: Children,
+ PropTypes: _PropTypes2['default'],
+ DOM: _DOM2['default']
+}, ReactDOM);
+
+React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactDOM;
+
+exports['default'] = React;
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/lib/react-tap-event-plugin.js b/lib/react-tap-event-plugin.js
new file mode 100644
index 0000000..955636a
--- /dev/null
+++ b/lib/react-tap-event-plugin.js
@@ -0,0 +1,9 @@
+'use strict';
+
+var Fastclick = require('fastclick');
+module.exports = function injectTapEventPlugin() {
+ var supportTouch = ('ontouchstart' in document);
+ if (supportTouch) {
+ Fastclick.attach(document.body);
+ }
+};
\ No newline at end of file
diff --git a/lib/renderSubtreeIntoContainer.js b/lib/renderSubtreeIntoContainer.js
new file mode 100644
index 0000000..87d28d8
--- /dev/null
+++ b/lib/renderSubtreeIntoContainer.js
@@ -0,0 +1,15 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+* @providesModule renderSubtreeIntoContainer
+*/
+
+'use strict';
+var React = require('../dist/react-lite.common');
+var unstable_renderSubtreeIntoContainer = React.unstable_renderSubtreeIntoContainer;
+module.exports = unstable_renderSubtreeIntoContainer;
\ No newline at end of file
diff --git a/lib/shallowCompare.js b/lib/shallowCompare.js
new file mode 100644
index 0000000..92fd6da
--- /dev/null
+++ b/lib/shallowCompare.js
@@ -0,0 +1,23 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+* @providesModule shallowCompare
+*/
+'use strict';
+
+var shallowEqual = require('./utils/shallowEqual');
+
+/**
+ * Does a shallow comparison for props and state.
+ * See ReactComponentWithPureRenderMixin
+ */
+function shallowCompare(instance, nextProps, nextState) {
+ return !shallowEqual(instance.props, nextProps) || !shallowEqual(instance.state, nextState);
+}
+
+module.exports = shallowCompare;
\ No newline at end of file
diff --git a/lib/shallowEqual.js b/lib/shallowEqual.js
new file mode 100644
index 0000000..bb3fb42
--- /dev/null
+++ b/lib/shallowEqual.js
@@ -0,0 +1,34 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports['default'] = shallowEqual;
+
+function shallowEqual(objA, objB) {
+ if (objA === objB) {
+ return true;
+ }
+
+ if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
+ return false;
+ }
+
+ var keysA = Object.keys(objA);
+ var keysB = Object.keys(objB);
+
+ if (keysA.length !== keysB.length) {
+ return false;
+ }
+
+ // Test for A's keys different from B.
+ for (var i = 0; i < keysA.length; i++) {
+ if (!objB.hasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+module.exports = exports['default'];
\ No newline at end of file
diff --git a/lib/update.js b/lib/update.js
new file mode 100644
index 0000000..a2a667c
--- /dev/null
+++ b/lib/update.js
@@ -0,0 +1,108 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule update
+ */
+
+/* global hasOwnProperty:true */
+
+'use strict';
+
+var React = require('../dist/react-lite.common');
+var assign = Object.assign;
+var keyOf = require('./utils/keyOf');
+var invariant = function invariant() {};
+var hasOwnProperty = ({}).hasOwnProperty;
+
+function shallowCopy(x) {
+ if (Array.isArray(x)) {
+ return x.concat();
+ } else if (x && typeof x === 'object') {
+ return assign(new x.constructor(), x);
+ } else {
+ return x;
+ }
+}
+
+var COMMAND_PUSH = keyOf({ $push: null });
+var COMMAND_UNSHIFT = keyOf({ $unshift: null });
+var COMMAND_SPLICE = keyOf({ $splice: null });
+var COMMAND_SET = keyOf({ $set: null });
+var COMMAND_MERGE = keyOf({ $merge: null });
+var COMMAND_APPLY = keyOf({ $apply: null });
+
+var ALL_COMMANDS_LIST = [COMMAND_PUSH, COMMAND_UNSHIFT, COMMAND_SPLICE, COMMAND_SET, COMMAND_MERGE, COMMAND_APPLY];
+
+var ALL_COMMANDS_SET = {};
+
+ALL_COMMANDS_LIST.forEach(function (command) {
+ ALL_COMMANDS_SET[command] = true;
+});
+
+function invariantArrayCase(value, spec, command) {
+ invariant(Array.isArray(value), 'update(): expected target of %s to be an array; got %s.', command, value);
+ var specValue = spec[command];
+ invariant(Array.isArray(specValue), 'update(): expected spec of %s to be an array; got %s. ' + 'Did you forget to wrap your parameter in an array?', command, specValue);
+}
+
+function update(value, spec) {
+ invariant(typeof spec === 'object', 'update(): You provided a key path to update() that did not contain one ' + 'of %s. Did you forget to include {%s: ...}?', ALL_COMMANDS_LIST.join(', '), COMMAND_SET);
+
+ if (hasOwnProperty.call(spec, COMMAND_SET)) {
+ invariant(Object.keys(spec).length === 1, 'Cannot have more than one key in an object with %s', COMMAND_SET);
+
+ return spec[COMMAND_SET];
+ }
+
+ var nextValue = shallowCopy(value);
+
+ if (hasOwnProperty.call(spec, COMMAND_MERGE)) {
+ var mergeObj = spec[COMMAND_MERGE];
+ invariant(mergeObj && typeof mergeObj === 'object', 'update(): %s expects a spec of type \'object\'; got %s', COMMAND_MERGE, mergeObj);
+ invariant(nextValue && typeof nextValue === 'object', 'update(): %s expects a target of type \'object\'; got %s', COMMAND_MERGE, nextValue);
+ assign(nextValue, spec[COMMAND_MERGE]);
+ }
+
+ if (hasOwnProperty.call(spec, COMMAND_PUSH)) {
+ invariantArrayCase(value, spec, COMMAND_PUSH);
+ spec[COMMAND_PUSH].forEach(function (item) {
+ nextValue.push(item);
+ });
+ }
+
+ if (hasOwnProperty.call(spec, COMMAND_UNSHIFT)) {
+ invariantArrayCase(value, spec, COMMAND_UNSHIFT);
+ spec[COMMAND_UNSHIFT].forEach(function (item) {
+ nextValue.unshift(item);
+ });
+ }
+
+ if (hasOwnProperty.call(spec, COMMAND_SPLICE)) {
+ invariant(Array.isArray(value), 'Expected %s target to be an array; got %s', COMMAND_SPLICE, value);
+ invariant(Array.isArray(spec[COMMAND_SPLICE]), 'update(): expected spec of %s to be an array of arrays; got %s. ' + 'Did you forget to wrap your parameters in an array?', COMMAND_SPLICE, spec[COMMAND_SPLICE]);
+ spec[COMMAND_SPLICE].forEach(function (args) {
+ invariant(Array.isArray(args), 'update(): expected spec of %s to be an array of arrays; got %s. ' + 'Did you forget to wrap your parameters in an array?', COMMAND_SPLICE, spec[COMMAND_SPLICE]);
+ nextValue.splice.apply(nextValue, args);
+ });
+ }
+
+ if (hasOwnProperty.call(spec, COMMAND_APPLY)) {
+ invariant(typeof spec[COMMAND_APPLY] === 'function', 'update(): expected spec of %s to be a function; got %s.', COMMAND_APPLY, spec[COMMAND_APPLY]);
+ nextValue = spec[COMMAND_APPLY](nextValue);
+ }
+
+ for (var k in spec) {
+ if (!(ALL_COMMANDS_SET.hasOwnProperty(k) && ALL_COMMANDS_SET[k])) {
+ nextValue[k] = update(value[k], spec[k]);
+ }
+ }
+
+ return nextValue;
+}
+
+module.exports = update;
\ No newline at end of file
diff --git a/lib/util.js b/lib/util.js
new file mode 100644
index 0000000..dc44083
--- /dev/null
+++ b/lib/util.js
@@ -0,0 +1,165 @@
+// util
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.isFn = isFn;
+exports.noop = noop;
+exports.identity = identity;
+exports.pipe = pipe;
+exports.addItem = addItem;
+exports.flatEach = flatEach;
+exports.extend = extend;
+exports.getUid = getUid;
+exports.setProps = setProps;
+exports.patchProps = patchProps;
+
+var _eventSystem = require('./event-system');
+
+var _CSSPropertyOperationsJs = require('./CSSPropertyOperations.js');
+
+var _DOMPropertyOperations = require('./DOMPropertyOperations');
+
+var _constant = require('./constant');
+
+function isFn(obj) {
+ return typeof obj === 'function';
+}
+
+var isArr = Array.isArray;
+
+exports.isArr = isArr;
+
+function noop() {}
+
+function identity(obj) {
+ return obj;
+}
+
+function pipe(fn1, fn2) {
+ return function () {
+ fn1.apply(this, arguments);
+ return fn2.apply(this, arguments);
+ };
+}
+
+function addItem(list, item) {
+ list[list.length] = item;
+}
+
+function flatEach(list, iteratee, a) {
+ var len = list.length;
+ var i = -1;
+
+ while (len--) {
+ var item = list[++i];
+ if (isArr(item)) {
+ flatEach(item, iteratee, a);
+ } else {
+ iteratee(item, a);
+ }
+ }
+}
+
+function extend(to, from) {
+ if (!from) {
+ return to;
+ }
+ var keys = Object.keys(from);
+ var i = keys.length;
+ while (i--) {
+ to[keys[i]] = from[keys[i]];
+ }
+ return to;
+}
+
+var uid = 0;
+
+function getUid() {
+ return ++uid;
+}
+
+var EVENT_KEYS = /^on/i;
+
+exports.EVENT_KEYS = EVENT_KEYS;
+function setProp(elem, key, value, isCustomComponent) {
+ if (EVENT_KEYS.test(key)) {
+ (0, _eventSystem.addEvent)(elem, key, value);
+ } else if (key === 'style') {
+ (0, _CSSPropertyOperationsJs.setStyle)(elem.style, value);
+ } else if (key === _constant.HTML_KEY) {
+ if (value && value.__html != null) {
+ elem.innerHTML = value.__html;
+ }
+ } else if (isCustomComponent) {
+ if (value == null) {
+ elem.removeAttribute(key);
+ } else {
+ elem.setAttribute(key, '' + value);
+ }
+ } else {
+ (0, _DOMPropertyOperations.setPropValue)(elem, key, value);
+ }
+}
+
+function removeProp(elem, key, oldValue, isCustomComponent) {
+ if (EVENT_KEYS.test(key)) {
+ (0, _eventSystem.removeEvent)(elem, key);
+ } else if (key === 'style') {
+ (0, _CSSPropertyOperationsJs.removeStyle)(elem.style, oldValue);
+ } else if (key === _constant.HTML_KEY) {
+ elem.innerHTML = '';
+ } else if (isCustomComponent) {
+ elem.removeAttribute(key);
+ } else {
+ (0, _DOMPropertyOperations.removePropValue)(elem, key);
+ }
+}
+
+function patchProp(elem, key, value, oldValue, isCustomComponent) {
+ if (key === 'value' || key === 'checked') {
+ oldValue = elem[key];
+ }
+ if (value === oldValue) {
+ return;
+ }
+ if (value === undefined) {
+ removeProp(elem, key, oldValue, isCustomComponent);
+ return;
+ }
+ if (key === 'style') {
+ (0, _CSSPropertyOperationsJs.patchStyle)(elem.style, oldValue, value);
+ } else {
+ setProp(elem, key, value, isCustomComponent);
+ }
+}
+
+function setProps(elem, props, isCustomComponent) {
+ for (var key in props) {
+ if (key !== 'children') {
+ setProp(elem, key, props[key], isCustomComponent);
+ }
+ }
+}
+
+function patchProps(elem, props, newProps, isCustomComponent) {
+ for (var key in props) {
+ if (key !== 'children') {
+ if (newProps.hasOwnProperty(key)) {
+ patchProp(elem, key, newProps[key], props[key], isCustomComponent);
+ } else {
+ removeProp(elem, key, props[key], isCustomComponent);
+ }
+ }
+ }
+ for (var key in newProps) {
+ if (key !== 'children' && !props.hasOwnProperty(key)) {
+ setProp(elem, key, newProps[key], isCustomComponent);
+ }
+ }
+}
+
+if (!Object.freeze) {
+ Object.freeze = identity;
+}
\ No newline at end of file
diff --git a/lib/utils/CSSCore.js b/lib/utils/CSSCore.js
new file mode 100644
index 0000000..7750979
--- /dev/null
+++ b/lib/utils/CSSCore.js
@@ -0,0 +1,97 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule CSSCore
+ * @typechecks
+ */
+
+'use strict';
+
+var invariant = function invariant() {};
+
+/**
+ * The CSSCore module specifies the API (and implements most of the methods)
+ * that should be used when dealing with the display of elements (via their
+ * CSS classes and visibility on screen. It is an API focused on mutating the
+ * display and not reading it as no logical state should be encoded in the
+ * display of elements.
+ */
+
+var CSSCore = {
+
+ /**
+ * Adds the class passed in to the element if it doesn't already have it.
+ *
+ * @param {DOMElement} element the element to set the class on
+ * @param {string} className the CSS className
+ * @return {DOMElement} the element passed in
+ */
+ addClass: function addClass(element, className) {
+ !!/\s/.test(className) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'CSSCore.addClass takes only a single class name. "%s" contains ' + 'multiple classes.', className) : invariant(false) : undefined;
+
+ if (className) {
+ if (element.classList) {
+ element.classList.add(className);
+ } else if (!CSSCore.hasClass(element, className)) {
+ element.className = element.className + ' ' + className;
+ }
+ }
+ return element;
+ },
+
+ /**
+ * Removes the class passed in from the element
+ *
+ * @param {DOMElement} element the element to set the class on
+ * @param {string} className the CSS className
+ * @return {DOMElement} the element passed in
+ */
+ removeClass: function removeClass(element, className) {
+ !!/\s/.test(className) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'CSSCore.removeClass takes only a single class name. "%s" contains ' + 'multiple classes.', className) : invariant(false) : undefined;
+
+ if (className) {
+ if (element.classList) {
+ element.classList.remove(className);
+ } else if (CSSCore.hasClass(element, className)) {
+ element.className = element.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)', 'g'), '$1').replace(/\s+/g, ' ') // multiple spaces to one
+ .replace(/^\s*|\s*$/g, ''); // trim the ends
+ }
+ }
+ return element;
+ },
+
+ /**
+ * Helper to add or remove a class from an element based on a condition.
+ *
+ * @param {DOMElement} element the element to set the class on
+ * @param {string} className the CSS className
+ * @param {*} bool condition to whether to add or remove the class
+ * @return {DOMElement} the element passed in
+ */
+ conditionClass: function conditionClass(element, className, bool) {
+ return (bool ? CSSCore.addClass : CSSCore.removeClass)(element, className);
+ },
+
+ /**
+ * Tests whether the element has the class specified.
+ *
+ * @param {DOMNode|DOMWindow} element the element to set the class on
+ * @param {string} className the CSS className
+ * @return {boolean} true if the element has the class, false if not
+ */
+ hasClass: function hasClass(element, className) {
+ !!/\s/.test(className) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'CSS.hasClass takes only a single class name.') : invariant(false) : undefined;
+ if (element.classList) {
+ return !!className && element.classList.contains(className);
+ }
+ return (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1;
+ }
+
+};
+
+module.exports = CSSCore;
\ No newline at end of file
diff --git a/lib/utils/PooledClass.js b/lib/utils/PooledClass.js
new file mode 100644
index 0000000..b2675f9
--- /dev/null
+++ b/lib/utils/PooledClass.js
@@ -0,0 +1,119 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule PooledClass
+ */
+
+'use strict';
+
+var invariant = function invariant() {};
+
+/**
+ * Static poolers. Several custom versions for each potential number of
+ * arguments. A completely generic pooler is easy to implement, but would
+ * require accessing the `arguments` object. In each of these, `this` refers to
+ * the Class itself, not an instance. If any others are needed, simply add them
+ * here, or in their own files.
+ */
+var oneArgumentPooler = function oneArgumentPooler(copyFieldsFrom) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, copyFieldsFrom);
+ return instance;
+ } else {
+ return new Klass(copyFieldsFrom);
+ }
+};
+
+var twoArgumentPooler = function twoArgumentPooler(a1, a2) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2);
+ return instance;
+ } else {
+ return new Klass(a1, a2);
+ }
+};
+
+var threeArgumentPooler = function threeArgumentPooler(a1, a2, a3) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2, a3);
+ return instance;
+ } else {
+ return new Klass(a1, a2, a3);
+ }
+};
+
+var fourArgumentPooler = function fourArgumentPooler(a1, a2, a3, a4) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2, a3, a4);
+ return instance;
+ } else {
+ return new Klass(a1, a2, a3, a4);
+ }
+};
+
+var fiveArgumentPooler = function fiveArgumentPooler(a1, a2, a3, a4, a5) {
+ var Klass = this;
+ if (Klass.instancePool.length) {
+ var instance = Klass.instancePool.pop();
+ Klass.call(instance, a1, a2, a3, a4, a5);
+ return instance;
+ } else {
+ return new Klass(a1, a2, a3, a4, a5);
+ }
+};
+
+var standardReleaser = function standardReleaser(instance) {
+ var Klass = this;
+ invariant(instance instanceof Klass, 'Trying to release an instance into a pool of a different type.');
+ instance.destructor();
+ if (Klass.instancePool.length < Klass.poolSize) {
+ Klass.instancePool.push(instance);
+ }
+};
+
+var DEFAULT_POOL_SIZE = 10;
+var DEFAULT_POOLER = oneArgumentPooler;
+
+/**
+ * Augments `CopyConstructor` to be a poolable class, augmenting only the class
+ * itself (statically) not adding any prototypical fields. Any CopyConstructor
+ * you give this may have a `poolSize` property, and will look for a
+ * prototypical `destructor` on instances (optional).
+ *
+ * @param {Function} CopyConstructor Constructor that can be used to reset.
+ * @param {Function} pooler Customizable pooler.
+ */
+var addPoolingTo = function addPoolingTo(CopyConstructor, pooler) {
+ var NewKlass = CopyConstructor;
+ NewKlass.instancePool = [];
+ NewKlass.getPooled = pooler || DEFAULT_POOLER;
+ if (!NewKlass.poolSize) {
+ NewKlass.poolSize = DEFAULT_POOL_SIZE;
+ }
+ NewKlass.release = standardReleaser;
+ return NewKlass;
+};
+
+var PooledClass = {
+ addPoolingTo: addPoolingTo,
+ oneArgumentPooler: oneArgumentPooler,
+ twoArgumentPooler: twoArgumentPooler,
+ threeArgumentPooler: threeArgumentPooler,
+ fourArgumentPooler: fourArgumentPooler,
+ fiveArgumentPooler: fiveArgumentPooler
+};
+
+module.exports = PooledClass;
\ No newline at end of file
diff --git a/lib/utils/emptyFunction.js b/lib/utils/emptyFunction.js
new file mode 100644
index 0000000..aa042b6
--- /dev/null
+++ b/lib/utils/emptyFunction.js
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule emptyFunction
+ */
+
+"use strict";
+
+function makeEmptyFunction(arg) {
+ return function () {
+ return arg;
+ };
+}
+
+/**
+ * This function accepts and discards inputs; it has no side effects. This is
+ * primarily useful idiomatically for overridable function endpoints which
+ * always need to be callable, since JS lacks a null-call idiom ala Cocoa.
+ */
+function emptyFunction() {}
+
+emptyFunction.thatReturns = makeEmptyFunction;
+emptyFunction.thatReturnsFalse = makeEmptyFunction(false);
+emptyFunction.thatReturnsTrue = makeEmptyFunction(true);
+emptyFunction.thatReturnsNull = makeEmptyFunction(null);
+emptyFunction.thatReturnsThis = function () {
+ return this;
+};
+emptyFunction.thatReturnsArgument = function (arg) {
+ return arg;
+};
+
+module.exports = emptyFunction;
\ No newline at end of file
diff --git a/lib/utils/escapeTextContentForBrowser.js b/lib/utils/escapeTextContentForBrowser.js
new file mode 100644
index 0000000..691dc29
--- /dev/null
+++ b/lib/utils/escapeTextContentForBrowser.js
@@ -0,0 +1,38 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule escapeTextContentForBrowser
+ */
+
+'use strict';
+
+var ESCAPE_LOOKUP = {
+ '&': '&',
+ '>': '>',
+ '<': '<',
+ '"': '"',
+ '\'': '''
+};
+
+var ESCAPE_REGEX = /[&><"']/g;
+
+function escaper(match) {
+ return ESCAPE_LOOKUP[match];
+}
+
+/**
+ * Escapes text to prevent scripting attacks.
+ *
+ * @param {*} text Text value to escape.
+ * @return {string} An escaped string.
+ */
+function escapeTextContentForBrowser(text) {
+ return ('' + text).replace(ESCAPE_REGEX, escaper);
+}
+
+module.exports = escapeTextContentForBrowser;
\ No newline at end of file
diff --git a/lib/utils/flattenChildren.js b/lib/utils/flattenChildren.js
new file mode 100644
index 0000000..316407b
--- /dev/null
+++ b/lib/utils/flattenChildren.js
@@ -0,0 +1,43 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule flattenChildren
+ */
+'use strict';
+
+var traverseAllChildren = require('./traverseAllChildren');
+
+/**
+ * @param {function} traverseContext Context passed through traversal.
+ * @param {?ReactComponent} child React child component.
+ * @param {!string} name String name of key path to child.
+ */
+function flattenSingleChildIntoContext(traverseContext, child, name) {
+ // We found a component instance.
+ var result = traverseContext;
+ var keyUnique = result[name] === undefined;
+ if (keyUnique && child != null) {
+ result[name] = child;
+ }
+}
+
+/**
+ * Flattens children that are typically specified as `props.children`. Any null
+ * children will not be included in the resulting object.
+ * @return {!object} flattened children keyed by name.
+ */
+function flattenChildren(children) {
+ if (children == null) {
+ return children;
+ }
+ var result = {};
+ traverseAllChildren(children, flattenSingleChildIntoContext, result);
+ return result;
+}
+
+module.exports = flattenChildren;
\ No newline at end of file
diff --git a/lib/utils/getIteratorFn.js b/lib/utils/getIteratorFn.js
new file mode 100644
index 0000000..d0f86c3
--- /dev/null
+++ b/lib/utils/getIteratorFn.js
@@ -0,0 +1,40 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule getIteratorFn
+ * @typechecks static-only
+ */
+
+'use strict';
+
+/* global Symbol */
+var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
+var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
+
+/**
+ * Returns the iterator method function contained on the iterable object.
+ *
+ * Be sure to invoke the function with the iterable as context:
+ *
+ * var iteratorFn = getIteratorFn(myIterable);
+ * if (iteratorFn) {
+ * var iterator = iteratorFn.call(myIterable);
+ * ...
+ * }
+ *
+ * @param {?object} maybeIterable
+ * @return {?function}
+ */
+function getIteratorFn(maybeIterable) {
+ var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
+ if (typeof iteratorFn === 'function') {
+ return iteratorFn;
+ }
+}
+
+module.exports = getIteratorFn;
\ No newline at end of file
diff --git a/lib/utils/keyOf.js b/lib/utils/keyOf.js
new file mode 100644
index 0000000..9673c2a
--- /dev/null
+++ b/lib/utils/keyOf.js
@@ -0,0 +1,35 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule keyOf
+ */
+
+/**
+ * Allows extraction of a minified key. Let's the build system minify keys
+ * without losing the ability to dynamically use key strings as values
+ * themselves. Pass in an object with a single key/val pair and it will return
+ * you the string key of that single record. Suppose you want to grab the
+ * value for a key 'className' inside of an object. Key/val minification may
+ * have aliased that key to be 'xa12'. keyOf({className: null}) will return
+ * 'xa12' in that case. Resolve keys you want to use once at startup time, then
+ * reuse those resolutions.
+ */
+"use strict";
+
+var keyOf = function keyOf(oneKeyObj) {
+ var key;
+ for (key in oneKeyObj) {
+ if (!oneKeyObj.hasOwnProperty(key)) {
+ continue;
+ }
+ return key;
+ }
+ return null;
+};
+
+module.exports = keyOf;
\ No newline at end of file
diff --git a/lib/utils/quoteAttributeValueForBrowser.js b/lib/utils/quoteAttributeValueForBrowser.js
new file mode 100644
index 0000000..1de985a
--- /dev/null
+++ b/lib/utils/quoteAttributeValueForBrowser.js
@@ -0,0 +1,26 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule quoteAttributeValueForBrowser
+ */
+
+'use strict';
+
+var escapeTextContentForBrowser = require('./escapeTextContentForBrowser');
+
+/**
+ * Escapes attribute value to prevent scripting attacks.
+ *
+ * @param {*} value Value to escape.
+ * @return {string} An escaped string.
+ */
+function quoteAttributeValueForBrowser(value) {
+ return '"' + escapeTextContentForBrowser(value) + '"';
+}
+
+module.exports = quoteAttributeValueForBrowser;
\ No newline at end of file
diff --git a/lib/utils/shallowEqual.js b/lib/utils/shallowEqual.js
new file mode 100644
index 0000000..5d54e62
--- /dev/null
+++ b/lib/utils/shallowEqual.js
@@ -0,0 +1,50 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule shallowEqual
+ * @typechecks
+ *
+ */
+
+'use strict';
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+/**
+ * Performs equality by iterating through keys on an object and returning false
+ * when any key has values which are not strictly equal between the arguments.
+ * Returns true when the values of all keys are strictly equal.
+ */
+function shallowEqual(objA, objB) {
+ if (objA === objB) {
+ return true;
+ }
+
+ if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) {
+ return false;
+ }
+
+ var keysA = Object.keys(objA);
+ var keysB = Object.keys(objB);
+
+ if (keysA.length !== keysB.length) {
+ return false;
+ }
+
+ // Test for A's keys different from B.
+ var bHasOwnProperty = hasOwnProperty.bind(objB);
+ for (var i = 0; i < keysA.length; i++) {
+ if (!bHasOwnProperty(keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+module.exports = shallowEqual;
\ No newline at end of file
diff --git a/lib/utils/traverseAllChildren.js b/lib/utils/traverseAllChildren.js
new file mode 100644
index 0000000..33354e3
--- /dev/null
+++ b/lib/utils/traverseAllChildren.js
@@ -0,0 +1,169 @@
+/**
+ * Copyright 2013-2015, Facebook, Inc.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree. An additional grant
+ * of patent rights can be found in the PATENTS file in the same directory.
+ *
+ * @providesModule traverseAllChildren
+ */
+'use strict';
+
+var React = require('../../dist/react-lite.common');
+var isValidElement = React.isValidElement;
+var getIteratorFn = require('./getIteratorFn');
+
+var invariant = function invariant() {};
+var SEPARATOR = '.';
+var SUBSEPARATOR = ':';
+
+/**
+ * TODO: Test that a single child and an array with one item have the same key
+ * pattern.
+ */
+
+var userProvidedKeyEscaperLookup = {
+ '=': '=0',
+ '.': '=1',
+ ':': '=2'
+};
+
+var userProvidedKeyEscapeRegex = /[=.:]/g;
+
+var didWarnAboutMaps = false;
+
+function userProvidedKeyEscaper(match) {
+ return userProvidedKeyEscaperLookup[match];
+}
+
+/**
+ * Generate a key string that identifies a component within a set.
+ *
+ * @param {*} component A component that could contain a manual key.
+ * @param {number} index Index that is used if a manual key is not provided.
+ * @return {string}
+ */
+function getComponentKey(component, index) {
+ if (component && component.key != null) {
+ // Explicit key
+ return wrapUserProvidedKey(component.key);
+ }
+ // Implicit key determined by the index in the set
+ return index.toString(36);
+}
+
+/**
+ * Escape a component key so that it is safe to use in a reactid.
+ *
+ * @param {*} text Component key to be escaped.
+ * @return {string} An escaped string.
+ */
+function escapeUserProvidedKey(text) {
+ return ('' + text).replace(userProvidedKeyEscapeRegex, userProvidedKeyEscaper);
+}
+
+/**
+ * Wrap a `key` value explicitly provided by the user to distinguish it from
+ * implicitly-generated keys generated by a component's index in its parent.
+ *
+ * @param {string} key Value of a user-provided `key` attribute
+ * @return {string}
+ */
+function wrapUserProvidedKey(key) {
+ return '$' + escapeUserProvidedKey(key);
+}
+
+/**
+ * @param {?*} children Children tree container.
+ * @param {!string} nameSoFar Name of the key path so far.
+ * @param {!function} callback Callback to invoke with each child found.
+ * @param {?*} traverseContext Used to pass information throughout the traversal
+ * process.
+ * @return {!number} The number of children in this subtree.
+ */
+function traverseAllChildrenImpl(children, nameSoFar, callback, traverseContext) {
+ var type = typeof children;
+
+ if (type === 'undefined' || type === 'boolean') {
+ // All of the above are perceived as null.
+ children = null;
+ }
+
+ if (children === null || type === 'string' || type === 'number' || isValidElement(children)) {
+ callback(traverseContext, children,
+ // If it's the only child, treat the name as if it was wrapped in an array
+ // so that it's consistent if the number of children grows.
+ nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar);
+ return 1;
+ }
+
+ var child;
+ var nextName;
+ var subtreeCount = 0; // Count of children found in the current subtree.
+ var nextNamePrefix = nameSoFar === '' ? SEPARATOR : nameSoFar + SUBSEPARATOR;
+
+ if (Array.isArray(children)) {
+ for (var i = 0; i < children.length; i++) {
+ child = children[i];
+ nextName = nextNamePrefix + getComponentKey(child, i);
+ subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
+ }
+ } else {
+ var iteratorFn = getIteratorFn(children);
+ if (iteratorFn) {
+ var iterator = iteratorFn.call(children);
+ var step;
+ if (iteratorFn !== children.entries) {
+ var ii = 0;
+ while (!(step = iterator.next()).done) {
+ child = step.value;
+ nextName = nextNamePrefix + getComponentKey(child, ii++);
+ subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
+ }
+ } else {
+ // Iterator will provide entry [k,v] tuples rather than values.
+ while (!(step = iterator.next()).done) {
+ var entry = step.value;
+ if (entry) {
+ child = entry[1];
+ nextName = nextNamePrefix + wrapUserProvidedKey(entry[0]) + SUBSEPARATOR + getComponentKey(child, 0);
+ subtreeCount += traverseAllChildrenImpl(child, nextName, callback, traverseContext);
+ }
+ }
+ }
+ } else if (type === 'object') {
+ var addendum = '';
+ var childrenString = String(children);
+ invariant(false, 'Objects are not valid as a React child (found: %s).%s', childrenString === '[object Object]' ? 'object with keys {' + Object.keys(children).join(', ') + '}' : childrenString, addendum);
+ }
+ }
+
+ return subtreeCount;
+}
+
+/**
+ * Traverses children that are typically specified as `props.children`, but
+ * might also be specified through attributes:
+ *
+ * - `traverseAllChildren(this.props.children, ...)`
+ * - `traverseAllChildren(this.props.leftPanelChildren, ...)`
+ *
+ * The `traverseContext` is an optional argument that is passed through the
+ * entire traversal. It can be used to store accumulations or anything else that
+ * the callback might find relevant.
+ *
+ * @param {?*} children Children tree object.
+ * @param {!function} callback To invoke upon traversing each child.
+ * @param {?*} traverseContext Context for traversal.
+ * @return {!number} The number of children in this subtree.
+ */
+function traverseAllChildren(children, callback, traverseContext) {
+ if (children == null) {
+ return 0;
+ }
+
+ return traverseAllChildrenImpl(children, '', callback, traverseContext);
+}
+
+module.exports = traverseAllChildren;
\ No newline at end of file
diff --git a/lib/virtual-dom.js b/lib/virtual-dom.js
new file mode 100644
index 0000000..52db0d4
--- /dev/null
+++ b/lib/virtual-dom.js
@@ -0,0 +1,643 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', {
+ value: true
+});
+exports.createVnode = createVnode;
+exports.initVnode = initVnode;
+exports.destroyVnode = destroyVnode;
+exports.renderComponent = renderComponent;
+exports.getChildContext = getChildContext;
+exports.clearPending = clearPending;
+exports.compareTwoVnodes = compareTwoVnodes;
+exports.syncCache = syncCache;
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+var _util = require('./util');
+
+var _ = _interopRequireWildcard(_util);
+
+var _constant = require('./constant');
+
+/**
+ * current stateful component's refs property
+ * will attach to every vnode created by calling component.render method
+ */
+var refs = null;
+
+function createVnode(vtype, type, props, key, ref) {
+ var vnode = {
+ vtype: vtype,
+ type: type,
+ props: props,
+ refs: refs,
+ key: key,
+ ref: ref
+ };
+ if (vtype === _constant.VSTATELESS || vtype === _constant.VCOMPONENT) {
+ vnode.uid = _.getUid();
+ }
+ return vnode;
+}
+
+function initVnode(vnode, parentContext, namespaceURI) {
+ var vtype = vnode.vtype;
+
+ var node = null;
+ if (!vtype) {
+ // init text
+ node = document.createTextNode(vnode);
+ } else if (vtype === _constant.VELEMENT) {
+ // init element
+ node = initVelem(vnode, parentContext, namespaceURI);
+ } else if (vtype === _constant.VCOMPONENT) {
+ // init stateful component
+ node = initVcomponent(vnode, parentContext, namespaceURI);
+ } else if (vtype === _constant.VSTATELESS) {
+ // init stateless component
+ node = initVstateless(vnode, parentContext, namespaceURI);
+ } else if (vtype === _constant.VCOMMENT) {
+ // init comment
+ node = document.createComment('react-text: ' + (vnode.uid || _.getUid()));
+ }
+ return node;
+}
+
+function updateVnode(vnode, newVnode, node, parentContext) {
+ var vtype = vnode.vtype;
+
+ if (vtype === _constant.VCOMPONENT) {
+ return updateVcomponent(vnode, newVnode, node, parentContext);
+ }
+
+ if (vtype === _constant.VSTATELESS) {
+ return updateVstateless(vnode, newVnode, node, parentContext);
+ }
+
+ // ignore VCOMMENT and other vtypes
+ if (vtype !== _constant.VELEMENT) {
+ return node;
+ }
+
+ var oldHtml = vnode.props[_constant.HTML_KEY] && vnode.props[_constant.HTML_KEY].__html;
+ if (oldHtml != null) {
+ updateVelem(vnode, newVnode, node, parentContext);
+ initVchildren(newVnode, node, parentContext);
+ } else {
+ updateVChildren(vnode, newVnode, node, parentContext);
+ updateVelem(vnode, newVnode, node, parentContext);
+ }
+ return node;
+}
+
+function updateVChildren(vnode, newVnode, node, parentContext) {
+ var patches = {
+ removes: [],
+ updates: [],
+ creates: []
+ };
+ diffVchildren(patches, vnode, newVnode, node, parentContext);
+ _.flatEach(patches.removes, applyDestroy);
+ _.flatEach(patches.updates, applyUpdate);
+ _.flatEach(patches.creates, applyCreate);
+}
+
+function applyUpdate(data) {
+ if (!data) {
+ return;
+ }
+ var vnode = data.vnode;
+ var newNode = data.node;
+
+ // update
+ if (!data.shouldIgnore) {
+ if (!vnode.vtype) {
+ newNode.replaceData(0, newNode.length, data.newVnode);
+ } else if (vnode.vtype === _constant.VELEMENT) {
+ updateVelem(vnode, data.newVnode, newNode, data.parentContext);
+ } else if (vnode.vtype === _constant.VSTATELESS) {
+ newNode = updateVstateless(vnode, data.newVnode, newNode, data.parentContext);
+ } else if (vnode.vtype === _constant.VCOMPONENT) {
+ newNode = updateVcomponent(vnode, data.newVnode, newNode, data.parentContext);
+ }
+ }
+
+ // re-order
+ var currentNode = newNode.parentNode.childNodes[data.index];
+ if (currentNode !== newNode) {
+ newNode.parentNode.insertBefore(newNode, currentNode);
+ }
+ return newNode;
+}
+
+function applyDestroy(data) {
+ destroyVnode(data.vnode, data.node);
+ data.node.parentNode.removeChild(data.node);
+}
+
+function applyCreate(data) {
+ var node = initVnode(data.vnode, data.parentContext, data.parentNode.namespaceURI);
+ data.parentNode.insertBefore(node, data.parentNode.childNodes[data.index]);
+}
+
+/**
+ * Only vnode which has props.children need to call destroy function
+ * to check whether subTree has component that need to call lify-cycle method and release cache.
+ */
+
+function destroyVnode(vnode, node) {
+ var vtype = vnode.vtype;
+
+ if (vtype === _constant.VELEMENT) {
+ // destroy element
+ destroyVelem(vnode, node);
+ } else if (vtype === _constant.VCOMPONENT) {
+ // destroy state component
+ destroyVcomponent(vnode, node);
+ } else if (vtype === _constant.VSTATELESS) {
+ // destroy stateless component
+ destroyVstateless(vnode, node);
+ }
+}
+
+function initVelem(velem, parentContext, namespaceURI) {
+ var type = velem.type;
+ var props = velem.props;
+
+ var node = null;
+
+ if (type === 'svg' || namespaceURI === _constant.SVGNamespaceURI) {
+ node = document.createElementNS(_constant.SVGNamespaceURI, type);
+ namespaceURI = _constant.SVGNamespaceURI;
+ } else {
+ node = document.createElement(type);
+ }
+
+ initVchildren(velem, node, parentContext);
+
+ var isCustomComponent = type.indexOf('-') >= 0 || props.is != null;
+ _.setProps(node, props, isCustomComponent);
+
+ if (velem.ref != null) {
+ _.addItem(pendingRefs, velem);
+ _.addItem(pendingRefs, node);
+ }
+
+ return node;
+}
+
+function initVchildren(velem, node, parentContext) {
+ var vchildren = node.vchildren = getFlattenChildren(velem);
+ var namespaceURI = node.namespaceURI;
+ for (var i = 0, len = vchildren.length; i < len; i++) {
+ node.appendChild(initVnode(vchildren[i], parentContext, namespaceURI));
+ }
+}
+
+function getFlattenChildren(vnode) {
+ var children = vnode.props.children;
+
+ var vchildren = [];
+ if (_.isArr(children)) {
+ _.flatEach(children, collectChild, vchildren);
+ } else {
+ collectChild(children, vchildren);
+ }
+ return vchildren;
+}
+
+function collectChild(child, children) {
+ if (child != null && typeof child !== 'boolean') {
+ if (!child.vtype) {
+ // convert immutablejs data
+ if (child.toJS) {
+ child = child.toJS();
+ if (_.isArr(child)) {
+ _.flatEach(child, collectChild, children);
+ } else {
+ collectChild(child, children);
+ }
+ return;
+ }
+ child = '' + child;
+ }
+ children[children.length] = child;
+ }
+}
+
+function diffVchildren(patches, vnode, newVnode, node, parentContext) {
+ if (!node.vchildren) return; // react-lite hasn't seen this DOM node before
+
+ var childNodes = node.childNodes;
+ var vchildren = node.vchildren;
+
+ var newVchildren = node.vchildren = getFlattenChildren(newVnode);
+ var vchildrenLen = vchildren.length;
+ var newVchildrenLen = newVchildren.length;
+
+ if (vchildrenLen === 0) {
+ if (newVchildrenLen > 0) {
+ for (var i = 0; i < newVchildrenLen; i++) {
+ _.addItem(patches.creates, {
+ vnode: newVchildren[i],
+ parentNode: node,
+ parentContext: parentContext,
+ index: i
+ });
+ }
+ }
+ return;
+ } else if (newVchildrenLen === 0) {
+ for (var i = 0; i < vchildrenLen; i++) {
+ _.addItem(patches.removes, {
+ vnode: vchildren[i],
+ node: childNodes[i]
+ });
+ }
+ return;
+ }
+
+ var updates = Array(newVchildrenLen);
+ var removes = null;
+ var creates = null;
+
+ // isEqual
+ for (var i = 0; i < vchildrenLen; i++) {
+ var _vnode = vchildren[i];
+ for (var j = 0; j < newVchildrenLen; j++) {
+ if (updates[j]) {
+ continue;
+ }
+ var _newVnode = newVchildren[j];
+ if (_vnode === _newVnode) {
+ var shouldIgnore = true;
+ if (parentContext) {
+ if (_vnode.vtype === _constant.VCOMPONENT || _vnode.vtype === _constant.VSTATELESS) {
+ if (_vnode.type.contextTypes) {
+ shouldIgnore = false;
+ }
+ }
+ }
+ updates[j] = {
+ shouldIgnore: shouldIgnore,
+ vnode: _vnode,
+ newVnode: _newVnode,
+ node: childNodes[i],
+ parentContext: parentContext,
+ index: j
+ };
+ vchildren[i] = null;
+ break;
+ }
+ }
+ }
+
+ // isSimilar
+ for (var i = 0; i < vchildrenLen; i++) {
+ var _vnode2 = vchildren[i];
+ if (_vnode2 === null) {
+ continue;
+ }
+ var shouldRemove = true;
+ for (var j = 0; j < newVchildrenLen; j++) {
+ if (updates[j]) {
+ continue;
+ }
+ var _newVnode2 = newVchildren[j];
+ if (_newVnode2.type === _vnode2.type && _newVnode2.key === _vnode2.key && _newVnode2.refs === _vnode2.refs) {
+ updates[j] = {
+ vnode: _vnode2,
+ newVnode: _newVnode2,
+ node: childNodes[i],
+ parentContext: parentContext,
+ index: j
+ };
+ shouldRemove = false;
+ break;
+ }
+ }
+ if (shouldRemove) {
+ if (!removes) {
+ removes = [];
+ }
+ _.addItem(removes, {
+ vnode: _vnode2,
+ node: childNodes[i]
+ });
+ }
+ }
+
+ for (var i = 0; i < newVchildrenLen; i++) {
+ var item = updates[i];
+ if (!item) {
+ if (!creates) {
+ creates = [];
+ }
+ _.addItem(creates, {
+ vnode: newVchildren[i],
+ parentNode: node,
+ parentContext: parentContext,
+ index: i
+ });
+ } else if (item.vnode.vtype === _constant.VELEMENT) {
+ diffVchildren(patches, item.vnode, item.newVnode, item.node, item.parentContext);
+ }
+ }
+
+ if (removes) {
+ _.addItem(patches.removes, removes);
+ }
+ if (creates) {
+ _.addItem(patches.creates, creates);
+ }
+ _.addItem(patches.updates, updates);
+}
+
+function updateVelem(velem, newVelem, node) {
+ var isCustomComponent = velem.type.indexOf('-') >= 0 || velem.props.is != null;
+ _.patchProps(node, velem.props, newVelem.props, isCustomComponent);
+ if (velem.ref !== newVelem.ref) {
+ detachRef(velem.refs, velem.ref, node);
+ attachRef(newVelem.refs, newVelem.ref, node);
+ }
+ return node;
+}
+
+function destroyVelem(velem, node) {
+ var props = velem.props;
+ var vchildren = node.vchildren;
+ var childNodes = node.childNodes;
+
+ if (vchildren) {
+ for (var i = 0, len = vchildren.length; i < len; i++) {
+ destroyVnode(vchildren[i], childNodes[i]);
+ }
+ }
+ detachRef(velem.refs, velem.ref, node);
+ node.eventStore = node.vchildren = null;
+}
+
+function initVstateless(vstateless, parentContext, namespaceURI) {
+ var vnode = renderVstateless(vstateless, parentContext);
+ var node = initVnode(vnode, parentContext, namespaceURI);
+ node.cache = node.cache || {};
+ node.cache[vstateless.uid] = vnode;
+ return node;
+}
+
+function updateVstateless(vstateless, newVstateless, node, parentContext) {
+ var uid = vstateless.uid;
+ var vnode = node.cache[uid];
+ delete node.cache[uid];
+ var newVnode = renderVstateless(newVstateless, parentContext);
+ var newNode = compareTwoVnodes(vnode, newVnode, node, parentContext);
+ newNode.cache = newNode.cache || {};
+ newNode.cache[newVstateless.uid] = newVnode;
+ if (newNode !== node) {
+ syncCache(newNode.cache, node.cache, newNode);
+ }
+ return newNode;
+}
+
+function destroyVstateless(vstateless, node) {
+ var uid = vstateless.uid;
+ var vnode = node.cache[uid];
+ delete node.cache[uid];
+ destroyVnode(vnode, node);
+}
+
+function renderVstateless(vstateless, parentContext) {
+ var factory = vstateless.type;
+ var props = vstateless.props;
+
+ var componentContext = getContextByTypes(parentContext, factory.contextTypes);
+ var vnode = factory(props, componentContext);
+ if (vnode && vnode.render) {
+ vnode = vnode.render();
+ }
+ if (vnode === null || vnode === false) {
+ vnode = createVnode(_constant.VCOMMENT);
+ } else if (!vnode || !vnode.vtype) {
+ throw new Error('@' + factory.name + '#render:You may have returned undefined, an array or some other invalid object');
+ }
+ return vnode;
+}
+
+function initVcomponent(vcomponent, parentContext, namespaceURI) {
+ var Component = vcomponent.type;
+ var props = vcomponent.props;
+ var uid = vcomponent.uid;
+
+ var componentContext = getContextByTypes(parentContext, Component.contextTypes);
+ var component = new Component(props, componentContext);
+ var updater = component.$updater;
+ var cache = component.$cache;
+
+ cache.parentContext = parentContext;
+ updater.isPending = true;
+ component.props = component.props || props;
+ component.context = component.context || componentContext;
+ if (component.componentWillMount) {
+ component.componentWillMount();
+ component.state = updater.getState();
+ }
+ var vnode = renderComponent(component);
+ var node = initVnode(vnode, getChildContext(component, parentContext), namespaceURI);
+ node.cache = node.cache || {};
+ node.cache[uid] = component;
+ cache.vnode = vnode;
+ cache.node = node;
+ cache.isMounted = true;
+ _.addItem(pendingComponents, component);
+
+ if (vcomponent.ref != null) {
+ _.addItem(pendingRefs, vcomponent);
+ _.addItem(pendingRefs, component);
+ }
+
+ return node;
+}
+
+function updateVcomponent(vcomponent, newVcomponent, node, parentContext) {
+ var uid = vcomponent.uid;
+ var component = node.cache[uid];
+ var updater = component.$updater;
+ var cache = component.$cache;
+ var Component = newVcomponent.type;
+ var nextProps = newVcomponent.props;
+
+ var componentContext = getContextByTypes(parentContext, Component.contextTypes);
+ delete node.cache[uid];
+ node.cache[newVcomponent.uid] = component;
+ cache.parentContext = parentContext;
+ if (component.componentWillReceiveProps) {
+ var needToggleIsPending = !updater.isPending;
+ if (needToggleIsPending) updater.isPending = true;
+ component.componentWillReceiveProps(nextProps, componentContext);
+ if (needToggleIsPending) updater.isPending = false;
+ }
+
+ if (vcomponent.ref !== newVcomponent.ref) {
+ detachRef(vcomponent.refs, vcomponent.ref, component);
+ attachRef(newVcomponent.refs, newVcomponent.ref, component);
+ }
+
+ updater.emitUpdate(nextProps, componentContext);
+
+ return cache.node;
+}
+
+function destroyVcomponent(vcomponent, node) {
+ var uid = vcomponent.uid;
+ var component = node.cache[uid];
+ var cache = component.$cache;
+ delete node.cache[uid];
+ detachRef(vcomponent.refs, vcomponent.ref, component);
+ component.setState = component.forceUpdate = _.noop;
+ if (component.componentWillUnmount) {
+ component.componentWillUnmount();
+ }
+ destroyVnode(cache.vnode, node);
+ delete component.setState;
+ cache.isMounted = false;
+ cache.node = cache.parentContext = cache.vnode = component.refs = component.context = null;
+}
+
+function getContextByTypes(curContext, contextTypes) {
+ var context = {};
+ if (!contextTypes || !curContext) {
+ return context;
+ }
+ for (var key in contextTypes) {
+ if (contextTypes.hasOwnProperty(key)) {
+ context[key] = curContext[key];
+ }
+ }
+ return context;
+}
+
+function renderComponent(component, parentContext) {
+ refs = component.refs;
+ var vnode = component.render();
+ if (vnode === null || vnode === false) {
+ vnode = createVnode(_constant.VCOMMENT);
+ } else if (!vnode || !vnode.vtype) {
+ throw new Error('@' + component.constructor.name + '#render:You may have returned undefined, an array or some other invalid object');
+ }
+ refs = null;
+ return vnode;
+}
+
+function getChildContext(component, parentContext) {
+ if (component.getChildContext) {
+ var curContext = component.getChildContext();
+ if (curContext) {
+ parentContext = _.extend(_.extend({}, parentContext), curContext);
+ }
+ }
+ return parentContext;
+}
+
+var pendingComponents = [];
+function clearPendingComponents() {
+ var len = pendingComponents.length;
+ if (!len) {
+ return;
+ }
+ var components = pendingComponents;
+ pendingComponents = [];
+ var i = -1;
+ while (len--) {
+ var component = components[++i];
+ var updater = component.$updater;
+ if (component.componentDidMount) {
+ component.componentDidMount();
+ }
+ updater.isPending = false;
+ updater.emitUpdate();
+ }
+}
+
+var pendingRefs = [];
+function clearPendingRefs() {
+ var len = pendingRefs.length;
+ if (!len) {
+ return;
+ }
+ var list = pendingRefs;
+ pendingRefs = [];
+ for (var i = 0; i < len; i += 2) {
+ var vnode = list[i];
+ var refValue = list[i + 1];
+ attachRef(vnode.refs, vnode.ref, refValue);
+ }
+}
+
+function clearPending() {
+ clearPendingRefs();
+ clearPendingComponents();
+}
+
+function compareTwoVnodes(vnode, newVnode, node, parentContext) {
+ var newNode = node;
+ if (newVnode == null) {
+ // remove
+ destroyVnode(vnode, node);
+ node.parentNode.removeChild(node);
+ } else if (vnode.type !== newVnode.type || vnode.key !== newVnode.key) {
+ // replace
+ destroyVnode(vnode, node);
+ newNode = initVnode(newVnode, parentContext, node.namespaceURI);
+ node.parentNode.replaceChild(newNode, node);
+ } else if (vnode !== newVnode || parentContext) {
+ // same type and same key -> update
+ newNode = updateVnode(vnode, newVnode, node, parentContext);
+ }
+ return newNode;
+}
+
+function getDOMNode() {
+ return this;
+}
+
+function attachRef(refs, refKey, refValue) {
+ if (refKey == null || !refValue) {
+ return;
+ }
+ if (refValue.nodeName && !refValue.getDOMNode) {
+ // support react v0.13 style: this.refs.myInput.getDOMNode()
+ refValue.getDOMNode = getDOMNode;
+ }
+ if (_.isFn(refKey)) {
+ refKey(refValue);
+ } else if (refs) {
+ refs[refKey] = refValue;
+ }
+}
+
+function detachRef(refs, refKey, refValue) {
+ if (refKey == null) {
+ return;
+ }
+ if (_.isFn(refKey)) {
+ refKey(null);
+ } else if (refs && refs[refKey] === refValue) {
+ delete refs[refKey];
+ }
+}
+
+function syncCache(cache, oldCache, node) {
+ for (var key in oldCache) {
+ if (!oldCache.hasOwnProperty(key)) {
+ continue;
+ }
+ var value = oldCache[key];
+ cache[key] = value;
+
+ // is component, update component.$cache.node
+ if (value.forceUpdate) {
+ value.$cache.node = node;
+ }
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index fd326cb..37d7858 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"scripts": {
"test": "jest",
"build:addons": "babel ./addons --out-dir ./lib",
- "build": "node build.js && npm run build:addons",
+ "build:core": "babel ./src --out-dir ./lib",
+ "build": "node build.js && npm run build:core && npm run build:addons",
"prepublish": "npm test && npm run build"
},
"publishConfig": {