diff --git a/packages/less/src/less/functions/math-helper.js b/packages/less/src/less/functions/math-helper.js index b557875c5..4cca18668 100644 --- a/packages/less/src/less/functions/math-helper.js +++ b/packages/less/src/less/functions/math-helper.js @@ -1,6 +1,15 @@ +import Call from '../tree/call'; +import CustomProperty from '../tree/custom-property'; import Dimension from '../tree/dimension'; const MathHelper = (fn, unit, n) => { + if (n instanceof Call && n.name === 'var') { + if (n.args && n.args.length === 1) { + return new Call(fn.name, [new CustomProperty(n.args[0].toCSS(), n._index, n._fileInfo)], n._index, n._fileInfo); + } else { + throw { type: 'Argument', message: 'var must contain one expression' }; + } + } if (!(n instanceof Dimension)) { throw { type: 'Argument', message: 'argument must be a number' }; } diff --git a/packages/less/src/less/parser/parser.js b/packages/less/src/less/parser/parser.js index 59aa2eef4..8b2ad6e42 100644 --- a/packages/less/src/less/parser/parser.js +++ b/packages/less/src/less/parser/parser.js @@ -794,6 +794,18 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) { if (parserInput.currentChar() === '@' && (name = parserInput.$re(/^(@[\w-]+)\s*:/))) { return name[1]; } }, + // + // The custom property part of a variable definition. + // + // --fink: + // + customProperty: function () { + var name; + if (parserInput.currentChar() === '-' && (name = parserInput.$re(/^(--[\w-]+)\s*:/))) { + return name[1]; + } + }, + // // Call a variable value to retrieve a detached ruleset // or a value from a detached ruleset's rules. @@ -1558,7 +1570,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) { parserInput.save(); - name = this.variable() || this.ruleProperty(); + name = this.variable() || this.customProperty() || this.ruleProperty(); if (name) { isVariable = typeof name === 'string'; @@ -1577,7 +1589,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) { merge = !isVariable && name.length > 1 && name.pop().value; // Custom property values get permissive parsing - if (name[0].value && name[0].value.slice(0, 2) === '--') { + if (isVariable && name.startsWith('--')) { value = this.permissiveValue(/[;}]/); } // Try to store values as anonymous diff --git a/packages/less/src/less/tree/custom-property.js b/packages/less/src/less/tree/custom-property.js new file mode 100644 index 000000000..3eaa284b9 --- /dev/null +++ b/packages/less/src/less/tree/custom-property.js @@ -0,0 +1,18 @@ +/* eslint-disable no-prototype-builtins */ +import Node from './node'; + +const CustomProperty = function (name, index, currentFileInfo) { + this.name = name; + this._index = index; + this._fileInfo = currentFileInfo; +}; + +CustomProperty.prototype = Object.assign(new Node(), { + type: 'CustomProperty', + + genCSS: function (context, output) { + output.add('var(' + this.name + ')'); + } +}); + +export default CustomProperty; diff --git a/packages/less/src/less/tree/operation.js b/packages/less/src/less/tree/operation.js index 2805326be..982d571d5 100644 --- a/packages/less/src/less/tree/operation.js +++ b/packages/less/src/less/tree/operation.js @@ -2,6 +2,7 @@ import Node from './node'; import Color from './color'; import Dimension from './dimension'; import * as Constants from '../constants'; +import Call from './call'; const MATH = Constants.Math; @@ -19,7 +20,15 @@ Operation.prototype = Object.assign(new Node(), { }, eval(context) { - let a = this.operands[0].eval(context), b = this.operands[1].eval(context), op; + var a = this.evalVariable(context, this.operands[0]) + if (!a) { + a = this.operands[0].eval(context) + } + var b = this.evalVariable(context, this.operands[1]); + if (!b) { + b = this.operands[1].eval(context); + } + var op; if (context.isMathOn(this.op)) { op = this.op === './' ? '/' : this.op; @@ -56,7 +65,41 @@ Operation.prototype = Object.assign(new Node(), { output.add(' '); } this.operands[1].genCSS(context, output); - } + }, + + find: function (obj, fun) { + for (var i_2 = 0, r = void 0; i_2 < obj.length; i_2++) { + r = fun.call(obj, obj[i_2]); + if (r) { + return r; + } + } + return null; + }, + + evalVariable: function (context, operand) { + if (operand.name === 'var' && operand.args.length === 1) { + var varName = operand.args[0].toCSS(); + var variable = this.find(context.frames, function (frame) { + var v = frame.variable(varName); + if (v) { + if (v.important) { + var importantScope = context.importantScope[context.importantScope.length - 1]; + importantScope.important = v.important; + } + // If in calc, wrap vars in a function call to cascade evaluate args first + if (context.inCalc) { + return (new Call('_SELF', [v.value])).eval(context); + } + else { + return v.value.eval(context); + } + } + }); + + return variable; + } + }, }); export default Operation; diff --git a/packages/less/src/less/tree/ruleset.js b/packages/less/src/less/tree/ruleset.js index a3324cf07..878ac3f80 100644 --- a/packages/less/src/less/tree/ruleset.js +++ b/packages/less/src/less/tree/ruleset.js @@ -286,7 +286,7 @@ Ruleset.prototype = Object.assign(new Node(), { variables() { if (!this._variables) { this._variables = !this.rules ? {} : this.rules.reduce(function (hash, r) { - if (r instanceof Declaration && r.variable === true) { + if (r instanceof Declaration && (r.variable === true || (typeof r.name ==='string' && r.name.startsWith('--')))) { hash[r.name] = r; } // when evaluating variables in an import statement, imports have not been eval'd diff --git a/packages/test-data/css/_main/custom-property.css b/packages/test-data/css/_main/custom-property.css new file mode 100644 index 000000000..243947443 --- /dev/null +++ b/packages/test-data/css/_main/custom-property.css @@ -0,0 +1,16 @@ +.test { + --basic-deg: 20deg; + --basic-deg-tan: tan(var(--basic-deg)); +} +.test2 { + --some-var: 5%; + prop: min(95%, 10px); +} +.test3 { + --some-var: 55%; + prop: min(60%, 15px); +} +.test4 { + color: red; + --other-color: green; +} diff --git a/packages/test-data/less/_main/custom-property.less b/packages/test-data/less/_main/custom-property.less new file mode 100644 index 000000000..960267dcd --- /dev/null +++ b/packages/test-data/less/_main/custom-property.less @@ -0,0 +1,19 @@ +.test { + --basic-deg: 20deg; + --basic-deg-tan: tan(var(--basic-deg)); +} + +.test2 { + --some-var: 5%; + prop: min(100% - var(--some-var), 10px); +} + +.test3 { + --some-var: 55%; + prop: min(var(--some-var) + 5%, 15px); +} + +.test4 { + color: red; + --other-color: green; +}