diff --git a/bower.json b/bower.json index c280181ee..dff7866c5 100755 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "jsstyles", "description": "Composable and reusable style sheets.", - "version": "2.1.6", + "version": "2.2.0", "author": { "name": "Oleg Slobodskoi", "email": "oleg008@gmail.com" diff --git a/dist/jss.js b/dist/jss.js index 2acd097f8..f2250b2b6 100755 --- a/dist/jss.js +++ b/dist/jss.js @@ -106,13 +106,14 @@ PluginsRegistry.prototype.run = function (rule) { var uid = require('./uid') var clone = require('./clone') +var defaults = require('./defaults') var toString = Object.prototype.toString /** * Rule is selector + style hash. * - * @param {String} [selector] + * @param {String} [selector] can be selector, rule name, @media etc. * @param {Object} [style] declarations block * @param {Object} [options] * @api public @@ -121,14 +122,17 @@ function Rule(selector, style, options) { this.id = uid.get() this.options = options || {} if (this.options.named == null) this.options.named = true + this.isAtRule = (selector || '')[0] == '@' - if (selector) { - this.selector = selector - this.isAtRule = selector[0] == '@' + if (this.options.named) { + if (this.isAtRule) { + this.selector = selector + } else { + this.className = Rule.NAMESPACE_PREFIX + '-' + this.id + this.selector = '.' + this.className + } } else { - this.isAtRule = false - this.className = Rule.NAMESPACE_PREFIX + '-' + this.id - this.selector = '.' + this.className + this.selector = selector } // We expect style to be plain object. @@ -137,9 +141,9 @@ function Rule(selector, style, options) { // Will be set by StyleSheet#link if link option is true. this.CSSRule = null // When at-rule has sub rules. - this.rules = null + this.subrules = null this.jss = this.options.jss - this.extractAtRules() + this.extractSubrules() } module.exports = Rule @@ -217,16 +221,26 @@ Rule.prototype.addChild = function (selector, style, options) { * @return {Rule} * @api private */ -Rule.prototype.extractAtRules = function () { +Rule.prototype.extractSubrules = function () { if (!this.isAtRule || !this.style) return - if (!this.rules) this.rules = {} - + if (!this.subrules) this.subrules = {} + var sheet = this.options.sheet for (var name in this.style) { + var options = this.options var style = this.style[name] // Not a nested rule. if (typeof style == 'string') break - var selector = this.options.named ? undefined : name - this.rules[name] = this.jss.createRule(selector, style, this.options) + var selector + // We are going to overwrite some rule within the same sheet when + // @media query matches conditions. + if (options.named) { + var prevRule = sheet && sheet.rules[name] + if (prevRule) { + selector = prevRule.selector + options = defaults({named: false}, options) + } + } else selector = name + this.subrules[name] = this.jss.createRule(selector, style, options) delete this.style[name] } } @@ -263,7 +277,7 @@ Rule.prototype.toString = function (options) { var style = this.style // At rules like @charset - if (this.isAtRule && !this.style && !this.rules) return this.selector + ';' + if (this.isAtRule && !this.style && !this.subrules) return this.selector + ';' if (!options) options = {} if (options.indentationLevel == null) options.indentationLevel = 0 @@ -282,13 +296,14 @@ Rule.prototype.toString = function (options) { } } - // We are have an at-rule with nested statements. + // We have an at-rule with nested statements. // https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule - for (var name in this.rules) { - var ruleStr = this.rules[name].toString({ - indentationLevel: options.indentationLevel + 1 - }) - str += '\n' + indent(options.indentationLevel, ruleStr) + var toStringOptions = {indentationLevel: options.indentationLevel + 1} + for (var name in this.subrules) { + str += '\n' + indent( + options.indentationLevel, + this.subrules[name].toString(toStringOptions) + ) } str += '\n' + indent(options.indentationLevel, '}') @@ -320,6 +335,8 @@ Rule.prototype.toJSON = function () { /** * Indent a string. * + * http://jsperf.com/array-join-vs-for + * * @param {Number} level * @param {String} str * @return {String} @@ -330,7 +347,7 @@ function indent(level, str) { return indentStr + str } -},{"./clone":5,"./uid":7}],4:[function(require,module,exports){ +},{"./clone":5,"./defaults":6,"./uid":8}],4:[function(require,module,exports){ 'use strict' var Rule = require('./Rule') @@ -492,7 +509,7 @@ StyleSheet.prototype.addRule = function (key, style) { */ StyleSheet.prototype.addRules = function (rules) { var added = [] - + for (var key in rules) { added.push.apply(added, this.addRule(key, rules[key])) } @@ -545,27 +562,21 @@ StyleSheet.prototype.toString = function () { */ StyleSheet.prototype.createRules = function (key, style, options) { var rules = [] - var selector, name - if (!options) options = {} var named = this.options.named // Scope options overwrite instance options. if (options.named != null) named = options.named - if (named) name = key - else selector = key - - var rule = this.jss.createRule(selector, style, { + var rule = this.jss.createRule(key, style, { sheet: this, - named: named, - name: name + named: named }) rules.push(rule) this.rules[rule.selector] = rule - if (name) { - this.rules[name] = rule - this.classes[name] = rule.className + if (named) { + this.rules[key] = rule + this.classes[key] = rule.className } for (key in rule.children) { @@ -602,8 +613,8 @@ var stringify = JSON.stringify var parse = JSON.parse /** - * Deeply clone object over serialization. - * Expects object to be without cyclic dependencies. + * Deeply clone object using serialization. + * Expects object to be plain and without cyclic dependencies. * * http://jsperf.com/lodash-deepclone-vs-jquery-extend-deep/6 * @@ -616,6 +627,25 @@ module.exports = function clone(obj) { },{}],6:[function(require,module,exports){ 'use strict' +/** + * Merges second object with first one only if value is undefined. + * It expects both objects to be plain. + * + * @param {Object} obj1 + * @param {Object} obj2 + * @return {Object} obj1 + */ +module.exports = function(obj1, obj2) { + for (var key in obj2) { + if (obj1[key] === undefined) obj1[key] = obj2[key] + } + return obj1 +} + + +},{}],7:[function(require,module,exports){ +'use strict' + /** * StyleSheets written in javascript. * @@ -635,7 +665,7 @@ exports.StyleSheet = StyleSheet exports.Rule = Rule exports.Jss = Jss exports.uid = uid -},{"./Jss":1,"./Rule":3,"./StyleSheet":4,"./uid":7}],7:[function(require,module,exports){ +},{"./Jss":1,"./Rule":3,"./StyleSheet":4,"./uid":8}],8:[function(require,module,exports){ (function (global){ 'use strict' @@ -668,5 +698,5 @@ exports.reset = function() { } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}]},{},[6])(6) +},{}]},{},[7])(7) }); \ No newline at end of file diff --git a/dist/jss.min.js b/dist/jss.min.js index 4c06f817f..b2c12bcc1 100755 --- a/dist/jss.min.js +++ b/dist/jss.min.js @@ -1,8 +1,8 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.jss=f()}})(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o