sass-embedded 1.54.6-x86_64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +42 -0
- data/ext/sass/embedded.rb +9 -0
- data/ext/sass/embedded_sass_pb.rb +349 -0
- data/ext/sass/sass_embedded/dart-sass-embedded +17 -0
- data/ext/sass/sass_embedded/src/LICENSE +1476 -0
- data/ext/sass/sass_embedded/src/dart +0 -0
- data/ext/sass/sass_embedded/src/dart-sass-embedded.snapshot +0 -0
- data/lib/sass/compile_error.rb +28 -0
- data/lib/sass/compile_result.rb +23 -0
- data/lib/sass/embedded/async.rb +65 -0
- data/lib/sass/embedded/channel.rb +61 -0
- data/lib/sass/embedded/compiler.rb +60 -0
- data/lib/sass/embedded/dispatcher.rb +90 -0
- data/lib/sass/embedded/host/function_registry.rb +90 -0
- data/lib/sass/embedded/host/importer_registry.rb +108 -0
- data/lib/sass/embedded/host/logger_registry.rb +50 -0
- data/lib/sass/embedded/host/value_protofier.rb +241 -0
- data/lib/sass/embedded/host.rb +141 -0
- data/lib/sass/embedded/protofier.rb +78 -0
- data/lib/sass/embedded/structifier.rb +36 -0
- data/lib/sass/embedded/varint.rb +35 -0
- data/lib/sass/embedded/version.rb +7 -0
- data/lib/sass/embedded.rb +245 -0
- data/lib/sass/logger/silent.rb +26 -0
- data/lib/sass/logger/source_location.rb +21 -0
- data/lib/sass/logger/source_span.rb +27 -0
- data/lib/sass/script_error.rb +6 -0
- data/lib/sass/value/argument_list.rb +30 -0
- data/lib/sass/value/boolean.rb +52 -0
- data/lib/sass/value/color.rb +253 -0
- data/lib/sass/value/function.rb +54 -0
- data/lib/sass/value/fuzzy_math.rb +81 -0
- data/lib/sass/value/list.rb +79 -0
- data/lib/sass/value/map.rb +71 -0
- data/lib/sass/value/null.rb +48 -0
- data/lib/sass/value/number/unit.rb +186 -0
- data/lib/sass/value/number.rb +358 -0
- data/lib/sass/value/string.rb +55 -0
- data/lib/sass/value.rb +132 -0
- data/lib/sass-embedded.rb +4 -0
- metadata +186 -0
@@ -0,0 +1,245 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../ext/sass/embedded'
|
4
|
+
require_relative '../../ext/sass/embedded_sass_pb'
|
5
|
+
require_relative 'compile_error'
|
6
|
+
require_relative 'compile_result'
|
7
|
+
require_relative 'embedded/async'
|
8
|
+
require_relative 'embedded/channel'
|
9
|
+
require_relative 'embedded/compiler'
|
10
|
+
require_relative 'embedded/dispatcher'
|
11
|
+
require_relative 'embedded/host'
|
12
|
+
require_relative 'embedded/protofier'
|
13
|
+
require_relative 'embedded/structifier'
|
14
|
+
require_relative 'embedded/varint'
|
15
|
+
require_relative 'embedded/version'
|
16
|
+
require_relative 'logger/silent'
|
17
|
+
require_relative 'logger/source_location'
|
18
|
+
require_relative 'logger/source_span'
|
19
|
+
require_relative 'value'
|
20
|
+
|
21
|
+
# The Sass module.
|
22
|
+
#
|
23
|
+
# This communicates with Embedded Dart Sass using the Embedded Sass protocol.
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# Sass.compile('style.scss')
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# Sass.compile_string('h1 { font-size: 40px; }')
|
30
|
+
module Sass
|
31
|
+
class << self
|
32
|
+
# Compiles the Sass file at +path+ to CSS.
|
33
|
+
# @param (see Embedded#compile)
|
34
|
+
# @return (see Embedded#compile)
|
35
|
+
# @raise (see Embedded#compile)
|
36
|
+
# @see Embedded#compile
|
37
|
+
def compile(path, **kwargs)
|
38
|
+
instance.compile(path, **kwargs)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Compiles a stylesheet whose contents is +source+ to CSS.
|
42
|
+
# @param (see Embedded#compile_string)
|
43
|
+
# @return (see Embedded#compile_string)
|
44
|
+
# @raise (see Embedded#compile_string)
|
45
|
+
# @see Embedded#compile_string
|
46
|
+
def compile_string(source, **kwargs)
|
47
|
+
instance.compile_string(source, **kwargs)
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param (see Embedded#info)
|
51
|
+
# @return (see Embedded#info)
|
52
|
+
# @raise (see Embedded#info)
|
53
|
+
# @see Embedded#info
|
54
|
+
def info
|
55
|
+
instance.info
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def instance
|
61
|
+
if defined? @instance
|
62
|
+
@instance = Embedded.new if @instance.closed?
|
63
|
+
else
|
64
|
+
@instance = Embedded.new
|
65
|
+
at_exit do
|
66
|
+
@instance.close
|
67
|
+
end
|
68
|
+
end
|
69
|
+
@instance
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# The {Embedded} host for using dart-sass-embedded. Each instance creates
|
74
|
+
# its own communication {Channel} with a dedicated compiler process.
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# embedded = Sass::Embedded.new
|
78
|
+
# result = embedded.compile_string('h1 { font-size: 40px; }')
|
79
|
+
# result = embedded.compile('style.scss')
|
80
|
+
# embedded.close
|
81
|
+
class Embedded
|
82
|
+
def initialize
|
83
|
+
@channel = Channel.new
|
84
|
+
end
|
85
|
+
|
86
|
+
# Compiles the Sass file at +path+ to CSS.
|
87
|
+
# @param path [String]
|
88
|
+
# @param load_paths [Array<String>] Paths in which to look for stylesheets loaded by rules like
|
89
|
+
# {@use}[https://sass-lang.com/documentation/at-rules/use] and {@import}[https://sass-lang.com/documentation/at-rules/import].
|
90
|
+
# @param charset [Boolean] By default, if the CSS document contains non-ASCII characters, Sass adds a +@charset+
|
91
|
+
# declaration (in expanded output mode) or a byte-order mark (in compressed mode) to indicate its encoding to
|
92
|
+
# browsers or other consumers. If +charset+ is +false+, these annotations are omitted.
|
93
|
+
# @param source_map [Boolean] Whether or not Sass should generate a source map.
|
94
|
+
# @param source_map_include_sources [Boolean] Whether Sass should include the sources in the generated source map.
|
95
|
+
# @param style [String, Symbol] The OutputStyle of the compiled CSS.
|
96
|
+
# @param functions [Hash<String, Proc>] Additional built-in Sass functions that are available in all stylesheets.
|
97
|
+
# @param importers [Array<Object>] Custom importers that control how Sass resolves loads from rules like
|
98
|
+
# {@use}[https://sass-lang.com/documentation/at-rules/use] and {@import}[https://sass-lang.com/documentation/at-rules/import].
|
99
|
+
# @param alert_ascii [Boolean] If this is +true+, the compiler will exclusively use ASCII characters in its error
|
100
|
+
# and warning messages. Otherwise, it may use non-ASCII Unicode characters as well.
|
101
|
+
# @param alert_color [Boolean] If this is +true+, the compiler will use ANSI color escape codes in its error and
|
102
|
+
# warning messages. If it's +false+, it won't use these. If it's +nil+, the compiler will determine whether or
|
103
|
+
# not to use colors depending on whether the user is using an interactive terminal.
|
104
|
+
# @param logger [Object] An object to use to handle warnings and/or debug messages from Sass.
|
105
|
+
# @param quiet_deps [Boolean] If this option is set to +true+, Sass won’t print warnings that are caused by
|
106
|
+
# dependencies. A “dependency” is defined as any file that’s loaded through +load_paths+ or +importer+.
|
107
|
+
# Stylesheets that are imported relative to the entrypoint are not considered dependencies.
|
108
|
+
# @param verbose [Boolean] By default, Dart Sass will print only five instances of the same deprecation warning per
|
109
|
+
# compilation to avoid deluging users in console noise. If you set verbose to +true+, it will instead print every
|
110
|
+
# deprecation warning it encounters.
|
111
|
+
# @return [CompileResult]
|
112
|
+
# @raise [CompileError]
|
113
|
+
# @see https://sass-lang.com/documentation/js-api/modules#compile
|
114
|
+
def compile(path,
|
115
|
+
load_paths: [],
|
116
|
+
|
117
|
+
charset: true,
|
118
|
+
source_map: false,
|
119
|
+
source_map_include_sources: false,
|
120
|
+
style: :expanded,
|
121
|
+
|
122
|
+
functions: {},
|
123
|
+
importers: [],
|
124
|
+
|
125
|
+
alert_ascii: false,
|
126
|
+
alert_color: nil,
|
127
|
+
logger: nil,
|
128
|
+
quiet_deps: false,
|
129
|
+
verbose: false)
|
130
|
+
raise ArgumentError, 'path must be set' if path.nil?
|
131
|
+
|
132
|
+
Protofier.from_proto_compile_response(
|
133
|
+
Host.new(@channel).compile_request(
|
134
|
+
path: path,
|
135
|
+
source: nil,
|
136
|
+
importer: nil,
|
137
|
+
load_paths: load_paths,
|
138
|
+
syntax: nil,
|
139
|
+
url: nil,
|
140
|
+
charset: charset,
|
141
|
+
source_map: source_map,
|
142
|
+
source_map_include_sources: source_map_include_sources,
|
143
|
+
style: style,
|
144
|
+
functions: functions,
|
145
|
+
importers: importers,
|
146
|
+
alert_color: alert_color,
|
147
|
+
alert_ascii: alert_ascii,
|
148
|
+
logger: logger,
|
149
|
+
quiet_deps: quiet_deps,
|
150
|
+
verbose: verbose
|
151
|
+
)
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
# Compiles a stylesheet whose contents is +source+ to CSS.
|
156
|
+
# @param source [String]
|
157
|
+
# @param importer [Object] The importer to use to handle loads that are relative to the entrypoint stylesheet.
|
158
|
+
# @param load_paths [Array<String>] Paths in which to look for stylesheets loaded by rules like
|
159
|
+
# {@use}[https://sass-lang.com/documentation/at-rules/use] and {@import}[https://sass-lang.com/documentation/at-rules/import].
|
160
|
+
# @param syntax [String, Symbol] The Syntax to use to parse the entrypoint stylesheet.
|
161
|
+
# @param url [String] The canonical URL of the entrypoint stylesheet. If this is passed along with +importer+, it's
|
162
|
+
# used to resolve relative loads in the entrypoint stylesheet.
|
163
|
+
# @param charset [Boolean] By default, if the CSS document contains non-ASCII characters, Sass adds a +@charset+
|
164
|
+
# declaration (in expanded output mode) or a byte-order mark (in compressed mode) to indicate its encoding to
|
165
|
+
# browsers or other consumers. If +charset+ is +false+, these annotations are omitted.
|
166
|
+
# @param source_map [Boolean] Whether or not Sass should generate a source map.
|
167
|
+
# @param source_map_include_sources [Boolean] Whether Sass should include the sources in the generated source map.
|
168
|
+
# @param style [String, Symbol] The OutputStyle of the compiled CSS.
|
169
|
+
# @param functions [Hash<String, Proc>] Additional built-in Sass functions that are available in all stylesheets.
|
170
|
+
# @param importers [Array<Object>] Custom importers that control how Sass resolves loads from rules like
|
171
|
+
# {@use}[https://sass-lang.com/documentation/at-rules/use] and {@import}[https://sass-lang.com/documentation/at-rules/import].
|
172
|
+
# @param alert_ascii [Boolean] If this is +true+, the compiler will exclusively use ASCII characters in its error
|
173
|
+
# and warning messages. Otherwise, it may use non-ASCII Unicode characters as well.
|
174
|
+
# @param alert_color [Boolean] If this is +true+, the compiler will use ANSI color escape codes in its error and
|
175
|
+
# warning messages. If it's +false+, it won't use these. If it's +nil+, the compiler will determine whether or
|
176
|
+
# not to use colors depending on whether the user is using an interactive terminal.
|
177
|
+
# @param logger [Object] An object to use to handle warnings and/or debug messages from Sass.
|
178
|
+
# @param quiet_deps [Boolean] If this option is set to +true+, Sass won’t print warnings that are caused by
|
179
|
+
# dependencies. A “dependency” is defined as any file that’s loaded through +load_paths+ or +importer+.
|
180
|
+
# Stylesheets that are imported relative to the entrypoint are not considered dependencies.
|
181
|
+
# @param verbose [Boolean] By default, Dart Sass will print only five instances of the same deprecation warning per
|
182
|
+
# compilation to avoid deluging users in console noise. If you set verbose to +true+, it will instead print every
|
183
|
+
# deprecation warning it encounters.
|
184
|
+
# @return [CompileResult]
|
185
|
+
# @raise [CompileError]
|
186
|
+
# @see https://sass-lang.com/documentation/js-api/modules#compileString
|
187
|
+
def compile_string(source,
|
188
|
+
importer: nil,
|
189
|
+
load_paths: [],
|
190
|
+
syntax: :scss,
|
191
|
+
url: nil,
|
192
|
+
|
193
|
+
charset: true,
|
194
|
+
source_map: false,
|
195
|
+
source_map_include_sources: false,
|
196
|
+
style: :expanded,
|
197
|
+
|
198
|
+
functions: {},
|
199
|
+
importers: [],
|
200
|
+
|
201
|
+
alert_ascii: false,
|
202
|
+
alert_color: nil,
|
203
|
+
logger: nil,
|
204
|
+
quiet_deps: false,
|
205
|
+
verbose: false)
|
206
|
+
raise ArgumentError, 'source must be set' if source.nil?
|
207
|
+
|
208
|
+
Protofier.from_proto_compile_response(
|
209
|
+
Host.new(@channel).compile_request(
|
210
|
+
path: nil,
|
211
|
+
source: source,
|
212
|
+
importer: importer,
|
213
|
+
load_paths: load_paths,
|
214
|
+
syntax: syntax,
|
215
|
+
url: url,
|
216
|
+
charset: charset,
|
217
|
+
source_map: source_map,
|
218
|
+
source_map_include_sources: source_map_include_sources,
|
219
|
+
style: style,
|
220
|
+
functions: functions,
|
221
|
+
importers: importers,
|
222
|
+
alert_color: alert_color,
|
223
|
+
alert_ascii: alert_ascii,
|
224
|
+
logger: logger,
|
225
|
+
quiet_deps: quiet_deps,
|
226
|
+
verbose: verbose
|
227
|
+
)
|
228
|
+
)
|
229
|
+
end
|
230
|
+
|
231
|
+
# @return [String] Information about the Sass implementation.
|
232
|
+
# @see https://sass-lang.com/documentation/js-api/modules#info
|
233
|
+
def info
|
234
|
+
@info ||= "sass-embedded\t#{Host.new(@channel).version_request.implementation_version}"
|
235
|
+
end
|
236
|
+
|
237
|
+
def close
|
238
|
+
@channel.close
|
239
|
+
end
|
240
|
+
|
241
|
+
def closed?
|
242
|
+
@channel.closed?
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
# A namespace for built-in Loggers.
|
5
|
+
#
|
6
|
+
# @see https://sass-lang.com/documentation/js-api/modules/Logger
|
7
|
+
module Logger
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# A Logger that silently ignores all warnings and debug messages.
|
11
|
+
def silent
|
12
|
+
Silent
|
13
|
+
end
|
14
|
+
|
15
|
+
# A Logger that silently ignores all warnings and debug messages.
|
16
|
+
module Silent
|
17
|
+
module_function
|
18
|
+
|
19
|
+
def warn(message, deprecation: false, span: nil, stack: nil); end
|
20
|
+
|
21
|
+
def debug(message, span: nil); end
|
22
|
+
end
|
23
|
+
|
24
|
+
private_constant :Silent
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
module Logger
|
5
|
+
# A specific location within a source file.
|
6
|
+
#
|
7
|
+
# This is always associated with a {SourceSpan} which indicates which file it refers to.
|
8
|
+
#
|
9
|
+
# @see https://sass-lang.com/documentation/js-api/interfaces/SourceLocation
|
10
|
+
class SourceLocation
|
11
|
+
# @return [Integer]
|
12
|
+
attr_reader :offset, :line, :column
|
13
|
+
|
14
|
+
def initialize(offset, line, column)
|
15
|
+
@offset = offset
|
16
|
+
@line = line
|
17
|
+
@column = column
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
module Logger
|
5
|
+
# A span of text within a source file.
|
6
|
+
#
|
7
|
+
# @see https://sass-lang.com/documentation/js-api/interfaces/SourceSpan
|
8
|
+
class SourceSpan
|
9
|
+
# @return [SourceLocation]
|
10
|
+
attr_reader :start, :end
|
11
|
+
|
12
|
+
# @return [String]
|
13
|
+
attr_reader :text
|
14
|
+
|
15
|
+
# @return [String, nil]
|
16
|
+
attr_reader :url, :context
|
17
|
+
|
18
|
+
def initialize(start, end_, text, url, context)
|
19
|
+
@start = start
|
20
|
+
@end = end_
|
21
|
+
@text = text
|
22
|
+
@url = url == '' ? nil : url
|
23
|
+
@context = context == '' ? nil : context
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
module Value
|
5
|
+
# Sass's argument list type.
|
6
|
+
#
|
7
|
+
# An argument list comes from a rest argument. It's distinct from a normal {List} in that it may contain a keyword
|
8
|
+
# map as well as the positional arguments.
|
9
|
+
#
|
10
|
+
# @see https://sass-lang.com/documentation/js-api/classes/SassArgumentList
|
11
|
+
class ArgumentList < Value::List
|
12
|
+
# @param contents [Array<Value>]
|
13
|
+
# @param keywords [Hash<::String, Value>]
|
14
|
+
# @param separator [::String]
|
15
|
+
def initialize(contents = [], keywords = {}, separator = ',')
|
16
|
+
super(contents, separator: separator)
|
17
|
+
|
18
|
+
@id = 0
|
19
|
+
@keywords_accessed = false
|
20
|
+
@keywords = keywords.transform_keys(&:to_s).freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Hash<::String, Value>]
|
24
|
+
def keywords
|
25
|
+
@keywords_accessed = true
|
26
|
+
@keywords
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
module Value
|
5
|
+
# Sass's boolean type.
|
6
|
+
#
|
7
|
+
# @see https://sass-lang.com/documentation/js-api/classes/SassBoolean
|
8
|
+
class Boolean
|
9
|
+
include Value
|
10
|
+
|
11
|
+
# @param value [::Boolean]
|
12
|
+
def initialize(value)
|
13
|
+
@value = value
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [::Boolean]
|
17
|
+
attr_reader :value
|
18
|
+
|
19
|
+
# @return [Boolean]
|
20
|
+
def !
|
21
|
+
value ? Boolean::FALSE : Boolean::TRUE
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [::Boolean]
|
25
|
+
def ==(other)
|
26
|
+
other.is_a?(Sass::Value::Boolean) && other.value == value
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Integer]
|
30
|
+
def hash
|
31
|
+
@hash ||= value.hash
|
32
|
+
end
|
33
|
+
|
34
|
+
alias to_bool value
|
35
|
+
|
36
|
+
# @return [Boolean]
|
37
|
+
def assert_boolean(_name = nil)
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# Sass's true value.
|
42
|
+
TRUE = Boolean.new(true)
|
43
|
+
|
44
|
+
# Sass's false value.
|
45
|
+
FALSE = Boolean.new(false)
|
46
|
+
|
47
|
+
def self.new(value)
|
48
|
+
value ? Boolean::TRUE : Boolean::FALSE
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,253 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
module Value
|
5
|
+
# Sass's color type.
|
6
|
+
#
|
7
|
+
# No matter what representation was originally used to create this color, all of its channels are accessible.
|
8
|
+
#
|
9
|
+
# @see https://sass-lang.com/documentation/js-api/classes/SassColor
|
10
|
+
class Color
|
11
|
+
include Value
|
12
|
+
|
13
|
+
# @param red [Numeric]
|
14
|
+
# @param green [Numeric]
|
15
|
+
# @param blue [Numeric]
|
16
|
+
# @param hue [Numeric]
|
17
|
+
# @param saturation [Numeric]
|
18
|
+
# @param lightness [Numeric]
|
19
|
+
# @param whiteness [Numeric]
|
20
|
+
# @param blackness [Numeric]
|
21
|
+
# @param alpha [Numeric]
|
22
|
+
def initialize(red: nil,
|
23
|
+
green: nil,
|
24
|
+
blue: nil,
|
25
|
+
hue: nil,
|
26
|
+
saturation: nil,
|
27
|
+
lightness: nil,
|
28
|
+
whiteness: nil,
|
29
|
+
blackness: nil,
|
30
|
+
alpha: nil)
|
31
|
+
@alpha = alpha.nil? ? 1 : FuzzyMath.assert_between(alpha, 0, 1, 'alpha')
|
32
|
+
if red && green && blue
|
33
|
+
@red = FuzzyMath.assert_between(FuzzyMath.round(red), 0, 255, 'red')
|
34
|
+
@green = FuzzyMath.assert_between(FuzzyMath.round(green), 0, 255, 'green')
|
35
|
+
@blue = FuzzyMath.assert_between(FuzzyMath.round(blue), 0, 255, 'blue')
|
36
|
+
elsif hue && saturation && lightness
|
37
|
+
@hue = hue % 360
|
38
|
+
@saturation = FuzzyMath.assert_between(saturation, 0, 100, 'saturation')
|
39
|
+
@lightness = FuzzyMath.assert_between(lightness, 0, 100, 'lightness')
|
40
|
+
elsif hue && whiteness && blackness
|
41
|
+
@hue = hue % 360
|
42
|
+
@whiteness = FuzzyMath.assert_between(whiteness, 0, 100, 'whiteness')
|
43
|
+
@blackness = FuzzyMath.assert_between(blackness, 0, 100, 'blackness')
|
44
|
+
hwb_to_rgb
|
45
|
+
@whiteness = @blackness = nil
|
46
|
+
else
|
47
|
+
raise error 'Invalid Color'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Integer]
|
52
|
+
def red
|
53
|
+
hsl_to_rgb unless defined? @red
|
54
|
+
|
55
|
+
@red
|
56
|
+
end
|
57
|
+
|
58
|
+
# @return [Integer]
|
59
|
+
def green
|
60
|
+
hsl_to_rgb unless defined? @green
|
61
|
+
|
62
|
+
@green
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Integer]
|
66
|
+
def blue
|
67
|
+
hsl_to_rgb unless defined? @blue
|
68
|
+
|
69
|
+
@blue
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [Numeric]
|
73
|
+
def hue
|
74
|
+
rgb_to_hsl unless defined? @hue
|
75
|
+
|
76
|
+
@hue
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Numeric]
|
80
|
+
def saturation
|
81
|
+
rgb_to_hsl unless defined? @saturation
|
82
|
+
|
83
|
+
@saturation
|
84
|
+
end
|
85
|
+
|
86
|
+
# @return [Numeric]
|
87
|
+
def lightness
|
88
|
+
rgb_to_hsl unless defined? @lightness
|
89
|
+
|
90
|
+
@lightness
|
91
|
+
end
|
92
|
+
|
93
|
+
# @return [Numeric]
|
94
|
+
def whiteness
|
95
|
+
@whiteness ||= Rational([red, green, blue].min, 255) * 100
|
96
|
+
end
|
97
|
+
|
98
|
+
# @return [Numeric]
|
99
|
+
def blackness
|
100
|
+
@blackness ||= 100 - (Rational([red, green, blue].max, 255) * 100)
|
101
|
+
end
|
102
|
+
|
103
|
+
# @return [Numeric]
|
104
|
+
attr_reader :alpha
|
105
|
+
|
106
|
+
# @param red [Numeric]
|
107
|
+
# @param green [Numeric]
|
108
|
+
# @param blue [Numeric]
|
109
|
+
# @param hue [Numeric]
|
110
|
+
# @param saturation [Numeric]
|
111
|
+
# @param lightness [Numeric]
|
112
|
+
# @param whiteness [Numeric]
|
113
|
+
# @param blackness [Numeric]
|
114
|
+
# @param alpha [Numeric]
|
115
|
+
# @return [Color]
|
116
|
+
def change(red: nil,
|
117
|
+
green: nil,
|
118
|
+
blue: nil,
|
119
|
+
hue: nil,
|
120
|
+
saturation: nil,
|
121
|
+
lightness: nil,
|
122
|
+
whiteness: nil,
|
123
|
+
blackness: nil,
|
124
|
+
alpha: nil)
|
125
|
+
if whiteness || blackness
|
126
|
+
Sass::Value::Color.new(hue: hue || self.hue,
|
127
|
+
whiteness: whiteness || self.whiteness,
|
128
|
+
blackness: blackness || self.blackness,
|
129
|
+
alpha: alpha || self.alpha)
|
130
|
+
elsif hue || saturation || lightness
|
131
|
+
Sass::Value::Color.new(hue: hue || self.hue,
|
132
|
+
saturation: saturation || self.saturation,
|
133
|
+
lightness: lightness || self.lightness,
|
134
|
+
alpha: alpha || self.alpha)
|
135
|
+
elsif red || green || blue
|
136
|
+
Sass::Value::Color.new(red: red ? FuzzyMath.round(red) : self.red,
|
137
|
+
green: green ? FuzzyMath.round(green) : self.green,
|
138
|
+
blue: blue ? FuzzyMath.round(blue) : self.blue,
|
139
|
+
alpha: alpha || self.alpha)
|
140
|
+
else
|
141
|
+
dup.instance_eval do
|
142
|
+
@alpha = FuzzyMath.assert_between(alpha, 0, 1, 'alpha')
|
143
|
+
self
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# @return [::Boolean]
|
149
|
+
def ==(other)
|
150
|
+
other.is_a?(Sass::Value::Color) &&
|
151
|
+
other.red == red &&
|
152
|
+
other.green == green &&
|
153
|
+
other.blue == blue &&
|
154
|
+
other.alpha == alpha
|
155
|
+
end
|
156
|
+
|
157
|
+
# @return [Integer]
|
158
|
+
def hash
|
159
|
+
@hash ||= [red, green, blue, alpha].hash
|
160
|
+
end
|
161
|
+
|
162
|
+
# @return [Color]
|
163
|
+
def assert_color(_name = nil)
|
164
|
+
self
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
|
169
|
+
def rgb_to_hsl
|
170
|
+
scaled_red = Rational(red, 255)
|
171
|
+
scaled_green = Rational(green, 255)
|
172
|
+
scaled_blue = Rational(blue, 255)
|
173
|
+
|
174
|
+
max = [scaled_red, scaled_green, scaled_blue].max
|
175
|
+
min = [scaled_red, scaled_green, scaled_blue].min
|
176
|
+
delta = max - min
|
177
|
+
|
178
|
+
if max == min
|
179
|
+
@hue = 0
|
180
|
+
elsif max == scaled_red
|
181
|
+
@hue = (60 * (scaled_green - scaled_blue) / delta) % 360
|
182
|
+
elsif max == scaled_green
|
183
|
+
@hue = (120 + (60 * (scaled_blue - scaled_red) / delta)) % 360
|
184
|
+
elsif max == scaled_blue
|
185
|
+
@hue = (240 + (60 * (scaled_red - scaled_green) / delta)) % 360
|
186
|
+
end
|
187
|
+
|
188
|
+
lightness = @lightness = 50 * (max + min)
|
189
|
+
|
190
|
+
@saturation = if max == min
|
191
|
+
0
|
192
|
+
elsif lightness < 50
|
193
|
+
100 * delta / (max + min)
|
194
|
+
else
|
195
|
+
100 * delta / (2 - max - min)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def hsl_to_rgb
|
200
|
+
scaled_hue = Rational(hue, 360)
|
201
|
+
scaled_saturation = Rational(saturation, 100)
|
202
|
+
scaled_lightness = Rational(lightness, 100)
|
203
|
+
|
204
|
+
tmp2 = if scaled_lightness <= 0.5
|
205
|
+
scaled_lightness * (scaled_saturation + 1)
|
206
|
+
else
|
207
|
+
scaled_lightness + scaled_saturation - (scaled_lightness * scaled_saturation)
|
208
|
+
end
|
209
|
+
tmp1 = (scaled_lightness * 2) - tmp2
|
210
|
+
@red = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue + Rational(1, 3)) * 255)
|
211
|
+
@green = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue) * 255)
|
212
|
+
@blue = FuzzyMath.round(hsl_hue_to_rgb(tmp1, tmp2, scaled_hue - Rational(1, 3)) * 255)
|
213
|
+
end
|
214
|
+
|
215
|
+
def hsl_hue_to_rgb(tmp1, tmp2, hue)
|
216
|
+
hue += 1 if hue.negative?
|
217
|
+
hue -= 1 if hue > 1
|
218
|
+
|
219
|
+
if hue < Rational(1, 6)
|
220
|
+
tmp1 + ((tmp2 - tmp1) * hue * 6)
|
221
|
+
elsif hue < Rational(1, 2)
|
222
|
+
tmp2
|
223
|
+
elsif hue < Rational(2, 3)
|
224
|
+
tmp1 + ((tmp2 - tmp1) * (Rational(2, 3) - hue) * 6)
|
225
|
+
else
|
226
|
+
tmp1
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def hwb_to_rgb
|
231
|
+
scaled_hue = Rational(hue, 360)
|
232
|
+
scaled_whiteness = Rational(whiteness, 100)
|
233
|
+
scaled_blackness = Rational(blackness, 100)
|
234
|
+
|
235
|
+
sum = scaled_whiteness + scaled_blackness
|
236
|
+
if sum > 1
|
237
|
+
scaled_whiteness /= sum
|
238
|
+
scaled_blackness /= sum
|
239
|
+
end
|
240
|
+
|
241
|
+
factor = 1 - scaled_whiteness - scaled_blackness
|
242
|
+
@red = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue + Rational(1, 3))
|
243
|
+
@green = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue)
|
244
|
+
@blue = hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue - Rational(1, 3))
|
245
|
+
end
|
246
|
+
|
247
|
+
def hwb_hue_to_rgb(factor, scaled_whiteness, scaled_hue)
|
248
|
+
channel = (hsl_hue_to_rgb(0, 1, scaled_hue) * factor) + scaled_whiteness
|
249
|
+
FuzzyMath.round(channel * 255)
|
250
|
+
end
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|