Search code examples
sasscompass-sasscompass

generate classes from Scss / Sass nested map


How does one generate a list of classes for each key that has a single value inside a Scss/Sass map?

For example, from this Scss map (disregard nested naming conventions, this will be used for many maps of varying purposes):

(See Codepen: http://codepen.io/harlanlewis/pen/emWVrr (thanks cimmanon!))

$palette: (
  brown: hsl(33,35,50),
  blue: hsl(207,80,50),

  green: (
    0: hsl(157,65,65),
    1: hsl(157,50,50),
    alt: (
      0: hsl(125,65,65),
    ),
  ),

  red: (
    0: hsl(0,60,50),
    alt: (
      0: hsl(0,100,50),
    ),
  ),

  yellow: (
    0: hsl(50,100,60),
    1: hsl(50,100,100),
  ),
};

-

@mixin map-to-class($map, $selector: '', $property: '') {
    $selector: if($selector == '' and &, &, $selector);

    @each $key, $value in $map {
        @if type-of($value) == map {
            $selector: selector-append($selector, #{$key});
            @include map-to-class($value, $selector, $property) {
                @content;
            }
        } @else {
          @at-root #{$selector}#{$key} {
                #{$property}: $value;
            };
        };
    };
};
@include map-to-class($palette, '.u-fg__', 'color')

...desired classes to generate:

.u-fg__brown { color: hsl(33,35,50) }
.u-fg__blue { color: hsl(207,80,50) }

.u-fg__green0 { color: hsl(157,65,65) }
.u-fg__green1 { color: hsl(157,50,50) }
.u-fg__greenalt0 { color: hsl(125,65,65) }

.u-fg__red0 { color: hsl(0,60,50) }
.u-fg__redalt0 { color: hsl(0,100,50) }

.u-fg__yellow0 { color: hsl(50,100,60) }
.u-fg__yellow1 { color: hsl(50,100,80) }

The actual (incorrect) generated classes are: (note greenredyellow instead of just yellow)

... (brown, blue, and green are fine) ...
.u-fg__green0 { color: hsl(157,65,65) }
.u-fg__green1 { color: hsl(157,50,50) }
.u-fg__greenalt0 { color: hsl(125,65,65) }

.u-fg__greenred0 { color: hsl(0,60,50) }
.u-fg__greenredalt0 { color: hsl(0,100,50) }

.u-fg__greenredyellow0 { color: hsl(50,100,60) }
.u-fg__greenredyellow1 { color: hsl(50,100,80) }

Solution

  • What you're looking for is a recursive mixin. Walk through the mapping. If the value is a mapping, call itself otherwise print out the property/value.

    $palette: (
      'brown': hsl( 33,  35,  50),
      'blue': hsl(207, 80,  50),
    
      'green': (
        0: hsl(157, 65, 65),
        1: hsl(157, 50, 50),
        alt: (
          0: hsl(125, 65, 65),
        ),
      ),
    
      'red': (
        0: hsl(0, 60, 50),
        alt: (
          0: hsl(0, 100, 50),
        ),
      ),
    
      'yellow': (
        0: hsl(50, 100, 60),
        2: hsl(50, 100, 100),
      ),
    );
    
    
    @mixin map-to-class($map, $property, $sel, $divider: '') {
        $sel: if($sel == '' and &, &, $sel);
        @debug $sel;
    
        #{$sel} {
            @each $k, $v in $map {
                @at-root #{$sel}#{$divider}#{$k} {
                    @if type-of($v) == map {
                        @include map-to-class($v, $property, '', $divider) {
                            @content;
                        }
                    } @else {
                        #{$property}: $v;
                    }
                }
            }
        }
    }
    
    @include map-to-class($palette, color, '.u-fg__', '');
    

    Output:

    /* line 33, ../sass/test.scss */
    .u-fg__brown {
      color: #ac8453;
    }
    /* line 33, ../sass/test.scss */
    .u-fg__blue {
      color: #198ae6;
    }
    /* line 33, ../sass/test.scss */
    .u-fg__green0 {
      color: #6ce0b3;
    }
    /* line 33, ../sass/test.scss */
    .u-fg__green1 {
      color: #40bf8e;
    }
    /* line 33, ../sass/test.scss */
    .u-fg__greenalt0 {
      color: #6ce075;
    }
    /* line 33, ../sass/test.scss */
    .u-fg__red0 {
      color: #cc3333;
    }
    /* line 33, ../sass/test.scss */
    .u-fg__redalt0 {
      color: red;
    }
    /* line 33, ../sass/test.scss */
    .u-fg__yellow0 {
      color: #ffdd33;
    }
    /* line 33, ../sass/test.scss */
    .u-fg__yellow2 {
      color: white;
    }
    

    Note that I quoted your mapping key names. Sass will convert those to their hex code equivalents under certain compression types.