sass-embedded 1.79.2 → 1.79.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/exe/sass +1 -9
  3. data/ext/sass/Rakefile +48 -15
  4. data/ext/sass/embedded_sass_pb.rb +1 -1
  5. data/ext/sass/package.json +1 -1
  6. data/lib/sass/compiler/connection.rb +1 -9
  7. data/lib/sass/compiler/host/protofier.rb +17 -55
  8. data/lib/sass/elf.rb +4 -4
  9. data/lib/sass/embedded/version.rb +1 -1
  10. data/lib/sass/value/color/channel.rb +79 -0
  11. data/lib/sass/value/color/conversions.rb +473 -0
  12. data/lib/sass/value/color/gamut_map_method/clip.rb +45 -0
  13. data/lib/sass/value/color/gamut_map_method/local_minde.rb +94 -0
  14. data/lib/sass/value/color/gamut_map_method.rb +45 -0
  15. data/lib/sass/value/color/interpolation_method.rb +51 -0
  16. data/lib/sass/value/color/space/a98_rgb.rb +57 -0
  17. data/lib/sass/value/color/space/display_p3.rb +57 -0
  18. data/lib/sass/value/color/space/hsl.rb +65 -0
  19. data/lib/sass/value/color/space/hwb.rb +70 -0
  20. data/lib/sass/value/color/space/lab.rb +77 -0
  21. data/lib/sass/value/color/space/lch.rb +53 -0
  22. data/lib/sass/value/color/space/lms.rb +129 -0
  23. data/lib/sass/value/color/space/oklab.rb +66 -0
  24. data/lib/sass/value/color/space/oklch.rb +54 -0
  25. data/lib/sass/value/color/space/prophoto_rgb.rb +59 -0
  26. data/lib/sass/value/color/space/rec2020.rb +69 -0
  27. data/lib/sass/value/color/space/rgb.rb +52 -0
  28. data/lib/sass/value/color/space/srgb.rb +140 -0
  29. data/lib/sass/value/color/space/srgb_linear.rb +72 -0
  30. data/lib/sass/value/color/space/utils.rb +86 -0
  31. data/lib/sass/value/color/space/xyz_d50.rb +100 -0
  32. data/lib/sass/value/color/space/xyz_d65.rb +57 -0
  33. data/lib/sass/value/color/space.rb +198 -0
  34. data/lib/sass/value/color.rb +537 -162
  35. data/lib/sass/value/fuzzy_math.rb +23 -19
  36. data/lib/sass/value/number.rb +1 -1
  37. data/lib/sass/value/string.rb +1 -1
  38. metadata +29 -5
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/interpolation_method.dart
7
+ class InterpolationMethod
8
+ # @return [Space]
9
+ attr_reader :space
10
+
11
+ # @return [Symbol, nil]
12
+ attr_reader :hue
13
+
14
+ # @param space [Space]
15
+ # @param hue [Symbol]
16
+ def initialize(space, hue = nil)
17
+ @space = space
18
+ @hue = if space.polar?
19
+ hue.nil? ? :shorter : hue
20
+ end
21
+
22
+ return unless !space.polar? && !hue.nil?
23
+
24
+ raise Sass::ScriptError,
25
+ "Hue interpolation method may not be set for rectangular color space #{space.name}."
26
+ end
27
+ end
28
+
29
+ private_constant :InterpolationMethod
30
+
31
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/interpolation_method.dart
32
+ module HueInterpolationMethod
33
+ class << self
34
+ # @param name [::String]
35
+ # @param argument_name [::String]
36
+ # @return [Symbol]
37
+ def from_name(name, argument_name = nil)
38
+ case name
39
+ when 'decreasing', 'increasing', 'longer', 'shorter'
40
+ name.to_sym
41
+ else
42
+ raise Sass::ScriptError.new("Unknown hue interpolation method \"#{name}\".", argument_name)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ private_constant :HueInterpolationMethod
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ module Space
7
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/space/a98_rgb.dart
8
+ class A98Rgb
9
+ include Space
10
+
11
+ def bounded?
12
+ true
13
+ end
14
+
15
+ def initialize
16
+ super('a98-rgb', Utils::RGB_CHANNELS)
17
+ end
18
+
19
+ def to_linear(channel)
20
+ (channel <=> 0) * (channel.abs**(563 / 256.0))
21
+ end
22
+
23
+ def from_linear(channel)
24
+ (channel <=> 0) * (channel.abs**(256 / 563.0))
25
+ end
26
+
27
+ private
28
+
29
+ def transformation_matrix(dest)
30
+ case dest
31
+ when DISPLAY_P3
32
+ Conversions::LINEAR_A98_RGB_TO_LINEAR_DISPLAY_P3
33
+ when LMS
34
+ Conversions::LINEAR_A98_RGB_TO_LMS
35
+ when PROPHOTO_RGB
36
+ Conversions::LINEAR_A98_RGB_TO_LINEAR_PROPHOTO_RGB
37
+ when REC2020
38
+ Conversions::LINEAR_A98_RGB_TO_LINEAR_REC2020
39
+ when RGB, SRGB, SRGB_LINEAR
40
+ Conversions::LINEAR_A98_RGB_TO_LINEAR_SRGB
41
+ when XYZ_D50
42
+ Conversions::LINEAR_A98_RGB_TO_XYZ_D50
43
+ when XYZ_D65
44
+ Conversions::LINEAR_A98_RGB_TO_XYZ_D65
45
+ else
46
+ super
47
+ end
48
+ end
49
+ end
50
+
51
+ private_constant :A98Rgb
52
+
53
+ A98_RGB = A98Rgb.new
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ module Space
7
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/space/display_p3.dart
8
+ class DisplayP3
9
+ include Space
10
+
11
+ def bounded?
12
+ true
13
+ end
14
+
15
+ def initialize
16
+ super('display-p3', Utils::RGB_CHANNELS)
17
+ end
18
+
19
+ def to_linear(channel)
20
+ Utils.srgb_and_display_p3_to_linear(channel)
21
+ end
22
+
23
+ def from_linear(channel)
24
+ Utils.srgb_and_display_p3_from_linear(channel)
25
+ end
26
+
27
+ private
28
+
29
+ def transformation_matrix(dest)
30
+ case dest
31
+ when A98_RGB
32
+ Conversions::LINEAR_DISPLAY_P3_TO_LINEAR_A98_RGB
33
+ when LMS
34
+ Conversions::LINEAR_DISPLAY_P3_TO_LMS
35
+ when PROPHOTO_RGB
36
+ Conversions::LINEAR_DISPLAY_P3_TO_LINEAR_PROPHOTO_RGB
37
+ when REC2020
38
+ Conversions::LINEAR_DISPLAY_P3_TO_LINEAR_REC2020
39
+ when RGB, SRGB, SRGB_LINEAR
40
+ Conversions::LINEAR_DISPLAY_P3_TO_LINEAR_SRGB
41
+ when XYZ_D50
42
+ Conversions::LINEAR_DISPLAY_P3_TO_XYZ_D50
43
+ when XYZ_D65
44
+ Conversions::LINEAR_DISPLAY_P3_TO_XYZ_D65
45
+ else
46
+ super
47
+ end
48
+ end
49
+ end
50
+
51
+ private_constant :DisplayP3
52
+
53
+ DISPLAY_P3 = DisplayP3.new
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ module Space
7
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/space/hsl.dart
8
+ class Hsl
9
+ include Space
10
+
11
+ def bounded?
12
+ true
13
+ end
14
+
15
+ def legacy?
16
+ true
17
+ end
18
+
19
+ def polar?
20
+ true
21
+ end
22
+
23
+ def initialize
24
+ super('hsl', [
25
+ Utils::HUE_CHANNEL,
26
+ LinearChannel.new('saturation', 0, 100, requires_percent: true, lower_clamped: true).freeze,
27
+ LinearChannel.new('lightness', 0, 100, requires_percent: true).freeze
28
+ ].freeze)
29
+ end
30
+
31
+ def convert(dest, hue, saturation, lightness, alpha)
32
+ missing_lightness = lightness.nil?
33
+ missing_chroma = saturation.nil?
34
+ missing_hue = hue.nil?
35
+
36
+ hue = ((hue.nil? ? 0 : hue) % 360) / 30.0
37
+ saturation = (saturation.nil? ? 0 : saturation) / 100.0
38
+ lightness = (lightness.nil? ? 0 : lightness) / 100.0
39
+
40
+ a = saturation * [lightness, 1 - lightness].min
41
+ f = lambda do |n|
42
+ k = (n + hue) % 12
43
+ lightness - (a * [-1, [k - 3, 9 - k, 1].min].max)
44
+ end
45
+
46
+ SRGB.convert(
47
+ dest,
48
+ f.call(0),
49
+ f.call(8),
50
+ f.call(4),
51
+ alpha,
52
+ missing_lightness:,
53
+ missing_chroma:,
54
+ missing_hue:
55
+ )
56
+ end
57
+ end
58
+
59
+ private_constant :Hsl
60
+
61
+ HSL = Hsl.new
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ module Space
7
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/space/hwb.dart
8
+ class Hwb
9
+ include Space
10
+
11
+ def bounded?
12
+ true
13
+ end
14
+
15
+ def legacy?
16
+ true
17
+ end
18
+
19
+ def polar?
20
+ true
21
+ end
22
+
23
+ def initialize
24
+ super('hwb', [
25
+ Utils::HUE_CHANNEL,
26
+ LinearChannel.new('whiteness', 0, 100, requires_percent: true).freeze,
27
+ LinearChannel.new('blackness', 0, 100, requires_percent: true).freeze
28
+ ].freeze)
29
+ end
30
+
31
+ def convert(dest, hue, whiteness, blackness, alpha)
32
+ missing_hue = hue.nil?
33
+
34
+ hue = ((hue.nil? ? 0 : hue) % 360) / 30.0
35
+ whiteness = (whiteness.nil? ? 0 : whiteness) / 100.0
36
+ blackness = (blackness.nil? ? 0 : blackness) / 100.0
37
+
38
+ sum = whiteness + blackness
39
+ if sum > 1
40
+ gray = whiteness / sum
41
+ SRGB.convert(dest,
42
+ gray,
43
+ gray,
44
+ gray,
45
+ alpha,
46
+ missing_hue:)
47
+ else
48
+ f = lambda do |n|
49
+ k = (n + hue) % 12
50
+ 0.5 - ([-1, [k - 3, 9 - k, 1].min].max / 2.0)
51
+ end
52
+
53
+ factor = 1 - sum
54
+ SRGB.convert(dest,
55
+ (f.call(0) * factor) + whiteness,
56
+ (f.call(8) * factor) + whiteness,
57
+ (f.call(4) * factor) + whiteness,
58
+ alpha,
59
+ missing_hue:)
60
+ end
61
+ end
62
+ end
63
+
64
+ private_constant :Hwb
65
+
66
+ HWB = Hwb.new
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ module Space
7
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/space/lab.dart
8
+ class Lab
9
+ include Space
10
+
11
+ def bounded?
12
+ false
13
+ end
14
+
15
+ def initialize
16
+ super('lab', [
17
+ LinearChannel.new('lightness', 0, 100, lower_clamped: true, upper_clamped: true).freeze,
18
+ LinearChannel.new('a', -125, 125).freeze,
19
+ LinearChannel.new('b', -125, 125).freeze
20
+ ].freeze)
21
+ end
22
+
23
+ def convert(dest, lightness, a, b, alpha, # rubocop:disable Naming/MethodParameterName
24
+ missing_chroma: false, missing_hue: false)
25
+ case dest
26
+ when LAB
27
+ powerless_ab = lightness.nil? || FuzzyMath.equals(lightness, 0)
28
+ Color.send(
29
+ :_for_space,
30
+ dest,
31
+ lightness,
32
+ a.nil? || powerless_ab ? nil : a,
33
+ b.nil? || powerless_ab ? nil : b,
34
+ alpha
35
+ )
36
+ when LCH
37
+ Utils.lab_to_lch(dest, lightness, a, b, alpha)
38
+ else
39
+ missing_lightness = lightness.nil?
40
+ lightness = 0 if missing_lightness
41
+
42
+ f1 = (lightness + 16) / 116.0
43
+
44
+ XYZ_D50.convert(
45
+ dest,
46
+ _convert_f_to_x_or_z(((a.nil? ? 0 : a) / 500.0) + f1) * Conversions::D50[0],
47
+ (if lightness > Utils::LAB_KAPPA * Utils::LAB_EPSILON
48
+ (((lightness + 16) / 116.0)**3)
49
+ else
50
+ lightness / Utils::LAB_KAPPA
51
+ end) * Conversions::D50[1],
52
+ _convert_f_to_x_or_z(f1 - ((b.nil? ? 0 : b) / 200.0)) * Conversions::D50[2],
53
+ alpha,
54
+ missing_lightness:,
55
+ missing_chroma:,
56
+ missing_hue:,
57
+ missing_a: a.nil?,
58
+ missing_b: b.nil?
59
+ )
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def _convert_f_to_x_or_z(component)
66
+ cubed = component**3
67
+ cubed > Utils::LAB_EPSILON ? cubed : ((116 * component) - 16) / Utils::LAB_KAPPA
68
+ end
69
+ end
70
+
71
+ private_constant :Lab
72
+
73
+ LAB = Lab.new
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ module Space
7
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/space/lch.dart
8
+ class Lch
9
+ include Space
10
+
11
+ def bounded?
12
+ false
13
+ end
14
+
15
+ def polar?
16
+ true
17
+ end
18
+
19
+ def initialize
20
+ super('lch', [
21
+ LinearChannel.new('lightness', 0, 100, lower_clamped: true, upper_clamped: true).freeze,
22
+ LinearChannel.new('chroma', 0, 150, lower_clamped: true).freeze,
23
+ Utils::HUE_CHANNEL
24
+ ].freeze)
25
+ end
26
+
27
+ def convert(dest, lightness, chroma, hue, alpha)
28
+ missing_chroma = chroma.nil?
29
+ missing_hue = hue.nil?
30
+
31
+ chroma = 0 if missing_chroma
32
+ hue = 0 if missing_hue
33
+
34
+ hue_radians = hue * Math::PI / 180
35
+ LAB.convert(
36
+ dest,
37
+ lightness,
38
+ chroma * Math.cos(hue_radians),
39
+ chroma * Math.sin(hue_radians),
40
+ alpha,
41
+ missing_chroma:,
42
+ missing_hue:
43
+ )
44
+ end
45
+ end
46
+
47
+ private_constant :Lch
48
+
49
+ LCH = Lch.new
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ module Space
7
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/space/lms.dart
8
+ class Lms
9
+ include Space
10
+
11
+ def bounded?
12
+ false
13
+ end
14
+
15
+ def initialize
16
+ super('lms', [
17
+ LinearChannel.new('long', 0, 1).freeze,
18
+ LinearChannel.new('medium', 0, 1).freeze,
19
+ LinearChannel.new('short', 0, 1).freeze
20
+ ].freeze)
21
+ end
22
+
23
+ def convert(dest, long, medium, short, alpha,
24
+ missing_lightness: false,
25
+ missing_chroma: false,
26
+ missing_hue: false,
27
+ missing_a: false,
28
+ missing_b: false)
29
+ case dest
30
+ when OKLAB
31
+ long_scaled = Math.cbrt(long.nil? ? 0 : long)
32
+ medium_scaled = Math.cbrt(medium.nil? ? 0 : medium)
33
+ short_scaled = Math.cbrt(short.nil? ? 0 : short)
34
+
35
+ Color.send(
36
+ :_for_space,
37
+ dest,
38
+ unless missing_lightness
39
+ (Conversions::LMS_TO_OKLAB[0] * long_scaled) +
40
+ (Conversions::LMS_TO_OKLAB[1] * medium_scaled) +
41
+ (Conversions::LMS_TO_OKLAB[2] * short_scaled)
42
+ end,
43
+ unless missing_a
44
+ (Conversions::LMS_TO_OKLAB[3] * long_scaled) +
45
+ (Conversions::LMS_TO_OKLAB[4] * medium_scaled) +
46
+ (Conversions::LMS_TO_OKLAB[5] * short_scaled)
47
+ end,
48
+ unless missing_b
49
+ (Conversions::LMS_TO_OKLAB[6] * long_scaled) +
50
+ (Conversions::LMS_TO_OKLAB[7] * medium_scaled) +
51
+ (Conversions::LMS_TO_OKLAB[8] * short_scaled)
52
+ end,
53
+ alpha
54
+ )
55
+ when OKLCH
56
+ long_scaled = Math.cbrt(long.nil? ? 0 : long)
57
+ medium_scaled = Math.cbrt(medium.nil? ? 0 : medium)
58
+ short_scaled = Math.cbrt(short.nil? ? 0 : short)
59
+
60
+ Utils.lab_to_lch(
61
+ dest,
62
+ unless missing_lightness
63
+ (Conversions::LMS_TO_OKLAB[0] * long_scaled) +
64
+ (Conversions::LMS_TO_OKLAB[1] * medium_scaled) +
65
+ (Conversions::LMS_TO_OKLAB[2] * short_scaled)
66
+ end,
67
+ unless missing_a
68
+ (Conversions::LMS_TO_OKLAB[3] * long_scaled) +
69
+ (Conversions::LMS_TO_OKLAB[4] * medium_scaled) +
70
+ (Conversions::LMS_TO_OKLAB[5] * short_scaled)
71
+ end,
72
+ unless missing_b
73
+ (Conversions::LMS_TO_OKLAB[6] * long_scaled) +
74
+ (Conversions::LMS_TO_OKLAB[7] * medium_scaled) +
75
+ (Conversions::LMS_TO_OKLAB[8] * short_scaled)
76
+ end,
77
+ alpha
78
+ )
79
+ else
80
+ convert_linear(dest, long, medium, short, alpha,
81
+ missing_lightness:,
82
+ missing_chroma:,
83
+ missing_hue:,
84
+ missing_a:,
85
+ missing_b:)
86
+ end
87
+ end
88
+
89
+ def to_linear(channel)
90
+ channel
91
+ end
92
+
93
+ def from_linear(channel)
94
+ channel
95
+ end
96
+
97
+ private
98
+
99
+ def transformation_matrix(dest)
100
+ case dest
101
+ when A98_RGB
102
+ Conversions::LMS_TO_LINEAR_A98_RGB
103
+ when DISPLAY_P3
104
+ Conversions::LMS_TO_LINEAR_DISPLAY_P3
105
+ when PROPHOTO_RGB
106
+ Conversions::LMS_TO_LINEAR_PROPHOTO_RGB
107
+ when REC2020
108
+ Conversions::LMS_TO_LINEAR_REC2020
109
+ when RGB, SRGB, SRGB_LINEAR
110
+ Conversions::LMS_TO_LINEAR_SRGB
111
+ when XYZ_D50
112
+ Conversions::LMS_TO_XYZ_D50
113
+ when XYZ_D65
114
+ Conversions::LMS_TO_XYZ_D65
115
+ else
116
+ super
117
+ end
118
+ end
119
+ end
120
+
121
+ private_constant :Lms
122
+
123
+ LMS = Lms.new
124
+
125
+ private_constant :LMS
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ module Space
7
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/space/oklab.dart
8
+ class Oklab
9
+ include Space
10
+
11
+ def bounded?
12
+ false
13
+ end
14
+
15
+ def initialize
16
+ super('oklab', [
17
+ LinearChannel.new('lightness', 0, 1,
18
+ conventionally_percent: true, lower_clamped: true, upper_clamped: true).freeze,
19
+ LinearChannel.new('a', -0.4, 0.4).freeze,
20
+ LinearChannel.new('b', -0.4, 0.4).freeze
21
+ ].freeze)
22
+ end
23
+
24
+ def convert(dest, lightness, a, b, alpha, # rubocop:disable Naming/MethodParameterName
25
+ missing_chroma: false, missing_hue: false)
26
+ case dest
27
+ when OKLCH
28
+ Utils.lab_to_lch(dest, lightness, a, b, alpha)
29
+ else
30
+ missing_lightness = lightness.nil?
31
+ missing_a = a.nil?
32
+ missing_b = b.nil?
33
+
34
+ lightness = 0 if missing_lightness
35
+ a = 0 if missing_a
36
+ b = 0 if missing_b
37
+
38
+ LMS.convert(
39
+ dest,
40
+ ((Conversions::OKLAB_TO_LMS[0] * lightness) +
41
+ (Conversions::OKLAB_TO_LMS[1] * a) +
42
+ (Conversions::OKLAB_TO_LMS[2] * b))**3,
43
+ ((Conversions::OKLAB_TO_LMS[3] * lightness) +
44
+ (Conversions::OKLAB_TO_LMS[4] * a) +
45
+ (Conversions::OKLAB_TO_LMS[5] * b))**3,
46
+ ((Conversions::OKLAB_TO_LMS[6] * lightness) +
47
+ (Conversions::OKLAB_TO_LMS[7] * a) +
48
+ (Conversions::OKLAB_TO_LMS[8] * b))**3,
49
+ alpha,
50
+ missing_lightness:,
51
+ missing_chroma:,
52
+ missing_hue:,
53
+ missing_a:,
54
+ missing_b:
55
+ )
56
+ end
57
+ end
58
+ end
59
+
60
+ private_constant :Oklab
61
+
62
+ OKLAB = Oklab.new
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sass
4
+ module Value
5
+ class Color
6
+ module Space
7
+ # @see https://github.com/sass/dart-sass/blob/main/lib/src/value/color/space/oklch.dart
8
+ class Oklch
9
+ include Space
10
+
11
+ def bounded?
12
+ false
13
+ end
14
+
15
+ def polar?
16
+ true
17
+ end
18
+
19
+ def initialize
20
+ super('oklch', [
21
+ LinearChannel.new('lightness', 0, 1,
22
+ conventionally_percent: true, lower_clamped: true, upper_clamped: true).freeze,
23
+ LinearChannel.new('chroma', 0, 0.4, lower_clamped: true).freeze,
24
+ Utils::HUE_CHANNEL
25
+ ].freeze)
26
+ end
27
+
28
+ def convert(dest, lightness, chroma, hue, alpha)
29
+ missing_chroma = chroma.nil?
30
+ missing_hue = hue.nil?
31
+
32
+ chroma = 0 if missing_chroma
33
+ hue = 0 if missing_hue
34
+
35
+ hue_radians = hue * Math::PI / 180
36
+ OKLAB.convert(
37
+ dest,
38
+ lightness,
39
+ chroma * Math.cos(hue_radians),
40
+ chroma * Math.sin(hue_radians),
41
+ alpha,
42
+ missing_chroma:,
43
+ missing_hue:
44
+ )
45
+ end
46
+ end
47
+
48
+ private_constant :Oklch
49
+
50
+ OKLCH = Oklch.new
51
+ end
52
+ end
53
+ end
54
+ end