UNPKG

styled-components

Version:

**This is a work in progress** based off of [this demo](https://github.com/geelen/css-components-demo).

216 lines (185 loc) 7.17 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /* high performance StyleSheet for css-in-js systems - uses multiple style tags behind the scenes for millions of rules - uses `insertRule` for appending in production for *much* faster performance - 'polyfills' on server side // usage import StyleSheet from 'glamor/lib/sheet' let styleSheet = new StyleSheet() styleSheet.inject() - 'injects' the stylesheet into the page (or into memory if on server) styleSheet.insert('#box { border: 1px solid red; }') - appends a css rule into the stylesheet styleSheet.flush() - empties the stylesheet of all its contents */ function last(arr) { return arr[arr.length - 1]; } function sheetForTag(tag) { for (var i = 0; i < document.styleSheets.length; i++) { if (document.styleSheets[i].ownerNode === tag) { return document.styleSheets[i]; } } } var isBrowser = typeof document !== 'undefined'; var isDev = function (x) { return x === 'development' || !x; }(process.env.NODE_ENV); var isTest = process.env.NODE_ENV === 'test'; var oldIE = function () { if (isBrowser) { var div = document.createElement('div'); div.innerHTML = '<!--[if lt IE 10]><i></i><![endif]-->'; return div.getElementsByTagName('i').length === 1; } }(); function makeStyleTag() { var tag = document.createElement('style'); tag.type = 'text/css'; tag.appendChild(document.createTextNode('')); (document.head || document.getElementsByTagName('head')[0]).appendChild(tag); return tag; } var StyleSheet = exports.StyleSheet = function () { function StyleSheet() { var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var _ref$speedy = _ref.speedy; var speedy = _ref$speedy === undefined ? !isDev && !isTest : _ref$speedy; var _ref$maxLength = _ref.maxLength; var maxLength = _ref$maxLength === undefined ? isBrowser && oldIE ? 4000 : 65000 : _ref$maxLength; _classCallCheck(this, StyleSheet); this.isSpeedy = speedy; // the big drawback here is that the css won't be editable in devtools this.sheet = undefined; this.tags = []; this.maxLength = maxLength; this.ctr = 0; } _createClass(StyleSheet, [{ key: 'inject', value: function inject() { var _this = this; if (this.injected) { throw new Error('already injected stylesheet!'); } if (isBrowser) { // this section is just weird alchemy I found online off many sources this.tags[0] = makeStyleTag(); // this weirdness brought to you by firefox this.sheet = sheetForTag(this.tags[0]); } else { // server side 'polyfill'. just enough behavior to be useful. this.sheet = { cssRules: [], insertRule: function insertRule(rule) { // enough 'spec compliance' to be able to extract the rules later // in other words, just the cssText field var serverRule = { cssText: rule }; _this.sheet.cssRules.push(serverRule); return { serverRule: serverRule, appendRule: function appendRule(newCss) { return serverRule.cssText += newCss; } }; } }; } this.injected = true; } }, { key: 'speedy', value: function speedy(bool) { if (this.ctr !== 0) { throw new Error('cannot change speedy mode after inserting any rule to sheet. Either call speedy(' + bool + ') earlier in your app, or call flush() before speedy(' + bool + ')'); } this.isSpeedy = !!bool; } }, { key: '_insert', value: function _insert(rule) { // this weirdness for perf, and chrome's weird bug // https://stackoverflow.com/questions/20007992/chrome-suddenly-stopped-accepting-insertrule try { this.sheet.insertRule(rule, this.sheet.cssRules.length); // todo - correct index here } catch (e) { if (isDev) { // might need beter dx for this console.warn('whoops, illegal rule inserted', rule); //eslint-disable-line no-console } } } }, { key: 'insert', value: function insert(rule) { var _this2 = this; var insertedRule = void 0; if (isBrowser) { // this is the ultrafast version, works across browsers if (this.isSpeedy && this.sheet.insertRule) { this._insert(rule); } // more browser weirdness. I don't even know else if (this.tags.length > 0 && last(this.tags).styleSheet) { last(this.tags).styleSheet.cssText += rule; } else { (function () { var textNode = document.createTextNode(rule); last(_this2.tags).appendChild(textNode); insertedRule = { textNode: textNode, appendRule: function appendRule(newCss) { return textNode.appendData(newCss); } }; if (!_this2.isSpeedy) { // sighhh _this2.sheet = sheetForTag(last(_this2.tags)); } })(); } } else { // server side is pretty simple insertedRule = this.sheet.insertRule(rule); } this.ctr++; if (isBrowser && this.ctr % this.maxLength === 0) { this.tags.push(makeStyleTag()); this.sheet = sheetForTag(last(this.tags)); } return insertedRule; } }, { key: 'flush', value: function flush() { if (isBrowser) { this.tags.forEach(function (tag) { return tag.parentNode.removeChild(tag); }); this.tags = []; this.sheet = null; this.ctr = 0; // todo - look for remnants in document.styleSheets } else { // simpler on server this.sheet.cssRules = []; } this.injected = false; } }, { key: 'rules', value: function rules() { if (!isBrowser) { return this.sheet.cssRules; } var arr = []; this.tags.forEach(function (tag) { return arr.splice.apply(arr, [arr.length, 0].concat(_toConsumableArray(Array.from(sheetForTag(tag).cssRules)))); }); return arr; } }]); return StyleSheet; }();