angular / components

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

docs-bug(*): Missing migration guide to v19 #30055

Open martinboue opened 6 days ago

martinboue commented 6 days ago

Documentation Feedback

I'm struggling to migrate from Angular Material v18 (with MD3) to v19. I did not find any migration guide and the new guides do not explain the basics as deeply as in the previous version.

Here are the most important use cases that I don't know how to deal with:

Note: I'm trying to remove the old $theme = mat.define-theme(...) to use the new @include mat.theme mixins

Styling custom components

Before

.my-component {
   background-color: mat.get-theme-color(theme.$theme, neutral, 98)
}

After

I cannot use mat.get-theme-color because I don't have a $theme anymore (previously from mat.define-theme). How can I do that?

Material 3 theme setup

Before

@include mat.core();
:root {
   @include mat.core-theme(theme.$light-theme);
}

After

It has been automatically replaced to:

@include mat.elevation-classes();
@include mat.app-background();
:root {
   @include mat.elevation-classes();
   @include mat.app-background();
}

What is it for? Why isn't it present if I create a new application with Angular Material? Should it be duplicated? I don't see any documentation mentioning those mixins.

Customising material components

Before

I could do this:

@include mat.chips-color(theme.$theme, $color-variant: primary);
@include mat.form-field-density(-3);

After

How to do the same? Do I need to use the new overrides mixins and set each color tokens? For example, that would be 25 colors for the chip component.

Affected documentation page

https://material.angular.io/guide/theming

X-Celcius commented 6 days ago

This is not only an issue when you want to migrate to the new mat.theme and override mixins. According to the comment in _core.scss, mat.core() is deprecated and doesn't do anything in v19. It took us some time to find out why .mat-app-background was no longer being defined when updating to v19. If this is a breaking change it should at least be mentioned in the Changelog, but I can't find mat.core being mentioned there either.

X-Celcius commented 6 days ago

And while this is not related to documentation, may I also suggest to keep the scss in mat.core as it was and just add the deprecation annotation / warning rather than immediately changing the behavior and adding a comment that it is going to be removed in v21? Because if you already have to modify your code to get the old behavior why keep an empty mixin around?

andrewseguin commented 5 days ago

Thanks for the feedback. Our previous theme config system was fairly complex and required a deep guide on its mechanics. We're hoping this new system is more straightforward with how it operates, but this means the guide might feel more lightweight than before.

Styling custom components

In the same pattern of system CSS variables, I'd recommend simply creating a top-level CSS variable for colors you want to use within your application. E.g.

--my-app-theme-neutral98: map.get($my-palette, neutral, 98);

This bypasses the need to create a separate mixin in your component styles that accepts a theme config, and allows you to just put the style directly in your component style.

If you want to continue using the mixin concept, you can pass it the palette or color directly.

Otherwise, you can always continue creating a theme config that can be passed around, in parallel to using mat.theme.

Material 3 theme setup

mat.core was replaced by elevation-classes and app-background since those styles were previously included in its old implementation. However, mat.core-theme should not have been replaced. If that happened in the update schematic, it should be filed as a bug.

For a new app, we don't really recommend using elevation-classes or app-background anymore. Elevation can be applied using the system level variables instead. And the app background can be set yourself if necessary (this is pointed out in the theming guide), which has the benefit of being explicit rather than a black-box mixin.

Customizing material components

What are you trying to achieve in the line for chips-color? Isn't the default going to be primary?

If you are trying to set it with a different color, you can write a selector that targets your mat-chips and redefine the theme as described in https://material.angular.io/guide/theming#context-specific-themes

This applies for density as well - you can target the form field and call mat.theme((density: -3)); or otherwise call the form field's overrides mixin and directly customize the tokens, e.g.

  @include mat.form-field-overrides((
    container-height: 44px,
    container-vertical-padding: 10px,
    filled-with-label-container-padding-top: 10px,
    filled-with-label-container-padding-bottom: 10px,
  ));

However, the density mixin still exists and you can continue calling mat.form-field-density(-3)

andrewseguin commented 5 days ago

This is not only an issue when you want to migrate to the new mat.theme and override mixins. According to the comment in _core.scss, mat.core() is deprecated and doesn't do anything in v19. It took us some time to find out why .mat-app-background was no longer being defined when updating to v19. If this is a breaking change it should at least be mentioned in the Changelog, but I can't find mat.core being mentioned there either.

mat.core should have been replaced through the schematic to be:

@include mat.elevation-classes();
@include mat.app-background();

If this wasn't the case, it'd be helpful to have an issue filed. Our intention is to keep the same behavior/styling preserved for applications in the update process

martinboue commented 5 days ago

Thanks @andrewseguin for your response, it has helped me a lot, but I still have a few issues:

Styling custom components

For color, replacing mat.get-theme-color(theme.$theme, neutral, 98) by map.get(theme.$palettes, neutral, 98) works great. Just one comment, I think it could be documented under Theming > Using Theme Styles

And for other styles, for example typography, I was used to do:

.my-component {
   font: mat.get-theme-typography(theme.$theme, label-large, font);
}

and now I should do the following (as described here)

.my-component {
   font: var(--mat-sys-label-large);
}

Am I right?

It is regrettable that reading theme styles does not follow the same rule as overriding styles, such as:

Angular strongly discourages, and does not directly support, overriding component CSS outside the theming APIs described above. Component DOM structure and CSS classes are considered private implementation details that may change at any time. CSS variables used by the Angular Material components should be defined through the overrides API instead of defined explicitly.

It would be great to have public APIs to rely on instead of CSS variables that cannot be checked during compilation.

Material 3 theme setup

I'll file a new issue for @include mat.core-theme(theme.$light-theme); being replaced to @include mat.elevation-classes(); and @include mat.app-background();

Customizing material components

Note: for chips, secondary color is actually the default one. It's documented here on v18. I was indeed changing the color from secondary to primary.

What you suggested do not work for me. I have:

// Theme setup, previously generated in v18
$palettes: (
   primary: (...),
   secondary: (...),
   ...
);
$_rest: (
   secondary: map.get($palettes, secondary),
   neutral: map.get($palettes, neutral),
   neutral-variant: map.get($palettes, neutral-variant),
   error: map.get($palettes, error),
);
$primary-palette: map.merge(map.get($palettes, primary), $_rest);

// Here I am trying to change the default color for all mat-chip
mat-chip-row {
   @include mat.theme((
      color: theme.$primary-palette,
   ));
}

It has no effect, no CSS properties have beean generated.

mat.theme((density: -3)) works great but compared to v18 it generates useless/unrelated CSS:

mat-chip-row {
   --mdc-checkbox-state-layer-size: 28px;
   --mdc-chip-container-height: 24px; // <====== I only need this one I guess
   --mdc-text-button-container-height: 28px;
   --mdc-protected-button-container-height: 28px;
   --mdc-filled-button-container-height: 28px;
   --mdc-outlined-button-container-height: 28px;
   --mdc-icon-button-state-layer-size: 28px;
   --mdc-list-list-item-one-line-container-height: 36px;
   --mdc-list-list-item-two-line-container-height: 52px;
   --mdc-list-list-item-three-line-container-height: 76px;
   --mdc-radio-state-layer-size: 28px;
   --mdc-secondary-navigation-tab-container-height: 36px;
   --mat-checkbox-touch-target-display: none;
   --mat-expansion-header-collapsed-state-height: 36px;
   --mat-expansion-header-expanded-state-height: 48px;
   --mat-fab-touch-target-display: none;
   --mat-form-field-container-height: 44px;
   --mat-form-field-filled-label-display: none;
   --mat-form-field-container-vertical-padding: 10px;
   --mat-form-field-filled-with-label-container-padding-top: 10px;
   --mat-form-field-filled-with-label-container-padding-bottom: 10px;
   --mat-icon-button-touch-target-display: none;
   --mat-list-list-item-leading-icon-start-space: 4px;
   --mat-list-list-item-leading-icon-end-space: 4px;
   --mat-text-button-touch-target-display: none;
   --mat-protected-button-touch-target-display: none;
   --mat-filled-button-touch-target-display: none;
   --mat-outlined-button-touch-target-display: none;
   --mat-paginator-container-size: 40px;
   --mat-paginator-form-field-container-height: 40px;
   --mat-paginator-form-field-container-vertical-padding: 8px;
   --mat-paginator-touch-target-display: none;
   --mat-radio-touch-target-display: none;
   --mat-select-arrow-transform: none;
   --mat-standard-button-toggle-height: 36px;
   --mat-stepper-header-height: 60px;
   --mat-table-header-container-height: 44px;
   --mat-table-footer-container-height: 40px;
   --mat-table-row-item-container-height: 40px;
   --mat-toolbar-standard-height: 52px;
   --mat-toolbar-mobile-height: 44px;
   --mat-tree-node-min-height: 36px;
}

Is there any way to generate only component related properties?

Also, now I need to specify every kind of chips (mat-chip, mat-chip-row and mat-chip-option) and rely on private CSS class or material host tag, both of which can change in the future and are not checked at compile time. Is there any other solution?

rars commented 5 days ago

It's not obvious to me how to handle typography for non-component styles. The default styles of h1, h2 etc. don't seem to look very nice with just the @include mat.theme(...) approach (I think the mixin doesn't touch the styles on these tags). I used to include the typography-hierarchy mixin and use the classes listed in type scale levels. I couldn't find relevant documentation and if it's missing, I think the documentation would benefit from touching on this subject.

X-Celcius commented 1 day ago

If this wasn't the case, it'd be helpful to have an issue filed. Our intention is to keep the same behavior/styling preserved for applications in the update process

Thanks, I wasn't aware of an update schematic. My colleague updated the Angular core libraries using ng update before the cdk & materials packages were available in v19. A day later, he updated the material packages directly without running ng update. I retried going v18 to v19 from scratch and everything updated automatically so this is actually working fine. Still - please consider adding this change to CHANGELOG.md as I consider this to be a breaking change and it is not mentioned there. Automatic migrations are nice if they work but knowing what and why something will change is also essential when upgrading.

martinboue commented 1 day ago

Because some of my comments on this issue goes beyond the scope "Migrating v18 to v19", I have created a specific request on "how to get theme values without relying on private APIs", see #30083

My main concern now is: How to migrate v18 mat.<component>-color mixins to v19?

If the solution is using the new mat.<component>-overrides mixin, could you consider adding a new mixin to easily change color for a single component without specifying every color tokens?