diff --git a/integration/mdc-migration/golden/src/styles.scss b/integration/mdc-migration/golden/src/styles.scss index 1f2234162fca..e5c476038e8e 100644 --- a/integration/mdc-migration/golden/src/styles.scss +++ b/integration/mdc-migration/golden/src/styles.scss @@ -46,6 +46,8 @@ $sample-project-theme: mat.define-light-theme(( @include mat.mdc-progress-bar-typography($sample-project-theme); @include mat.mdc-paginator-theme($sample-project-theme); @include mat.mdc-paginator-typography($sample-project-theme); +@include mat.mdc-list-theme($sample-project-theme); +@include mat.mdc-list-typography($sample-project-theme); @include mat.mdc-dialog-theme($sample-project-theme); @include mat.mdc-dialog-typography($sample-project-theme); @include mat.mdc-chips-theme($sample-project-theme); diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/components/list/list-styles.spec.ts b/src/material/schematics/ng-generate/mdc-migration/rules/components/list/list-styles.spec.ts new file mode 100644 index 000000000000..59a0a3ef9606 --- /dev/null +++ b/src/material/schematics/ng-generate/mdc-migration/rules/components/list/list-styles.spec.ts @@ -0,0 +1,274 @@ +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('list styles', () => { + let runner: SchematicTestRunner; + let cliAppTree: UnitTestTree; + + async function runMigrationTest(oldFileContent: string, newFileContent: string) { + cliAppTree.create(THEME_FILE, oldFileContent); + const tree = await migrateComponents(['list'], 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.list-theme($theme); + `, + ` + @use '@angular/material' as mat; + $theme: (); + @include mat.mdc-list-theme($theme); + @include mat.mdc-list-typography($theme); + `, + ); + }); + + it('should use the correct namespace', async () => { + await runMigrationTest( + ` + @use '@angular/material' as arbitrary; + $theme: (); + @include arbitrary.list-theme($theme); + `, + ` + @use '@angular/material' as arbitrary; + $theme: (); + @include arbitrary.mdc-list-theme($theme); + @include arbitrary.mdc-list-typography($theme); + `, + ); + }); + + it('should handle updating multiple themes', async () => { + await runMigrationTest( + ` + @use '@angular/material' as mat; + $light-theme: (); + $dark-theme: (); + @include mat.list-theme($light-theme); + @include mat.list-theme($dark-theme); + `, + ` + @use '@angular/material' as mat; + $light-theme: (); + $dark-theme: (); + @include mat.mdc-list-theme($light-theme); + @include mat.mdc-list-typography($light-theme); + @include mat.mdc-list-theme($dark-theme); + @include mat.mdc-list-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-list-theme($theme); + @include mat.mdc-list-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-list-theme($light-theme); + @include mat.mdc-list-typography($light-theme); + @include mat.all-component-themes($dark-theme); + @include mat.mdc-list-theme($dark-theme); + @include mat.mdc-list-typography($dark-theme); + `, + ); + }); + + it('should preserve whitespace', async () => { + await runMigrationTest( + ` + @use '@angular/material' as mat; + $theme: (); + + + @include mat.list-theme($theme); + + + `, + ` + @use '@angular/material' as mat; + $theme: (); + + + @include mat.mdc-list-theme($theme); + @include mat.mdc-list-typography($theme); + + + `, + ); + }); + }); + + describe('selector migrations', () => { + it('should update the legacy mat-list classname', async () => { + await runMigrationTest( + ` + .mat-list { + padding: 25px; + } + `, + ` + .mat-mdc-list { + padding: 25px; + } + `, + ); + }); + + it('should update multiple legacy classnames', async () => { + await runMigrationTest( + ` + .mat-list { + padding: 25px; + } + .mat-subheader { + color: red; + } + `, + ` + .mat-mdc-list { + padding: 25px; + } + .mat-mdc-subheader { + color: red; + } + `, + ); + }); + + it('should update a legacy classname w/ multiple selectors', async () => { + await runMigrationTest( + ` + .some-class.mat-list, .another-class { + padding: 25px; + } + `, + ` + .some-class.mat-mdc-list, .another-class { + padding: 25px; + } + `, + ); + }); + + it('should preserve the whitespace of multiple selectors', async () => { + await runMigrationTest( + ` + .some-class, + .mat-list, + .another-class { padding: 25px; } + `, + ` + .some-class, + .mat-mdc-list, + .another-class { padding: 25px; } + `, + ); + }); + + it('should add comment for potentially deprecated selector', async () => { + await runMigrationTest( + ` + .mat-list-item-content { + padding: 16px; + } + `, + ` + /* TODO: The following rule targets internal classes of list that may no longer apply for the MDC version. */ + + .mat-list-item-content { + padding: 16px; + } + `, + ); + }); + + it('should not add comment for legacy selector that also starts with deprecated prefix', async () => { + await runMigrationTest( + ` + .mat-list-icon { + color: red; + } + `, + ` + .mat-mdc-list-item-icon { + color: red; + } + `, + ); + }); + + it('should add comment for potentially deprecated multi-line selector', async () => { + await runMigrationTest( + ` + .some-class + .mat-list-item-content { + padding: 16px; + } + `, + ` + /* TODO: The following rule targets internal classes of list that may no longer apply for the MDC version. */ + + .some-class + .mat-list-item-content { + padding: 16px; + } + `, + ); + }); + + it('should update the legacy mat-list class and add comment for potentially deprecated selector', async () => { + await runMigrationTest( + ` + .mat-list.some-class, .mat-list-item-content { + padding: 16px; + } + `, + ` + /* TODO: The following rule targets internal classes of list that may no longer apply for the MDC version. */ + + .mat-mdc-list.some-class, .mat-list-item-content { + padding: 16px; + } + `, + ); + }); + }); +}); diff --git a/src/material/schematics/ng-generate/mdc-migration/rules/components/list/list-styles.ts b/src/material/schematics/ng-generate/mdc-migration/rules/components/list/list-styles.ts new file mode 100644 index 000000000000..3d3f805d490b --- /dev/null +++ b/src/material/schematics/ng-generate/mdc-migration/rules/components/list/list-styles.ts @@ -0,0 +1,31 @@ +/** + * @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 ListStylesMigrator extends StyleMigrator { + component = 'list'; + + deprecatedPrefix = 'mat-list'; + + mixinChanges = [ + { + old: 'list-theme', + new: ['mdc-list-theme', 'mdc-list-typography'], + }, + ]; + + classChanges: ClassNameChange[] = [ + {old: `.mat-list-base`, new: `.mat-mdc-list-base`}, + {old: `.mat-list`, new: `.mat-mdc-list`}, + {old: `.mat-list-avatar`, new: `.mat-mdc-list-item-avatar`}, + {old: `.mat-list-icon`, new: `.mat-mdc-list-item-icon`}, + {old: `.mat-subheader`, new: `.mat-mdc-subheader`}, + {old: `.mat-list-item`, new: `.mat-mdc-list-item`}, + ]; +} 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 fcd537482e4d..c222280ccadc 100644 --- a/src/material/schematics/ng-generate/mdc-migration/rules/index.ts +++ b/src/material/schematics/ng-generate/mdc-migration/rules/index.ts @@ -12,6 +12,7 @@ import {CardTemplateMigrator} from './components/card/card-template'; import {CheckboxStylesMigrator} from './components/checkbox/checkbox-styles'; import {ChipsStylesMigrator} from './components/chips/chips-styles'; import {DialogStylesMigrator} from './components/dialog/dialog-styles'; +import {ListStylesMigrator} from './components/list/list-styles'; import {PaginatorStylesMigrator} from './components/paginator/paginator-styles'; import {ProgressBarStylesMigrator} from './components/progress-bar/progress-bar-styles'; import {ProgressSpinnerStylesMigrator} from './components/progress-spinner/progress-spinner-styles'; @@ -51,6 +52,10 @@ export const MIGRATORS: ComponentMigrator[] = [ component: 'dialog', styles: new DialogStylesMigrator(), }, + { + component: 'list', + styles: new ListStylesMigrator(), + }, { component: 'paginator', styles: new PaginatorStylesMigrator(),