simplify declaration of other color fns
This commit is contained in:
parent
11e0d523b2
commit
4cfa29c971
@ -3,8 +3,12 @@ use super::GlobalFunctionMap;
|
||||
use num_traits::{One, Signed, Zero};
|
||||
|
||||
use super::Builtin;
|
||||
use crate::args::CallArgs;
|
||||
use crate::color::Color;
|
||||
use crate::common::QuoteKind;
|
||||
use crate::error::SassResult;
|
||||
use crate::scope::Scope;
|
||||
use crate::selector::Selector;
|
||||
use crate::unit::Unit;
|
||||
use crate::value::{Number, Value};
|
||||
|
||||
@ -51,7 +55,11 @@ macro_rules! opt_hsl {
|
||||
}
|
||||
|
||||
pub(crate) fn register(f: &mut GlobalFunctionMap) {
|
||||
f.insert("change-color", Builtin::new(|mut args, scope, super_selector| {
|
||||
fn change_color(
|
||||
mut args: CallArgs,
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
) -> SassResult<Value> {
|
||||
if args.get_positional(1, scope, super_selector).is_some() {
|
||||
return Err(
|
||||
("Only one positional argument is allowed. All other arguments must be passed by name.", args.span()
|
||||
@ -60,9 +68,13 @@ pub(crate) fn register(f: &mut GlobalFunctionMap) {
|
||||
|
||||
let color = match arg!(args, scope, super_selector, 0, "color") {
|
||||
Value::Color(c) => c,
|
||||
v => return Err(
|
||||
(format!("$color: {} is not a color.", v.to_css_string(args.span())?), args.span()
|
||||
).into()),
|
||||
v => {
|
||||
return Err((
|
||||
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
|
||||
opt_rgba!(args, alpha, "alpha", 0, 1, scope, super_selector);
|
||||
@ -71,24 +83,46 @@ pub(crate) fn register(f: &mut GlobalFunctionMap) {
|
||||
opt_rgba!(args, blue, "blue", 0, 255, scope, super_selector);
|
||||
|
||||
if red.is_some() || green.is_some() || blue.is_some() {
|
||||
return Ok(Value::Color(Box::new(Color::from_rgba(red.unwrap_or(color.red()), green.unwrap_or(color.green()), blue.unwrap_or(color.blue()), alpha.unwrap_or(color.alpha())))))
|
||||
return Ok(Value::Color(Box::new(Color::from_rgba(
|
||||
red.unwrap_or(color.red()),
|
||||
green.unwrap_or(color.green()),
|
||||
blue.unwrap_or(color.blue()),
|
||||
alpha.unwrap_or(color.alpha()),
|
||||
))));
|
||||
}
|
||||
|
||||
let hue = match named_arg!(args, scope, super_selector, "hue"=Value::Null) {
|
||||
let hue = match named_arg!(args, scope, super_selector, "hue" = Value::Null) {
|
||||
Value::Dimension(n, _) => Some(n),
|
||||
Value::Null => None,
|
||||
v => return Err(
|
||||
(format!("$hue: {} is not a number.", v.to_css_string(args.span())?), args.span()
|
||||
).into()),
|
||||
v => {
|
||||
return Err((
|
||||
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
|
||||
opt_hsl!(args, saturation, "saturation", 0, 100, scope, super_selector);
|
||||
opt_hsl!(
|
||||
args,
|
||||
saturation,
|
||||
"saturation",
|
||||
0,
|
||||
100,
|
||||
scope,
|
||||
super_selector
|
||||
);
|
||||
opt_hsl!(args, luminance, "lightness", 0, 100, scope, super_selector);
|
||||
|
||||
if hue.is_some() || saturation.is_some() || luminance.is_some() {
|
||||
// Color::as_hsla() returns more exact values than Color::hue(), etc.
|
||||
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
|
||||
return Ok(Value::Color(Box::new(Color::from_hsla(hue.unwrap_or(this_hue), saturation.unwrap_or(this_saturation), luminance.unwrap_or(this_luminance), alpha.unwrap_or(this_alpha)))))
|
||||
return Ok(Value::Color(Box::new(Color::from_hsla(
|
||||
hue.unwrap_or(this_hue),
|
||||
saturation.unwrap_or(this_saturation),
|
||||
luminance.unwrap_or(this_luminance),
|
||||
alpha.unwrap_or(this_alpha),
|
||||
))));
|
||||
}
|
||||
|
||||
Ok(Value::Color(if let Some(a) = alpha {
|
||||
@ -96,197 +130,242 @@ pub(crate) fn register(f: &mut GlobalFunctionMap) {
|
||||
} else {
|
||||
color
|
||||
}))
|
||||
}));
|
||||
f.insert(
|
||||
"adjust-color",
|
||||
Builtin::new(|mut args, scope, super_selector| {
|
||||
let color = match arg!(args, scope, super_selector, 0, "color") {
|
||||
Value::Color(c) => c,
|
||||
v => {
|
||||
return Err((
|
||||
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
|
||||
opt_rgba!(args, alpha, "alpha", -1, 1, scope, super_selector);
|
||||
opt_rgba!(args, red, "red", -255, 255, scope, super_selector);
|
||||
opt_rgba!(args, green, "green", -255, 255, scope, super_selector);
|
||||
opt_rgba!(args, blue, "blue", -255, 255, scope, super_selector);
|
||||
|
||||
if red.is_some() || green.is_some() || blue.is_some() {
|
||||
return Ok(Value::Color(Box::new(Color::from_rgba(
|
||||
color.red() + red.unwrap_or(Number::zero()),
|
||||
color.green() + green.unwrap_or(Number::zero()),
|
||||
color.blue() + blue.unwrap_or(Number::zero()),
|
||||
color.alpha() + alpha.unwrap_or(Number::zero()),
|
||||
))));
|
||||
}
|
||||
|
||||
let hue = match named_arg!(args, scope, super_selector, "hue" = Value::Null) {
|
||||
Value::Dimension(n, _) => Some(n),
|
||||
Value::Null => None,
|
||||
v => {
|
||||
return Err((
|
||||
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
|
||||
opt_hsl!(
|
||||
args,
|
||||
saturation,
|
||||
"saturation",
|
||||
-100,
|
||||
100,
|
||||
scope,
|
||||
super_selector
|
||||
);
|
||||
opt_hsl!(
|
||||
args,
|
||||
luminance,
|
||||
"lightness",
|
||||
-100,
|
||||
100,
|
||||
scope,
|
||||
super_selector
|
||||
);
|
||||
|
||||
if hue.is_some() || saturation.is_some() || luminance.is_some() {
|
||||
// Color::as_hsla() returns more exact values than Color::hue(), etc.
|
||||
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
|
||||
return Ok(Value::Color(Box::new(Color::from_hsla(
|
||||
this_hue + hue.unwrap_or(Number::zero()),
|
||||
this_saturation + saturation.unwrap_or(Number::zero()),
|
||||
this_luminance + luminance.unwrap_or(Number::zero()),
|
||||
this_alpha + alpha.unwrap_or(Number::zero()),
|
||||
))));
|
||||
}
|
||||
|
||||
Ok(Value::Color(if let Some(a) = alpha {
|
||||
let temp_alpha = color.alpha();
|
||||
Box::new(color.with_alpha(temp_alpha + a))
|
||||
} else {
|
||||
color
|
||||
}))
|
||||
}),
|
||||
);
|
||||
f.insert(
|
||||
"scale-color",
|
||||
Builtin::new(|mut args, scope, super_selector| {
|
||||
let span = args.span();
|
||||
let color = match arg!(args, scope, super_selector, 0, "color") {
|
||||
Value::Color(c) => c,
|
||||
v => return Err(
|
||||
(format!("$color: {} is not a color.", v.to_css_string(span)?), span
|
||||
).into()),
|
||||
};
|
||||
|
||||
macro_rules! opt_scale_arg {
|
||||
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal, $scope:ident, $super_selector:ident) => {
|
||||
let $name = match named_arg!($args, $scope, $super_selector, $arg = Value::Null) {
|
||||
Value::Dimension(n, Unit::Percent) => {
|
||||
Some(bound!($args, $arg, n, Unit::Percent, $low, $high) / Number::from(100))
|
||||
}
|
||||
v @ Value::Dimension(..) => {
|
||||
return Err(
|
||||
(format!("${}: Expected {} to have unit \"%\".", $arg, v.to_css_string($args.span())?), $args.span()).into()
|
||||
)
|
||||
}
|
||||
Value::Null => None,
|
||||
v => return Err(
|
||||
(format!("${}: {} is not a number.", $arg, v.to_css_string($args.span())?), $args.span()
|
||||
).into()),
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
opt_scale_arg!(args, alpha, "alpha", -100, 100, scope, super_selector);
|
||||
opt_scale_arg!(args, red, "red", -100, 100, scope, super_selector);
|
||||
opt_scale_arg!(args, green, "green", -100, 100, scope, super_selector);
|
||||
opt_scale_arg!(args, blue, "blue", -100, 100, scope, super_selector);
|
||||
|
||||
if red.is_some() || green.is_some() || blue.is_some() {
|
||||
return Ok(Value::Color(Box::new(Color::from_rgba(
|
||||
scale(
|
||||
color.red(),
|
||||
red.unwrap_or(Number::zero()),
|
||||
Number::from(255),
|
||||
),
|
||||
scale(
|
||||
color.green(),
|
||||
green.unwrap_or(Number::zero()),
|
||||
Number::from(255),
|
||||
),
|
||||
scale(
|
||||
color.blue(),
|
||||
blue.unwrap_or(Number::zero()),
|
||||
Number::from(255),
|
||||
),
|
||||
scale(
|
||||
color.alpha(),
|
||||
alpha.unwrap_or(Number::zero()),
|
||||
Number::one(),
|
||||
),
|
||||
))));
|
||||
}
|
||||
|
||||
opt_scale_arg!(args, saturation, "saturation", -100, 100, scope, super_selector);
|
||||
opt_scale_arg!(args, luminance, "lightness", -100, 100, scope, super_selector);
|
||||
|
||||
if saturation.is_some() || luminance.is_some() {
|
||||
// Color::as_hsla() returns more exact values than Color::hue(), etc.
|
||||
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
|
||||
return Ok(Value::Color(Box::new(Color::from_hsla(
|
||||
scale(this_hue, Number::zero(), Number::from(360)),
|
||||
scale(
|
||||
this_saturation,
|
||||
saturation.unwrap_or(Number::zero()),
|
||||
Number::one(),
|
||||
),
|
||||
scale(
|
||||
this_luminance,
|
||||
luminance.unwrap_or(Number::zero()),
|
||||
Number::one(),
|
||||
),
|
||||
scale(this_alpha, alpha.unwrap_or(Number::zero()), Number::one()),
|
||||
))));
|
||||
}
|
||||
|
||||
Ok(Value::Color(if let Some(a) = alpha {
|
||||
let temp_alpha = color.alpha();
|
||||
Box::new(color.with_alpha(scale(temp_alpha, a, Number::one())))
|
||||
} else {
|
||||
color
|
||||
}))
|
||||
}),
|
||||
);
|
||||
f.insert(
|
||||
"ie-hex-str",
|
||||
Builtin::new(|mut args, scope, super_selector| {
|
||||
args.max_args(1)?;
|
||||
let color = match arg!(args, scope, super_selector, 0, "color") {
|
||||
Value::Color(c) => c,
|
||||
v => {
|
||||
return Err((
|
||||
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
Ok(Value::Ident(color.to_ie_hex_str(), QuoteKind::None))
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
fn scale(val: Number, by: Number, max: Number) -> Number {
|
||||
if by.is_zero() {
|
||||
return val;
|
||||
}
|
||||
val.clone() + (if by.is_positive() { max - val } else { val }) * by
|
||||
|
||||
fn adjust_color(
|
||||
mut args: CallArgs,
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
) -> SassResult<Value> {
|
||||
let color = match arg!(args, scope, super_selector, 0, "color") {
|
||||
Value::Color(c) => c,
|
||||
v => {
|
||||
return Err((
|
||||
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
|
||||
opt_rgba!(args, alpha, "alpha", -1, 1, scope, super_selector);
|
||||
opt_rgba!(args, red, "red", -255, 255, scope, super_selector);
|
||||
opt_rgba!(args, green, "green", -255, 255, scope, super_selector);
|
||||
opt_rgba!(args, blue, "blue", -255, 255, scope, super_selector);
|
||||
|
||||
if red.is_some() || green.is_some() || blue.is_some() {
|
||||
return Ok(Value::Color(Box::new(Color::from_rgba(
|
||||
color.red() + red.unwrap_or(Number::zero()),
|
||||
color.green() + green.unwrap_or(Number::zero()),
|
||||
color.blue() + blue.unwrap_or(Number::zero()),
|
||||
color.alpha() + alpha.unwrap_or(Number::zero()),
|
||||
))));
|
||||
}
|
||||
|
||||
let hue = match named_arg!(args, scope, super_selector, "hue" = Value::Null) {
|
||||
Value::Dimension(n, _) => Some(n),
|
||||
Value::Null => None,
|
||||
v => {
|
||||
return Err((
|
||||
format!("$hue: {} is not a number.", v.to_css_string(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
|
||||
opt_hsl!(
|
||||
args,
|
||||
saturation,
|
||||
"saturation",
|
||||
-100,
|
||||
100,
|
||||
scope,
|
||||
super_selector
|
||||
);
|
||||
opt_hsl!(
|
||||
args,
|
||||
luminance,
|
||||
"lightness",
|
||||
-100,
|
||||
100,
|
||||
scope,
|
||||
super_selector
|
||||
);
|
||||
|
||||
if hue.is_some() || saturation.is_some() || luminance.is_some() {
|
||||
// Color::as_hsla() returns more exact values than Color::hue(), etc.
|
||||
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
|
||||
return Ok(Value::Color(Box::new(Color::from_hsla(
|
||||
this_hue + hue.unwrap_or(Number::zero()),
|
||||
this_saturation + saturation.unwrap_or(Number::zero()),
|
||||
this_luminance + luminance.unwrap_or(Number::zero()),
|
||||
this_alpha + alpha.unwrap_or(Number::zero()),
|
||||
))));
|
||||
}
|
||||
|
||||
Ok(Value::Color(if let Some(a) = alpha {
|
||||
let temp_alpha = color.alpha();
|
||||
Box::new(color.with_alpha(temp_alpha + a))
|
||||
} else {
|
||||
color
|
||||
}))
|
||||
}
|
||||
|
||||
fn scale_color(
|
||||
mut args: CallArgs,
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
) -> SassResult<Value> {
|
||||
fn scale(val: Number, by: Number, max: Number) -> Number {
|
||||
if by.is_zero() {
|
||||
return val;
|
||||
}
|
||||
val.clone() + (if by.is_positive() { max - val } else { val }) * by
|
||||
}
|
||||
|
||||
let span = args.span();
|
||||
let color = match arg!(args, scope, super_selector, 0, "color") {
|
||||
Value::Color(c) => c,
|
||||
v => {
|
||||
return Err((
|
||||
format!("$color: {} is not a color.", v.to_css_string(span)?),
|
||||
span,
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
|
||||
macro_rules! opt_scale_arg {
|
||||
($args:ident, $name:ident, $arg:literal, $low:literal, $high:literal, $scope:ident, $super_selector:ident) => {
|
||||
let $name = match named_arg!($args, $scope, $super_selector, $arg = Value::Null) {
|
||||
Value::Dimension(n, Unit::Percent) => {
|
||||
Some(bound!($args, $arg, n, Unit::Percent, $low, $high) / Number::from(100))
|
||||
}
|
||||
v @ Value::Dimension(..) => {
|
||||
return Err((
|
||||
format!(
|
||||
"${}: Expected {} to have unit \"%\".",
|
||||
$arg,
|
||||
v.to_css_string($args.span())?
|
||||
),
|
||||
$args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
Value::Null => None,
|
||||
v => {
|
||||
return Err((
|
||||
format!(
|
||||
"${}: {} is not a number.",
|
||||
$arg,
|
||||
v.to_css_string($args.span())?
|
||||
),
|
||||
$args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
opt_scale_arg!(args, alpha, "alpha", -100, 100, scope, super_selector);
|
||||
opt_scale_arg!(args, red, "red", -100, 100, scope, super_selector);
|
||||
opt_scale_arg!(args, green, "green", -100, 100, scope, super_selector);
|
||||
opt_scale_arg!(args, blue, "blue", -100, 100, scope, super_selector);
|
||||
|
||||
if red.is_some() || green.is_some() || blue.is_some() {
|
||||
return Ok(Value::Color(Box::new(Color::from_rgba(
|
||||
scale(
|
||||
color.red(),
|
||||
red.unwrap_or(Number::zero()),
|
||||
Number::from(255),
|
||||
),
|
||||
scale(
|
||||
color.green(),
|
||||
green.unwrap_or(Number::zero()),
|
||||
Number::from(255),
|
||||
),
|
||||
scale(
|
||||
color.blue(),
|
||||
blue.unwrap_or(Number::zero()),
|
||||
Number::from(255),
|
||||
),
|
||||
scale(
|
||||
color.alpha(),
|
||||
alpha.unwrap_or(Number::zero()),
|
||||
Number::one(),
|
||||
),
|
||||
))));
|
||||
}
|
||||
|
||||
opt_scale_arg!(
|
||||
args,
|
||||
saturation,
|
||||
"saturation",
|
||||
-100,
|
||||
100,
|
||||
scope,
|
||||
super_selector
|
||||
);
|
||||
opt_scale_arg!(
|
||||
args,
|
||||
luminance,
|
||||
"lightness",
|
||||
-100,
|
||||
100,
|
||||
scope,
|
||||
super_selector
|
||||
);
|
||||
|
||||
if saturation.is_some() || luminance.is_some() {
|
||||
// Color::as_hsla() returns more exact values than Color::hue(), etc.
|
||||
let (this_hue, this_saturation, this_luminance, this_alpha) = color.as_hsla();
|
||||
return Ok(Value::Color(Box::new(Color::from_hsla(
|
||||
scale(this_hue, Number::zero(), Number::from(360)),
|
||||
scale(
|
||||
this_saturation,
|
||||
saturation.unwrap_or(Number::zero()),
|
||||
Number::one(),
|
||||
),
|
||||
scale(
|
||||
this_luminance,
|
||||
luminance.unwrap_or(Number::zero()),
|
||||
Number::one(),
|
||||
),
|
||||
scale(this_alpha, alpha.unwrap_or(Number::zero()), Number::one()),
|
||||
))));
|
||||
}
|
||||
|
||||
Ok(Value::Color(if let Some(a) = alpha {
|
||||
let temp_alpha = color.alpha();
|
||||
Box::new(color.with_alpha(scale(temp_alpha, a, Number::one())))
|
||||
} else {
|
||||
color
|
||||
}))
|
||||
}
|
||||
|
||||
fn ie_hex_str(
|
||||
mut args: CallArgs,
|
||||
scope: &Scope,
|
||||
super_selector: &Selector,
|
||||
) -> SassResult<Value> {
|
||||
args.max_args(1)?;
|
||||
let color = match arg!(args, scope, super_selector, 0, "color") {
|
||||
Value::Color(c) => c,
|
||||
v => {
|
||||
return Err((
|
||||
format!("$color: {} is not a color.", v.to_css_string(args.span())?),
|
||||
args.span(),
|
||||
)
|
||||
.into())
|
||||
}
|
||||
};
|
||||
Ok(Value::Ident(color.to_ie_hex_str(), QuoteKind::None))
|
||||
}
|
||||
|
||||
f.insert("change-color", Builtin::new(change_color));
|
||||
f.insert("adjust-color", Builtin::new(adjust_color));
|
||||
f.insert("scale-color", Builtin::new(scale_color));
|
||||
f.insert("ie-hex-str", Builtin::new(ie_hex_str));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user