angularsassangular-materialangular-material-6angular-material-theming

How to propagate graphical theme efficiently in Angular with Sass?


Scenario :

For example:

$themeAColors: (
    my-background-color: 'blue';
    my-color: 'green';
);

$themeBColors: (
    my-background-color: 'red';
    my-color: 'yellow';
);

$themeCColors: (
    my-background-color: 'white';
    my-color: 'black';
)

Then in every sub components in which I wish to apply my theme I'm using the following pattern:

@mixin subComponentStyle($theme) {
    .title {
       background-color: map-get($theme, my-background-color);
       color: map-get($theme, my-color);
    }
}

:host-context(.themeA) {
    @include subComponentStyle($themeAColors);
}

:host-context(.themeB) {
    @include subComponentStyle($themeBColors);
}

:host-context(.themeC) {
    @include subComponentStyle($themeCColors);
}



Problem :

Update: Thank you, that is helping simplify things a bit. Now we would like to find a way to avoid copying this block in every sub-components:

@each $param in ($themeAColors, $themeBColors, $themeCColors) {
   $name: map-get($param, name);
   :host-context(#{ $name }) {
       @include subComponentStyle($param);
    }
}

Ideally, we would like to replace this by a function call that would take any mixin in parameter and apply it. So in every components we would just have to call this function with the right mixin to handle theming.


Solution

  • Sass mixin with multiple themes and :host-context

    Be careful with the use of :host-context is does not have a lot of support.

    After playing around for a while with the sass could i got it to iterate over a list of themes. The themes are then passed down to the mixing.
    Used a name variable in the loop so it can get used in the css rule definition.

    @mixin subComponentStyle($theme) {
      background-color: map-get($theme, my-background-color);
      color: map-get($theme, my-color);
    }
    
    $themeAColors: (
      name: ".themeA",
      my-color: 'blue',
      my-background-color: 'red',
    );
    
    $themeBColors: (
      name: ".themeB",
      my-color: 'white',
      my-background-color: 'black',
    );
    
    $themeCColors: (
      name: ".themeC",
      my-color: 'Orange',
      my-background-color: '#2a4',
    );
    
    @each $param in ($themeAColors, $themeBColors, $themeCColors) {
      $name: map-get($param, name);
      :host-context(#{ $name }) {
        @include subComponentStyle($param);
      }
    }
    

    And this compiles to this css:

    :host-context(.themeA) {
      background-color: "red";
      color: "blue";
    }
    
    :host-context(.themeB) {
      background-color: "black";
      color: "white";
    }
    
    :host-context(.themeC) {
      background-color: "#2a4";
      color: "Orange";
    }