Allow var() in place of multiple arguments to color functions (#208)

See sass/sass#2440
This commit is contained in:
Natalie Weizenbaum 2018-01-12 11:43:36 -08:00 committed by GitHub
parent 00cb5532a0
commit aa3c765b10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 151 additions and 44 deletions

View File

@ -5,6 +5,9 @@
* `round()` now returns the correct results for negative numbers that should * `round()` now returns the correct results for negative numbers that should
round down. round down.
* `var()` may now be passed in place of multiple arguments to `rgb()`, `rgba()`,
`hsl()` and `hsla()`.
## 1.0.0-beta.4 ## 1.0.0-beta.4
* Support unquoted imports in the indented syntax. * Support unquoted imports in the indented syntax.

View File

@ -43,21 +43,39 @@ final List<BuiltInCallable> coreFunctions = new UnmodifiableListView([
// ## Colors // ## Colors
// ### RGB // ### RGB
new BuiltInCallable("rgb", r"$red, $green, $blue", (arguments) { new BuiltInCallable.overloaded("rgb", {
if (arguments[0].isSpecialNumber || r"$red, $green, $blue": (arguments) {
arguments[1].isSpecialNumber || if (arguments[0].isSpecialNumber ||
arguments[2].isSpecialNumber) { arguments[1].isSpecialNumber ||
return _functionString('rgb', arguments); arguments[2].isSpecialNumber) {
return _functionString('rgb', arguments);
}
var red = arguments[0].assertNumber("red");
var green = arguments[1].assertNumber("green");
var blue = arguments[2].assertNumber("blue");
return new SassColor.rgb(
fuzzyRound(_percentageOrUnitless(red, 255, "red")),
fuzzyRound(_percentageOrUnitless(green, 255, "green")),
fuzzyRound(_percentageOrUnitless(blue, 255, "blue")));
},
r"$red, $green": (arguments) {
// rgb(123, var(--foo)) is valid CSS because --foo might be `456, 789` and
// functions are parsed after variable substitution.
if (arguments[0].isVar || arguments[1].isVar) {
return _functionString('rgb', arguments);
} else {
throw new SassScriptException(r"Missing argument $blue.");
}
},
r"$red": (arguments) {
if (arguments.first.isVar) {
return _functionString('rgb', arguments);
} else {
throw new SassScriptException(r"Missing argument $green.");
}
} }
var red = arguments[0].assertNumber("red");
var green = arguments[1].assertNumber("green");
var blue = arguments[2].assertNumber("blue");
return new SassColor.rgb(
fuzzyRound(_percentageOrUnitless(red, 255, "red")),
fuzzyRound(_percentageOrUnitless(green, 255, "green")),
fuzzyRound(_percentageOrUnitless(blue, 255, "blue")));
}), }),
new BuiltInCallable.overloaded("rgba", { new BuiltInCallable.overloaded("rgba", {
@ -81,16 +99,43 @@ final List<BuiltInCallable> coreFunctions = new UnmodifiableListView([
_percentageOrUnitless(alpha, 1, "alpha")); _percentageOrUnitless(alpha, 1, "alpha"));
}, },
r"$color, $alpha": (arguments) { r"$color, $alpha": (arguments) {
var color = arguments[0].assertColor("color"); // rgba(var(--foo), 0.5) is valid CSS because --foo might be `123, 456,
// 789` and functions are parsed after variable substitution.
if (arguments[1].isSpecialNumber) { if (arguments[0].isVar) {
return _functionString('rgba', arguments);
} else if (arguments[1].isVar) {
var first = arguments[0];
if (first is SassColor) {
return new SassString(
"rgba(${first.red}, ${first.green}, ${first.blue}, "
"${arguments[1].toCssString()})");
} else {
return _functionString('rgba', arguments);
}
} else if (arguments[1].isSpecialNumber) {
var color = arguments[0].assertColor("color");
return new SassString( return new SassString(
"rgba(${color.red}, ${color.green}, ${color.blue}, " "rgba(${color.red}, ${color.green}, ${color.blue}, "
"${arguments[1].toCssString()})"); "${arguments[1].toCssString()})");
} }
var color = arguments[0].assertColor("color");
var alpha = arguments[1].assertNumber("alpha"); var alpha = arguments[1].assertNumber("alpha");
return color.changeAlpha(_percentageOrUnitless(alpha, 1, "alpha")); return color.changeAlpha(_percentageOrUnitless(alpha, 1, "alpha"));
},
r"$red, $green, $blue": (arguments) {
if (arguments[0].isVar || arguments[1].isVar || arguments[2].isVar) {
return _functionString('rgba', arguments);
} else {
throw new SassScriptException(r"Missing argument $alpha.");
}
},
r"$red": (arguments) {
if (arguments.first.isVar) {
return _functionString('rgba', arguments);
} else {
throw new SassScriptException(r"Missing argument $green.");
}
} }
}), }),
@ -115,36 +160,78 @@ final List<BuiltInCallable> coreFunctions = new UnmodifiableListView([
// ### HSL // ### HSL
new BuiltInCallable("hsl", r"$hue, $saturation, $lightness", (arguments) { new BuiltInCallable.overloaded("hsl", {
if (arguments[0].isSpecialNumber || r"$hue, $saturation, $lightness": (arguments) {
arguments[1].isSpecialNumber || if (arguments[0].isSpecialNumber ||
arguments[2].isSpecialNumber) { arguments[1].isSpecialNumber ||
return _functionString("hsl", arguments); arguments[2].isSpecialNumber) {
return _functionString("hsl", arguments);
}
var hue = arguments[0].assertNumber("hue");
var saturation = arguments[1].assertNumber("saturation");
var lightness = arguments[2].assertNumber("lightness");
return new SassColor.hsl(hue.value, saturation.value, lightness.value);
},
r"$hue, $saturation": (arguments) {
// hsl(123, var(--foo)) is valid CSS because --foo might be `10%, 20%` and
// functions are parsed after variable substitution.
if (arguments[0].isVar || arguments[1].isVar) {
return _functionString('hsl', arguments);
} else {
throw new SassScriptException(r"Missing argument $lightness.");
}
},
r"$hue": (arguments) {
if (arguments.first.isVar) {
return _functionString('hsl', arguments);
} else {
throw new SassScriptException(r"Missing argument $saturation.");
}
} }
var hue = arguments[0].assertNumber("hue");
var saturation = arguments[1].assertNumber("saturation");
var lightness = arguments[2].assertNumber("lightness");
return new SassColor.hsl(hue.value, saturation.value, lightness.value);
}), }),
new BuiltInCallable("hsla", r"$hue, $saturation, $lightness, $alpha", new BuiltInCallable.overloaded("hsla", {
(arguments) { r"$hue, $saturation, $lightness, $alpha": (arguments) {
if (arguments[0].isSpecialNumber || if (arguments[0].isSpecialNumber ||
arguments[1].isSpecialNumber || arguments[1].isSpecialNumber ||
arguments[2].isSpecialNumber || arguments[2].isSpecialNumber ||
arguments[3].isSpecialNumber) { arguments[3].isSpecialNumber) {
return _functionString("hsla", arguments); return _functionString("hsla", arguments);
}
var hue = arguments[0].assertNumber("hue");
var saturation = arguments[1].assertNumber("saturation");
var lightness = arguments[2].assertNumber("lightness");
var alpha = arguments[3].assertNumber("alpha");
return new SassColor.hsl(hue.value, saturation.value, lightness.value,
_percentageOrUnitless(alpha, 1, "alpha"));
},
r"$hue, $saturation, $lightness": (arguments) {
// hsla(123, var(--foo)) is valid CSS because --foo might be `10%, 20%,
// 0.5` and functions are parsed after variable substitution.
if (arguments[0].isVar || arguments[1].isVar || arguments[2].isVar) {
return _functionString('hsla', arguments);
} else {
throw new SassScriptException(r"Missing argument $alpha.");
}
},
r"$hue, $saturation": (arguments) {
if (arguments[0].isVar || arguments[1].isVar) {
return _functionString('hsla', arguments);
} else {
throw new SassScriptException(r"Missing argument $lightness.");
}
},
r"$hue": (arguments) {
if (arguments.first.isVar) {
return _functionString('hsla', arguments);
} else {
throw new SassScriptException(r"Missing argument $saturation.");
}
} }
var hue = arguments[0].assertNumber("hue");
var saturation = arguments[1].assertNumber("saturation");
var lightness = arguments[2].assertNumber("lightness");
var alpha = arguments[3].assertNumber("alpha");
return new SassColor.hsl(hue.value, saturation.value, lightness.value,
_percentageOrUnitless(alpha, 1, "alpha"));
}), }),
new BuiltInCallable( new BuiltInCallable(

View File

@ -53,13 +53,20 @@ abstract class Value {
/// and all other values count as single-value lists. /// and all other values count as single-value lists.
List<Value> get asList => [this]; List<Value> get asList => [this];
/// Whether this is a value that CSS may treate as a number, such as `calc()` /// Whether this is a value that CSS may treat as a number, such as `calc()`
/// or `var()`. /// or `var()`.
/// ///
/// Functions that shadow plain CSS functions need to gracefully handle when /// Functions that shadow plain CSS functions need to gracefully handle when
/// these arguments are passed in. /// these arguments are passed in.
bool get isSpecialNumber => false; bool get isSpecialNumber => false;
/// Whether this is a call to `var()`, which may be substituted in CSS for a
/// custom property value.
///
/// Functions that shadow plain CSS functions need to gracefully handle when
/// these arguments are passed in.
bool get isVar => false;
const Value(); const Value();
/// Calls the appropriate visit method on [visitor]. /// Calls the appropriate visit method on [visitor].

View File

@ -55,6 +55,16 @@ class SassString extends Value {
} }
} }
bool get isVar {
if (hasQuotes) return false;
if (text.length < "var(--_)".length) return false;
return equalsLetterIgnoreCase($v, text.codeUnitAt(0)) &&
equalsLetterIgnoreCase($a, text.codeUnitAt(1)) &&
equalsLetterIgnoreCase($r, text.codeUnitAt(2)) &&
text.codeUnitAt(3) == $lparen;
}
bool get isBlank => !hasQuotes && text.isEmpty; bool get isBlank => !hasQuotes && text.isEmpty;
factory SassString.empty({bool quotes: false}) => factory SassString.empty({bool quotes: false}) =>