Skip to content

Commit 9b93bb1

Browse files
committed
feat(material/card): support filled variant
this commit add `filled` variant for material card which provides subtle seperation from background and has less emphasis than elevated or outlined cards fixes #29840
1 parent 4e0ea8e commit 9b93bb1

File tree

6 files changed

+189
-2
lines changed

6 files changed

+189
-2
lines changed

goldens/material/card/index.api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export class MatCardActions {
3232
}
3333

3434
// @public (undocumented)
35-
export type MatCardAppearance = 'outlined' | 'raised';
35+
export type MatCardAppearance = 'outlined' | 'raised' | 'filled';
3636

3737
// @public
3838
export class MatCardAvatar {

src/material/card/_m2-card.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ $prefix: (mat, card);
1212
@return (
1313
elevated-container-shape: 4px,
1414
outlined-container-shape: 4px,
15+
filled-container-shape: 4px,
1516
outlined-outline-width: 1px,
1617
);
1718
}
@@ -25,6 +26,8 @@ $prefix: (mat, card);
2526
outlined-container-elevation: elevation.get-box-shadow(0),
2627
outlined-outline-color: rgba(inspection.get-theme-color($theme, foreground, base), 0.12),
2728
subtitle-text-color: inspection.get-theme-color($theme, foreground, secondary-text),
29+
filled-container-color: inspection.get-theme-color($theme, background, card),
30+
filled-container-elevation: elevation.get-box-shadow(0)
2831
);
2932
}
3033

src/material/card/_m3-card.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ $prefix: (mat, card);
2525
outlined-container-shape: map.get($systems, md-sys-shape, corner-medium),
2626
outlined-outline-color: map.get($systems, md-sys-color, outline-variant),
2727
outlined-outline-width: if($exclude-hardcoded, null, 1px),
28+
filled-container-color: map.get($systems, md-sys-color, surface-container-highest),
29+
filled-container-elevation: map.get($systems, md-sys-elevation, level0),
30+
filled-container-shape: map.get($systems, md-sys-shape, corner-medium),
2831
),
2932
);
3033

src/material/card/card.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ $mat-card-default-padding: 16px !default;
5151
}
5252
}
5353

54+
.mat-mdc-card-filled {
55+
@include token-utils.use-tokens(m2-card.$prefix, m2-card.get-token-slots()) {
56+
background-color: token-utils.slot(filled-container-color);
57+
border-radius: token-utils.slot(filled-container-shape);
58+
box-shadow: token-utils.slot(filled-container-elevation);
59+
}
60+
}
61+
5462
.mdc-card__media {
5563
position: relative;
5664
box-sizing: border-box;

src/material/card/card.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
inject,
1717
} from '@angular/core';
1818

19-
export type MatCardAppearance = 'outlined' | 'raised';
19+
export type MatCardAppearance = 'outlined' | 'raised' | 'filled';
2020

2121
/** Object that can be used to configure the default options for the card module. */
2222
export interface MatCardConfig {
@@ -41,6 +41,8 @@ export const MAT_CARD_CONFIG = new InjectionToken<MatCardConfig>('MAT_CARD_CONFI
4141
'class': 'mat-mdc-card mdc-card',
4242
'[class.mat-mdc-card-outlined]': 'appearance === "outlined"',
4343
'[class.mdc-card--outlined]': 'appearance === "outlined"',
44+
'[class.mat-mdc-card-filled]': 'appearance === "filled"',
45+
'[class.mdc-card--filled]': 'appearance === "filled"',
4446
},
4547
exportAs: 'matCard',
4648
encapsulation: ViewEncapsulation.None,
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
@use 'sass:list';
2+
@use 'sass:map';
3+
@use '../theming/theming';
4+
5+
/// Maps namespaced tokens to per-density-scale values.
6+
/// This is used as a temporary solution for density, since Material Design currently does not have
7+
/// systemized density.
8+
/// Format:
9+
/// (
10+
/// (mat, comp): (
11+
/// token: (<scale 0 value>, <scale -1 value>, <scale -2 value>, ...),
12+
/// ...
13+
/// ),
14+
/// ...
15+
/// )
16+
// TODO(mmalerba): Add density tokens for remaining components.
17+
$_density-tokens: (
18+
(mat, autocomplete): (),
19+
(mat, badge): (),
20+
(mat, bottom-sheet): (),
21+
(mat, card): (),
22+
(mat, checkbox): (
23+
state-layer-size: (40px, 36px, 32px, 28px),
24+
touch-target-display: (block, block, none, none),
25+
),
26+
(mat, chip): (
27+
container-height: (32px, 28px, 24px),
28+
),
29+
(mat, circular-progress): (),
30+
(mat, datepicker): (),
31+
(mat, dialog): (),
32+
(mat, divider): (),
33+
(mat, elevated-card): (),
34+
(mat, expansion): (
35+
header-collapsed-state-height: (48px, 44px, 40px, 36px),
36+
header-expanded-state-height: (64px, 60px, 56px, 48px),
37+
),
38+
(mat, extended-fab): (),
39+
(mat, fab): (
40+
touch-target-display: (block, block, none, none),
41+
),
42+
(mat, fab-small): (),
43+
(mat, filled-button): (
44+
touch-target-display: (block, block, none, none),
45+
container-height: (40px, 36px, 32px, 28px),
46+
),
47+
(mat, filled-card): (),
48+
(mat, filled-text-field): (),
49+
(mat, form-field): (
50+
container-height: (56px, 52px, 48px, 44px, 40px, 36px),
51+
filled-label-display: (block, block, none, none, none, none),
52+
container-vertical-padding: (16px, 14px, 12px, 10px, 8px, 6px),
53+
filled-with-label-container-padding-top: (24px, 22px, 12px, 10px, 8px, 6px),
54+
filled-with-label-container-padding-bottom: (8px, 6px, 12px, 10px, 8px, 6px),
55+
),
56+
(mat, full-pseudo-checkbox): (),
57+
(mat, grid-list): (),
58+
(mat, icon): (),
59+
(mat, icon-button): (
60+
touch-target-display: (block, block, none, none),
61+
// The size caps out at 24px, because anything lower will be smaller than the icon.
62+
state-layer-size: (40px, 36px, 32px, 28px, 24px, 24px),
63+
),
64+
(mat, linear-progress): (),
65+
(mat, list): (
66+
list-item-leading-icon-start-space: (16px, 12px, 8px, 4px),
67+
list-item-leading-icon-end-space: (16px, 12px, 8px, 4px),
68+
list-item-one-line-container-height: (48px, 44px, 40px, 36px, 32px, 24px),
69+
list-item-two-line-container-height: (64px, 60px, 56px, 52px, 48px, 48px),
70+
list-item-three-line-container-height: (88px, 84px, 80px, 76px, 72px, 56px),
71+
),
72+
(mat, menu): (),
73+
(mat, minimal-pseudo-checkbox): (),
74+
(mat, optgroup): (),
75+
(mat, option): (),
76+
(mat, outlined-button): (
77+
container-height: (40px, 36px, 32px, 28px),
78+
touch-target-display: (block, block, none, none),
79+
),
80+
(mat, outlined-card): (),
81+
(mat, outlined-text-field): (),
82+
(mat, paginator): (
83+
container-size: (56px, 52px, 48px, 40px),
84+
form-field-container-height: (40px, 40px, 40px, 40px, 40px, 36px),
85+
form-field-container-vertical-padding: (8px, 8px, 8px, 8px, 8px, 6px),
86+
touch-target-display: (block, block, none, none),
87+
),
88+
(mat, plain-tooltip): (),
89+
(mat, protected-button): (
90+
touch-target-display: (block, block, none, none),
91+
container-height: (40px, 36px, 32px, 28px),
92+
),
93+
(mat, radio): (
94+
touch-target-display: (block, block, none, none),
95+
state-layer-size: (40px, 36px, 32px, 28px),
96+
),
97+
(mat, ripple): (),
98+
(mat, secondary-navigation-tab): (
99+
container-height: (48px, 44px, 40px, 36px, 32px),
100+
),
101+
(mat, select): (
102+
arrow-transform: (translateY(-8px), translateY(-8px), none),
103+
),
104+
(mat, sidenav): (),
105+
(mat, slide-toggle): (),
106+
(mat, slider): (),
107+
(mat, snack-bar): (),
108+
(mat, sort): (),
109+
(mat, standard-button-toggle): (
110+
height: (40px, 40px, 40px, 36px, 24px),
111+
),
112+
(mat, stepper): (
113+
header-height: (72px, 68px, 64px, 60px, 42px),
114+
),
115+
(mat, switch): (),
116+
(mat, tab-header): (),
117+
(mat, tab-indicator): (),
118+
(mat, table): (
119+
header-container-height: (56px, 52px, 48px, 44px, 40px),
120+
footer-container-height: (52px, 48px, 44px, 40px, 36px),
121+
row-item-container-height: (52px, 48px, 44px, 40px, 36px),
122+
),
123+
(mat, text-button): (
124+
touch-target-display: (block, block, none, none),
125+
container-height: (40px, 36px, 32px, 28px),
126+
),
127+
(mat, timepicker): (),
128+
(mat, tonal-button): (
129+
container-height: (40px, 36px, 32px, 28px),
130+
touch-target-display: (block, block, none, none),
131+
),
132+
(mat, toolbar): (
133+
standard-height: (64px, 60px, 56px, 52px),
134+
mobile-height: (56px, 52px, 48px, 44px),
135+
),
136+
(mat, tree): (
137+
node-min-height: (48px, 44px, 40px, 36px, 28px),
138+
),
139+
);
140+
141+
/// Gets the value for the given density scale from the given set of density values.
142+
/// @param {List} $density-values The list of values for each density scale.
143+
/// @param {Number} $scale The density scale to get the value for.
144+
/// @return {*} The value for the given scale.
145+
@function _get-value-for-scale($density-values, $scale) {
146+
$scale: theming.clamp-density($scale, -1 * list.length($density-values) + 1);
147+
$index: -$scale + 1;
148+
@return list.nth($density-values, $index);
149+
}
150+
151+
/// Gets a map of all density tokens for the given scale
152+
/// @param {Number} $scale The density scale
153+
/// @return {Map} Map of all fully qualified density tokens for the given scale.
154+
@function get-tokens-for-scale($scale) {
155+
$result: ();
156+
@each $namespace, $tokens in $_density-tokens {
157+
@each $token, $density-values in $tokens {
158+
$tokens: map.set($tokens, $token, _get-value-for-scale($density-values, $scale));
159+
}
160+
$result: map.set($result, $namespace, $tokens);
161+
}
162+
@return $result;
163+
}
164+
165+
/// Checks whether the given token is systemized by Angular Material's made up density system.
166+
/// @param {List} $namespace The namespace of the token
167+
/// @param {String} $token The name of the token
168+
/// @return {Boolean} Whether the token is systemized by the density system
169+
@function is-systemized($namespace, $token) {
170+
@return map.get($_density-tokens, $namespace, $token) != null;
171+
}

0 commit comments

Comments
 (0)