diff --git a/integration/mdc-migration/golden/src/styles.scss b/integration/mdc-migration/golden/src/styles.scss index 488ef33352ff..5d8b53cd45e2 100644 --- a/integration/mdc-migration/golden/src/styles.scss +++ b/integration/mdc-migration/golden/src/styles.scss @@ -42,6 +42,10 @@ $sample-project-theme: mat.define-light-theme(( @include mat.mdc-slider-typography($sample-project-theme); @include mat.mdc-slide-toggle-theme($sample-project-theme); @include mat.mdc-slide-toggle-typography($sample-project-theme); +@include mat.mdc-select-theme($sample-project-theme); +@include mat.mdc-select-typography($sample-project-theme); +@include mat.mdc-core-theme($sample-project-theme); +@include mat.mdc-core-typography($sample-project-theme); @include mat.mdc-radio-theme($sample-project-theme); @include mat.mdc-radio-typography($sample-project-theme); @include mat.mdc-progress-spinner-theme($sample-project-theme); diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/components/select/select-styles.spec.ts b/src/material/schematics/ng-generate/mdc-migration/rules/components/select/select-styles.spec.ts new file mode 100644 index 000000000000..761a61b1f832 --- /dev/null +++ b/src/material/schematics/ng-generate/mdc-migration/rules/components/select/select-styles.spec.ts @@ -0,0 +1,308 @@ +import {createTestApp, patchDevkitTreeToExposeTypeScript} from '@angular/cdk/schematics/testing'; +import {SchematicTestRunner, UnitTestTree} from '@angular-devkit/schematics/testing'; +import {createNewTestRunner, migrateComponents, THEME_FILE} from '../test-setup-helper'; + +describe('select styles', () => { + let runner: SchematicTestRunner; + let cliAppTree: UnitTestTree; + + async function runMigrationTest(oldFileContent: string, newFileContent: string) { + cliAppTree.create(THEME_FILE, oldFileContent); + const tree = await migrateComponents(['select'], runner, cliAppTree); + expect(tree.readContent(THEME_FILE)).toBe(newFileContent); + } + + beforeEach(async () => { + runner = createNewTestRunner(); + cliAppTree = patchDevkitTreeToExposeTypeScript(await createTestApp(runner)); + }); + + describe('mixin migrations', () => { + it('should replace the old theme with the new ones', async () => { + await runMigrationTest( + ` + @use '@angular/material' as mat; + $theme: (); + @include mat.select-theme($theme); + `, + ` + @use '@angular/material' as mat; + $theme: (); + @include mat.mdc-select-theme($theme); + @include mat.mdc-select-typography($theme); + @include mat.mdc-core-theme($theme); + @include mat.mdc-core-typography($theme); + `, + ); + }); + + it('should use the correct namespace', async () => { + await runMigrationTest( + ` + @use '@angular/material' as arbitrary; + $theme: (); + @include arbitrary.select-theme($theme); + `, + ` + @use '@angular/material' as arbitrary; + $theme: (); + @include arbitrary.mdc-select-theme($theme); + @include arbitrary.mdc-select-typography($theme); + @include arbitrary.mdc-core-theme($theme); + @include arbitrary.mdc-core-typography($theme); + `, + ); + }); + + it('should handle updating multiple themes', async () => { + await runMigrationTest( + ` + @use '@angular/material' as mat; + $light-theme: (); + $dark-theme: (); + @include mat.select-theme($light-theme); + @include mat.select-theme($dark-theme); + `, + ` + @use '@angular/material' as mat; + $light-theme: (); + $dark-theme: (); + @include mat.mdc-select-theme($light-theme); + @include mat.mdc-select-typography($light-theme); + @include mat.mdc-core-theme($light-theme); + @include mat.mdc-core-typography($light-theme); + @include mat.mdc-select-theme($dark-theme); + @include mat.mdc-select-typography($dark-theme); + @include mat.mdc-core-theme($dark-theme); + @include mat.mdc-core-typography($dark-theme); + `, + ); + }); + + it('should add correct theme if all-component-themes mixin included', async () => { + await runMigrationTest( + ` + @use '@angular/material' as mat; + $theme: (); + @include mat.all-component-themes($theme); + `, + ` + @use '@angular/material' as mat; + $theme: (); + @include mat.all-component-themes($theme); + @include mat.mdc-select-theme($theme); + @include mat.mdc-select-typography($theme); + @include mat.mdc-core-theme($theme); + @include mat.mdc-core-typography($theme); + @include mat.mdc-input-theme($theme); + @include mat.mdc-input-typography($theme); + @include mat.mdc-form-field-theme($theme); + @include mat.mdc-form-field-typography($theme); + @include mat.mdc-autocomplete-theme($theme); + @include mat.mdc-autocomplete-typography($theme); + `, + ); + }); + + it('should add multiple themes for multiple all-component-themes mixins', async () => { + await runMigrationTest( + ` + @use '@angular/material' as mat; + $light-theme: (); + $dark-theme: (); + @include mat.all-component-themes($light-theme); + @include mat.all-component-themes($dark-theme); + `, + ` + @use '@angular/material' as mat; + $light-theme: (); + $dark-theme: (); + @include mat.all-component-themes($light-theme); + @include mat.mdc-select-theme($light-theme); + @include mat.mdc-select-typography($light-theme); + @include mat.mdc-core-theme($light-theme); + @include mat.mdc-core-typography($light-theme); + @include mat.mdc-input-theme($light-theme); + @include mat.mdc-input-typography($light-theme); + @include mat.mdc-form-field-theme($light-theme); + @include mat.mdc-form-field-typography($light-theme); + @include mat.mdc-autocomplete-theme($light-theme); + @include mat.mdc-autocomplete-typography($light-theme); + @include mat.all-component-themes($dark-theme); + @include mat.mdc-select-theme($dark-theme); + @include mat.mdc-select-typography($dark-theme); + @include mat.mdc-core-theme($dark-theme); + @include mat.mdc-core-typography($dark-theme); + @include mat.mdc-input-theme($dark-theme); + @include mat.mdc-input-typography($dark-theme); + @include mat.mdc-form-field-theme($dark-theme); + @include mat.mdc-form-field-typography($dark-theme); + @include mat.mdc-autocomplete-theme($dark-theme); + @include mat.mdc-autocomplete-typography($dark-theme); + `, + ); + }); + + it('should preserve whitespace', async () => { + await runMigrationTest( + ` + @use '@angular/material' as mat; + $theme: (); + + + @include mat.select-theme($theme); + + + `, + ` + @use '@angular/material' as mat; + $theme: (); + + + @include mat.mdc-select-theme($theme); + @include mat.mdc-select-typography($theme); + @include mat.mdc-core-theme($theme); + @include mat.mdc-core-typography($theme); + + + `, + ); + }); + }); + + describe('selector migrations', () => { + it('should update the legacy mat-select classname', async () => { + await runMigrationTest( + ` + .mat-select { + padding: 16px; + } + `, + ` + .mat-mdc-select { + padding: 16px; + } + `, + ); + }); + + it('should update multiple legacy classnames', async () => { + await runMigrationTest( + ` + .mat-select { + padding: 16px; + } + .mat-option { + padding: 16px; + } + `, + ` + .mat-mdc-select { + padding: 16px; + } + .mat-mdc-option { + padding: 16px; + } + `, + ); + }); + + it('should update a legacy classname w/ multiple selectors', async () => { + await runMigrationTest( + ` + .some-class.mat-select, .another-class { + padding: 16px; + } + `, + ` + .some-class.mat-mdc-select, .another-class { + padding: 16px; + } + `, + ); + }); + + it('should preserve the whitespace of multiple selectors', async () => { + await runMigrationTest( + ` + .some-class, + .mat-select, + .another-class { padding: 16px; } + `, + ` + .some-class, + .mat-mdc-select, + .another-class { padding: 16px; } + `, + ); + }); + + it('should add comment for potentially deprecated selector', async () => { + await runMigrationTest( + ` + .mat-select-value { + color: red; + } + `, + ` + /* TODO: The following rule targets internal classes of select that may no longer apply for the MDC version. */ + + .mat-select-value { + color: red; + } + `, + ); + }); + + it('should not add comment for legacy selector that also starts with deprecated prefix', async () => { + await runMigrationTest( + ` + .mat-select-panel { + padding: 16px; + } + `, + ` + .mat-mdc-select-panel { + padding: 16px; + } + `, + ); + }); + + it('should add comment for potentially deprecated multi-line selector', async () => { + await runMigrationTest( + ` + .some-class + .mat-select-value { + color: red; + } + `, + ` + /* TODO: The following rule targets internal classes of select that may no longer apply for the MDC version. */ + + .some-class + .mat-select-value { + color: red; + } + `, + ); + }); + + it('should update the legacy mat-select class and add comment for potentially deprecated selector', async () => { + await runMigrationTest( + ` + .mat-select.some-class, .mat-select-value { + padding: 16px; + } + `, + ` + /* TODO: The following rule targets internal classes of select that may no longer apply for the MDC version. */ + + .mat-mdc-select.some-class, .mat-select-value { + padding: 16px; + } + `, + ); + }); + }); +}); diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/components/select/select-styles.ts b/src/material/schematics/ng-generate/mdc-migration/rules/components/select/select-styles.ts new file mode 100644 index 000000000000..05eb1e10d82f --- /dev/null +++ b/src/material/schematics/ng-generate/mdc-migration/rules/components/select/select-styles.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {ClassNameChange, StyleMigrator} from '../../style-migrator'; + +export class SelectStylesMigrator extends StyleMigrator { + component = 'select'; + + deprecatedPrefixes = ['mat-select', 'mat-option']; + + mixinChanges = [ + { + old: 'select-theme', + new: ['mdc-select-theme', 'mdc-select-typography', 'mdc-core-theme', 'mdc-core-typography'], + }, + ]; + + classChanges: ClassNameChange[] = [ + {old: '.mat-select', new: '.mat-mdc-select'}, + {old: '.mat-select-panel', new: '.mat-mdc-select-panel'}, + {old: '.mat-option', new: '.mat-mdc-option'}, + ]; +} diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/index.ts b/src/material/schematics/ng-generate/mdc-migration/rules/index.ts index cbfeab2c4b6c..6a220c9a47d1 100644 --- a/src/material/schematics/ng-generate/mdc-migration/rules/index.ts +++ b/src/material/schematics/ng-generate/mdc-migration/rules/index.ts @@ -26,6 +26,7 @@ import {ProgressBarStylesMigrator} from './components/progress-bar/progress-bar- import {ProgressSpinnerStylesMigrator} from './components/progress-spinner/progress-spinner-styles'; import {RadioStylesMigrator} from './components/radio/radio-styles'; import {RuntimeMigrator} from './runtime-migrator'; +import {SelectStylesMigrator} from './components/select/select-styles'; import {SlideToggleStylesMigrator} from './components/slide-toggle/slide-toggle-styles'; import {SliderStylesMigrator} from './components/slider/slider-styles'; import {TableStylesMigrator} from './components/table/table-styles'; @@ -99,6 +100,10 @@ export const MIGRATORS: ComponentMigrator[] = [ component: 'radio', styles: new RadioStylesMigrator(), }, + { + component: 'select', + styles: new SelectStylesMigrator(), + }, { component: 'slide-toggle', styles: new SlideToggleStylesMigrator(),