diff --git a/src/lib/apply-shim.html b/src/lib/apply-shim.html index a971c9eb16..19803c8d27 100644 --- a/src/lib/apply-shim.html +++ b/src/lib/apply-shim.html @@ -77,7 +77,8 @@ var MIXIN_MATCH = styleUtil.rx.MIXIN_MATCH; var VAR_ASSIGN = styleUtil.rx.VAR_ASSIGN; - var VAR_MATCH = styleUtil.rx.VAR_MATCH; + // match var(--a, --b) to make var(--a, var(--b)); + var BAD_VAR = /var\(\s*(--[^,]*),\s*(--[^)]*)\)/g; var APPLY_NAME_CLEAN = /;\s*/m; // separator used between mixin-name and mixin-property-name when producing properties @@ -120,14 +121,11 @@ function produceCssProperties(matchText, propertyName, valueProperty, valueMixin) { // handle case where property value is a mixin if (valueProperty) { - VAR_MATCH.lastIndex = 0; - var m = VAR_MATCH.exec(valueProperty); - if (m) { - var value = m[2]; - if (mapGet(value)){ + styleUtil.processVariableAndFallback(valueProperty, function(prefix, value) { + if (value && mapGet(value)) { valueMixin = '@apply ' + value + ';'; } - } + }); } if (!valueMixin) { return matchText; @@ -160,12 +158,9 @@ // fix shim'd var syntax // var(--a, --b) -> var(--a, var(--b)); - function fixVars(matchText, prefix, value, fallback) { + function fixVars(matchText, varA, varB) { // if fallback doesn't exist, or isn't a broken variable, abort - if (!fallback || fallback.indexOf('--') !== 0) { - return matchText; - } - return [prefix, 'var(', value, ', var(', fallback, '));'].join(''); + return 'var(' + varA + ',' + 'var(' + varB + '));'; } // produce variable consumption at the site of mixin consumption @@ -233,7 +228,7 @@ }, transformCssText: function(cssText) { // fix shim variables - cssText = cssText.replace(VAR_MATCH, fixVars); + cssText = cssText.replace(BAD_VAR, fixVars); // produce variables cssText = cssText.replace(VAR_ASSIGN, produceCssProperties); // consume mixins diff --git a/src/lib/style-properties.html b/src/lib/style-properties.html index 13576b751a..81995f2679 100644 --- a/src/lib/style-properties.html +++ b/src/lib/style-properties.html @@ -150,14 +150,14 @@ } else { // case (2) variable var self = this; - var fn = function(all, prefix, value, fallback) { + var fn = function(prefix, value, fallback, suffix) { var propertyValue = (self.valueForProperty(props[value], props) || // fallback may be --a or var(--a) or literal self.valueForProperty(props[fallback] || fallback, props) || fallback); - return prefix + (propertyValue || ''); + return prefix + (propertyValue || '') + suffix; }; - property = property.replace(this.rx.VAR_MATCH, fn); + property = styleUtil.processVariableAndFallback(property, fn); } } return property && property.trim() || ''; diff --git a/src/lib/style-util.html b/src/lib/style-util.html index d10b4e7902..83c6b24fde 100644 --- a/src/lib/style-util.html +++ b/src/lib/style-util.html @@ -235,20 +235,53 @@ return element.getAttribute('css-build'); }, + // Walk from text[start] matching parens + // returns position of the outer end paren + _findMatchingParen: function(text, start) { + var level = 0; + for (var i=start, l=text.length; i < l; i++) { + switch (text[i]) { + case '(': + level++; + break; + case ')': + if (--level === 0) { + return i; + } + break; + } + } + return -1; + }, + + processVariableAndFallback: function(str, callback) { + // find 'var(' + var start = str.indexOf('var('); + if (start === -1) { + // no var?, everything is prefix + return callback(str, '', '', ''); + } + //${prefix}var(${inner})${suffix} + var end = this._findMatchingParen(str, start + 3); + var inner = str.substring(start + 4, end); + var prefix = str.substring(0, start); + // suffix may have other variables + var suffix = this.processVariableAndFallback(str.substring(end + 1), callback); + var comma = inner.indexOf(','); + // value and fallback args should be trimmed to match in property lookup + if (comma === -1) { + // variable, no fallback + return callback(prefix, inner.trim(), '', suffix); + } + // var(${value},${fallback}) + var value = inner.substring(0, comma).trim(); + var fallback = inner.substring(comma + 1).trim(); + return callback(prefix, value, fallback, suffix); + }, + rx: { VAR_ASSIGN: /(?:^|[;\s{]\s*)(--[\w-]*?)\s*:\s*(?:([^;{]*)|{([^}]*)})(?:(?=[;\s}])|$)/gi, MIXIN_MATCH: /(?:^|\W+)@apply\s*\(?([^);\n]*)\)?/gi, - // note, this supports: - // var(--a) - // var(--a, --b) - // var(--a, fallback-literal) - // var(--a, fallback-literal(with-one-nested-parentheses)) - // var(--a, var(--b)) - // var(--a, var(--b, fallback-literal)) - // var(--a, var(--b, fallback-literal(with-one-nested-parentheses))) - // var(--a, var(--b, var(--c, fallback-literal))) - // var(--a, var(--b, var(--c, fallback-literal(with-one-nested-parentheses)))) - VAR_MATCH: /(^|\W+)var\([\s]*([^,)]*)[\s]*,?[\s]*((?:[^,()]*)|(?:[^;()]*\([^;)]*\)+))[\s]*?\)/gi, VAR_CONSUMED: /(--[\w-]+)\s*([:,;)]|$)/gi, ANIMATION_MATCH: /(animation\s*:)|(animation-name\s*:)/, MEDIA_MATCH: /@media[^(]*(\([^)]*\))/, diff --git a/test/smoke/css-gradient-var.html b/test/smoke/css-gradient-var.html new file mode 100644 index 0000000000..7fa0e2f3c2 --- /dev/null +++ b/test/smoke/css-gradient-var.html @@ -0,0 +1,42 @@ + + +
+ +