mirror of
https://github.com/danog/dart-sass.git
synced 2024-11-26 20:24:42 +01:00
parent
6ec78f975b
commit
1918674295
@ -1,3 +1,12 @@
|
||||
## 1.27.0
|
||||
|
||||
### Dart API
|
||||
|
||||
* Add [HWB] support to the `SassColor` class, including a `SassColor.hwb()`
|
||||
constructor, `whiteness` and `blackness` getters, and a `changeHwb()` method.
|
||||
|
||||
[HWB]: https://en.wikipedia.org/wiki/HWB_color_model
|
||||
|
||||
## 1.26.11
|
||||
|
||||
* **Potentially breaking bug fix:** `selector.nest()` now throws an error
|
||||
|
@ -55,6 +55,20 @@ class SassColor extends Value implements ext.SassColor {
|
||||
|
||||
num _lightness;
|
||||
|
||||
num get whiteness {
|
||||
// Because HWB is (currently) used much less frequently than HSL or RGB, we
|
||||
// don't cache its values because we expect the memory overhead of doing so
|
||||
// to outweigh the cost of recalculating it on access.
|
||||
return math.min(math.min(red, green), blue) / 255 * 100;
|
||||
}
|
||||
|
||||
num get blackness {
|
||||
// Because HWB is (currently) used much less frequently than HSL or RGB, we
|
||||
// don't cache its values because we expect the memory overhead of doing so
|
||||
// to outweigh the cost of recalculating it on access.
|
||||
return 100 - math.max(math.max(red, green), blue) / 255 * 100;
|
||||
}
|
||||
|
||||
final num alpha;
|
||||
|
||||
/// The original string representation of this color, or `null` if one is
|
||||
@ -81,6 +95,35 @@ class SassColor extends Value implements ext.SassColor {
|
||||
alpha = alpha == null ? 1 : fuzzyAssertRange(alpha, 0, 1, "alpha"),
|
||||
originalSpan = null;
|
||||
|
||||
factory SassColor.hwb(num hue, num whiteness, num blackness, [num alpha]) {
|
||||
// From https://www.w3.org/TR/css-color-4/#hwb-to-rgb
|
||||
var scaledHue = hue % 360 / 360;
|
||||
var scaledWhiteness = fuzzyAssertRange(whiteness, 0, 100, "whiteness") / 100;
|
||||
var scaledBlackness = fuzzyAssertRange(blackness, 0, 100, "blackness") / 100;
|
||||
|
||||
var sum = scaledWhiteness + scaledBlackness;
|
||||
if (sum > 1) {
|
||||
scaledWhiteness /= sum;
|
||||
scaledBlackness /= sum;
|
||||
}
|
||||
|
||||
var factor = 1 - scaledWhiteness - scaledBlackness;
|
||||
int toRgb(num hue) {
|
||||
var channel = _hueToRgb(0, 1, hue) * factor + scaledWhiteness;
|
||||
return fuzzyRound(channel * 255);
|
||||
}
|
||||
|
||||
// Because HWB is (currently) used much less frequently than HSL or RGB, we
|
||||
// don't cache its values because we expect the memory overhead of doing so
|
||||
// to outweigh the cost of recalculating it on access. Instead, we eagerly
|
||||
// convert it to RGB and then convert back if necessary.
|
||||
return SassColor.rgb(
|
||||
toRgb(scaledHue + 1/3),
|
||||
toRgb(scaledHue),
|
||||
toRgb(scaledHue - 1/3),
|
||||
alpha);
|
||||
}
|
||||
|
||||
SassColor._(this._red, this._green, this._blue, this._hue, this._saturation,
|
||||
this._lightness, this.alpha)
|
||||
: originalSpan = null;
|
||||
@ -97,6 +140,10 @@ class SassColor extends Value implements ext.SassColor {
|
||||
SassColor.hsl(hue ?? this.hue, saturation ?? this.saturation,
|
||||
lightness ?? this.lightness, alpha ?? this.alpha);
|
||||
|
||||
SassColor changeHwb({num hue, num whiteness, num blackness, num alpha}) =>
|
||||
SassColor.hwb(hue ?? this.hue, whiteness ?? this.whiteness,
|
||||
blackness ?? this.blackness, alpha ?? this.alpha);
|
||||
|
||||
SassColor changeAlpha(num alpha) => SassColor._(_red, _green, _blue, _hue,
|
||||
_saturation, _lightness, fuzzyAssertRange(alpha, 0, 1, "alpha"));
|
||||
|
||||
@ -177,29 +224,26 @@ class SassColor extends Value implements ext.SassColor {
|
||||
scaledSaturation -
|
||||
scaledLightness * scaledSaturation;
|
||||
var m1 = scaledLightness * 2 - m2;
|
||||
_red = _hueToRgb(m1, m2, scaledHue + 1 / 3);
|
||||
_green = _hueToRgb(m1, m2, scaledHue);
|
||||
_blue = _hueToRgb(m1, m2, scaledHue - 1 / 3);
|
||||
_red = fuzzyRound(_hueToRgb(m1, m2, scaledHue + 1 / 3) * 255);
|
||||
_green = fuzzyRound(_hueToRgb(m1, m2, scaledHue) * 255);
|
||||
_blue = fuzzyRound(_hueToRgb(m1, m2, scaledHue - 1 / 3) * 255);
|
||||
}
|
||||
|
||||
/// An algorithm from the CSS3 spec:
|
||||
/// http://www.w3.org/TR/css3-color/#hsl-color.
|
||||
int _hueToRgb(num m1, num m2, num hue) {
|
||||
static num _hueToRgb(num m1, num m2, num hue) {
|
||||
if (hue < 0) hue += 1;
|
||||
if (hue > 1) hue -= 1;
|
||||
|
||||
num result;
|
||||
if (hue < 1 / 6) {
|
||||
result = m1 + (m2 - m1) * hue * 6;
|
||||
return m1 + (m2 - m1) * hue * 6;
|
||||
} else if (hue < 1 / 2) {
|
||||
result = m2;
|
||||
return m2;
|
||||
} else if (hue < 2 / 3) {
|
||||
result = m1 + (m2 - m1) * (2 / 3 - hue) * 6;
|
||||
return m1 + (m2 - m1) * (2 / 3 - hue) * 6;
|
||||
} else {
|
||||
result = m1;
|
||||
return m1;
|
||||
}
|
||||
|
||||
return fuzzyRound(result * 255);
|
||||
}
|
||||
|
||||
/// Returns an `rgb()` or `rgba()` function call that will evaluate to this
|
||||
|
16
lib/src/value/external/color.dart
vendored
16
lib/src/value/external/color.dart
vendored
@ -28,6 +28,12 @@ abstract class SassColor extends Value {
|
||||
/// This color's lightness, a percentage between `0` and `100`.
|
||||
num get lightness;
|
||||
|
||||
/// This color's whiteness, a percentage between `0` and `100`.
|
||||
num get whiteness;
|
||||
|
||||
/// This color's blackness, a percentage between `0` and `100`.
|
||||
num get blackness;
|
||||
|
||||
/// This color's alpha channel, between `0` and `1`.
|
||||
num get alpha;
|
||||
|
||||
@ -45,12 +51,22 @@ abstract class SassColor extends Value {
|
||||
factory SassColor.hsl(num hue, num saturation, num lightness, [num alpha]) =
|
||||
internal.SassColor.hsl;
|
||||
|
||||
/// Creates an HWB color.
|
||||
///
|
||||
/// Throws a [RangeError] if [whiteness] or [blackness] aren't between `0` and
|
||||
/// `100`, or if [alpha] isn't between `0` and `1`.
|
||||
factory SassColor.hwb(num hue, num whiteness, num blackness, [num alpha]) =
|
||||
internal.SassColor.hwb;
|
||||
|
||||
/// Changes one or more of this color's RGB channels and returns the result.
|
||||
SassColor changeRgb({int red, int green, int blue, num alpha});
|
||||
|
||||
/// Changes one or more of this color's HSL channels and returns the result.
|
||||
SassColor changeHsl({num hue, num saturation, num lightness, num alpha});
|
||||
|
||||
/// Changes one or more of this color's HWB channels and returns the result.
|
||||
SassColor changeHwb({num hue, num whiteness, num blackness, num alpha});
|
||||
|
||||
/// Returns a new copy of this color with the alpha channel set to [alpha].
|
||||
SassColor changeAlpha(num alpha);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
name: sass
|
||||
version: 1.26.11-dev
|
||||
version: 1.27.0-dev
|
||||
description: A Sass implementation in Dart.
|
||||
author: Sass Team
|
||||
homepage: https://github.com/sass/dart-sass
|
||||
|
@ -28,6 +28,12 @@ void main() {
|
||||
expect(value.lightness, equals(20.392156862745097));
|
||||
});
|
||||
|
||||
test("has HWB channels", () {
|
||||
expect(value.hue, equals(210));
|
||||
expect(value.whiteness, equals(7.0588235294117645));
|
||||
expect(value.blackness, equals(66.27450980392157));
|
||||
});
|
||||
|
||||
test("has an alpha channel", () {
|
||||
expect(value.alpha, equals(1));
|
||||
});
|
||||
@ -114,6 +120,46 @@ void main() {
|
||||
});
|
||||
});
|
||||
|
||||
group("changeHwb()", () {
|
||||
test("changes HWB values", () {
|
||||
expect(value.changeHwb(hue: 120),
|
||||
equals(SassColor.hwb(120, 7.0588235294117645, 66.27450980392157)));
|
||||
expect(value.changeHwb(whiteness: 20),
|
||||
equals(SassColor.hwb(210, 20, 66.27450980392157)));
|
||||
expect(value.changeHwb(blackness: 42),
|
||||
equals(SassColor.hwb(210, 7.0588235294117645, 42)));
|
||||
expect(
|
||||
value.changeHwb(alpha: 0.5),
|
||||
equals(
|
||||
SassColor.hwb(210, 7.0588235294117645, 66.27450980392157, 0.5)));
|
||||
expect(
|
||||
value.changeHwb(
|
||||
hue: 120, whiteness: 42, blackness: 42, alpha: 0.5),
|
||||
equals(SassColor.hwb(120, 42, 42, 0.5)));
|
||||
expect(
|
||||
value.changeHwb(whiteness: 50),
|
||||
equals(SassColor.hwb(210, 43, 57)));
|
||||
});
|
||||
|
||||
test("allows valid values", () {
|
||||
expect(value.changeHwb(whiteness: 0).whiteness, equals(0));
|
||||
expect(value.changeHwb(whiteness: 100).whiteness, equals(60.0));
|
||||
expect(value.changeHwb(blackness: 0).blackness, equals(0));
|
||||
expect(value.changeHwb(blackness: 100).blackness, equals(93.33333333333333));
|
||||
expect(value.changeHwb(alpha: 0).alpha, equals(0));
|
||||
expect(value.changeHwb(alpha: 1).alpha, equals(1));
|
||||
});
|
||||
|
||||
test("disallows invalid values", () {
|
||||
expect(() => value.changeHwb(whiteness: -0.1), throwsRangeError);
|
||||
expect(() => value.changeHwb(whiteness: 100.1), throwsRangeError);
|
||||
expect(() => value.changeHwb(blackness: -0.1), throwsRangeError);
|
||||
expect(() => value.changeHwb(blackness: 100.1), throwsRangeError);
|
||||
expect(() => value.changeHwb(alpha: -0.1), throwsRangeError);
|
||||
expect(() => value.changeHwb(alpha: 1.1), throwsRangeError);
|
||||
});
|
||||
});
|
||||
|
||||
group("changeAlpha()", () {
|
||||
test("changes the alpha value", () {
|
||||
expect(value.changeAlpha(0.5),
|
||||
@ -160,6 +206,11 @@ void main() {
|
||||
expect(value.lightness, equals(42));
|
||||
});
|
||||
|
||||
test("has HWB channels", () {
|
||||
expect(value.whiteness, equals(24.313725490196077));
|
||||
expect(value.blackness, equals(40.3921568627451));
|
||||
});
|
||||
|
||||
test("has an alpha channel", () {
|
||||
expect(value.alpha, equals(1));
|
||||
});
|
||||
@ -167,6 +218,7 @@ void main() {
|
||||
test("equals the same color", () {
|
||||
expect(value, equalsWithHash(SassColor.rgb(0x3E, 0x98, 0x3E)));
|
||||
expect(value, equalsWithHash(SassColor.hsl(120, 42, 42)));
|
||||
expect(value, equalsWithHash(SassColor.hwb(120, 24.313725490196077, 40.3921568627451)));
|
||||
});
|
||||
});
|
||||
|
||||
@ -209,4 +261,51 @@ void main() {
|
||||
expect(() => SassColor.hsl(0, 0, 0, 1.1), throwsRangeError);
|
||||
});
|
||||
});
|
||||
|
||||
group("new SassColor.hwb()", () {
|
||||
SassColor value;
|
||||
setUp(() => value = SassColor.hwb(120, 42, 42));
|
||||
|
||||
test("has RGB channels", () {
|
||||
expect(value.red, equals(0x6B));
|
||||
expect(value.green, equals(0x94));
|
||||
expect(value.blue, equals(0x6B));
|
||||
});
|
||||
|
||||
test("has HSL channels", () {
|
||||
expect(value.hue, equals(120));
|
||||
expect(value.saturation, equals(16.078431372549026));
|
||||
expect(value.lightness, equals(50));
|
||||
});
|
||||
|
||||
test("has HWB channels", () {
|
||||
expect(value.whiteness, equals(41.96078431372549));
|
||||
expect(value.blackness, equals(41.96078431372548));
|
||||
});
|
||||
|
||||
test("has an alpha channel", () {
|
||||
expect(value.alpha, equals(1));
|
||||
});
|
||||
|
||||
test("equals the same color", () {
|
||||
expect(value, equalsWithHash(SassColor.rgb(0x6B, 0x94, 0x6B)));
|
||||
expect(value, equalsWithHash(SassColor.hsl(120, 16, 50)));
|
||||
expect(value, equalsWithHash(SassColor.hwb(120, 42, 42)));
|
||||
});
|
||||
|
||||
test("allows valid values", () {
|
||||
expect(SassColor.hwb(0, 0, 0, 0), equals(parseValue("rgba(255, 0, 0, 0)")));
|
||||
expect(SassColor.hwb(4320, 100, 100, 1),
|
||||
equals(parseValue("grey")));
|
||||
});
|
||||
|
||||
test("disallows invalid values", () {
|
||||
expect(() => SassColor.hwb(0, -0.1, 0, 0), throwsRangeError);
|
||||
expect(() => SassColor.hwb(0, 0, -0.1, 0), throwsRangeError);
|
||||
expect(() => SassColor.hwb(0, 0, 0, -0.1), throwsRangeError);
|
||||
expect(() => SassColor.hwb(0, 100.1, 0, 0), throwsRangeError);
|
||||
expect(() => SassColor.hwb(0, 0, 100.1, 0), throwsRangeError);
|
||||
expect(() => SassColor.hwb(0, 0, 0, 1.1), throwsRangeError);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user