From b034b11f0271377b6ce0dd28b26c4356a26f39fe Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 9 Dec 2025 09:16:04 +0100 Subject: [PATCH] fix(material/schematics): combine style resets Prior to #31522 we had two places with style resets, because the user could either use a custom theme or one of the pre-built ones. After the change all themes are "custom" so we don't need the extra branch in the logic. These changes combine the style resets into the theme and remove the wording around "custom" from the code. Fixes #32495. --- src/material/schematics/ng-add/index.spec.ts | 33 ++++-------- .../schematics/ng-add/setup-project.ts | 53 +------------------ ...create-custom-theme.ts => create-theme.ts} | 8 +-- .../schematics/ng-add/theming/theming.ts | 30 +++++------ 4 files changed, 31 insertions(+), 93 deletions(-) rename src/material/schematics/ng-add/theming/{create-custom-theme.ts => create-theme.ts} (88%) diff --git a/src/material/schematics/ng-add/index.spec.ts b/src/material/schematics/ng-add/index.spec.ts index 5af909f5ac03..58977ad01a32 100644 --- a/src/material/schematics/ng-add/index.spec.ts +++ b/src/material/schematics/ng-add/index.spec.ts @@ -4,7 +4,6 @@ import {SchematicTestRunner} from '@angular-devkit/schematics/testing'; import { getProjectFromWorkspace, getProjectIndexFiles, - getProjectStyleFile, getProjectTargetOptions, } from '@angular/cdk/schematics'; import {createTestApp, createTestLibrary, getFileContent} from '../../../cdk/schematics/testing'; @@ -87,7 +86,7 @@ describe('ng-add schematic', () => { const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); it('should support adding a custom theme', async () => { @@ -121,12 +120,12 @@ describe('ng-add schematic', () => { ); const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - const expectedStylesPath = normalize(`/${project.root}/src/custom-theme.scss`); + const expectedStylesPath = normalize(`/${project.root}/src/material-theme.scss`); expect(tree.files) .withContext('Expected a custom theme file to be created') .toContain(expectedStylesPath); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); it('should add font links', async () => { @@ -160,20 +159,6 @@ describe('ng-add schematic', () => { }); }); - it('should add material app styles', async () => { - const tree = await runner.runSchematic('ng-add-setup-project', baseOptions, appTree); - const workspace = await readWorkspace(tree); - const project = getProjectFromWorkspace(workspace, baseOptions.project); - - const defaultStylesPath = getProjectStyleFile(project)!; - const htmlContent = tree.read(defaultStylesPath)!.toString(); - - expect(htmlContent).toContain('html, body { height: 100%; }'); - expect(htmlContent).toContain( - 'body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }', - ); - }); - describe('custom project builders', () => { /** Overwrites a target builder for the workspace in the given tree */ function overwriteTargetBuilder(tree: Tree, targetName: 'build' | 'test', newBuilder: string) { @@ -223,15 +208,15 @@ describe('ng-add schematic', () => { describe('theme files', () => { it('should not overwrite existing custom theme files', async () => { - appTree.create('/projects/material/custom-theme.scss', 'custom-theme'); + appTree.create('/projects/material/material-theme.scss', 'material-theme'); const tree = await runner.runSchematic( 'ng-add-setup-project', {...baseOptions, theme: 'azure-blue'}, appTree, ); - expect(tree.readContent('/projects/material/custom-theme.scss')) + expect(tree.readContent('/projects/material/material-theme.scss')) .withContext('Expected the old custom theme content to be unchanged.') - .toBe('custom-theme'); + .toBe('material-theme'); }); }); @@ -277,7 +262,7 @@ describe('ng-add schematic', () => { const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); }); @@ -323,7 +308,7 @@ describe('ng-add schematic', () => { const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); }); @@ -360,7 +345,7 @@ describe('ng-add schematic', () => { const workspace = await readWorkspace(tree); const project = getProjectFromWorkspace(workspace, baseOptions.project); - expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss'); + expectProjectStyleFile(project, 'projects/material/src/material-theme.scss'); }); }); }); diff --git a/src/material/schematics/ng-add/setup-project.ts b/src/material/schematics/ng-add/setup-project.ts index f0897ade7206..652679b52a4e 100644 --- a/src/material/schematics/ng-add/setup-project.ts +++ b/src/material/schematics/ng-add/setup-project.ts @@ -7,7 +7,7 @@ */ import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics'; -import {getProjectFromWorkspace, getProjectStyleFile} from '@angular/cdk/schematics'; +import {getProjectFromWorkspace} from '@angular/cdk/schematics'; import {readWorkspace} from '@schematics/angular/utility'; import {ProjectType} from '@schematics/angular/utility/workspace-models'; import {addFontsToIndex} from './fonts/material-fonts'; @@ -25,11 +25,7 @@ export default function (options: Schema): Rule { const project = getProjectFromWorkspace(workspace, options.project); if (project.extensions['projectType'] === ProjectType.Application) { - return chain([ - addThemeToAppStyles(options), - addFontsToIndex(options), - addMaterialAppStyles(options), - ]); + return chain([addThemeToAppStyles(options), addFontsToIndex(options)]); } context.logger.warn( 'Angular Material has been set up in your workspace. There is no additional setup ' + @@ -40,48 +36,3 @@ export default function (options: Schema): Rule { return; }; } - -/** - * Adds custom Material styles to the project style file. The custom CSS sets up the Roboto font - * and reset the default browser body margin. - */ -function addMaterialAppStyles(options: Schema) { - return async (host: Tree, context: SchematicContext) => { - const workspace = await readWorkspace(host); - const project = getProjectFromWorkspace(workspace, options.project); - const styleFilePath = getProjectStyleFile(project); - const logger = context.logger; - - if (!styleFilePath) { - logger.error(`Could not find the default style file for this project.`); - logger.info(`Consider manually adding the Roboto font to your CSS.`); - logger.info(`More information at https://fonts.google.com/specimen/Roboto`); - return; - } - - const buffer = host.read(styleFilePath); - - if (!buffer) { - logger.error( - `Could not read the default style file within the project ` + `(${styleFilePath})`, - ); - logger.info(`Please consider manually setting up the Roboto font.`); - return; - } - - const htmlContent = buffer.toString(); - const insertion = - '\n' + - `html, body { height: 100%; }\n` + - `body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }\n`; - - if (htmlContent.includes(insertion)) { - return; - } - - const recorder = host.beginUpdate(styleFilePath); - - recorder.insertLeft(htmlContent.length, insertion); - host.commitUpdate(recorder); - }; -} diff --git a/src/material/schematics/ng-add/theming/create-custom-theme.ts b/src/material/schematics/ng-add/theming/create-theme.ts similarity index 88% rename from src/material/schematics/ng-add/theming/create-custom-theme.ts rename to src/material/schematics/ng-add/theming/create-theme.ts index 9a648ead5f45..fb25eb8eb010 100644 --- a/src/material/schematics/ng-add/theming/create-custom-theme.ts +++ b/src/material/schematics/ng-add/theming/create-theme.ts @@ -6,9 +6,9 @@ * found in the LICENSE file at https://angular.dev/license */ -/** Create custom theme for the given application configuration. */ -export function createCustomTheme(userPaletteChoice: string): string { - const colorPalettes = new Map([ +/** Create theme for the given application configuration. */ +export function createTheme(userPaletteChoice: string): string { + const colorPalettes = new Map([ ['azure-blue', {primary: 'azure', tertiary: 'blue'}], ['rose-red', {primary: 'rose', tertiary: 'red'}], ['magenta-violet', {primary: 'magenta', tertiary: 'violet'}], @@ -23,6 +23,7 @@ export function createCustomTheme(userPaletteChoice: string): string { @use '@angular/material' as mat; html { + height: 100%; @include mat.theme(( color: ( primary: mat.$${colorPalettes.get(userPaletteChoice)!.primary}-palette, @@ -48,6 +49,7 @@ body { // Reset the user agent margin. margin: 0; + height: 100%; } `; } diff --git a/src/material/schematics/ng-add/theming/theming.ts b/src/material/schematics/ng-add/theming/theming.ts index 7486d1b61114..f8ebae0096f3 100644 --- a/src/material/schematics/ng-add/theming/theming.ts +++ b/src/material/schematics/ng-add/theming/theming.ts @@ -19,13 +19,13 @@ import {InsertChange} from '@schematics/angular/utility/change'; import {ProjectDefinition, readWorkspace, updateWorkspace} from '@schematics/angular/utility'; import {join} from 'path'; import {Schema} from '../schema'; -import {createCustomTheme} from './create-custom-theme'; +import {createTheme} from './create-theme'; /** Path segment that can be found in paths that refer to a prebuilt theme. */ const prebuiltThemePathSegment = '@angular/material/prebuilt-themes'; /** Default file name of the custom theme that can be generated. */ -const defaultCustomThemeFilename = 'custom-theme.scss'; +const defaultThemeFilename = 'material-theme.scss'; /** Add pre-built styles to the main project style file. */ export function addThemeToAppStyles(options: Schema): Rule { @@ -40,15 +40,15 @@ export function addThemeToAppStyles(options: Schema): Rule { palettes = 'azure-blue'; } - return insertCustomTheme(palettes, options.project, host, context.logger); + return insertTheme(palettes, options.project, host, context.logger); }; } /** - * Insert an Angular Material theme to project style file. If no valid style file could be found, a new - * Scss file for the custom theme will be created. + * Insert an Angular Material theme to project style file. If no valid style file could be found, + * a new Sass file for the theme will be created. */ -async function insertCustomTheme( +async function insertTheme( palettes: string, projectName: string, host: Tree, @@ -57,7 +57,7 @@ async function insertCustomTheme( const workspace = await readWorkspace(host); const project = getProjectFromWorkspace(workspace, projectName); const stylesPath = getProjectStyleFile(project, 'scss'); - const themeContent = createCustomTheme(palettes); + const themeContent = createTheme(palettes); if (!stylesPath) { if (!project.sourceRoot) { @@ -69,16 +69,16 @@ async function insertCustomTheme( // Normalize the path through the devkit utilities because we want to avoid having // unnecessary path segments and windows backslash delimiters. - const customThemePath = normalize(join(project.sourceRoot, defaultCustomThemeFilename)); + const themePath = normalize(join(project.sourceRoot, defaultThemeFilename)); - if (host.exists(customThemePath)) { - logger.warn(`Cannot create a custom Angular Material theme because - ${customThemePath} already exists. Skipping theme generation.`); + if (host.exists(themePath)) { + logger.warn(`Cannot create an Angular Material theme because + ${themePath} already exists. Skipping theme generation.`); return noop(); } - host.create(customThemePath, themeContent); - return addThemeStyleToTarget(projectName, 'build', customThemePath, logger); + host.create(themePath, themeContent); + return addThemeStyleToTarget(projectName, 'build', themePath, logger); } const insertion = new InsertChange(stylesPath, 0, themeContent); @@ -122,10 +122,10 @@ function addThemeStyleToTarget( // theme file. If a custom theme is set up, we are not able to safely replace the custom // theme because these files can contain custom styles, while prebuilt themes are // always packaged and considered replaceable. - if (stylePath.includes(defaultCustomThemeFilename)) { + if (stylePath.includes(defaultThemeFilename)) { logger.error( `Could not add the selected theme to the CLI project ` + - `configuration because there is already a custom theme file referenced.`, + `configuration because there is already a theme file referenced.`, ); logger.info(`Please manually add the following style file to your configuration:`); logger.info(` ${assetPath}`);