styled-components 2.1.1 → 2.2.1

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 (85) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/CODE_OF_CONDUCT.md +1 -1
  3. package/README.md +12 -67
  4. package/dist/styled-components.es.js +273 -110
  5. package/dist/styled-components.js +325 -119
  6. package/dist/styled-components.min.js +2 -2
  7. package/lib/hoc/withTheme.js +13 -7
  8. package/lib/models/BrowserStyleSheet.js +11 -0
  9. package/lib/models/ComponentStyle.js +45 -2
  10. package/lib/models/InlineStyle.js +1 -1
  11. package/lib/models/ServerStyleSheet.js +33 -17
  12. package/lib/models/StyleSheet.js +9 -0
  13. package/lib/models/StyledComponent.js +82 -38
  14. package/lib/models/StyledNativeComponent.js +31 -15
  15. package/lib/models/ThemeProvider.js +44 -12
  16. package/lib/native/index.js +1 -1
  17. package/lib/test/utils.js +5 -2
  18. package/lib/utils/create-broadcast.js +34 -24
  19. package/lib/utils/domElements.js +1 -1
  20. package/lib/utils/flatten.js +4 -1
  21. package/lib/utils/generateAlphabeticName.js +1 -1
  22. package/lib/utils/nonce.js +10 -0
  23. package/lib/utils/once.js +17 -0
  24. package/package.json +10 -10
  25. package/src/hoc/withTheme.js +14 -7
  26. package/src/models/BrowserStyleSheet.js +8 -0
  27. package/src/models/ComponentStyle.js +42 -2
  28. package/src/models/InlineStyle.js +1 -1
  29. package/src/models/ServerStyleSheet.js +27 -12
  30. package/src/models/StyleSheet.js +9 -0
  31. package/src/models/StyledComponent.js +81 -26
  32. package/src/models/StyledNativeComponent.js +30 -10
  33. package/src/models/ThemeProvider.js +38 -9
  34. package/src/models/test/ThemeProvider.test.js +7 -8
  35. package/src/native/index.js +1 -1
  36. package/src/native/test/native.test.js +14 -0
  37. package/src/test/__snapshots__/ssr.test.js.snap +147 -0
  38. package/src/test/expanded-api.test.js +24 -0
  39. package/src/test/props.test.js +14 -3
  40. package/src/test/ssr.test.js +90 -123
  41. package/src/test/styles.test.js +52 -0
  42. package/src/test/utils.js +5 -2
  43. package/src/utils/create-broadcast.js +31 -17
  44. package/src/utils/domElements.js +1 -0
  45. package/src/utils/flatten.js +16 -6
  46. package/src/utils/generateAlphabeticName.js +1 -1
  47. package/src/utils/nonce.js +6 -0
  48. package/src/utils/once.js +12 -0
  49. package/typings/styled-components.d.ts +15 -21
  50. package/typings/tests/issue1068.tsx +226 -0
  51. package/typings/tests/main-test.tsx +1 -1
  52. package/typings/tests/string-tags-test.tsx +62 -0
  53. package/typings/tests/themed-tests/issue1068.tsx +226 -0
  54. package/typings/tests/themed-tests/mytheme-styled-components.tsx +1 -1
  55. package/typings/tests/themed-tests/with-theme-test.tsx +2 -1
  56. package/typings/tests/with-theme-test.tsx +17 -0
  57. package/lib/constructors/test/injectGlobal.test.js +0 -63
  58. package/lib/constructors/test/keyframes.test.js +0 -48
  59. package/lib/constructors/test/styled.test.js +0 -19
  60. package/lib/models/AbstractStyledComponent.js +0 -43
  61. package/lib/models/test/ThemeProvider.test.js +0 -200
  62. package/lib/native/test/native.test.js +0 -290
  63. package/lib/no-parser/test/basic.test.js +0 -46
  64. package/lib/no-parser/test/flatten.test.js +0 -125
  65. package/lib/no-parser/test/keyframes.test.js +0 -45
  66. package/lib/primitives/test/primitives.test.js +0 -289
  67. package/lib/test/attrs.test.js +0 -158
  68. package/lib/test/basic.test.js +0 -267
  69. package/lib/test/css.test.js +0 -43
  70. package/lib/test/expanded-api.test.js +0 -90
  71. package/lib/test/extending.test.js +0 -198
  72. package/lib/test/overriding.test.js +0 -35
  73. package/lib/test/props.test.js +0 -38
  74. package/lib/test/rehydration.test.js +0 -306
  75. package/lib/test/ssr.test.js +0 -187
  76. package/lib/test/styles.test.js +0 -146
  77. package/lib/test/theme.test.js +0 -497
  78. package/lib/test/warnTooManyClasses.test.js +0 -71
  79. package/lib/utils/test/extractCompsFromCSS.test.js +0 -46
  80. package/lib/utils/test/flatten.test.js +0 -109
  81. package/lib/utils/test/generateAlphabeticName.test.js +0 -14
  82. package/lib/utils/test/interleave.test.js +0 -22
  83. package/lib/utils/test/validAttr.test.js +0 -560
  84. package/src/models/AbstractStyledComponent.js +0 -21
  85. package/typings/tags.d.ts +0 -137
@@ -64,7 +64,10 @@ var hyphenateStyleName_1 = hyphenateStyleName;
64
64
 
65
65
  //
66
66
  var objToCss = function objToCss(obj, prevKey) {
67
- var css = Object.keys(obj).map(function (key) {
67
+ var css = Object.keys(obj).filter(function (key) {
68
+ var chunk = obj[key];
69
+ return chunk !== undefined && chunk !== null && chunk !== false && chunk !== '';
70
+ }).map(function (key) {
68
71
  if (isPlainObject(obj[key])) return objToCss(obj[key], key);
69
72
  return hyphenateStyleName_1(key) + ': ' + obj[key] + ';';
70
73
  }).join(' ');
@@ -120,7 +123,7 @@ var generateAlphabeticName = function generateAlphabeticName(code) {
120
123
  var name = '';
121
124
  var x = void 0;
122
125
 
123
- for (x = code; x > charsLength; x = Math.floor(x / chars.length)) {
126
+ for (x = code; x > charsLength; x = Math.floor(x / charsLength)) {
124
127
  name = chars[x % charsLength] + name;
125
128
  }
126
129
 
@@ -165,6 +168,13 @@ var extractCompsFromCSS = (function (maybeCSS) {
165
168
  });
166
169
  });
167
170
 
171
+ //
172
+ /* eslint-disable camelcase, no-undef */
173
+
174
+ var getNonce = (function () {
175
+ return typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null;
176
+ });
177
+
168
178
  var classCallCheck = function (instance, Constructor) {
169
179
  if (!(instance instanceof Constructor)) {
170
180
  throw new TypeError("Cannot call a class as a function");
@@ -256,6 +266,7 @@ var possibleConstructorReturn = function (self, call) {
256
266
  };
257
267
 
258
268
  //
269
+ /* eslint-disable no-underscore-dangle */
259
270
  /*
260
271
  * Browser Style Sheet with Rehydration
261
272
  *
@@ -319,6 +330,12 @@ var BrowserTag = function () {
319
330
  var existingNames = this.el.getAttribute(SC_ATTR);
320
331
  this.el.setAttribute(SC_ATTR, existingNames ? existingNames + ' ' + name : name);
321
332
  }
333
+
334
+ var nonce = getNonce();
335
+
336
+ if (nonce) {
337
+ this.el.setAttribute('nonce', nonce);
338
+ }
322
339
  };
323
340
 
324
341
  BrowserTag.prototype.toHTML = function toHTML() {
@@ -422,6 +439,7 @@ var StyleSheet = function () {
422
439
  classCallCheck(this, StyleSheet);
423
440
  this.hashes = {};
424
441
  this.deferredInjections = {};
442
+ this.stylesCacheable = typeof document !== 'undefined';
425
443
 
426
444
  this.tagConstructor = tagConstructor;
427
445
  this.tags = tags;
@@ -429,6 +447,15 @@ var StyleSheet = function () {
429
447
  this.constructComponentTagMap();
430
448
  }
431
449
 
450
+ // helper for `ComponentStyle` to know when it cache static styles.
451
+ // staticly styled-component can not safely cache styles on the server
452
+ // without all `ComponentStyle` instances saving a reference to the
453
+ // the styleSheet instance they last rendered with,
454
+ // or listening to creation / reset events. otherwise you might create
455
+ // a component with one stylesheet and render it another api response
456
+ // with another, losing styles on from your server-side render.
457
+
458
+
432
459
  StyleSheet.prototype.constructComponentTagMap = function constructComponentTagMap() {
433
460
  var _this = this;
434
461
 
@@ -600,6 +627,7 @@ StyleSheetManager.propTypes = {
600
627
  };
601
628
 
602
629
  //
630
+ /* eslint-disable no-underscore-dangle */
603
631
  var ServerTag = function () {
604
632
  function ServerTag(isLocal) {
605
633
  classCallCheck(this, ServerTag);
@@ -620,6 +648,14 @@ var ServerTag = function () {
620
648
  this.size += 1;
621
649
  };
622
650
 
651
+ ServerTag.prototype.concatenateCSS = function concatenateCSS() {
652
+ var _this = this;
653
+
654
+ return Object.keys(this.components).reduce(function (styles, k) {
655
+ return styles + _this.components[k].css;
656
+ }, '');
657
+ };
658
+
623
659
  ServerTag.prototype.inject = function inject(componentId, css, name) {
624
660
  var comp = this.components[componentId];
625
661
 
@@ -632,40 +668,42 @@ var ServerTag = function () {
632
668
  };
633
669
 
634
670
  ServerTag.prototype.toHTML = function toHTML() {
635
- var _this = this;
671
+ var attrs = ['type="text/css"', SC_ATTR + '="' + this.names.join(' ') + '"', LOCAL_ATTR + '="' + (this.isLocal ? 'true' : 'false') + '"'];
636
672
 
637
- var namesAttr = SC_ATTR + '="' + this.names.join(' ') + '"';
638
- var localAttr = LOCAL_ATTR + '="' + (this.isLocal ? 'true' : 'false') + '"';
639
- var css = Object.keys(this.components).map(function (key) {
640
- return _this.components[key].css;
641
- }).join('');
673
+ var nonce = getNonce();
642
674
 
643
- return '<style type="text/css" ' + namesAttr + ' ' + localAttr + '>\n' + css + '\n</style>';
675
+ if (nonce) {
676
+ attrs.push('nonce="' + nonce + '"');
677
+ }
678
+
679
+ return '<style ' + attrs.join(' ') + '>' + this.concatenateCSS() + '</style>';
644
680
  };
645
681
 
646
682
  ServerTag.prototype.toReactElement = function toReactElement(key) {
647
- var _attributes,
648
- _this2 = this;
683
+ var _attrs;
649
684
 
650
- var attributes = (_attributes = {}, _attributes[SC_ATTR] = this.names.join(' '), _attributes[LOCAL_ATTR] = this.isLocal.toString(), _attributes);
651
- var css = Object.keys(this.components).map(function (k) {
652
- return _this2.components[k].css;
653
- }).join('');
685
+ var attrs = (_attrs = {}, _attrs[SC_ATTR] = this.names.join(' '), _attrs[LOCAL_ATTR] = this.isLocal.toString(), _attrs);
686
+
687
+ var nonce = getNonce();
688
+
689
+ if (nonce) {
690
+ attrs.nonce = nonce;
691
+ }
654
692
 
655
693
  return React.createElement('style', _extends({
656
- key: key, type: 'text/css' }, attributes, {
657
- dangerouslySetInnerHTML: { __html: css }
694
+ key: key, type: 'text/css' }, attrs, {
695
+ dangerouslySetInnerHTML: { __html: this.concatenateCSS() }
658
696
  }));
659
697
  };
660
698
 
661
699
  ServerTag.prototype.clone = function clone() {
662
- var _this3 = this;
700
+ var _this2 = this;
663
701
 
664
702
  var copy = new ServerTag(this.isLocal);
665
703
  copy.names = [].concat(this.names);
666
704
  copy.size = this.size;
667
705
  copy.components = Object.keys(this.components).reduce(function (acc, key) {
668
- acc[key] = _extends({}, _this3.components[key]); // eslint-disable-line no-param-reassign
706
+ acc[key] = _extends({}, _this2.components[key]); // eslint-disable-line no-param-reassign
669
707
  return acc;
670
708
  }, {});
671
709
 
@@ -1361,32 +1399,54 @@ function getComponentName(target) {
1361
1399
  * @see https://github.com/ReactTraining/react-broadcast
1362
1400
  */
1363
1401
 
1364
- var createBroadcast = function createBroadcast(initialValue) {
1365
- var listeners = [];
1366
- var currentValue = initialValue;
1402
+ var createBroadcast = function createBroadcast(initialState) {
1403
+ var listeners = {};
1404
+ var id = 0;
1405
+ var state = initialState;
1367
1406
 
1368
- return {
1369
- publish: function publish(value) {
1370
- currentValue = value;
1371
- listeners.forEach(function (listener) {
1372
- return listener(currentValue);
1373
- });
1374
- },
1375
- subscribe: function subscribe(listener) {
1376
- listeners.push(listener);
1407
+ function publish(nextState) {
1408
+ state = nextState;
1377
1409
 
1378
- // Publish to this subscriber once immediately.
1379
- listener(currentValue);
1410
+ // eslint-disable-next-line guard-for-in, no-restricted-syntax
1411
+ for (var key in listeners) {
1412
+ var listener = listeners[key];
1413
+ if (listener === undefined) {
1414
+ // eslint-disable-next-line no-continue
1415
+ continue;
1416
+ }
1380
1417
 
1381
- return function () {
1382
- listeners = listeners.filter(function (item) {
1383
- return item !== listener;
1384
- });
1385
- };
1418
+ listener(state);
1386
1419
  }
1387
- };
1420
+ }
1421
+
1422
+ function subscribe(listener) {
1423
+ var currentId = id;
1424
+ listeners[currentId] = listener;
1425
+ id += 1;
1426
+ listener(state);
1427
+ return currentId;
1428
+ }
1429
+
1430
+ function unsubscribe(unsubID) {
1431
+ listeners[unsubID] = undefined;
1432
+ }
1433
+
1434
+ return { publish: publish, subscribe: subscribe, unsubscribe: unsubscribe };
1388
1435
  };
1389
1436
 
1437
+ //
1438
+ // Helper to call a given function, only once
1439
+ var once = (function (cb) {
1440
+ var called = false;
1441
+
1442
+ return function () {
1443
+ if (!called) {
1444
+ called = true;
1445
+ cb();
1446
+ }
1447
+ };
1448
+ });
1449
+
1390
1450
  var _ThemeProvider$childC;
1391
1451
  var _ThemeProvider$contex;
1392
1452
 
@@ -1394,7 +1454,18 @@ var _ThemeProvider$contex;
1394
1454
  /* globals React$Element */
1395
1455
  // NOTE: DO NOT CHANGE, changing this is a semver major change!
1396
1456
  var CHANNEL = '__styled-components__';
1457
+ var CHANNEL_NEXT = CHANNEL + 'next__';
1397
1458
 
1459
+ var CONTEXT_CHANNEL_SHAPE = PropTypes.shape({
1460
+ getTheme: PropTypes.func,
1461
+ subscribe: PropTypes.func,
1462
+ unsubscribe: PropTypes.func
1463
+ });
1464
+
1465
+ var warnChannelDeprecated = once(function () {
1466
+ // eslint-disable-next-line no-console
1467
+ console.error('Warning: Usage of `context.' + CHANNEL + '` as a function is deprecated. It will be replaced with the object on `.context.' + CHANNEL_NEXT + '` in a future version.');
1468
+ });
1398
1469
  /**
1399
1470
  * Provide a theme to an entire react component tree via context and event listeners (have to do
1400
1471
  * both context and event emitter as pure components block context updates)
@@ -1408,6 +1479,8 @@ var ThemeProvider = function (_Component) {
1408
1479
 
1409
1480
  var _this = possibleConstructorReturn(this, _Component.call(this));
1410
1481
 
1482
+ _this.unsubscribeToOuterId = -1;
1483
+
1411
1484
  _this.getTheme = _this.getTheme.bind(_this);
1412
1485
  return _this;
1413
1486
  }
@@ -1417,9 +1490,9 @@ var ThemeProvider = function (_Component) {
1417
1490
 
1418
1491
  // If there is a ThemeProvider wrapper anywhere around this theme provider, merge this theme
1419
1492
  // with the outer theme
1420
- if (this.context[CHANNEL]) {
1421
- var subscribe = this.context[CHANNEL];
1422
- this.unsubscribeToOuter = subscribe(function (theme) {
1493
+ var outerContext = this.context[CHANNEL_NEXT];
1494
+ if (outerContext !== undefined) {
1495
+ this.unsubscribeToOuterId = outerContext.subscribe(function (theme) {
1423
1496
  _this2.outerTheme = theme;
1424
1497
  });
1425
1498
  }
@@ -1427,9 +1500,22 @@ var ThemeProvider = function (_Component) {
1427
1500
  };
1428
1501
 
1429
1502
  ThemeProvider.prototype.getChildContext = function getChildContext() {
1430
- var _babelHelpers$extends;
1431
-
1432
- return _extends({}, this.context, (_babelHelpers$extends = {}, _babelHelpers$extends[CHANNEL] = this.broadcast.subscribe, _babelHelpers$extends));
1503
+ var _this3 = this,
1504
+ _babelHelpers$extends;
1505
+
1506
+ return _extends({}, this.context, (_babelHelpers$extends = {}, _babelHelpers$extends[CHANNEL_NEXT] = {
1507
+ getTheme: this.getTheme,
1508
+ subscribe: this.broadcast.subscribe,
1509
+ unsubscribe: this.broadcast.unsubscribe
1510
+ }, _babelHelpers$extends[CHANNEL] = function (subscriber) {
1511
+ warnChannelDeprecated();
1512
+
1513
+ // Patch the old `subscribe` provide via `CHANNEL` for older clients.
1514
+ var unsubscribeId = _this3.broadcast.subscribe(subscriber);
1515
+ return function () {
1516
+ return _this3.broadcast.unsubscribe(unsubscribeId);
1517
+ };
1518
+ }, _babelHelpers$extends));
1433
1519
  };
1434
1520
 
1435
1521
  ThemeProvider.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
@@ -1437,8 +1523,8 @@ var ThemeProvider = function (_Component) {
1437
1523
  };
1438
1524
 
1439
1525
  ThemeProvider.prototype.componentWillUnmount = function componentWillUnmount() {
1440
- if (this.context[CHANNEL]) {
1441
- this.unsubscribeToOuter();
1526
+ if (this.unsubscribeToOuterId !== -1) {
1527
+ this.context[CHANNEL_NEXT].unsubscribe(this.unsubscribeToOuterId);
1442
1528
  }
1443
1529
  };
1444
1530
 
@@ -1470,34 +1556,22 @@ var ThemeProvider = function (_Component) {
1470
1556
  return ThemeProvider;
1471
1557
  }(Component);
1472
1558
 
1473
- ThemeProvider.childContextTypes = (_ThemeProvider$childC = {}, _ThemeProvider$childC[CHANNEL] = PropTypes.func.isRequired, _ThemeProvider$childC);
1474
- ThemeProvider.contextTypes = (_ThemeProvider$contex = {}, _ThemeProvider$contex[CHANNEL] = PropTypes.func, _ThemeProvider$contex);
1475
-
1476
- var _AbstractStyledCompon;
1477
-
1478
- //
1479
- var AbstractStyledComponent = function (_Component) {
1480
- inherits(AbstractStyledComponent, _Component);
1481
-
1482
- function AbstractStyledComponent() {
1483
- classCallCheck(this, AbstractStyledComponent);
1484
- return possibleConstructorReturn(this, _Component.apply(this, arguments));
1485
- }
1486
-
1487
- return AbstractStyledComponent;
1488
- }(Component);
1489
-
1490
- AbstractStyledComponent.contextTypes = (_AbstractStyledCompon = {}, _AbstractStyledCompon[CHANNEL] = PropTypes.func, _AbstractStyledCompon[CONTEXT_KEY] = PropTypes.instanceOf(StyleSheet), _AbstractStyledCompon);
1559
+ ThemeProvider.childContextTypes = (_ThemeProvider$childC = {}, _ThemeProvider$childC[CHANNEL] = PropTypes.func, _ThemeProvider$childC[CHANNEL_NEXT] = CONTEXT_CHANNEL_SHAPE, _ThemeProvider$childC);
1560
+ ThemeProvider.contextTypes = (_ThemeProvider$contex = {}, _ThemeProvider$contex[CHANNEL_NEXT] = CONTEXT_CHANNEL_SHAPE, _ThemeProvider$contex);
1491
1561
 
1492
1562
  //
1493
1563
 
1494
1564
  var escapeRegex = /[[\].#*$><+~=|^:(),"'`]/g;
1495
1565
  var multiDashRegex = /--+/g;
1496
1566
 
1567
+ // HACK for generating all static styles without needing to allocate
1568
+ // an empty execution context every single time...
1569
+ var STATIC_EXECUTION_CONTEXT = {};
1570
+
1497
1571
  var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1498
1572
  /* We depend on components having unique IDs */
1499
1573
  var identifiers = {};
1500
- var generateId = function generateId(_displayName) {
1574
+ var generateId = function generateId(_displayName, parentComponentId) {
1501
1575
  var displayName = typeof _displayName !== 'string' ? 'sc' : _displayName.replace(escapeRegex, '-') // Replace all possible CSS selectors
1502
1576
  .replace(multiDashRegex, '-'); // Replace multiple -- with single -
1503
1577
 
@@ -1505,11 +1579,12 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1505
1579
  identifiers[displayName] = nr;
1506
1580
 
1507
1581
  var hash = ComponentStyle.generateName(displayName + nr);
1508
- return displayName + '-' + hash;
1582
+ var componentId = displayName + '-' + hash;
1583
+ return parentComponentId !== undefined ? parentComponentId + '-' + componentId : componentId;
1509
1584
  };
1510
1585
 
1511
- var BaseStyledComponent = function (_AbstractStyledCompon) {
1512
- inherits(BaseStyledComponent, _AbstractStyledCompon);
1586
+ var BaseStyledComponent = function (_Component) {
1587
+ inherits(BaseStyledComponent, _Component);
1513
1588
 
1514
1589
  function BaseStyledComponent() {
1515
1590
  var _temp, _this, _ret;
@@ -1520,12 +1595,18 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1520
1595
  args[_key] = arguments[_key];
1521
1596
  }
1522
1597
 
1523
- return _ret = (_temp = (_this = possibleConstructorReturn(this, _AbstractStyledCompon.call.apply(_AbstractStyledCompon, [this].concat(args))), _this), _this.attrs = {}, _this.state = {
1598
+ return _ret = (_temp = (_this = possibleConstructorReturn(this, _Component.call.apply(_Component, [this].concat(args))), _this), _this.attrs = {}, _this.state = {
1524
1599
  theme: null,
1525
1600
  generatedClassName: ''
1526
- }, _temp), possibleConstructorReturn(_this, _ret);
1601
+ }, _this.unsubscribeId = -1, _temp), possibleConstructorReturn(_this, _ret);
1527
1602
  }
1528
1603
 
1604
+ BaseStyledComponent.prototype.unsubscribeFromContext = function unsubscribeFromContext() {
1605
+ if (this.unsubscribeId !== -1) {
1606
+ this.context[CHANNEL_NEXT].unsubscribe(this.unsubscribeId);
1607
+ }
1608
+ };
1609
+
1529
1610
  BaseStyledComponent.prototype.buildExecutionContext = function buildExecutionContext(theme, props) {
1530
1611
  var attrs = this.constructor.attrs;
1531
1612
 
@@ -1546,55 +1627,86 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1546
1627
 
1547
1628
  BaseStyledComponent.prototype.generateAndInjectStyles = function generateAndInjectStyles(theme, props) {
1548
1629
  var _constructor = this.constructor,
1630
+ attrs = _constructor.attrs,
1549
1631
  componentStyle = _constructor.componentStyle,
1550
1632
  warnTooManyClasses = _constructor.warnTooManyClasses;
1551
1633
 
1552
- var executionContext = this.buildExecutionContext(theme, props);
1553
1634
  var styleSheet = this.context[CONTEXT_KEY] || StyleSheet.instance;
1554
- var className = componentStyle.generateAndInjectStyles(executionContext, styleSheet);
1555
1635
 
1556
- if (warnTooManyClasses !== undefined) warnTooManyClasses(className);
1636
+ // staticaly styled-components don't need to build an execution context object,
1637
+ // and shouldn't be increasing the number of class names
1638
+ if (componentStyle.isStatic && attrs === undefined) {
1639
+ return componentStyle.generateAndInjectStyles(STATIC_EXECUTION_CONTEXT, styleSheet);
1640
+ } else {
1641
+ var executionContext = this.buildExecutionContext(theme, props);
1642
+ var className = componentStyle.generateAndInjectStyles(executionContext, styleSheet);
1643
+
1644
+ if (warnTooManyClasses !== undefined) warnTooManyClasses(className);
1557
1645
 
1558
- return className;
1646
+ return className;
1647
+ }
1559
1648
  };
1560
1649
 
1561
1650
  BaseStyledComponent.prototype.componentWillMount = function componentWillMount() {
1562
1651
  var _this2 = this;
1563
1652
 
1564
- // If there is a theme in the context, subscribe to the event emitter. This
1565
- // is necessary due to pure components blocking context updates, this circumvents
1566
- // that by updating when an event is emitted
1567
- if (this.context[CHANNEL]) {
1568
- var subscribe = this.context[CHANNEL];
1569
- this.unsubscribe = subscribe(function (nextTheme) {
1653
+ var componentStyle = this.constructor.componentStyle;
1654
+
1655
+ var styledContext = this.context[CHANNEL_NEXT];
1656
+
1657
+ // If this is a staticaly-styled component, we don't need to the theme
1658
+ // to generate or build styles.
1659
+ if (componentStyle.isStatic) {
1660
+ var generatedClassName = this.generateAndInjectStyles(STATIC_EXECUTION_CONTEXT, this.props);
1661
+ this.setState({ generatedClassName: generatedClassName });
1662
+ // If there is a theme in the context, subscribe to the event emitter. This
1663
+ // is necessary due to pure components blocking context updates, this circumvents
1664
+ // that by updating when an event is emitted
1665
+ } else if (styledContext !== undefined) {
1666
+ var subscribe = styledContext.subscribe;
1667
+
1668
+ this.unsubscribeId = subscribe(function (nextTheme) {
1570
1669
  // This will be called once immediately
1571
1670
 
1572
1671
  // Props should take precedence over ThemeProvider, which should take precedence over
1573
1672
  // defaultProps, but React automatically puts defaultProps on props.
1574
1673
  var defaultProps = _this2.constructor.defaultProps;
1674
+ /* eslint-disable react/prop-types */
1575
1675
 
1576
1676
  var isDefaultTheme = defaultProps && _this2.props.theme === defaultProps.theme;
1577
1677
  var theme = _this2.props.theme && !isDefaultTheme ? _this2.props.theme : nextTheme;
1678
+ /* eslint-enable */
1578
1679
  var generatedClassName = _this2.generateAndInjectStyles(theme, _this2.props);
1579
1680
  _this2.setState({ theme: theme, generatedClassName: generatedClassName });
1580
1681
  });
1581
1682
  } else {
1683
+ // eslint-disable-next-line react/prop-types
1582
1684
  var theme = this.props.theme || {};
1583
- var generatedClassName = this.generateAndInjectStyles(theme, this.props);
1584
- this.setState({ theme: theme, generatedClassName: generatedClassName });
1685
+ var _generatedClassName = this.generateAndInjectStyles(theme, this.props);
1686
+ this.setState({ theme: theme, generatedClassName: _generatedClassName });
1585
1687
  }
1586
1688
  };
1587
1689
 
1588
1690
  BaseStyledComponent.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
1589
1691
  var _this3 = this;
1590
1692
 
1693
+ // If this is a staticaly-styled component, we don't need to listen to
1694
+ // props changes to update styles
1695
+ var componentStyle = this.constructor.componentStyle;
1696
+
1697
+ if (componentStyle.isStatic) {
1698
+ return;
1699
+ }
1700
+
1591
1701
  this.setState(function (oldState) {
1592
1702
  // Props should take precedence over ThemeProvider, which should take precedence over
1593
1703
  // defaultProps, but React automatically puts defaultProps on props.
1594
1704
  var defaultProps = _this3.constructor.defaultProps;
1705
+ /* eslint-disable react/prop-types */
1595
1706
 
1596
1707
  var isDefaultTheme = defaultProps && nextProps.theme === defaultProps.theme;
1597
1708
  var theme = nextProps.theme && !isDefaultTheme ? nextProps.theme : oldState.theme;
1709
+ /* eslint-enable */
1598
1710
  var generatedClassName = _this3.generateAndInjectStyles(theme, nextProps);
1599
1711
 
1600
1712
  return { theme: theme, generatedClassName: generatedClassName };
@@ -1602,14 +1714,13 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1602
1714
  };
1603
1715
 
1604
1716
  BaseStyledComponent.prototype.componentWillUnmount = function componentWillUnmount() {
1605
- if (this.unsubscribe) {
1606
- this.unsubscribe();
1607
- }
1717
+ this.unsubscribeFromContext();
1608
1718
  };
1609
1719
 
1610
1720
  BaseStyledComponent.prototype.render = function render() {
1611
1721
  var _this4 = this;
1612
1722
 
1723
+ // eslint-disable-next-line react/prop-types
1613
1724
  var innerRef = this.props.innerRef;
1614
1725
  var generatedClassName = this.state.generatedClassName;
1615
1726
  var _constructor2 = this.constructor,
@@ -1619,7 +1730,9 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1619
1730
 
1620
1731
  var isTargetTag = isTag(target);
1621
1732
 
1622
- var className = [this.props.className, styledComponentId, this.attrs.className, generatedClassName].filter(Boolean).join(' ');
1733
+ var className = [
1734
+ // eslint-disable-next-line react/prop-types
1735
+ this.props.className, styledComponentId, this.attrs.className, generatedClassName].filter(Boolean).join(' ');
1623
1736
 
1624
1737
  var baseProps = _extends({}, this.attrs, {
1625
1738
  className: className
@@ -1646,7 +1759,7 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1646
1759
  };
1647
1760
 
1648
1761
  return BaseStyledComponent;
1649
- }(AbstractStyledComponent);
1762
+ }(Component);
1650
1763
 
1651
1764
  var createStyledComponent = function createStyledComponent(target, options, rules) {
1652
1765
  var _StyledComponent$cont;
@@ -1654,7 +1767,7 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1654
1767
  var _options$displayName = options.displayName,
1655
1768
  displayName = _options$displayName === undefined ? isTag(target) ? 'styled.' + target : 'Styled(' + getComponentName(target) + ')' : _options$displayName,
1656
1769
  _options$componentId = options.componentId,
1657
- componentId = _options$componentId === undefined ? generateId(options.displayName) : _options$componentId,
1770
+ componentId = _options$componentId === undefined ? generateId(options.displayName, options.parentComponentId) : _options$componentId,
1658
1771
  _options$ParentCompon = options.ParentComponent,
1659
1772
  ParentComponent = _options$ParentCompon === undefined ? BaseStyledComponent : _options$ParentCompon,
1660
1773
  extendingRules = options.rules,
@@ -1664,7 +1777,7 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1664
1777
  var styledComponentId = options.displayName && options.componentId ? options.displayName + '-' + options.componentId : componentId;
1665
1778
 
1666
1779
  var warnTooManyClasses = void 0;
1667
- if (typeof process !== 'undefined' && "development" !== 'production') {
1780
+ if (process.env.NODE_ENV !== 'production') {
1668
1781
  warnTooManyClasses = createWarnTooManyClasses(displayName);
1669
1782
  }
1670
1783
 
@@ -1679,27 +1792,33 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1679
1792
  }
1680
1793
 
1681
1794
  StyledComponent.withComponent = function withComponent(tag) {
1682
- var _ = options.displayName,
1683
- __ = options.componentId,
1684
- optionsToCopy = objectWithoutProperties(options, ['displayName', 'componentId']);
1795
+ var previousComponentId = options.componentId,
1796
+ optionsToCopy = objectWithoutProperties(options, ['componentId']);
1797
+
1798
+
1799
+ var newComponentId = previousComponentId && previousComponentId + '-' + (isTag(tag) ? tag : getComponentName(tag));
1800
+
1801
+ var newOptions = _extends({}, optionsToCopy, {
1802
+ componentId: newComponentId,
1803
+ ParentComponent: StyledComponent
1804
+ });
1685
1805
 
1686
- var newOptions = _extends({}, optionsToCopy, { ParentComponent: StyledComponent });
1687
1806
  return createStyledComponent(tag, newOptions, rules);
1688
1807
  };
1689
1808
 
1690
1809
  createClass(StyledComponent, null, [{
1691
1810
  key: 'extend',
1692
1811
  get: function get$$1() {
1693
- var _ = options.displayName,
1694
- __ = options.componentId,
1695
- rulesFromOptions = options.rules,
1696
- optionsToCopy = objectWithoutProperties(options, ['displayName', 'componentId', 'rules']);
1812
+ var rulesFromOptions = options.rules,
1813
+ parentComponentId = options.componentId,
1814
+ optionsToCopy = objectWithoutProperties(options, ['rules', 'componentId']);
1697
1815
 
1698
1816
 
1699
1817
  var newRules = rulesFromOptions === undefined ? rules : rulesFromOptions.concat(rules);
1700
1818
 
1701
1819
  var newOptions = _extends({}, optionsToCopy, {
1702
1820
  rules: newRules,
1821
+ parentComponentId: parentComponentId,
1703
1822
  ParentComponent: StyledComponent
1704
1823
  });
1705
1824
 
@@ -1709,7 +1828,7 @@ var _StyledComponent = (function (ComponentStyle, constructWithOptions) {
1709
1828
  return StyledComponent;
1710
1829
  }(ParentComponent);
1711
1830
 
1712
- StyledComponent.contextTypes = (_StyledComponent$cont = {}, _StyledComponent$cont[CHANNEL] = PropTypes.func, _StyledComponent$cont[CONTEXT_KEY] = PropTypes.instanceOf(StyleSheet), _StyledComponent$cont);
1831
+ StyledComponent.contextTypes = (_StyledComponent$cont = {}, _StyledComponent$cont[CHANNEL] = PropTypes.func, _StyledComponent$cont[CHANNEL_NEXT] = CONTEXT_CHANNEL_SHAPE, _StyledComponent$cont[CONTEXT_KEY] = PropTypes.instanceOf(StyleSheet), _StyledComponent$cont);
1713
1832
  StyledComponent.displayName = displayName;
1714
1833
  StyledComponent.styledComponentId = styledComponentId;
1715
1834
  StyledComponent.attrs = attrs;
@@ -1790,6 +1909,23 @@ function Umul32(n, m) {
1790
1909
  }
1791
1910
 
1792
1911
  //
1912
+ var isStaticRules = function isStaticRules(rules) {
1913
+ for (var i = 0; i < rules.length; i += 1) {
1914
+ var rule = rules[i];
1915
+
1916
+ // recursive case
1917
+ if (Array.isArray(rule) && !isStaticRules(rule)) {
1918
+ return false;
1919
+ } else if (typeof rule === 'function' && !isStyledComponent(rule)) {
1920
+ // functions are allowed to be static if they're just being
1921
+ // used to get the classname of a nested styled copmonent
1922
+ return false;
1923
+ }
1924
+ }
1925
+
1926
+ return true;
1927
+ };
1928
+
1793
1929
  /*
1794
1930
  ComponentStyle is all the CSS-specific stuff, not
1795
1931
  the React-specific stuff.
@@ -1800,9 +1936,10 @@ var _ComponentStyle = (function (nameGenerator, flatten, stringifyRules) {
1800
1936
  classCallCheck(this, ComponentStyle);
1801
1937
 
1802
1938
  this.rules = rules;
1939
+ this.isStatic = isStaticRules(rules);
1803
1940
  this.componentId = componentId;
1804
1941
  if (!StyleSheet.instance.hasInjectedComponent(this.componentId)) {
1805
- var placeholder = '.' + componentId + ' {}';
1942
+ var placeholder = process.env.NODE_ENV !== 'production' ? '.' + componentId + ' {}' : '';
1806
1943
  StyleSheet.instance.deferredInject(componentId, true, placeholder);
1807
1944
  }
1808
1945
  }
@@ -1815,16 +1952,36 @@ var _ComponentStyle = (function (nameGenerator, flatten, stringifyRules) {
1815
1952
 
1816
1953
 
1817
1954
  ComponentStyle.prototype.generateAndInjectStyles = function generateAndInjectStyles(executionContext, styleSheet) {
1955
+ var isStatic = this.isStatic,
1956
+ lastClassName = this.lastClassName;
1957
+
1958
+ if (isStatic && lastClassName !== undefined) {
1959
+ return lastClassName;
1960
+ }
1961
+
1818
1962
  var flatCSS = flatten(this.rules, executionContext);
1819
1963
  var hash = doHash(this.componentId + flatCSS.join(''));
1820
1964
 
1821
1965
  var existingName = styleSheet.getName(hash);
1822
- if (existingName) return existingName;
1966
+ if (existingName !== undefined) {
1967
+ if (styleSheet.stylesCacheable) {
1968
+ this.lastClassName = existingName;
1969
+ }
1970
+ return existingName;
1971
+ }
1823
1972
 
1824
1973
  var name = nameGenerator(hash);
1825
- if (styleSheet.alreadyInjected(hash, name)) return name;
1974
+ if (styleSheet.stylesCacheable) {
1975
+ this.lastClassName = existingName;
1976
+ }
1977
+ if (styleSheet.alreadyInjected(hash, name)) {
1978
+ return name;
1979
+ }
1826
1980
 
1827
1981
  var css = '\n' + stringifyRules(flatCSS, '.' + name);
1982
+ // NOTE: this can only be set when we inject the class-name.
1983
+ // For some reason, presumably due to how css is stringifyRules behaves in
1984
+ // differently between client and server, styles break.
1828
1985
  styleSheet.inject(this.componentId, true, css, hash, name);
1829
1986
  return name;
1830
1987
  };
@@ -1842,7 +1999,7 @@ var _ComponentStyle = (function (nameGenerator, flatten, stringifyRules) {
1842
1999
  //
1843
2000
  // Thanks to ReactDOMFactories for this handy list!
1844
2001
 
1845
- var domElements = ['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',
2002
+ var domElements = ['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', 'marquee', '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',
1846
2003
 
1847
2004
  // SVG
1848
2005
  'circle', 'clipPath', 'defs', 'ellipse', 'g', 'image', 'line', 'linearGradient', 'mask', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'stop', 'svg', 'text', 'tspan'];
@@ -1965,7 +2122,7 @@ var wrapWithTheme = function wrapWithTheme(Component$$1) {
1965
2122
  args[_key] = arguments[_key];
1966
2123
  }
1967
2124
 
1968
- return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = {}, _temp), possibleConstructorReturn(_this, _ret);
2125
+ return _ret = (_temp = (_this = possibleConstructorReturn(this, _React$Component.call.apply(_React$Component, [this].concat(args))), _this), _this.state = {}, _this.unsubscribeId = -1, _temp), possibleConstructorReturn(_this, _ret);
1969
2126
  }
1970
2127
 
1971
2128
  // NOTE: This is so that isStyledComponent passes for the innerRef unwrapping
@@ -1974,18 +2131,24 @@ var wrapWithTheme = function wrapWithTheme(Component$$1) {
1974
2131
  WithTheme.prototype.componentWillMount = function componentWillMount() {
1975
2132
  var _this2 = this;
1976
2133
 
1977
- if (!this.context[CHANNEL]) {
1978
- throw new Error('[withTheme] Please use ThemeProvider to be able to use withTheme');
2134
+ var styledContext = this.context[CHANNEL_NEXT];
2135
+ if (styledContext === undefined) {
2136
+ // eslint-disable-next-line no-console
2137
+ console.error('[withTheme] Please use ThemeProvider to be able to use withTheme');
2138
+ return;
1979
2139
  }
1980
2140
 
1981
- var subscribe = this.context[CHANNEL];
1982
- this.unsubscribe = subscribe(function (theme) {
2141
+ var subscribe = styledContext.subscribe;
2142
+
2143
+ this.unsubscribeId = subscribe(function (theme) {
1983
2144
  _this2.setState({ theme: theme });
1984
2145
  });
1985
2146
  };
1986
2147
 
1987
2148
  WithTheme.prototype.componentWillUnmount = function componentWillUnmount() {
1988
- if (typeof this.unsubscribe === 'function') this.unsubscribe();
2149
+ if (this.unsubscribeId !== -1) {
2150
+ this.context[CHANNEL_NEXT].unsubscribe(this.unsubscribeId);
2151
+ }
1989
2152
  };
1990
2153
 
1991
2154
  WithTheme.prototype.render = function render() {
@@ -2007,7 +2170,7 @@ var wrapWithTheme = function wrapWithTheme(Component$$1) {
2007
2170
 
2008
2171
  WithTheme.displayName = 'WithTheme(' + componentName + ')';
2009
2172
  WithTheme.styledComponentId = 'withTheme';
2010
- WithTheme.contextTypes = (_WithTheme$contextTyp = {}, _WithTheme$contextTyp[CHANNEL] = PropTypes.func, _WithTheme$contextTyp);
2173
+ WithTheme.contextTypes = (_WithTheme$contextTyp = {}, _WithTheme$contextTyp[CHANNEL] = PropTypes.func, _WithTheme$contextTyp[CHANNEL_NEXT] = CONTEXT_CHANNEL_SHAPE, _WithTheme$contextTyp);
2011
2174
 
2012
2175
 
2013
2176
  return hoistStatics(WithTheme, Component$$1);