angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.23k stars 6.7k forks source link

bug(M3): theme not being applied on mat-menu and mat-option #29367

Open Aljumaily opened 1 week ago

Aljumaily commented 1 week ago

Is this a regression?

The previous version in which this bug was not present was

No response

Description

I have the following working theme switcher code:

@use '@angular/material' as mat;
@import '@angular/cdk/overlay-prebuilt.css'; //copied it from a random place.

@mixin patch-menu-colour($theme) {
  @if mat.get-theme-type($theme)==dark {

    .mat-mdc-menu-panel,
    .mat-mdc-menu-item-text,
    .mat-mdc-menu-item,
    .mat-mdc-menu-content {
      --mat-menu-container-color: #00ff00 !important;
      background-color: var(--mat-menu-container-color) !important;
    }
  }

  @else {

    .mat-mdc-menu-panel,
    .mat-mdc-menu-item-text,
    .mat-mdc-menu-item,
    .mat-mdc-menu-content {
      --mat-menu-container-color: #ff00ff;
      background-color: var(--mat-menu-container-color) !important;
    }
  }

}

$light-theme: mat.define-theme(( //
      color: ( //
        theme-type: light,
        primary: mat.$azure-palette,
        tertiary: mat.$blue-palette,
      ),
      typography: ( //
        plain-family: "Arial",
        brand-family: "Arial",
        regular-weight: "Arial",
      ),
    ));

$dark-theme: mat.define-theme(( //
      color: ( //
        theme-type: dark,
        primary: mat.$magenta-palette,
        tertiary: mat.$violet-palette,
      ),
      typography: ( //
        plain-family: "Playwrite US Modern",
        brand-family: "Playwrite US Modern",
        regular-weight: "Playwrite US Modern",
      ),
    ));

@include mat.core();
@include mat.color-variants-backwards-compatibility($light-theme);

:root {
  @include mat.all-component-themes($light-theme);
  @include mat.all-component-typographies($light-theme);
  @include mat.system-level-typography($light-theme);
  @include mat.system-level-colors($light-theme);
  @include patch-menu-colour($light-theme);
}

.light-theme {
  @include mat.system-level-typography($light-theme);
  @include mat.all-component-typographies($light-theme);
  @include mat.system-level-typography($light-theme);
  @include patch-menu-colour($light-theme);
}

.dark-theme {

  @include mat.all-component-colors($dark-theme);
  @include mat.system-level-typography($dark-theme);
  @include mat.all-component-typographies($dark-theme);
  @include mat.system-level-colors($dark-theme);
  @include mat.system-level-typography($dark-theme);
  @include mat.system-level-colors($dark-theme);
  @include patch-menu-colour($dark-theme);
}

All of the mat-... work by default except mat-menu and mat-option.

I create a custom mixin to manually update the colour of mat-menu but it only works for the light theme because it is placed in :root{ }. Otherwise, it will not be triggered. All of the packages are up to date and no errors occur. The html code used is:

<div ngClass="dark-theme">
  <mat-menu #langMenu="matMenu" color="primary" >
    <button
      mat-menu-item
      (click)="changeLanguage(language)"
      name="languageSelector"
      yPosition="below"
      *ngFor="let language of languages"
    >
      <mat-icon [svgIcon]="language.icon"></mat-icon>
      <span>{{ language.text }}</span>
    </button>
  </mat-menu>

  <mat-form-field>
    <mat-label>Select an option</mat-label>
    <mat-select>
      <mat-option>None</mat-option>
      <mat-option value="option1">Option 1</mat-option>
      <mat-option value="option2">Option 2</mat-option>
      <mat-option value="option3">Option 3</mat-option>
    </mat-select>
  </mat-form-field>
</div>

Reproduction

There is no StackBlitz link because the link of the documentation doesn't work with Angular 18.0.6.

Expected Behavior

The expected behaviour is to have both mat-menu and mat-option to follow automatically the theme, without the need of custom mixins.

Actual Behavior

The mat-menu is updated once because the mixin call was placed in :root{}, and mat-option just doesn't work.

mat-menu mat-option

Environment

Angular CLI: 18.0.6 Node: 20.14.0 Package Manager: npm 10.8.1 OS: darwin arm64

Angular: 18.0.5 ... animations, cdk, common, compiler, compiler-cli, core, forms ... material, platform-browser, platform-browser-dynamic, router

Package Version

@angular-devkit/architect 0.1800.6 @angular-devkit/build-angular 18.0.6 @angular-devkit/core 18.0.6 @angular-devkit/schematics 18.0.6 @angular/cli 18.0.6 @schematics/angular 18.0.6 rxjs 7.8.1 typescript 5.4.5 zone.js 0.14.7

crisbeto commented 5 days ago

What color are you expecting for the menu and option exactly? I just tried it out and it seems like they have the proper color based on the passed-in palettes:

image image
Aljumaily commented 5 days ago

The issue is apparent when the project has two themes. Suppose that the light theme is applied in :root{ ... }, then it will work fine and the correct colours will be applied. Now, suppose a toggle button is available to switch to dark theme, then other components, such as mat-button, mat-button-toggle-group, etc. will have the correct theme applied. However, mat-menu and mat-option will still follow the light theme style. So, if the toggle button is kept on being clicked to change from to light theme to dark theme and vice-versa, mat-menu and mat-option will apply the same theme found in :root{ ... }, regardless of which theme is currently selected.

crisbeto commented 4 days ago

What element are you applying the theme classes to? I suspect that it isn't being set on the .cdk-overlay-container.

Aljumaily commented 4 days ago

I am applying the themes on all of the components as am using the following commands:

@include mat.all-component-themes($light-theme);
@include mat.all-component-typographies($light-theme);
@include mat.system-level-typography($light-theme);
@include mat.system-level-colors($light-theme);

As for using .cdk-overlay-container, unfortunately, it doesn't work as expected. It will change to the theme specified in :root { ... }. Switching the theme from light to dark or vice-versa will show one and only one colour.