Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sass configuration map with default values

I am creating css using SASS and would like to make it possible for another developer to create a custom css by changing sass variables. This works fine when I in my base file use a single variable like this:

$text-color: #000 !default;

To test the override I create a new project where I first declare an override for the variable and then import the "base" sass file.

$text-color: #0074b;    
@import "base-file";

But I would also like to use maps for configuration but then I do not get the override to work. How should I use configuration maps that can be overriden?

$colors: (text-color: #000, icon-color: #ccc );

Adding !default after #000 gives me a compilation error: expected ")", was "!default,") Adding !default after the ) gives no error but the variables does not get overwritten either.

Any ideas on what I am doing wrong?

like image 415
P3anuts Avatar asked Nov 16 '14 13:11

P3anuts


2 Answers

I don't think the functionality you want exists in standard Sass. I built this function though that does what you're asking for:

//A function for filling in a map variable with default values
@function defaultTo($mapVariable: (), $defaultMap){

    //if it's a map, treat each setting in the map seperately
    @if (type-of($defaultMap) == 'map' ){

        $finalParams: $mapVariable;

        // We iterate over each property of the defaultMap
        @each $key, $value in $defaultMap {

            // If the variable map does not have the associative key
            @if (not map-has-key($mapVariable, $key)) {

                // add it to finalParams
                $finalParams: map-merge($finalParams, ($key : $value));

            }
        }

        @return $finalParams;

    //Throw an error message if not a map
    } @else {
        @error 'The defaultTo function only works for Sass maps';
    }
}

Usage:

$map: defaultTo($map, (
    key1 : value1,
    key2 : value2
));

Then if you have a mixin for something, you can do this sort of thing:

@mixin someMixin($settings: ()){
    $settings: defaultTo($settings, (
        background: white,
        text: black
    );
    background: map-get($settings, background);
    color: map-get($settings, text);
}

.element {
    @include someMixin((text: blue));
}

Outputted CSS:

.element { background: white; color: blue; }

So you would use it like this based on what you said in the question:

$colors: defaultTo($colors, (
    text-color: #000,
    icon-color: #ccc,
));
like image 162
Daniel Tonon Avatar answered Sep 28 '22 00:09

Daniel Tonon


Bootstrap has solved this issue as:

$grays: () !default;
// stylelint-disable-next-line scss/dollar-variable-default
$grays: map-merge(
  (
    "100": $gray-100,
    "200": $gray-200,
    "300": $gray-300,
    "400": $gray-400,
    "500": $gray-500,
    "600": $gray-600,
    "700": $gray-700,
    "800": $gray-800,
    "900": $gray-900
  ),
  $grays
);

https://github.com/twbs/bootstrap/blob/v4.1.3/scss/_variables.scss#L23

like image 34
kitimenpolku Avatar answered Sep 28 '22 00:09

kitimenpolku