diff --git a/packages/less/src/less/parser/parser.js b/packages/less/src/less/parser/parser.js index cd02ddbb7..103d17599 100644 --- a/packages/less/src/less/parser/parser.js +++ b/packages/less/src/less/parser/parser.js @@ -796,6 +796,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. @@ -1578,7 +1590,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'; @@ -1597,7 +1609,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('--')) { if (parserInput.$char(';')) { value = new Anonymous(''); } else { diff --git a/packages/less/src/less/tree/operation.js b/packages/less/src/less/tree/operation.js index 2805326be..03a4bd542 100644 --- a/packages/less/src/less/tree/operation.js +++ b/packages/less/src/less/tree/operation.js @@ -2,6 +2,8 @@ import Node from './node'; import Color from './color'; import Dimension from './dimension'; import * as Constants from '../constants'; +import Variable from './variable'; +import Call from './call'; const MATH = Constants.Math; @@ -18,8 +20,51 @@ Operation.prototype = Object.assign(new Node(), { this.operands = visitor.visitArray(this.operands); }, + 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); + } + } + }); + if (variable) { + return variable; + } + } + }, + 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; @@ -29,6 +74,18 @@ Operation.prototype = Object.assign(new Node(), { if (b instanceof Dimension && a instanceof Color) { b = b.toColor(); } + if (a instanceof Dimension && b instanceof Call && b.name === 'var') { + if (b.args && b.args.length === 1) { + b = new Variable(b.args[0].toCSS(), 0, {}); + return a.operate(context, op, b); + } + } + if (b instanceof Dimension && a instanceof Call && a.name === 'var') { + if (a.args && a.args.length === 1) { + a = new Variable(a.args[0].toCSS(), 0, {}); + return b.operate(context, op, a); + } + } if (!a.operate || !b.operate) { if ( (a instanceof Operation || b instanceof Operation) diff --git a/packages/less/src/less/tree/ruleset.js b/packages/less/src/less/tree/ruleset.js index cea8a7645..09bb9e4d6 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 index f7b495866..a5c1b3a5d 100644 --- a/packages/test-data/css/_main/custom-property.css +++ b/packages/test-data/css/_main/custom-property.css @@ -2,3 +2,7 @@ --basic-deg: 20deg; --basic-deg-tan: tan(var(--basic-deg)); } +.test2 { + --some-var: 5px; + prop: min(100% - var(--some-var), 10px); +} diff --git a/packages/test-data/less/_main/custom-property.less b/packages/test-data/less/_main/custom-property.less index 2d19e1dbc..45d573ec4 100644 --- a/packages/test-data/less/_main/custom-property.less +++ b/packages/test-data/less/_main/custom-property.less @@ -2,3 +2,8 @@ --basic-deg: 20deg; --basic-deg-tan: tan(var(--basic-deg)); } + +.test2 { + --some-var: 5px; + prop: min(100% - var(--some-var), 10px); +}