Skip to content

Commit 7fd8dba

Browse files
committed
Refactor implementation and improve package resolution
- Compare algorithms with hsluv-javascript 1.0.2; no numerical changes needed - Deduplicate public API functions via private _to-color() helper - Refactor args-hsl into _normalize-hue and _normalize-percent helpers - Mark internal conversion helpers as private with _ prefix - Add package exports for modern Sass pkg: URL support - Document CLI usage with --load-path and --pkg-importer options - Refresh package-lock.json version to match package.json
1 parent c2f2432 commit 7fd8dba

8 files changed

Lines changed: 124 additions & 95 deletions

File tree

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,24 @@ Emitted css:
4141
}
4242
```
4343

44+
When compiling with the Sass CLI, make sure `node_modules` is in the load path:
45+
46+
```sh
47+
sass --load-path=node_modules styles.scss styles.css
48+
```
49+
50+
Or use the Node package importer with a `pkg:` URL:
51+
52+
```scss
53+
@use "pkg:hsluv-sass" as hsluv;
54+
```
55+
56+
```sh
57+
sass --pkg-importer=node styles.scss styles.css
58+
```
59+
60+
Most build tools add `node_modules` to the Sass load path automatically.
61+
4462
### API
4563

4664
```scss

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@
33
"version": "3.0.0-beta.1",
44
"type": "module",
55
"description": "HSLuv Sass - Human friendly HSL",
6-
"main": "src/_hsluv.scss",
7-
"sass": "src/_hsluv.scss",
6+
"main": "index.scss",
7+
"sass": "index.scss",
8+
"exports": {
9+
".": {
10+
"sass": "./index.scss",
11+
"default": "./src/_hsluv.scss"
12+
}
13+
},
814
"directories": {
915
"test": "test"
1016
},

src/_conversions.scss

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,65 +8,71 @@
88
@use "./conversions/rgb" as rgb;
99

1010
@function args-hsl($hue, $saturation, $lightness) {
11-
$hsl: $hue;
12-
13-
@if ($saturation and $lightness) {
14-
@if math.is-unitless($hue) {
15-
$hue: $hue * 1deg;
16-
}
17-
@if math.unit($saturation) == "%" {
18-
$saturation: math.div($saturation, 1%);
19-
}
20-
@if math.unit($lightness) == "%" {
21-
$lightness: math.div($lightness, 1%);
22-
}
23-
24-
$hsl: (
25-
h: $hue,
26-
s: $saturation,
27-
l: $lightness,
11+
@if $saturation and $lightness {
12+
@return (
13+
"h": _normalize-hue($hue),
14+
"s": _normalize-percent($saturation),
15+
"l": _normalize-percent($lightness)
2816
);
29-
} @else if (meta.type-of($value: $hsl) != map) {
17+
}
18+
19+
@if meta.type-of($hue) != map {
3020
@error "hsluv function with a single parameter must be called with a map of the form (h: $hue, s: $saturation, l: $lightness)";
31-
} @else if not (map.get($hsl, h) and map.get($hsl, s) and map.get($hsl, l)) {
21+
}
22+
23+
@if not
24+
map.has-key($hue, "h") or not
25+
map.has-key($hue, "s") or not
26+
map.has-key($hue, "l")
27+
{
3228
@error "hsluv function with a single parameter must be called with a map of the form (h: $hue, s: $saturation, l: $lightness)";
3329
}
3430

35-
@return $hsl;
31+
@return $hue;
32+
}
33+
34+
@function _normalize-hue($hue) {
35+
@if math.is-unitless($hue) {
36+
@return $hue * 1deg;
37+
}
38+
@return $hue;
39+
}
40+
41+
@function _normalize-percent($value) {
42+
@if math.unit($value) == "%" {
43+
@return math.div($value, 1%);
44+
}
45+
@return $value;
3646
}
3747

3848
@function hsluv-rgb($hsluv) {
3949
$lch: lch.from-hsluv($hsluv);
4050
$luv: luv.from-lch($lch);
4151
$xyz: xyz.from-luv($luv);
42-
$rgb: rgb.from-xyz($xyz);
4352

44-
@return $rgb;
53+
@return rgb.from-xyz($xyz);
4554
}
4655

4756
@function hpluv-rgb($hpluv) {
4857
$lch: lch.from-hpluv($hpluv);
4958
$luv: luv.from-lch($lch);
5059
$xyz: xyz.from-luv($luv);
51-
$rgb: rgb.from-xyz($xyz);
5260

53-
@return $rgb;
61+
@return rgb.from-xyz($xyz);
5462
}
5563

5664
@function rgb-hsluv($rgb) {
5765
$xyz: rgb.to-xyz($rgb);
5866
$luv: xyz.to-luv($xyz);
5967
$lch: luv.to-lch($luv);
60-
$hsluv: lch.to-hsluv($lch);
6168

62-
@return $hsluv;
69+
@return lch.to-hsluv($lch);
6370
}
6471

6572
@function rgb-hpluv($rgb) {
6673
$xyz: rgb.to-xyz($rgb);
6774
$luv: xyz.to-luv($xyz);
6875
$lch: luv.to-lch($luv);
69-
$hpluv: lch.to-hpluv($lch);
7076

71-
@return $hpluv;
77+
@return lch.to-hpluv($lch);
7278
}

src/_hsluv.scss

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,42 @@
11
@use "sass:map";
22

33
@use "./conversions" as conv;
4-
@use "./conversions/xyz" as xyz;
54

6-
@function hsluv($hue, $saturation: null, $lightness: null) {
7-
$hsluv: conv.args-hsl($hue, $saturation, $lightness);
8-
$rgb: conv.hsluv-rgb($hsluv);
5+
// Convert an RGB map to a Sass color, optionally with alpha.
6+
@function _to-color($rgb, $alpha: 1) {
7+
$r: map.get($rgb, "r");
8+
$g: map.get($rgb, "g");
9+
$b: map.get($rgb, "b");
10+
11+
@if $alpha == 1 {
12+
@return rgb($r, $g, $b);
13+
}
914

10-
@return rgb(map.get($rgb, "r"), map.get($rgb, "g"), map.get($rgb, "b"));
15+
@return rgba($r, $g, $b, $alpha);
1116
}
1217

13-
@function hpluv($hue, $saturation: null, $lightness: null) {
14-
$hpluv: conv.args-hsl($hue, $saturation, $lightness);
15-
$rgb: conv.hpluv-rgb($hpluv);
18+
@function hsluv($hue, $saturation: null, $lightness: null) {
19+
@return _to-color(
20+
conv.hsluv-rgb(conv.args-hsl($hue, $saturation, $lightness))
21+
);
22+
}
1623

17-
@return rgb(map.get($rgb, "r"), map.get($rgb, "g"), map.get($rgb, "b"));
24+
@function hpluv($hue, $saturation: null, $lightness: null) {
25+
@return _to-color(
26+
conv.hpluv-rgb(conv.args-hsl($hue, $saturation, $lightness))
27+
);
1828
}
1929

2030
@function hsluva($hue, $saturation: null, $lightness: null, $alpha: 1) {
21-
$hsluv: conv.args-hsl($hue, $saturation, $lightness);
22-
$rgb: conv.hsluv-rgb($hsluv);
23-
24-
@return rgba(
25-
map.get($rgb, "r"),
26-
map.get($rgb, "g"),
27-
map.get($rgb, "b"),
31+
@return _to-color(
32+
conv.hsluv-rgb(conv.args-hsl($hue, $saturation, $lightness)),
2833
$alpha
2934
);
3035
}
3136

3237
@function hpluva($hue, $saturation: null, $lightness: null, $alpha: 1) {
33-
$hpluv: conv.args-hsl($hue, $saturation, $lightness);
34-
$rgb: conv.hpluv-rgb($hpluv);
35-
36-
@return rgba(
37-
map.get($rgb, "r"),
38-
map.get($rgb, "g"),
39-
map.get($rgb, "b"),
38+
@return _to-color(
39+
conv.hpluv-rgb(conv.args-hsl($hue, $saturation, $lightness)),
4040
$alpha
4141
);
4242
}

src/conversions/_lch.scss

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
$c: 0;
1313
// white and black: disambiguate chroma
1414
@if not($l > 99.9999999 or $l < 0.00000001) {
15-
$max: max-chroma-for-l-h($l, $h);
15+
$max: _max-chroma-for-l-h($l, $h);
1616
$c: math.div($max, 100) * $s;
1717
}
1818

@@ -27,7 +27,7 @@
2727
$c: 0;
2828
// white and black: disambiguate chroma
2929
@if not($l > 99.9999999 or $l < 0.00000001) {
30-
$max: max-safe-chroma-for-l($l);
30+
$max: _max-safe-chroma-for-l($l);
3131
$c: math.div($max, 100) * $s;
3232
}
3333
@return ("l": $l, "c": $c, "h": $h);
@@ -41,7 +41,7 @@
4141
$s: 0;
4242
// white and black: disambiguate saturation
4343
@if not($l > 99.9999999 or $l < 0.00000001) {
44-
$max: max-chroma-for-l-h($l, $h);
44+
$max: _max-chroma-for-l-h($l, $h);
4545
$s: math.div($c, $max) * 100;
4646
}
4747
@return ("h": $h, "s": $s, "l": $l);
@@ -55,24 +55,24 @@
5555
$s: 0;
5656
// white and black: disambiguate saturation
5757
@if not($l > 99.9999999 or $l < 0.00000001) {
58-
$max: max-safe-chroma-for-l($l);
58+
$max: _max-safe-chroma-for-l($l);
5959
$s: math.div($c, $max) * 100;
6060
}
6161
@return ("h": $h, "s": $s, "l": $l);
6262
}
6363

6464
// For a given lightness and hue, return the maximum chroma that fits in
6565
// the RGB gamut.
66-
// @param {number[][2]} $l
66+
// @param {number} $l
6767
// @param {number} $h
6868
// @return {number}
69-
@function max-chroma-for-l-h($l, $h) {
69+
@function _max-chroma-for-l-h($l, $h) {
7070
$lengths: ();
7171

72-
@each $line in get-bounds($l) {
73-
$l: length-of-ray-until-intersect($h, $line);
74-
@if $l != null {
75-
$lengths: list.append($lengths, $l);
72+
@each $line in _get-bounds($l) {
73+
$length: _length-of-ray-until-intersect($h, $line);
74+
@if $length != null {
75+
$lengths: list.append($lengths, $length);
7676
}
7777
}
7878

@@ -82,17 +82,17 @@
8282
// For given lightness, returns the maximum chroma. Keeping the chroma value
8383
// below this number will ensure that for any hue, the color is within the RGB
8484
// gamut.
85-
// @param {number[][2]} $l
85+
// @param {number} $l
8686
// @return {number}
87-
@function max-safe-chroma-for-l($l) {
87+
@function _max-safe-chroma-for-l($l) {
8888
$lengths: ();
8989

90-
@each $point in get-bounds($l) {
90+
@each $point in _get-bounds($l) {
9191
$m1: list.nth($point, 1);
9292
$b1: list.nth($point, 2);
93-
// x where line intersects with perpendicular running though (0, 0)
94-
$x: intersect-line-line(($m1, $b1), (math.div(-1, $m1), 0));
95-
$lengths: list.append($lengths, distance-from-pole(($x, $b1 + $x * $m1)));
93+
// x where line intersects with perpendicular running through (0, 0)
94+
$x: _intersect-line-line(($m1, $b1), (math.div(-1, $m1), 0));
95+
$lengths: list.append($lengths, _distance-from-pole(($x, $b1 + $x * $m1)));
9696
}
9797

9898
@return math.min($lengths...);
@@ -103,18 +103,20 @@
103103
// push a value out of the RGB gamut
104104
// @param {number} $l
105105
// @return {number[][2]}
106-
@function get-bounds($l) {
106+
@function _get-bounds($l) {
107107
$sub1: math.div(math.pow($l + 16, 3), 1560896);
108108
$sub2: $sub1;
109109
@if $sub1 <= const.$epsilon {
110110
$sub2: math.div($l, const.$kappa);
111111
}
112+
112113
$ret: ();
113114
@each $channel in (r, g, b) {
114115
$m_: map.get(const.$m, $channel);
115116
$m1: list.nth($m_, 1);
116117
$m2: list.nth($m_, 2);
117118
$m3: list.nth($m_, 3);
119+
118120
@for $t from 0 through 1 {
119121
$top1: (284517 * $m1 - 94839 * $m3) * $sub2;
120122
$top2: (838422 * $m3 + 769860 * $m2 + 731718 * $m1) *
@@ -138,7 +140,7 @@
138140
// @param {number} $theta
139141
// @param {number[2]} $line
140142
// @return {number?}
141-
@function length-of-ray-until-intersect($theta, $line) {
143+
@function _length-of-ray-until-intersect($theta, $line) {
142144
// theta -- angle of ray starting at (0, 0)
143145
// m, b -- slope and intercept of line
144146
// x1, y1 -- coordinates of intersection
@@ -149,7 +151,6 @@
149151
// len * cos(theta) = x1
150152
// len * sin(theta) = y1
151153
//
152-
//
153154
// b + m * (len * cos(theta)) = len * sin(theta)
154155
// b = len * sin(hrad) - m * len * cos(theta)
155156
// b = len * (sin(hrad) - m * cos(hrad))
@@ -167,7 +168,7 @@
167168

168169
// @param {number[2]} $point
169170
// @return {number}
170-
@function distance-from-pole($point) {
171+
@function _distance-from-pole($point) {
171172
@return math.sqrt(
172173
math.pow(list.nth($point, 1), 2) + math.pow(list.nth($point, 2), 2)
173174
);
@@ -176,7 +177,7 @@
176177
// @param {number[2]} $line1
177178
// @param {number[2]} $line2
178179
// @return {number}
179-
@function intersect-line-line($line1, $line2) {
180+
@function _intersect-line-line($line1, $line2) {
180181
@return math.div(
181182
list.nth($line1, 2) - list.nth($line2, 2),
182183
list.nth($line2, 1) - list.nth($line1, 1)

0 commit comments

Comments
 (0)