react 0.9.0 → 0.10.0-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/lib/AutoFocusMixin.js +3 -1
  2. package/lib/DOMChildrenOperations.js +12 -6
  3. package/lib/DOMProperty.js +6 -4
  4. package/lib/DOMPropertyOperations.js +6 -6
  5. package/lib/DefaultDOMPropertyConfig.js +5 -12
  6. package/lib/EventPluginHub.js +2 -0
  7. package/lib/LinkedValueUtils.js +22 -23
  8. package/lib/React.js +3 -1
  9. package/lib/ReactBrowserComponentMixin.js +42 -0
  10. package/lib/ReactCSSTransitionGroup.js +10 -10
  11. package/lib/ReactComponent.js +76 -31
  12. package/lib/ReactComponentBrowserEnvironment.js +1 -35
  13. package/lib/ReactCompositeComponent.js +199 -67
  14. package/lib/ReactDOM.js +5 -5
  15. package/lib/ReactDOMButton.js +2 -1
  16. package/lib/ReactDOMComponent.js +22 -5
  17. package/lib/ReactDOMForm.js +3 -0
  18. package/lib/ReactDOMImg.js +3 -0
  19. package/lib/ReactDOMInput.js +2 -1
  20. package/lib/ReactDOMOption.js +11 -7
  21. package/lib/ReactDOMSelect.js +2 -1
  22. package/lib/ReactDOMTextarea.js +7 -3
  23. package/lib/ReactDefaultInjection.js +10 -0
  24. package/lib/ReactInjection.js +4 -0
  25. package/lib/ReactInputSelection.js +2 -1
  26. package/lib/ReactMount.js +13 -5
  27. package/lib/ReactMultiChild.js +10 -3
  28. package/lib/ReactOwner.js +6 -1
  29. package/lib/ReactPropTransferer.js +1 -1
  30. package/lib/ReactReconcileTransaction.js +7 -6
  31. package/lib/ReactServerRendering.js +38 -8
  32. package/lib/ReactServerRenderingTransaction.js +116 -0
  33. package/lib/ReactTextComponent.js +24 -2
  34. package/lib/ReactWithAddons.js +3 -1
  35. package/lib/cloneWithProps.js +7 -7
  36. package/lib/{ReactComponentEnvironment.js → emptyObject.js} +6 -5
  37. package/lib/focusNode.js +33 -0
  38. package/lib/instantiateReactComponent.js +70 -0
  39. package/lib/isNode.js +1 -1
  40. package/lib/monitorCodeUse.js +37 -0
  41. package/lib/shouldUpdateReactComponent.js +17 -14
  42. package/lib/traverseAllChildren.js +2 -1
  43. package/lib/update.js +159 -0
  44. package/package.json +1 -1
@@ -39,26 +39,6 @@ var DOC_NODE_TYPE = 9;
39
39
  * the browser context.
40
40
  */
41
41
  var ReactComponentBrowserEnvironment = {
42
- /**
43
- * Mixed into every component instance.
44
- */
45
- Mixin: {
46
- /**
47
- * Returns the DOM node rendered by this component.
48
- *
49
- * @return {DOMElement} The root node of this component.
50
- * @final
51
- * @protected
52
- */
53
- getDOMNode: function() {
54
- ("production" !== process.env.NODE_ENV ? invariant(
55
- this.isMounted(),
56
- 'getDOMNode(): A component must be mounted to have a DOM node.'
57
- ) : invariant(this.isMounted()));
58
- return ReactMount.getNode(this._rootNodeID);
59
- }
60
- },
61
-
62
42
  ReactReconcileTransaction: ReactReconcileTransaction,
63
43
 
64
44
  BackendIDOperations: ReactDOMIDOperations,
@@ -136,21 +116,7 @@ var ReactComponentBrowserEnvironment = {
136
116
  'See renderComponentToString() for server rendering.'
137
117
  ) : invariant(container.nodeType !== DOC_NODE_TYPE));
138
118
 
139
- // Asynchronously inject markup by ensuring that the container is not in
140
- // the document when settings its `innerHTML`.
141
- var parent = container.parentNode;
142
- if (parent) {
143
- var next = container.nextSibling;
144
- parent.removeChild(container);
145
- container.innerHTML = markup;
146
- if (next) {
147
- parent.insertBefore(container, next);
148
- } else {
149
- parent.appendChild(container);
150
- }
151
- } else {
152
- container.innerHTML = markup;
153
- }
119
+ container.innerHTML = markup;
154
120
  }
155
121
  )
156
122
  };
@@ -29,12 +29,15 @@ var ReactPropTypeLocations = require("./ReactPropTypeLocations");
29
29
  var ReactPropTypeLocationNames = require("./ReactPropTypeLocationNames");
30
30
  var ReactUpdates = require("./ReactUpdates");
31
31
 
32
+ var instantiateReactComponent = require("./instantiateReactComponent");
32
33
  var invariant = require("./invariant");
33
34
  var keyMirror = require("./keyMirror");
34
35
  var merge = require("./merge");
35
36
  var mixInto = require("./mixInto");
37
+ var monitorCodeUse = require("./monitorCodeUse");
36
38
  var objMap = require("./objMap");
37
39
  var shouldUpdateReactComponent = require("./shouldUpdateReactComponent");
40
+ var warning = require("./warning");
38
41
 
39
42
  /**
40
43
  * Policies that describe methods in `ReactCompositeComponentInterface`.
@@ -61,6 +64,9 @@ var SpecPolicy = keyMirror({
61
64
  DEFINE_MANY_MERGED: null
62
65
  });
63
66
 
67
+
68
+ var injectedMixins = [];
69
+
64
70
  /**
65
71
  * Composite components are higher-level components that compose other composite
66
72
  * or native components.
@@ -500,7 +506,7 @@ function mixStaticSpecIntoComponent(ConvenienceConstructor, statics) {
500
506
  }
501
507
  for (var name in statics) {
502
508
  var property = statics[name];
503
- if (!statics.hasOwnProperty(name) || !property) {
509
+ if (!statics.hasOwnProperty(name)) {
504
510
  return;
505
511
  }
506
512
 
@@ -592,19 +598,52 @@ if ("production" !== process.env.NODE_ENV) {
592
598
  constructor: true,
593
599
  construct: true,
594
600
  isOwnedBy: true, // should be deprecated but can have code mod (internal)
595
- mountComponent: true,
596
- mountComponentIntoNode: true,
597
- props: true,
598
601
  type: true,
599
- _checkPropTypes: true,
600
- _mountComponentIntoNode: true,
601
- _processContext: true
602
+ props: true,
603
+ // currently private but belong on the descriptor and are valid for use
604
+ // inside the framework:
605
+ __keyValidated__: true,
606
+ _owner: true,
607
+ _currentContext: true
608
+ };
609
+
610
+ var componentInstanceProperties = {
611
+ __keyValidated__: true,
612
+ __keySetters: true,
613
+ _compositeLifeCycleState: true,
614
+ _currentContext: true,
615
+ _defaultProps: true,
616
+ _instance: true,
617
+ _lifeCycleState: true,
618
+ _mountDepth: true,
619
+ _owner: true,
620
+ _pendingCallbacks: true,
621
+ _pendingContext: true,
622
+ _pendingForceUpdate: true,
623
+ _pendingOwner: true,
624
+ _pendingProps: true,
625
+ _pendingState: true,
626
+ _renderedComponent: true,
627
+ _rootNodeID: true,
628
+ context: true,
629
+ props: true,
630
+ refs: true,
631
+ state: true,
632
+
633
+ // These are known instance properties coming from other sources
634
+ _pendingQueries: true,
635
+ _queryPropListeners: true,
636
+ queryParams: true
637
+
602
638
  };
603
639
 
604
640
  var hasWarnedOnComponentType = {};
605
641
 
606
- var warnIfUnmounted = function(instance, key) {
607
- if (instance.__hasBeenMounted) {
642
+ var warningStackCounter = 0;
643
+
644
+ var issueMembraneWarning = function(instance, key) {
645
+ var isWhitelisted = unmountedPropertyWhitelist.hasOwnProperty(key);
646
+ if (warningStackCounter > 0 || isWhitelisted) {
608
647
  return;
609
648
  }
610
649
  var name = instance.constructor.displayName || 'Unknown';
@@ -620,6 +659,7 @@ if ("production" !== process.env.NODE_ENV) {
620
659
  var context = owner ? ' in ' + ownerName + '.' : ' at the top level.';
621
660
  var staticMethodExample = '<' + name + ' />.type.' + key + '(...)';
622
661
 
662
+ monitorCodeUse('react_descriptor_property_access', { component: name });
623
663
  console.warn(
624
664
  'Invalid access to component property "' + key + '" on ' + name +
625
665
  context + ' See http://fb.me/react-warning-descriptors .' +
@@ -627,6 +667,30 @@ if ("production" !== process.env.NODE_ENV) {
627
667
  );
628
668
  };
629
669
 
670
+ var wrapInMembraneFunction = function(fn, thisBinding) {
671
+ if (fn.__reactMembraneFunction && fn.__reactMembraneSelf === thisBinding) {
672
+ return fn.__reactMembraneFunction;
673
+ }
674
+ return fn.__reactMembraneFunction = function() {
675
+ /**
676
+ * By getting this function, you've already received a warning. The
677
+ * internals of this function will likely cause more warnings. To avoid
678
+ * Spamming too much we disable any warning triggered inside of this
679
+ * stack.
680
+ */
681
+ warningStackCounter++;
682
+ try {
683
+ // If the this binding is unchanged, we defer to the real component.
684
+ // This is important to keep some referential integrity in the
685
+ // internals. E.g. owner equality check.
686
+ var self = this === thisBinding ? this.__realComponentInstance : this;
687
+ return fn.apply(self, arguments);
688
+ } finally {
689
+ warningStackCounter--;
690
+ }
691
+ };
692
+ };
693
+
630
694
  var defineMembraneProperty = function(membrane, prototype, key) {
631
695
  Object.defineProperty(membrane, key, {
632
696
 
@@ -634,31 +698,33 @@ if ("production" !== process.env.NODE_ENV) {
634
698
  enumerable: true,
635
699
 
636
700
  get: function() {
637
- if (this !== membrane) {
638
- // When this is accessed through a prototype chain we need to check if
639
- // this component was mounted.
640
- warnIfUnmounted(this, key);
701
+ if (this === membrane) {
702
+ // We're allowed to access the prototype directly.
703
+ return prototype[key];
704
+ }
705
+ issueMembraneWarning(this, key);
706
+
707
+ var realValue = this.__realComponentInstance[key];
708
+ // If the real value is a function, we need to provide a wrapper that
709
+ // disables nested warnings. The properties type and constructors are
710
+ // expected to the be constructors and therefore is often use with an
711
+ // equality check and we shouldn't try to rebind those.
712
+ if (typeof realValue === 'function' &&
713
+ key !== 'type' &&
714
+ key !== 'constructor') {
715
+ return wrapInMembraneFunction(realValue, this);
641
716
  }
642
- return prototype[key];
717
+ return realValue;
643
718
  },
644
719
 
645
720
  set: function(value) {
646
- if (this !== membrane) {
647
- // When this is accessed through a prototype chain, we first check if
648
- // this component was mounted. Then we define a value on "this"
649
- // instance, effectively disabling the membrane on that prototype
650
- // chain.
651
- warnIfUnmounted(this, key);
652
- Object.defineProperty(this, key, {
653
- enumerable: true,
654
- configurable: true,
655
- writable: true,
656
- value: value
657
- });
658
- } else {
659
- // Otherwise, this should modify the prototype
721
+ if (this === membrane) {
722
+ // We're allowed to set a value on the prototype directly.
660
723
  prototype[key] = value;
724
+ return;
661
725
  }
726
+ issueMembraneWarning(this, key);
727
+ this.__realComponentInstance[key] = value;
662
728
  }
663
729
 
664
730
  });
@@ -673,26 +739,51 @@ if ("production" !== process.env.NODE_ENV) {
673
739
  * @private
674
740
  */
675
741
  var createMountWarningMembrane = function(prototype) {
676
- try {
677
- var membrane = Object.create(prototype);
678
- for (var key in prototype) {
679
- if (unmountedPropertyWhitelist.hasOwnProperty(key)) {
680
- continue;
681
- }
742
+ var membrane = {};
743
+ var key;
744
+ for (key in prototype) {
745
+ defineMembraneProperty(membrane, prototype, key);
746
+ }
747
+ // These are properties that goes into the instance but not the prototype.
748
+ // We can create the membrane on the prototype even though this will
749
+ // result in a faulty hasOwnProperty check it's better perf.
750
+ for (key in componentInstanceProperties) {
751
+ if (componentInstanceProperties.hasOwnProperty(key) &&
752
+ !(key in prototype)) {
682
753
  defineMembraneProperty(membrane, prototype, key);
683
754
  }
755
+ }
756
+ return membrane;
757
+ };
758
+
759
+ /**
760
+ * Creates a membrane constructor which wraps the component that gets mounted.
761
+ *
762
+ * @param {function} constructor Original constructor.
763
+ * @return {function} The membrane constructor.
764
+ * @private
765
+ */
766
+ var createDescriptorProxy = function(constructor) {
767
+ try {
768
+ var ProxyConstructor = function() {
769
+ this.__realComponentInstance = new constructor();
684
770
 
685
- membrane.mountComponent = function() {
686
- this.__hasBeenMounted = true;
687
- return prototype.mountComponent.apply(this, arguments);
771
+ // We can only safely pass through known instance variables. Unknown
772
+ // expandos are not safe. Use the real mounted instance to avoid this
773
+ // problem if it blows something up.
774
+ Object.freeze(this);
688
775
  };
689
776
 
690
- return membrane;
777
+ ProxyConstructor.prototype = createMountWarningMembrane(
778
+ constructor.prototype
779
+ );
780
+
781
+ return ProxyConstructor;
691
782
  } catch(x) {
692
783
  // In IE8 define property will fail on non-DOM objects. If anything in
693
- // the membrane creation fails, we'll bail out and just use the prototype
694
- // without warnings.
695
- return prototype;
784
+ // the membrane creation fails, we'll bail out and just use the plain
785
+ // constructor without warnings.
786
+ return constructor;
696
787
  }
697
788
  };
698
789
 
@@ -763,17 +854,34 @@ var ReactCompositeComponentMixin = {
763
854
  construct: function(initialProps, children) {
764
855
  // Children can be either an array or more than one argument
765
856
  ReactComponent.Mixin.construct.apply(this, arguments);
857
+ ReactOwner.Mixin.construct.apply(this, arguments);
766
858
 
767
859
  this.state = null;
768
860
  this._pendingState = null;
769
861
 
770
- this.context = this._processContext(ReactContext.current);
862
+ this.context = null;
771
863
  this._currentContext = ReactContext.current;
772
864
  this._pendingContext = null;
773
865
 
866
+ // The descriptor that was used to instantiate this component. Will be
867
+ // set by the instantiator instead of the constructor since this
868
+ // constructor is currently used by both instances and descriptors.
869
+ this._descriptor = null;
870
+
774
871
  this._compositeLifeCycleState = null;
775
872
  },
776
873
 
874
+ /**
875
+ * Components in the intermediate state now has cyclic references. To avoid
876
+ * breaking JSON serialization we expose a custom JSON format.
877
+ * @return {object} JSON compatible representation.
878
+ * @internal
879
+ * @final
880
+ */
881
+ toJSON: function() {
882
+ return { type: this.type, props: this.props };
883
+ },
884
+
777
885
  /**
778
886
  * Checks whether or not this composite component is mounted.
779
887
  * @return {boolean} True if mounted, false otherwise.
@@ -789,7 +897,7 @@ var ReactCompositeComponentMixin = {
789
897
  * Initializes the component, renders markup, and registers event listeners.
790
898
  *
791
899
  * @param {string} rootID DOM ID of the root node.
792
- * @param {ReactReconcileTransaction} transaction
900
+ * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction
793
901
  * @param {number} mountDepth number of components in the owner hierarchy
794
902
  * @return {?string} Rendered markup to be inserted into the DOM.
795
903
  * @final
@@ -807,6 +915,7 @@ var ReactCompositeComponentMixin = {
807
915
  );
808
916
  this._compositeLifeCycleState = CompositeLifeCycle.MOUNTING;
809
917
 
918
+ this.context = this._processContext(this._currentContext);
810
919
  this._defaultProps = this.getDefaultProps ? this.getDefaultProps() : null;
811
920
  this.props = this._processProps(this.props);
812
921
 
@@ -834,7 +943,9 @@ var ReactCompositeComponentMixin = {
834
943
  }
835
944
  }
836
945
 
837
- this._renderedComponent = this._renderValidatedComponent();
946
+ this._renderedComponent = instantiateReactComponent(
947
+ this._renderValidatedComponent()
948
+ );
838
949
 
839
950
  // Done with mounting, `setState` will now trigger UI changes.
840
951
  this._compositeLifeCycleState = null;
@@ -870,10 +981,6 @@ var ReactCompositeComponentMixin = {
870
981
 
871
982
  ReactComponent.Mixin.unmountComponent.call(this);
872
983
 
873
- if (this.refs) {
874
- this.refs = null;
875
- }
876
-
877
984
  // Some existing components rely on this.props even after they've been
878
985
  // destroyed (in event handlers).
879
986
  // TODO: this.props = null;
@@ -903,12 +1010,11 @@ var ReactCompositeComponentMixin = {
903
1010
  'setState(...): takes an object of state variables to update.'
904
1011
  ) : invariant(typeof partialState === 'object' || partialState == null));
905
1012
  if ("production" !== process.env.NODE_ENV) {
906
- if (partialState == null) {
907
- console.warn(
908
- 'setState(...): You passed an undefined or null state object; ' +
909
- 'instead, use forceUpdate().'
910
- );
911
- }
1013
+ ("production" !== process.env.NODE_ENV ? warning(
1014
+ partialState != null,
1015
+ 'setState(...): You passed an undefined or null state object; ' +
1016
+ 'instead, use forceUpdate().'
1017
+ ) : null);
912
1018
  }
913
1019
  // Merge with `_pendingState` if it exists, otherwise with existing state.
914
1020
  this.replaceState(
@@ -1172,13 +1278,16 @@ var ReactCompositeComponentMixin = {
1172
1278
  },
1173
1279
 
1174
1280
  receiveComponent: function(nextComponent, transaction) {
1175
- if (nextComponent === this) {
1281
+ if (nextComponent === this._descriptor) {
1176
1282
  // Since props and context are immutable after the component is
1177
1283
  // mounted, we can do a cheap identity compare here to determine
1178
1284
  // if this is a superfluous reconcile.
1179
1285
  return;
1180
1286
  }
1181
1287
 
1288
+ // Update the descriptor that was last used by this component instance
1289
+ this._descriptor = nextComponent;
1290
+
1182
1291
  this._pendingContext = nextComponent._currentContext;
1183
1292
  ReactComponent.Mixin.receiveComponent.call(
1184
1293
  this,
@@ -1211,17 +1320,19 @@ var ReactCompositeComponentMixin = {
1211
1320
  prevProps,
1212
1321
  prevOwner
1213
1322
  );
1214
- var prevComponent = this._renderedComponent;
1323
+
1324
+
1325
+ var prevComponentInstance = this._renderedComponent;
1215
1326
  var nextComponent = this._renderValidatedComponent();
1216
- if (shouldUpdateReactComponent(prevComponent, nextComponent)) {
1217
- prevComponent.receiveComponent(nextComponent, transaction);
1327
+ if (shouldUpdateReactComponent(prevComponentInstance, nextComponent)) {
1328
+ prevComponentInstance.receiveComponent(nextComponent, transaction);
1218
1329
  } else {
1219
1330
  // These two IDs are actually the same! But nothing should rely on that.
1220
1331
  var thisID = this._rootNodeID;
1221
- var prevComponentID = prevComponent._rootNodeID;
1222
- prevComponent.unmountComponent();
1223
- this._renderedComponent = nextComponent;
1224
- var nextMarkup = nextComponent.mountComponent(
1332
+ var prevComponentID = prevComponentInstance._rootNodeID;
1333
+ prevComponentInstance.unmountComponent();
1334
+ this._renderedComponent = instantiateReactComponent(nextComponent);
1335
+ var nextMarkup = this._renderedComponent.mountComponent(
1225
1336
  thisID,
1226
1337
  transaction,
1227
1338
  this._mountDepth + 1
@@ -1333,11 +1444,13 @@ var ReactCompositeComponentMixin = {
1333
1444
  // ignore the value of "this" that the user is trying to use, so
1334
1445
  // let's warn.
1335
1446
  if (newThis !== component && newThis !== null) {
1447
+ monitorCodeUse('react_bind_warning', { component: componentName });
1336
1448
  console.warn(
1337
1449
  'bind(): React component methods may only be bound to the ' +
1338
1450
  'component instance. See ' + componentName
1339
1451
  );
1340
1452
  } else if (!args.length) {
1453
+ monitorCodeUse('react_bind_warning', { component: componentName });
1341
1454
  console.warn(
1342
1455
  'bind(): You are binding a component method to the component. ' +
1343
1456
  'React does this for you automatically in a high-performance ' +
@@ -1400,15 +1513,21 @@ var ReactCompositeComponent = {
1400
1513
  Constructor.prototype = new ReactCompositeComponentBase();
1401
1514
  Constructor.prototype.constructor = Constructor;
1402
1515
 
1516
+ var DescriptorConstructor = Constructor;
1517
+
1403
1518
  var ConvenienceConstructor = function(props, children) {
1404
- var instance = new Constructor();
1405
- instance.construct.apply(instance, arguments);
1406
- return instance;
1519
+ var descriptor = new DescriptorConstructor();
1520
+ descriptor.construct.apply(descriptor, arguments);
1521
+ return descriptor;
1407
1522
  };
1408
1523
  ConvenienceConstructor.componentConstructor = Constructor;
1409
1524
  Constructor.ConvenienceConstructor = ConvenienceConstructor;
1410
1525
  ConvenienceConstructor.originalSpec = spec;
1411
1526
 
1527
+ injectedMixins.forEach(
1528
+ mixSpecIntoComponent.bind(null, ConvenienceConstructor)
1529
+ );
1530
+
1412
1531
  mixSpecIntoComponent(ConvenienceConstructor, spec);
1413
1532
 
1414
1533
  ("production" !== process.env.NODE_ENV ? invariant(
@@ -1418,6 +1537,10 @@ var ReactCompositeComponent = {
1418
1537
 
1419
1538
  if ("production" !== process.env.NODE_ENV) {
1420
1539
  if (Constructor.prototype.componentShouldUpdate) {
1540
+ monitorCodeUse(
1541
+ 'react_component_should_update_warning',
1542
+ { component: spec.displayName }
1543
+ );
1421
1544
  console.warn(
1422
1545
  (spec.displayName || 'A component') + ' has a method called ' +
1423
1546
  'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' +
@@ -1443,13 +1566,22 @@ var ReactCompositeComponent = {
1443
1566
  }
1444
1567
 
1445
1568
  if ("production" !== process.env.NODE_ENV) {
1446
- Constructor.prototype = createMountWarningMembrane(Constructor.prototype);
1569
+ // In DEV the convenience constructor generates a proxy to another
1570
+ // instance around it to warn about access to properties on the
1571
+ // descriptor.
1572
+ DescriptorConstructor = createDescriptorProxy(Constructor);
1447
1573
  }
1448
1574
 
1449
1575
  return ConvenienceConstructor;
1450
1576
  },
1451
1577
 
1452
- isValidClass: isValidClass
1578
+ isValidClass: isValidClass,
1579
+
1580
+ injection: {
1581
+ injectMixin: function(mixin) {
1582
+ injectedMixins.push(mixin);
1583
+ }
1584
+ }
1453
1585
  };
1454
1586
 
1455
1587
  module.exports = ReactCompositeComponent;