` which has
been pre-configured with a datasource for sorting and pagination.
-```
+```bash
ng generate @angular/material:table
```
@@ -93,7 +93,7 @@ ng generate @angular/material:table
The `dashboard` schematic will create a new component that contains
a dynamic grid list of Material Design cards.
-```
+```bash
ng generate @angular/material:dashboard
```
@@ -102,7 +102,7 @@ ng generate @angular/material:dashboard
The `tree` schematic can be used to quickly generate an Angular component that uses the Angular
Material `` component to visualize a nested folder structure.
-```
+```bash
ng generate @angular/material:tree
```
@@ -111,7 +111,7 @@ ng generate @angular/material:tree
The `drag-drop` schematic is provided by the `@angular/cdk` and can be used to generate a component
that uses the CDK drag and drop directives.
-```
+```bash
ng generate @angular/cdk:drag-drop
```
@@ -121,7 +121,7 @@ The `theme-color` schematic will generate a file with Material 3 palettes from t
that can be used in a theme file. It also generates high contrast color override mixins if
specified.
-```
+```bash
ng generate @angular/material:theme-color
```
diff --git a/guides/theming.md b/guides/theming.md
index 22b154549d8d..6b70dca2deda 100644
--- a/guides/theming.md
+++ b/guides/theming.md
@@ -5,12 +5,12 @@ defining a custom theme. Angular Material’s theming system is inspired by
Google’s [Material Design](https://m3.material.io/styles).
This guide describes how to set up theming for your application using
-Sass APIs introduced in Angular Material v19.
+Sass APIs introduced in Angular Material v19.
If your application depends on a version before v19, or if your application's
-theme is applied using a theme config created with `mat.define-theme`,
+theme is applied using a theme config created with `mat.define-theme`,
`mat.define-light-theme`, or `mat.define-dark-theme`,
-then you can refer to the theming guides at
+then you can refer to the theming guides at
[v18.material.angular.dev/guides](https://v18.material.angular.dev/guides).
## Getting Started
@@ -35,7 +35,7 @@ entire application. The `color-scheme` is explicitly set to `light dark` so that
the end user's system preferences are used to determine whether the application
appears in light or dark mode.
-```
+```scss
@use '@angular/material' as mat;
html {
@@ -51,7 +51,7 @@ html {
You can use the following styles to apply the theme’s surface background and
on-surface text colors as a default across your application:
-```
+```scss
body {
background: var(--mat-sys-surface);
color: var(--mat-sys-on-surface);
@@ -62,7 +62,7 @@ The `mat.theme` mixin will only declare CSS variables for the categories
included in the input. For example, if `typography` is not defined, then
typography CSS variables will not be included in the output.
-### **Color**
+### Color
The `theme`‘s color determines the component color styles, such as the fill
color of checkboxes or ripple color of buttons. It depends on color palettes of
@@ -74,14 +74,14 @@ palettes.
You can set the color in one of two ways: as a single color palette, or as a
color map.
-#### *Single Color Palette*
+#### Single Color Palette
If you provide a single color palette, Angular Material uses its values for the
theme’s primary, secondary, and tertiary colors. The CSS color values will be
defined using `light-dark` CSS color function. Your application styles should
define an explicit value declaration for the `color-scheme` CSS property.
-#### *Color Map*
+#### Color Map
If you provide a color map, then the tertiary color palette can be configured
separately from the primary palette. The tertiary palette can be used to add a
@@ -105,7 +105,7 @@ tertiary color. The theme-type is set to `light` which means that only the light
color values will be set for the application. The typography is set to Roboto
with a standard density setting.
-```
+```scss
@use '@angular/material' as mat;
html {
@@ -121,7 +121,7 @@ html {
}
```
-### **Typography**
+### Typography
The `mat.theme` ‘s typography determines the text styles used in components,
such as the font for dialog titles or menu list items.
@@ -129,13 +129,13 @@ such as the font for dialog titles or menu list items.
You can set the typography in one of two ways: as a single font family value, or
as a typography map.
-#### *Single Font Family Value*
+#### Single Font Family Value
If you provide a font family, Angular Material uses it for all the text in its
components. The font weights used in components are set to 700 for bold text,
500 for medium text, and 400 for regular text.
-#### *Typography Map*
+#### Typography Map
If you provide a typography map, then distinct font families are set for plain
and brand text. The plain font family is typically used for most of the
@@ -150,7 +150,7 @@ and the Open Sans font family to brand text. It specifies that bold weight is
900, medium weight is 500, and regular weight is 300\. The color scheme uses the
violet color palette with a standard density.
-```
+```scss
@use '@angular/material' as mat;
html {
@@ -168,7 +168,7 @@ html {
}
```
-### **Density**
+### Density
The `mat.theme` ‘s density value determines the spacing within components, such
as how much padding is used around a button’s text or the height of form fields.
@@ -182,7 +182,7 @@ The following example theme file has a density setting of \-2 which causes most
components to include less whitespace in their layout. The color scheme uses the
violet color palette and applies Roboto as the font-family.
-```
+```scss
@use '@angular/material' as mat;
html {
@@ -202,31 +202,31 @@ pop-up contexts, such as the date picker. The Material Design density guidance
explicitly discourages changes to density for such interactions because they
don't compete for space in the application's layout.
-## **Color Palettes**
+## Color Palettes
A color palette is a set of similar colors with different hues ranging from
light to dark. The Angular Material theme uses color palettes to create a color
scheme to communicate an application’s hierarchy, state, and brand.
-### **Prebuilt Color Palettes**
+### Prebuilt Color Palettes
Angular Material provides twelve prebuilt color palettes that can be used for
your application’s theme:
-* `$red-palette`
-* `$green-palette`
-* `$blue-palette`
-* `$yellow-palette`
-* `$cyan-palette`
-* `$magenta-palette`
-* `$orange-palette`
-* `$chartreuse-palette`
-* `$spring-green-palette`
-* `$azure-palette`
-* `$violet-palette`
-* `$rose-palette`
-
-### **Custom Color Palettes**
+* `$red-palette`
+* `$green-palette`
+* `$blue-palette`
+* `$yellow-palette`
+* `$cyan-palette`
+* `$magenta-palette`
+* `$orange-palette`
+* `$chartreuse-palette`
+* `$spring-green-palette`
+* `$azure-palette`
+* `$violet-palette`
+* `$rose-palette`
+
+### Custom Color Palettes
The Angular Material
[palette generation schematic](https://github.com/angular/components/blob/main/src/material/schematics/ng-generate/theme-color/README.md)
@@ -234,17 +234,17 @@ builds custom color palettes based on a single color input for the primary
color, and optionally color inputs to further customize secondary, tertiary, and
neutral palettes:
-```
+```bash
ng generate @angular/material:theme-color
```
-## **Loading Fonts**
+## Loading Fonts
You can use Google Fonts as one option to load fonts in your application. For
example, the following code in an application’s `` loads the font family
Roboto with the font weights 700, 500, and 400:
-```
+```html
@@ -256,7 +256,7 @@ default, projects created with the Angular CLI are
[configured](https://angular.dev/reference/configs/workspace-config#fonts-optimization-options)
to inline assets from Google Fonts to reduce render-blocking requests.
-## **Supporting Light and Dark Mode**
+## Supporting Light and Dark Mode
By default, the `mat.theme` mixin defines colors using the CSS color function
`light-dark` to make it easy for your application to switch between light and
@@ -268,7 +268,7 @@ You can define `color-scheme: light` or `color-scheme: dark` to explicitly
define your application’s mode. To set the mode depending on the user’s system
preferences, use `color-scheme: light-dark` as shown in the following example:
-```
+```scss
@use '@angular/material' as mat;
html {
@@ -286,7 +286,7 @@ that the mode depends on whether that class has been applied. In the following
example, the application always displays the light mode theme unless the class
“dark-mode” is added to the HTML body.
-```
+```scss
@use '@angular/material' as mat;
html {
@@ -310,19 +310,19 @@ define your own queries to apply the styles that make sense for your users. This
may mean relying on `color-scheme: light dark`, defining custom media queries,
or reading a saved user preference to apply styles.
-## **Multiple Themes**
+## Multiple Themes
You can call the `mat.theme` mixin more than once to apply multiple different
color schemes in your application.
-### **Context-specific Themes**
+### Context-specific Themes
The following example theme file customizes the theme for components in
different contexts. In this case, a cyan-based palette is applied to a container
of information about deleting data, causing buttons and other components to have
a unique and attention-grabbing style applied:
-```
+```scss
@use '@angular/material' as mat;
html {
@@ -340,7 +340,7 @@ html {
}
```
-## **Using Theme Styles**
+## Using Theme Styles
An application’s custom components can use the CSS variables defined by
`mat.theme` to apply the theme’s colors and typography.
@@ -356,7 +356,7 @@ The following example styles demonstrate a component using the color and
typography variables to create an application-wide banner presenting important
information to the user:
-```
+```scss
:host {
background: var(--mat-sys-primary-container);
color: var(--mat-sys-on-primary-container);
@@ -369,7 +369,7 @@ See the [Theme Variables](https://material.angular.dev/guide/system-variables) g
comprehensive list of these variables, examples of where they are used, and how
components can depend on them.
-## **Customizing Tokens**
+## Customizing Tokens
Angular Material components also allow for narrowly targeted customization of
specific tokens through the `overrides` mixins. This enables fine-grained
@@ -380,7 +380,7 @@ The `overrides` API validates that the customized tokens are correctly spelled
and can be used to ensure backwards compatibility if tokens are added, moved, or
renamed in future versions.
-### **System Tokens**
+### System Tokens
System-level tokens can be changed to different values through the
`mat.theme-overrides` mixin, which will redefine CSS variables that are used in
@@ -389,7 +389,7 @@ the application.
The following example applies a violet color palette for the application, but
alters the `primary-container` token to a specific shade of blue.
-```
+```scss
@use '@angular/material' as mat;
html {
@@ -411,7 +411,7 @@ html {
Alternatively, an optional override map can be provided in the `mat.theme` mixin
to replace values applied by the mixin:
-```
+```scss
@use '@angular/material' as mat;
html {
@@ -426,7 +426,7 @@ html {
}
```
-### **Component Tokens**
+### Component Tokens
Each Angular Material component defines an `overrides` mixin that can be used to
customize tokenized styles for their color, typography, and density.
@@ -439,7 +439,7 @@ The following example demonstrates the Card’s `overrides` API to change the
background color to red, increase the corner border radius, and specify a larger
title font size.
-```
+```scss
html {
@include mat.card-overrides((
elevated-container-color: red,
@@ -449,7 +449,7 @@ html {
}
```
-### **Direct Style Overrides**
+### Direct Style Overrides
Angular Material supports customizing color, typography, and density as outlined
in this document. Angular strongly discourages, and does not directly support,
@@ -458,7 +458,7 @@ structure and CSS classes are considered private implementation details that may
change at any time. CSS variables used by the Angular Material components should
be defined through the `overrides` API instead of defined explicitly.
-## **Shadow DOM**
+## Shadow DOM
Angular Material assumes that, by default, all theme styles are loaded as global
CSS. If you want to use
diff --git a/package.json b/package.json
index 06d796c25849..a6a1bacb2c6b 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,7 @@
"ci-docs-monitor-test": "node --no-warnings=ExperimentalWarning --loader ts-node/esm/transpile-only scripts/docs-deploy/monitoring/ci-test.mts",
"prepare": "husky"
},
- "version": "20.1.0",
+ "version": "20.1.1",
"dependencies": {
"@angular-devkit/core": "catalog:",
"@angular-devkit/schematics": "catalog:",
@@ -92,7 +92,6 @@
"@schematics/angular": "catalog:",
"@types/babel__core": "^7.1.18",
"@types/fs-extra": "^11.0.0",
- "@types/glob": "^8.0.0",
"@types/jasmine": "^5.0.0",
"@types/luxon": "^3.0.0",
"@types/node": "^22.14.1",
@@ -106,7 +105,7 @@
"dgeni": "^0.4.14",
"dgeni-packages": "^0.30.0",
"esbuild": "^0.25.0",
- "firebase-tools": "14.9.0",
+ "firebase-tools": "14.10.1",
"fs-extra": "^11.0.0",
"glob": "^11.0.3",
"highlight.js": "^11.0.0",
@@ -124,7 +123,7 @@
"magic-string": "0.30.17",
"marked": "^16.0.0",
"minimatch": "^10.0.3",
- "parse5": "^7.1.2",
+ "parse5": "^8.0.0",
"postcss": "^8.4.17",
"postcss-scss": "^4.0.4",
"prettier": "^3.5.3",
@@ -132,7 +131,7 @@
"requirejs": "^2.3.6",
"rollup": "^4.0.0",
"rollup-plugin-dts": "6.2.1",
- "rollup-plugin-sourcemaps2": "0.5.2",
+ "rollup-plugin-sourcemaps2": "0.5.3",
"sass": "^1.80.6",
"selenium-webdriver": "^3.6.0",
"semver": "^7.3.5",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 03b19f59db7d..8b7a3c52e0e0 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -179,9 +179,6 @@ importers:
'@types/fs-extra':
specifier: ^11.0.0
version: 11.0.4
- '@types/glob':
- specifier: ^8.0.0
- version: 8.1.0
'@types/jasmine':
specifier: ^5.0.0
version: 5.1.8
@@ -222,8 +219,8 @@ importers:
specifier: ^0.25.0
version: 0.25.4
firebase-tools:
- specifier: 14.9.0
- version: 14.9.0(@types/node@22.14.1)(encoding@0.1.13)
+ specifier: 14.10.1
+ version: 14.10.1(@types/node@22.14.1)(encoding@0.1.13)
fs-extra:
specifier: ^11.0.0
version: 11.3.0
@@ -276,8 +273,8 @@ importers:
specifier: ^10.0.3
version: 10.0.3
parse5:
- specifier: ^7.1.2
- version: 7.2.1
+ specifier: ^8.0.0
+ version: 8.0.0
postcss:
specifier: ^8.4.17
version: 8.5.3
@@ -300,8 +297,8 @@ importers:
specifier: 6.2.1
version: 6.2.1(rollup@4.40.2)(typescript@5.8.3)
rollup-plugin-sourcemaps2:
- specifier: 0.5.2
- version: 0.5.2(@types/node@22.14.1)(rollup@4.40.2)
+ specifier: 0.5.3
+ version: 0.5.3(@types/node@22.14.1)(rollup@4.40.2)
sass:
specifier: ^1.80.6
version: 1.86.3
@@ -448,8 +445,8 @@ importers:
specifier: ^22.14.1
version: 22.14.1
'@types/shelljs':
- specifier: 0.8.16
- version: 0.8.16
+ specifier: 0.8.17
+ version: 0.8.17
firebase-tools:
specifier: ^14.0.0
version: 14.4.0(@types/node@22.14.1)(encoding@0.1.13)
@@ -532,8 +529,8 @@ importers:
src/cdk:
dependencies:
parse5:
- specifier: ^7.1.2
- version: 7.2.1
+ specifier: ^8.0.0
+ version: 8.0.0
tslib:
specifier: ^2.3.0
version: 2.8.1
@@ -2648,6 +2645,15 @@ packages:
rollup:
optional: true
+ '@rollup/pluginutils@5.2.0':
+ resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
'@rollup/rollup-android-arm-eabi@4.40.2':
resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==}
cpu: [arm]
@@ -2900,9 +2906,6 @@ packages:
'@types/glob@7.2.0':
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
- '@types/glob@8.1.0':
- resolution: {integrity: sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==}
-
'@types/google.maps@3.58.1':
resolution: {integrity: sha512-X9QTSvGJ0nCfMzYOnaVs/k6/4L+7F5uCS+4iUmkLEls6J9S/Phv+m/i3mDeyc49ZBgwab3EFO1HEoBY7k98EGQ==}
@@ -2991,8 +2994,8 @@ packages:
'@types/shelljs@0.8.15':
resolution: {integrity: sha512-vzmnCHl6hViPu9GNLQJ+DZFd6BQI2DBTUeOvYHqkWQLMfKAAQYMb/xAmZkTogZI/vqXHCWkqDRymDI5p0QTi5Q==}
- '@types/shelljs@0.8.16':
- resolution: {integrity: sha512-40SUXiH0tZfAg/oKkkGF1kdHPAmE4slv2xAmbfa8VtE6ztHYwdpW2phlzHTVdJh5JOGqA3Cx1Hzp7kxFalKHYA==}
+ '@types/shelljs@0.8.17':
+ resolution: {integrity: sha512-IDksKYmQA2W9MkQjiyptbMmcQx+8+Ol6b7h6dPU5S05JyiQDSb/nZKnrMrZqGwgV6VkVdl6/SPCKPDlMRvqECg==}
'@types/sockjs@0.3.36':
resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==}
@@ -4666,13 +4669,13 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
- firebase-tools@14.4.0:
- resolution: {integrity: sha512-avJJrEoWdlntCc1OWo55pt53CDWPmTMMkh4vKsQEgMxVPLIesUg2OqP3XdlUZuOe4o2yP/58r+73BTyJjQKoVA==}
+ firebase-tools@14.10.1:
+ resolution: {integrity: sha512-KUwA/HyJhiOLgsHwsanQmXI5j7J12IkA+JnA+oMpmyOv/gBzJxp3LRuxHTdfv/MY17w29ppUMDqS2+jR3ViSzw==}
engines: {node: '>=20.0.0 || >=22.0.0'}
hasBin: true
- firebase-tools@14.9.0:
- resolution: {integrity: sha512-8si+bTK9WJ82zr/wiwbfqlMeuqIQgRfwFOzGE+9OA+m9pRnN7fuFvMiE1UEfQmsbmLrVsD9Tv22AFsU6vaBUVA==}
+ firebase-tools@14.4.0:
+ resolution: {integrity: sha512-avJJrEoWdlntCc1OWo55pt53CDWPmTMMkh4vKsQEgMxVPLIesUg2OqP3XdlUZuOe4o2yP/58r+73BTyJjQKoVA==}
engines: {node: '>=20.0.0 || >=22.0.0'}
hasBin: true
@@ -6760,6 +6763,9 @@ packages:
parse5@7.2.1:
resolution: {integrity: sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==}
+ parse5@8.0.0:
+ resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==}
+
parseurl@1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@@ -7391,8 +7397,8 @@ packages:
rollup: ^3.29.4 || ^4
typescript: 5.8.3
- rollup-plugin-sourcemaps2@0.5.2:
- resolution: {integrity: sha512-NTz5Y5ySYH9cZZF+qteTHN2x3dnFggTKzCtiN3NhtMvIEXdkOsZVBh6r6xrwsyDnZAhmKRsttwTfXfJVoanM6w==}
+ rollup-plugin-sourcemaps2@0.5.3:
+ resolution: {integrity: sha512-KmD8A50Lvi/FVkmu8Xo1LXFfhE5tCK/CIAWcnN44cJlgjyGR1l8WqYrSpJ+SQ3e6KNSj7GBvwqUg/4nQt3Agow==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@types/node': '>=18.0.0'
@@ -10990,6 +10996,14 @@ snapshots:
optionalDependencies:
rollup: 4.40.2
+ '@rollup/pluginutils@5.2.0(rollup@4.40.2)':
+ dependencies:
+ '@types/estree': 1.0.7
+ estree-walker: 2.0.2
+ picomatch: 4.0.2
+ optionalDependencies:
+ rollup: 4.40.2
+
'@rollup/rollup-android-arm-eabi@4.40.2':
optional: true
@@ -11255,11 +11269,6 @@ snapshots:
'@types/minimatch': 5.1.2
'@types/node': 22.14.1
- '@types/glob@8.1.0':
- dependencies:
- '@types/minimatch': 5.1.2
- '@types/node': 22.14.1
-
'@types/google.maps@3.58.1': {}
'@types/http-errors@2.0.4': {}
@@ -11348,10 +11357,10 @@ snapshots:
'@types/glob': 7.2.0
'@types/node': 22.14.1
- '@types/shelljs@0.8.16':
+ '@types/shelljs@0.8.17':
dependencies:
- '@types/glob': 7.2.0
'@types/node': 22.14.1
+ glob: 11.0.3
'@types/sockjs@0.3.36':
dependencies:
@@ -13311,9 +13320,10 @@ snapshots:
locate-path: 6.0.0
path-exists: 4.0.0
- firebase-tools@14.4.0(@types/node@22.14.1)(encoding@0.1.13):
+ firebase-tools@14.10.1(@types/node@22.14.1)(encoding@0.1.13):
dependencies:
- '@electric-sql/pglite': 0.2.17
+ '@electric-sql/pglite': 0.3.3
+ '@electric-sql/pglite-tools': 0.2.8(@electric-sql/pglite@0.3.3)
'@google-cloud/cloud-sql-connector': 1.8.0(encoding@0.1.13)
'@google-cloud/pubsub': 4.11.0(encoding@0.1.13)
'@inquirer/prompts': 7.5.1(@types/node@22.14.1)
@@ -13362,6 +13372,8 @@ snapshots:
ora: 5.4.1
p-limit: 3.1.0
pg: 8.16.0
+ pg-gateway: 0.3.0-beta.4
+ pglite-2: '@electric-sql/pglite@0.2.17'
portfinder: 1.0.35
progress: 2.0.3
proxy-agent: 6.5.0
@@ -13392,10 +13404,9 @@ snapshots:
- supports-color
- utf-8-validate
- firebase-tools@14.9.0(@types/node@22.14.1)(encoding@0.1.13):
+ firebase-tools@14.4.0(@types/node@22.14.1)(encoding@0.1.13):
dependencies:
- '@electric-sql/pglite': 0.3.3
- '@electric-sql/pglite-tools': 0.2.8(@electric-sql/pglite@0.3.3)
+ '@electric-sql/pglite': 0.2.17
'@google-cloud/cloud-sql-connector': 1.8.0(encoding@0.1.13)
'@google-cloud/pubsub': 4.11.0(encoding@0.1.13)
'@inquirer/prompts': 7.5.1(@types/node@22.14.1)
@@ -13444,8 +13455,6 @@ snapshots:
ora: 5.4.1
p-limit: 3.1.0
pg: 8.16.0
- pg-gateway: 0.3.0-beta.4
- pglite-2: '@electric-sql/pglite@0.2.17'
portfinder: 1.0.35
progress: 2.0.3
proxy-agent: 6.5.0
@@ -15862,6 +15871,10 @@ snapshots:
dependencies:
entities: 4.5.0
+ parse5@8.0.0:
+ dependencies:
+ entities: 6.0.0
+
parseurl@1.3.3: {}
pascal-case@2.0.1:
@@ -16544,9 +16557,9 @@ snapshots:
optionalDependencies:
'@babel/code-frame': 7.26.2
- rollup-plugin-sourcemaps2@0.5.2(@types/node@22.14.1)(rollup@4.40.2):
+ rollup-plugin-sourcemaps2@0.5.3(@types/node@22.14.1)(rollup@4.40.2):
dependencies:
- '@rollup/pluginutils': 5.1.4(rollup@4.40.2)
+ '@rollup/pluginutils': 5.2.0(rollup@4.40.2)
rollup: 4.40.2
optionalDependencies:
'@types/node': 22.14.1
diff --git a/src/cdk/drag-drop/directives/drag.ts b/src/cdk/drag-drop/directives/drag.ts
index 9ac4ef7f1261..9e8c738a3b60 100644
--- a/src/cdk/drag-drop/directives/drag.ts
+++ b/src/cdk/drag-drop/directives/drag.ts
@@ -248,7 +248,6 @@ export class CdkDrag implements AfterViewInit, OnChanges, OnDestroy {
// is too late since the two modes save different kinds of information. We work around it by
// assigning the drop container both from here and the list.
if (dropContainer) {
- this._dragRef._withDropContainer(dropContainer._dropListRef);
dropContainer.addItem(this);
// The drop container reads this so we need to sync it here.
diff --git a/src/cdk/drag-drop/directives/drop-list.ts b/src/cdk/drag-drop/directives/drop-list.ts
index 06f235c3aca9..bab8a65c91d1 100644
--- a/src/cdk/drag-drop/directives/drop-list.ts
+++ b/src/cdk/drag-drop/directives/drop-list.ts
@@ -235,6 +235,7 @@ export class CdkDropList implements OnDestroy {
/** Registers an items with the drop list. */
addItem(item: CdkDrag): void {
this._unsortedItems.add(item);
+ item._dragRef._withDropContainer(this._dropListRef);
// Only sync the items while dragging since this method is
// called when items are being initialized one-by-one.
diff --git a/src/cdk/drag-drop/drag-drop.md b/src/cdk/drag-drop/drag-drop.md
index 44d9f791d23d..0aca4d30d639 100644
--- a/src/cdk/drag-drop/drag-drop.md
+++ b/src/cdk/drag-drop/drag-drop.md
@@ -280,3 +280,10 @@ This example shows how you can set up a table which supports re-ordering of tabs
#### Sortable tabs
Example of how to add sorting support to a `mat-tab-group`.
+
+#### Scrollable container
+If your draggable items are inside a scrollable container (e.g., a div with overflow: auto)
+automatic scrolling will not work unless the scrollable container has the `cdkScrollable` directive.
+Without it, the CDK cannot detect or control the scroll behavior of the container during drag
+operations.
+
diff --git a/src/cdk/package.json b/src/cdk/package.json
index 0cb0dc83ae09..5923d56a28b0 100644
--- a/src/cdk/package.json
+++ b/src/cdk/package.json
@@ -50,7 +50,7 @@
"rxjs": "^6.5.3 || ^7.4.0"
},
"dependencies": {
- "parse5": "^7.1.2",
+ "parse5": "^8.0.0",
"tslib": "^2.3.0"
},
"schematics": "./schematics/collection.json",
diff --git a/src/cdk/schematics/BUILD.bazel b/src/cdk/schematics/BUILD.bazel
index 2499dea4b11e..a47a9c8bf73b 100644
--- a/src/cdk/schematics/BUILD.bazel
+++ b/src/cdk/schematics/BUILD.bazel
@@ -1,6 +1,6 @@
load("@aspect_bazel_lib//lib:copy_to_bin.bzl", "copy_to_bin")
-load("//tools:defaults.bzl", "jasmine_test", "npm_package", "ts_project")
load("@aspect_rules_ts//ts:defs.bzl", rules_js_tsconfig = "ts_config")
+load("//tools:defaults.bzl", "jasmine_test", "npm_package", "ts_project")
package(default_visibility = [":__subpackages__"])
@@ -44,7 +44,6 @@ ts_project(
"//:node_modules/@angular-devkit/core",
"//:node_modules/@angular-devkit/schematics",
"//:node_modules/@schematics/angular",
- "//:node_modules/@types/glob",
"//:node_modules/@types/node",
"//:node_modules/glob",
"//:node_modules/parse5",
diff --git a/src/cdk/schematics/testing/BUILD.bazel b/src/cdk/schematics/testing/BUILD.bazel
index b018fffc8680..ab868ebd40eb 100644
--- a/src/cdk/schematics/testing/BUILD.bazel
+++ b/src/cdk/schematics/testing/BUILD.bazel
@@ -18,7 +18,6 @@ ts_project(
"//:node_modules/@bazel/runfiles",
"//:node_modules/@schematics/angular",
"//:node_modules/@types/fs-extra",
- "//:node_modules/@types/glob",
"//:node_modules/@types/jasmine",
"//:node_modules/@types/node",
"//:node_modules/fs-extra",
diff --git a/src/components-examples/cdk/drag-drop/cdk-drag-drop-scrollable/cdk-drag-drop-scrollable-example.css b/src/components-examples/cdk/drag-drop/cdk-drag-drop-scrollable/cdk-drag-drop-scrollable-example.css
new file mode 100644
index 000000000000..1288a030736c
--- /dev/null
+++ b/src/components-examples/cdk/drag-drop/cdk-drag-drop-scrollable/cdk-drag-drop-scrollable-example.css
@@ -0,0 +1,54 @@
+.example-container {
+ height: 20rem;
+ overflow: auto;
+}
+
+.example-list {
+ width: 500px;
+ max-width: 100%;
+ border: solid 1px #ccc;
+ min-height: 60px;
+ display: block;
+ background: white;
+ border-radius: 4px;
+ overflow: hidden;
+}
+
+.example-box {
+ padding: 20px 10px;
+ border-bottom: solid 1px #ccc;
+ color: rgba(0, 0, 0, 0.87);
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+ box-sizing: border-box;
+ cursor: move;
+ background: white;
+ font-size: 14px;
+}
+
+.cdk-drag-preview {
+ border: none;
+ box-sizing: border-box;
+ border-radius: 4px;
+ box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
+ 0 8px 10px 1px rgba(0, 0, 0, 0.14),
+ 0 3px 14px 2px rgba(0, 0, 0, 0.12);
+}
+
+.cdk-drag-placeholder {
+ opacity: 0;
+}
+
+.cdk-drag-animating {
+ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}
+
+.example-box:last-child {
+ border: none;
+}
+
+.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
+ transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
+}
diff --git a/src/components-examples/cdk/drag-drop/cdk-drag-drop-scrollable/cdk-drag-drop-scrollable-example.html b/src/components-examples/cdk/drag-drop/cdk-drag-drop-scrollable/cdk-drag-drop-scrollable-example.html
new file mode 100644
index 000000000000..1c35951951ac
--- /dev/null
+++ b/src/components-examples/cdk/drag-drop/cdk-drag-drop-scrollable/cdk-drag-drop-scrollable-example.html
@@ -0,0 +1,7 @@
+
+
+ @for (elementName of elementNames; track elementName) {
+
{{elementName}}
+ }
+
+
\ No newline at end of file
diff --git a/src/components-examples/cdk/drag-drop/cdk-drag-drop-scrollable/cdk-drag-drop-scrollable-example.ts b/src/components-examples/cdk/drag-drop/cdk-drag-drop-scrollable/cdk-drag-drop-scrollable-example.ts
new file mode 100644
index 000000000000..02712a7eac5e
--- /dev/null
+++ b/src/components-examples/cdk/drag-drop/cdk-drag-drop-scrollable/cdk-drag-drop-scrollable-example.ts
@@ -0,0 +1,138 @@
+import {Component} from '@angular/core';
+import {CdkDragDrop, CdkDropList, CdkDrag, moveItemInArray} from '@angular/cdk/drag-drop';
+import {CdkScrollable} from '@angular/cdk/scrolling';
+
+/**
+ * @title Drag&Drop scrollable
+ */
+@Component({
+ selector: 'cdk-drag-drop-scrollable-example',
+ templateUrl: 'cdk-drag-drop-scrollable-example.html',
+ styleUrl: 'cdk-drag-drop-scrollable-example.css',
+ imports: [CdkDropList, CdkDrag, CdkScrollable],
+})
+export class CdkDragDropScrollableExample {
+ elementNames = [
+ 'Hydrogen',
+ 'Helium',
+ 'Lithium',
+ 'Beryllium',
+ 'Boron',
+ 'Carbon',
+ 'Nitrogen',
+ 'Oxygen',
+ 'Fluorine',
+ 'Neon',
+ 'Sodium',
+ 'Magnesium',
+ 'Aluminum',
+ 'Silicon',
+ 'Phosphorus',
+ 'Sulfur',
+ 'Chlorine',
+ 'Argon',
+ 'Potassium',
+ 'Calcium',
+ 'Scandium',
+ 'Titanium',
+ 'Vanadium',
+ 'Chromium',
+ 'Manganese',
+ 'Iron',
+ 'Cobalt',
+ 'Nickel',
+ 'Copper',
+ 'Zinc',
+ 'Gallium',
+ 'Germanium',
+ 'Arsenic',
+ 'Selenium',
+ 'Bromine',
+ 'Krypton',
+ 'Rubidium',
+ 'Strontium',
+ 'Yttrium',
+ 'Zirconium',
+ 'Niobium',
+ 'Molybdenum',
+ 'Technetium',
+ 'Ruthenium',
+ 'Rhodium',
+ 'Palladium',
+ 'Silver',
+ 'Cadmium',
+ 'Indium',
+ 'Tin',
+ 'Antimony',
+ 'Tellurium',
+ 'Iodine',
+ 'Xenon',
+ 'Cesium',
+ 'Barium',
+ 'Lanthanum',
+ 'Cerium',
+ 'Praseodymium',
+ 'Neodymium',
+ 'Promethium',
+ 'Samarium',
+ 'Europium',
+ 'Gadolinium',
+ 'Terbium',
+ 'Dysprosium',
+ 'Holmium',
+ 'Erbium',
+ 'Thulium',
+ 'Ytterbium',
+ 'Lutetium',
+ 'Hafnium',
+ 'Tantalum',
+ 'Tungsten',
+ 'Rhenium',
+ 'Osmium',
+ 'Iridium',
+ 'Platinum',
+ 'Gold',
+ 'Mercury',
+ 'Thallium',
+ 'Lead',
+ 'Bismuth',
+ 'Polonium',
+ 'Astatine',
+ 'Radon',
+ 'Francium',
+ 'Radium',
+ 'Actinium',
+ 'Thorium',
+ 'Protactinium',
+ 'Uranium',
+ 'Neptunium',
+ 'Plutonium',
+ 'Americium',
+ 'Curium',
+ 'Berkelium',
+ 'Californium',
+ 'Einsteinium',
+ 'Fermium',
+ 'Mendelevium',
+ 'Nobelium',
+ 'Lawrencium',
+ 'Rutherfordium',
+ 'Dubnium',
+ 'Seaborgium',
+ 'Bohrium',
+ 'Hassium',
+ 'Meitnerium',
+ 'Darmstadtium',
+ 'Roentgenium',
+ 'Copernicium',
+ 'Nihonium',
+ 'Flerovium',
+ 'Moscovium',
+ 'Livermorium',
+ 'Tennessine',
+ 'Oganesson',
+ ];
+ drop(event: CdkDragDrop) {
+ moveItemInArray(this.elementNames, event.previousIndex, event.currentIndex);
+ }
+}
diff --git a/src/material/schematics/ng-add/index.spec.ts b/src/material/schematics/ng-add/index.spec.ts
index e8c240462a10..9101f6a017c9 100644
--- a/src/material/schematics/ng-add/index.spec.ts
+++ b/src/material/schematics/ng-add/index.spec.ts
@@ -87,7 +87,7 @@ describe('ng-add schematic', () => {
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);
- expectProjectStyleFile(project, '@angular/material/prebuilt-themes/azure-blue.css');
+ expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss');
});
it('should support adding a custom theme', async () => {
@@ -96,7 +96,7 @@ describe('ng-add schematic', () => {
const tree = await runner.runSchematic(
'ng-add-setup-project',
- {...baseOptions, theme: 'custom'},
+ {...baseOptions, theme: 'azure-blue'},
appTree,
);
const workspace = await readWorkspace(tree);
@@ -116,7 +116,7 @@ describe('ng-add schematic', () => {
const tree = await runner.runSchematic(
'ng-add-setup-project',
- {...baseOptions, theme: 'custom'},
+ {...baseOptions, theme: 'azure-blue'},
appTree,
);
const workspace = await readWorkspace(tree);
@@ -213,108 +213,14 @@ describe('ng-add schematic', () => {
runner.runSchematic('ng-add-setup-project', baseOptions, appTree),
).toBeRejected();
});
-
- it('should warn if the "test" target has been changed', async () => {
- overwriteTargetBuilder(appTree, 'test', 'thirdparty-test-builder');
- await runner.runSchematic('ng-add-setup-project', baseOptions, appTree);
-
- expect(errorOutput.length).toBe(0);
- expect(warnOutput.length).toBe(1);
- expect(warnOutput[0]).toMatch(
- /not using the default builders.*cannot add the configured theme/,
- );
- });
});
describe('theme files', () => {
- /** Path to the default prebuilt theme file that will be added when running ng-add. */
- const defaultPrebuiltThemePath = '@angular/material/prebuilt-themes/azure-blue.css';
-
- /** Writes a specific style file to the workspace in the given tree */
- function writeStyleFileToWorkspace(tree: Tree, stylePath: string) {
- tree.overwrite(
- '/angular.json',
- JSON.stringify(
- {
- version: 1,
- projects: {
- material: {
- projectType: 'application',
- root: 'projects/material',
- sourceRoot: 'projects/material/src',
- prefix: 'app',
- architect: {
- build: {
- builder: '@angular-devkit/build-angular:application',
- options: {
- outputPath: 'dist/material',
- index: 'projects/material/src/index.html',
- browser: 'projects/material/src/main.ts',
- styles: ['projects/material/src/styles.css', stylePath],
- },
- },
- },
- },
- },
- },
- null,
- 2,
- ),
- );
- }
-
- it('should replace existing prebuilt theme files', async () => {
- const existingThemePath = '@angular/material/prebuilt-themes/purple-green.css';
- writeStyleFileToWorkspace(appTree, existingThemePath);
-
- const tree = await runner.runSchematic('ng-add-setup-project', baseOptions, appTree);
- const workspace = await readWorkspace(tree);
- const project = getProjectFromWorkspace(workspace, baseOptions.project);
- const styles = getProjectTargetOptions(project, 'build')['styles'];
-
- expect(styles)
- .not.withContext('Expected the existing prebuilt theme file to be removed.')
- .toContain(existingThemePath);
- expect(styles)
- .withContext('Expected the default prebuilt theme to be added.')
- .toContain(defaultPrebuiltThemePath);
- });
-
- it('should not replace existing custom theme files', async () => {
- writeStyleFileToWorkspace(appTree, './projects/material/custom-theme.scss');
-
- const tree = await runner.runSchematic('ng-add-setup-project', baseOptions, appTree);
- const workspace = await readWorkspace(tree);
- const project = getProjectFromWorkspace(workspace, baseOptions.project);
- const styles = getProjectTargetOptions(project, 'build')['styles'];
-
- expect(styles)
- .not.withContext('Expected the default prebuilt theme to be not configured.')
- .toContain(defaultPrebuiltThemePath);
- expect(errorOutput.length).toBe(1);
- expect(errorOutput[0]).toMatch(/Could not add the selected theme/);
- });
-
- it('should not add a theme file multiple times', async () => {
- writeStyleFileToWorkspace(appTree, defaultPrebuiltThemePath);
-
- const tree = await runner.runSchematic('ng-add-setup-project', baseOptions, appTree);
- const workspace = await readWorkspace(tree);
- const project = getProjectFromWorkspace(workspace, baseOptions.project);
- const styles = getProjectTargetOptions(project, 'build')['styles'];
-
- expect(styles)
- .withContext(
- 'Expected the "styles.css" file and default prebuilt theme to be ' + 'the only styles',
- )
- .toEqual(['projects/material/src/styles.css', defaultPrebuiltThemePath]);
- });
-
it('should not overwrite existing custom theme files', async () => {
appTree.create('/projects/material/custom-theme.scss', 'custom-theme');
const tree = await runner.runSchematic(
'ng-add-setup-project',
- {...baseOptions, theme: 'custom'},
+ {...baseOptions, theme: 'azure-blue'},
appTree,
);
expect(tree.readContent('/projects/material/custom-theme.scss'))
@@ -323,117 +229,6 @@ describe('ng-add schematic', () => {
});
});
- it('should add the global typography class if the body has no classes', async () => {
- const tree = await runner.runSchematic(
- 'ng-add-setup-project',
- {
- ...baseOptions,
- typography: true,
- },
- appTree,
- );
- const workspace = await readWorkspace(tree);
- const project = getProjectFromWorkspace(workspace, baseOptions.project);
-
- const indexFiles = getProjectIndexFiles(project);
- expect(indexFiles.length).toBe(1);
-
- indexFiles.forEach(indexPath => {
- const buffer = tree.read(indexPath)!;
- expect(buffer.toString()).toContain('');
- });
- });
-
- it('should add the global typography class if the body has existing classes', async () => {
- appTree.overwrite(
- 'projects/material/src/index.html',
- `
-
-
-
-
- `,
- );
-
- const tree = await runner.runSchematic(
- 'ng-add-setup-project',
- {
- ...baseOptions,
- typography: true,
- },
- appTree,
- );
- const workspace = await readWorkspace(tree);
- const project = getProjectFromWorkspace(workspace, baseOptions.project);
- const indexFiles = getProjectIndexFiles(project);
- expect(indexFiles.length).toBe(1);
-
- indexFiles.forEach(indexPath => {
- const buffer = tree.read(indexPath)!;
- expect(buffer.toString()).toContain('');
- });
- });
-
- it('should not add the global typography class if it exists already', async () => {
- appTree.overwrite(
- 'projects/material/src/index.html',
- `
-
-
-
-
- `,
- );
-
- const tree = await runner.runSchematic(
- 'ng-add-setup-project',
- {
- ...baseOptions,
- typography: true,
- },
- appTree,
- );
- const workspace = await readWorkspace(tree);
- const project = getProjectFromWorkspace(workspace, baseOptions.project);
- const indexFiles = getProjectIndexFiles(project);
- expect(indexFiles.length).toBe(1);
-
- indexFiles.forEach(indexPath => {
- const buffer = tree.read(indexPath)!;
- expect(buffer.toString()).toContain('');
- });
- });
-
- it('should not add the global typography class if the user did not opt into it', async () => {
- appTree.overwrite(
- 'projects/material/src/index.html',
- `
-
-
-
-
- `,
- );
-
- const tree = await runner.runSchematic(
- 'ng-add-setup-project',
- {
- ...baseOptions,
- typography: false,
- },
- appTree,
- );
- const workspace = await readWorkspace(tree);
- const project = getProjectFromWorkspace(workspace, baseOptions.project);
- const indexFiles = getProjectIndexFiles(project);
- expect(indexFiles.length).toBe(1);
-
- indexFiles.forEach(indexPath => {
- const buffer = tree.read(indexPath)!;
- expect(buffer.toString()).toContain('');
- });
- });
-
describe('using browser builder', () => {
beforeEach(() => {
const config = {
@@ -476,21 +271,7 @@ describe('ng-add schematic', () => {
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);
- expectProjectStyleFile(project, '@angular/material/prebuilt-themes/azure-blue.css');
- });
-
- 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; }',
- );
+ expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss');
});
});
@@ -536,21 +317,7 @@ describe('ng-add schematic', () => {
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);
- expectProjectStyleFile(project, '@angular/material/prebuilt-themes/azure-blue.css');
- });
-
- 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; }',
- );
+ expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss');
});
});
@@ -587,7 +354,7 @@ describe('ng-add schematic', () => {
const workspace = await readWorkspace(tree);
const project = getProjectFromWorkspace(workspace, baseOptions.project);
- expectProjectStyleFile(project, '@angular/material/prebuilt-themes/azure-blue.css');
+ expectProjectStyleFile(project, 'projects/material/src/custom-theme.scss');
});
});
});
diff --git a/src/material/schematics/ng-add/schema.json b/src/material/schematics/ng-add/schema.json
index 7017356a89ff..683e954780f6 100644
--- a/src/material/schematics/ng-add/schema.json
+++ b/src/material/schematics/ng-add/schema.json
@@ -16,7 +16,7 @@
"type": "string",
"default": "azure-blue",
"x-prompt": {
- "message": "Choose a prebuilt theme name, or \"custom\" for a custom theme:",
+ "message": "Select a pair of starter prebuilt color palettes for your Angular Material theme",
"type": "list",
"items": [
{
@@ -34,16 +34,9 @@
{
"value": "cyan-orange",
"label": "Cyan/Orange [Preview: https://material.angular.dev?theme=cyan-orange]"
- },
- {"value": "custom", "label": "Custom"}
+ }
]
}
- },
- "typography": {
- "type": "boolean",
- "default": false,
- "description": "Whether to set up global typography styles.",
- "x-prompt": "Set up global Angular Material typography styles?"
}
},
"required": []
diff --git a/src/material/schematics/ng-add/setup-project.ts b/src/material/schematics/ng-add/setup-project.ts
index dfb077b7f227..f0897ade7206 100644
--- a/src/material/schematics/ng-add/setup-project.ts
+++ b/src/material/schematics/ng-add/setup-project.ts
@@ -6,13 +6,13 @@
* found in the LICENSE file at https://angular.dev/license
*/
-import {chain, noop, Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
+import {chain, Rule, SchematicContext, Tree} from '@angular-devkit/schematics';
import {getProjectFromWorkspace, getProjectStyleFile} from '@angular/cdk/schematics';
import {readWorkspace} from '@schematics/angular/utility';
import {ProjectType} from '@schematics/angular/utility/workspace-models';
import {addFontsToIndex} from './fonts/material-fonts';
import {Schema} from './schema';
-import {addThemeToAppStyles, addTypographyClass} from './theming/theming';
+import {addThemeToAppStyles} from './theming/theming';
/**
* Scaffolds the basics of a Angular Material application, this includes:
@@ -29,7 +29,6 @@ export default function (options: Schema): Rule {
addThemeToAppStyles(options),
addFontsToIndex(options),
addMaterialAppStyles(options),
- options.typography ? addTypographyClass(options) : noop(),
]);
}
context.logger.warn(
diff --git a/src/material/schematics/ng-add/theming/create-custom-theme.ts b/src/material/schematics/ng-add/theming/create-custom-theme.ts
index d490edef7b90..91c8b0ad9660 100644
--- a/src/material/schematics/ng-add/theming/create-custom-theme.ts
+++ b/src/material/schematics/ng-add/theming/create-custom-theme.ts
@@ -7,21 +7,41 @@
*/
/** Create custom theme for the given application configuration. */
-export function createCustomTheme(name: string = 'app') {
+export function createCustomTheme(userPaletteChoice: string) {
+ const colorPalettes = new Map([
+ ['azure-blue', {primary: 'azure', tertiary: 'blue'}],
+ ['rose-red', {primary: 'rose', tertiary: 'red'}],
+ ['magenta-violet', {primary: 'magenta', tertiary: 'violet'}],
+ ['cyan-orange', {primary: 'cyan', tertiary: 'orange'}],
+ ]);
return `
-// Custom Theming for Angular Material
-// For more information: https://material.angular.dev/guide/theming
+// Include theming for Angular Material with \`mat.theme()\`.
+// This Sass mixin will define CSS variables that are used for styling Angular Material
+// components according to the Material 3 design spec.
+// Learn more about theming and how to use it for your application's
+// custom components at https://material.angular.dev/guide/theming
@use '@angular/material' as mat;
html {
@include mat.theme((
color: (
- theme-type: light,
- primary: mat.$azure-palette,
- tertiary: mat.$blue-palette,
+ primary: mat.$${colorPalettes.get(userPaletteChoice)!.primary}-palette,
+ tertiary: mat.$${colorPalettes.get(userPaletteChoice)!.tertiary}-palette,
),
typography: Roboto,
density: 0,
));
+
+ // Default the application to a light color theme. This can be changed to
+ // \`dark\` to enable the dark color theme, or to \`light dark\` to defer to the
+ // user's system settings.
+ color-scheme: light;
+
+ // Set a default background, font and text colors for the application using
+ // Angular Material's system-level CSS variables. Learn more about these
+ // variables at https://material.angular.dev/guide/system-variables
+ background-color: var(--mat-sys-surface);
+ color: var(--mat-sys-on-surface);
+ font: var(--mat-sys-body-medium);
}`;
}
diff --git a/src/material/schematics/ng-add/theming/theming.ts b/src/material/schematics/ng-add/theming/theming.ts
index 7be0e02ff941..ed9263dfd49a 100644
--- a/src/material/schematics/ng-add/theming/theming.ts
+++ b/src/material/schematics/ng-add/theming/theming.ts
@@ -7,20 +7,11 @@
*/
import {normalize, logging} from '@angular-devkit/core';
+import {noop, Rule, SchematicContext, SchematicsException, Tree} from '@angular-devkit/schematics';
import {
- chain,
- noop,
- Rule,
- SchematicContext,
- SchematicsException,
- Tree,
-} from '@angular-devkit/schematics';
-import {
- addBodyClass,
getProjectFromWorkspace,
getProjectStyleFile,
getProjectTargetOptions,
- getProjectIndexFiles,
getProjectTestTargets,
getProjectBuildTargets,
} from '@angular/cdk/schematics';
@@ -39,33 +30,17 @@ const defaultCustomThemeFilename = 'custom-theme.scss';
/** Add pre-built styles to the main project style file. */
export function addThemeToAppStyles(options: Schema): Rule {
return (host: Tree, context: SchematicContext) => {
- const themeName = options.theme || 'azure-blue';
- return themeName === 'custom'
- ? insertCustomTheme(options.project, host, context.logger)
- : insertPrebuiltTheme(options.project, themeName, context.logger);
- };
-}
-
-/** Adds the global typography class to the body element. */
-export function addTypographyClass(options: Schema): Rule {
- return async (host: Tree) => {
- const workspace = await readWorkspace(host);
- const project = getProjectFromWorkspace(workspace, options.project);
- const projectIndexFiles = getProjectIndexFiles(project);
-
- if (!projectIndexFiles.length) {
- throw new SchematicsException('No project index HTML file could be found.');
- }
-
- projectIndexFiles.forEach(path => addBodyClass(host, path, 'mat-typography'));
+ const palettes = options.theme || 'azure-blue';
+ return insertCustomTheme(palettes, options.project, host, context.logger);
};
}
/**
- * Insert a custom theme to project style file. If no valid style file could be found, a new
+ * 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.
*/
async function insertCustomTheme(
+ palettes: string,
projectName: string,
host: Tree,
logger: logging.LoggerApi,
@@ -73,7 +48,7 @@ async function insertCustomTheme(
const workspace = await readWorkspace(host);
const project = getProjectFromWorkspace(workspace, projectName);
const stylesPath = getProjectStyleFile(project, 'scss');
- const themeContent = createCustomTheme(projectName);
+ const themeContent = createCustomTheme(palettes);
if (!stylesPath) {
if (!project.sourceRoot) {
@@ -89,7 +64,7 @@ async function insertCustomTheme(
if (host.exists(customThemePath)) {
logger.warn(`Cannot create a custom Angular Material theme because
- ${customThemePath} already exists. Skipping custom theme generation.`);
+ ${customThemePath} already exists. Skipping theme generation.`);
return noop();
}
@@ -105,16 +80,6 @@ async function insertCustomTheme(
return noop();
}
-/** Insert a pre-built theme into the angular.json file. */
-function insertPrebuiltTheme(project: string, theme: string, logger: logging.LoggerApi): Rule {
- const themePath = `@angular/material/prebuilt-themes/${theme}.css`;
-
- return chain([
- addThemeStyleToTarget(project, 'build', themePath, logger),
- addThemeStyleToTarget(project, 'test', themePath, logger),
- ]);
-}
-
/** Adds a theming style entry to the given project target options. */
function addThemeStyleToTarget(
projectName: string,
diff --git a/src/material/tabs/tab-body.scss b/src/material/tabs/tab-body.scss
index 4a589ccc2ead..89db99c45976 100644
--- a/src/material/tabs/tab-body.scss
+++ b/src/material/tabs/tab-body.scss
@@ -35,6 +35,14 @@
visibility: visible;
}
+ // Chrome appears to have a bug where the animation glitches in RTL if the element
+ // has a height of 0px which can happen with lazy-loaded content or when it's off-screen.
+ // See: https://github.com/angular/components/issues/31503. We can work around it by setting
+ // a minimum height on it.
+ .mat-tab-body-animating > & {
+ min-height: 1px;
+ }
+
.mat-mdc-tab-group-dynamic-height & {
overflow: hidden;
}
diff --git a/src/material/timepicker/timepicker-input.ts b/src/material/timepicker/timepicker-input.ts
index 3912a236e2d8..93e695139fde 100644
--- a/src/material/timepicker/timepicker-input.ts
+++ b/src/material/timepicker/timepicker-input.ts
@@ -140,6 +140,16 @@ export class MatTimepickerInput implements ControlValueAccessor, Validator, O
transform: (value: unknown) => this._transformDateInput(value),
});
+ /**
+ * Whether to open the timepicker overlay when clicking on the input. Enabled by default.
+ * Note that when disabling this option, you'll have to provide your own logic for opening
+ * the overlay.
+ */
+ readonly openOnClick: InputSignalWithTransform = input(true, {
+ alias: 'matTimepickerOpenOnClick',
+ transform: booleanAttribute,
+ });
+
/** Whether the input is disabled. */
readonly disabled: Signal = computed(
() => this.disabledInput() || this._accessorDisabled(),
@@ -254,7 +264,7 @@ export class MatTimepickerInput implements ControlValueAccessor, Validator, O
/** Handles clicks on the input or the containing form field. */
private _handleClick = (): void => {
- if (!this.disabled()) {
+ if (!this.disabled() && this.openOnClick()) {
this.timepicker().open();
}
};
diff --git a/src/material/timepicker/timepicker.spec.ts b/src/material/timepicker/timepicker.spec.ts
index baf1d2ee7df1..3fa080efb157 100644
--- a/src/material/timepicker/timepicker.spec.ts
+++ b/src/material/timepicker/timepicker.spec.ts
@@ -480,6 +480,15 @@ describe('MatTimepicker', () => {
fixture.detectChanges();
expect(getPanel()).toBeTruthy();
}));
+
+ it('should be able to opt out of opening on click', () => {
+ const fixture = TestBed.createComponent(StandaloneTimepicker);
+ fixture.componentInstance.openOnClick.set(false);
+ fixture.detectChanges();
+ getInput(fixture).click();
+ fixture.detectChanges();
+ expect(getPanel()).toBeFalsy();
+ });
});
// Note: these tests intentionally don't cover the full option generation logic
@@ -1313,6 +1322,7 @@ describe('MatTimepicker', () => {
[disabled]="disabled()"
[matTimepickerMin]="min()"
[matTimepickerMax]="max()"
+ [matTimepickerOpenOnClick]="openOnClick()"
[value]="value()"/>
(false);
readonly toggleTabIndex = signal(0);
readonly customOptions = signal[] | null>(null);
+ readonly openOnClick = signal(true);
readonly openedSpy = jasmine.createSpy('opened');
readonly closedSpy = jasmine.createSpy('closed');
readonly selectedSpy = jasmine.createSpy('selected');