From 61b5f2afca382308bd602de04bd9d8b1fbabf9b1 Mon Sep 17 00:00:00 2001
From: Amy Sorto <8575252+amysorto@users.noreply.github.com>
Date: Mon, 18 Nov 2024 16:35:01 +0000
Subject: [PATCH 1/3] feat(material/icon): Change icon font default to Material
symbols from Material icons
---
guides/getting-started.md | 4 ++--
guides/schematics.md | 11 +++++++----
integration/yarn-pnp-compat/src/index.html | 2 +-
src/e2e-app/index.html | 2 +-
src/material/icon/icon-registry.ts | 6 +++---
src/material/icon/icon.md | 11 +++++------
src/material/icon/icon.spec.ts | 12 ++++++------
src/material/icon/testing/fake-icon-registry.ts | 2 +-
.../schematics/ng-add/fonts/material-fonts.ts | 2 +-
src/material/schematics/ng-add/index.spec.ts | 2 +-
src/universal-app/index-source.html | 2 +-
11 files changed, 29 insertions(+), 27 deletions(-)
diff --git a/guides/getting-started.md b/guides/getting-started.md
index 059ff4351e31..45389bf6326c 100644
--- a/guides/getting-started.md
+++ b/guides/getting-started.md
@@ -35,7 +35,7 @@ The `ng add` command will additionally perform the following actions:
* Add project dependencies to `package.json`
* Add the Roboto font to your `index.html`
-* Add the Material Design icon font to your `index.html`
+* Add the Material Symbols icon font to your `index.html`
* Add a few global CSS styles to:
* Remove margins from `body`
* Set `height: 100%` on `html` and `body`
@@ -48,7 +48,7 @@ You're done! Angular Material is now configured to be used in your application.
Let's display a slide toggle component in your app and verify that everything works.
You need to import the `MatSlideToggleModule` that you want to display by adding the following lines to
-your standalone component's imports, or otherwise your component's `NgModule`.
+your standalone component's imports, or otherwise your component's `NgModule`.
```ts
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
diff --git a/guides/schematics.md b/guides/schematics.md
index 25d14101e6d9..c5d232075aad 100644
--- a/guides/schematics.md
+++ b/guides/schematics.md
@@ -22,13 +22,16 @@ In case you just want to install the `@angular/cdk`, there are also schematics f
ng add @angular/cdk
```
-The Angular Material `ng add` schematic helps you set up an Angular CLI project that uses Material. Running `ng add` will:
+The Angular Material `ng add` schematic helps you set up an Angular CLI project that uses Material.
+See the [`getting started guide](./getting-started#install-angular-material) for more information.
-- Ensure [project dependencies](./getting-started#step-1-install-angular-material-angular-cdk-and-angular-animations) are placed in `package.json`
-- Enable the [BrowserAnimationsModule](./getting-started#step-2-configure-animations) in your app module
+Running `ng add` will:
+
+- Ensure project dependencies are placed in `package.json`
+- Enable the BrowserAnimationsModule in your app module
- Add either a prebuilt theme or a custom theme
- Add Roboto fonts to your `index.html`
-- Add the [Material Icon font](./getting-started#step-6-optional-add-material-icons) to your `index.html`
+- Add the Material Symbols font to your `index.html`
- Add global styles to
- Remove margins from `body`
- Set `height: 100%` on `html` and `body`
diff --git a/integration/yarn-pnp-compat/src/index.html b/integration/yarn-pnp-compat/src/index.html
index dc58be14fdd7..65fc76e825e9 100644
--- a/integration/yarn-pnp-compat/src/index.html
+++ b/integration/yarn-pnp-compat/src/index.html
@@ -8,7 +8,7 @@
-
+
diff --git a/src/e2e-app/index.html b/src/e2e-app/index.html
index 32b525b4f1c0..35e390350bc4 100644
--- a/src/e2e-app/index.html
+++ b/src/e2e-app/index.html
@@ -7,7 +7,7 @@
-
+
diff --git a/src/material/icon/icon-registry.ts b/src/material/icon/icon-registry.ts
index 004a74060d93..f4f0cc37df94 100644
--- a/src/material/icon/icon-registry.ts
+++ b/src/material/icon/icon-registry.ts
@@ -145,10 +145,10 @@ export class MatIconRegistry implements OnDestroy {
/**
* The CSS classes to apply when an `` component has no icon name, url, or font
- * specified. The default 'material-icons' value assumes that the material icon font has been
- * loaded as described at https://google.github.io/material-design-icons/#icon-font-for-the-web
+ * specified. The default 'material-symbols-outlined' value assumes that the material icon font
+ * has been loaded as described at https://google.github.io/material-design-icons/#icon-font-for-the-web
*/
- private _defaultFontSetClass = ['material-icons', 'mat-ligature-font'];
+ private _defaultFontSetClass = ['material-symbols-outlined', 'mat-ligature-font'];
constructor(
@Optional() private _httpClient: HttpClient,
diff --git a/src/material/icon/icon.md b/src/material/icon/icon.md
index 4063a860a10f..37761136d2a2 100644
--- a/src/material/icon/icon.md
+++ b/src/material/icon/icon.md
@@ -17,14 +17,13 @@ Some fonts are designed to show icons by using
component.
By default, `` expects the
-[Material icons font](https://google.github.io/material-design-icons/#icon-font-for-the-web).
+[Material Symbols](https://developers.google.com/fonts/docs/material_symbols#use_in_web).
(You will still need to include the HTML to load the font and its CSS, as described in the link).
-You can specify a different font, such as Material's latest icons,
-[Material Symbols](https://fonts.google.com/icons), by setting the `fontSet` input to either the
-CSS class to apply to use the desired font, or to an alias previously registered with
-`MatIconRegistry.registerFontClassAlias`. Alternatively you can set the default for all
-your application's icons using `MatIconRegistry.setDefaultFontSetClass`.
+You can specify a different font, set the `fontSet` input to either the CSS class to apply to the
+desired font, or to an alias previously registered with `MatIconRegistry.registerFontClassAlias`.
+Alternatively you can set the default for all your application's icons using
+`MatIconRegistry.setDefaultFontSetClass`.
### Font icons with CSS
diff --git a/src/material/icon/icon.spec.ts b/src/material/icon/icon.spec.ts
index 84f9971285b9..206cd4f232ec 100644
--- a/src/material/icon/icon.spec.ts
+++ b/src/material/icon/icon.spec.ts
@@ -122,7 +122,7 @@ describe('MatIcon', () => {
'mat-icon',
'mat-ligature-font',
'mat-primary',
- 'material-icons',
+ 'material-symbols-outlined',
'notranslate',
]);
});
@@ -141,7 +141,7 @@ describe('MatIcon', () => {
'mat-icon',
'mat-icon-no-color',
'mat-ligature-font',
- 'material-icons',
+ 'material-symbols-outlined',
'notranslate',
]);
});
@@ -178,7 +178,7 @@ describe('MatIcon', () => {
});
describe('Ligature icons', () => {
- it('should add material-icons and mat-ligature-font class by default', () => {
+ it('should add material-symbols-outlined and mat-ligature-font class by default', () => {
const fixture = TestBed.createComponent(IconWithLigature);
const testComponent = fixture.componentInstance;
@@ -190,7 +190,7 @@ describe('MatIcon', () => {
'mat-icon',
'mat-icon-no-color',
'mat-ligature-font',
- 'material-icons',
+ 'material-symbols-outlined',
'notranslate',
]);
});
@@ -265,7 +265,7 @@ describe('MatIcon', () => {
expect(icon.getAttribute('fontIcon')).toBe('house');
});
- it('should add material-icons and mat-ligature-font class by default', () => {
+ it('should add material-symbols-outlined and mat-ligature-font class by default', () => {
const fixture = TestBed.createComponent(IconWithLigatureByAttribute);
const testComponent = fixture.componentInstance;
@@ -277,7 +277,7 @@ describe('MatIcon', () => {
'mat-icon',
'mat-icon-no-color',
'mat-ligature-font',
- 'material-icons',
+ 'material-symbols-outlined',
'notranslate',
]);
});
diff --git a/src/material/icon/testing/fake-icon-registry.ts b/src/material/icon/testing/fake-icon-registry.ts
index 0045b58c3284..75e7c70c0788 100644
--- a/src/material/icon/testing/fake-icon-registry.ts
+++ b/src/material/icon/testing/fake-icon-registry.ts
@@ -61,7 +61,7 @@ export class FakeMatIconRegistry implements PublicApi, OnDestro
}
getDefaultFontSetClass() {
- return ['material-icons'];
+ return ['material-symbols-outlined'];
}
getSvgIconFromUrl(): Observable {
diff --git a/src/material/schematics/ng-add/fonts/material-fonts.ts b/src/material/schematics/ng-add/fonts/material-fonts.ts
index 2470c768521e..56c7c988a849 100644
--- a/src/material/schematics/ng-add/fonts/material-fonts.ts
+++ b/src/material/schematics/ng-add/fonts/material-fonts.ts
@@ -28,7 +28,7 @@ export function addFontsToIndex(options: Schema): Rule {
const fonts = [
'https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap',
- 'https://fonts.googleapis.com/icon?family=Material+Icons',
+ 'https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined',
];
projectIndexFiles.forEach(indexFilePath => {
diff --git a/src/material/schematics/ng-add/index.spec.ts b/src/material/schematics/ng-add/index.spec.ts
index 803a9d243604..c1d560a4fca7 100644
--- a/src/material/schematics/ng-add/index.spec.ts
+++ b/src/material/schematics/ng-add/index.spec.ts
@@ -162,7 +162,7 @@ describe('ng-add schematic', () => {
// the created links properly align with the existing HTML. Default CLI projects use an
// indentation of two columns.
expect(htmlContent).toContain(
- '
-
+
From 0972ab621097870cd52afeafd21b65e9bba34991 Mon Sep 17 00:00:00 2001
From: Amy Sorto <8575252+amysorto@users.noreply.github.com>
Date: Mon, 9 Dec 2024 19:32:09 +0000
Subject: [PATCH 2/3] build: set up schematics for v20
---
src/cdk/schematics/migration.json | 8 +-
src/cdk/schematics/ng-update/index.ts | 4 +-
.../ng-update/migrations/misc-template.ts | 2 +-
.../schematics/update-tool/target-version.ts | 2 +-
src/material/schematics/migration.json | 8 +-
src/material/schematics/ng-update/index.ts | 13 +-
.../explicit-system-variable-prefix.ts | 125 ----------
.../ng-update/migrations/mat-core-removal.ts | 101 --------
...19-explicit-system-variable-prefix.spec.ts | 215 ------------------
.../test-cases/v19-mat-core-removal.spec.ts | 84 -------
10 files changed, 16 insertions(+), 546 deletions(-)
delete mode 100644 src/material/schematics/ng-update/migrations/explicit-system-variable-prefix.ts
delete mode 100644 src/material/schematics/ng-update/migrations/mat-core-removal.ts
delete mode 100644 src/material/schematics/ng-update/test-cases/v19-explicit-system-variable-prefix.spec.ts
delete mode 100644 src/material/schematics/ng-update/test-cases/v19-mat-core-removal.spec.ts
diff --git a/src/cdk/schematics/migration.json b/src/cdk/schematics/migration.json
index 0bf15e8d6334..b65a92dd0cae 100644
--- a/src/cdk/schematics/migration.json
+++ b/src/cdk/schematics/migration.json
@@ -1,10 +1,10 @@
{
"$schema": "./node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
- "migration-v19": {
- "version": "19.0.0-0",
- "description": "Updates the Angular CDK to v19",
- "factory": "./ng-update/index#updateToV19"
+ "migration-v20": {
+ "version": "20.0.0-0",
+ "description": "Updates the Angular CDK to v20",
+ "factory": "./ng-update/index#updateToV20"
},
"ng-post-update": {
"description": "Prints out results after ng-update.",
diff --git a/src/cdk/schematics/ng-update/index.ts b/src/cdk/schematics/ng-update/index.ts
index 046f272d0060..223f12e3bcab 100644
--- a/src/cdk/schematics/ng-update/index.ts
+++ b/src/cdk/schematics/ng-update/index.ts
@@ -14,9 +14,9 @@ import {createMigrationSchematicRule, NullableDevkitMigration} from './devkit-mi
const cdkMigrations: NullableDevkitMigration[] = [];
/** Entry point for the migration schematics with target of Angular CDK 18.0.0 */
-export function updateToV19(): Rule {
+export function updateToV20(): Rule {
return createMigrationSchematicRule(
- TargetVersion.V19,
+ TargetVersion.V20,
cdkMigrations,
cdkUpgradeData,
onMigrationComplete,
diff --git a/src/cdk/schematics/ng-update/migrations/misc-template.ts b/src/cdk/schematics/ng-update/migrations/misc-template.ts
index 54d2ab086186..25fb7caa02af 100644
--- a/src/cdk/schematics/ng-update/migrations/misc-template.ts
+++ b/src/cdk/schematics/ng-update/migrations/misc-template.ts
@@ -15,7 +15,7 @@ import {UpgradeData} from '../upgrade-data';
* instances of outdated Angular CDK API that can't be migrated automatically.
*/
export class MiscTemplateMigration extends Migration {
- // There are currently no migrations for V19 deprecations.
+ // There are currently no migrations for V20 deprecations.
enabled = false;
override visitTemplate(template: ResolvedResource): void {}
diff --git a/src/cdk/schematics/update-tool/target-version.ts b/src/cdk/schematics/update-tool/target-version.ts
index 26908bc23800..295939467932 100644
--- a/src/cdk/schematics/update-tool/target-version.ts
+++ b/src/cdk/schematics/update-tool/target-version.ts
@@ -10,7 +10,7 @@
// tslint:disable-next-line:prefer-const-enum
export enum TargetVersion {
- V19 = 'version 19',
+ V20 = 'version 20',
}
/**
diff --git a/src/material/schematics/migration.json b/src/material/schematics/migration.json
index 9a667ca12f4e..7675e20d8658 100644
--- a/src/material/schematics/migration.json
+++ b/src/material/schematics/migration.json
@@ -1,10 +1,10 @@
{
"$schema": "./node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
- "migration-v19": {
- "version": "19.0.0-0",
- "description": "Updates Angular Material to v19",
- "factory": "./ng-update/index_bundled#updateToV19"
+ "migration-v20": {
+ "version": "20.0.0-0",
+ "description": "Updates Angular Material to v20",
+ "factory": "./ng-update/index_bundled#updateToV20"
}
}
}
diff --git a/src/material/schematics/ng-update/index.ts b/src/material/schematics/ng-update/index.ts
index e9f51ee593a6..52ab85b84b7e 100644
--- a/src/material/schematics/ng-update/index.ts
+++ b/src/material/schematics/ng-update/index.ts
@@ -14,18 +14,13 @@ import {
} from '@angular/cdk/schematics';
import {materialUpgradeData} from './upgrade-data';
-import {MatCoreMigration} from './migrations/mat-core-removal';
-import {ExplicitSystemVariablePrefixMigration} from './migrations/explicit-system-variable-prefix';
-const materialMigrations: NullableDevkitMigration[] = [
- MatCoreMigration,
- ExplicitSystemVariablePrefixMigration,
-];
+const materialMigrations: NullableDevkitMigration[] = [];
-/** Entry point for the migration schematics with target of Angular Material v19 */
-export function updateToV19(): Rule {
+/** Entry point for the migration schematics with target of Angular Material v20 */
+export function updateToV20(): Rule {
return createMigrationSchematicRule(
- TargetVersion.V19,
+ TargetVersion.V20,
materialMigrations,
materialUpgradeData,
onMigrationComplete,
diff --git a/src/material/schematics/ng-update/migrations/explicit-system-variable-prefix.ts b/src/material/schematics/ng-update/migrations/explicit-system-variable-prefix.ts
deleted file mode 100644
index f49a8962bec1..000000000000
--- a/src/material/schematics/ng-update/migrations/explicit-system-variable-prefix.ts
+++ /dev/null
@@ -1,125 +0,0 @@
-/**
- * @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.dev/license
- */
-
-import {DevkitContext, Migration, ResolvedResource, UpgradeData} from '@angular/cdk/schematics';
-
-/**
- * Migration that adds `system-variables-prefix` to apps that have `use-system-variables` enabled.
- */
-export class ExplicitSystemVariablePrefixMigration extends Migration {
- override enabled = true;
-
- override visitStylesheet(stylesheet: ResolvedResource): void {
- if (!stylesheet.filePath.endsWith('.scss')) {
- return;
- }
-
- const content = this.fileSystem.read(stylesheet.filePath);
- if (!content || !content.includes('@angular/material')) {
- return;
- }
-
- const changes = this._getChanges(content);
-
- if (changes.length > 0) {
- const update = this.fileSystem.edit(stylesheet.filePath);
-
- for (let i = changes.length - 1; i > -1; i--) {
- update.insertRight(changes[i].start, changes[i].text);
- }
-
- this.fileSystem.commitEdits();
- }
- }
-
- /** Gets the changes that should be applied to a file. */
- private _getChanges(content: string) {
- const key = 'use-system-variables';
- const prefixKey = 'system-variables-prefix';
- const changes: {start: number; text: string}[] = [];
- let index = content.indexOf(key);
-
- // Note: this migration is a bit rudimentary, because Sass doesn't expose a proper AST.
- while (index > -1) {
- const colonIndex = content.indexOf(':', index);
- const valueEnd = colonIndex === -1 ? -1 : this._getValueEnd(content, colonIndex);
-
- if (valueEnd === -1) {
- index = content.indexOf(key, index + key.length);
- continue;
- }
-
- const value = content.slice(colonIndex + 1, valueEnd + 1).trim();
- if (value.startsWith('true') && !this._hasSystemPrefix(content, index, prefixKey)) {
- changes.push({
- start: this._getInsertIndex(content, valueEnd),
- text: `${value.endsWith(',') ? '' : ','}\n ${prefixKey}: sys,`,
- });
- }
-
- index = content.indexOf(key, valueEnd);
- }
-
- return changes;
- }
-
- /**
- * Gets the end index of a Sass map key.
- * @param content Content of the file.
- * @param startIndex Index at which to start the search.
- */
- private _getValueEnd(content: string, startIndex: number): number {
- for (let i = startIndex + 1; i < content.length; i++) {
- const char = content[i];
-
- if (char === ',' || char === '\n' || char === ')') {
- return i;
- }
- }
-
- return -1;
- }
-
- /**
- * Gets the index at which to insert the migrated content.
- * @param content Initial file content.
- * @param valueEnd Index at which the value of the system variables opt-in ends.
- */
- private _getInsertIndex(content: string, valueEnd: number): number {
- for (let i = valueEnd; i < content.length; i++) {
- if (content[i] === '\n') {
- return i;
- } else if (content[i] === ')') {
- return i;
- }
- }
-
- return valueEnd;
- }
-
- /**
- * Determines if a map that enables system variables is using system variables already.
- * @param content Full file contents.
- * @param keyIndex Index at which the systems variable key is defined.
- * @param prefixKey Name of the key that defines the prefix.
- */
- private _hasSystemPrefix(content: string, keyIndex: number, prefixKey: string): boolean {
- // Note: technically this can break if there are other inline maps, but it should be rare.
- const mapEnd = content.indexOf(')', keyIndex);
-
- if (mapEnd > -1) {
- for (let i = keyIndex; i > -1; i--) {
- if (content[i] === '(') {
- return content.slice(i, mapEnd).includes(prefixKey);
- }
- }
- }
-
- return false;
- }
-}
diff --git a/src/material/schematics/ng-update/migrations/mat-core-removal.ts b/src/material/schematics/ng-update/migrations/mat-core-removal.ts
deleted file mode 100644
index 64c0b84d2808..000000000000
--- a/src/material/schematics/ng-update/migrations/mat-core-removal.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * @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.dev/license
- */
-
-import * as postcss from 'postcss';
-import * as scss from 'postcss-scss';
-import {
- DevkitContext,
- Migration,
- ResolvedResource,
- UpgradeData,
- WorkspacePath,
-} from '@angular/cdk/schematics';
-
-const MATERIAL_IMPORT_PATH = '@angular/material';
-
-export class MatCoreMigration extends Migration {
- override enabled = true;
- private _namespace: string | undefined;
-
- override init() {
- // TODO: Check if mat-app-background is used in the application.
- }
-
- override visitStylesheet(stylesheet: ResolvedResource): void {
- // Avoid parsing the template Material isn't used.
- if (!stylesheet.content.includes(MATERIAL_IMPORT_PATH)) {
- return;
- }
-
- try {
- const processor = new postcss.Processor([
- {
- postcssPlugin: 'mat-core-removal-v19-plugin',
- AtRule: {
- use: node => this._getNamespace(node),
- include: node => this._handleAtInclude(node, stylesheet.filePath),
- },
- },
- ]);
- processor.process(stylesheet.content, {syntax: scss}).sync();
- } catch (e) {
- this.logger.warn(
- `Failed to migrate usages of mat.core in ${stylesheet.filePath} due to error:`,
- );
- this.logger.warn(e + '');
- }
- }
-
- /** Handles updating the at-include rules of uses of the core mixin. */
- private _handleAtInclude(node: postcss.AtRule, filePath: WorkspacePath): void {
- if (!this._namespace || !node.source?.start || !node.source.end) {
- return;
- }
-
- if (this._isMatCoreMixin(node)) {
- const end = node.source.end.offset;
- const start = node.source.start.offset;
-
- const prefix = '\n' + (node.raws.before?.split('\n').pop() || '');
- const snippet = prefix + node.source.input.css.slice(start, end);
-
- const elevation = prefix + `@include ${this._namespace}.elevation-classes();`;
- const background = prefix + `@include ${this._namespace}.app-background();`;
-
- this._replaceAt(filePath, node.source.start.offset - prefix.length, {
- old: snippet,
- new: elevation + background,
- });
- }
- }
-
- /** Returns true if the given at-rule is a use of the core mixin. */
- private _isMatCoreMixin(node: postcss.AtRule): boolean {
- if (node.params.startsWith(`${this._namespace}.core`)) {
- return true;
- }
- return false;
- }
-
- /** Sets the namespace if the given at-rule if it is importing from @angular/material. */
- private _getNamespace(node: postcss.AtRule): void {
- if (!this._namespace && node.params.startsWith(MATERIAL_IMPORT_PATH, 1)) {
- this._namespace = node.params.split(/\s+/)[2] || 'material';
- }
- }
-
- /** Updates the source file with the given replacements. */
- private _replaceAt(
- filePath: WorkspacePath,
- offset: number,
- str: {old: string; new: string},
- ): void {
- const index = this.fileSystem.read(filePath)!.indexOf(str.old, offset);
- this.fileSystem.edit(filePath).remove(index, str.old.length).insertRight(index, str.new);
- }
-}
diff --git a/src/material/schematics/ng-update/test-cases/v19-explicit-system-variable-prefix.spec.ts b/src/material/schematics/ng-update/test-cases/v19-explicit-system-variable-prefix.spec.ts
deleted file mode 100644
index 5a7a86afc73f..000000000000
--- a/src/material/schematics/ng-update/test-cases/v19-explicit-system-variable-prefix.spec.ts
+++ /dev/null
@@ -1,215 +0,0 @@
-import {UnitTestTree} from '@angular-devkit/schematics/testing';
-import {createTestCaseSetup} from '@angular/cdk/schematics/testing';
-import {MIGRATION_PATH} from '../../paths';
-
-const THEME_FILE_PATH = '/projects/cdk-testing/src/theme.scss';
-
-describe('v19 explicit system variable prefix migration', () => {
- let tree: UnitTestTree;
- let writeFile: (filename: string, content: string) => void;
- let runMigration: () => Promise;
-
- function stripWhitespace(content: string): string {
- return content.replace(/\s/g, '');
- }
-
- beforeEach(async () => {
- const testSetup = await createTestCaseSetup('migration-v19', MIGRATION_PATH, []);
- tree = testSetup.appTree;
- writeFile = testSetup.writeFile;
- runMigration = testSetup.runFixers;
- });
-
- it('should add an explicit system variables prefix', async () => {
- writeFile(
- THEME_FILE_PATH,
- `
- @use '@angular/material' as mat;
-
- $theme: mat.define-theme((
- color: (
- theme-type: 'light',
- primary: mat.$azure-palette,
- tertiary: mat.$red-palette,
- use-system-variables: true
- ),
- typography: (
- use-system-variables: true
- ),
- density: (
- scale: -1
- ),
- ));
-
- @include mat.all-component-themes($theme);
- `,
- );
-
- await runMigration();
-
- expect(stripWhitespace(tree.readText(THEME_FILE_PATH))).toBe(
- stripWhitespace(`
- @use '@angular/material' as mat;
-
- $theme: mat.define-theme((
- color: (
- theme-type: 'light',
- primary: mat.$azure-palette,
- tertiary: mat.$red-palette,
- use-system-variables: true,
- system-variables-prefix: sys,
- ),
- typography: (
- use-system-variables: true,
- system-variables-prefix: sys,
- ),
- density: (
- scale: -1
- ),
- ));
-
- @include mat.all-component-themes($theme);
- `),
- );
- });
-
- it('should add an explicit system variables prefix if the value is using trailing commas', async () => {
- writeFile(
- THEME_FILE_PATH,
- `
- @use '@angular/material' as mat;
-
- $theme: mat.define-theme((
- color: (
- theme-type: 'light',
- primary: mat.$azure-palette,
- tertiary: mat.$red-palette,
- use-system-variables: true,
- ),
- typography: (
- use-system-variables: true,
- ),
- density: (
- scale: -1
- ),
- ));
-
- @include mat.all-component-themes($theme);
- `,
- );
-
- await runMigration();
-
- expect(stripWhitespace(tree.readText(THEME_FILE_PATH))).toBe(
- stripWhitespace(`
- @use '@angular/material' as mat;
-
- $theme: mat.define-theme((
- color: (
- theme-type: 'light',
- primary: mat.$azure-palette,
- tertiary: mat.$red-palette,
- use-system-variables: true,
- system-variables-prefix: sys,
- ),
- typography: (
- use-system-variables: true,
- system-variables-prefix: sys,
- ),
- density: (
- scale: -1
- ),
- ));
-
- @include mat.all-component-themes($theme);
- `),
- );
- });
-
- it('should not add an explicit system variables prefix if the map has one already', async () => {
- writeFile(
- THEME_FILE_PATH,
- `
- @use '@angular/material' as mat;
-
- $theme: mat.define-theme((
- color: (
- theme-type: 'light',
- primary: mat.$azure-palette,
- tertiary: mat.$red-palette,
- use-system-variables: true
- ),
- typography: (
- use-system-variables: true,
- system-variables-prefix: foo
- ),
- density: (
- scale: -1
- ),
- ));
-
- @include mat.all-component-themes($theme);
- `,
- );
-
- await runMigration();
-
- expect(stripWhitespace(tree.readText(THEME_FILE_PATH))).toBe(
- stripWhitespace(`
- @use '@angular/material' as mat;
-
- $theme: mat.define-theme((
- color: (
- theme-type: 'light',
- primary: mat.$azure-palette,
- tertiary: mat.$red-palette,
- use-system-variables: true,
- system-variables-prefix: sys,
- ),
- typography: (
- use-system-variables: true,
- system-variables-prefix: foo
- ),
- density: (
- scale: -1
- ),
- ));
-
- @include mat.all-component-themes($theme);
- `),
- );
- });
-
- it('should handle a single-line map', async () => {
- writeFile(
- THEME_FILE_PATH,
- `
- @use '@angular/material' as mat;
-
- $theme: mat.define-theme((
- color: (theme-type: 'light', primary: mat.$azure-palette, use-system-variables: true),
- typography: (use-system-variables: true),
- density: (scale: -1),
- ));
-
- @include mat.all-component-themes($theme);
- `,
- );
-
- await runMigration();
-
- expect(stripWhitespace(tree.readText(THEME_FILE_PATH))).toBe(
- stripWhitespace(`
- @use '@angular/material' as mat;
-
- $theme: mat.define-theme((
- color: (theme-type: 'light', primary: mat.$azure-palette, use-system-variables: true, system-variables-prefix: sys,),
- typography: (use-system-variables: true, system-variables-prefix: sys,),
- density: (scale: -1),
- ));
-
- @include mat.all-component-themes($theme);
- `),
- );
- });
-});
diff --git a/src/material/schematics/ng-update/test-cases/v19-mat-core-removal.spec.ts b/src/material/schematics/ng-update/test-cases/v19-mat-core-removal.spec.ts
deleted file mode 100644
index 2a05fac5c73d..000000000000
--- a/src/material/schematics/ng-update/test-cases/v19-mat-core-removal.spec.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-import {UnitTestTree} from '@angular-devkit/schematics/testing';
-import {createTestCaseSetup} from '@angular/cdk/schematics/testing';
-import {join} from 'path';
-import {MIGRATION_PATH} from '../../paths';
-
-const PROJECT_ROOT_DIR = '/projects/cdk-testing';
-const THEME_FILE_PATH = join(PROJECT_ROOT_DIR, 'src/theme.scss');
-
-describe('v19 mat.core migration', () => {
- let tree: UnitTestTree;
-
- /** Writes multiple lines to a file. */
- let writeLines: (path: string, lines: string[]) => void;
-
- /** Reads multiple lines from a file. */
- let readLines: (path: string) => string[];
-
- /** Runs the v15 migration on the test application. */
- let runMigration: () => Promise<{logOutput: string}>;
-
- beforeEach(async () => {
- const testSetup = await createTestCaseSetup('migration-v19', MIGRATION_PATH, []);
- tree = testSetup.appTree;
- runMigration = testSetup.runFixers;
- readLines = (path: string) => tree.readContent(path).split('\n');
- writeLines = (path: string, lines: string[]) => testSetup.writeFile(path, lines.join('\n'));
- });
-
- describe('style migrations', () => {
- async function runSassMigrationTest(ctx: string, opts: {old: string[]; new: string[]}) {
- writeLines(THEME_FILE_PATH, opts.old);
- await runMigration();
- expect(readLines(THEME_FILE_PATH)).withContext(ctx).toEqual(opts.new);
- }
-
- it('should remove uses of the core mixin', async () => {
- await runSassMigrationTest('', {
- old: [`@use '@angular/material' as mat;`, `@include mat.core();`],
- new: [
- `@use '@angular/material' as mat;`,
- `@include mat.elevation-classes();`,
- `@include mat.app-background();`,
- ],
- });
-
- await runSassMigrationTest('w/ unique namespace', {
- old: [`@use '@angular/material' as material;`, `@include material.core();`],
- new: [
- `@use '@angular/material' as material;`,
- `@include material.elevation-classes();`,
- `@include material.app-background();`,
- ],
- });
-
- await runSassMigrationTest('w/ no namespace', {
- old: [`@use '@angular/material';`, `@include material.core();`],
- new: [
- `@use '@angular/material';`,
- `@include material.elevation-classes();`,
- `@include material.app-background();`,
- ],
- });
-
- await runSassMigrationTest('w/ unique whitespace', {
- old: [
- ` @use '@angular/material' as material ; `,
- ` @include material.core( ) ; `,
- ],
- new: [
- ` @use '@angular/material' as material ; `,
- ` @include material.elevation-classes();`,
- ` @include material.app-background(); `,
- ],
- });
- });
-
- it('should not break if there is an invalid syntax', async () => {
- await runSassMigrationTest('', {
- old: [`@use '@angular/material' as mat;`, `.foo { content: '; }`],
- new: [`@use '@angular/material' as mat;`, `.foo { content: '; }`],
- });
- });
- });
-});
From 54def5aa4ec05bd363f869c3730fc1ab9b6a4c8b Mon Sep 17 00:00:00 2001
From: Amy Sorto <8575252+amysorto@users.noreply.github.com>
Date: Fri, 13 Dec 2024 17:21:40 +0000
Subject: [PATCH 3/3] feat(material/schematics): Add Material Symbols icon font
schematic
---
src/material/schematics/ng-update/index.ts | 61 +++++++++++--
.../v20-mat-symbols-icon-font.spec.ts | 87 +++++++++++++++++++
2 files changed, 141 insertions(+), 7 deletions(-)
create mode 100644 src/material/schematics/ng-update/test-cases/v20-mat-symbols-icon-font.spec.ts
diff --git a/src/material/schematics/ng-update/index.ts b/src/material/schematics/ng-update/index.ts
index 52ab85b84b7e..468a25c536f7 100644
--- a/src/material/schematics/ng-update/index.ts
+++ b/src/material/schematics/ng-update/index.ts
@@ -6,12 +6,17 @@
* found in the LICENSE file at https://angular.dev/license
*/
-import {Rule, SchematicContext} from '@angular-devkit/schematics';
+import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {
+ appendHtmlElementToHead,
createMigrationSchematicRule,
+ getProjectFromWorkspace,
+ getProjectIndexFiles,
+ getWorkspaceConfigGracefully,
NullableDevkitMigration,
TargetVersion,
} from '@angular/cdk/schematics';
+import {getWorkspace} from '@schematics/angular/utility/workspace';
import {materialUpgradeData} from './upgrade-data';
@@ -19,12 +24,54 @@ const materialMigrations: NullableDevkitMigration[] = [];
/** Entry point for the migration schematics with target of Angular Material v20 */
export function updateToV20(): Rule {
- return createMigrationSchematicRule(
- TargetVersion.V20,
- materialMigrations,
- materialUpgradeData,
- onMigrationComplete,
- );
+ return chain([
+ createMigrationSchematicRule(
+ TargetVersion.V20,
+ materialMigrations,
+ materialUpgradeData,
+ onMigrationComplete,
+ ),
+ // Updating to the new Material Symbols isn't a migration within materialMigrations since
+ // the index files are never visited within the migration schematic rule. The
+ // migrate() function within the update-tool only visits files referenced in
+ // typescript files which excludes the index template files:
+ // https://github.com/angular/components/blob/main/src/cdk/schematics/update-tool/index.ts#L71.
+ updateIconFontToMaterialSymbolsRule(),
+ ]);
+}
+
+/**
+ * Finds the index files and adds the import for Material Symbols font if needed. As of v20,
+ * Material Symbols becomes the default font icon since Material Icons is deprecated. This
+ * rule ensures the Material Symbols font is imported for existing applications.
+ * @returns Rule that adds the import for the Material Symbols icon font to the index files
+ */
+function updateIconFontToMaterialSymbolsRule(): Rule {
+ return async (tree: Tree, context: SchematicContext) => {
+ const workspace = await getWorkspaceConfigGracefully(tree);
+ const projectNames = workspace!.projects.keys();
+
+ let indexFiles: string[] = [];
+ for (const projectName of projectNames) {
+ const project = getProjectFromWorkspace(await getWorkspace(tree), projectName);
+ indexFiles = [...indexFiles, ...getProjectIndexFiles(project)];
+ }
+
+ const materialSymbolsFont =
+ 'https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined';
+ for (const indexFile of indexFiles) {
+ // Add Material Symbols font if not imported in index file. References to the deprecated
+ // Material Icons are not removed since some applications may have manual overrides in their
+ // component styles that still reference it.
+ if (!tree.read(indexFile)?.includes(materialSymbolsFont)) {
+ appendHtmlElementToHead(
+ tree,
+ indexFile,
+ ``,
+ );
+ }
+ }
+ };
}
/** Function that will be called when the migration completed. */
diff --git a/src/material/schematics/ng-update/test-cases/v20-mat-symbols-icon-font.spec.ts b/src/material/schematics/ng-update/test-cases/v20-mat-symbols-icon-font.spec.ts
new file mode 100644
index 000000000000..4ce196537d38
--- /dev/null
+++ b/src/material/schematics/ng-update/test-cases/v20-mat-symbols-icon-font.spec.ts
@@ -0,0 +1,87 @@
+import {UnitTestTree} from '@angular-devkit/schematics/testing';
+import {createTestCaseSetup} from '@angular/cdk/schematics/testing';
+import {MIGRATION_PATH} from '../../paths';
+
+const INDEX_HTML_FILE_PATH = '/projects/cdk-testing/src/index.html';
+
+describe('v20 material symbols icon font migration', () => {
+ let tree: UnitTestTree;
+ let writeFile: (filename: string, content: string) => void;
+ let runMigration: () => Promise;
+
+ function stripWhitespace(content: string): string {
+ return content.replace(/\s/g, '');
+ }
+
+ beforeEach(async () => {
+ const testSetup = await createTestCaseSetup('migration-v20', MIGRATION_PATH, []);
+ tree = testSetup.appTree;
+ writeFile = testSetup.writeFile;
+ runMigration = testSetup.runFixers;
+ });
+
+ it('should add Material Symbols font to index html file', async () => {
+ writeFile(
+ INDEX_HTML_FILE_PATH,
+ `
+
+
+
+
+
+
+
+
+ `,
+ );
+
+ await runMigration();
+
+ expect(stripWhitespace(tree.readText(INDEX_HTML_FILE_PATH))).toBe(
+ stripWhitespace(`
+
+
+
+
+
+
+
+
+
+ `),
+ );
+ });
+
+ it('should not add Material Symbols font to index html file if it is already imported', async () => {
+ writeFile(
+ INDEX_HTML_FILE_PATH,
+ `
+
+
+
+
+
+
+
+
+
+ `,
+ );
+
+ await runMigration();
+
+ expect(stripWhitespace(tree.readText(INDEX_HTML_FILE_PATH))).toBe(
+ stripWhitespace(`
+
+
+
+
+
+
+
+
+
+ `),
+ );
+ });
+});