diff --git a/Readme.md b/Readme.md index 62f8e0369..6dbbec8e6 100644 --- a/Readme.md +++ b/Readme.md @@ -73,7 +73,7 @@ form input { - single-line and multi-line [comments](/LearnBoost/stylus/blob/master/docs/comments.md) - css [literal](/LearnBoost/stylus/blob/master/docs/literal.md) - character [escaping](/LearnBoost/stylus/blob/master/docs/escape.md) - - [@keyframes](/LearnBoost/stylus/blob/master/docs/keyframes.md) support + - [@keyframes](/LearnBoost/stylus/blob/master/docs/keyframes.md) support & expansion - [@font-face](/LearnBoost/stylus/blob/master/docs/font-face.md) support - [@media](/LearnBoost/stylus/blob/master/docs/media.md) support - Connect [Middleware](/LearnBoost/stylus/blob/master/docs/middleware.md) diff --git a/docs/keyframes.md b/docs/keyframes.md index 48ee6c420..9486ed93d 100644 --- a/docs/keyframes.md +++ b/docs/keyframes.md @@ -50,3 +50,71 @@ yielding: } } + +## Expansion + + By utilizing `@keyframes` your rules are automatically expanded to the vendor prefixes defined by the `vendors` variable, defaulting to `webkit moz official`. This means we can alter it at any time for the expansion to take effect immediately. For example consider the following + + @keyframes foo { + from { + color: black + } + to { + color: white + } + } + +expands to our two default vendors and the official syntax: + + @-moz-keyframes foo { + 0% { + color: #000; + } + + 100% { + color: #fff; + } + } + @-webkit-keyframes foo { + 0% { + color: #000; + } + + 100% { + color: #fff; + } + } + @keyframes foo { + 0% { + color: #000; + } + + 100% { + color: #fff; + } + } + +if we wanted to limit to the official syntax only, simply alter `vendors`: + + vendors = official + + @keyframes foo { + from { + color: black + } + to { + color: white + } + } + +yielding: + + @keyframes foo { + 0% { + color: #000; + } + + 100% { + color: #fff; + } + } diff --git a/lib/functions/index.styl b/lib/functions/index.styl index e2703e440..e314f8629 100644 --- a/lib/functions/index.styl +++ b/lib/functions/index.styl @@ -1,4 +1,6 @@ +vendors = moz webkit official + // stringify the given arg -string(arg) diff --git a/lib/lexer.js b/lib/lexer.js index e1f319108..ca42271a8 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -444,7 +444,7 @@ Lexer.prototype = { atrule: function() { var captures; - if (captures = /^@(import|(-webkit-)?keyframes|charset|page) */.exec(this.str)) { + if (captures = /^@(import|(-\w+-)?keyframes|charset|page) */.exec(this.str)) { this.skip(captures); return new Token(captures[1]); } diff --git a/lib/nodes/keyframes.js b/lib/nodes/keyframes.js index cd156042b..f1732b1b5 100644 --- a/lib/nodes/keyframes.js +++ b/lib/nodes/keyframes.js @@ -22,6 +22,7 @@ var Keyframes = module.exports = function Keyframes(name){ Node.call(this); this.name = name; this.frames = []; + this.prefix = 'official'; }; /** @@ -45,6 +46,24 @@ Keyframes.prototype.push = function(pos, block){ }); }; +/** + * Return a clone of this node. + * + * @return {Node} + * @api public + */ + +Keyframes.prototype.clone = function(){ + var clone = new Keyframes(this.name); + clone.lineno = this.lineno; + clone.prefix = this.prefix; + clone.frames = this.frames.map(function(node){ + node.block = node.block.clone(); + return node; + }); + return clone; +}; + /** * Return `@keyframes name`. * diff --git a/lib/visitor/compiler.js b/lib/visitor/compiler.js index 76af3b0f5..ab54d8cfd 100644 --- a/lib/visitor/compiler.js +++ b/lib/visitor/compiler.js @@ -144,7 +144,11 @@ Compiler.prototype.visitBlock = function(block){ */ Compiler.prototype.visitKeyframes = function(node){ - this.buf += '@-webkit-keyframes ' + var prefix = 'official' == node.prefix + ? '' + : '-' + node.prefix + '-'; + + this.buf += '@' + prefix + 'keyframes ' + this.visit(node.name) + (this.compress ? '{' : ' {'); ++this.indents; diff --git a/lib/visitor/evaluator.js b/lib/visitor/evaluator.js index 3e9ddcfec..261d1fa13 100644 --- a/lib/visitor/evaluator.js +++ b/lib/visitor/evaluator.js @@ -184,12 +184,23 @@ Evaluator.prototype.visitMedia = function(media){ */ Evaluator.prototype.visitKeyframes = function(keyframes){ + if (keyframes.fabricated) return keyframes; + keyframes.name = this.visit(keyframes.name).first.name; keyframes.frames = keyframes.frames.map(function(frame){ frame.block = this.visit(frame.block); return frame; }, this); - return keyframes; + console.log(keyframes.prefix); + + this.vendors.forEach(function(prefix){ + var node = keyframes.clone(); + node.prefix = prefix; + node.fabricated = true; + this.root.push(node); + }, this); + + return nodes.null; }; /** @@ -1019,6 +1030,19 @@ Evaluator.prototype.__defineGetter__('closestBlock', function(){ } }); +/** + * Return an array of vendor names. + * + * @return {Array} + * @api private + */ + +Evaluator.prototype.__defineGetter__('vendors', function(){ + return this.lookup('vendors').nodes.map(function(node){ + return node.string; + }); +}); + /** * Return the current frame `Scope`. * diff --git a/test/cases/css.keyframes.styl b/test/cases/css.keyframes.styl index ff6b6a63d..e79346564 100644 --- a/test/cases/css.keyframes.styl +++ b/test/cases/css.keyframes.styl @@ -1,4 +1,6 @@ +vendors = webkit + @keyframes bouce { from { foo: bar; diff --git a/test/cases/keyframes.fabrication.css b/test/cases/keyframes.fabrication.css new file mode 100644 index 000000000..5317feeae --- /dev/null +++ b/test/cases/keyframes.fabrication.css @@ -0,0 +1,18 @@ +@-moz-keyframes foo { + 0% { + color: #000; + } + + 100% { + color: #fff; + } +} +@keyframes foo { + 0% { + color: #000; + } + + 100% { + color: #fff; + } +} diff --git a/test/cases/keyframes.fabrication.defaults.css b/test/cases/keyframes.fabrication.defaults.css new file mode 100644 index 000000000..727ff901f --- /dev/null +++ b/test/cases/keyframes.fabrication.defaults.css @@ -0,0 +1,27 @@ +@-moz-keyframes foo { + 0% { + color: #000; + } + + 100% { + color: #fff; + } +} +@-webkit-keyframes foo { + 0% { + color: #000; + } + + 100% { + color: #fff; + } +} +@keyframes foo { + 0% { + color: #000; + } + + 100% { + color: #fff; + } +} \ No newline at end of file diff --git a/test/cases/keyframes.fabrication.defaults.styl b/test/cases/keyframes.fabrication.defaults.styl new file mode 100644 index 000000000..1f8e76f02 --- /dev/null +++ b/test/cases/keyframes.fabrication.defaults.styl @@ -0,0 +1,9 @@ + +@keyframes foo { + from { + color: black + } + to { + color: white + } +} \ No newline at end of file diff --git a/test/cases/keyframes.fabrication.styl b/test/cases/keyframes.fabrication.styl new file mode 100644 index 000000000..318c2aedb --- /dev/null +++ b/test/cases/keyframes.fabrication.styl @@ -0,0 +1,11 @@ + +vendors = moz official + +@keyframes foo { + from { + color: black + } + to { + color: white + } +} \ No newline at end of file diff --git a/test/cases/regression.248.compressed.styl b/test/cases/regression.248.compressed.styl index b186369ff..e7e1d919a 100644 --- a/test/cases/regression.248.compressed.styl +++ b/test/cases/regression.248.compressed.styl @@ -1,4 +1,6 @@ +vendors = webkit + @keyframes colors 0% background-color red diff --git a/test/cases/regression.252.styl b/test/cases/regression.252.styl index c45b42b58..8fb4ef4af 100644 --- a/test/cases/regression.252.styl +++ b/test/cases/regression.252.styl @@ -1,4 +1,6 @@ +vendors = webkit + $border-radius = 25px @keyframes movingBorder