Skip to content

Commit

Permalink
feat(material/schematics): Add custom M3 theme schematic (#28766)
Browse files Browse the repository at this point in the history
* feat(material/schematics): Add custom M3 theme schematic

* fix(material/schematics): Add generated file comment and color source comment to output theme file

* fix(material/schematics): Create README and update docs theme example

* fix(material/schematics): Move more of the m3-schematic docs into the README and link to it from the m3 and schematics guide
  • Loading branch information
amysorto committed Apr 17, 2024
1 parent 0fbc899 commit 295fd67
Show file tree
Hide file tree
Showing 14 changed files with 1,020 additions and 7 deletions.
28 changes: 23 additions & 5 deletions guides/material-3.md
Expand Up @@ -78,6 +78,29 @@ used with the `primary` and `tertiary` options:
- `$m3-violet-palette`
- `$m3-rose-palette`

Alternatively, a theme can be generated with a custom color with the following schematic:

```shell
ng generate @angular/material:m3-theme
```

This schematic integrates with [Material Color Utilities](https://github.com/material-foundation/material-color-utilities) to build a theme based on a generated set of palettes based on a single color. Optionally you can provide additional custom colors for the secondary, tertiary, and neutral palettes.

The output of the schematic is a new Sass file that exports a theme or themes (if generating both a light and dark theme) that can be provided to component theme mixins.

```scss
@use '@angular/material' as mat;
@use './path/to/m3-theme';

@include mat.core();

// Apply the light theme by default
@include mat.core-theme(m3-theme.$light-theme);
@include mat.button-theme(m3-theme.$light-theme);
```

Learn more about this schematic in its [documentation](https://github.com/angular/components/blob/main/src/material/schematics/ng-generate/m3-theme/README.md).

<!-- TODO(mmalerba): Illustrate palettes with example. -->

#### Customizing your typography
Expand Down Expand Up @@ -427,11 +450,6 @@ $theme: matx.define-theme();

## FAQ

### Can I use colors other than the pre-defined Material 3 palettes?

Currently, we only offer predefined palettes, but we plan to add support for using custom generated
palettes as part of making the M3 APIs stable and available in `@angular/material`.

### Can I depend on the CSS custom property names being stable?

We may make changes to the custom property names before moving the API out of experimental, but
Expand Down
11 changes: 11 additions & 0 deletions guides/schematics.md
Expand Up @@ -115,3 +115,14 @@ that uses the CDK drag and drop directives.
```
ng generate @angular/cdk:drag-drop <component-name>
```

### Material 3 Theme schematic

The `m3-theme` schematic will generate a file with Material 3 themes created
from custom colors.

```
ng generate @angular/material:m3-theme
```

Learn more about this schematic in its [documentation](https://github.com/angular/components/blob/main/src/material/schematics/ng-generate/m3-theme/README.md).
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -122,6 +122,7 @@
"@material/line-ripple": "15.0.0-canary.7f224ddd4.0",
"@material/linear-progress": "15.0.0-canary.7f224ddd4.0",
"@material/list": "15.0.0-canary.7f224ddd4.0",
"@material/material-color-utilities": "^0.2.7",
"@material/menu": "15.0.0-canary.7f224ddd4.0",
"@material/menu-surface": "15.0.0-canary.7f224ddd4.0",
"@material/notched-outline": "15.0.0-canary.7f224ddd4.0",
Expand Down
3 changes: 3 additions & 0 deletions src/material/schematics/BUILD.bazel
Expand Up @@ -75,6 +75,9 @@ ts_library(
pkg_npm(
name = "npm_package",
srcs = ["package.json"],
nested_packages = [
"//src/material/schematics/ng-generate/m3-theme:npm_package",
],
deps = [
":collection_assets",
":ng_generate_assets",
Expand Down
6 changes: 6 additions & 0 deletions src/material/schematics/collection.json
Expand Up @@ -44,6 +44,12 @@
"factory": "./ng-generate/address-form/index",
"schema": "./ng-generate/address-form/schema.json",
"aliases": ["address-form", "material-address-form", "material-addressForm"]
},
"m3Theme": {
"description": "Generate M3 theme",
"factory": "./ng-generate/m3-theme/index_bundled",
"schema": "./ng-generate/m3-theme/schema.json",
"aliases": ["m3-theme", "M3-theme"]
}
}
}
108 changes: 108 additions & 0 deletions src/material/schematics/ng-generate/m3-theme/BUILD.bazel
@@ -0,0 +1,108 @@
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
load("//tools:defaults.bzl", "esbuild", "jasmine_node_test", "pkg_npm", "spec_bundle", "ts_library")

package(default_visibility = ["//visibility:public"])

STATIC_ASSETS = [
"schema.json",
]

ts_library(
name = "m3_theme_lib",
srcs = glob(
["**/*.ts"],
exclude = ["**/*.spec.ts"] + ["rules/components/test-setup-helper.ts"],
),
deps = [
"//src/cdk/schematics",
"@npm//@angular-devkit/schematics",
"@npm//@material/material-color-utilities",
"@npm//@types/node",
"@npm//sass",
"@npm//typescript",
],
)

esbuild(
name = "m3_theme_bundle",
entry_point = ":index.ts",
external = [
"@angular/cdk/schematics",
"@angular/material-experimental/",
"@angular-devkit/schematics",
"@angular-devkit/core",
"typescript",
],
format = "cjs",
output = "index_bundled.js",
platform = "node",
target = "es2015",
deps = [
":m3_theme_lib",
"//src/material:sass_lib",
"//src/material-experimental:sass_lib",
],
)

pkg_npm(
name = "npm_package",
srcs = STATIC_ASSETS,
deps = [":m3_theme_bundle"],
)

########################################
# Testing configuration #
########################################

ts_library(
name = "unit_tests_lib",
testonly = True,
srcs = glob(["**/*.spec.ts"] + ["rules/components/test-setup-helper.ts"]),
devmode_module = "commonjs",
deps = [
":m3_theme_lib",
"//src/cdk/schematics/testing",
"//tools/sass:sass_lib",
"@npm//@angular-devkit/schematics",
"@npm//@bazel/runfiles",
"@npm//@material/material-color-utilities",
"@npm//@types/jasmine",
"@npm//@types/node",
"@npm//sass",
],
)

spec_bundle(
name = "unit_tests_bundle",
# Exclude the `node` devkit entry-point to avoid bundling native modules like
# `chokidar` and `fsevents`. These rely on native bindings and break with ESBuild.
external = ["@angular-devkit/core/node"],
platform = "node",
target = "es2020",
deps = [":unit_tests_lib"],
)

copy_to_bin(
name = "unit_tests_assets",
testonly = True,
srcs = STATIC_ASSETS,
)

jasmine_node_test(
name = "unit_tests",
data = [
":m3_theme_bundle",
":unit_tests_assets",
"//src/material/schematics:collection_assets",
"//src/material/schematics:ng_generate_assets",
],
shard_count = 10,
deps = [
":unit_tests_bundle",
# Runtime dependencies needed by the test and actual migration sources. These need
# to be specified explicitly here because they are not captured by the bundling.
"@npm//@schematics/angular",
"//src/material:sass_lib",
"//src/material-experimental:sass_lib",
],
)
52 changes: 52 additions & 0 deletions src/material/schematics/ng-generate/m3-theme/README.md
@@ -0,0 +1,52 @@
# Material 3 Custom Theme schematic

```shell
ng generate @angular/material:m3-theme
```

This schematic allows users to create new Material 3 theme configurations based
on custom colors by using [Material Color Utilities](https://github.com/material-foundation/material-color-utilities).

The generated [color palettes](https://m3.material.io/styles/color/roles) are
optimized to have enough contrast to be more accessible. See [Science of Color Design](https://material.io/blog/science-of-color-design) for more information about Material's color design.

For more customization, custom palette colors can be also be provided for the
secondary, tertiary, and neutral colors. It is recommended to choose colors that
are contrastful, Material has more detailed guidance for [accessible design](https://m3.material.io/foundations/accessible-design/patterns).

The output of the schematic will create a file named `m3-theme.scss` at the
specified directory or the project root with the generated themes. The exported
themes (`$light-theme` and/or `$dark-theme`) can be provided to component theme
mixins.

```scss
@use '@angular/material' as mat;
@use './path/to/my-theme';

@include mat.core();

// Apply the light theme by default
@include mat.core-theme(my-theme.$light-theme);
@include mat.button-theme(my-theme.$light-theme);
```

## Options

### Required

* `primaryColor` - Color to use for app's primary color palette (Note: the other
palettes described in the Material 3 spec will be automatically chosen based on
your primary palette unless specified, to ensure a harmonious color combination).

### Optional

* `secondaryColor` - Color to use for app's secondary color palette. Defaults to
secondary color generated from Material based on the primary.
* `tertiaryColor` - Color to use for app's tertiary color palette. Defaults to
tertiary color generated from Material based on the primary.
* `neutralColor` - Color to use for app's neutral color palette. Defaults to
neutral color generated from Material based on the primary.
* `directory` - Relative path to a directory within the project that the
generated theme file should be created in. Defaults to the project root.
* `themeTypes` - List of theme types (light and dark) to generate themes for.
Defaults to both light and dark.

0 comments on commit 295fd67

Please sign in to comment.