I'm trying to generate an automated system to define colors in SASS.
I have a map of colors named $brand-colors, and I would like the colors of this map to be used to generate the tints and shades in a second map, no matter how many colors there are in $ brand-colors.
This is the point where I arrived:
$brand-colors: (
brand-color: (
primary-color: #0096d6,
secondary-color: #1a4760,
),
) !default;
@function generate-map($map) {
@each $item, $colors in $map {
@each $color-name, $value in $colors {
@return(
$color-name: (
light-30: mix(white, $value, 30%),
light-20: mix(white, $value, 20%),
light-10: mix(white, $value, 10%),
base: $value,
dark-10: mix(black, $value, 10%),
dark-20: mix(black, $value, 20%),
dark-30: mix(black, $value, 30%),
),
);
};
};
};
$brand-palette: (
brand-palette:(
generate-map($_new-brand-colors)
),
) !default;
With the above code, I get this result from the terminal:
brand-palette:(
primary-color:(
light-30: #4db6e2,
light-20: #33abde,
light-10: #1aa1da,
base: #0096d6,
dark-10: #0087c1,
dark-20: #0078ab,
dark-30: #006996
)
)
In short, only the first key-value pair is taken, and I can not understand why. Can someone give me an answer?
The @return
statement tells the function to stop everything and return the value.
@function myFunction() {
@each $item in [a, b, c, d] {
@return $item;
}
}
myFunction()
will only return a
. Even though we have a loop with four items, it will run only once (the first time) because it immediately hits the @return
statement.
One best practice with functions is to have a $result
variable, and only call @return $result
once at the end of the function
@function myFunctionFixed() {
$result;
@each $item in [a, b, c, d] {
$result: $result + a;
}
@return $result;
}
myFunctionFixed()
will return abcd
because we allow the loop to run from beginning to end without interupting it with @return
, and we only return at the end of the function after the loop has completed.
map-merge
to incrementally build a mapApplying the best practice described above, we can move the @return
statement to the end of your function and use map-merge
to incrementally build a $result-map
variable.
@function generate-map($map) {
$result-map: () !default;
@each $item, $colors in $map {
@each $color-name, $value in $colors {
$result-map: map-merge($result-map,
($color-name: (
light-30: mix(white, $value, 30%),
light-20: mix(white, $value, 20%),
light-10: mix(white, $value, 10%),
base: $value,
dark-10: mix(black, $value, 10%),
dark-20: mix(black, $value, 20%),
dark-30: mix(black, $value, 30%),
))
);
};
};
@return $result-map;
};